/*

  in_cube Gamecube Stream Player for Winamp
  by hcs

  includes work by Destop and bero


*/

// experimental AFC support
#include "../xmms_cube/windows.h"
#include "wamain.h"
#include "cube.h"

int InitAFCFILE(char * inputfile, CUBEFILE * afc) {
	unsigned char readbuf[0x50];
	char* ext;
	DWORD l;
	
	ext=strrchr((char*)inputfile,'.')+1;
	if (ext==(char*)1 || strcmpi(ext,"afc")) return 1; // only check for .afc extension

	if (inputfile) {
		afc->ch[0].infile=afc->ch[1].infile=INVALID_HANDLE_VALUE;

#ifndef __amigaos4__
		afc->ch[0].infile = CreateFile(inputfile,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,
			OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
#else
		afc->ch[0].infile = IDOS->Open(inputfile, MODE_OLDFILE);
#endif

		if (afc->ch[0].infile == INVALID_HANDLE_VALUE) // error opening file
			return 1;
	} else if (afc->ch[0].type!=type_afc) return 1; // we don't have the file name to recheck

	afc->ch[1].infile=afc->ch[0].infile;

#ifndef __amigaos4__
	ReadFile(afc->ch[0].infile,readbuf,0x50,&l,NULL);
#else
	IDOS->FRead(afc->ch[0].infile, readbuf, 1, 0x50);
#endif

#ifndef __amigaos4__
	afc->file_length=GetFileSize(afc->ch[0].infile,NULL);
#else
	afc->file_length = IDOS->GetFileSize(afc->ch[0].infile);
#endif

	if (!memcmp(readbuf, "STRM",4) && afc->file_length-0x40 == get32bit(readbuf+4) &&
		!memcmp(readbuf+0x40,"BLCK",4))
	{
		afc->NCH = 2;
		afc->ch[0].sample_rate = get32bit(readbuf+0x10);
		afc->ch[0].chanstart =
		afc->ch[1].chanstart = 0x40;
		afc->ch[0].num_samples = get32bit(readbuf+0x14)*16/8/2;
		afc->ch[0].loop_flag = get16bit(readbuf+0xe);
		afc->ch[0].sa = get32bit(readbuf+0x18);
		afc->ch[0].ea = get32bit(readbuf+0x1c);

		afc->samplesdone = 0;

		// uses a very HALP-like mechanism, BLCK
		afc->nexthalp=0x40;
		afc->halpsize=0;

		afc->ch[0].hist1=0;
		afc->ch[0].hist2=0;
		afc->ch[1].hist1=0;
		afc->ch[1].hist2=0;

		// invalidate loop context so it'll be remembered when we hit the start
		afc->loophalpsize=-1;

		afc->ch[0].type = type_astafc;
	} else {
		afc->NCH = 2;
		afc->ch[0].sample_rate = (unsigned short)get16bit(readbuf+8);
		if (!CheckSampleRate(afc->ch[0].sample_rate)) {
			CloseCUBEFILE(afc);
			return 1;
		}

		afc->ch[0].chanstart = 0x20;
		afc->ch[0].hist1=0;
		afc->ch[0].hist2=0;
		afc->ch[1].hist1=0;
		afc->ch[1].hist2=0;
		afc->ch[0].type = type_afc;

		afc->ch[0].offs=afc->ch[0].chanstart;
		afc->ch[0].num_samples = get32bit(readbuf+4); //(GetFileSize(afc->ch[0].infile,&l)-afc->ch[0].chanstart)*16/18;
		afc->ch[0].loop_flag = get32bit(readbuf+0x10);
		afc->ch[0].sa = get32bit(readbuf+0x14);
		afc->ch[0].ea = afc->ch[0].num_samples;
	}

	/*if (!afc->ch[0].loop_flag)*/ afc->nrsamples = afc->ch[0].num_samples;
	/*else afc->nrsamples=afc->ch[0].sa+looptimes*(afc->ch[0].ea-afc->ch[0].sa)+(fadelength+fadedelay)*afc->ch[0].sample_rate;*/
	
	afc->ch[0].readloc=afc->ch[1].readloc=afc->ch[0].writeloc=afc->ch[1].writeloc=0;

	return 0;
}

void fillbufferAFC(CUBEFILE * afc) {
	int l,i;
	unsigned char AFCbuf[18];
	short wavbuf[32];

#ifndef __amigaos4__
	SetFilePointer(afc->ch[0].infile,afc->ch[0].offs,0,FILE_BEGIN);
#else
	IDOS->ChangeFilePosition(afc->ch[0].infile, afc->ch[0].offs, OFFSET_BEGINNING);
#endif

	do {
#ifndef __amigaos4__
		ReadFile(afc->ch[0].infile, AFCbuf, 18, &l, NULL);
#else
		l = IDOS->FRead(afc->ch[0].infile, AFCbuf, 1, 18);
#endif
		if (l<18) {
			// only seems to support loop from end
			if (afc->ch[0].loop_flag) {
				afc->ch[0].offs=afc->ch[0].chanstart+afc->ch[0].sa/SIXTEEN_MUL_EIGHTEEN;
#ifndef __amigaos4__
				SetFilePointer(afc->ch[0].infile,afc->ch[0].offs,0,FILE_BEGIN);
#else
				IDOS->ChangeFilePosition(afc->ch[0].infile, afc->ch[0].offs, OFFSET_BEGINNING);
#endif
				continue;
			}
			return;
		}
		afc->ch[0].offs+=18;

		AFCdecodebuffer(AFCbuf,wavbuf,&afc->ch[0].hist1,&afc->ch[0].hist2);
		AFCdecodebuffer(AFCbuf+9,wavbuf+16,&afc->ch[1].hist1,&afc->ch[1].hist2);

		for (i=0;i<16;i++) {
			afc->ch[0].chanbuf[afc->ch[0].writeloc++]=wavbuf[i];
			if (afc->ch[0].writeloc>=HEX_8000_DIV_EIGHT_MUL_FOURTEEN) afc->ch[0].writeloc=0;
			afc->ch[1].chanbuf[afc->ch[1].writeloc++]=wavbuf[i+16];
			if (afc->ch[1].writeloc>=HEX_8000_DIV_EIGHT_MUL_FOURTEEN) afc->ch[1].writeloc=0;
		}
	} while (afc->ch[0].writeloc != afc->ch[0].readloc);

}

void fillbufferASTAFC(CUBEFILE * afc) {
	int l,i;
	unsigned char AFCbuf1[9],AFCbuf2[9];
	short wavbuf1[16],wavbuf2[16];

	if (afc->halpsize==0 && (long)afc->nexthalp == 0) afc->ch[0].readloc=afc->ch[1].readloc=afc->ch[0].writeloc-1;
	
	do {
			// handle BLCK headers
			if (afc->halpsize==0) {
				if ((long)afc->nexthalp == 0) return;
				afc->ch[0].offs=afc->nexthalp+0x20;
#ifndef __amigaos4__
				SetFilePointer(afc->ch[0].infile, afc->nexthalp,0,FILE_BEGIN);
				ReadFile(afc->ch[0].infile, AFCbuf1, 8, &l, NULL);
#else
				IDOS->ChangeFilePosition(afc->ch[0].infile, afc->nexthalp, OFFSET_BEGINNING);
				l = IDOS->FRead(afc->ch[0].infile, AFCbuf1, 1, 8);
#endif
				if (l<8) return;
				afc->halpsize=get32bit(AFCbuf1+4)*2; // interleave amount (this whole BLCK is 2x)
								
				afc->ch[1].offs=afc->nexthalp+0x20+get32bit(AFCbuf1+4);
				afc->nexthalp+=get32bit(AFCbuf1+4)*2+0x20;
			}

#ifndef __amigaos4__
			SetFilePointer(afc->ch[0].infile, afc->ch[0].offs,0,FILE_BEGIN);
			ReadFile(afc->ch[0].infile, AFCbuf1, 9, &l, NULL);
#else
			IDOS->ChangeFilePosition(afc->ch[0].infile, afc->ch[0].offs, OFFSET_BEGINNING);
			IDOS->FRead(afc->ch[0].infile, AFCbuf1, 1, 9);
#endif

#ifndef __amigaos4__
			SetFilePointer(afc->ch[0].infile, afc->ch[1].offs,0,FILE_BEGIN);
			ReadFile(afc->ch[0].infile, AFCbuf2, 9, &l, NULL);
#else
			IDOS->ChangeFilePosition(afc->ch[0].infile, afc->ch[1].offs, OFFSET_BEGINNING);
			IDOS->FRead(afc->ch[0].infile, AFCbuf2, 1, 9);
#endif		

			afc->ch[0].offs+=9;
			afc->ch[1].offs+=9;
			
			afc->halpsize-=18;
			if (afc->halpsize<18) afc->halpsize=0;

			AFCdecodebuffer(AFCbuf1,wavbuf1,&afc->ch[0].hist1,&afc->ch[0].hist2);
			AFCdecodebuffer(AFCbuf2,wavbuf2,&afc->ch[1].hist1,&afc->ch[1].hist2);

			afc->samplesdone+=16;
			if (afc->loophalpsize < 0 && afc->samplesdone >= (int)afc->ch[0].sa) {
				// a lot of these values could probably just be recalculated, but it's easy to save them
				afc->loophalpsize = afc->halpsize;
				afc->loopnexthalp = afc->nexthalp;
				afc->ch[0].loopoffs = afc->ch[0].offs;
				afc->ch[1].loopoffs = afc->ch[1].offs;
				afc->ch[0].sa = afc->samplesdone;
			}
			if (afc->samplesdone >= (int)afc->ch[0].ea) {
				afc->halpsize = afc->loophalpsize;
				afc->nexthalp = afc->loopnexthalp;
				afc->ch[0].offs = afc->ch[0].loopoffs;
				afc->ch[1].offs = afc->ch[1].loopoffs;
				afc->samplesdone = afc->ch[0].sa;
			}
		
			for (i=0;i<16;i++) {
				afc->ch[0].chanbuf[afc->ch[0].writeloc++]=wavbuf1[i];
				afc->ch[1].chanbuf[afc->ch[1].writeloc++]=wavbuf2[i];
			
				if (afc->ch[0].writeloc>=HEX_8000_DIV_EIGHT_MUL_FOURTEEN) afc->ch[0].writeloc=0;
				if (afc->ch[1].writeloc>=HEX_8000_DIV_EIGHT_MUL_FOURTEEN) afc->ch[1].writeloc=0;
			}
	} while (afc->ch[0].writeloc != afc->ch[0].readloc);
}
