
#define TIMER_INT (int)100 //alle 100ms puffer berechnen 
extern ifstream f;

//*******************Prototypes***********************
void sig_handle(int);
//****************************************************

word dwbufferlength;
int  surrbufferlen=4096;//Achtung ebenfalls in asmplay.s (SurrBufferLen)
byte surrlength=15;

//********************Fileobject fuer Modfiles**************************
ifstream f;	
string filename;

//****************globale variablen*************************************************


   //modul-infos
   tmodtype filetype ;              //fileformat
   word filesiz;                  //dateigroesse in kbyte
   string modname;
   word numtracks;                  //anzahl der kanaele pro notenzeile
   word difftracks;                  //anzahl der voneinander verschiedenen gespielten tracks
   word numinstruments;
   tinstrument instruments[256];
   word dummypatterns;                  //anzahl der gespeicherten aber nicht gespielten patterns
   int32 extrabytes;               //ueberlaenge des files
   int32 missingbytes;               //fehlende bytezahl
   word effectsused;                  //bit gesetzt=effekt benutzt
   word proeffectsused;               //bit gesetzt=effekt benutzt
   word extraeffused;                  //bit gesetzt=effekt benutzt
   word extraeffused1;                  //bit gesetzt=effekt benutzt
   word panningoff;              //panning wird nicht benutzt
   int32 songmem;               //speichergroesse fuer pattern und samples
   int32 playmemtop;               //speichergroesse fuer playbuffers
   int loopfrom;               //pattern, von dem aus geloopt wird
   int loopto;               //pattern, zu welchem geloopt wird
   boolean playing;              //modul spielt
   int32 cpuusage;               //aktuelle cpu-auslastung
   int32 totaltime;               //gesamtspielzeit [ms]
   int32 currtime;               //aktuell zu hrende zeit [ms]
   int32 buftimelen;               //samplepufferlnge [ms]
   word currpttrn;                  //aktuell zu hrendes pattern
   word numpatterns;                  //gre des patternarrangements
   word diffpatterns;                  //anzahl der voneinander verschiedenen gespielten pattern
   word currline;
   effectstate curreffects;           //zu hrende effekte
   effectstate currproeffects;           //zu hrende protracker-effekte
   effectstate currextraeff;           //zu hrende stm/okt...-effekte
   effectstate currextraeff1;           //zu hrende stm/okt...-effekte
   tbytestate currinstr ;
   tbytestate currvols;
   tbytestate currnotes;
   byte currspd;
   byte currbpm;
   word commentlen;
   pcommentbuf comment;

   //ende der info.............

// Zeitnahme
itimerval timertime;
struct sigaction Sig_Action={sig_handle,0,SA_NOMASK,NULL};

   int32 i,j,k;   //allgemein zum zaehlen

   //speicherhandling
   void *songmemhandle;
   void *songmemsel;
   int32 songmemofs;

/*aufbau songmem:
     tracks     ...[1..32][0..numpatterns-1]of word
     pattern    ...statisches pattern zum spielen [1..numtracks][0..maxpattlen-1(63)]of tnote
     trackdata  ...[0..lasttrack]of ttrack
     samples
*/
   void *playmemhandle;
   void *songmemtop;
   int32 instrmemsize;
   int32 trackmemsize;
   int32 firsttrack;
   //waveout-var's
   tsettings soundsettings ;
   byte playmode;                  //8bit mono...16bit stereo
   int32 notestretch;
   int32 wavestrt;
   int32 waveofs;
   int32 waveend;
   byte *currbuffer;
   byte *lastbuffer;
   word buffersize;

   //zeitgeber-var's
   word amplaying;
   boolean ende;
   boolean notplay;

   //spielstatus
   ptrackseq     tracks;
   word          lasttrack;             //letzte gespielte tracknummer
   ppattern      pattern;               //enthaelt aktuelle daten zum abspielen
   char ptrntempi[256];
   byte ptrnbreaks[256];
   byte lastpattern;                  //letzte gespielte patternnummer
   boolean alreadyplayed[256];//pattern wurde schon gespielt

   byte currpattern;                  //aktuelle patternnummer
   byte currnote;                  //notenzeile im pattern
   byte currvblanc;                  //vblanc-takt

   byte speed;
   byte bpmspeed;
   word numsamples;                  //anzahl der samples fuer 1/50 sec

   boolean pm_is_working;
   boolean mod_end;
   boolean repeatsong;

   int32 playtime;               //zeit des aktuellen songs in ms
   int32 loopfromtime;               //zeit fr looping
   int32 looptotime;
   int32 timestep;
   word timesteprest;
   pplaytimes playtimes     ;
   int32 searchtime;               //zu suchende position beim spulen
   boolean search;               //nicht spielen, sondern spulen
   int32 starttime;               //systemzeit bei eintritt in play_the_module
   boolean Pause_;               //pause aktiv
   boolean amrepeating;
   byte repeatbuffer;

   int32 patterntimes[256];
   boolean searchpattern ;
   byte searchp       ;
   byte searchl       ;


  //kanaele
   char sintable[256],ramptable[256],rndtable[256],sqrtable[256];    //sinustabelle fuer vibrato,tremolo
   void *vtable,*ttable;
   boolean glissandoon;

   boolean delaypattern;
   byte patterndelay;
   byte patternloopst;
   byte patternloops;
   byte patternloopend;
   tpanarray defpanning;
   tchannel asmchn        ;
   tchannels channels     ;
   byte initspeed;
   byte initbpmspeed;
   word stmsamplememofs[32];
   int bufstart,bufend;

   int error;
   boolean forcerange;
// ------------ende der datendefinitionen ----------------------


static word result;
static boolean reached;
static word bufsize;
static byte *pbuffer;
static int32 unilong;

byte parrangement[256];

void gettotaltime(void){
boolean pjump, pbreak;
byte jumpto, breakto;
boolean forcebpm=false;
boolean noteplayed[256];

	//tatsaechlich hoechstes, erreichbares pattern ermitteln
        memset(patterntimes,0,sizeof(patterntimes));
	memset(alreadyplayed,0,sizeof(alreadyplayed));
	i=0;
	panningoff=true;
	forcebpm=true;
	dosetspeed(initbpmspeed);
	forcebpm=false;
	dosetspeed(initspeed);
  playtime=0;
  if ( (filetype!=f669)&&(filetype!=unis)&&(filetype!=ffar)){
    loopto=-1;
    loopfrom=-1;
  };
  loopfromtime=-1;
  patterndelay=0;
  patternloops=0;
  breakto=0;
  memset(noteplayed,0,256);
  do{
    getpattern(i);
    unilong=playtime;
    patterntimes[i]=playtime;
    if ( ptrntempi[i]>0 ) dosetspeed(ptrntempi[i]);
    for (j=breakto; j<=ptrnbreaks[i];j++)
    {
      breakto=0;
      for (k=0;k<numtracks;k++){
     // with pattern^[k][j] do
  	   byte& instrument= (*pattern)[k][j].instrument;
           word& ton= (*pattern)[k][j].ton;
           byte& effekt= (*pattern)[k][j].effekt;
           byte& operands= (*pattern)[k][j].operands;
           char& chnvol= (*pattern)[k][j].chnvol;
        printf("operand: %6x effekt: %6x \n",operands,effekt);
	 switch ( effekt ){
		case setspeed : dosetspeed(operands);break;
		case setbpmspeed    :{ forcebpm=true; dosetspeed(operands); forcebpm=false; } break;
		case finetempoup    :dofinefartempo (operands);break;
		case finetempodwn   :dofinefartempo (-operands);break;
		case panning        :if ((operands!=0)&&(operands!=128)) panningoff=false;break;
		case portamento_up  :if ((filetype==s3m)||(filetype==stm)){
			if (operands < 0xe0) effekt = portamento_up ;else
			if (operands < 0xf0) effekt = xtrafsldup    ;else{
				effekt = enhanced;
				operands = fsldup << 4;
				goto enh;
			}
		}break;
		case portamento_down:if ((filetype==s3m)||(filetype==stm)){
			if (operands < 0xe0 ) effekt = portamento_down ;else
			if (operands < 0xf0 ) effekt = xtrafslddwn     ;else{
				effekt = enhanced;
				operands = fslddwn << 4;
				goto enh;
			}
		};break;
		case volumeslide: if ((filetype==s3m)||(filetype==stm)){
			if ((operands & 0x0f == 0x0f)&&(operands & 0xf0 != 0)){
				effekt = enhanced;
				operands = finevolup << 4;
				goto enh;
			}else if ((operands & 0xf0==0xf0)&&(operands & 0x0f!=0)){
				effekt = enhanced;
				operands = finevoldwn << 4;
				goto enh;
			}
		}break;
                case noeffekt : break;  //? EB
     		case enhanced :{
			switch (operands >> 4){ 
				case pattrndelay: patterndelay=operands & 0x0f;break;
				case pattrnloop : if ( (operands & 0x0f) ==0 ) unilong=playtime; 
							else patternloops=(operands & 0x0f)
				;break;
		case epanning   : if ( !( ((operands & 0x0f) >=0) && ((operands & 0x0f)<= 15 )) ) panningoff=false;
				;break;
			}

		enh:
			proeffectsused |= (1 << (operands >> 4));
		}break;
	}
	if ( effekt<16 ) effectsused |= (1 << effekt) ;else
        if ( effekt<32 ) extraeffused |= (1 << (effekt-16)) ;else
        if ( effekt<48 ) extraeffused1 |= (1 << (effekt-32));      
      }
 // printf("eff: %6x pro: %6x extra: %6x extra1: %6x \n",effectsused,proeffectsused,extraeffused,extraeffused1);
 asm("
        xorw %ax,%ax
        xorl %ecx,%ecx
        movb patterndelay,%al
        incw %ax
        mulb speed
        movw %ax,%cx
      lls:
        call inctime__Fv
        aword;loop lls
        movb $0,patterndelay
      ");
	if (patternloops>0){
		unilong=playtime-unilong;
		playtime += unilong*patternloops;
		patternloops=0;
	}
	noteplayed[j]=true;
	pjump=false;
	pbreak=false;
	for (k=0;k < numtracks;k++){
   //   with pattern^[k][j] do  (*pattern)[k][j]
		byte& instrument= (*pattern)[k][j].instrument;
		word& ton= (*pattern)[k][j].ton;
		byte& effekt= (*pattern)[k][j].effekt;
		byte& operands= (*pattern)[k][j].operands;
		char& chnvol= (*pattern)[k][j].chnvol;
		
		switch (effekt){
			case noeffekt:;break;
			case positionjump   :if (operands<numpatterns){
				pjump=true;
				jumpto=operands;
			};break;
			case patternbreak   :{
				pbreak=true;
				breakto=10*(operands >> 4)+(operands & 0x0f);
			};break;
		}
	}
	if (pjump){
		if (  ptrnbreaks[jumpto]<breakto ) breakto=0;
		if (  i!=jumpto ){
			alreadyplayed[i]=true;
			memset(noteplayed,0,256);
		}
		if ((alreadyplayed[jumpto])||(noteplayed[breakto])){
			if ( (loopfrom=-1) ){
				loopfrom=i+1;
				loopto=jumpto+1;
				loopfromtime=playtime;
			}
		}else{
			i=jumpto;
			goto jmp;
		}
	}else if (  pbreak ) break;
    }
    memset(noteplayed,0,256);
    alreadyplayed[i]=true;
    i++;
    if (  i>=numpatterns ) i=0;
  jmp:
    if (  ptrnbreaks[i]<breakto ) breakto=0;
  }while (!alreadyplayed[i]);
  totaltime=playtime;
    if (  loopfromtime==-1 ) loopfromtime=totaltime;
    if (loopto > -1) looptotime=patterntimes[loopto-1]; else looptotime=0;
    if (initglobvol<64) initglobvol=64;
    for (i=0;i < numtracks;i++) if ( (defpanning[i] !=0)&&(defpanning[i]!=128)) panningoff=false;
}


