#define MAXIM  0x10000
#define VBLVAL 70938
#define VBLVALNTSC 71591
#define CIAVAL 1773447
#define CIAVALNTSC 1789772

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<proto/exec.h>
#include<exec/memory.h>
#include<proto/dos.h>
#include<proto/exec.h>
#include<proto/intuition.h>
#include<proto/gadtools.h>
#include<proto/reqtools.h>
#include<proto/graphics.h>
#include<devices/audio.h>
#include<libraries/reqtools.h>
#include<thom/thomdos.h>
#include"mix_rev.h"
#include"gadtools.h"

char ver[]=VERSTAG;

#define ABOUTTXT "Mod2Samp v0.78g\nby\nHali/Union\n\nGUI by Thom/Union"

// prototypy
void main(int,char **);
ULONG	mixer(struct kupa);
void adresysampli(BYTE *,struct sampel *,UWORD);
void HandleMainWnd(void);
void Work(void);
void RequestOK(char *);
void RequestAbout(void);
void PrintNote(ULONG);
void LoadModule(char *);
void SaveSample(char *);
void FreeMemory(void);
void Status(char *);
BOOL OpenAudio(void);
void CloseAudio(void);
void Play(void);
void adresysampli(BYTE *,struct sampel *,UWORD);
UWORD policzpatterny(BYTE *);
void SetDefault(APTR);
void SetTitle(void);
WORD	calculate_pom(WORD,WORD,ULONG,ULONG,UBYTE);
WORD	findperiod(WORD,BYTE,BYTE);

struct notes
{
	char a[4];
};

WORD  periodtab[16][12*3]={
	{ 856,808,762,720,678,640,604,570,538,508,480,453,    // Tuning 0, Normal
	  428,404,381,360,339,320,302,285,269,254,240,226,
	  214,202,190,180,170,160,151,143,135,127,120,113},
	{ 850,802,757,715,674,637,601,567,535,505,477,450,    // Tuning 1
	  425,401,379,357,337,318,300,284,268,253,239,225,
	  213,201,189,179,169,159,150,142,134,126,119,113},
	{ 844,796,752,709,670,632,597,563,532,502,474,447,    // Tuning 2
	  422,398,376,355,335,316,298,282,266,251,237,224,
	  211,199,188,177,167,158,149,141,133,125,118,112},
	{ 838,791,746,704,665,628,592,559,528,498,470,444,    // Tuning 3
	  419,395,373,352,332,314,296,280,264,249,235,222,
	  209,198,187,176,166,157,148,140,132,125,118,111},
	{ 832,785,741,699,660,623,588,555,524,495,467,441,    // Tuning 4
	  416,392,370,350,330,312,294,278,262,247,233,220,
	  208,196,185,175,165,156,147,139,131,124,117,110},
	{ 826,779,736,694,655,619,584,551,520,491,463,437,    // Tuning 5
	  413,390,368,347,328,309,292,276,260,245,232,219,
	  206,195,184,174,164,155,146,138,130,123,116,109},
	{ 820,774,730,689,651,614,580,547,516,487,460,434,    // Tuning 6
	  410,387,365,345,325,307,290,274,258,244,230,217,
	  205,193,183,172,163,154,145,137,129,122,115,109},
	{ 814,768,725,684,646,610,575,543,513,484,457,431,    // Tuning 7
	  407,384,363,342,323,305,288,272,256,242,228,216,
	  204,192,181,171,161,152,144,136,128,121,114,108},
	{ 907,856,808,762,720,678,640,604,570,538,508,480,    // Tuning -8
	  453,428,404,381,360,339,320,302,285,269,254,240,
	  226,214,202,190,180,170,160,151,143,135,127,120},
	{ 900,850,802,757,715,675,636,601,567,535,505,477,    // Tuning -7
	  450,425,401,379,357,337,318,300,284,268,253,238,
	  225,212,200,189,179,169,159,150,142,134,126,119},
	{ 894,844,796,752,709,670,632,597,563,532,502,474,    // Tuning -6
	  447,422,398,376,355,335,316,298,282,266,251,237,
	  223,211,199,188,177,167,158,149,141,133,125,118},
	{ 887,838,791,746,704,665,628,592,559,528,498,470,    // Tuning -5
	  444,419,395,373,352,332,314,296,280,264,249,235,
	  222,209,198,187,176,166,157,148,140,132,125,118},
	{ 881,832,785,741,699,660,623,588,555,524,494,467,    // Tuning -4
	  441,416,392,370,350,330,312,294,278,262,247,233,
	  220,208,196,185,175,165,156,147,139,131,123,117},
	{ 875,826,779,736,694,655,619,584,551,520,491,463,    // Tuning -3
	  437,413,390,368,347,328,309,292,276,260,245,232,
	  219,206,195,184,174,164,155,146,138,130,123,116},
	{ 868,820,774,730,689,651,614,580,547,516,487,460,    // Tuning -2
	  434,410,387,365,345,325,307,290,274,258,244,230,
	  217,205,193,183,172,163,154,145,137,129,122,115},
	{ 862,814,768,725,684,646,610,575,543,513,484,457,    // Tuning -1
	  431,407,384,363,342,323,305,288,272,256,242,228,
	  216,203,192,181,171,161,152,144,136,128,121,114}};

struct	kupa {				// user interface
	UBYTE	modstrt;
	UBYTE	modstop;
	UBYTE	speed;
	UBYTE	patt;
	WORD	destperd;
	UBYTE	volume;
	UBYTE	ciaspeed;
	UBYTE	ciaon;
	UBYTE	ntscon;
	UBYTE	resampling;
	UBYTE	sustain;
	};
struct  sampel {			// opis sampla
	UBYTE	volume;
	BYTE	*smpstrt;
	UWORD	smpstop;
	UWORD	repeat;
	UWORD	repeatlen;
	BYTE	finetune;
	};

char name[108],loadname[108],savename[108],BORING[]="Boring...",defmod[108],defsmp[108];
BOOL running=TRUE,playing=FALSE,mixed=FALSE;
UBYTE	whichannel[] = { 1,2,4,8 },*chipptr=NULL;
ULONG class,code,modlen,smplen,device,oldlen,kick;
APTR modptr=0,smpptr=0;
BPTR modhandle,smphandle;
struct IOAudio *AudioIO=NULL;
struct MsgPort *AudioMP=NULL;
struct IntuiMessage *message;
struct Library *ReqToolsBase;
struct DiskObject *icon;
struct rtFileRequester *file_req;
struct rtFileRequester *sfile_req;
struct notes notes[]=
{
	"C-1","C#1","D-1","D#1","E-1","F-1","F#1","G-1","G#1","A-1","A#1","B-1",
	"C-2","C#2","D-2","D#2","E-2","F-2","F#2","G-2","G#2","A-2","A#2","B-2",
	"C-3","C#3","D-3","D#3","E-3","F-3","F#3","G-3","G#3","A-3","A#3","B-3",
};
struct kupa sinfo={0,31,6,0,214,50,125,1,0};
extern struct Library *SysBase;

void main(int argc,char *argv[])
{
	kick=SysBase->lib_Version;

	if(kick>35)
	{
		if(ReqToolsBase=OpenLibrary("reqtools.library",0))
		{
			if(!(icon=TTGetOurIcon(WBenchMsg))) icon=GetDiskObject(argv[0]);
			if(icon)
			{
				strcpy(defmod,TTString(icon,"MODULE","PROGDIR:"));
				strcpy(defsmp,TTString(icon,"SAMPLE","PROGDIR:"));
				TTFreeOurIcon(icon);
			}
			if(file_req=rtAllocRequest(RT_FILEREQ,NULL))
			{
				if(sfile_req=rtAllocRequest(RT_FILEREQ,NULL))
				{
					rtChangeReqAttr( file_req,RTFI_Dir,defmod);
					rtChangeReqAttr(sfile_req,RTFI_Dir,defsmp);
					if(OpenAudio())
					{
						if(!SetupScreen())
						{
							if(!OpenMainWindow())
							{
								PrintNote(24);
								while(running)
								{
									Wait(1<<MainWnd->UserPort->mp_SigBit);
									HandleMainWnd();
								}
								CloseMainWindow();
							}
							else RequestOK("Can't open window");
							CloseDownScreen();
						}
						else RequestOK("Can't setup screen");
						CloseAudio();
					}
					else RequestOK("Can't allocate audio channel");
					rtFreeRequest(sfile_req);
				}
				else RequestOK("Can't allocate requester");
				rtFreeRequest(file_req);
			}
			else RequestOK("Can't allocate requester");
			CloseLibrary(ReqToolsBase);
		}
		else RequestOK("Can't open reqtools.library");
		FreeMemory();
	}
}

void HandleMainWnd()
{
	APTR windowlock;
	struct Gadget *gadget;
	struct MenuItem *item;

	while(message=GT_GetIMsg(MainWnd->UserPort))
	{
		class  = message->Class;
		code   = message->Code;
		gadget = (struct Gadget *)message->IAddress;
		GT_ReplyIMsg(message);
		switch(class)
		{
			case IDCMP_CLOSEWINDOW:
				running=FALSE;
				break;
			case IDCMP_MENUPICK:
				while(code!=MENUNULL) 
				{
					item = (struct MenuItem *) ItemAddress(MainMenus,code);
					switch(ITEMNUM(code))
					{
						case 0:	// About
							RequestAbout();
							break;
						case 2: // Quit
							running=FALSE;
							break;
					}
					code=item->NextSelect;
				}
				break;
			case IDCMP_MOUSEMOVE:
				switch(gadget->GadgetID)
				{
					case GD_PATTERN:
						sinfo.patt=code;
						break;
					case GD_START:
						sinfo.modstrt=code;
						break;
					case GD_END:
						sinfo.modstop=code;
						break;
					case GD_CIASPEED:
						sinfo.ciaspeed=code;
						break;
					case GD_VBLSPEED:
						sinfo.speed=code;
						break;
					case GD_FREQUENCY:
						PrintNote(code);
						sinfo.destperd=periodtab[0][code];
						break;
					case GD_VOLUME:
						sinfo.volume=code;
						break;
				}
				break;
			case IDCMP_GADGETUP:
				switch(gadget->GadgetID)
				{
					case GD_QUIT:
						running=FALSE;
						break;
					case GD_LOAD:
						windowlock=rtLockWindow(MainWnd);
						rtSetWaitPointer(MainWnd);
						if(rtFileRequest(file_req,name,"Select file...",
								RT_Window,			MainWnd,
								RT_Underscore,	'_',
								RT_ReqPos,			REQPOS_CENTERSCR,
								RTFI_Height,		256,
								RTFI_OkText,		"_Ok...",
								TAG_DONE))
						{
							strcpy(loadname,file_req->Dir);
							if(loadname[strlen(loadname)>0])
								if(loadname[strlen(loadname)-1]!=':') strcat(loadname,"/");
							strcat(loadname,name);
							Status("Loading...");
							LoadModule(loadname);
							SetDefault(modptr);
							Status(BORING);
						}
						rtUnlockWindow(MainWnd,windowlock);
						break;
					case GD_SAVE:
						windowlock=rtLockWindow(MainWnd);
						rtSetWaitPointer(MainWnd);
						if(rtFileRequest(sfile_req,name,"Select file...",
								RT_Window,			MainWnd,
								RT_Underscore,	'_',
								RT_ReqPos,			REQPOS_CENTERSCR,
								RTFI_Flags,			FREQF_SAVE,
								RTFI_Height,		256,
								RTFI_OkText,		"_Ok...",
								TAG_DONE))
						{
							strcpy(savename,sfile_req->Dir);
							if(savename[strlen(savename)>0])
								if(savename[strlen(savename)-1]!=':') strcat(savename,"/");
							strcat(savename,name);
							Status("Loading...");
							SaveSample(savename);
							Status(BORING);
						}
						rtUnlockWindow(MainWnd,windowlock);
						break;
					case GD_PLAY:			// disabled
//						windowlock=rtLockWindow(MainWnd);
//						rtSetWaitPointer(MainWnd);
						Status("Playing...");
						Play();
						Status(BORING);
						SetTitle();
//						rtUnlockWindow(MainWnd,windowlock);
						break;
					case GD_MIX:
						windowlock=rtLockWindow(MainWnd);
						rtSetWaitPointer(MainWnd);
						Status("Working...");
						Work();
						Status(BORING);
						rtUnlockWindow(MainWnd,windowlock);
						break;
					case GD_CIA:
						sinfo.ntscon=code;
						break;
					case GD_INTERRUPT:
						if(code) sinfo.ciaon=0;
						else sinfo.ciaon=1;
						break;
					case GD_RESAMPLING:
						sinfo.resampling=(UBYTE) code;
						break;
					case GD_PATTERN:
						sinfo.patt=code;
						break;
					case GD_START:
						sinfo.modstrt=code;
						break;
					case GD_END:
						sinfo.modstop=code;
						break;
					case GD_CIASPEED:
						sinfo.ciaspeed=code;
						break;
					case GD_VBLSPEED:
						sinfo.speed=code;
						break;
					case GD_FREQUENCY:
						PrintNote(code);
						sinfo.destperd=periodtab[0][code];
						break;
					case GD_VOLUME:
						sinfo.volume=code;
						break;
					case GD_SUSTAIN:
						sinfo.sustain=code;
						break;
				}
				break;
		}
	}
}

void PrintNote(ULONG code)
{
	char notetxt[4];

	sprintf(notetxt,"%s",notes[code].a);
	GT_SetGadgetAttrs(MainGadgets[GD_PITCHTEXT],MainWnd,NULL,GTTX_Text,notetxt,TAG_DONE);
}

void Work()
{
	int a;
	ULONG *ptr;

	if(modptr)
	{
//		printf(" Module length : %i \n",modlen);
//		printf(" Module name   : %s \n",modptr);
//		printf(" Module mark   : %s \n",(ULONG)modptr+1080);
//		memset(smpptr,0,2*MAXIM);
		ptr=smpptr;
		for(a=0;a<MAXIM/2;a++) ptr[a]=0L;
		smplen=mixer(sinfo);
	}
	else
		RequestOK("No module in memory");
}




/**********************************\
*                                  *
*               Mixer              *
*                                  *
\**********************************/

#define	FIND_ANYTHING(ptr)  (*((ULONG *)(ptr)))
#define	FIND_PERIOD(ptr)    (*((UWORD *)ptr)&0x0fff)
#define	FIND_SMPNUMBER(ptr) (((*ptr)&(0xf0))+((*(ptr+2))>>4))
#define	FIND_EFFECT(ptr)    ((*(ptr+2))&0x0f)
#define	FIND_PARAMETR(ptr)  (*(ptr+3))


ULONG	mixer(sinfo)
struct	kupa sinfo;
{
	char	text[20];
	BYTE	*module;            // adres moduîu
	WORD	*fromword;          // pointery do zamiany z word'ow na
	BYTE	*tobyte;            // bajty
	ULONG	len;                // koncowa dlugosc sampla
	ULONG	h,i,j,k;            // zmienne do organizacji petli
	UWORD	hipatt=0;           // tu bedzie ilosc pattern'ów
	ULONG	ilenapoz;           // ile sampla wygenerowac
                                // do nastepnej pozycji
	WORD	*ptr2smp;           // pointery do generowania
	WORD	*ptr2smppom;        // zmiksowanego sampla ( w word'ach)
	UBYTE	*ptr2mod;           // pointer do przesuwania sie 
                                // po module
	UBYTE	speed;              // aktualna predkosc
	UBYTE	ciaspeed;
	UBYTE	ilepozycji;         // ile pozycji do zrobienia
	UWORD	pomoc;
	WORD	pom;
	WORD	probka0,probka1;
	UBYTE	sust;

	struct	sampel smp[32];     // tablica pointerow do sampli 
	struct	canal {             // co sie dzieje w kanale
		BYTE	nrsmp;       // numer odgrywanego sampla
		BYTE	volume;      // gîoônoôê sampla
		WORD	period;      // period
		ULONG	jump;
		ULONG	jumppos;
		UWORD	smppos;
		BYTE	*smpstrt;
		UWORD	smpstop;
		UWORD	smprepeat;
		UWORD	smprepeatlen;
		BYTE	volslide;    // do komendy - Axx
		UBYTE	last9;       // do komendy - 9xx
		UBYTE	actE9;       // do komendy - E9x
		UBYTE	notecut;     // do komendy - ECx
		WORD	trgetperd;   // do komendy - 3xx
		WORD	toneslide;   // ----------------
		WORD	lasttrget;   // ----------------
		WORD	lasttonesl;  // ----------------
		UBYTE	arpeggio;    // do komendy - 0xx
		WORD	saveperd;    // ----------------
		};
	struct	canal chan[4]={{0,0,0,0,0,0,0,0},
	                       {0,0,0,0,0,0,0,0},
	                       {0,0,0,0,0,0,0,0},
	                       {0,0,0,0,0,0,0,0}};
	struct	line {
		ULONG	anything;
		WORD	period;
		UBYTE	smpnumber;
		UBYTE	effect;
		UBYTE	parametr;
	};
	struct	line	trackline[4];


	sust=sinfo.sustain;
	module=modptr;
	ptr2smp=smpptr;
	hipatt=policzpatterny(module);
	adresysampli(module,smp,hipatt);
	speed=sinfo.speed;
	ciaspeed=sinfo.ciaspeed;
	if(sust){
	  ilepozycji=sinfo.modstop+1;
	  ptr2mod=module+1084+1024*sinfo.patt; // ustawienie sie na odpowiednia pozycje
	}
	else{
	  ilepozycji=sinfo.modstop-sinfo.modstrt+1;
	  ptr2mod=module+1084+1024*sinfo.patt+16*sinfo.modstrt; // ustawienie sie na odpowiednia pozycje
	}

//	if(debug)  printf("   Destination Period = %i\n",sinfo.destperd);


//	printf("   Wow! There will be %i positions. \n    >",ilepozycji);
	for(h=0;h<=(ilepozycji-1);h++){

	  if((sust)&&(h>=sinfo.modstrt)) sust=0;

	  for(i=0;i<=3;i++){
	    trackline[i].anything  = (ULONG)FIND_ANYTHING(ptr2mod);
	    trackline[i].period    = (WORD)FIND_PERIOD(ptr2mod);
	    trackline[i].smpnumber = (UBYTE)FIND_SMPNUMBER(ptr2mod);
	    trackline[i].effect    = (UBYTE)FIND_EFFECT(ptr2mod);
	    trackline[i].parametr  = (UBYTE)FIND_PARAMETR(ptr2mod);
	    ptr2mod=ptr2mod+4;
	  }

//	  if(debug){
//	    printf("\n"); 
//	    for(i=0;i<=3;i++){
//	      if(trackline[i].period) printf("  J-4");
//	      else printf("  ---");
//	      printf("%2x%1x%2x",trackline[i].smpnumber,trackline[i].effect,trackline[i].parametr);
//	    }
//	  }




	  for(i=0;i<=3;i++){
	    chan[i].volslide=0;
	    chan[i].actE9=0;
	    chan[i].toneslide=0;
	    chan[i].arpeggio=0;
	    chan[i].saveperd=0;
	    if(trackline[i].smpnumber){
 	      chan[i].nrsmp=trackline[i].smpnumber;
	      chan[i].volume=smp[chan[i].nrsmp].volume;
	    }
	    pomoc=0;
	    if(trackline[i].effect==0x03) pomoc=1;
	    if(trackline[i].effect==0x05) pomoc=1;
	    if( (trackline[i].period)&&(pomoc==0) ){
	      chan[i].period=trackline[i].period;
	      chan[i].trgetperd=0;
	      if( smp[chan[i].nrsmp].finetune)
	        chan[i].period = findperiod( chan[i].period, smp[chan[i].nrsmp].finetune,0);
	      chan[i].smpstrt=smp[chan[i].nrsmp].smpstrt;
	      chan[i].smpstop=smp[chan[i].nrsmp].smpstop;
	      chan[i].smprepeat=smp[chan[i].nrsmp].repeat;
	      chan[i].smprepeatlen=smp[chan[i].nrsmp].repeatlen;
	      chan[i].smppos=0;
	      chan[i].jumppos=0;
	    }
	    switch(trackline[i].effect){
	      case 0x0f:
	        if( (sinfo.ciaon)&&(trackline[i].parametr>0x1f) )
	          ciaspeed=trackline[i].parametr;
	        else
	          speed=trackline[i].parametr;
	        break;
	      case 0x0e:
	        switch(trackline[i].parametr>>4){
	          case 0x09:
	            chan[i].actE9=trackline[i].parametr&0x0f;
	          break;
	          case 0x0a:
	            chan[i].volume+=trackline[i].parametr&0x0f;
	          break;
	          case 0x0b:
	            chan[i].volume-=trackline[i].parametr&0x0f;
	          break;
	          case 0x0c:
	            chan[i].notecut=(trackline[i].parametr&0x0f)+1;
	          break;
	          case 0x02:
	            chan[i].period+=trackline[i].parametr&0x0f;
	            if( chan[i].period>findperiod(856,smp[chan[i].nrsmp].finetune,0) )
	              chan[i].period=findperiod(856,smp[chan[i].nrsmp].finetune,0);
	          break;
	          case 0x01:
	            chan[i].period-=trackline[i].parametr&0x0f;
	            if( chan[i].period<findperiod(113,smp[chan[i].nrsmp].finetune,0) )
	              chan[i].period=findperiod(113,smp[chan[i].nrsmp].finetune,0);
	          break;
	        }
	        break;
	      case 0x0c:
	        chan[i].volume=trackline[i].parametr;
	        break;
	      case 0x0a:
	        if( (trackline[i].parametr)&0xf0)
	          chan[i].volslide=(trackline[i].parametr>>4)&0x0f;
	        else
	          chan[i].volslide=-trackline[i].parametr;
	        break;
	      case 0x09:
	        if(trackline[i].parametr)
	          chan[i].last9=trackline[i].parametr;
	        pomoc=((UWORD)chan[i].last9)<<8;
	        if(pomoc>(chan[i].smpstop))
	          chan[i].smppos=chan[i].smprepeat;
	        else
	          chan[i].smppos=pomoc;
	        chan[i].jumppos=0;
	        break;
	      case 0x05:
	        if( (trackline[i].parametr)&0xf0)
	          chan[i].volslide=(trackline[i].parametr>>4)&0x0f;
	        else
	          chan[i].volslide=-trackline[i].parametr;
	        if(trackline[i].period){
	          chan[i].trgetperd=findperiod(trackline[i].period,smp[chan[i].nrsmp].finetune,0);
	          chan[i].lasttrget=chan[i].trgetperd;
	        }
	        else{
	          chan[i].trgetperd=chan[i].lasttrget;
	        }
	        if( chan[i].period>chan[i].trgetperd )
	          chan[i].toneslide=-chan[i].lasttonesl;
	        else
	          chan[i].toneslide=chan[i].lasttonesl;
	        if(chan[i].trgetperd==0) chan[i].toneslide=0;
	        break;
	      case 0x03:
	        if(trackline[i].period){
	          chan[i].trgetperd=findperiod(trackline[i].period,smp[chan[i].nrsmp].finetune,0);
	          chan[i].lasttrget=chan[i].trgetperd;
	        }
	        else{
	          chan[i].trgetperd=chan[i].lasttrget;
	        }
	        chan[i].lasttonesl=trackline[i].parametr;
	        if( chan[i].period>chan[i].trgetperd )
	          chan[i].toneslide=-trackline[i].parametr;
	        else
	          chan[i].toneslide=trackline[i].parametr;
	        if(chan[i].trgetperd==0) chan[i].toneslide=0;
	        break;
	      case 0x02:
	        chan[i].trgetperd=findperiod(856,smp[chan[i].nrsmp].finetune,0);
	        chan[i].toneslide=trackline[i].parametr;
	        break;
	      case 0x01:
	        chan[i].trgetperd=findperiod(113,smp[chan[i].nrsmp].finetune,0);
	        chan[i].toneslide=-trackline[i].parametr;
	        break;
	      case 0x00:
	        if(trackline[i].parametr){
	          chan[i].arpeggio=trackline[i].parametr;
	          chan[i].saveperd=chan[i].period;
	        }
	        break;
	    } 
	  }

	  // ile probek
	  if(sinfo.ciaon){
	    if(sinfo.ntscon)
	      ilenapoz=((CIAVALNTSC*5)/ciaspeed)/sinfo.destperd;
	    else
	      ilenapoz=((CIAVAL*5)/ciaspeed)/sinfo.destperd;
	  }
	  else{  
	    if(sinfo.ntscon)
	      ilenapoz=VBLVALNTSC/sinfo.destperd;
	    else
	      ilenapoz=VBLVAL/sinfo.destperd;
	  }

	  // mixowanie
	  for(i=0;i<=3;i++){
	  ptr2smppom=ptr2smp;
	  //printf("\n");
	    for(k=0;k<=(speed-1);k++){
	      // comman E9x retrig note
	      if(chan[i].actE9){
	        if( (k-(k/chan[i].actE9)*chan[i].actE9)==0 ){
	          chan[i].smppos=0;
	          chan[i].jumppos=0;
	          chan[i].smpstop=smp[chan[i].nrsmp].smpstop;
	        }
	      }
	      // comman ECx note cut
	      if(chan[i].notecut){
	        if( k==(chan[i].notecut-1) ){
	          chan[i].volume=0;
	        }
	      }
	      // command Axx volsliding
	      if((chan[i].volslide)&&(k!=0)){
	        chan[i].volume=chan[i].volume+chan[i].volslide;
	        if(chan[i].volume<0) chan[i].volume=0;
	        if(chan[i].volume>64) chan[i].volume=64;
	      }
	      // command 3xx tone sliding
	      if((chan[i].toneslide)&&(k!=0)){
	        //printf("!");
	        chan[i].period+=chan[i].toneslide;
	        if(chan[i].toneslide<0){
	          if(chan[i].period<chan[i].trgetperd)
	            chan[i].period=chan[i].trgetperd;
	        }
	        else{
	          if(chan[i].period>chan[i].trgetperd)
	            chan[i].period=chan[i].trgetperd;
	        }
	      }
	      // command 0xx arpeggio
	      if(chan[i].arpeggio){
                switch( k-(k/3)*3 ){
	          case 2:
	            chan[i].period=findperiod( chan[i].saveperd, smp[chan[i].nrsmp].finetune, chan[i].arpeggio&0x0f);
	            break;
	          case 1:
	            chan[i].period=findperiod( chan[i].saveperd, smp[chan[i].nrsmp].finetune, chan[i].arpeggio>>4);
	            break;
	          case 0:
	            chan[i].period=chan[i].saveperd;
	            break;
	        }
	      }

	      //printf(" %i",chan[i].period);

	      if(chan[i].period!=0)
	        chan[i].jump=(((ULONG)sinfo.destperd)<<16)/chan[i].period;
	      else
	        chan[i].jump=0;

	      // generowanie sampla
	      for(j=0;j<=ilenapoz;j++){
	        if((ULONG)ptr2smppom>=(ULONG)smpptr+MAXIM*2) break; // jesli przekroczymy bufor to stop

	        chan[i].smppos+=(UWORD)(chan[i].jumppos>>16);
	        chan[i].jumppos=chan[i].jumppos&0xffff;

	        if(chan[i].smppos>=chan[i].smpstop){
	           chan[i].smppos=chan[i].smprepeat+(chan[i].smppos-chan[i].smpstop);
	           chan[i].smpstop=chan[i].smprepeat+chan[i].smprepeatlen;
	        }

	        probka0=*(chan[i].smppos+chan[i].smpstrt);
	        probka1=*(chan[i].smppos+chan[i].smpstrt+1);
	        if((chan[i].smppos+1)>=chan[i].smpstop){
	            probka1=*(chan[i].smprepeat+chan[i].smpstrt);
	        }

	        pom=calculate_pom(probka0,probka1,chan[i].jumppos,chan[i].jump,sinfo.resampling);

	        if(sust==0){
	          *ptr2smppom+=(pom*chan[i].volume)/64;
	          ptr2smppom++;
	        }
	        chan[i].jumppos+=chan[i].jump;
	      }
	    }
	    if(chan[i].saveperd){
	      chan[i].period=chan[i].saveperd;
	    }
	  }
	  ptr2smp=ptr2smppom;
//	  printf("*");
	}
//	printf("\n");

	// obcinanie
	len=((ULONG)ptr2smp-(ULONG)smpptr)/2;
	fromword=smpptr;
	tobyte=smpptr;
	for(i=0;i<=len;i++){
	  pom=((*fromword++)*sinfo.volume)/100;
	  if(pom>127) pom=127;
	  if(pom<-128) pom=-128;
	  *tobyte++=pom;
	  if((i>>10)<<10==i)
	  {
			sprintf(text,"%i",i);
			Status(text);
		}
//	    printf("\r   hmm ... : %i ",i);
	}
//	printf("\r   OK it's: %i \n",i);
	sprintf(text,"%i",i);
	Status(text);

	mixed=TRUE;

	return(len);
}

WORD	findperiod(mainperiod,finetune,index)
WORD	mainperiod;
BYTE	finetune;
BYTE	index;
{
	UWORD	i;

	for(i=0;i<=12*3;i++)
	  if(mainperiod==periodtab[0][i]) break;
	i=i+index;
	if(i>=12*3) return(0);

	return(periodtab[finetune][i]);
}

WORD	calculate_pom(sample0,sample1,jumppos,jump,method)
WORD	sample0;
WORD	sample1;
ULONG	jumppos;
ULONG	jump;
UBYTE	method;
{
	WORD	a;
	WORD	i;
	ULONG	myjumppos;

	if(jump==0)
	  return(0);

	myjumppos=jumppos;

    if(method){
	  for(i=1;(jump)<(0x10000/(i+1));i++);
	  //printf("i= %i\n",i);
	  if(i>1){
	    if(jumppos<((0x10000/i)*(i-1)))
	      return(sample0);
	    else{
	      myjumppos=(jumppos-((0x10000/i)*(i-1)))*i;
	    }
	  }
	}

	a=sample1-sample0;
	a=(WORD)(((LONG)myjumppos*a)>>16);
	a=a+sample0;
	return(a);
}


UWORD	policzpatterny(module)
BYTE	*module;
{
	UWORD	pomoc;
	UWORD	i;
	UWORD	hipat=0;

	for(i=0;i<=127;i++){
	  pomoc=*((UBYTE *)(module+952+i));
	  hipat=(hipat>pomoc)?hipat:pomoc;
	}
	hipat++;
	return(hipat);
}



void	adresysampli(module,smp,hipatt)
BYTE	*module;
struct	sampel smp[];		// tablica pointerow do sampli 
UWORD	hipatt;
{
	UWORD	i;
	UWORD	pomoc;

	smp[1].smpstrt=module+1084+1024*hipatt;
	smp[1].smpstop=(*((UWORD *)(module+42)))*2;
	smp[1].volume=*((UBYTE *)(module+45));
	smp[1].repeat=(*((UWORD *)(module+46)))*2;
	smp[1].repeatlen=(*((UWORD *)(module+48)))*2;
	smp[1].finetune=*((UBYTE *)(module+44));
	for(i=2;i<=31;i++){
	  pomoc=*((UWORD *)(module+42+30*(i-2)));
	  smp[i].smpstrt=smp[i-1].smpstrt+pomoc*2;
	  smp[i].smpstop=(*((UWORD *)(module+42+30*(i-1))))*2;
	  smp[i].volume=*((UBYTE *)(module+45+30*(i-1)));
	  smp[i].repeat=(*((UWORD *)(module+46+30*(i-1))))*2;
	  smp[i].repeatlen=(*((UWORD *)(module+48+30*(i-1))))*2;
	  smp[i].finetune=*((UBYTE *)(module+44+30*(i-1)));
      if(smp[i].repeat)  smp[i].smpstop=smp[i].repeat+smp[i].repeatlen;
	}

//	if(debug){
//	  for(i=1;i<=8;i++)
//	    printf(" %2i.  vol %-2x   strt $%-6x   stop $%-4x %-5i repeat $%-4x repeatlen $%-4x \n",i,smp[i].volume,smp[i].smpstrt,smp[i].smpstop,smp[i].smpstop,smp[i].repeat,smp[i].repeatlen);
//	}
}

/*------------------------------------------------------------------------------*/

void RequestOK(char *what)
{
	APTR windowlock;

	windowlock=rtLockWindow(MainWnd);
	rtSetWaitPointer(MainWnd);
	rtEZRequestTags(what,"_Ok",NULL,NULL,RT_Underscore,'_',RT_Window,MainWnd,TAG_DONE);
	rtUnlockWindow(MainWnd,windowlock);
}

void RequestAbout()
{
	APTR windowlock;

	windowlock=rtLockWindow(MainWnd);
	rtSetWaitPointer(MainWnd);
	rtEZRequestTags(ABOUTTXT,"_Ok",NULL,NULL,RT_Underscore,'_',
					RT_Window,MainWnd,
					RTEZ_Flags,EZREQF_CENTERTEXT,
					TAG_DONE);
	rtUnlockWindow(MainWnd,windowlock);
}

void LoadModule(char *filename)
{
	FreeMemory();
	if(modhandle=Open(filename,MODE_OLDFILE))
	{
		Seek(modhandle,0,OFFSET_END);
		modlen=Seek(modhandle,0,OFFSET_BEGINNING);
		if(modptr=AllocMem(modlen,MEMF_PUBLIC))
		{
			Read(modhandle,modptr,modlen);
			if(*((ULONG *)((ULONG)modptr+1080))!=*((ULONG *)"M.K."))
			{
				RequestOK("This is not a ProTracker module");
				FreeMem(modptr,modlen);
				modptr=0;
			}
			if(!(smpptr=AllocMem(MAXIM*2,MEMF_CLEAR|MEMF_PUBLIC)))
			{
				RequestOK("Not enough memory to allocate sample buffer.");
				FreeMem(smpptr,MAXIM*2);
				modptr=0;
			}
			mixed=FALSE;
		}
		else
			RequestOK("Not enough memory");
		Close(modhandle);
	}
	else
		RequestOK("Can't open module");
}

void SaveSample(char *filename)
{
	if(modptr && smpptr)
	{
		if(smphandle=Open(filename,MODE_NEWFILE))
		{
			if(Write(smphandle,smpptr,smplen)==-1)
			{
		  	RequestOK("Can't save file.");
			}
			Close(smphandle);
		}
		else
			RequestOK("Can't open file to save");
	}
}

void FreeMemory()
{
	if(modptr) FreeMem(modptr,modlen);
	modptr=0;
	if(smpptr) FreeMem(smpptr,MAXIM*2);
	smpptr=0;
}

void Status(char *text)
{
	GT_SetGadgetAttrs(MainGadgets[GD_STATUS],MainWnd,NULL,GTTX_Text,text,TAG_DONE);
}

BOOL OpenAudio()
{
	if(AudioMP = CreatePort(0,0))
	{
		if(AudioIO=(struct IOAudio *)CreateExtIO(AudioMP,sizeof(struct IOAudio)))
		{
			AudioIO->ioa_Request.io_Command = ADCMD_ALLOCATE;
			AudioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 50;
			AudioIO->ioa_AllocKey = 0;
			AudioIO->ioa_Data     = whichannel;
			AudioIO->ioa_Length   = sizeof(whichannel);
			if(!(device=OpenDevice(AUDIONAME,0L, (struct IORequest *) AudioIO ,0L)))
			{
				return(1);
			}
		}
	}
	return(0);
}

void CloseAudio()
{
	if (device == 0) CloseDevice((struct IORequest *) AudioIO);
	if (AudioIO != 0) DeleteExtIO((struct IORequest *)AudioIO);
	if (AudioMP != 0) DeletePort(AudioMP);
}

void Play()
{
	if(playing)
	{
		AbortIO((struct IORequest *)AudioIO);
		playing=FALSE;
		if(chipptr) FreeMem(chipptr,oldlen);
		chipptr=NULL;
	}
	else
	{
		if(mixed)
		{
			if(smpptr)
			{
				if(chipptr=AllocMem(smplen,MEMF_CHIP))
				{
					playing=TRUE;
					oldlen=smplen;
					CopyMem(smpptr,(APTR) chipptr,smplen);
					AudioIO->ioa_Request.io_Command=CMD_WRITE;
					AudioIO->ioa_Request.io_Flags  =ADIOF_PERVOL;
					AudioIO->ioa_Data  =chipptr;
					AudioIO->ioa_Length=smplen;
					AudioIO->ioa_Period=sinfo.destperd;
					AudioIO->ioa_Volume=64;
					AudioIO->ioa_Cycles=0;
					BeginIO((struct IORequest *)AudioIO);
//					WaitIO((struct IORequest *)AudioIO);
//					AbortIO((struct IORequest *)AudioIO);
//					FreeMem(chipptr,smplen);
				}
			}
		}
		else
			RequestOK("No sample in memory");
	}
}

void SetDefault(APTR modptr)
{
	UWORD patts;

	patts=policzpatterny(modptr);
	GT_SetGadgetAttrs(MainGadgets[GD_PATTERN],MainWnd,NULL,GTSL_Max,(ULONG)patts-1,TAG_DONE);
}

void SetTitle()
{
//	if(playing)	MainGadgets[GD_PLAY]->GadgetText="Stop";
//	else MainGadgets[GD_PLAY]->GadgetText="Play";
//	GT_RefreshWindow(MainWnd,NULL);
}
