struct {
	unsigned char chanVol[4];
	short int     chanDiv[4];
	short int     chanCnt[4];
	
	unsigned short int noiseLFSR;
	unsigned short int noiseTBits;
	
	int tickPerSample;
	
	char latchedChan;
	char latchedType;//0 tone(noise) 1 volume
} PSG;


struct {
	unsigned char *data;
	int wait;
	int ptr;
	int ticksPerSample;
	int loopOffset;
	bool play;
} VGM;




inline void psg_out_port(unsigned char val)
{
	int chan,div;
	
	if(val&128)
	{
		chan=(val>>5)&3;
		div=(PSG.chanDiv[chan]&0xfff0)|(val&15);
		
		PSG.latchedChan=chan;
		PSG.latchedType=val&16;
	}
	else
	{
		chan=PSG.latchedChan;
		div=(PSG.chanDiv[chan]&15)|((val&63)<<4);
	}
	
	if(PSG.latchedType)
	{
		PSG.chanVol[chan]=(PSG.chanVol[chan]&16)|(val&15);
	}
	else
	{
		PSG.chanDiv[chan]=div;
		if(chan==3)
		{
			if(((div>>2)&1)) PSG.noiseTBits=9; else PSG.noiseTBits=1;
			PSG.noiseLFSR=0x8000;
		}
	}
}







int read_int32(unsigned char *mem)
{
	return (mem[0]+(mem[1]<<8)+(mem[2]<<16)+(mem[3]<<24));
}






inline void vgm_tick(void)
{
	int tt,incr;
	
	for(tt=0;tt<VGM.ticksPerSample;tt++)
	{
		if(VGM.wait>0)
		{
			VGM.wait--;
		}
		else
		{
			switch(VGM.data[VGM.ptr])
			{
			case 0x50:
				psg_out_port(VGM.data[VGM.ptr+1]);
			case 0x4f:
				incr=2;
				break;
			case 0x61:
				VGM.wait=VGM.data[VGM.ptr+1]+(VGM.data[VGM.ptr+2]<<8);
			case 0x51:
			case 0x52:
			case 0x53:
			case 0x54:
				incr=3;
				break;
			case 0x62:
				VGM.wait=735;
				incr=1;
				break;
			case 0x63:
				VGM.wait=882;
				incr=1;
				break;
			case 0x66:
				if(VGM.loopOffset>0) VGM.ptr=VGM.loopOffset+0x1c; else VGM.play=false;
			default:
				incr=0;
			}
			VGM.ptr+=incr;
		}
	}
}

/*
выбор канала: auto/1234 (123tone, 4noise)
импорт только тона(шум) или смешивание

AS> Сильно чешу репу насчёт импорта эффектов из vgm (sega master system).
 AS> Там три тональника и шум, и все четыре канала имеют свою громкость.
 AS> Эффекты обычно содержат в себе и шум, и тональник - вот думаю, чью-же
 AS> громкость брать-то в этом случае...
это проблема...
видимо, так:
а) если громкость шума меньше 1/2 громкости тональника - шум игнорируем.
б) если громкость шума больше 2 громкостей тональника - тональник игнорируем.
в) иначе TN, громкость = (громкость тональника + громкость шума)/1.4. [Делим не
на 2, а на 1.4, потому что TN тише, чем T, и тише, чем N.]

потом громкость пересчитываем в AY громкость по таблице by Monster/Sage.

----------------

пока сделать только импорт тональников, без автовыбора канала
*/


bool ImportVGM(int fxn,const char *filename,int ichan,bool inoise)
{
	FILE *file;
	int size;
	int lenght;
	int baseFreq;
	
	file=fopen(filename,"rb");
	if(!file) return false;

	fseek(file,0,SEEK_END);
	size=ftell(file);
	fseek(file,0,SEEK_SET);
	VGM.data=(unsigned char*)malloc(size);
	fread(VGM.data,size,1,file);
	fclose(file);
	
	if(memcmp(VGM.data,"Vgm ",4)!=0)
	{
		Application->MessageBox("No VGM signature found (possibly wrong file type)","Error",MB_OK);
		free(VGM.data);
		return false;
	}
	
	VGM.wait=0;
	VGM.ptr=0x40;
        baseFreq=read_int32(&VGM.data[0x0c]);

        if(baseFreq==0)
        {
		Application->MessageBox("No data for PSG found","Error",MB_OK);
		free(VGM.data);
		return false;
        }

	memset(&PSG,0,sizeof(PSG));

int incr,wcnt,pd,pchan;
bool done;

EffectInit(fxn);


done=false;
pd=0;
pchan=2; //канал для импорта

while(!done)
{
			switch(VGM.data[VGM.ptr])
			{
			case 0x50:
				psg_out_port(VGM.data[VGM.ptr+1]);
			case 0x4f:
				incr=2;
				break;
			case 0x61:
				VGM.wait+=VGM.data[VGM.ptr+1]+(VGM.data[VGM.ptr+2]<<8);
			case 0x51:
			case 0x52:
			case 0x53:
			case 0x54:
				incr=3;
				break;
			case 0x62:
				VGM.wait+=735;
				incr=1;
				break;
			case 0x63:
				VGM.wait+=882;
				incr=1;
				break;
			case 0x66:
				done=true;
			default:
				incr=0;
			}
			VGM.ptr+=incr;
			
			if(VGM.wait>=735)
			{
			VGM.wait-=735;
			//здесь производить конверсию для AY, это прерывание
			
			//для расчёта частоты нужно знать тактовую частоту PSG
                        //частота сигнала:
                        //baseFreq/сколько-то/div
                        //делитель для AY: 1773400/8/частоту
                        int frq,noiseDiv;
                        //if(PSG.chanDiv[pchan]>0) frq=baseFreq/PSG.chanDiv[pchan]; else frq=100;
                        
                        
            switch(PSG.chanDiv[3]&3)
			{
			case 0: noiseDiv=0; break;
			case 1: noiseDiv=4; break;
			case 2: noiseDiv=8; break;
			case 3:
				noiseDiv=PSG.chanDiv[2]>>1;
				if(noiseDiv>63) noiseDiv=63;
				break;
			}
			
			
			ayBank[fxn].ayEffect[pd].tone=PSG.chanDiv[pchan];// /1773400/8/frq;
			ayBank[fxn].ayEffect[pd].noise=noiseDiv;
			ayBank[fxn].ayEffect[pd].volume=15-PSG.chanVol[pchan];
			ayBank[fxn].ayEffect[pd].t=true;
			ayBank[fxn].ayEffect[pd].n=true;
			
			pd++;
			if(pd>=4096) done=true;
			}
}

	if(VGM.data) free(VGM.data);
	
	return true;
}