//---------------------------------------------------------------------------

#include <vcl.h>
#include <mmsystem.h>
#include <stdio.h>
#include <math.h>
#pragma hdrstop

#include "Unit1.h"
#include "Unit2.h"
#include "Unit3.h"

#define TITLE_STR "AY Sound FX Editor v0.4"
#define MIXRATE 44100

int import_chan; //-1=auto, 012=ABC

unsigned char *wave=NULL;

const int edit_xoff=8;
const int edit_yoff=35;
const int edit_head=20;
const int tone_off=151;
const int tone_wdt=326;
const int noise_off=484;
const int noise_wdt=64;
const int vol_off=555;
const int vol_wdt=64;
const int tflag_off=36;
const int tflag_wdt=9;
const int nflag_off=54;
const int nflag_wdt=9;
const int pos_wdt=27;
const int tcol_off=72;
const int tcol_wdt=27;
const int ncol_off=108;
const int ncol_wdt=18;
const int vcol_off=135;
const int vcol_wdt=9;


int line_onscr=25;
const int line_hgt=15;

int no_click;//задержка обработки кликов по форме после всяких диалогов открытия-сохранения

bool form_focus;

bool period_linear;

struct ayfxCell {
	int tone;
	int noise;
	int volume;
	bool t;
	bool n;
	bool sel;
};

#define max_fx_len	0x1000
#define max_fx_all	0x100


ayfxCell ayClipboard[max_fx_len];

struct ayfxBankCell {
	ayfxCell ayEffect[max_fx_len];
	char name[256];
};

ayfxBankCell ayBank[max_fx_all];



int curOffset;
int curPrevLine;
int curXpos;
int curYpos;
int clipLen;
POINT mousePrev;

int curEffect;   //текущий редактируемый эффект
int allEffect; //кол-во эффектов в банке всего



#include "rdwrnums.h"
#include "wavrender.h"



int PeriodToWidth(int period)
{
	if(period_linear)
	{
		return 1+tone_wdt*period/4096;
	}
	else
	{
        if(period<=0) return 0;
        return (int)float(float(tone_wdt)*log(period/8.)/log(4095./8.));
	}
}


int WidthToPeriod(int wdt)
{
	if(period_linear)
	{
		return wdt*4096/tone_wdt;
	}
	else
	{
        return (int)float(8.*exp(float(1+wdt)/(float(tone_wdt)/log(4095./8.))));
	}
}


bool SetBool(bool &var,bool val)
{
	if(var!=val)
	{
		var=val;
		return true;
	}
	return false;
}


bool SetInt(int &var,int val)
{
	if(var!=val)
	{
		var=val;
		return true;
	}
	return false;
}



AnsiString NameTrimPath(AnsiString name)
{
	name=name.Delete(1,name.LastDelimiter("\\/"));
	name=name.Delete(name.LastDelimiter("."),name.Length());
	return name;
}



void CenterView(void)
{
	if(curYpos<curOffset||curYpos>=curOffset+line_onscr)
	{
		curOffset=curYpos-line_onscr/2;
		if(curOffset<0) curOffset=0;
		if(curOffset>max_fx_len-line_onscr) curOffset=max_fx_len-line_onscr;
	}
}



int EffectRealLen(int fxn)
{
	int aa,len;
	
	len=0;
	for(aa=max_fx_len-1;aa>=0;aa--)
	{
		if(ayBank[fxn].ayEffect[aa].volume>0)
		{
			len=aa+1;
			break;
		}
	}
	return len;
}



void EffectDefaultStr(ayfxCell &cell)
{
    cell.tone=0;
    cell.noise=0;
    cell.volume=0;
    cell.t=false;
    cell.n=false;
    cell.sel=false;
}



void EffectInit(int fxn)
{
	int aa;
	for(aa=0;aa<max_fx_len;aa++) EffectDefaultStr(ayBank[fxn].ayEffect[aa]);
	curOffset=0;
	curPrevLine=-1;
	curXpos=0;
	curYpos=0;
}



int EffectDecode(int fxn,unsigned char *buf,int size)
{
	ayfxCell *afx;
	int it,pp,pd,tone,noise;
	
	afx=ayBank[fxn].ayEffect;
	
	EffectInit(fxn);
	
	pd=0;
	pp=0;
	
	while(pp<size)
	{
		it=buf[pp++];
		
		if(it&(1<<5))
		{
			tone=RdWordLH(&buf[pp])&0xfff;
			pp+=2;
		}
		if(it&(1<<6))
		{
			noise=buf[pp++];
			if(it==0xd0&&noise>=0x20) break;
			noise&=0x1f;
		}
		
		afx[pd].tone=tone;
		afx[pd].noise=noise;
		afx[pd].volume=it&0x0f;
		afx[pd].t=((it&(1<<4))?false:true);
		afx[pd].n=((it&(1<<7))?false:true);
		pd++;
	}
	
	return pp;
}



bool EffectLoad(int fxn,const char *filename)
{
	
	FILE *file;
	unsigned char *buf;
	int size;
	
	file=fopen(filename,"rb");
	if(!file) return false;
	fseek(file,0,SEEK_END);
	size=ftell(file);
	fseek(file,0,SEEK_SET);
	buf=(unsigned char*)malloc(size);
	fread(buf,size,1,file);
	fclose(file);
	
	EffectDecode(fxn,buf,size);
	strcpy(ayBank[fxn].name,NameTrimPath(filename).c_str());
	
	free(buf);
	
	return true;
}



int EffectEncode(int fxn,unsigned char *buf)
{
	int aa,it,pp,fx_len,tone,noise;
	ayfxCell *afx;
	
	
	fx_len=EffectRealLen(fxn);
	tone=-1;
	noise=-1;
	pp=0;
	afx=ayBank[fxn].ayEffect;
	
	for(aa=0;aa<fx_len;aa++)
	{
		it =(afx[aa].volume&0x0f);
		it|=(afx[aa].t?0:(1<<4));
		it|=(afx[aa].n?0:(1<<7));
		if(afx[aa].tone!=tone)
		{
			tone=afx[aa].tone;
			it|=(1<<5);
		}
		if(afx[aa].noise!=noise)
		{
			noise=afx[aa].noise;
			it|=(1<<6);
		}
		buf[pp++]=it;
		if(it&(1<<5))
		{
			WrWordLH(&buf[pp],tone&0xfff);
			pp+=2;
		}
		if(it&(1<<6))
		{
			buf[pp++]=noise&0x1f;
		}
	}
	
	buf[pp++]=0xd0;//конечный маркер
	buf[pp++]=0x20;
	
	return pp;
}



bool EffectSave(int fxn,const char *filename)
{
	unsigned char *buf;
	FILE *file;
	int len;
	
	buf=(unsigned char*)malloc(max_fx_len*4);
	
	len=EffectEncode(fxn,buf);
	
	file=fopen(filename,"wb");
	if(!file)
	{
		free(buf);
		return false;
	}
	fwrite(buf,len,1,file);
	fclose(file);
	free(buf);
	return true;
}



bool EffectDeleteSel(int fxn)
{
	int aa,bb;
	bool done,del;
	
	done=false;
	del=false;
	
	while(!done)
	{
		done=true;
		for(aa=0;aa<max_fx_len;aa++)
		{
			if(ayBank[fxn].ayEffect[aa].sel)
			{
				for(bb=aa;bb<max_fx_len-1;bb++) ayBank[fxn].ayEffect[bb]=ayBank[fxn].ayEffect[bb+1];
				EffectDefaultStr(ayBank[fxn].ayEffect[max_fx_len-1]);
				done=false;
				del=true;
				break;
			}
		}
	}
	CenterView();
	return del;
}



void EffectInsertStr(int fxn,int pos,bool clr)
{
    int aa;
    for(aa=max_fx_len-1;aa>pos;aa--) ayBank[fxn].ayEffect[aa]=ayBank[fxn].ayEffect[aa-1];
	if(clr) EffectDefaultStr(ayBank[fxn].ayEffect[pos]);
}



void EffectCopy(int fxn,bool res)
{
	int aa;
	clipLen=0;
	
	for(aa=0;aa<max_fx_len;aa++)
	{
		if(ayBank[fxn].ayEffect[aa].sel)
		{
			if(res) ayBank[fxn].ayEffect[aa].sel=false;
			ayClipboard[clipLen]=ayBank[fxn].ayEffect[aa];
			ayClipboard[clipLen].sel=false;
			clipLen++;
		}
	}
	if(clipLen==0)
	{
		ayClipboard[0]=ayBank[fxn].ayEffect[curYpos];
		clipLen=1;
	}
}



void EffectCut(int fxn)
{
	EffectCopy(fxn,false);
	if(!EffectDeleteSel(fxn))
	{
		ayBank[fxn].ayEffect[curYpos].sel=true;
		EffectDeleteSel(fxn);
	}
}



void EffectPaste(int fxn)
{
	int aa,len;
	if(clipLen<=0) return;
	for(aa=0;aa<clipLen;aa++) EffectInsertStr(fxn,curYpos,true);
	len=clipLen;
	if(curYpos+len>=max_fx_len) len=max_fx_len-curYpos;
	for(aa=0;aa<len;aa++) ayBank[fxn].ayEffect[curYpos+aa]=ayClipboard[aa];
}



void __fastcall TForm1::TitleUpdate(void)
{
	Caption=(AnsiString)TITLE_STR+" ["+NameTrimPath(SaveDialog2->FileName)+".afb]";
}




void __fastcall TForm1::DrawEdit(bool full)
{
	int aa,x,xo,y,fwdt,pp,rl;
	AnsiString str;
	TRect rect;
	TColor back,lcol,fcol;
	
	Canvas->Brush->Color=clWhite;
	Canvas->Font->Color=clBlack;
	Canvas->Pen->Color=clBlack;
	
	y=edit_yoff;
	pp=curOffset;
	rl=EffectRealLen(curEffect);
	
	if(full)
	{
        if(period_linear)
        {
			Canvas->TextOut(edit_xoff,y,"Pos|T|N|Per|Ns|V|Period (linear)                     |Noise  |Volume ");
        }
        else
        {
			Canvas->TextOut(edit_xoff,y,"Pos|T|N|Per|Ns|V|Period (log)                        |Noise  |Volume ");
        }
	}
	y+=edit_head;
	
	for(aa=0;aa<line_onscr;aa++)
	{
        if(ayBank[curEffect].ayEffect[pp].sel) back=(TColor)0xc0ffc0; else back=clWhite;
        if(pp<rl)
        {
			fcol=clBlack;
			lcol=clGray;
        }
        else
        {
			fcol=clGray;
			lcol=clSilver;
        }
        Canvas->Font->Color=fcol;
        Canvas->Pen->Color=fcol;
        Canvas->Brush->Color=back;
		Canvas->TextOut(edit_xoff,y,IntToHex(pp,3));
		str=(ayBank[curEffect].ayEffect[pp].t?"T":"-");
		Canvas->TextOut(edit_xoff+36,y,str);
		str=(ayBank[curEffect].ayEffect[pp].n?"N":"-");
		Canvas->TextOut(edit_xoff+54,y,str);
		
		if(curXpos==0&&pp==curYpos)
		{
			Canvas->Brush->Color=clBlack;
			Canvas->Font->Color=clWhite;
		}
		else
		{
			Canvas->Brush->Color=back;
			Canvas->Font->Color=fcol;
		}
		Canvas->TextOut(edit_xoff+72,y,IntToHex(ayBank[curEffect].ayEffect[pp].tone,3));
		if(curXpos==1&&pp==curYpos)
		{
			Canvas->Brush->Color=clBlack;
			Canvas->Font->Color=clWhite;
		}
		else
		{
			Canvas->Brush->Color=back;
			Canvas->Font->Color=fcol;
		}
		Canvas->TextOut(edit_xoff+108,y,IntToHex(ayBank[curEffect].ayEffect[pp].noise,2));
		if(curXpos==2&&pp==curYpos)
		{
			Canvas->Brush->Color=clBlack;
			Canvas->Font->Color=clWhite;
		}
		else
		{
			Canvas->Brush->Color=back;
			Canvas->Font->Color=fcol;
		}
		Canvas->TextOut(edit_xoff+135,y,IntToHex(ayBank[curEffect].ayEffect[pp].volume,1));
		
		x=edit_xoff+tone_off;
		fwdt=PeriodToWidth(ayBank[curEffect].ayEffect[pp].tone);//*tone_wdt/4095);
		if(fwdt<2&&ayBank[curEffect].ayEffect[pp].tone>0) fwdt=2;
		Canvas->Brush->Color=back;
		xo=x+fwdt-1;
		if(xo<x) xo=x;
		Canvas->Rectangle(xo,y+1,x+tone_wdt,y+line_hgt-1);
		Canvas->Brush->Color=lcol;
		Canvas->Rectangle(x,y+1,x+fwdt,y+line_hgt-1);
		
		x=edit_xoff+noise_off;
		fwdt=ayBank[curEffect].ayEffect[pp].noise*noise_wdt/31;
		if(fwdt<2&&ayBank[curEffect].ayEffect[pp].noise>0) fwdt=2;
		Canvas->Brush->Color=back;
		xo=x+fwdt-1;
		if(xo<x) xo=x;
		Canvas->Rectangle(xo,y+1,x+noise_wdt,y+line_hgt-1);
		Canvas->Brush->Color=lcol;
		Canvas->Rectangle(x,y+1,x+fwdt,y+line_hgt-1);
		
		x=edit_xoff+vol_off;
		fwdt=ayBank[curEffect].ayEffect[pp].volume*vol_wdt/15;
		if(fwdt<2&&ayBank[curEffect].ayEffect[pp].volume>0) fwdt=2;
		Canvas->Brush->Color=back;
		xo=x+fwdt-1;
		if(xo<x) xo=x;
		Canvas->Rectangle(xo,y+1,x+vol_wdt,y+line_hgt-1);
		Canvas->Brush->Color=lcol;
		Canvas->Rectangle(x,y+1,x+fwdt,y+line_hgt-1);
		
		y+=line_hgt;
		pp++;
	}
}



bool MouseCheck(int x,int y,TShiftState state,bool hold)
{
	int ln,temp;
	bool l,r,mkey;
	if(state.Contains(ssLeft))  l=true; else l=false;
	if(state.Contains(ssRight)) r=true; else r=false;
	if(l||r) mkey=true; else mkey=false;
	
	if(!form_focus) return false;
	
	if(y>=edit_yoff+edit_head&&y<edit_yoff+edit_head+line_onscr*line_hgt)
	{
		ln=(y-edit_yoff-edit_head)/line_hgt+curOffset;
		if(ln<0) ln=0;
		if(ln>=max_fx_len) ln=max_fx_len-1;
		
		if(mkey)
		{
			if(x>=edit_xoff+tone_off&&x<=edit_xoff+tone_off+tone_wdt)
			{
				temp=WidthToPeriod(x-edit_xoff-tone_off);
				if(temp>4095) temp=4095;
				if(SetInt(ayBank[curEffect].ayEffect[ln].tone,temp)) return true;
			}
			if(x>=edit_xoff+tone_off-2&&x<edit_xoff+tone_off)
			{
				if(SetInt(ayBank[curEffect].ayEffect[ln].tone,0)) return true;
			}
			if(x>=edit_xoff+noise_off&&x<=edit_xoff+noise_off+noise_wdt)
			{
				temp=1+(x-edit_xoff-noise_off)*31/noise_wdt;
				if(temp>31) temp=31;
				if(SetInt(ayBank[curEffect].ayEffect[ln].noise,temp)) return true;
			}
			if(x>=edit_xoff+noise_off-2&&x<edit_xoff+noise_off)
			{
				if(SetInt(ayBank[curEffect].ayEffect[ln].noise,0)) return true;
			}
			if(x>=edit_xoff+vol_off&&x<=edit_xoff+vol_off+vol_wdt)
			{
				temp=1+(x-edit_xoff-vol_off)*15/vol_wdt;
				if(temp>15) temp=15;
				if(SetInt(ayBank[curEffect].ayEffect[ln].volume,temp)) return true;
			}
			if(x>=edit_xoff+vol_off-2&&x<edit_xoff+vol_off)
			{
				if(SetInt(ayBank[curEffect].ayEffect[ln].volume,0)) return true;
			}
		}
		
		if(x>=edit_xoff+tflag_off&&x<=edit_xoff+tflag_off+tflag_wdt)
		{
			if(l)
			{
				if(SetBool(ayBank[curEffect].ayEffect[ln].t,true)) return true;
			}
			if(r)
			{
				if(SetBool(ayBank[curEffect].ayEffect[ln].t,false)) return true;
			}
		}
		if(x>=edit_xoff+nflag_off&&x<=edit_xoff+nflag_off+nflag_wdt)
		{
			if(l)
			{
				if(SetBool(ayBank[curEffect].ayEffect[ln].n,true)) return true;
			}
			if(r)
			{
				if(SetBool(ayBank[curEffect].ayEffect[ln].n,false)) return true;
			}
		}
		
		if(curPrevLine!=ln||!hold)
		{
			curPrevLine=ln;
			
			if(x>=edit_xoff&&x<=edit_xoff+pos_wdt)
			{
				if(l)
				{
					if(SetBool(ayBank[curEffect].ayEffect[ln].sel,true)) return true;
				}
				if(r)
				{
					if(SetBool(ayBank[curEffect].ayEffect[ln].sel,false)) return true;
				}
			}
		}
	}
	
	return false;
}



void EffectPlay(int off)
{
	int aa,pp,icnt,frames,slen,flen,ifrq;
	short int *buf;
	
	if(wave)
	{
		free(wave);
		wave=NULL;
	}
	
    ifrq=MIXRATE/50;
	frames=EffectRealLen(curEffect)+3-off;//плюс, чтобы точно отзвучало полностью
	slen=ifrq*frames;
	
	flen=slen*2+44;
	wave=(unsigned char*)malloc(flen);
	
	memcpy(wave,"RIFF",4);//id riff-файла
	WrDWordLH(&wave[4],flen-8);//размер файла минус 8
	memcpy(&wave[8],"WAVEfmt ",8);//id формата
	WrDWordLH(&wave[16],16);//размер заголовка
	WrWordLH(&wave[20],1);//формат PCM
	WrWordLH(&wave[22],1);//моно
	WrDWordLH(&wave[24],MIXRATE);//частота дискретизации
	WrDWordLH(&wave[28],MIXRATE*2);//byterate (mixrate*channels*bytespersample)
	WrDWordLH(&wave[32],2);//кол-во байт на сэмпл (channels*bytespersample)
	WrDWordLH(&wave[34],16);//кол-во бит на один сэмпл
	memcpy(&wave[36],"data",4);//id данных
	WrDWordLH(&wave[40],slen*2);//размер данных в байтах
	pp=44;
	
	
	buf=(short int*)(wave+pp);//оффсет после заголовка
	
	icnt=0;
	ay_init(&ayChip);
	pp=off;
	
	for(aa=0;aa<slen;aa++)
	{
		ay_tick(&ayChip,(1773400/MIXRATE/8));
		if(icnt++>=ifrq)
		{
			icnt=0;
			if(pp<max_fx_len)
			{
				ay_out(&ayChip,0,ayBank[curEffect].ayEffect[pp].tone&255);
				ay_out(&ayChip,1,ayBank[curEffect].ayEffect[pp].tone>>8);
				ay_out(&ayChip,6,ayBank[curEffect].ayEffect[pp].noise);
				ay_out(&ayChip,7,0xf6|(ayBank[curEffect].ayEffect[pp].t?0:1)|(ayBank[curEffect].ayEffect[pp].n?0:8));
				ay_out(&ayChip,8,ayBank[curEffect].ayEffect[pp].volume);
			}
			pp++;
		}
		
		buf[aa]=volTab[ayChip.dac[0]];
	}
	
	PlaySound(wave,NULL,SND_MEMORY|SND_ASYNC);
}


void EffectStop(void)
{
	PlaySound(NULL,NULL,NULL);
	if(wave)
	{
		free(wave);
		wave=NULL;
	}
}



void __fastcall TForm1::HoldCheck(int X,int Y)
{
	bool hold;
	int xmin,xmax;
	RECT clip;
	TPoint tpos;
	
	hold=false;
	
	if(Y>=edit_head+edit_yoff&&Y<edit_head+edit_yoff+line_onscr*line_hgt)
	{
		if(X>=edit_xoff&&X<=edit_xoff+pos_wdt)
		{
			xmin=edit_xoff;
			xmax=edit_xoff+pos_wdt;
			hold=true;
		}
		if(X>=edit_xoff+tflag_off&&X<=edit_xoff+tflag_off+tflag_wdt)
		{
			xmin=edit_xoff+tflag_off;
			xmax=edit_xoff+tflag_off+tflag_wdt;
			hold=true;
		}
		if(X>=edit_xoff+nflag_off&&X<=edit_xoff+nflag_off+nflag_wdt)
		{
			xmin=edit_xoff+nflag_off;
			xmax=edit_xoff+nflag_off+nflag_wdt;
			hold=true;
		}
		if(X>=edit_xoff+tone_off-2&&X<=edit_xoff+tone_off+tone_wdt)
		{
			xmin=edit_xoff+tone_off-2;
			xmax=edit_xoff+tone_off+tone_wdt;
			hold=true;
		}
		if(X>=edit_xoff+noise_off-2&&X<=edit_xoff+noise_off+noise_wdt)
		{
			xmin=edit_xoff+noise_off-2;
			xmax=edit_xoff+noise_off+noise_wdt;
			hold=true;
		}
		if(X>=edit_xoff+vol_off-2&&X<=edit_xoff+vol_off+vol_wdt)
		{
			xmin=edit_xoff+vol_off-2;
			xmax=edit_xoff+vol_off+vol_wdt;
			hold=true;
		}
		
		if(hold)
		{
			tpos.x=0;
			tpos.y=0;
			tpos=ClientToScreen(tpos);
			clip.left=tpos.x+xmin;
			clip.right=tpos.x+xmax+1;
			clip.top=tpos.y+edit_yoff+edit_head;
			clip.bottom=tpos.y+edit_yoff+edit_head+line_onscr*line_hgt;
			ClipCursor(&clip);
		}
	}
}


void HoldRelease(void)
{
	ClipCursor(NULL);
}



void BankInit(void)
{
	int aa,bb;
	char name[16];
	for(aa=0;aa<max_fx_all;aa++)
	{
		for(bb=0;bb<max_fx_len;bb++) EffectDefaultStr(ayBank[aa].ayEffect[bb]);
		sprintf(name,"noname%3.3i",aa+1);
		strcpy(ayBank[aa].name,name);
	}
	curEffect=0;
	allEffect=1;
}


void __fastcall TForm1::BankUpdateCount(void)
{
	char str[16];
	sprintf(str,"%3.3i/%3.3i",curEffect+1,allEffect);
	Edit3->Text=str;
	Edit4->Text=ayBank[curEffect].name;
}



bool BankSave(const char *filename,bool names)
{
	FILE *file;
	unsigned char *buf;
	int aa,size,pp,off,len;
	
	size=max_fx_len*allEffect+260*allEffect;
	buf=(unsigned char*)malloc(size);
	
	buf[0]=allEffect&0xff;
	pp=2*allEffect+1;
	
	for(aa=0;aa<allEffect;aa++)
	{
		off=pp-aa*2-2;
		WrWordLH(&buf[1+aa*2],off);
		len=EffectEncode(aa,&buf[pp]);
		pp+=len;
		
		if(names&&ayBank[aa].name[0]!=0)
		{
			strcpy(&buf[pp],ayBank[aa].name);
			pp+=strlen(ayBank[aa].name);
			buf[pp++]=0;
		}
	}
	
	size=pp;
	
	file=fopen(filename,"wb");
	if(!file)
	{
		free(buf);
		return false;
	}
	fwrite(buf,size,1,file);
	fclose(file);
	free(buf);
	return true;
}



bool BankLoad(const char *filename)
{
	FILE *file;
	unsigned char *buf;
	char name[16];
	int aa,size,len,rlen,off;
	
	file=fopen(filename,"rb");
	if(!file) return false;
	fseek(file,0,SEEK_END);
	size=ftell(file);
	fseek(file,0,SEEK_SET);
	buf=(unsigned char*)malloc(size);
	fread(buf,size,1,file);
	fclose(file);
	
	BankInit();
	
	allEffect=buf[0];
	
	for(aa=0;aa<allEffect;aa++)
	{
		off=RdWordLH(&buf[1+aa*2])+2+aa*2;
		if(aa<allEffect-1)
		{
			len=RdWordLH(&buf[3+aa*2])+4+aa*2-off;
		}
		else
		{
			len=size-off;
		}
		rlen=EffectDecode(aa,&buf[off],len);
		
		if(rlen!=len)
		{
			strcpy(ayBank[aa].name,&buf[off+rlen]);
		}
		else
		{
			sprintf(name,"noname%3.3i",aa+1);
			strcpy(ayBank[aa].name,name);
		}
	}
	
	free(buf);
	
	return true;
}



bool BankAddEffect(void)
{
	if(allEffect>=256) return false;
	EffectInit(allEffect);
	allEffect++;
	return true;
}



bool BankDeleteEffect(int fxn)
{
	int aa;
	if(allEffect==1)
	{
		EffectInit(fxn);
		return true;
	}
	for(aa=fxn;aa<max_fx_all-1;aa++) ayBank[aa]=ayBank[aa+1];
	EffectInit(max_fx_all-1);
	allEffect--;
	return true;
}



bool BankInsertEffect(int fxn)
{
	int aa;
	char str[256];
	if(allEffect>=256) return false;
	for(aa=max_fx_all-1;aa>fxn;aa--) ayBank[aa]=ayBank[aa-1];
	EffectInit(fxn);
	sprintf(str,"inserted%3.3i",fxn);
	strcpy(ayBank[fxn].name,str);
	allEffect++;
	return true;
}



void __fastcall TForm1::EffectSwitchEnable(void)
{
	if(curEffect>0) SpeedButton3->Enabled=true; else SpeedButton3->Enabled=false;
	if(curEffect<allEffect-1) SpeedButton7->Enabled=true; else SpeedButton7->Enabled=false;
	if(curEffect==0) SpeedButton4->Enabled=false; else SpeedButton4->Enabled=true;
	if(curEffect<allEffect-1) SpeedButton5->Enabled=true; else SpeedButton5->Enabled=false;
}



void __fastcall TForm1::EnterFromPiano(int div,bool st,int vol,int step,int fill)
{
int aa;

for(aa=0;aa<fill;aa++)
{
if(curYpos+aa>=max_fx_len) break;
ayBank[curEffect].ayEffect[curYpos+aa].tone=div;
if(st) ayBank[curEffect].ayEffect[curYpos+aa].t=true;
if(vol>=0) ayBank[curEffect].ayEffect[curYpos+aa].volume=vol;
}

for(aa=0;aa<step;aa++)
{
		if(curYpos<max_fx_len-1)
		{
			curYpos++;
			if(curYpos>=curOffset+line_onscr)
			{
				curOffset++;
				if(curOffset>max_fx_len-line_onscr) curOffset=max_fx_len-line_onscr;
			}
		}
                }
DrawEdit(false);
}


#include "import_wav.h"
#include "import_psg.h"
#include "import_vtx.h"


//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Close1Click(TObject *Sender)
{
	//надо-бы спрашивать, хочет-ли юзер закрыть
	Close();
}
//---------------------------------------------------------------------------


void __fastcall TForm1::FormPaint(TObject *Sender)
{
	DrawEdit(true);
}
//---------------------------------------------------------------------------


void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,
									  TShiftState Shift, int X, int Y)
{
	bool upd;
	
	if(no_click) return;
	
	mousePrev.y=Y;
	mousePrev.x=X;
	
	if(Shift.Contains(ssLeft)||Shift.Contains(ssRight)) HoldCheck(X,Y);
	if(MouseCheck(X,Y,Shift,false)) DrawEdit(false);
	
	if(Y>=edit_yoff+edit_head&&Y<edit_yoff+edit_head+line_onscr*line_hgt)
	{
		upd=false;
		if(X>=edit_xoff+tcol_off&&X<=edit_xoff+tcol_off+tcol_wdt)
		{
			curXpos=0;
			upd=true;
		}
		if(X>=edit_xoff+ncol_off&&X<=edit_xoff+ncol_off+ncol_wdt)
		{
			curXpos=1;
			upd=true;
		}
		if(X>=edit_xoff+vcol_off&&X<=edit_xoff+vcol_off+vcol_wdt)
		{
			curXpos=2;
			upd=true;
		}
		if(upd)
		{
			curYpos=curOffset+(Y-edit_yoff-edit_head)/line_hgt;
			DrawEdit(false);
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift,
									  int X, int Y)
{
	bool redraw;
	int delta,yy,ys;
	float xx,xs;
	
	if(no_click) return;
	if(Shift.Contains(ssLeft)||Shift.Contains(ssRight)) HoldCheck(X,Y);
	
	delta=labs(mousePrev.y-Y);
	
	if(mousePrev.y>=0&&delta>=line_hgt)
	{
		redraw=false;
		yy=mousePrev.y;
		xx=float(mousePrev.x);
		xs=(float(X)-xx)/float(delta);
		if(mousePrev.y<Y) ys=1; else ys=0-1;
		while(delta>=0)
		{
            if(MouseCheck(int(xx),yy,Shift,true)) redraw=true;
            yy+=ys;
            xx+=xs;
            delta-=1;
		}
		
		if(redraw) DrawEdit(false);
	}
	else
	{
		if(MouseCheck(X,Y,Shift,true)) DrawEdit(false);
	}
	
	mousePrev.y=Y;
	mousePrev.x=X;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,
									TShiftState Shift)
{
	int aa,len,num,nval;
	
	if(Shift.Contains(ssCtrl))
	{
		switch(Key)
		{
		case 'A':
			len=EffectRealLen(curEffect);
			for(aa=0;aa<len;aa++) ayBank[curEffect].ayEffect[aa].sel=true;
			DrawEdit(false);
			return;
		case 'I':
			len=EffectRealLen(curEffect);
			for(aa=0;aa<len;aa++) ayBank[curEffect].ayEffect[aa].sel=!ayBank[curEffect].ayEffect[aa].sel;
			DrawEdit(false);
			return;
		case 'Z':
			//undo
			return;
		case 'X':
			EffectCut(curEffect);
			DrawEdit(false);
			return;
		case 'C':
			EffectCopy(curEffect,true);
			DrawEdit(false);
			return;
		case 'V':
			EffectPaste(curEffect);
			DrawEdit(false);
			return;
		}
	}
	
	num=-1;
	if(Key>='0'&&Key<='9') num=Key-'0';
	if(Key>='A'&&Key<='F') num=Key-'A'+10;
	
	if(num>=0)
	{
		switch(curXpos)
		{
		case 0:
			ayBank[curEffect].ayEffect[curYpos].tone=((ayBank[curEffect].ayEffect[curYpos].tone<<4)|num)&0xfff;
			break;
		case 1:
			nval=((ayBank[curEffect].ayEffect[curYpos].noise<<4)|num)&0xff;
			if(nval<=0x1f) ayBank[curEffect].ayEffect[curYpos].noise=nval; else ayBank[curEffect].ayEffect[curYpos].noise=num;
			break;
		case 2:
			ayBank[curEffect].ayEffect[curYpos].volume=num;
			break;
		}
		DrawEdit(false);
		return;
	}
	
	switch(Key)
	{
	case VK_ADD:
		SpeedButton7Click(Sender);
		return;
	case VK_SUBTRACT:
		SpeedButton3Click(Sender);
		return;
		
	case VK_UP:
		if(curYpos>0)
		{
			curYpos--;
			if(curYpos<curOffset)
			{
				curOffset--;
				if(curOffset<0) curOffset=0;
			}
			DrawEdit(false);
		}
		break;
	case VK_DOWN:
		if(curYpos<max_fx_len-1)
		{
			curYpos++;
			if(curYpos>=curOffset+line_onscr)
			{
				curOffset++;
				if(curOffset>max_fx_len-line_onscr) curOffset=max_fx_len-line_onscr;
			}
			DrawEdit(false);
		}
		break;
	case VK_LEFT:
		curXpos--;
		if(curXpos<0) curXpos=2;
		DrawEdit(false);
		break;
	case VK_RIGHT:
		curXpos++;
		if(curXpos>2) curXpos=0;
		DrawEdit(false);
		break;
	case VK_PRIOR:
		curYpos-=line_onscr;
		if(curYpos<0) curYpos=0;
		curOffset-=line_onscr;
		if(curOffset<0) curOffset=0;
		DrawEdit(false);
		break;
	case VK_NEXT:
		curYpos+=line_onscr;
		if(curYpos>=max_fx_len) curYpos=max_fx_len-1;
		curOffset+=line_onscr;
		if(curOffset>max_fx_len-line_onscr) curOffset=max_fx_len-line_onscr;
		DrawEdit(false);
		break;
	case VK_HOME:
		if(curYpos>0)
		{
			curYpos=0;
			CenterView();
			DrawEdit(false);
		}
		break;
	case VK_END:
		curYpos=EffectRealLen(curEffect)-1;
		if(curYpos<0) curYpos=0;
		CenterView();
		DrawEdit(false);
		break;
	case VK_RETURN:
		if(Shift.Contains(ssCtrl))
		{
			EffectPlay(curYpos);
		}
		else
		{
			EffectPlay(0);
		}
		break;
	case VK_SPACE:
		EffectStop();
		break;
	case VK_DELETE:
		if(!EffectDeleteSel(curEffect))
		{
			ayBank[curEffect].ayEffect[curYpos].sel=true;
			EffectDeleteSel(curEffect);
		}
		DrawEdit(false);
		break;
	case VK_INSERT:
        if(Shift.Contains(ssShift))
        {
			EffectInsertStr(curEffect,curYpos,false);
		}
		else
		{
			EffectInsertStr(curEffect,curYpos,true);
		}
		DrawEdit(false);
		break;
	case 'T':
		ayBank[curEffect].ayEffect[curYpos].t=!ayBank[curEffect].ayEffect[curYpos].t;
		DrawEdit(false);
		break;
	case 'N':
		ayBank[curEffect].ayEffect[curYpos].n=!ayBank[curEffect].ayEffect[curYpos].n;
		DrawEdit(false);
		break;
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::New1Click(TObject *Sender)
{
	EffectInit(curEffect);
	DrawEdit(false);
	BankUpdateCount();
	no_click=50;
}
//---------------------------------------------------------------------------

int window_border;

void __fastcall TForm1::FormCreate(TObject *Sender)
{
	int aa;
	
	mousePrev.y=-1;
	mousePrev.x=-1;
	BankInit();
	EffectInit(curEffect);
	TitleUpdate();
	no_click=0;
	window_border=Height-ClientHeight;
	Linperiod1Click(Sender);
	for(aa=0;aa<max_fx_len;aa++) EffectDefaultStr(ayClipboard[aa]);
	clipLen=0;
	BankUpdateCount();
	EffectSwitchEnable();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
{
	EffectPlay(0);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButton2Click(TObject *Sender)
{
	EffectStop();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Load1Click(TObject *Sender)
{
	if(OpenDialog1->Execute())
	{
		if(EffectLoad(curEffect,OpenDialog1->FileName.c_str()))
		{
			BankUpdateCount();
			DrawEdit(false);
			no_click=50;
		}
		else
		{
			Application->MessageBox("Can't load effect!","Error",MB_OK);
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SaveFX1Click(TObject *Sender)
{
	if(EffectRealLen(curEffect)==0)
	{
		Application->MessageBox("Effect is empty, nothing to save.","Save effect",MB_OK);
	}
	else
	{
		SaveDialog1->FileName=AnsiString(ayBank[curEffect].name)+".afx";
		if(SaveDialog1->Execute())
		{
			EffectSave(curEffect,SaveDialog1->FileName.c_str());
			no_click=50;
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormMouseWheelDown(TObject *Sender,
										   TShiftState Shift, TPoint &MousePos, bool &Handled)
{
	if(curYpos<max_fx_len-1)
	{
		curYpos+=5;
		if(curYpos>=max_fx_len) curYpos=max_fx_len-1;
		if(curYpos>=curOffset+line_onscr)
		{
			curOffset=curYpos-line_onscr+1;
			if(curOffset>max_fx_len-line_onscr) curOffset=max_fx_len-line_onscr;
		}
		DrawEdit(false);
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormMouseWheelUp(TObject *Sender,
										 TShiftState Shift, TPoint &MousePos, bool &Handled)
{
	if(curYpos>0)
	{
		curYpos-=5;
		if(curYpos<0) curYpos=0;
		if(curYpos<curOffset)
		{
			curOffset=curYpos;
		}
		DrawEdit(false);
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormResize(TObject *Sender)
{
	DrawEdit(true);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCanResize(TObject *Sender, int &NewWidth,
									  int &NewHeight, bool &Resize)
{
	NewWidth=Width;
	if(NewHeight<200) NewHeight=200;
	NewHeight=(NewHeight-edit_yoff-edit_head-(window_border))/line_hgt*line_hgt+edit_yoff+edit_head+(window_border);
	line_onscr=(NewHeight-edit_yoff-edit_head-window_border)/line_hgt;
}
//---------------------------------------------------------------------------





void __fastcall TForm1::Importfromwav1Click(TObject *Sender)
{
	OpenDialog2->Title="Load wave file";
	OpenDialog2->DefaultExt="wav";
	OpenDialog2->Filter="Windows sound file (*.wav)|*.wav";
	if(OpenDialog2->Execute())
	{
		if(ImportWAV(curEffect,OpenDialog2->FileName.c_str()))
		{
			SaveDialog1->FileName="imported.afx";
			TitleUpdate();
			BankUpdateCount();
			DrawEdit(false);
			no_click=50;
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button,
									TShiftState Shift, int X, int Y)
{
	HoldRelease();
	mousePrev.y=-1;
	mousePrev.x=-1;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
	if(no_click>0) no_click--;
}
//---------------------------------------------------------------------------


void __fastcall TForm1::PSG1Click(TObject *Sender)
{
	OpenDialog2->Title="Load PSG file";
	OpenDialog2->DefaultExt="psg";
	OpenDialog2->Filter="PSG AY register dump (*.psg)|*.psg";
	if(OpenDialog2->Execute())
	{
		Form2->ShowModal();
		if(ImportPSG(curEffect,OpenDialog2->FileName.c_str(),import_chan))
		{
			SaveDialog1->FileName="imported.afx";
			TitleUpdate();
			BankUpdateCount();
			DrawEdit(false);
			no_click=50;
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Unselectall1Click(TObject *Sender)
{
	int aa;
	for(aa=0;aa<max_fx_len;aa++) ayBank[curEffect].ayEffect[aa].sel=false;
	DrawEdit(false);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Selectall1Click(TObject *Sender)
{
	int aa,len;
	len=EffectRealLen(curEffect);
	for(aa=0;aa<len;aa++) ayBank[curEffect].ayEffect[aa].sel=true;
	DrawEdit(false);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Inverseselection1Click(TObject *Sender)
{
	int aa,len;
	len=EffectRealLen(curEffect);
	for(aa=0;aa<len;aa++) ayBank[curEffect].ayEffect[aa].sel=!ayBank[curEffect].ayEffect[aa].sel;
	DrawEdit(false);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Deleteselection1Click(TObject *Sender)
{
	if(!EffectDeleteSel(curEffect))
	{
		ayBank[curEffect].ayEffect[curYpos].sel=true;
		EffectDeleteSel(curEffect);
	}
	DrawEdit(false);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Linperiod1Click(TObject *Sender)
{
	Linperiod1->Checked=true;
	period_linear=true;
	DrawEdit(true);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Logperiod1Click(TObject *Sender)
{
	Logperiod1->Checked=true;
	period_linear=false;
	DrawEdit(true);
}
//---------------------------------------------------------------------------



void __fastcall TForm1::FormActivate(TObject *Sender)
{
	form_focus=true;	
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormDeactivate(TObject *Sender)
{
	form_focus=false;	
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Copy1Click(TObject *Sender)
{
	EffectCopy(curEffect,true);
	DrawEdit(false);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Cut1Click(TObject *Sender)
{
	EffectCut(curEffect);
	DrawEdit(false);	
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Paste1Click(TObject *Sender)
{
	EffectPaste(curEffect);
	DrawEdit(false);	
}
//---------------------------------------------------------------------------


void __fastcall TForm1::VortexVTX1Click(TObject *Sender)
{
	OpenDialog2->Title="Load VTX file";
	OpenDialog2->DefaultExt="vtx";
	OpenDialog2->Filter="VTX AY register dump (*.vtx)|*.vtx";
	if(OpenDialog2->Execute())
	{
		Form2->ShowModal();
		if(ImportVTX(curEffect,OpenDialog2->FileName.c_str(),import_chan))
		{
			SaveDialog1->FileName="imported.afx";
			TitleUpdate();
			BankUpdateCount();
			DrawEdit(false);
			no_click=50;
		}
	}
}
//---------------------------------------------------------------------------


void __fastcall TForm1::Newbank1Click(TObject *Sender)
{
	BankInit();
	DrawEdit(true);
	BankUpdateCount();
	SaveDialog2->FileName="noname.afb";
	TitleUpdate();
	no_click=50;
	EffectSwitchEnable();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButton3Click(TObject *Sender)
{
	if(curEffect>0)
	{
		curEffect--;
		BankUpdateCount();
		DrawEdit(true);
		EffectSwitchEnable();
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButton7Click(TObject *Sender)
{
	if(curEffect<allEffect-1)
	{
		curEffect++;
		BankUpdateCount();
		DrawEdit(true);
		EffectSwitchEnable();
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Multiloadtobank1Click(TObject *Sender)
{
	int aa,pp;
	if(OpenDialog3->Execute())
	{
		pp=allEffect-1;
		if(EffectRealLen(pp)>0) pp+=1;
		
		for(aa=0;aa<OpenDialog3->Files->Count;aa++)
		{
			if(pp>=256) break;
			if(!EffectLoad(pp,OpenDialog3->Files->Strings[aa].c_str()))
			{
				Application->MessageBox(("Can't load effect '"+OpenDialog3->Files->Strings[aa]+"'!").c_str(),"Error",MB_OK);
			}
			else
			{
				SpeedButton9->Enabled=true;
				Deleteeffect1->Enabled=true;
			}
			pp++;
		}
		allEffect=pp;
		
		TitleUpdate();
		BankUpdateCount();
		DrawEdit(false);
		EffectSwitchEnable();
		no_click=50;
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SaveFXbank1Click(TObject *Sender)
{
	if(SaveDialog2->Execute())
	{
		BankSave(SaveDialog2->FileName.c_str(),true);
		TitleUpdate();
		no_click=50;
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::LoadFXbank1Click(TObject *Sender)
{
	if(OpenDialog4->Execute())
	{
		if(BankLoad(OpenDialog4->FileName.c_str()))
		{
			SaveDialog2->FileName=OpenDialog4->FileName;
			TitleUpdate();
			DrawEdit(false);
			BankUpdateCount();
			EffectSwitchEnable();
			no_click=50;
		}
		else
		{
			Application->MessageBox("Can't load bank!","Error",MB_OK);
		}
	}
}
//---------------------------------------------------------------------------




void __fastcall TForm1::Savebankwonames1Click(TObject *Sender)
{
	if(SaveDialog2->Execute())
	{
		BankSave(SaveDialog2->FileName.c_str(),false);
		TitleUpdate();
		no_click=50;
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Edit4KeyPress(TObject *Sender, char &Key)
{
	if(Key==VK_RETURN)
	{
		Edit4->Enabled=false;
		Edit4->Enabled=true;
		Edit4->ReadOnly=true;
		Edit4->Font->Color=clGrayText;
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Edit4Click(TObject *Sender)
{
	Edit4->ReadOnly=false;
	Edit4->Font->Color=clWindowText;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Edit4Change(TObject *Sender)
{
	strcpy(ayBank[curEffect].name,Edit4->Text.c_str());	
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Addeffecttoend1Click(TObject *Sender)
{
	SpeedButton8Click(Sender);	
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButton8Click(TObject *Sender)
{
	if(BankAddEffect())
	{
        curEffect=allEffect-1;
		BankUpdateCount();
		DrawEdit(true);
        SpeedButton9->Enabled=true;
		Deleteeffect1->Enabled=true;
		EffectSwitchEnable();
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButton9Click(TObject *Sender)
{
	if(Application->MessageBox("Delete effect?","Sure?",MB_YESNO)==IDYES)
	{
		if(BankDeleteEffect(curEffect))
		{
			if(curEffect>=allEffect&&curEffect>0) curEffect=allEffect-1;
			BankUpdateCount();
			DrawEdit(true);
			if(allEffect==1)
			{
				SpeedButton9->Enabled=false;
				Deleteeffect1->Enabled=false;
				EffectSwitchEnable();
			}
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Deleteeffect1Click(TObject *Sender)
{
	SpeedButton9Click(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Inserteffect1Click(TObject *Sender)
{
	if(BankInsertEffect(curEffect))
	{
		BankUpdateCount();
		DrawEdit(true);
		SpeedButton9->Enabled=true;
		Deleteeffect1->Enabled=true;
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Multisavefrombank1Click(TObject *Sender)
{
	int aa;
	AnsiString name;
	char str[256];
	
	name="";
	for(aa=0;aa<allEffect;aa++)
	{
		if(EffectRealLen(aa)>0)
		{
			name=ayBank[aa].name;
			if(name=="")
			{
				sprintf(str,"%s%3.3i",NameTrimPath(SaveDialog2->FileName).c_str(),aa);
				name=str;
			}
			break;
		}
	}
	
	if(name!="")
	{
		SaveDialog3->FileName=name+".afx";
		if(SaveDialog3->Execute())
		{
			for(aa=0;aa<allEffect;aa++)
			{
				if(EffectRealLen(aa)>0)
				{
					name=ayBank[aa].name;
					if(name=="")
					{
						sprintf(str,"%s%3.3i",NameTrimPath(SaveDialog2->FileName).c_str(),aa);
						name=str;
					}
					name=SaveDialog3->FileName.SubString(1,SaveDialog3->FileName.LastDelimiter("\\/"))+name+".afx";
					if(FileExists(name))
					{
						if(Application->MessageBox(("File '"+name+"' already exists, overwrite?").c_str(),"Confirm",MB_YESNO)==IDNO) continue;
					}
					
					EffectSave(aa,name.c_str());
					no_click=50;
				}
			}
		}
	}
	else
	{
		Application->MessageBox("Bank is empty, nothing to save.","Multi-save",MB_OK);
	}
}
//---------------------------------------------------------------------------


void __fastcall TForm1::SpeedButton4Click(TObject *Sender)
{
	if(curEffect>0)
	{
		curEffect=0;
		BankUpdateCount();
		DrawEdit(true);
		EffectSwitchEnable();
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButton5Click(TObject *Sender)
{
	if(curEffect<allEffect-1)
	{
		curEffect=allEffect-1;
		BankUpdateCount();
		DrawEdit(true);
		EffectSwitchEnable();
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Pianoinput1Click(TObject *Sender)
{
	SpeedButton6->Down=!SpeedButton6->Down;
	Pianoinput1->Checked=SpeedButton6->Down;
	Form3->Visible=SpeedButton6->Down;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButton6Click(TObject *Sender)
{
	//
	Pianoinput1->Checked=SpeedButton6->Down;
	Form3->Visible=SpeedButton6->Down;
}
//---------------------------------------------------------------------------

