//http://www.youtube.com/user/thecplusplusguy
//Playing 3D sound with OpenAL, and loading a wav file manually
#include <iostream>
#include <fstream>
#include <cstring>
#include <AL/al.h>
#include <AL/alc.h>
#include <SDL/SDL.h>

bool isBigEndian()
{
	int a=1;
	return !((char*)&a)[0];
}

int convertToInt(char* buffer,int len)
{
	int a=0;
	if(!isBigEndian())
		for(int i=0;i<len;i++)
			((char*)&a)[i]=buffer[i];
	else
		for(int i=0;i<len;i++)
			((char*)&a)[3-i]=buffer[i];	
	return a;
}

char* loadWAV(const char* fn,int& chan,int& samplerate,int& bps,int& size)
{
	char buffer[4];
	std::ifstream in(fn,std::ios::binary);
	in.read(buffer,4);
	if(strncmp(buffer,"RIFF",4)!=0)
	{
		std::cout << "this is not a valid WAVE file"  << std::endl;
		return NULL;
	}
	in.read(buffer,4);
	in.read(buffer,4);	//WAVE
	in.read(buffer,4);	//fmt 
	in.read(buffer,4);	//16
	in.read(buffer,2);	//1
	in.read(buffer,2);
	chan=convertToInt(buffer,2);
	in.read(buffer,4);
	samplerate=convertToInt(buffer,4);
	in.read(buffer,4);
	in.read(buffer,2);
	in.read(buffer,2);
	bps=convertToInt(buffer,2);
	in.read(buffer,4);	//data
	in.read(buffer,4);
	size=convertToInt(buffer,4);
	char* data=new char[size];
	in.read(data,size);
	return data;	
}

int main(int argc,char** argv)
{
	int channel,sampleRate,bps,size;
	char* data=loadWAV("test.wav",channel,sampleRate,bps,size);
	ALCdevice* device=alcOpenDevice(NULL);
	if(device==NULL)
	{
		std::cout << "cannot open sound card" << std::endl;
		return 0;
	}
	ALCcontext* context=alcCreateContext(device,NULL);
	if(context==NULL)
	{
		std::cout << "cannot open context" << std::endl;
		return 0;
	}
	alcMakeContextCurrent(context);
	
	unsigned int bufferid,format;
	alGenBuffers(1,&bufferid);
	if(channel==1)
	{
		if(bps==8)
		{
			format=AL_FORMAT_MONO8;
		}else{
			format=AL_FORMAT_MONO16;		
		}
	}else{
		if(bps==8)
		{
			format=AL_FORMAT_STEREO8;
		}else{
			format=AL_FORMAT_STEREO16;		
		}	
	}
	alBufferData(bufferid,format,data,size,sampleRate);
	unsigned int sourceid;
	alGenSources(1,&sourceid);
	alSourcei(sourceid,AL_BUFFER,bufferid);
	SDL_Init(SDL_INIT_EVERYTHING);
	SDL_Surface* screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE);
	SDL_Event event;
	Uint32 start;
	bool running;
	bool b[4]={0,0,0,0};
	float x=0,z=0;
	while(running)
	{
		start=SDL_GetTicks();
		while(SDL_PollEvent(&event))
		{
			switch(event.type)
			{
				case SDL_QUIT:
					running=false;
					break;
				case SDL_KEYDOWN:
					switch(event.key.keysym.sym)
					{
						case SDLK_UP:
							b[0]=true;
							break;
						case SDLK_RIGHT:
							b[1]=true;
							break;
						case SDLK_DOWN:
							b[2]=true;
							break;
						case SDLK_LEFT:
							b[3]=true;
							break;
						case SDLK_SPACE:
							alSourcePlay(sourceid);
							break;						
					}
					break;
				case SDL_KEYUP:
					switch(event.key.keysym.sym)
					{
						case SDLK_UP:
							b[0]=false;
							break;
						case SDLK_RIGHT:
							b[1]=false;
							break;
						case SDLK_DOWN:
							b[2]=false;
							break;
						case SDLK_LEFT:
							b[3]=false;
							break;
					}
					break;
			}
		}
		
		if(b[0])
			z+=0.3;
		if(b[1])
			x+=0.3;
		if(b[2])
			z-=0.3;
		if(b[3])
			x-=0.3;
		alSource3f(sourceid,AL_POSITION,x,0,z);
		alSourcei(sourceid,AL_LOOPING,AL_TRUE);
		
		
		float f[]={1,0,0,0,1,0};
		alListenerfv(AL_ORIENTATION,f);
		
		
		if(1000/30.0>SDL_GetTicks()-start)
			SDL_Delay(1000/30.0-(SDL_GetTicks()-start));
	}
	
	alDeleteSources(1,&sourceid);
	alDeleteBuffers(1,&bufferid);
	
	alcDestroyContext(context);
	alcCloseDevice(device);
	delete[] data;
	return 0;
}