/*
    PsyTexx: psytexx.c. Main appliction.
    Copyright (C) 2004  Zolotov Alexandr

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
//*** Contact info: Zolotov Alexandr (NightRadio project)
//***               Ekaterinburg. Russia.
//***               Email: observer_page@mail.ru
//***                      warmplace@warmplace.ru
//***                      nightradio@knoppix.ru
//***               WWW: warmplace.ru

#include <PalmOS.h>
#include "sound.h"
#include "audio.h"
#include "mod.h"
#include "sampler.h"

//If you want to run PsyTexx in the Simulator:
//#define SIMULATOR
#define DLL_DIR "psytexx_win32.dll\0ARMlet_Main"

#define _srmControl(p1,p2,p3,p4) \
  if(model==1){value32=0;}\
  else{SrmControl(p1,p2,p3,p4);}
SndStreamRef main_stream;
void fillb(uchar*,uchar*);
Err main_callback(void*,SndStreamRef,void*,UInt32);

Boolean FormHandle_sampler(EventPtr event) sec1;
Boolean FormHandle(EventPtr event) sec2;

void select_note(int,int,ulong) sec3;
void select_note2(int,int) sec4;
void select_pattern(int,int);
void GetEvent(ulong);
void drawmodlist(void);
void drawSMPlist(void);
void setSMPpars(void);
void getSMPpars(void);
void getVOLUME(void);
void setVOLUME(void);
void saveSAMPLENAME(void);
void closeSAMPLENAME(void);
void closeFILENAME(void);
void drawSAMPLENAME(void);
void drawFILENAME(void);
void soundCLOSE(void);
void soundINIT(void);
void soundREPLAY(void);
void reINITsound(void);
void drawChar(UInt16,UInt16); //Draw char from MYFONT in BMP screen.
void drawText(UInt16,char*); //Draw text in BMP screen.
void drawNum(UInt16,UInt16); //Draw number (0 - FF) in BMP screen.
int  drawPattern(); //Draw current pattern in BMP screen.
void DrawPattern();
void playnote1(uint,uint,channel*,ulong); //Play note (clone for record mode).
void ClearPatterns(void);
void ClearSamples(void);
void ChangeChannels(uint); //Change number of channels
void backup(void);
void undo_backup(void);
void clone(void); //Clone current MOD;
void copyC(UInt16,char*); //Copy channel in current pattern.
void clearC(UInt16);      //Clear channel in current pattern.
void pasteC(UInt16,char*);//Paste channel to current pattern.
void drawScroll(int);
uint get_note(int,int);
uint get_ins(int,int);
uint get_effect(int,int);
uint get_effect_par(int,int);
void set_note(int,int,uint);
void set_ins(int,int,uint);
void set_effect(int,int,uint);
void set_effect_par(int,int,uint);

void drawChar2(UInt16,long,UInt16); //Draw char from MYFONT2 in BMP screen.
void draw_str(unsigned char*);
void one_demoframe(void);
void draw_scope(UInt16);

void get_global_options(void);
void set_global_options(void);
void saveOPTIONS(void);
void loadOPTIONS(void);

static FormPtr gpForm;

char str[128];
int index=0;
Err err;
long value32;
UInt16 port=0,vlen,c,new_freq;
long a,b,bb,b1,b2,b3,b4,b5,b6;
DmOpenRef db;
MemHandle h;
char *m;
int autooff;

uint freq=22050;
ulong volume=8;

uint note_table1[14]={0,1,1,3,3,4,5,6,6,8,8,10,10,11}; //Up
uint note_table2[14]={0,0,2,2,4,4,5,5,7,7,9,9,11,11};  //Down
uint samp=0; //current sample;
uint rec_status=0; //1-record mode;
uint cur_c=0,cur_p=0; //Current channel and horisontal position of cursor;
int  ppnt=0; //Pattern position pointer;
int p_mode=1; //Anim patterns: 1-ON 0-OFF

int demo_mode=0;
UInt16 text_y[20]={8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8};
unsigned char dtext[20]="                    ";
unsigned char *demo_text="      PsyTexx        Amiga MOD  Tracker      for PALMOS              by         [c] Zolotov Alexandr";
int toffset=0,tsize=100;
int demo_timer1=38;
int demo_timer2=0;

EventType event;
UInt16 error;
char *start_header="END.";
ListType *list,*list2,*freqlist;
FieldType *filename;
FieldType *helpfield;
char *texts[64];  //Files
char *texts2[31]; //Samples
char *nofile[1]={"no files"};
int curFILE=0; //Current file number in list
uint curMOD=0; //Current loaded file number in list

unsigned char *bmpP,*scroll_bmpP,*bmp2P,*backupP;
BitmapType *bmp_old,*scroll_bmp;
BitmapType *bmp2,*bmp22;
BitmapType *bmp,*backup_bmp;
UInt16 bmp_err;
int scroll_pos=0;
MemHandle myfont,myfont2,myfont3,bmpR,fname,about_pic;
unsigned char *about_picH;
char *myfontH,*myfont2H,*myfont3H,*fnameP;
char char_mode=0; //0-normal; 1-bold;
char char_invert=0; //0-normal; 1-invert;
char null_str[21]={83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,96};
uchar up_str[21]={94+24,83+24,84+24,83+24,85+24,83+24,95+24,83+24,
86+24,83+24,87+24,83+24,88+24,89+24,90+24,83+24,91+24,92+24,93+24,83+24,96+24};
char copy_buffer1[4048]; //Copy buffer for pattern.
char copy_buffer2[1024];  //Copy buffer for channel.


//************************************************
//********* NEW GENERATION ADDITION :) ***********
//************************************************
void add1(); //additional function 1
void add2(); //additional function 1
void add3(); //additional function 1
void add4(); //additional function 1
void add5(); //additional function 1
//#define PatDraw if(FrmGetActiveFormID()==EditorForm) WinDrawBitmap(bmp_old,0,-1)
#define PatDraw if(FrmGetActiveFormID()==EditorForm) WinDrawBitmap(bmp,0,-1)
#define PAT_SCREEN_X 160 * 2
#define PAT_SCREEN_Y 56*2 * 2
long CHAR_SIZE = 16; 
long CHAR_SIZE_Y = 16; //sizes: 16x16; 10x16; 10x8; 8x8
long CHAR_SIZES[4][2] = {16,16, 10,16, 10,8, 8,8}; //all available sizes (x,y)
long CURRENT_SIZE = 0;
long MAX_SIZE_NUM = 3;
int old_form; //previous form
int START_CHANNEL = 0;
#define CalcPatFirstLine PAT_FIRST_LINE = PAT_SCREEN_Y/CHAR_SIZE_Y/2 - UP_EMPTY_LINES;
long PAT_FIRST_LINE = 5;
long UP_EMPTY_LINES = 2;

MemHandle SAMPLENAME;

typedef struct {
	long x;  //x coord
	long y;  //y coord
	long cc; //char code
    long SCREEN_X;
	long CHAR_SIZE;
	long CHAR_SIZE_Y;
	long char_mode;
	long char_invert;
	unsigned char *bmpP; //screen pointer
	unsigned char *myfontH; //font pointer
} render_info;

render_info render;
MemHandle arm_renderH;
MemPtr    arm_render;

MemHandle help_text_handler;
char *help_text_ptr;

MemHandle echo;
signed short *echoP;

int current_octave = 12;
int view_accords = 0;

FormActiveStateType current_state;
//************************************************
//************************************************
//************************************************


void _sampler_load()
{
  Sampler_load(sampledata[samp],
               song.samples[samp].length,
               song.samples[samp].reppnt,
               song.samples[samp].replen);
}

void _sampler_draw()
{
  draw_sample(bmpP,1120);WinDrawBitmap(bmp,0,44);
}

long interpolate( long v1, long v2, long pos )  //pos: 0..255
{
	return ((v1 * (255 - pos))>>8) + ((v2 * pos)>>8);
}

long get_pos( long v1, long v2, long cur_val )
{
	return ((cur_val-v1)<<8)/(v2-v1);
}

void empty_f( void )
{
	int a;
}

Boolean FormHandle_sampler(EventPtr event)
{
 Boolean handled=false;
 long off, off2;
 long delta;
 long v1, v2, vol, res, max;
 long data_size;
     switch(event->eType)
     {
		case menuEvent:
			switch( event->data.menu.itemID ) {
				case menu_fade:
					//Volume fade:
					mod_info._status=0;
					correct_selection();
					v1 = FrmAlert(SelVol3);
					v2 = FrmAlert(SelVol4);
					v1 *= 64;
					v2 *= 64;
					for( off = smp_sel1; off <= smp_sel2; off ++ )
					{
						vol = interpolate( v1, v2, ((off-smp_sel1)<<8)/(smp_sel2-smp_sel1) );
						res = smpP[ off ];
						res *= vol;
						res >>= 8;
						if( res > 127 ) res = 127;
						if( res < -127 ) res = -127;
						smpP[ off ] = res;
					}
					save_sample(samp);
					_sampler_draw();
					break;
				case menu_loopsmooth:
					//Smooth loop:
					mod_info._status=0;
					correct_selection();
					if( smp_start > smp_size - smp_end ) { //get data from start:
						data_size = smp_start;
						if( data_size > smp_end-smp_start ) data_size = smp_end-smp_start;
						for( off2 = smp_start-data_size, off = smp_end-data_size; off <= smp_end; off++, off2++ )
						{
							v1 = get_pos( smp_end-data_size, smp_end, off );
							v2 = v1;
							v1 = 255 - v1;
							res = ((long)smpP[ off ] * v1) >> 8;
							res += ((long)smpP[ off2 ] * v2) >> 8;
							smpP[ off ] = res;
						}
					} else { //get data from end:
						data_size = smp_size - smp_end;
						if( data_size > smp_end-smp_start ) data_size = smp_end-smp_start;
						for( off2 = smp_end, off = smp_start; off <= smp_start+data_size; off++, off2++ )
						{
							v1 = get_pos( smp_end-data_size, smp_end, off );
							v2 = v1;
							v1 = 255 - v1;
							res = ((long)smpP[ off2 ] * v1) >> 8;
							res += ((long)smpP[ off ] * v2) >> 8;
							smpP[ off ] = res;
						}
					}
					save_sample(samp);
					_sampler_draw();
					break;
				case menu_smooth:
					//Smooth:
					mod_info._status=0;
					correct_selection();
					for( off = smp_sel1; off <= smp_sel2; off ++ )
					{
						res = smpP[ off ];
						if( off+1 < smp_size ) res += smpP[ off + 1 ];
						if( off-1 >= 0 ) res += smpP[ off - 1 ];
						res /= 3;
						smpP[ off ] = res;								 
					}
					save_sample(samp);
					_sampler_draw();
					break;
				case menu_reverse:
					//Reverse:
					mod_info._status=0;
					correct_selection();
					for( off2 = 0, off = smp_sel1; off2 <= (smp_sel2-smp_sel1)>>1; off++, off2++ )
					{
						res = smpP[ off ];
						smpP[ off ] = smpP[ smp_sel2 - off2 ];
						smpP[ smp_sel2 - off2 ] = res;
					}
					save_sample(samp);
					_sampler_draw();
					break;
				case menu_normalize:
					//Normalize:
					mod_info._status=0;
					correct_selection();
					max = 0;
					for( off = smp_sel1; off <= smp_sel2; off ++ )
					{
						res = smpP[ off ];
						if( res < 0 ) res = -res;
						if( res > max ) max = res;
					}
					if( max < 127 ) {
						max = (127 << 8) / max;
						for( off = smp_sel1; off <= smp_sel2; off ++ )
						{
							res = smpP[ off ];
							res *= max;
							res >>= 8;
							smpP[ off ] = res;
						}
					}
					save_sample(samp);
					_sampler_draw();
					break;
			  }
			  break;
          case lstSelectEvent:
                       if(event->data.lstSelect.listID==SMPlist){
                         samp=LstGetSelection(list2);
                         drawScroll(2);
                         WinDrawBitmap(scroll_bmp,152,0);
                         _sampler_load();
                         set_zoom(smp_size);
                         _sampler_draw();
                       }
                       break;
          case penDownEvent:
                       if(event->screenY>110){
						 correct_selection();
						 if( smp_sel1 != smp_sel2 ) one_sample_limit = smp_sel2;
						 else one_sample_limit = 65000;
                         select_note( event->screenX, event->screenY, smp_sel1 );
						 break;
                       }

                       if(event->screenY<44){
                         if(event->screenX>151){
                           a=event->screenY-4;if(a<0){a=0;}if(a>30){a=30;} a=a/7;a=a*7;
                           samp=a;LstSetSelection(list2,samp);drawScroll(2);LstDrawList(list2);WinDrawBitmap(scroll_bmp,152,0);
                         }
                       }else{
                         if(event->screenY<55){
                           smp_start=get_sample_off(smp_offset,event->screenX);
                           if(smp_start>smp_end){smp_start=smp_end;}
                           draw_loop(bmpP);WinDrawBitmap(bmp,0,44);
                           song.samples[samp].reppnt = smp_start;
                           song.samples[samp].replen = smp_end-smp_start;
                         }
                         if(event->screenY>88){
                           if(event->screenY<100){
                             smp_end=get_sample_off(smp_offset,event->screenX);
                             if(smp_start>smp_end){smp_end=smp_start;}
                             draw_loop(bmpP);WinDrawBitmap(bmp,0,44);
                             song.samples[samp].reppnt = smp_start;
                             song.samples[samp].replen = smp_end-smp_start;
                           }
                         }
                         if(event->screenY>56){
                         if(event->screenY<88){
                           draw_block(bmpP);
                           smp_sel1=get_sample_off(smp_offset,event->screenX);
                           draw_block(bmpP);
                           WinDrawBitmap(bmp,0,44);
                         }}
                       }
                       break;
          case penMoveEvent:
                       if(event->screenY>110){
						 correct_selection();
 						 if( smp_sel1 != smp_sel2 ) one_sample_limit = smp_sel2;
						 else one_sample_limit = 65000;
                         select_note2( event->screenX, event->screenY );
						 break;
                       }

                       if(event->screenY<44){
                         if(event->screenX>151){
                           a=event->screenY-4;if(a<0){a=0;}if(a>30){a=30;} a=a/7;a=a*7;
                           samp=a;LstSetSelection(list2,samp);drawScroll(2);LstDrawList(list2);WinDrawBitmap(scroll_bmp,152,0);
                         }
                       }else{
                         if(event->screenY<55){
                           smp_start=get_sample_off(smp_offset,event->screenX);
                           if(smp_start>smp_end){smp_start=smp_end;}
                           draw_loop(bmpP);WinDrawBitmap(bmp,0,44);
                           song.samples[samp].reppnt = smp_start;
                           song.samples[samp].replen = smp_end-smp_start;
                         }
                         if(event->screenY>88){
                           if(event->screenY<100){
                             smp_end=get_sample_off(smp_offset,event->screenX);
                             if(smp_start>smp_end){smp_end=smp_start;}
                             draw_loop(bmpP);WinDrawBitmap(bmp,0,44);
                             song.samples[samp].reppnt = smp_start;
                             song.samples[samp].replen = smp_end-smp_start;
                           }
                         }
                         if(event->screenY>56){
                         if(event->screenY<88){
                           draw_block(bmpP);
                           smp_sel2=get_sample_off(smp_offset,event->screenX);
                           draw_block(bmpP);
                           WinDrawBitmap(bmp,0,44);
                         }}
                       }
                       break;
          case ctlSelectEvent:
                       switch(event->data.ctlSelect.controlID){
                         case Exit:
                           bmp=backup_bmp;
                           bmpP=backupP;
                           save_sample(samp);
                           mod_info._status=0;
                           reINITsound();
                           FrmGotoForm(SampleForm);
                           GetEvent(0);
                           GetEvent(0);
                           GetEvent(0);
                           drawSMPlist();
                           LstSetSelection(list2,samp);
                           break;
                         case Record:
						   mod_info._status=0;
                           b=FrmAlert(SelRecord);
                           if(b==5){ //from pattern
                             b=FrmAlert(SelRecFreq);
                             switch(b){
                               case 0: new_freq=8000;break;
                               case 1: new_freq=11005;break;
                               case 2: new_freq=22050;break;
                               case 3: new_freq=44100;break;
                             }
                             if(model==1){SndStreamPause(main_stream,1);}
                             mod_set_freq(new_freq);
                             mod_info._status=2;
                             WinDrawChars("RECORDING...",12,55,67);
                             for(a=0;a<60000;a+=BUFSIZE){
                               mod_info._buffer_size=BUFSIZE;
                               fillbuffer(smpP+a,&mod_info);
                             }
                             mod_info._status=0;
                             mod_set_freq(freq);
                             if(model==1){SndStreamPause(main_stream,0);}
                             smp_size=a;
                             save_sample(samp);
                           }else{
                             if(b==0){ //from microphone
                               b=FrmAlert(SelRecFreq);
                               switch(b){
                                 case 0: new_freq=8000;break;
                                 case 1: new_freq=11025;break;
                                 case 2: new_freq=22050;break;
                                 case 3: new_freq=44100;break;
                               }
                               if(model==1){SndStreamPause(main_stream,1);}
                               WinDrawChars("RECORDING...",12,55,67);
							   mod_info.record_buf = ByteSwap32( smpP );
							   mod_info.record_pos = 0;
                               rec_init(new_freq, &mod_info, arm_code);
                               while(ByteSwap32(mod_info.record_pos)<60000)
									{ empty_f(); } //Record process;
                               rec_close();
                               if(model==1){SndStreamPause(main_stream,0);}
                               song.samples[samp].volume=63;
                               smp_size=60000;
                               smp_offset=0;
                               set_zoom(smp_size);
                               save_sample(samp);
                             }
                           }
                           break;
                         case SmpLeft:
							 off = smp_offset;
							 delta = smp_zoom >> 6;
							 if( delta == 0 ) delta = 1;
							 off -= delta * 4;
							 if( off < 0 ) off = 0;
							 smp_offset = off;
							 _sampler_draw();
							 break;
                         case SmpRight:
							 off = smp_offset;
							 delta = smp_zoom >> 6;
							 if( delta == 0 ) delta = 1;
							 off += delta * 4;
							 if( off + ((smp_zoom*160)>>6) >= smp_size ) off = smp_size - ((smp_zoom*160)>>6);
							 smp_offset = off;
							 _sampler_draw();
							break;
						 case SmpIn:
							 correct_selection();
							 off = smp_offset;
							 delta = smp_zoom >> 6;
							 if( delta == 0 ) delta = 1;
							 off += delta * 8;
							 if( off + ((smp_zoom*160)>>6) >= smp_size ) off = smp_size - ((smp_zoom*160)>>6);
							 smp_offset = off;
							 set_zoom( (smp_zoom*144)>>6 );
							 _sampler_draw();
							 break;
						 case SmpOut:
							 correct_selection();
							 off = smp_offset;
							 delta = smp_zoom >> 6;
							 if( delta == 0 ) delta = 1;
							 off -= delta * 8;
							 if( off < 0 ) off = 0;
							 smp_offset = off;
							 set_zoom( (smp_zoom*176)>>6 );
							 if( off + ((smp_zoom*160)>>6) >= smp_size ) {
								 off = smp_size - ((smp_zoom*160)>>6);
								 if( off < 0 ) { off = 0; set_zoom( smp_size ); }
							 }
							 smp_offset = off;
							 _sampler_draw();
							 break;
						 case SmpAll:
							 smp_sel1 = 0;
							 smp_sel2 = smp_size - 1;
							 _sampler_draw();
							 break;
						 case SmpLoop:
							 smp_sel1 = smp_start;
							 smp_sel2 = smp_end;
							 _sampler_draw();
							 break;
                         case SmpZoom:
						   correct_selection();
                           smp_offset=smp_sel1;
                           set_zoom(smp_sel2-smp_sel1);
                           _sampler_draw();
                           break;
                         case SmpFull:
                           smp_offset=0;
                           set_zoom(smp_size);
                           _sampler_draw();
                           break;
                         case SmpCopy:
                           if(smp_sel1>smp_sel2) {a=smp_sel1;smp_sel1=smp_sel2;smp_sel2=a;}
                           for(a=smp_sel1;a<smp_sel2;a++){
                             copyP[a-smp_sel1]=smpP[a];
                           }
                           copy_size=smp_sel2-smp_sel1;
                           break;
                         case SmpPaste:
						   mod_info._status=0;
						   correct_selection();
						   if( smp_start >= smp_sel1 ) smp_start += copy_size;
						   if( smp_start > 60000 ) smp_start = 60000;
						   if( smp_end >= smp_sel1 ) smp_end += copy_size;
						   if( smp_end > 60000 ) smp_end = 60000;
                           smp_size+=copy_size;if(smp_size>60000) smp_size=60000;
                           b=smp_sel1;
                           for(a=smp_size-1;a>=(b+copy_size);a--){
                             smpP[a]=smpP[a-copy_size];
                           }
                           for(a=0;a<copy_size;a++){
                             smpP[b]=copyP[a];
                             b++; if(b>=60000) break;
                           }
                           smp_sel2=b-1;
                           save_sample(samp);
                           smp_offset=0;
                           set_zoom(smp_size);
                           _sampler_draw();
                           break;
                         case SmpCut:
							 mod_info._status=0;
							 correct_selection();
							 if( smp_start >= smp_sel1 ) {
								 if( smp_start <= smp_sel2 ) smp_start = smp_sel1;
								 else smp_start -= smp_sel2-smp_sel1;
							 }
							 if( smp_end >= smp_sel1 ) {
								 if( smp_end <= smp_sel2 ) smp_end = smp_sel1;
								 else smp_end -= smp_sel2-smp_sel1;
							 }
                           if(smp_sel1>smp_sel2) {a=smp_sel1;smp_sel1=smp_sel2;smp_sel2=a;}
                           for(a=smp_sel1;a<smp_sel2;a++){
                             copyP[a-smp_sel1]=smpP[a];
                           }
                           copy_size=smp_sel2-smp_sel1;
                           smp_size-=copy_size;
                           for(a=smp_sel1;a<smp_size;a++){
                             smpP[a]=smpP[a+copy_size];
                           }
                           smp_sel2=smp_sel1;
                           save_sample(samp);
                           smp_offset=0;
                           set_zoom(smp_size);
                           _sampler_draw();
                           break;
                         case SmpCrop:
						   mod_info._status=0;
                           if(smp_sel1>smp_sel2) {a=smp_sel1;smp_sel1=smp_sel2;smp_sel2=a;}
							 if( smp_start >= smp_sel1 ) {
								 if( smp_start <= smp_sel2 ) smp_start -= smp_sel1;
								 else smp_start = smp_sel2;
							 } else smp_start = 0;
							 if( smp_end >= smp_sel1 ) {
								 if( smp_end <= smp_sel2 ) smp_end -= smp_sel1;
								 else smp_end = smp_sel2;
							 } else smp_end = 0;
                           smp_size=smp_sel2-smp_sel1;
                           for(a=0;a<smp_size;a++){
                             smpP[a]=smpP[a+smp_sel1];
                           }
                           smp_sel1=0;smp_sel2=smp_size-1;
                           save_sample(samp);
                           smp_offset=0;
                           set_zoom(smp_size);
                           _sampler_draw();
                           break;
						 case Stop:
                           mod_info._status=0;
						   break;
                       }
          case frmOpenEvent:
                       gpForm=FrmGetActiveForm();
                       FrmDrawForm(gpForm);
                       handled=true;
                       drawScroll(2);
                       WinDrawBitmap(scroll_bmp,152,0);
                       _sampler_load();
                       _sampler_draw();
                       break;
          case frmCloseEvent:
                       FrmEraseForm(gpForm);
                       FrmDeleteForm(gpForm);
                       gpForm = 0;
                       handled = true;
                       break;
          default:
     }
return handled;
}

Boolean FormHandle(EventPtr event)
{
 Boolean handled=false;
     switch(event->eType)
     {
          case lstSelectEvent:
                       if(event->data.lstSelect.listID==SMPlist){
                         samp=LstGetSelection(list2);
                         drawScroll(2);
                         WinDrawBitmap(scroll_bmp,152,0);
						 setSMPpars();
						 drawSAMPLENAME();
                       }
                       break;
          case penDownEvent:
						if(FrmGetActiveFormID()==AboutForm2) 
						{
                            FrmGotoForm(AboutForm);                         
				            GetEvent(0);
                            GetEvent(0);
                            GetEvent(0);
						    helpfield = FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),HelpField));
						    FldSetTextPtr(helpfield,help_text_ptr);
						    FldRecalculateField(helpfield,1);
							break;
						}
                       demo_mode=0;
                       if(event->screenY>110 && FrmGetActiveFormID()!=AboutForm){
						 one_sample_limit = 65000;
                         select_note(event->screenX,event->screenY,0);
						 break;
                       }
                       if(event->screenY<44 && FrmGetActiveFormID()!=AboutForm){
                         if(event->screenX>151){
                           a=event->screenY-4;if(a<0){a=0;}if(a>30){a=30;} a=a/7;a=a*7;
                           if(FrmGetActiveFormID()==SampleForm){samp=a;LstSetSelection(list2,samp);drawScroll(2);LstDrawList(list2);WinDrawBitmap(scroll_bmp,152,0);}
						   break;
						 }
                       }
					   if(FrmGetActiveFormID()==EditorForm) 
						   pattern_editor(event->screenX,event->screenY);
                       break;
          case penMoveEvent:
                       if(event->screenY<44 && FrmGetActiveFormID()!=AboutForm){
                         if(event->screenX>151){
                           a=event->screenY-4;if(a<0){a=0;}if(a>30){a=30;} a=a/7;a=a*7;
                           if(FrmGetActiveFormID()==SampleForm){samp=a;LstSetSelection(list2,samp);drawScroll(2);LstDrawList(list2);WinDrawBitmap(scroll_bmp,152,0);}
                         }
                       }
                       if(event->screenY>110 && FrmGetActiveFormID()!=AboutForm){
						   one_sample_limit = 65000;
                           select_note2(event->screenX,event->screenY);
                       }
                       break;
          case keyDownEvent:
				if(FrmGetActiveFormID()!=CloneForm)
				{
                       if( event->data.keyDown.chr == chrSmall_A )
					   { //Octave 0
						   current_octave = 0;
						   break;
                       }
                       if( event->data.keyDown.chr == chrSmall_B )
					   { //Octave 1
						   current_octave = 12;
						   break;
                       }
                       if( event->data.keyDown.chr == chrSmall_C )
					   { //Octave 2
						   current_octave = 24;
						   break;
                       }
                       if( event->data.keyDown.chr == chrSmall_Z )
					   { //View accords in pattern editor:
						   view_accords ^= 1;
						   drawPattern();PatDraw;
						   break;
                       }
                       if(event->data.keyDown.chr==chrDigitOne){ //Effect clone
						   add1();
                         break;
                       }
                       if(event->data.keyDown.chr==chrDigitTwo){ //Block clone
						   add2();
						 break;
                       }
                       if(event->data.keyDown.chr==chrDigitThree){ //Echo
						   add3();
                         break;
                       }
                       if(event->data.keyDown.chr==chrDigitFour){ //Channel notes UP/DOWN
						   add4();
                         break;
                       }
                       if(event->data.keyDown.chr==chrDigitFive){ //Volume fade
						   add5();
                         break;
                       }
                       if(event->data.keyDown.chr==vchrPageUp){
                         if(ppnt!=0){ppnt--;}else{ppnt=63;}
                         drawPattern();
                         PatDraw;
                         break;
                       }
                       if(event->data.keyDown.chr==vchrPageDown){
                         if(ppnt!=63){ppnt++;}else{ppnt=0;}
                         drawPattern();
                         PatDraw;
                         break;
                       }
				}
                       break;
          case ctlSelectEvent:
			  switch(event->data.ctlSelect.controlID){
					   case chn:
						 b=FrmAlert(SelChn);
						 switch(b){
							 case 0: ChangeChannels(4); break;
							 case 1: ChangeChannels(6); break;
							 case 2: ChangeChannels(8); break;
							 case 3: ChangeChannels(12); break;
						 }
						 break;

				       case sampleOK:
						 saveSAMPLENAME();
						 break;

                       case ShowAbout:
                         reINITsound();
                         FrmGotoForm(AboutForm2);                         
				         GetEvent(0);
                         GetEvent(0);
                         GetEvent(0);
					     break;

                       case AboutButton:
                         reINITsound();
                         FrmGotoForm(AboutForm);                         
				         GetEvent(0);
                         GetEvent(0);
                         GetEvent(0);
						 helpfield = FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),HelpField));
						 FldSetTextPtr(helpfield,help_text_ptr);
						 FldRecalculateField(helpfield,1);
					     break;

                       case HelpUp:
						   FldScrollField( helpfield, 8, winUp );
						   break;
                       case HelpDown:
						   FldScrollField( helpfield, 8, winDown );
						   break;

                       case Config:
                         reINITsound();
                         FrmGotoForm(ConfigForm);
						 GetEvent(0);
						 GetEvent(0);
						 GetEvent(0);
						 set_global_options();
						 //setVOLUME();
                         break;

                       case View:
                         reINITsound();
						 if(FrmGetActiveFormID()==EditorForm){
							 FrmGotoForm(old_form);
							if(old_form==SampleForm){
								GetEvent(0);
								GetEvent(0);
								GetEvent(0);
								drawSMPlist();
								LstSetSelection(list2,samp);
							}
							if(old_form==MainForm){
								GetEvent(0);
								GetEvent(0);
								GetEvent(0);
								drawmodlist();
								LstSetSelection(list,curFILE);
							}
							if(old_form==ConfigForm){
								GetEvent(0);
								GetEvent(0);
								GetEvent(0);
								set_global_options();
								//setVOLUME();
							}
						 }else{
							old_form=FrmGetActiveFormID();
							FrmGotoForm(EditorForm);
						 }
                         break;

                       case SizeDown:
						   CURRENT_SIZE++;
						   if(CURRENT_SIZE>MAX_SIZE_NUM) CURRENT_SIZE=MAX_SIZE_NUM;
						   CHAR_SIZE = CHAR_SIZES[CURRENT_SIZE][0];
						   CHAR_SIZE_Y = CHAR_SIZES[CURRENT_SIZE][1];
						   CalcPatFirstLine;
						   drawPattern(); PatDraw;
						   break;

                       case SizeUp:
						   CURRENT_SIZE--;
						   if(CURRENT_SIZE<0) CURRENT_SIZE=0;
						   CHAR_SIZE = CHAR_SIZES[CURRENT_SIZE][0];
						   CHAR_SIZE_Y = CHAR_SIZES[CURRENT_SIZE][1];
						   CalcPatFirstLine;
						   drawPattern(); PatDraw;
						   break;

					   case Effect:
						   b=FrmAlert(SelAdd);
						   switch(b){
								case 0: add1(); break;
								case 1: add2(); break;
								case 2: add3(); break;
								case 3: add4(); break;
								case 4: add5(); break;
						   }
						   break;

                       case Samples:
                         reINITsound();
                         FrmGotoForm(SampleForm);
                         GetEvent(0);
                         GetEvent(0);
                         GetEvent(0);
                         drawSMPlist();
                         LstSetSelection(list2,samp);
                         break;

					   case SampVolume:
						 getSMPpars();
						 break;
					   
					   case SampTune:
						 getSMPpars();
						 break;

					   case SampEcho:
						 getSMPpars();
						 break;

					   case GlobalVolume:
						 getVOLUME();
						 break;

					   case GlobalEcho:
						 get_global_options();
						 break;

					   case GlobalLen:
						 get_global_options();
						 break;

					   case GlobalClassic:
						 get_global_options();
						 break;

                       case Files:
                         reINITsound();
                         FrmGotoForm(MainForm);
                         GetEvent(0);
                         GetEvent(0);
                         GetEvent(0);
                         drawmodlist();
                         LstSetSelection(list,curFILE);
                         break;

                       case AboutOK:
                         reINITsound();
                         FrmGotoForm(MainForm);
                         GetEvent(0);
                         GetEvent(0);
                         GetEvent(0);
                         drawmodlist();
                         break;

                       case loadMOD:
                         curFILE=LstGetSelection(list);curMOD=curFILE;
                         _srmControl(port,AUdrvOpCodeStop,&value32,&vlen);
                         if(curFILE<num_of_mods){ //OPEN MOD:
                           modclose();
                           soundCLOSE();
                           newsearch();
                           for(a=0;a<curFILE;a++){nextfile();}
                           soundINIT();
                           modload();
						   echo_setup( echoP, ECHO, ECHOLEN );
                           ppnt=0;
                           drawPattern();
                           PatDraw;
                           modplay(freq);
						   START_CHANNEL = 0;
						   cur_c = 0;
						   cur_p = 0;
                         }else{                   //OPEN MP3:
                           //mp3close();
                           //soundCLOSE();
                           //mp3_newsearch();for(a=0;a<(curFILE-num_of_mods);a++){mp3_nextfile();}
                           //mp3open();
                           //mp3_status=1;
                           //soundINIT();
                         }
                         break;

                       case SamplerButton:
                         undo_backup();
						 mod_info._status=0;
                         backup_bmp=bmp;
                         backupP=bmpP;
                         bmp=bmp2;
                         bmpP=bmp2P;
                         reINITsound();
                         _sampler_load();
                         set_zoom(smp_size);
                         FrmGotoForm(frmSampler);
                         GetEvent(0);
                         GetEvent(0);
                         GetEvent(0);
                         drawSMPlist();
                         LstSetSelection(list2,samp);
                         break;

                       case delMOD:
                         if(FrmAlert(Delete)==0){
                         _srmControl(port,AUdrvOpCodeStop,&value32,&vlen);
                         b=LstGetSelection(list);
                         if(b<num_of_mods){ //DELETE MOD FILE:
                           if(b==curMOD){modclose();}
                           newsearch();for(a=0;a<b;a++){nextfile();}
                           DmDeleteDatabase(0,ID);
                           drawmodlist();
                           if(b==curMOD){
                             newsearch();
                             modload();
							 echo_setup( echoP, ECHO, ECHOLEN );
                             modplay(freq);
                           }
                         }else{    //DELETE MP3 FILE:
                           //mp3_newsearch();for(a=0;a<(b-num_of_mods);a++){mp3_nextfile();}
                           //DmDeleteDatabase(0,mID);
                           //drawmodlist();
                         }}
                         break;

                       case clearMOD:
                         mod_info._status=0;
                         b=FrmAlert(CLEARMOD);
                         if(b==0){ClearPatterns();}
                         if(b==1){ClearSamples();}
                         break;

                       case saveMOD:
                         mod_info._status=0; //stop
                         _srmControl(port,AUdrvOpCodeStop,&value32,&vlen); //stop sound
                         soundCLOSE(); //close sound
                         save_current_mod(); //save
                         soundINIT(); //open sound
                         drawPattern();
                         PatDraw;
                         break;

                       case cloneMOD:
                         reINITsound();
                         FrmGotoForm(CloneForm);
                         GetEvent(0);
                         GetEvent(0);
                         GetEvent(0);
                         drawFILENAME();
                         break;

                       case cloneCANCEL:
                         reINITsound();
                         FldSetText(filename,NULL,0,32);
                         FrmGotoForm(MainForm);
                         GetEvent(0);
                         GetEvent(0);
                         GetEvent(0);
                         drawmodlist();
                         LstSetSelection(list,curFILE);
                         break;

                       case cloneOK:
                         reINITsound();
                         clone();
                         FldSetText(filename,NULL,0,32);
                         FrmGotoForm(MainForm);
                         GetEvent(0);
                         GetEvent(0);
                         GetEvent(0);
                         drawmodlist();
                         LstSetSelection(list,curFILE);
                         break;

                       case Play:
						 rec_status=0;
                         start_clear();
                         mod_info._tablepos=0;
                         mod_info._patternpos=0;
                         mod_info._status=2;
                         break;

                       case Play1:
						 rec_status=0;
                         start_clear();
                         mod_info._patternpos=0;
                         mod_info._status=2;
                         break;

                       case PlayToBuf:
						 rec_status=0;
						 b = FrmAlert(SelPlay);
						 if(b==4) break;
                         start_clear();
						 mod_info.rec_pointer = copyP;
						 mod_info.rec_count = 0;
						 if( b == 0 ) mod_info.rec_add = 1;
						 if( b == 1 ) mod_info.rec_add = 2;
						 if( b == 2 ) mod_info.rec_add = 3;
						 if( b == 3 ) mod_info.rec_add = 4;
						 copy_size = 60000;
                         mod_info._patternpos=0;
                         mod_info._status=2;
                         break;

                       case Play2:
						 rec_status=0;
                         start_clear();
                         mod_info._patternpos=0;
                         mod_info._status=3;
                         break;

                       case Stop:
                         /*if(mp3_status==1){
                           mp3_status=0;
                           _srmControl(port,AUdrvOpCodeStop,&value32,&vlen);
                           value32=freq;vlen=4;_srmControl(port,AUdrvOpCodeSampling,&value32,&vlen);
                         }*/
                         mod_info._status=0;
                         break;

                       case PatUp:
                         if(ppnt!=0){ppnt--;}else{ppnt=63;}
                         drawPattern();
                         PatDraw;
                         break;

                       case PatDown:
                         if(ppnt!=63){ppnt++;}else{ppnt=0;}
                         drawPattern();
                         PatDraw;
                         break;

                       case PatUp2:
                         ppnt=0;
                         drawPattern();
                         PatDraw;
                         break;

                       case PatDown2:
                         ppnt=63;
                         drawPattern();
                         PatDraw;
                         break;

                       case Rec:
                         rec_status^=1;
                         drawPattern();
                         PatDraw;
                         break;
			 }

                       handled=true;
                       break;
          case frmOpenEvent:
                       gpForm=FrmGetActiveForm();
                       FrmDrawForm(gpForm);
                       handled=true;
                       if(FrmGetActiveFormID()!=AboutForm){
                       if(FrmGetActiveFormID()!=CloneForm){
                         drawPattern();
                         PatDraw;
                       }}
                       if(FrmGetActiveFormID()==SampleForm){
                         drawScroll(2);
                         WinDrawBitmap(scroll_bmp,152,0);
                       }
                       break;
          case frmCloseEvent:
					   closeSAMPLENAME();
					   closeFILENAME();
                       FrmEraseForm(gpForm);
                       FrmDeleteForm(gpForm);
                       gpForm = 0;
                       handled = true;
                       break;
          default:
 }

 return handled;
}

static Boolean ApplicationHandleEvent(EventPtr event)
{
 FormPtr frm;
 UInt16 formId;
 Boolean handled=false;

 switch(event->eType)
 {
  case frmLoadEvent:{
               FormPtr pForm=FrmInitForm(event->data.frmLoad.formID);
               FrmSetActiveForm(pForm);
               if(event->data.frmLoad.formID==frmSampler){
                 FrmSetEventHandler(pForm, FormHandle_sampler);
               }else{
                 FrmSetEventHandler(pForm, FormHandle);
               }
               handled = true;
               break;
   }
  default:
   break;
 }
 return handled;
}


void add1() //Effect clone
{
		b=FrmAlert(SelEffect);
		if(b!=1){
          b1=get_effect(cur_c,ppnt);
          b2=get_effect_par(cur_c,ppnt);
          for(a=0;a<64;a++){
            set_effect(cur_c,a,b1);
            set_effect_par(cur_c,a,b2);
          }
        }
        drawPattern();
        PatDraw;
}

void add2() //Block clone
{
                         b=FrmAlert(SelClone);
                         if(b!=1){
                           bb=ppnt+1;b5=0;
                           for(a=0;a<64;a++){
                             b1=get_effect(cur_c,b5);
                             b2=get_effect_par(cur_c,b5);
                             b3=get_ins(cur_c,b5);
                             b4=get_note(cur_c,b5);
                             set_effect(cur_c,a,b1);
                             set_effect_par(cur_c,a,b2);
                             set_ins(cur_c,a,b3);
                             set_note(cur_c,a,b4);
                             b5++;if(b5==bb){b5=0;}
                           }
                         }
                         drawPattern();
                         PatDraw;
}

void add3() //Echo
{
	uint ch2;
                         b=FrmAlert(SelEcho);
                         if(b!=2){
                           if(b==1){ //2 channel
                             b6=FrmAlert(SelEchoStep);
                             if(b6==0){b5=64-1;}
                             if(b6==1){b5=64-2;}
                             if(b6==2){b5=64-3;}
                             if(b6==3){b5=64-4;}
                             if(b6==4){b5=64-8;}
                             if(b6==5){b5=64-16;}
                             for(a=0;a<64;a++){
                               b1=get_effect(cur_c,b5);
                               if(b1==0xC){b2=get_effect_par(cur_c,b5);}else{b2=0x40;}
                               b3=get_ins(cur_c,b5);
                               b4=get_note(cur_c,b5);
							   ch2 = cur_c+1; if(ch2>=CHANNELS) ch2=0;
                               if(get_ins(ch2,a)==0){
                                 if(b3!=0){
                                   set_effect(ch2,a,0xC);
                                   set_effect_par(ch2,a,b2>>1);
                                   set_ins(ch2,a,b3);
                                   set_note(ch2,a,b4);
                                 }
                               }
                               b5++;if(b5>63){b5=0;}
                             }
                           }else{//1 channel
                             b6=FrmAlert(SelEchoStep);
                             if(b6==0){b5=63-1;}
                             if(b6==1){b5=63-2;}
                             if(b6==2){b5=63-3;}
                             if(b6==3){b5=63-4;}
                             if(b6==4){b5=63-8;}
                             if(b6==5){b5=63-16;}
                             for(a=63;a>=0;a--){
                               b1=get_effect(cur_c,b5);
                               if(b1==0xC){b2=get_effect_par(cur_c,b5);}else{b2=0x40;}
                               b3=get_ins(cur_c,b5);
                               b4=get_note(cur_c,b5);
                               if(get_ins(cur_c,a)==0){
                                 if(b3!=0){
                                   set_effect(cur_c,a,0xC);
                                   set_effect_par(cur_c,a,b2>>1);
                                   set_ins(cur_c,a,b3);
                                   set_note(cur_c,a,b4);
                                 }
                               }
                               b5--;if(b5<0){b5=63;}
                             }
                           }
                         }
                         drawPattern();
                         PatDraw;
}

void add4() //Channel notes UP/DOWN
{
                         b=FrmAlert(SelNote);
                         if(b!=2){
                           for(a=0;a<64;a++){
                             b1=get_note(cur_c,a);
                             if(b==0){set_note(cur_c,a,b1+1);}
                             if(b==1){set_note(cur_c,a,b1-1);}
                           }
                         }
                         drawPattern();
                         PatDraw;
}

void add5() //Volume fade
{
                        b=FrmAlert(SelVol1);
                         if(b!=5){
                           b4=FrmAlert(SelVol2);
                           for(a=0;a<64;a++){
                             b3=0;
                             b1=get_effect(cur_c,a);
                             if(b1==0xC){b2=get_effect_par(cur_c,a);b3=1;}else{b2=0x40;}
                             if(get_ins(cur_c,a)!=0){b3=1;}
                             if(b3==1){
                               set_effect(cur_c,a,0xC);
                               set_effect_par(cur_c,a,((b*(64-a)*b2)>>8)+((b4*a*b2)>>8));
                             }
                           }
                         }
                         drawPattern();
						 PatDraw;
}

void soundINIT()
{
  if(model==0){
    SrmOpen(0x61754469,1280,&port);
    value32=volume;vlen=4;_srmControl(port,AUdrvOpCodeVolume,&value32,&vlen);
    //if(mp3_status==0){value32=freq;}else{value32=mp3freq;}
    vlen=4;_srmControl(port,AUdrvOpCodeSampling,&value32,&vlen);
  }
    tableinit();
}


void soundCLOSE()
{
  if(model==0){
    _srmControl(port,AUdrvOpCodeStop,&value32,&vlen);
    SrmClose(port);
  }
}

void reINITsound()
{
  soundCLOSE();
  if(model==0) SrmOpen(0x61754469,1280,&port);
  value32=volume;vlen=4;_srmControl(port,AUdrvOpCodeVolume,&value32,&vlen);
  //if(mp3_status==0){value32=freq;}else{value32=mp3freq;}
  vlen=4;_srmControl(port,AUdrvOpCodeSampling,&value32,&vlen);
}

void soundREPLAY()
{
    mod_info._status=1;
}

void drawmodlist()
{
    getmodlist();
//    getmp3list();
    for(a=0;a<64;a++){texts[a]=mod_list+(a<<5);}
    list=FrmGetObjectPtr(FrmGetActiveForm(),
                         FrmGetObjectIndex(FrmGetActiveForm(),MODlist));
    if(num_of_mods!=0){
      LstSetListChoices(list,texts,num_of_mods);
    }else{
      //if(num_of_mp3s!=0){LstSetListChoices(list,texts,num_of_mp3s);}else{LstSetListChoices(list,nofile,1);}
    }
    LstDrawList(list);
}

void setSMPpars() //set current sample parameters:
{
    Int16 new_val;
	//set current sample parameters:
	if(FrmGetActiveFormID()==SampleForm){
		new_val = song.samples[samp].volume;
		CtlSetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),SampVolume)), new_val);
		if(song.samples[samp].finetune>7) new_val = song.samples[samp].finetune - 16;
							         else new_val = song.samples[samp].finetune;
		CtlSetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),SampTune)), new_val);
		if( song.samples[samp].name[21] < 32 ) new_val = (uchar)song.samples[samp].name[21]; else new_val = 0;
		CtlSetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),SampEcho)), new_val);
	}
}

void getSMPpars() //get parameters from sliders:
{
    Int16 new_val;
	new_val = CtlGetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),SampVolume)));
	song.samples[samp].volume = new_val;
	song2.samples[samp].volume = new_val;
	new_val = CtlGetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),SampTune)));
	if(new_val<0) new_val+=16;
	song.samples[samp].finetune = new_val;
	song2.samples[samp].finetune = new_val;
	new_val = CtlGetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),SampEcho)));
	song.samples[samp].name[21] = new_val;
	song2.samples[samp].name[21] = new_val;
}

void setVOLUME() //set volume to the slider
{
    Int16 new_val;
	new_val = VOLUME;
	CtlSetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),GlobalVolume)), new_val);
}

void getVOLUME() //get volume from the slider
{
    Int16 new_val;
	new_val = CtlGetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),GlobalVolume)));
	set_volume(new_val);
}

void drawSMPlist()
{
	for(a=0;a<31;a++){texts2[a]=song.samples[a].name;}
    list2=FrmGetObjectPtr(FrmGetActiveForm(),
                          FrmGetObjectIndex(FrmGetActiveForm(),SMPlist));
    if(num_of_mods!=0){
      LstSetListChoices(list2,texts2,31);
    }
    LstDrawList(list2);

	setSMPpars();

	if(FrmGetActiveFormID()==SampleForm) drawSAMPLENAME();
}

void saveSAMPLENAME()
{
    char *name = song.samples[samp].name;
	char *sn;
	sn = MemHandleLock(SAMPLENAME);
	for(a=0;a<21;a++) {name[a]=sn[a];if(sn[a]==0) break;}
	MemHandleUnlock(SAMPLENAME);
	drawSMPlist();
}

void closeSAMPLENAME()
{
	if(FrmGetActiveFormID()==SampleForm)
	FldSetText(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),sampleNAME)),0,0,32);	
}

void drawSAMPLENAME()
{
    int a;
    char *name = song.samples[samp].name;
	char *sn;

	if(FrmGetActiveFormID()==SampleForm){

		sn = MemHandleLock(SAMPLENAME);
		for(a=0;a<22;a++) {sn[a]=name[a];if(sn[a]==0) break;}
		sn[22] = 0;
		MemHandleUnlock(SAMPLENAME);

		FldSetTextHandle(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),sampleNAME)),SAMPLENAME);
		FldDrawField(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),sampleNAME)));

	}
}

void closeFILENAME()
{
	if(FrmGetActiveFormID()==CloneForm)
	FldSetText(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),cloneNAME)),0,0,32);	
}

void drawFILENAME()
{
    int a;
    char *txt_str;
    filename=FrmGetObjectPtr(FrmGetActiveForm(),
                             FrmGetObjectIndex(FrmGetActiveForm(),cloneNAME));
    txt_str=texts[curMOD];

	fnameP = MemHandleLock(fname);
    for(a=0;a<32;a++){fnameP[a]=txt_str[a];if(fnameP[a]==0){break;}}
	MemHandleUnlock(fname);

    FldSetText(filename,fname,0,32);
    FldDrawField(filename);
}

void backup()
{
   LocalID newDB_ID;
   newDB_ID=DmFindDatabase(0,"BACKUP.MOD");
   if(newDB_ID!=0){
     if(newDB_ID!=ID){
		fnameP = MemHandleLock(fname);
       fnameP[0]='B'; fnameP[1]='A'; fnameP[2]='C';
       fnameP[3]='K'; fnameP[4]='U'; fnameP[5]='P';
       fnameP[6]='.'; fnameP[7]='M'; fnameP[8]='O';
       fnameP[9]='D'; fnameP[10]=0;
       clone();
		MemHandleUnlock(fname);
     }
   }
}

void undo_backup()
{
   LocalID newDB_ID;
   newDB_ID=DmFindDatabase(0,"UNDO.MOD");
     if(newDB_ID!=ID){
		fnameP = MemHandleLock(fname);
       fnameP[0]='U'; fnameP[1]='N'; fnameP[2]='D';
       fnameP[3]='O'; fnameP[4]='.'; fnameP[5]='M';
       fnameP[6]='O'; fnameP[7]='D'; fnameP[8]=0;
       clone();
		MemHandleUnlock(fname);
     }
}

void clone()
{
   DmOpenRef newDB;
   MemHandle newH;
   LocalID newDB_ID;
   char *newP;
   UInt16 ind;
   long ptt,mm,nn,len;

 if(num_of_mods!=0){
   for(a=0;a<31;a++){
     song.samples[a].length /= 2;
     song.samples[a].reppnt /= 2;
     song.samples[a].replen /= 2;
   }
   err=DmCreateDatabase(0,fnameP,0x5A554C55,0x4D4F4420,0);
   if((err==errNone)|(err==dmErrAlreadyExists)){
     if(err==dmErrAlreadyExists){mm=1;}else{mm=0;}
     newDB_ID=DmFindDatabase(0,fnameP);
     newDB=DmOpenDatabase(0,newDB_ID,dmModeReadWrite);
     nn=DmNumRecords(newDB);
     if(mm) for(a=0;a<34;a++) DmReleaseRecord(newDB,a,0);

       if(!mm){ind=0;newH=DmNewRecord(newDB,&ind,4);newP=MemHandleLock(newH);}
          else{ind=0;newH=DmGetRecord(newDB,ind);newP=MemHandleLock(newH);}
       DmWrite(newP,0,start_header,4);MemHandleUnlock(newH);
     if(!mm){ind=1;newH=DmNewRecord(newDB,&ind,1084);newP=MemHandleLock(newH);}
        else{ind=1;newH=DmGetRecord(newDB,ind);newP=MemHandleLock(newH);}
     DmWrite(newP,0,&(song.title),1084);MemHandleUnlock(newH); //Save MOD information.
       maxp=0;
       for(ptt=0;ptt<song.length;ptt++){      //Search for maximal number of pattern.
         if(song.patterntable[ptt]>maxp){maxp=song.patterntable[ptt];}
       }if(maxp>63){maxp=63;}
       if(!mm){ind=2;newH=DmNewRecord(newDB,&ind,(maxp+1)*PAT_SIZE);newP=MemHandleLock(newH);}
          else{ind=2;newH=DmResizeRecord(newDB,ind,(maxp+1)*PAT_SIZE);newP=MemHandleLock(newH);}
	//print(maxp+1);
	//write pattern data:
	ptt=0;
	for(p=0;p<maxp+1;p++){
		DmWrite(newP,ptt,patterndata[p],PAT_SIZE);
		ptt+=PAT_SIZE;
	}
	//===================
       MemHandleUnlock(newH);

     for (a = 0; a < 31; a++) {
       ind=a+3;
       len=song.samples[a].length;
	   if(len!=0){
         if(!mm){newH=DmNewRecord(newDB,&ind,len*2);}
            else{if(ind>=nn){newH=DmNewRecord(newDB,&ind,len*2);}
                 else{newH=DmResizeRecord(newDB,ind,len*2);}
                 }
       }else{
         if(!mm){newH=DmNewRecord(newDB,&ind,2);}
            else{if(ind>=nn){newH=DmNewRecord(newDB,&ind,2);}
                 else{newH=DmResizeRecord(newDB,ind,2);}
                 }
       }
	   
	   newP=MemHandleLock(newH);
       if(song.samples[a].length!=0){
         DmWrite(newP,0,sampledata[a],len*2);
       }else{
         DmWrite(newP,0,&len,2);  //len - ot baldy
       }
       MemHandleUnlock(newH);
     }

     curFILE++;curMOD++;
     DmCloseDatabase(newDB);
   }
   for(a=0;a<31;a++){
     song.samples[a].length *= 2;
     song.samples[a].reppnt *= 2;
     song.samples[a].replen *= 2;
   }
 }
}

void GetEvent(ulong wait_time)
{
   EvtGetEvent(&event,wait_time);
   if(!SysHandleEvent(&event))
   if(!MenuHandleEvent(0, &event, &error))
   if(!ApplicationHandleEvent(&event))
   FrmDispatchEvent(&event);
}

void ClearPatterns(void)
{
  long ptt;
  char *pat;
  for(ptt=0;ptt<128;ptt++){
    song.patterntable[ptt]=0;
  }
  mem_off();
  for(p=0;p<128;p++) {
	pat=(char*)patterndata[p];
    for(ptt=0;ptt<PAT_SIZE;ptt++) pat[ptt]=0;
  }
  mem_on();
  song.length=1;
  drawPattern();
  PatDraw;
}

void ClearSamples(void)
{
}

void ChangeChannels(uint num)
{
	note temp_pat[CHANNELS_MAX*64];
	note *pat;
	uint x,y;
	uint pat_num;
	uint pnt; //pointer in temp pat;
	uint pnt2; //pointer in current pattern;

	mem_off();
	
	MemSet(temp_pat,(ulong)CHANNELS_MAX*4*64,0);

	for(pat_num=0;pat_num<128;pat_num++){
		//get pattern:
		pat = patterndata[pat_num];
		pnt2 = 0;
		for(y=0;y<64;y++){
			pnt=y*CHANNELS_MAX;
			for(x=0;x<CHANNELS;x++){
				temp_pat[pnt+x] = pat[pnt2];
				pnt2++;
			}
		}
		
		//resize pattern:
		for(y=0;y<64;y++){
			pnt2 = y*num;
			pnt = y*CHANNELS_MAX;
			for(x=0;x<num;x++){
				pat[pnt2+x] = temp_pat[pnt+x];
			}
		}
	}

	//set channels number:
	song.signature[1] = 'C';
	song.signature[2] = 'H';
	song.signature[3] = 'N';
	switch(num){
		case 4:	 song.signature[0] = '4'; break;
		case 6:	 song.signature[0] = '6'; break;
		case 8:	 song.signature[0] = '8'; break;
		case 12: song.signature[0] = 'C'; break;
		case 16: song.signature[0] = 'X'; break;
	}

	channels_setup();

	START_CHANNEL = 0;
	cur_c = 0;
	cur_p = 0;

	mem_on();
}

void copyC(UInt16 ch_num,char *dest)
{
  int aa,aaa;
  aaa=0;
  for(aa=0;aa<64;aa++){
    if(get_note(ch_num,aa)==500) dest[aaa] = 0;
	else dest[aaa] = get_note(ch_num,aa);
    dest[aaa+1]=get_ins(ch_num,aa);
    dest[aaa+2]=get_effect(ch_num,aa);
    dest[aaa+3]=get_effect_par(ch_num,aa);
	aaa+=4;
  }
}

void clearC(UInt16 ch_num)
{
  int aa;
  for(aa=0;aa<64;aa++){
    set_note(ch_num,aa,500);
    set_ins(ch_num,aa,0);
    set_effect(ch_num,aa,0);
    set_effect_par(ch_num,aa,0);
  }
}

void pasteC(UInt16 ch_num,char *dest)
{
  int aa,aaa;
  aaa=0;
  for(aa=0;aa<64;aa++){
    set_note(ch_num,aa,dest[aaa]);
    set_ins(ch_num,aa,dest[aaa+1]);
    set_effect(ch_num,aa,dest[aaa+2]);
    set_effect_par(ch_num,aa,dest[aaa+3]);
	aaa+=4;
  }
}

uint get_note(int chan,int pos){ //return 500 if note is empty
  uint period;
  note *nptr;
  nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
  nptr+=(pos*CHANNELS)+chan;
  period = ((nptr->sampperiod & 0xF) << 8) | nptr->period;
  if(period==0){return 500;}else{return pp[period];}
}
uint get_ins(int chan,int pos){
  uint sample;
  note *nptr;
  nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
  nptr+=(pos*CHANNELS)+chan;
  sample = (nptr->sampperiod & 0xF0) | (nptr->sampeffect >> 4);
  return sample;
}
uint get_effect(int chan,int pos){
  uint effect;
  note *nptr;
  nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
  nptr+=(pos*CHANNELS)+chan;
  effect = ((nptr->sampeffect & 0xF) << 8) | nptr->effect;
  return effect>>8;
}
uint get_effect_par(int chan,int pos){
  uint effect;
  note *nptr;
  nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
  nptr+=(pos*CHANNELS)+chan;
  effect = ((nptr->sampeffect & 0xF) << 8) | nptr->effect;
  return effect&0xFF;
}
void set_note(int chan,int pos,uint nnn){
  note *nptr;
  uint period;
  mem_off();
  nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
  nptr+=(pos*CHANNELS)+chan;
  if(nnn<255){period=fine[0][nnn];}else{period=0;}
  nptr->period=period&0xFF;
  period&=0xF00;period>>=8;
  nptr->sampperiod&=0xF0;
  nptr->sampperiod^=period;
  mem_on();
}
void set_ins(int chan,int pos,uint inss){
  note *nptr;
  mem_off();
  nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
  nptr+=(pos*CHANNELS)+chan;
  nptr->sampperiod&=0xF;
  nptr->sampperiod+=(inss&0xF0);
  nptr->sampeffect&=0xF;
  nptr->sampeffect+=(inss<<4);
  mem_on();
}
void set_effect(int chan,int pos,uint eff){
  note *nptr;
  mem_off();
  nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
  nptr+=(pos*CHANNELS)+chan;
  nptr->sampeffect&=0xF0;
  nptr->sampeffect+=eff;
  mem_on();
}
void set_effect_par(int chan,int pos,uint par){
  note *nptr;
  mem_off();
  nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
  nptr+=(pos*CHANNELS)+chan;
  nptr->effect=par;
  mem_on();
}


void playnote1(uint note_num,uint samplenum,channel *cptr,ulong start) //Play note and write it to pattern;
{
  uint period;
  note *nptr;
  playnote(note_num,samplenum,cptr,start);
  if(rec_status==1){
    samplenum++;
    period=fine[0][note_num];
    if(cur_p<2){ //If position<2 then write this note:
		mem_off();
      nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
      nptr+=(ppnt*CHANNELS)+cur_c;
        nptr->sampperiod&=0xF;
        nptr->sampperiod+=(samplenum&0xF0);
        nptr->sampeffect&=0xF;
        nptr->sampeffect+=(samplenum<<4);
        if(cur_p!=1){ //If cursor position=1 then write sample number only;
          nptr->period=period&0xFF;
          period&=0xF00;period>>=8;
          nptr->sampperiod&=0xF0;
          nptr->sampperiod^=period;
        }
      ppnt++;if(ppnt>63){ppnt=0;}
		mem_on();
    }
    drawPattern();
    PatDraw;
  }
}


//************************************************
//********* NEW GENERATION ADDITION :) ***********
//************************************************

int pattern_editor(int x,int y)
{
    int xx,yy,ptt,y_delta;
	if(FrmGetActiveFormID()!=AboutForm){
	if(FrmGetActiveFormID()!=CloneForm){
	    x=x/(CHAR_SIZE>>1);y=y/(CHAR_SIZE_Y>>1);xx=x>>1;
		if(y==0){ //first line:
			if(xx==1){if(mod_info._tablepos!=0){mod_info._tablepos--;}ppnt=0;mod_info._patternpos=0;goto okps;} //Pos--;
			if(xx==2){if(mod_info._tablepos!=song.length-1){mod_info._tablepos++;}ppnt=0;mod_info._patternpos=0;goto okps;} //Pos++;
			if(xx==0){if(mod_info._tablepos>3){mod_info._tablepos-=4;}else{mod_info._tablepos=0;}ppnt=0;mod_info._patternpos=0;goto okps;}
			if(xx==3){mod_info._tablepos+=4;ppnt=0;mod_info._patternpos=0;goto okps;}
			if(xx==4){song.patterntable[mod_info._tablepos]++;ppnt=0;mod_info._patternpos=0;goto okps;}
			if(xx==5){song.patterntable[mod_info._tablepos]--;ppnt=0;mod_info._patternpos=0;goto okps;}
			if(x>11){if(x<16){ //add pattern:
				if(song.length!=255){song.length++;}
				for(ptt=song.length-1;ptt>mod_info._tablepos;ptt--){
					song.patterntable[ptt]=song.patterntable[ptt-1];
				}ppnt=0;goto okps;
			}}
			if(x>15){if(x<20){ //delete pattern
				if(song.length!=0){song.length--;}
				for(ptt=mod_info._tablepos;ptt<song.length-1;ptt++){
					song.patterntable[ptt]=song.patterntable[ptt+1];
				}ppnt=0;goto okps;
			}}
		} //end first line
		    
		if(y>1){if(y<PAT_SCREEN_Y){ //After 1st line:
			cur_c = x/5;
			cur_p = x-(cur_c*5);
			cur_c += START_CHANNEL;
			y_delta=y-(PAT_FIRST_LINE + UP_EMPTY_LINES);
			ppnt+=y_delta;
			if(ppnt>63){ppnt=63;}
			if(ppnt<0){ppnt=0;}
		}}

okps:
		if(xx==4 || xx==5)
		{
			if( song.patterntable[mod_info._tablepos] > 127 )
			{
				switch( CHANNELS )
				{
					case 4: song.patterntable[mod_info._tablepos] = 62; break;
					case 6: song.patterntable[mod_info._tablepos] = 41; break;
					case 8: song.patterntable[mod_info._tablepos] = 30; break;
					case 12: song.patterntable[mod_info._tablepos] = 20; break;
				}
			}
			switch( CHANNELS )
			{
				case 4: 
				if( song.patterntable[mod_info._tablepos] > 62 )
					song.patterntable[mod_info._tablepos] = 0;
				break;
				case 6: 
				if( song.patterntable[mod_info._tablepos] > 41 )
					song.patterntable[mod_info._tablepos] = 0;
				break;
				case 8: 
				if( song.patterntable[mod_info._tablepos] > 30 )
					song.patterntable[mod_info._tablepos] = 0;
				break;
				case 12: 
				if( song.patterntable[mod_info._tablepos] > 20 )
					song.patterntable[mod_info._tablepos] = 0;
				break;
			}
		}

		//ARM-code must see it:
		MemMove(&song2.patterntable,&song.patterntable,128);
		//====================
		if(mod_info._tablepos>song.length-1){mod_info._tablepos=song.length-1;}
		drawPattern();
		PatDraw;
	}}
}

//************************************************
//************************************************
//************************************************


void select_note(int x,int y,ulong start)
{
  note *nptr,*nptr1;
  int ppnt1,a;

  if(y>120){
    if(cur_p>0){ //If selected panel with number buttons
	if(y<140){
    if(rec_status==1){
		mem_off();
      x=x/10;
      nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
      nptr+=(ppnt*CHANNELS)+cur_c;
      if(cur_p==2){
        nptr->sampeffect&=0xF0;
        nptr->sampeffect+=x;
        ppnt++;
      }
      if(cur_p==3){
        nptr->effect&=0xF;
        nptr->effect+=x<<4;
        ppnt++;
      }
      if(cur_p==4){
        nptr->effect&=0xF0;
        nptr->effect+=x;
        ppnt++;
      }
		mem_on();
      if(ppnt>63){ppnt=0;}
      drawPattern();
      PatDraw;
	  goto oksn;
    }}}

	//select note:
    x=x/5;y=y/10;
    if(y==15){if(x<14){playnote1(note_table2[x]+current_octave,samp,one,start);soundREPLAY();}}
    if(y==14){if(x<14){playnote1(note_table1[x]+current_octave,samp,one,start);soundREPLAY();}}
    if(y==13){
      if(x>=14){if(x<28){playnote1(note_table2[x-14]+24+current_octave,samp,one,start);soundREPLAY();}}
      else{playnote1(note_table2[x]+12+current_octave,samp,one,start);soundREPLAY();}
    }
    if(y==12){
      if(x>=14){if(x<28){playnote1(note_table1[x-14]+24+current_octave,samp,one,start);soundREPLAY();}}
      else{playnote1(note_table1[x]+12+current_octave,samp,one,start);soundREPLAY();}
    }
    goto oksn;
  }
  if(y<120){ //If click on the panel with action buttons;
  if(y>110){
    x=x/20;
    if(rec_status==1){
      if(x==1){ //Insert empty note;
		  mem_off();
        nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
        nptr+=((CHANNELS*64)-CHANNELS)+cur_c;nptr1=nptr-CHANNELS;
        for(ppnt1=63;ppnt1>ppnt;ppnt1--){
          nptr->sampperiod=nptr1->sampperiod;
          nptr->sampeffect=nptr1->sampeffect;
          nptr->period=nptr1->period;
          nptr->effect=nptr1->effect;
          nptr-=CHANNELS;nptr1-=CHANNELS;
        }
        nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
        nptr+=(ppnt*CHANNELS)+cur_c;
        nptr->sampperiod=0;
        nptr->sampeffect=0;
        nptr->period=0;
        nptr->effect=0;
		  mem_on();
        drawPattern();
        PatDraw;
      }
      if(x==2){ //Delete note;
		  mem_off();
        nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
        nptr+=(ppnt*CHANNELS)+cur_c;nptr1=nptr+CHANNELS;
        for(ppnt1=ppnt;ppnt1<63;ppnt1++){
          nptr->sampperiod=nptr1->sampperiod;
          nptr->sampeffect=nptr1->sampeffect;
          nptr->period=nptr1->period;
          nptr->effect=nptr1->effect;
          nptr+=CHANNELS;nptr1+=CHANNELS;
        }
        nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
        nptr+=((CHANNELS*64)-CHANNELS)+cur_c;
        nptr->sampperiod=0;
        nptr->sampeffect=0;
        nptr->period=0;
        nptr->effect=0;
		  mem_on();
        drawPattern();
        PatDraw;
      }
      if(x==3){ //Clear current note;
		  mem_off();
        nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
        nptr+=(ppnt*CHANNELS)+cur_c;
        if(cur_p==0){ //clear note
          nptr->sampperiod=0;
          nptr->sampeffect&=0xF;
          nptr->period=0;
        }
        if(cur_p==1){ //clear sample number
          nptr->sampperiod&=0xF;
          nptr->sampeffect&=0xF;
        }
        if(cur_p>1){  //clear effect
          nptr->sampeffect&=0xF0;
          nptr->effect=0;
        }
        ppnt++;if(ppnt>63){ppnt=0;}
		  mem_on();
        drawPattern();
        PatDraw;
      }
    }
    if(x==4){ //Edit pattern;
      b=FrmAlert(EditPat);
      if(b==0){
		  for(a=0;a<CHANNELS;a++) {copyC(a,copy_buffer1+(a*256));clearC(a);}
	  }
      if(b==1){
		  for(a=0;a<CHANNELS;a++) {copyC(a,copy_buffer1+(a*256));}
	  }
      if(b==2){
		  for(a=0;a<CHANNELS;a++) {pasteC(a,copy_buffer1+(a*256));}
	  }
      drawPattern();
      PatDraw;
    }
    if(x==5){ //Edit channel;
      b=FrmAlert(EditChan);
      if(b==0){copyC(cur_c,copy_buffer2);clearC(cur_c);}
      if(b==1){copyC(cur_c,copy_buffer2);}
      if(b==2){pasteC(cur_c,copy_buffer2);}
      drawPattern();
      PatDraw;
    }
  }}
oksn:
}

void select_note2(int x,int y) //slide mode
{
  note *nptr,*nptr1;
  int ppnt1;
  if(y>119){
  if(rec_status==0){
    x=x/5;y=y/10;
    if(y==15){if(x<14){slidenote(note_table2[x]+current_octave,samp,one);soundREPLAY();}}
    if(y==14){if(x<14){slidenote(note_table1[x]+current_octave,samp,one);soundREPLAY();}}
    if(y==13){
      if(x>=14){if(x<28){slidenote(note_table2[x-14]+24+current_octave,samp,one);soundREPLAY();}}
      else{slidenote(note_table2[x]+12+current_octave,samp,one);soundREPLAY();}
    }
    if(y==12){
      if(x>=14){if(x<28){slidenote(note_table1[x-14]+24+current_octave,samp,one);soundREPLAY();}}
      else{slidenote(note_table1[x]+12+current_octave,samp,one);soundREPLAY();}
    }
  }}
}


int InvertChar(long x, long y)
{
	UInt16 aa,bb;
	long pnt;

	pnt = (y * PAT_SCREEN_X) + x;

	for(aa=0;aa<CHAR_SIZE_Y;aa++){
	for(bb=0;bb<CHAR_SIZE;bb++){
		bmpP[pnt]^=255;pnt++;
	}
	pnt += (PAT_SCREEN_X-CHAR_SIZE);
	}	
	return 0;
}


int DrawChar(long x, long y, long cc)
{
#ifdef SIMULATOR
	long aa,bb;
	unsigned char ccc,back=0,fore=255;
	long pnt;
#endif

	render.x = ByteSwap32(x);
	render.y = ByteSwap32(y);
	render.cc = ByteSwap32(cc);
#ifndef SIMULATOR
    PceNativeCall(arm_render, &render);

#else	
	cc<<=3;
	pnt = (y * PAT_SCREEN_X) + x;

	if(render.char_mode) back=90; else back=0;
	if(render.char_invert)  {fore=back;back=255;}

	if(CHAR_SIZE==8){
		for(aa=0;aa<8;aa++){
		ccc=myfontH[cc];
		for(bb=0;bb<8;bb++){
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;
			ccc<<=1;pnt++;
	    }
		pnt += (PAT_SCREEN_X-8); cc++;
		}
		return 0;
	}
	if(CHAR_SIZE==16){
		for(aa=0;aa<16;aa++){
		ccc=myfontH[cc];
		for(bb=0;bb<16;bb+=2){
			if(ccc&128) {bmpP[pnt]=fore;bmpP[pnt+1]=fore;}
			       else {bmpP[pnt]=back;bmpP[pnt+1]=back;}
			ccc<<=1;pnt+=2;
	    }
		pnt += (PAT_SCREEN_X-16);
		ccc=myfontH[cc];
		if(aa&1) cc++;
		}
		return 0;
	}
	if(CHAR_SIZE==10){
	if(CHAR_SIZE_Y==8){
		for(aa=0;aa<8;aa++){
		ccc=myfontH[cc];
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   pnt++;
		pnt += (PAT_SCREEN_X-10); cc++;
		}
		return 0;
	}
	if(CHAR_SIZE_Y==16){
		for(aa=0;aa<16;aa++){
		ccc=myfontH[cc];
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   ccc<<=1;pnt++;
			if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;   pnt++;
		pnt += (PAT_SCREEN_X-10); 
		if(aa&1) cc++;
		}
		return 0;
	}
	}
#endif

	return 0;
}


void DrawText(long x, long y, uchar *text)
{
  uint tpnt;
  tpnt=0;
check_s:
  if(text[tpnt]!=96+24){
    DrawChar(x,y,text[tpnt]);
    tpnt++;x+=CHAR_SIZE;
    goto check_s;
  }
}


void DrawNum(long x,long y,UInt16 numm)
{
  DrawChar(x,y,((numm&0xF0)>>4)+67+24);
  DrawChar(x+CHAR_SIZE,y,(numm&0xF)+67+24);
}


void DrawEmptyString(long x,long y)
{
	for(x;x<PAT_SCREEN_X;x+=CHAR_SIZE) DrawChar(x,y,83+24);
}


void DrawPattern()
{
	uint sample, period, effect;
	note *nptr;
	int ln;
	long y,x;
	long ch; //channel
	int pat_num;
	int pat_first_line = PAT_FIRST_LINE;
	long up_empty_lines = UP_EMPTY_LINES;

	//setup arm render:
    render.SCREEN_X = ByteSwap32((long)PAT_SCREEN_X);
	render.CHAR_SIZE = ByteSwap32((long)CHAR_SIZE);
	render.CHAR_SIZE_Y = ByteSwap32((long)CHAR_SIZE_Y);
	render.bmpP = (unsigned char*)ByteSwap32(bmpP);
	render.myfontH = (unsigned char*)ByteSwap32(myfontH);
	//================
	
	MemSet(bmpP,(ulong)PAT_SCREEN_X*PAT_SCREEN_Y,0);
	x = ((((long)cur_c-(long)START_CHANNEL)*5) + (long)cur_p)*(long)CHAR_SIZE;
	if(x<0) START_CHANNEL--;
	if(x>((long)PAT_SCREEN_X-(long)CHAR_SIZE)) START_CHANNEL++;

	ln=ppnt-pat_first_line; //position in pattern;
  
	//Draw pattern data:
	for(y=CHAR_SIZE_Y*up_empty_lines; y<PAT_SCREEN_Y; y+=CHAR_SIZE_Y){
		x=0;
		if( (ln&64)==0 ) {
			for(ch=START_CHANNEL;ch<CHANNELS;ch++){
				if(x+(CHAR_SIZE*5)>PAT_SCREEN_X) break;
				nptr = patterndata[song.patterntable[mod_info._tablepos]+(view_accords*64)];
				nptr += ( (ln*CHANNELS) + ch );
				sample = (nptr->sampperiod & 0xF0) | (nptr->sampeffect >> 4); //channel
				period = ((nptr->sampperiod & 0xF) << 8) | nptr->period;
				effect = ((nptr->sampeffect & 0xF) << 8) | nptr->effect;
				if((ln&7)==0) render.char_mode=1;
				if((ln&15)==0) render.char_invert=1;
				if(sample!=0){
					if(period) {DrawChar( x, y, pp[period] ); x+=CHAR_SIZE;}
					      else {x+=CHAR_SIZE;}
					DrawChar( x, y, sample+35+24 ); x+=CHAR_SIZE;
				} else { x+=CHAR_SIZE; x+=CHAR_SIZE; }
				if((ln&3)==0) render.char_mode=1;
				DrawChar(x,y,(effect>>8)+67+24);x+=CHAR_SIZE;
				DrawNum(x,y,effect&0xFF);
				render.char_mode=0;render.char_invert=0;x+=(CHAR_SIZE*2);
			}
		}
		ln++;
	}

	render.char_mode=1;
	DrawText(0,0,up_str);  //Draw pattern panel;
	render.char_mode=0;
	
	pat_num=-3;
	for(x=0;x<PAT_SCREEN_X;x+=(CHAR_SIZE*3)){  //Draw numbers of patterns;
		if(x+(CHAR_SIZE*2)>PAT_SCREEN_X) break;
		if(mod_info._tablepos+pat_num < song.length){
		if(mod_info._tablepos+pat_num >= 0){
			if(pat_num==0) render.char_invert=1; else render.char_invert=0;
			DrawNum(x,CHAR_SIZE_Y,song.patterntable[mod_info._tablepos+pat_num]);
			render.char_invert=0;
		}}
		pat_num++;
	}

	if(rec_status==1){
		x = ((((long)cur_c-(long)START_CHANNEL)*5) + (long)cur_p)*(long)CHAR_SIZE;
		if( (x>=0) & (x<=((long)PAT_SCREEN_X-(long)CHAR_SIZE)) ) 
		InvertChar( x, (up_empty_lines+pat_first_line) * CHAR_SIZE_Y ); //Draw cursor
	}
	
	//Draw center line:
	for(x=0;x<PAT_SCREEN_X;x+=CHAR_SIZE) InvertChar(x, (up_empty_lines+pat_first_line) * CHAR_SIZE_Y);
}


void drawChar(UInt16 pnt,UInt16 cc)
{
	UInt16 aa,bb;
	char ccc,back=0,fore=255;
	cc<<=3;

  if(char_mode==0) back=0; else back=90;
  if(char_invert)  {fore=back;back=255;}
  pnt<<=3;
  for(aa=0;aa<8;aa++){
    ccc=myfontH[cc];
    for(bb=0;bb<8;bb++){
      if(ccc&128) bmpP[pnt]=fore; else bmpP[pnt]=back;
      ccc<<=1;pnt++;
    }
    pnt+=152;cc++;
  }
}

void drawText(UInt16 pnt,char *text)
{
  uint tpnt;
  tpnt=0;
check_s:
  if(text[tpnt]!=96){
    drawChar(pnt,text[tpnt]);
    tpnt++;pnt++;
    goto check_s;
  }
}

void drawNum(UInt16 pnt,UInt16 numm)
{
  drawChar(pnt,((numm&0xF0)>>4)+67);
  drawChar(pnt+1,(numm&0xF)+67);
}

int drawPattern()
{
	if(demo_mode==0)
	{
		if(FrmGetActiveFormID()==EditorForm) DrawPattern();
	}
	return 0;
}

void drawScroll(int mode)
{
  UInt16 aa;
  if(mode==1){scroll_pos=curFILE;}else{scroll_pos=samp;}
  for(aa=0;aa<88;aa+=2){scroll_bmpP[aa]=0;}
  scroll_pos<<=1;
  for(aa=0;aa<26;aa+=2){
    scroll_bmpP[aa+scroll_pos]=255;
  }
  scroll_pos>>=1;
}


//############################################################################
//################################ OPTIONS ###################################
//############################################################################

void get_global_options(void)
{
    Int16 new_val;

	if(FrmGetActiveFormID()==ConfigForm) {
		getVOLUME();
		ECHO = CtlGetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),GlobalEcho)));
		ECHOLEN = CtlGetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),GlobalLen)));
		CLASSIC = CtlGetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),GlobalClassic)));
		echo_setup( echoP, ECHO, ECHOLEN );
	}
}

void set_global_options(void)
{
    Int16 new_val;

	if(FrmGetActiveFormID()==ConfigForm) {
		setVOLUME();
		new_val = ECHO;	CtlSetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),GlobalEcho)), new_val);
		new_val = ECHOLEN;	CtlSetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),GlobalLen)), new_val);
		new_val = CLASSIC;	CtlSetValue(FrmGetObjectPtr(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),GlobalClassic)), new_val);
	}
}

void saveOPTIONS(void)
{
	MemHandle rec;
	unsigned char *recP;
	UInt16 atP;
	DmOpenRef iniDB;

	get_global_options();
	
	error=DmCreateDatabase(0,"PSYTEXX.INI",'NR  ','INI ',0);
	ID=DmFindDatabase(0,"PSYTEXX.INI");
	if(ID!=0){
		iniDB=DmOpenDatabase(0,ID,dmModeWrite);
		if(error!=dmErrAlreadyExists){
			atP=0;rec=DmNewRecord(iniDB,&atP,128);
			recP=MemHandleLock(rec);
			DmWrite(recP,0,&VOLUME,2);
			DmWrite(recP,2,&ECHO,2);
			DmWrite(recP,4,&ECHOLEN,2);
			DmWrite(recP,6,&CLASSIC,1);
			MemHandleUnlock(rec);
		}else{
			DmReleaseRecord(iniDB,0,0);
			rec=DmGetRecord(iniDB,0);
			recP=MemHandleLock(rec);
			DmWrite(recP,0,&VOLUME,2);
			DmWrite(recP,2,&ECHO,2);
			DmWrite(recP,4,&ECHOLEN,2);
			DmWrite(recP,6,&CLASSIC,1);
			MemHandleUnlock(rec);
		}
		DmCloseDatabase(iniDB);
	}
}

void loadOPTIONS(void)
{
	MemHandle cur_h;
	unsigned char *recP,*cur;
	unsigned char ss;
	unsigned int blocks;
	unsigned long sss,ssss;
	int filen,a;
    DmOpenRef iniDB;

    ID=DmFindDatabase(0,"PSYTEXX.INI");
		if(ID!=0){
			iniDB=DmOpenDatabase(0,ID,dmModeReadWrite);
			if(iniDB!=0){
				DmReleaseRecord(iniDB,0,0);
				cur_h=DmGetRecord(iniDB,0);
				cur=MemHandleLock(cur_h);
				MemMove(&VOLUME,cur,2);
				MemMove(&ECHO,cur+2,2);
				MemMove(&ECHOLEN,cur+4,2);
				MemMove(&CLASSIC,cur+6,1);
				MemHandleUnlock(cur_h);
				DmCloseDatabase(iniDB);
			}
		}

	echo_setup( echoP, ECHO, ECHOLEN );
	set_global_options();
}

//############################################################################
//############################################################################
//############################################################################


/*void LOAD() {
	soundINIT();
	modload();
	echo_setup( echoP, ECHO, ECHOLEN );
	ppnt=0;
	drawPattern();
	PatDraw;
	modplay(freq);
	START_CHANNEL = 0;
	cur_c = 0;
	cur_p = 0;
}*/

//########################### DEMO FUNCTIONS #################################
void drawChar2(UInt16 pnt,long sy,UInt16 cc)
{
  UInt16 aa,ddy;
  cc-=65;
  cc<<=3;cc<<=8;
  ddy=2048/sy;
  for(aa=0;aa<sy;aa++){
    bmp2P[pnt]|=myfont2H[cc>>8];
    cc+=ddy;
    pnt+=20;
  }
}
void draw_str(unsigned char *str)
{
  UInt16 aa,bb,dd;
  bb=0;
  MemMove(bmp2P,about_picH+16,1120);
  for(aa=0;aa<20;aa++){
    text_y[aa]-=2;if(text_y[aa]<8){text_y[aa]=8;}
    if(str[aa]!=' '){
      dd=(((56-text_y[aa])>>1)*20)+bb;
      drawChar2(dd,text_y[aa],str[aa]);
    }
    bb++;
  }
}
void draw_scope(UInt16 offset)
{
  UInt16 aa,dd,ee=0;
  long sum;

  MemSet(bmp2P,20*56,0);

  for(dd=0;dd<32;dd++){
  for(aa=0;aa<10;aa++){
	if(aa<CHANNELS) sum = ByteSwap16(channels[aa].summar_volume); else sum = 1;
	if(dd<sum) bmp2P[ee]^=255;
	ee+=2;
  }}
}
void one_demoframe()
{
  demo_timer1++;
  if(demo_timer1>40){demo_timer2++;}
  if(demo_timer2>20){demo_timer2=0;demo_timer1=0;toffset+=20;
                     if(toffset>=tsize){toffset=0;}}
  if(demo_timer2>0){text_y[demo_timer2-1]=50;
                    dtext[demo_timer2-1]=demo_text[demo_timer2+toffset-1];}
}
//############################################################################

Err main_callback(void *userData,
                  SndStreamRef stream,
                  void *_buffer,
                  UInt32 frameCount)
{
  long l;
  user_info *ui;
  ui=userData;
  ui->win32_buffer = (void*)ByteSwap32( _buffer );
  ui->win32_frameCount = ByteSwap32( frameCount );

  PceNativeCall( DLL_DIR, ui);
  //fillbuffer(_buffer,ui);
}

UInt32 PilotMain(UInt16 launchCode, void *cmdPBP, UInt16 launchFlags)
{
  UInt32 sx,sy,sd,processorType,version;
  long cf,a;
  Err err;
  ulong chrr;

  if(launchCode==sysAppLaunchCmdNormalLaunch)
  {
	appInfo = SysGetAppInfo( &ai1, &ai2 ); //For large memory managment

	mod_info.file_is_open = 0;
    autooff=SysSetAutoOffTime(0);
    armH = DmGetResource('armc', 1000);
    arm_code = MemHandleLock(armH);
    myfont =DmGetResource(0x54666E74,palmfont);
    myfont2=DmGetResource(0x74666E74,palmfont2);
    myfont3=DmGetResource(0x74666E74,palmfont3);
    myfontH =MemHandleLock(myfont);
    myfont2H=MemHandleLock(myfont2);
    myfont3H=MemHandleLock(myfont3);
    about_pic= DmGetResource(0x54626D70,0x03FA);
    about_picH=MemHandleLock(about_pic);
    bmp2=BmpCreate(160,56,1,0,&bmp_err); //scope
    bmp2P=BmpGetBits(bmp2);
    bmp_old=BmpCreate(PAT_SCREEN_X,PAT_SCREEN_Y,8,0,&bmp_err);
    bmpP=BmpGetBits(bmp_old);
    bmp=BmpCreateBitmapV3(bmp_old,kDensityDouble,bmpP,0);
    bmp22=BmpCreateBitmapV3(bmp2,kDensityDouble,bmp2P,0);
    scroll_bmp=BmpCreate(16,44,1,0,&bmp_err);
    scroll_bmpP=BmpGetBits(scroll_bmp);
    SAMPLENAME = MemHandleNew(32);
	fname=MemHandleNew(32);
    FntDefineFont(129,(FontPtr)myfont3H);
    Sampler_init();
	echo = MemHandleNew( 62000 );
	echoP = MemHandleLock( echo );
	MemSet( echoP, 62000, 0 );
    Fine_tune_init();

    arm_renderH = DmGetResource('armc', 1001);
    arm_render = MemHandleLock(arm_renderH);

	help_text_handler = DmGetResource('help', 2000);
	help_text_ptr = MemHandleLock(help_text_handler);

	//patterns init:
	for(a=0;a<128;a++){
#ifdef USE_STORAGE
		patterndata[a] = mem_new( CHANNELS_MAX*4*64 );
		patterndata2[a] = (note*)ByteSwap32(patterndata[a]);
#else
		patterndataH[a] = MemHandleNew(CHANNELS_MAX*4*64);
		patterndata[a] = MemHandleLock(patterndataH[a]);
		patterndata2[a] = (note*)ByteSwap32(patterndata[a]);
#endif
	}
	ClearPatterns();

    sx = 320; sy = 320; sd = 16;
    WinScreenMode( winScreenModeSet, &sx, &sy, &sd, 0 );
	//goto exitt;

	err = FtrGet(sysFileCSoundMgr, sndFtrIDVersion, &version); 
	if(err){
        // Sound Stream Feature Set not present
		model=1;freq=44100;
    } else {
        // The Sound Stream Feature Set is present.
		model=1;freq=44100;
    }
    soundINIT();
//############################ NEW SOUND INIT ################################
    create_user_info();
  if(model==1){
#ifndef SIMULATOR
    SndStreamCreate(&main_stream,
                    sndOutput,
                    freq,
                    sndInt16Little,
                    sndStereo,
                    arm_code,
                    &mod_info,
                    BUFSIZE,
                    1);
#else
    SndStreamCreate(&main_stream,
                    sndOutput,
                    freq,
                    sndInt16Little,
                    sndStereo,
                    main_callback,
                    &mod_info,
                    BUFSIZE,
                    0);
#endif
    port=1;
  }
//############################################################################
    if(port){
      FrmPopupForm(MainForm);
      GetEvent(1);
      drawmodlist();

	ECHO = 100; ECHOLEN = 24; VOLUME = 64; CLASSIC = 0;
	loadOPTIONS();
	set_volume( VOLUME );
	echo_setup( echoP, ECHO, ECHOLEN );

    newsearch();
    modload();
	echo_setup( echoP, ECHO, ECHOLEN );

    create_user_info();
	modplay(freq);
//############################ NEW SOUND PLAY ################################
    if(model==1) SndStreamStart(main_stream);
//############################################################################


    do
    {
m_c:
      GetEvent(0);
	  
	  chrr=KeyCurrentState();
	  if((chrr&0x1000000)!=0) { if(cur_p>0) cur_p--; else if(cur_c>0) {cur_p=4;cur_c--;} DrawPattern();PatDraw;} //LEFT
	  if((chrr&0x2000000)!=0) { if(cur_p<4) cur_p++; else if(cur_c<CHANNELS-1) {cur_p=0;cur_c++;} DrawPattern();PatDraw;} //RIGHT
	  if((chrr&0x4000000)!=0) { rec_status^=1; DrawPattern();PatDraw;} //FIRE
      
	  vlen=4;_srmControl(port,AUdrvOpCodeBusy,&value32,&vlen);
      if(value32<BUFSIZE){
        {
          if(model==0) fillbuffer(buffer,&mod_info);
          if(FrmGetActiveFormID()!=AboutForm){
          if(FrmGetActiveFormID()!=CloneForm){
          if(p_mode==1){
          if(mod_info._status>1){
          if(demo_mode==0){
            if(mod_info._update==1){
              ppnt=mod_info._patternpos / CHANNELS; drawPattern();PatDraw;
              mod_info._update=0;
            }
          }}}}}
          cf=FrmGetActiveFormID();
		  if(cf==MainForm || cf==ConfigForm){
            one_demoframe();
            //draw_str(dtext);
            draw_scope(150);
            WinDrawBitmap(bmp22,0,44);
          }
        }
        if(model==0) SrmSend(port,buffer,BUFSIZE,&err);
        _srmControl(port,AUdrvOpCodePlay,&value32,&vlen);
      }
    }while(event.eType!=appStopEvent);
    if(FrmAlert(Message1)==1){goto m_c;}

    mod_info._status=0;
    backup();
//############################ NEW SOUND CLOSE ###############################
    if(model==1) SndStreamDelete(main_stream);
//############################################################################
	saveOPTIONS();
	modclose();
    soundCLOSE();
    }

exitt:
	//patterns close:
	for(a=0;a<128;a++){
#ifdef USE_STORAGE
		mem_free( patterndata[a] );
#else
		MemHandleUnlock(patterndataH[a]);
		MemHandleFree(patterndataH[a]);
#endif
	}

  MemHandleUnlock(help_text_handler);

  MemHandleUnlock(arm_renderH);
  DmReleaseResource(arm_renderH);

  MemHandleUnlock( echo );
  Sampler_close();
  MemHandleUnlock( about_pic );
  MemHandleUnlock( myfont );
  MemHandleUnlock( myfont2 );
  MemHandleUnlock( myfont3 );
  MemHandleFree( fname );
  MemHandleFree( SAMPLENAME );
  MemHandleFree( echo );
  DmReleaseResource( myfont );
  BmpDelete(bmp_old);
  BmpDelete(bmp);
  BmpDelete(bmp2);
  BmpDelete(bmp22);
  BmpDelete(scroll_bmp);
  MemHandleUnlock(armH);
  SysSetAutoOffTime(autooff);
  }
  return 0;
}

