added an old version of mikmod for dos
[dosdemo] / libs / oldmik / src / mplayer.c
diff --git a/libs/oldmik/src/mplayer.c b/libs/oldmik/src/mplayer.c
new file mode 100644 (file)
index 0000000..cbf642b
--- /dev/null
@@ -0,0 +1,1386 @@
+/*\r
+\r
+Name:\r
+MPLAYER.C\r
+\r
+Description:\r
+The actual modplaying routines\r
+\r
+Portability:\r
+All systems - all compilers\r
+\r
+*/\r
+#include <stdlib.h>\r
+#include "mikmod.h"\r
+\r
+UNIMOD *pf;                     /* <- this modfile is being played */\r
+UWORD reppos;                   /* patternloop position */\r
+UWORD repcnt;                   /* times to loop */\r
+UWORD vbtick;                   /* tick counter */\r
+UWORD patbrk;                   /* position where to start a new pattern */\r
+UBYTE patdly;                   /* patterndelay counter */\r
+UBYTE patdly2;                  /* patterndelay counter */\r
+UWORD numrow;                   /* number of rows on current pattern */\r
+SWORD  posjmp;                   /*      flag to indicate a position jump is needed...\r
+                                                       changed since 1.00: now also indicates the\r
+                                                       direction the position has to jump to:\r
+\r
+                                                       0: Don't do anything\r
+                                                       1: Jump back 1 position\r
+                                                       2: Restart on current position\r
+                                                       3: Jump forward 1 position\r
+                                               */\r
+int   forbid;                   /* forbidflag */\r
+static int isfirst;\r
+\r
+/*\r
+       Set forbid to 1 when you want to modify any of the mp_sngpos, mp_patpos etc.\r
+       variables and clear it when you're done. This prevents getting strange\r
+       results due to intermediate interrupts.\r
+*/\r
+\r
+\r
+AUDTMP mp_audio[32];    /* max 32 channels */\r
+UBYTE  mp_bpm;          /* beats-per-minute speed */\r
+UWORD  mp_patpos;       /* current row number (0-255) */\r
+SWORD  mp_sngpos;       /* current song position */\r
+UWORD  mp_sngspd;       /* current songspeed */\r
+UWORD  mp_channel;      /* channel it's working on */\r
+BOOL   mp_extspd=1;     /* extended speed flag, default enabled */\r
+BOOL   mp_panning=1;    /* panning flag, default enabled */\r
+BOOL   mp_loop=0;       /* loop module ? */\r
+UBYTE  mp_volume=100;   /* song volume (0-100) (or user volume) */\r
+\r
+static SBYTE globalvolume=64;  /* global volume */\r
+static UBYTE globalslide;\r
+\r
+AUDTMP *a;                              /* current AUDTMP it's working on */\r
+\r
+\r
+UWORD mytab[12]={\r
+       1712*16,1616*16,1524*16,1440*16,1356*16,1280*16,\r
+       1208*16,1140*16,1076*16,1016*16,960*16,907*16\r
+};\r
+\r
+static UBYTE VibratoTable[32]={\r
+       0,24,49,74,97,120,141,161,\r
+       180,197,212,224,235,244,250,253,\r
+       255,253,250,244,235,224,212,197,\r
+       180,161,141,120,97,74,49,24\r
+};\r
+\r
+\r
+/* linear periods to frequency translation table: */\r
+\r
+UWORD lintab[768]={\r
+16726,16741,16756,16771,16786,16801,16816,16832,16847,16862,16877,16892,16908,16923,16938,16953,\r
+16969,16984,16999,17015,17030,17046,17061,17076,17092,17107,17123,17138,17154,17169,17185,17200,\r
+17216,17231,17247,17262,17278,17293,17309,17325,17340,17356,17372,17387,17403,17419,17435,17450,\r
+17466,17482,17498,17513,17529,17545,17561,17577,17593,17608,17624,17640,17656,17672,17688,17704,\r
+17720,17736,17752,17768,17784,17800,17816,17832,17848,17865,17881,17897,17913,17929,17945,17962,\r
+17978,17994,18010,18027,18043,18059,18075,18092,18108,18124,18141,18157,18174,18190,18206,18223,\r
+18239,18256,18272,18289,18305,18322,18338,18355,18372,18388,18405,18421,18438,18455,18471,18488,\r
+18505,18521,18538,18555,18572,18588,18605,18622,18639,18656,18672,18689,18706,18723,18740,18757,\r
+18774,18791,18808,18825,18842,18859,18876,18893,18910,18927,18944,18961,18978,18995,19013,19030,\r
+19047,19064,19081,19099,19116,19133,19150,19168,19185,19202,19220,19237,19254,19272,19289,19306,\r
+19324,19341,19359,19376,19394,19411,19429,19446,19464,19482,19499,19517,19534,19552,19570,19587,\r
+19605,19623,19640,19658,19676,19694,19711,19729,19747,19765,19783,19801,19819,19836,19854,19872,\r
+19890,19908,19926,19944,19962,19980,19998,20016,20034,20052,20071,20089,20107,20125,20143,20161,\r
+20179,20198,20216,20234,20252,20271,20289,20307,20326,20344,20362,20381,20399,20418,20436,20455,\r
+20473,20492,20510,20529,20547,20566,20584,20603,20621,20640,20659,20677,20696,20715,20733,20752,\r
+20771,20790,20808,20827,20846,20865,20884,20902,20921,20940,20959,20978,20997,21016,21035,21054,\r
+21073,21092,21111,21130,21149,21168,21187,21206,21226,21245,21264,21283,21302,21322,21341,21360,\r
+21379,21399,21418,21437,21457,21476,21496,21515,21534,21554,21573,21593,21612,21632,21651,21671,\r
+21690,21710,21730,21749,21769,21789,21808,21828,21848,21867,21887,21907,21927,21946,21966,21986,\r
+22006,22026,22046,22066,22086,22105,22125,22145,22165,22185,22205,22226,22246,22266,22286,22306,\r
+22326,22346,22366,22387,22407,22427,22447,22468,22488,22508,22528,22549,22569,22590,22610,22630,\r
+22651,22671,22692,22712,22733,22753,22774,22794,22815,22836,22856,22877,22897,22918,22939,22960,\r
+22980,23001,23022,23043,23063,23084,23105,23126,23147,23168,23189,23210,23230,23251,23272,23293,\r
+23315,23336,23357,23378,23399,23420,23441,23462,23483,23505,23526,23547,23568,23590,23611,23632,\r
+23654,23675,23696,23718,23739,23761,23782,23804,23825,23847,23868,23890,23911,23933,23954,23976,\r
+23998,24019,24041,24063,24084,24106,24128,24150,24172,24193,24215,24237,24259,24281,24303,24325,\r
+24347,24369,24391,24413,24435,24457,24479,24501,24523,24545,24567,24590,24612,24634,24656,24679,\r
+24701,24723,24746,24768,24790,24813,24835,24857,24880,24902,24925,24947,24970,24992,25015,25038,\r
+25060,25083,25105,25128,25151,25174,25196,25219,25242,25265,25287,25310,25333,25356,25379,25402,\r
+25425,25448,25471,25494,25517,25540,25563,25586,25609,25632,25655,25678,25702,25725,25748,25771,\r
+25795,25818,25841,25864,25888,25911,25935,25958,25981,26005,26028,26052,26075,26099,26123,26146,\r
+26170,26193,26217,26241,26264,26288,26312,26336,26359,26383,26407,26431,26455,26479,26502,26526,\r
+26550,26574,26598,26622,26646,26670,26695,26719,26743,26767,26791,26815,26839,26864,26888,26912,\r
+26937,26961,26985,27010,27034,27058,27083,27107,27132,27156,27181,27205,27230,27254,27279,27304,\r
+27328,27353,27378,27402,27427,27452,27477,27502,27526,27551,27576,27601,27626,27651,27676,27701,\r
+27726,27751,27776,27801,27826,27851,27876,27902,27927,27952,27977,28003,28028,28053,28078,28104,\r
+28129,28155,28180,28205,28231,28256,28282,28307,28333,28359,28384,28410,28435,28461,28487,28513,\r
+28538,28564,28590,28616,28642,28667,28693,28719,28745,28771,28797,28823,28849,28875,28901,28927,\r
+28953,28980,29006,29032,29058,29084,29111,29137,29163,29190,29216,29242,29269,29295,29322,29348,\r
+29375,29401,29428,29454,29481,29507,29534,29561,29587,29614,29641,29668,29694,29721,29748,29775,\r
+29802,29829,29856,29883,29910,29937,29964,29991,30018,30045,30072,30099,30126,30154,30181,30208,\r
+30235,30263,30290,30317,30345,30372,30400,30427,30454,30482,30509,30537,30565,30592,30620,30647,\r
+30675,30703,30731,30758,30786,30814,30842,30870,30897,30925,30953,30981,31009,31037,31065,31093,\r
+31121,31149,31178,31206,31234,31262,31290,31319,31347,31375,31403,31432,31460,31489,31517,31546,\r
+31574,31602,31631,31660,31688,31717,31745,31774,31803,31832,31860,31889,31918,31947,31975,32004,\r
+32033,32062,32091,32120,32149,32178,32207,32236,32265,32295,32324,32353,32382,32411,32441,32470,\r
+32499,32529,32558,32587,32617,32646,32676,32705,32735,32764,32794,32823,32853,32883,32912,32942,\r
+32972,33002,33031,33061,33091,33121,33151,33181,33211,33241,33271,33301,33331,33361,33391,33421\r
+};\r
+\r
+\r
+\r
+\r
+#define LOGFAC 2*16\r
+\r
+UWORD logtab[]={\r
+       LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862,\r
+       LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814,\r
+       LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768,\r
+       LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725,\r
+       LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684,\r
+       LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646,\r
+       LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610,\r
+       LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575,\r
+       LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543,\r
+       LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513,\r
+       LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484,\r
+       LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457,\r
+       LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431\r
+};\r
+\r
+\r
+SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2)\r
+{\r
+       SWORD dp,dv,di;\r
+\r
+       if(p1==p2) return v1;\r
+\r
+       dv=v2-v1;\r
+       dp=p2-p1;\r
+       di=p-p1;\r
+\r
+       return v1 + ((SLONG)(di*dv) / dp);\r
+}\r
+\r
+\r
+UWORD getlinearperiod(UBYTE note,UWORD fine)\r
+{\r
+       return((10L*12*16*4)-((UWORD)note*16*4)-(fine/2)+64);\r
+}\r
+\r
+\r
+UWORD getlogperiod(UBYTE note,UWORD fine)\r
+{\r
+       UBYTE n,o;\r
+       UWORD p1,p2,i;\r
+\r
+       n=note%12;\r
+       o=note/12;\r
+       i=(n<<3)+(fine>>4);                     /* n*8 + fine/16 */\r
+\r
+       p1=logtab[i];\r
+       p2=logtab[i+1];\r
+\r
+       return(Interpolate(fine/16,0,15,p1,p2)>>o);\r
+}\r
+\r
+\r
+UWORD getoldperiod(UBYTE note,UWORD c2spd)\r
+{\r
+       UBYTE n,o;\r
+       ULONG period;\r
+\r
+       if(!c2spd) return 4242;         /* <- prevent divide overflow.. (42 eheh) */\r
+\r
+       n=note%12;\r
+       o=note/12;\r
+       period=((8363L*mytab[n]) >> o )/c2spd;\r
+       return period;\r
+}\r
+\r
+\r
+\r
+UWORD GetPeriod(UBYTE note,UWORD c2spd)\r
+{\r
+       if(pf->flags&UF_XMPERIODS){\r
+               return (pf->flags&UF_LINEAR) ? getlinearperiod(note,c2spd) : getlogperiod(note,c2spd);\r
+       }\r
+       return(getoldperiod(note,c2spd));\r
+}\r
+\r
+\r
+\r
+void DoEEffects(UBYTE dat)\r
+{\r
+       UBYTE nib;\r
+\r
+       nib=dat&0xf;\r
+\r
+       switch(dat>>4){\r
+\r
+               case 0x0:       /* filter toggle, not supported */\r
+                               break;\r
+\r
+               case 0x1:       /* fineslide up */\r
+                               if(!vbtick) a->tmpperiod-=(nib<<2);\r
+                               break;\r
+\r
+               case 0x2:       /* fineslide dn */\r
+                               if(!vbtick) a->tmpperiod+=(nib<<2);\r
+                               break;\r
+\r
+               case 0x3:       /* glissando ctrl */\r
+                               a->glissando=nib;\r
+                               break;\r
+\r
+               case 0x4:       /* set vibrato waveform */\r
+                               a->wavecontrol&=0xf0;\r
+                               a->wavecontrol|=nib;\r
+                               break;\r
+\r
+               case 0x5:       /* set finetune */\r
+/*                              a->c2spd=finetune[nib]; */\r
+/*                              a->tmpperiod=GetPeriod(a->note,pf->samples[a->sample].transpose,a->c2spd); */\r
+                               break;\r
+\r
+               case 0x6:       /* set patternloop */\r
+\r
+                               if(vbtick) break;\r
+\r
+                               /* hmm.. this one is a real kludge. But now it\r
+                                  works. */\r
+\r
+                               if(nib){                /* set reppos or repcnt ? */\r
+\r
+                                       /* set repcnt, so check if repcnt already is set,\r
+                                          which means we are already looping */\r
+\r
+                                       if(repcnt>0)\r
+                                               repcnt--;               /* already looping, decrease counter */\r
+                                       else\r
+                                               repcnt=nib;             /* not yet looping, so set repcnt */\r
+\r
+                                       if(repcnt)                      /* jump to reppos if repcnt>0 */\r
+                                               mp_patpos=reppos;\r
+                               }\r
+                               else{\r
+                                       reppos=mp_patpos-1;     /* set reppos */\r
+                               }\r
+                               break;\r
+\r
+\r
+               case 0x7:       /* set tremolo waveform */\r
+                               a->wavecontrol&=0x0f;\r
+                               a->wavecontrol|=nib<<4;\r
+                               break;\r
+\r
+                case 0x8:       /* set panning */\r
+                                if(mp_panning){\r
+                                        nib<<=4;\r
+                                        a->panning=nib;\r
+                                        pf->panning[mp_channel]=nib;\r
+                                }\r
+                               break;\r
+\r
+               case 0x9:       /* retrig note */\r
+\r
+                               /* only retrigger if\r
+                                  data nibble > 0 */\r
+\r
+                               if(nib>0){\r
+                                       if(a->retrig==0){\r
+\r
+                                               /* when retrig counter reaches 0,\r
+                                                  reset counter and restart the sample */\r
+\r
+                                               a->kick=1;\r
+                                               a->retrig=nib;\r
+                                       }\r
+                                       a->retrig--; /* countdown */\r
+                               }\r
+                               break;\r
+\r
+               case 0xa:       /* fine volume slide up */\r
+                               if(vbtick) break;\r
+\r
+                               a->tmpvolume+=nib;\r
+                               if(a->tmpvolume>64) a->tmpvolume=64;\r
+                               break;\r
+\r
+               case 0xb:       /* fine volume slide dn */\r
+                               if(vbtick) break;\r
+\r
+                               a->tmpvolume-=nib;\r
+                               if(a->tmpvolume<0) a->tmpvolume=0;\r
+                               break;\r
+\r
+               case 0xc:       /* cut note */\r
+\r
+                               /* When vbtick reaches the cut-note value,\r
+                                  turn the volume to zero ( Just like\r
+                                  on the amiga) */\r
+\r
+                               if(vbtick>=nib){\r
+                                       a->tmpvolume=0;                 /* just turn the volume down */\r
+                               }\r
+                               break;\r
+\r
+               case 0xd:       /* note delay */\r
+\r
+                               /* delay the start of the\r
+                                  sample until vbtick==nib */\r
+\r
+                               if(vbtick==nib){\r
+                                       a->kick=1;\r
+                               }\r
+                               else a->kick=0;\r
+                               break;\r
+\r
+               case 0xe:       /* pattern delay */\r
+                               if(vbtick) break;\r
+                               if(!patdly2) patdly=nib+1;                              /* only once (when vbtick=0) */\r
+                               break;\r
+\r
+               case 0xf:       /* invert loop, not supported */\r
+                               break;\r
+       }\r
+}\r
+\r
+\r
+void DoVibrato(void)\r
+{\r
+       UBYTE q;\r
+       UWORD temp;\r
+\r
+       q=(a->vibpos>>2)&0x1f;\r
+\r
+       switch(a->wavecontrol&3){\r
+\r
+               case 0: /* sine */\r
+                       temp=VibratoTable[q];\r
+                       break;\r
+\r
+               case 1: /* ramp down */\r
+                       q<<=3;\r
+                       if(a->vibpos<0) q=255-q;\r
+                       temp=q;\r
+                       break;\r
+\r
+               case 2: /* square wave */\r
+                       temp=255;\r
+                       break;\r
+       }\r
+\r
+       temp*=a->vibdepth;\r
+       temp>>=7;\r
+       temp<<=2;\r
+\r
+       if(a->vibpos>=0)\r
+               a->period=a->tmpperiod+temp;\r
+       else\r
+               a->period=a->tmpperiod-temp;\r
+\r
+       if(vbtick) a->vibpos+=a->vibspd;        /* do not update when vbtick==0 */\r
+}\r
+\r
+\r
+\r
+void DoTremolo(void)\r
+{\r
+       UBYTE q;\r
+       UWORD temp;\r
+\r
+       q=(a->trmpos>>2)&0x1f;\r
+\r
+       switch((a->wavecontrol>>4)&3){\r
+\r
+               case 0: /* sine */\r
+                       temp=VibratoTable[q];\r
+                       break;\r
+\r
+               case 1: /* ramp down */\r
+                       q<<=3;\r
+                       if(a->trmpos<0) q=255-q;\r
+                       temp=q;\r
+                       break;\r
+\r
+               case 2: /* square wave */\r
+                       temp=255;\r
+                       break;\r
+       }\r
+\r
+       temp*=a->trmdepth;\r
+       temp>>=6;\r
+\r
+       if(a->trmpos>=0){\r
+               a->volume=a->tmpvolume+temp;\r
+               if(a->volume>64) a->volume=64;\r
+       }\r
+       else{\r
+               a->volume=a->tmpvolume-temp;\r
+               if(a->volume<0) a->volume=0;\r
+       }\r
+\r
+       if(vbtick) a->trmpos+=a->trmspd;        /* do not update when vbtick==0 */\r
+}\r
+\r
+\r
+void DoVolSlide(UBYTE dat)\r
+{\r
+       if(!vbtick) return;             /* do not update when vbtick==0 */\r
+\r
+       a->tmpvolume+=dat>>4;           /* volume slide */\r
+       a->tmpvolume-=dat&0xf;\r
+       if(a->tmpvolume<0) a->tmpvolume=0;\r
+       if(a->tmpvolume>64) a->tmpvolume=64;\r
+}\r
+\r
+\r
+\r
+void DoS3MVolSlide(UBYTE inf)\r
+{\r
+       UBYTE lo,hi;\r
+\r
+       if(inf){\r
+               a->s3mvolslide=inf;\r
+       }\r
+       inf=a->s3mvolslide;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       if(hi==0){\r
+               a->tmpvolume-=lo;\r
+       }\r
+       else if(lo==0){\r
+               a->tmpvolume+=hi;\r
+       }\r
+       else if(hi==0xf){\r
+               if(!vbtick) a->tmpvolume-=lo;\r
+       }\r
+       else if(lo==0xf){\r
+               if(!vbtick) a->tmpvolume+=hi;\r
+       }\r
+\r
+       if(a->tmpvolume<0) a->tmpvolume=0;\r
+       if(a->tmpvolume>64) a->tmpvolume=64;\r
+}\r
+\r
+\r
+\r
+void DoXMVolSlide(UBYTE inf)\r
+{\r
+       UBYTE lo,hi;\r
+\r
+       if(inf){\r
+               a->s3mvolslide=inf;\r
+       }\r
+       inf=a->s3mvolslide;\r
+\r
+       if(!vbtick) return;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       if(hi==0)\r
+               a->tmpvolume-=lo;\r
+       else\r
+               a->tmpvolume+=hi;\r
+\r
+       if(a->tmpvolume<0) a->tmpvolume=0;\r
+       else if(a->tmpvolume>64) a->tmpvolume=64;\r
+}\r
+\r
+\r
+\r
+void DoXMGlobalSlide(UBYTE inf)\r
+{\r
+       UBYTE lo,hi;\r
+\r
+       if(inf){\r
+               globalslide=inf;\r
+       }\r
+       inf=globalslide;\r
+\r
+       if(!vbtick) return;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       if(hi==0)\r
+               globalvolume-=lo;\r
+       else\r
+               globalvolume+=hi;\r
+\r
+       if(globalvolume<0) globalvolume=0;\r
+       else if(globalvolume>64) globalvolume=64;\r
+}\r
+\r
+\r
+\r
+void DoXMPanSlide(UBYTE inf)\r
+{\r
+       UBYTE lo,hi;\r
+       SWORD pan;\r
+\r
+\r
+       if(inf!=0) a->pansspd=inf;\r
+       else inf=a->pansspd;\r
+\r
+       if(!vbtick) return;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       /* slide right has absolute priority: */\r
+\r
+       if(hi) lo=0;\r
+\r
+       pan=a->panning;\r
+\r
+       pan-=lo;\r
+       pan+=hi;\r
+\r
+       if(pan<0) pan=0;\r
+       if(pan>255) pan=255;\r
+\r
+       a->panning=pan;\r
+}\r
+\r
+\r
+\r
+void DoS3MSlideDn(UBYTE inf)\r
+{\r
+       UBYTE hi,lo;\r
+\r
+       if(inf!=0) a->slidespeed=inf;\r
+       else inf=a->slidespeed;\r
+\r
+       hi=inf>>4;\r
+       lo=inf&0xf;\r
+\r
+       if(hi==0xf){\r
+               if(!vbtick) a->tmpperiod+=(UWORD)lo<<2;\r
+       }\r
+       else if(hi==0xe){\r
+               if(!vbtick) a->tmpperiod+=lo;\r
+       }\r
+       else{\r
+               if(vbtick) a->tmpperiod+=(UWORD)inf<<2;\r
+       }\r
+}\r
+\r
+\r
+\r
+void DoS3MSlideUp(UBYTE inf)\r
+{\r
+       UBYTE hi,lo;\r
+\r
+       if(inf!=0) a->slidespeed=inf;\r
+       else inf=a->slidespeed;\r
+\r
+       hi=inf>>4;\r
+       lo=inf&0xf;\r
+\r
+       if(hi==0xf){\r
+               if(!vbtick) a->tmpperiod-=(UWORD)lo<<2;\r
+       }\r
+       else if(hi==0xe){\r
+               if(!vbtick) a->tmpperiod-=lo;\r
+       }\r
+       else{\r
+               if(vbtick) a->tmpperiod-=(UWORD)inf<<2;\r
+       }\r
+}\r
+\r
+\r
+\r
+void DoS3MTremor(UBYTE inf)\r
+{\r
+       UBYTE on,off;\r
+\r
+       if(inf!=0) a->s3mtronof=inf;\r
+       else inf=a->s3mtronof;\r
+\r
+       if(!vbtick) return;\r
+\r
+       on=(inf>>4)+1;\r
+       off=(inf&0xf)+1;\r
+\r
+       a->s3mtremor%=(on+off);\r
+       a->volume=(a->s3mtremor < on ) ? a->tmpvolume:0;\r
+       a->s3mtremor++;\r
+}\r
+\r
+\r
+\r
+void DoS3MRetrig(UBYTE inf)\r
+{\r
+       UBYTE hi,lo;\r
+\r
+       hi=inf>>4;\r
+       lo=inf&0xf;\r
+\r
+       if(lo){\r
+               a->s3mrtgslide=hi;\r
+               a->s3mrtgspeed=lo;\r
+       }\r
+\r
+       if(hi){\r
+               a->s3mrtgslide=hi;\r
+       }\r
+\r
+       /* only retrigger if\r
+          lo nibble > 0 */\r
+\r
+       if(a->s3mrtgspeed>0){\r
+               if(a->retrig==0){\r
+\r
+                       /* when retrig counter reaches 0,\r
+                          reset counter and restart the sample */\r
+\r
+                       a->kick=1;\r
+                       a->retrig=a->s3mrtgspeed;\r
+\r
+                       if(vbtick){                     /* don't slide on first retrig */\r
+                               switch(a->s3mrtgslide){\r
+\r
+                                       case 1:\r
+                                       case 2:\r
+                                       case 3:\r
+                                       case 4:\r
+                                       case 5:\r
+                                               a->tmpvolume-=(1<<(a->s3mrtgslide-1));\r
+                                               break;\r
+\r
+                                       case 6:\r
+                                               a->tmpvolume=(2*a->tmpvolume)/3;\r
+                                               break;\r
+\r
+                                       case 7:\r
+                                               a->tmpvolume=a->tmpvolume>>1;\r
+                                               break;\r
+\r
+                                       case 9:\r
+                                       case 0xa:\r
+                                       case 0xb:\r
+                                       case 0xc:\r
+                                       case 0xd:\r
+                                               a->tmpvolume+=(1<<(a->s3mrtgslide-9));\r
+                                               break;\r
+\r
+                                       case 0xe:\r
+                                               a->tmpvolume=(3*a->tmpvolume)/2;\r
+                                               break;\r
+\r
+                                       case 0xf:\r
+                                               a->tmpvolume=a->tmpvolume<<1;\r
+                                               break;\r
+                               }\r
+                               if(a->tmpvolume<0) a->tmpvolume=0;\r
+                               if(a->tmpvolume>64) a->tmpvolume=64;\r
+                       }\r
+               }\r
+               a->retrig--; /* countdown */\r
+       }\r
+}\r
+\r
+\r
+void DoS3MSpeed(UBYTE speed)\r
+{\r
+       if(vbtick || patdly2) return;\r
+\r
+       if(speed){                      /* <- v0.44 bugfix */\r
+               mp_sngspd=speed;\r
+               vbtick=0;\r
+       }\r
+}\r
+\r
+\r
+void DoS3MTempo(UBYTE tempo)\r
+{\r
+       if(vbtick || patdly2) return;\r
+       mp_bpm=tempo;\r
+}\r
+\r
+\r
+void DoToneSlide(void)\r
+{\r
+       int dist,t;\r
+\r
+       if(!vbtick){\r
+               a->tmpperiod=a->period;\r
+               return;\r
+       }\r
+\r
+       /* We have to slide a->period towards a->wantedperiod, so\r
+          compute the difference between those two values */\r
+\r
+       dist=a->period-a->wantedperiod;\r
+\r
+       if( dist==0 ||                          /* if they are equal */\r
+               a->portspeed>abs(dist) ){       /* or if portamentospeed is too big */\r
+\r
+               a->period=a->wantedperiod;      /* make tmpperiod equal tperiod */\r
+       }\r
+       else if(dist>0){                                /* dist>0 ? */\r
+               a->period-=a->portspeed;        /* then slide up */\r
+       }\r
+       else\r
+               a->period+=a->portspeed;        /* dist<0 -> slide down */\r
+\r
+/*      if(a->glissando){\r
+\r
+                If glissando is on, find the nearest\r
+                  halfnote to a->tmpperiod\r
+\r
+               for(t=0;t<60;t++){\r
+                       if(a->tmpperiod>=npertab[a->finetune][t]) break;\r
+               }\r
+\r
+               a->period=npertab[a->finetune][t];\r
+       }\r
+       else\r
+*/\r
+       a->tmpperiod=a->period;\r
+}\r
+\r
+\r
+void DoPTEffect0(UBYTE dat)\r
+{\r
+       UBYTE note;\r
+\r
+       note=a->note;\r
+\r
+       if(dat!=0){\r
+               switch(vbtick%3){\r
+                       case 1:\r
+                               note+=(dat>>4); break;\r
+                       case 2:\r
+                               note+=(dat&0xf); break;\r
+               }\r
+               a->period=GetPeriod(note+a->transpose,a->c2spd);\r
+               a->ownper=1;\r
+       }\r
+}\r
+\r
+\r
+void PlayNote(void)\r
+{\r
+       INSTRUMENT *i;\r
+       SAMPLE *s;\r
+       UWORD period;\r
+       UBYTE inst,c;\r
+       UBYTE note;\r
+\r
+       if(a->row==NULL) return;\r
+\r
+       UniSetRow(a->row);\r
+\r
+       while(c=UniGetByte()){\r
+\r
+               switch(c){\r
+\r
+                       case UNI_NOTE:\r
+                               note=UniGetByte();\r
+\r
+                               if(note==96){                   /* key off ? */\r
+                                       a->keyon=0;\r
+                                       if(a->i && !(a->i->volflg & EF_ON)){\r
+                                               a->tmpvolume=0;\r
+                                       }\r
+                               }\r
+                               else{\r
+                                       a->note=note;\r
+\r
+                                       period=GetPeriod(note+a->transpose,a->c2spd);\r
+\r
+                                       a->wantedperiod=period;\r
+                                       a->tmpperiod=period;\r
+\r
+                                       a->kick=1;\r
+                                       a->start=0;\r
+\r
+                                       /* retrig tremolo and vibrato waves ? */\r
+\r
+                                       if(!(a->wavecontrol&0x80)) a->trmpos=0;\r
+                                       if(!(a->wavecontrol&0x08)) a->vibpos=0;\r
+                               }\r
+                               break;\r
+\r
+                       case UNI_INSTRUMENT:\r
+                               inst=UniGetByte();\r
+                               if(inst>=pf->numins) break;             /* <- safety valve */\r
+\r
+                               a->sample=inst;\r
+\r
+                               i=&pf->instruments[inst];\r
+                               a->i=i;\r
+\r
+                               if(i->samplenumber[a->note]>=i->numsmp) break;\r
+\r
+                               s=&i->samples[i->samplenumber[a->note]];\r
+                               a->s=s;\r
+\r
+                               /* channel or instrument determined panning ? */\r
+\r
+                               if(s->flags& SF_OWNPAN){\r
+                                       a->panning=s->panning;\r
+                               }\r
+                               else{\r
+                                       a->panning=pf->panning[mp_channel];\r
+                               }\r
+\r
+                               a->transpose=s->transpose;\r
+                               a->handle=s->handle;\r
+                               a->tmpvolume=s->volume;\r
+                               a->volume=s->volume;\r
+                               a->c2spd=s->c2spd;\r
+                               a->retrig=0;\r
+                               a->s3mtremor=0;\r
+\r
+                               period=GetPeriod(a->note+a->transpose,a->c2spd);\r
+\r
+                               a->wantedperiod=period;\r
+                               a->tmpperiod=period;\r
+                               break;\r
+\r
+                       default:\r
+                               UniSkipOpcode(c);\r
+                               break;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+void PlayEffects(void)\r
+{\r
+       UBYTE c,dat;\r
+\r
+       if(a->row==NULL) return;\r
+\r
+       UniSetRow(a->row);\r
+\r
+       a->ownper=0;\r
+       a->ownvol=0;\r
+\r
+       while(c=UniGetByte()){\r
+\r
+               switch(c){\r
+\r
+                       case UNI_NOTE:\r
+                       case UNI_INSTRUMENT:\r
+                               UniSkipOpcode(c);\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT0:\r
+                               DoPTEffect0(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT1:\r
+                               dat=UniGetByte();\r
+                               if(dat!=0) a->slidespeed=(UWORD)dat<<2;\r
+                               if(vbtick) a->tmpperiod-=a->slidespeed;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT2:\r
+                               dat=UniGetByte();\r
+                               if(dat!=0) a->slidespeed=(UWORD)dat<<2;\r
+                               if(vbtick) a->tmpperiod+=a->slidespeed;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT3:\r
+                               dat=UniGetByte();\r
+                               a->kick=0;                              /* temp XM fix */\r
+                               if(dat!=0){\r
+                                       a->portspeed=dat;\r
+                                       a->portspeed<<=2;\r
+                               }\r
+                               DoToneSlide();\r
+                               a->ownper=1;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT4:\r
+                               dat=UniGetByte();\r
+                               if(dat&0x0f) a->vibdepth=dat&0xf;\r
+                               if(dat&0xf0) a->vibspd=(dat&0xf0)>>2;\r
+                               DoVibrato();\r
+                               a->ownper=1;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT5:\r
+                               dat=UniGetByte();\r
+                               a->kick=0;\r
+                               DoToneSlide();\r
+                               DoVolSlide(dat);\r
+                               a->ownper=1;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT6:\r
+                               dat=UniGetByte();\r
+                               DoVibrato();\r
+                               DoVolSlide(dat);\r
+                               a->ownper=1;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT7:\r
+                               dat=UniGetByte();\r
+                               if(dat&0x0f) a->trmdepth=dat&0xf;\r
+                               if(dat&0xf0) a->trmspd=(dat&0xf0)>>2;\r
+                               DoTremolo();\r
+                               a->ownvol=1;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT8:\r
+                               dat=UniGetByte();\r
+                                if(mp_panning){\r
+                                        a->panning=dat;\r
+                                        pf->panning[mp_channel]=dat;\r
+                                }\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT9:\r
+                               dat=UniGetByte();\r
+                               if(dat) a->soffset=(UWORD)dat<<8;       /* <- 0.43 fix.. */\r
+                               a->start=a->soffset;\r
+                               if(a->start>a->s->length) a->start=a->s->length;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTA:\r
+                               DoVolSlide(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTB:\r
+                               dat=UniGetByte();\r
+                               if(patdly2) break;\r
+                               patbrk=0;\r
+                               mp_sngpos=dat-1;\r
+                               posjmp=3;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTC:\r
+                               dat=UniGetByte();\r
+                               if(vbtick) break;\r
+                               if(dat>64) dat=64;\r
+                               a->tmpvolume=dat;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTD:\r
+                               dat=UniGetByte();\r
+                               if(patdly2) break;\r
+                               {\r
+                                       int hi=(dat&0xf0)>>4;\r
+                                       int     lo=(dat&0xf);\r
+                                       patbrk=(hi*10)+lo;\r
+                               }\r
+                               if(patbrk>64) patbrk=64;        /* <- v0.42 fix */\r
+                               posjmp=3;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTE:\r
+                               DoEEffects(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTF:\r
+                               dat=UniGetByte();\r
+\r
+                               if(vbtick || patdly2) break;\r
+\r
+                               if(mp_extspd && dat>=0x20){\r
+                                       mp_bpm=dat;\r
+                               }\r
+                               else{\r
+                                       if(dat){                        /* <- v0.44 bugfix */\r
+                                               mp_sngspd=dat;\r
+                                               vbtick=0;\r
+                                       }\r
+                               }\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTD:\r
+                               DoS3MVolSlide(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTE:\r
+                               DoS3MSlideDn(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTF:\r
+                               DoS3MSlideUp(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTI:\r
+                               DoS3MTremor(UniGetByte());\r
+                               a->ownvol=1;\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTQ:\r
+                               DoS3MRetrig(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTA:\r
+                               DoS3MSpeed(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTT:\r
+                               DoS3MTempo(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_XMEFFECTA:\r
+                               DoXMVolSlide(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_XMEFFECTG:\r
+                               globalvolume=UniGetByte();\r
+                               break;\r
+\r
+                       case UNI_XMEFFECTH:\r
+                               DoXMGlobalSlide(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_XMEFFECTP:\r
+                               DoXMPanSlide(UniGetByte());\r
+                               break;\r
+\r
+                       default:\r
+                               UniSkipOpcode(c);\r
+                               break;\r
+               }\r
+       }\r
+\r
+       if(!a->ownper){\r
+               a->period=a->tmpperiod;\r
+       }\r
+\r
+       if(!a->ownvol){\r
+               a->volume=a->tmpvolume;\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b)\r
+{\r
+       return(Interpolate(p,a->pos,b->pos,a->val,b->val));\r
+}\r
+\r
+\r
+SWORD DoPan(SWORD envpan,SWORD pan)\r
+{\r
+       return(pan + (((envpan-128)*(128-abs(pan-128)))/128));\r
+}\r
+\r
+\r
+\r
+void StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE sus,UBYTE beg,UBYTE end,ENVPT *p)\r
+{\r
+       t->flg=flg;\r
+       t->pts=pts;\r
+       t->sus=sus;\r
+       t->beg=beg;\r
+       t->end=end;\r
+       t->env=p;\r
+       t->p=0;\r
+       t->a=0;\r
+       t->b=1;\r
+}\r
+\r
+\r
+\r
+SWORD ProcessEnvelope(ENVPR *t,SWORD v,UBYTE keyon)\r
+{\r
+       if(t->flg & EF_ON){\r
+\r
+               /* panning active? -> copy variables */\r
+\r
+               UBYTE a,b;\r
+               UWORD p;\r
+\r
+               a=t->a;\r
+               b=t->b;\r
+               p=t->p;\r
+\r
+               /* compute the envelope value between points a and b */\r
+\r
+               v=InterpolateEnv(p,&t->env[a],&t->env[b]);\r
+\r
+               /* Should we sustain? (sustain flag on, key-on, point a is the sustain\r
+                  point, and the pointer is exactly on point a) */\r
+\r
+               if((t->flg & EF_SUSTAIN) && keyon && a==t->sus && p==t->env[a].pos){\r
+                       /* do nothing */\r
+               }\r
+               else{\r
+                       /* don't sustain, so increase pointer. */\r
+\r
+                       p++;\r
+\r
+                       /* pointer reached point b? */\r
+\r
+                       if(p >= t->env[b].pos){\r
+\r
+                               /* shift points a and b */\r
+\r
+                               a=b; b++;\r
+\r
+                               if(t->flg & EF_LOOP){\r
+                                       if(b > t->end){\r
+                                               a=t->beg;\r
+                                               b=a+1;\r
+                                               p=t->env[a].pos;\r
+                                       }\r
+                               }\r
+                               else{\r
+                                       if(b >= t->pts){\r
+                                               b--;\r
+                                               p--;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               t->a=a;\r
+               t->b=b;\r
+               t->p=p;\r
+       }\r
+       return v;\r
+}\r
+\r
+/*\r
+long GetFreq2(long period)\r
+{\r
+       float frequency;\r
+\r
+       frequency=8363.0*pow(2,((6*12*16*4.0)-period)/(12*16*4.0));\r
+       return(floor(frequency));\r
+}\r
+*/\r
+\r
+long GetFreq2(long period)\r
+{\r
+       int okt;\r
+       long frequency;\r
+       period=7680-period;\r
+       okt=period/768;\r
+       frequency=lintab[period%768];\r
+       frequency<<=2;\r
+       return(frequency>>(7-okt));\r
+}\r
+\r
+void MP_HandleTick(void)\r
+{\r
+       int z,t,tr;\r
+       ULONG tmpvol;\r
+\r
+       if(isfirst){           \r
+               /* don't handle the very first ticks, this allows the\r
+                  other hardware to settle down so we don't loose any \r
+                  starting notes\r
+               */\r
+               isfirst--;\r
+               return;\r
+       }\r
+\r
+       if(forbid) return;      /* don't go any further when forbid is true */\r
+\r
+       if(MP_Ready()) return;\r
+\r
+       if(++vbtick>=mp_sngspd){\r
+\r
+               mp_patpos++;\r
+               vbtick=0;\r
+\r
+               if(patdly){\r
+                       patdly2=patdly;\r
+                       patdly=0;\r
+               }\r
+\r
+               if(patdly2){\r
+\r
+                       /* patterndelay active */\r
+\r
+                       if(--patdly2){\r
+                               mp_patpos--;    /* so turn back mp_patpos by 1 */\r
+                       }\r
+               }\r
+\r
+               /* Do we have to get a new patternpointer ?\r
+                  (when mp_patpos reaches 64 or when\r
+                  a patternbreak is active) */\r
+\r
+               if( mp_patpos == numrow ) posjmp=3;\r
+\r
+\r
+               if( posjmp ){\r
+                       mp_patpos=patbrk;\r
+                       mp_sngpos+=(posjmp-2);\r
+                       patbrk=posjmp=0;\r
+                       if(mp_sngpos>=pf->numpos){\r
+                               if(!mp_loop) return;\r
+                               mp_sngpos=pf->reppos;\r
+                       }\r
+                       if(mp_sngpos<0) mp_sngpos=pf->numpos-1;\r
+               }\r
+\r
+\r
+               if(!patdly2){\r
+\r
+                       for(t=0;t<pf->numchn;t++){\r
+\r
+                               tr=pf->patterns[(pf->positions[mp_sngpos]*pf->numchn)+t];\r
+                               numrow=pf->pattrows[pf->positions[mp_sngpos]];\r
+\r
+                               mp_channel=t;\r
+                               a=&mp_audio[t];\r
+                               a->row=(tr<pf->numtrk) ? UniFindRow(pf->tracks[tr],mp_patpos) : NULL;\r
+\r
+                               PlayNote();\r
+                       }\r
+               }\r
+       }\r
+\r
+       /* Update effects */\r
+\r
+       for(t=0;t<pf->numchn;t++){\r
+               mp_channel=t;\r
+               a=&mp_audio[t];\r
+               PlayEffects();\r
+       }\r
+\r
+       for(t=0;t<pf->numchn;t++){\r
+               INSTRUMENT *i;\r
+               SAMPLE *s;\r
+               SWORD envpan,envvol;\r
+\r
+               a=&mp_audio[t];\r
+               i=a->i;\r
+               s=a->s;\r
+\r
+               if(i==NULL || s==NULL) continue;\r
+\r
+               if(a->period<40) a->period=40;\r
+               if(a->period>8000) a->period=8000;\r
+\r
+               if(a->kick){\r
+                       MD_VoicePlay(t,a->handle,a->start,s->length,s->loopstart,s->loopend,s->flags);\r
+                       a->kick=0;\r
+                       a->keyon=1;\r
+\r
+                       a->fadevol=32768;\r
+\r
+                       StartEnvelope(&a->venv,i->volflg,i->volpts,i->volsus,i->volbeg,i->volend,i->volenv);\r
+                       StartEnvelope(&a->penv,i->panflg,i->panpts,i->pansus,i->panbeg,i->panend,i->panenv);\r
+               }\r
+\r
+               envvol=ProcessEnvelope(&a->venv,256,a->keyon);\r
+               envpan=ProcessEnvelope(&a->penv,128,a->keyon);\r
+\r
+               tmpvol=a->fadevol;              /* max 32768 */\r
+               tmpvol*=envvol;                 /* * max 256 */\r
+               tmpvol*=a->volume;              /* * max 64 */\r
+               tmpvol/=16384;                  /* tmpvol/(256*64) => tmpvol is max 32768 */\r
+\r
+               tmpvol*=globalvolume;   /* * max 64 */\r
+               tmpvol*=mp_volume;              /* * max 100 */\r
+               tmpvol/=3276800UL;              /* tmpvol/(64*100*512) => tmpvol is max 64 */\r
+\r
+               MD_VoiceSetVolume(t,tmpvol);\r
+\r
+               if(s->flags& SF_OWNPAN){\r
+                       MD_VoiceSetPanning(t,DoPan(envpan,a->panning));\r
+               }\r
+               else{\r
+                       MD_VoiceSetPanning(t,a->panning);\r
+               }\r
+\r
+               if(pf->flags&UF_LINEAR)\r
+                       MD_VoiceSetFrequency(t,GetFreq2(a->period));\r
+               else\r
+                       MD_VoiceSetFrequency(t,(3579546UL<<2)/a->period);\r
+\r
+               /*  if key-off, start substracting\r
+                       fadeoutspeed from fadevol: */\r
+\r
+               if(!a->keyon){\r
+                       if(a->fadevol>=i->volfade)\r
+                               a->fadevol-=i->volfade;\r
+                       else\r
+                               a->fadevol=0;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+\r
+void MP_Init(UNIMOD *m)\r
+{\r
+       int t;\r
+\r
+       pf=m;\r
+       reppos=0;\r
+       repcnt=0;\r
+       mp_sngpos=0;\r
+       mp_sngspd=m->initspeed;\r
+\r
+       vbtick=mp_sngspd;\r
+       patdly=0;\r
+       patdly2=0;\r
+       mp_bpm=m->inittempo;\r
+\r
+       forbid=0;\r
+       mp_patpos=0;\r
+       posjmp=2;               /* <- make sure the player fetches the first note */\r
+       patbrk=0;\r
+\r
+       isfirst=2;              /* delay start by 2 ticks */\r
+\r
+       globalvolume=64;                /* reset global volume */\r
+\r
+       /* Make sure the player doesn't start with garbage: */\r
+\r
+       for(t=0;t<pf->numchn;t++){\r
+               mp_audio[t].kick=0;\r
+               mp_audio[t].tmpvolume=0;\r
+               mp_audio[t].retrig=0;\r
+               mp_audio[t].wavecontrol=0;\r
+               mp_audio[t].glissando=0;\r
+               mp_audio[t].soffset=0;\r
+       }\r
+}\r
+\r
+\r
+\r
+int MP_Ready(void)\r
+{\r
+       return(mp_sngpos>=pf->numpos);\r
+}\r
+\r
+\r
+void MP_NextPosition(void)\r
+{\r
+       forbid=1;\r
+       posjmp=3;\r
+       patbrk=0;\r
+       vbtick=mp_sngspd;\r
+       forbid=0;\r
+}\r
+\r
+\r
+void MP_PrevPosition(void)\r
+{\r
+       forbid=1;\r
+       posjmp=1;\r
+       patbrk=0;\r
+       vbtick=mp_sngspd;\r
+       forbid=0;\r
+}\r
+\r
+\r
+void MP_SetPosition(UWORD pos)\r
+{\r
+       if(pos>=pf->numpos) pos=pf->numpos;\r
+       forbid=1;\r
+       posjmp=2;\r
+       patbrk=0;\r
+       mp_sngpos=pos;\r
+       vbtick=mp_sngspd;\r
+       forbid=0;\r
+}\r