
#include "include/glut.h"
#include "wrapbass.h"

HWND win=NULL;
///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////              audio_init               ////////////////////
////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

bool cAudio::init(unsigned int flags,int mixrate,int musvol,int samvol,int strmvol,float bufsize,boolean logvol,boolean logpan)
{
	win=GetForegroundWindow();
	if (BASS_GetVersion()!=MAKELONG(0,8)) {
		printf("BASS version 0.8 was not loaded!!");
		return 0;
	}

	if (!BASS_Init(-1,mixrate,flags,win))     
		BASS_Init(-2,mixrate,flags,win);

	//BASS_SetGlobalVolumes(musvol,samvol,strmvol);
	BASS_SetBufferLength(bufsize);						
	//BASS_SetLogCurves(logvol,logpan);					//use logarithmic volume/pan?
	BASS_Start();
	printf("--Audio Init--\n");
	return 1;
}

///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////              audio_stats              ////////////////////
////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

void cAudio::stats()
{
	char *devdesc;
	for (int a=0; a<4; a++)
		if (BASS_GetDeviceDescription(a,&devdesc)) 
			printf("Device %i: %s\n",a,devdesc);

	AUD_DEVICE.size=sizeof(AUD_DEVICE);
	BASS_GetInfo(&AUD_DEVICE);
	/*printf("Current Audio Device:\n");
	printf("		RAM: %i, %i free\n",AUD_DEVICE.hwsize,AUD_DEVICE.hwfree);
	printf("		Sample slots: %i standard, %i 3d\n",AUD_DEVICE.freesam,AUD_DEVICE.free3d);
	printf("		Sample rate: %i -> %i\n",AUD_DEVICE.minrate,AUD_DEVICE.maxrate);
	printf("		DirectSound: v%i\n---------------\n",AUD_DEVICE.dsver);*/
}

///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////            audio_addstream            ////////////////////
////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

boolean cAudio::addstream(char *filename,unsigned int flags)
{
	printf("Adding [%s]...",filename);
	char *filetype=strpbrk(filename,".");
	if (filetype==NULL)
	{
		printf("ERROR (problem with extension)\n",filename);
		type=AUD_NULL;
		marker=AUD_NULL;
		return 0;
	}

 	if ( (!strcmp(filetype,".it"))  || (!strcmp(filetype,".xm"))  ||
		 (!strcmp(filetype,".mod")) || (!strcmp(filetype,".mtm")) ||
		 (!strcmp(filetype,".s3m")) || (!strcmp(filetype,".mo3")) )
	{
		printf("(Module)..");
		type=AUD_MODULE;
		marker=BASS_MusicLoad(AUD_NULL,filename,AUD_NULL,AUD_NULL,flags);
		printf("OK!..\n");
		return 1;
	}

	if (!strcmp(filetype,".mp3"))
	{
		printf("(MP3 Stream)..");
		type=AUD_MP3;
		marker=BASS_StreamCreateFile(AUD_NULL,filename,AUD_NULL,AUD_NULL,flags);
		printf("OK!(%i)..\n",marker);
		return 1;
	}

	if (!strcmp(filetype,".wav"))
	{
		printf("(WAV Sample)..");
		type=AUD_SAMPLE;
		marker=BASS_SampleLoad(AUD_NULL,filename,AUD_NULL,AUD_NULL,8,flags);
		printf("OK!..\n");
		return 1;
	}
	
	return 0;
}

///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////              audio_play               ////////////////////
////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

void cAudio::play()
{
	if (type==AUD_NULL) 
	{
		printf("Can't play\n");
		return;
	}
	if (type==AUD_SAMPLE)
	{
		BASS_SamplePlay(marker);
		//printf("Playing SAMPLE %i\n",marker);
	}
	if (type==AUD_MODULE)
	{
		BASS_MusicPlay(marker);
		//printf("Playing MODULE %i\n",marker);
	}
	if (type==AUD_MP3)
	{
		BASS_StreamPlay(marker,1,BASS_SAMPLE_LOOP);
		printf("Playing MP3 %i\n",marker);
	}
}

void cAudio::dumpbuf(char *buf,int num)
{
	BASS_ChannelGetData(marker,buf,num);
//	printf("%i %i %i\n",marker,buf,num);
}

void cAudio::give(int *left,int *right)
{
	int i;
	i=BASS_ChannelGetLevel(marker);
	*left=i&128;
	*right=(i>>16)&128;
}

void cAudio::givemid(int *mid)
{
	int i,j;
	i=BASS_ChannelGetLevel(marker);
	j=(i>>16)&128;
	*mid=((i&128)+j) >> 1;
}


int cAudio::givemid()
{
	int i,j;
	i=BASS_ChannelGetLevel(marker);
	j=(i>>16)&65535;
	j=((i&65535)+j);
	j=abs(j);
	if (j>255) return 255;
	return j;
}


#define clip(a) (short)((a<=-32768)?-32768:((a>=32767)?32767:a))
#define MESS(id,m,w,l) SendDlgItemMessage(win,id,m,(WPARAM)w,(LPARAM)l)
#define ID_ECHO                         12
#define ID_FLANGE						13
#define ID_PAN							14
#define ECHBUFLEN 1200	// buffer length
#define FLABUFLEN 350	// buffer length
static HDSP echdsp=0;	// DSP handle
static HDSP pandsp=0;
static short echbuf[ECHBUFLEN][2];	// buffer
static int echpos;	// cur.pos
static HDSP fladsp=0;	// DSP handle
static short flabuf[FLABUFLEN][2];	// buffer
static int flapos;	// cur.pos
static float flas,flasmin,flasinc;	// sweep pos/min/max/incHDSP pandsp=0;	// DSP handle
float panpos;	// cur.pos


void CALLBACK Pan(HSYNC handle, DWORD channel, void *buffer, DWORD length, DWORD user)
{
	short *d=(short*)buffer;
	for (;length;length-=4,d+=2) {
		d[0]=(short)(   (float)d[0]*sin(panpos*3.14/180));
		d[1]=(short)(   (float)d[1]*cos(panpos*3.14/180));
		//panpos+=3.0f;
	}
}

void cAudio::PanOn()
{
	if (pan) return;
	pan=1;
	SendMessage(win,WM_COMMAND,ID_PAN,0);
	{
		pandsp=BASS_ChannelSetDSP(marker,&Pan,0);
	}
}

void cAudio::PanOff()
{
	if (!pan) return;
	pan=0;
	BASS_ChannelRemoveDSP(marker,pandsp);
}


void CALLBACK Echo(HSYNC handle, DWORD channel, void *buffer, DWORD length, DWORD user)
{
	short *d=(short*)buffer;
	for (;length;length-=4,d+=2) {
		int l=d[0]+(echbuf[echpos][1]/2);
		int r=d[1]+(echbuf[echpos][0]/2);
#if 1 // 0=echo, 1=basic "bathroom" reverb
		echbuf[echpos][0]=d[0]=clip(l);
		echbuf[echpos][1]=d[1]=clip(r);
#else
		echbuf[echpos][0]=d[0];
		echbuf[echpos][1]=d[1];
		d[0]=clip(l);
		d[1]=clip(r);
#endif
		echpos++;
		if (echpos==ECHBUFLEN) echpos=0;
	}
}

void cAudio::EchoOn()
{
	if (echo) return;
	echo=1;
	SendMessage(win,WM_COMMAND,ID_ECHO,0);
	{
		memset(echbuf,0,sizeof(echbuf));
		echpos=0;
		echdsp=BASS_ChannelSetDSP(marker,&Echo,0);
	}
}

void cAudio::EchoOff()
{
	if (!echo) return;
	echo=0;
	BASS_ChannelRemoveDSP(marker,echdsp);
}


void CALLBACK Flange(HSYNC handle, DWORD channel, void *buffer, DWORD length, DWORD user)
{
	short *d=(short*)buffer;

	for (;length;length-=4,d+=2) {
        int p1=(flapos+(int)flas)%FLABUFLEN;
        int p2=(p1+1)%FLABUFLEN;
		double f=fmod(flas,1.0);
		int s;

		s=d[0]+(int)(((1.0-f)*(float)flabuf[p1][0])+(f*(float)flabuf[p2][0]));
        flabuf[flapos][0]=d[0];
		d[0]=clip(s);

		s=d[1]+(int)(((1.0-f)*(float)flabuf[p1][1])+(f*(float)flabuf[p2][1]));
        flabuf[flapos][1]=d[1];
		d[1]=clip(s);
            
        flapos++;
		if (flapos==FLABUFLEN) flapos=0;
        flas+=flasinc;
        if (flas<0.0 || flas>FLABUFLEN)
            flasinc=-flasinc;
	}
}


void cAudio::FlangeOn()
{
	if (flange) return;
	flange=1;
	memset(flabuf,0,sizeof(flabuf));
	flapos=0;
	flas=FLABUFLEN/2;
	flasinc=0.002f;
	fladsp=BASS_ChannelSetDSP(marker,&Flange,0);
}

void cAudio::FlangeOff()
{
	if (!flange) return;
	flange=0;
	BASS_ChannelRemoveDSP(marker,fladsp);
}

///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////              audio_kill               ////////////////////
////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

boolean cAudio::kill()
{
	BASS_Free();
	return 1;
}


///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
