7 The actual modplaying routines
\r
10 All systems - all compilers
\r
16 UNIMOD *pf; /* <- this modfile is being played */
\r
17 UWORD reppos; /* patternloop position */
\r
18 UWORD repcnt; /* times to loop */
\r
19 UWORD vbtick; /* tick counter */
\r
20 UWORD patbrk; /* position where to start a new pattern */
\r
21 UBYTE patdly; /* patterndelay counter */
\r
22 UBYTE patdly2; /* patterndelay counter */
\r
23 UWORD numrow; /* number of rows on current pattern */
\r
24 SWORD posjmp; /* flag to indicate a position jump is needed...
\r
25 changed since 1.00: now also indicates the
\r
26 direction the position has to jump to:
\r
28 0: Don't do anything
\r
29 1: Jump back 1 position
\r
30 2: Restart on current position
\r
31 3: Jump forward 1 position
\r
33 int forbid; /* forbidflag */
\r
37 Set forbid to 1 when you want to modify any of the mp_sngpos, mp_patpos etc.
\r
38 variables and clear it when you're done. This prevents getting strange
\r
39 results due to intermediate interrupts.
\r
43 AUDTMP mp_audio[32]; /* max 32 channels */
\r
44 UBYTE mp_bpm; /* beats-per-minute speed */
\r
45 UWORD mp_patpos; /* current row number (0-255) */
\r
46 SWORD mp_sngpos; /* current song position */
\r
47 UWORD mp_sngspd; /* current songspeed */
\r
48 UWORD mp_channel; /* channel it's working on */
\r
49 BOOL mp_extspd=1; /* extended speed flag, default enabled */
\r
50 BOOL mp_panning=1; /* panning flag, default enabled */
\r
51 BOOL mp_loop=0; /* loop module ? */
\r
52 UBYTE mp_volume=100; /* song volume (0-100) (or user volume) */
\r
54 static SBYTE globalvolume=64; /* global volume */
\r
55 static UBYTE globalslide;
\r
57 AUDTMP *a; /* current AUDTMP it's working on */
\r
61 1712*16,1616*16,1524*16,1440*16,1356*16,1280*16,
\r
62 1208*16,1140*16,1076*16,1016*16,960*16,907*16
\r
65 static UBYTE VibratoTable[32]={
\r
66 0,24,49,74,97,120,141,161,
\r
67 180,197,212,224,235,244,250,253,
\r
68 255,253,250,244,235,224,212,197,
\r
69 180,161,141,120,97,74,49,24
\r
73 /* linear periods to frequency translation table: */
\r
76 16726,16741,16756,16771,16786,16801,16816,16832,16847,16862,16877,16892,16908,16923,16938,16953,
\r
77 16969,16984,16999,17015,17030,17046,17061,17076,17092,17107,17123,17138,17154,17169,17185,17200,
\r
78 17216,17231,17247,17262,17278,17293,17309,17325,17340,17356,17372,17387,17403,17419,17435,17450,
\r
79 17466,17482,17498,17513,17529,17545,17561,17577,17593,17608,17624,17640,17656,17672,17688,17704,
\r
80 17720,17736,17752,17768,17784,17800,17816,17832,17848,17865,17881,17897,17913,17929,17945,17962,
\r
81 17978,17994,18010,18027,18043,18059,18075,18092,18108,18124,18141,18157,18174,18190,18206,18223,
\r
82 18239,18256,18272,18289,18305,18322,18338,18355,18372,18388,18405,18421,18438,18455,18471,18488,
\r
83 18505,18521,18538,18555,18572,18588,18605,18622,18639,18656,18672,18689,18706,18723,18740,18757,
\r
84 18774,18791,18808,18825,18842,18859,18876,18893,18910,18927,18944,18961,18978,18995,19013,19030,
\r
85 19047,19064,19081,19099,19116,19133,19150,19168,19185,19202,19220,19237,19254,19272,19289,19306,
\r
86 19324,19341,19359,19376,19394,19411,19429,19446,19464,19482,19499,19517,19534,19552,19570,19587,
\r
87 19605,19623,19640,19658,19676,19694,19711,19729,19747,19765,19783,19801,19819,19836,19854,19872,
\r
88 19890,19908,19926,19944,19962,19980,19998,20016,20034,20052,20071,20089,20107,20125,20143,20161,
\r
89 20179,20198,20216,20234,20252,20271,20289,20307,20326,20344,20362,20381,20399,20418,20436,20455,
\r
90 20473,20492,20510,20529,20547,20566,20584,20603,20621,20640,20659,20677,20696,20715,20733,20752,
\r
91 20771,20790,20808,20827,20846,20865,20884,20902,20921,20940,20959,20978,20997,21016,21035,21054,
\r
92 21073,21092,21111,21130,21149,21168,21187,21206,21226,21245,21264,21283,21302,21322,21341,21360,
\r
93 21379,21399,21418,21437,21457,21476,21496,21515,21534,21554,21573,21593,21612,21632,21651,21671,
\r
94 21690,21710,21730,21749,21769,21789,21808,21828,21848,21867,21887,21907,21927,21946,21966,21986,
\r
95 22006,22026,22046,22066,22086,22105,22125,22145,22165,22185,22205,22226,22246,22266,22286,22306,
\r
96 22326,22346,22366,22387,22407,22427,22447,22468,22488,22508,22528,22549,22569,22590,22610,22630,
\r
97 22651,22671,22692,22712,22733,22753,22774,22794,22815,22836,22856,22877,22897,22918,22939,22960,
\r
98 22980,23001,23022,23043,23063,23084,23105,23126,23147,23168,23189,23210,23230,23251,23272,23293,
\r
99 23315,23336,23357,23378,23399,23420,23441,23462,23483,23505,23526,23547,23568,23590,23611,23632,
\r
100 23654,23675,23696,23718,23739,23761,23782,23804,23825,23847,23868,23890,23911,23933,23954,23976,
\r
101 23998,24019,24041,24063,24084,24106,24128,24150,24172,24193,24215,24237,24259,24281,24303,24325,
\r
102 24347,24369,24391,24413,24435,24457,24479,24501,24523,24545,24567,24590,24612,24634,24656,24679,
\r
103 24701,24723,24746,24768,24790,24813,24835,24857,24880,24902,24925,24947,24970,24992,25015,25038,
\r
104 25060,25083,25105,25128,25151,25174,25196,25219,25242,25265,25287,25310,25333,25356,25379,25402,
\r
105 25425,25448,25471,25494,25517,25540,25563,25586,25609,25632,25655,25678,25702,25725,25748,25771,
\r
106 25795,25818,25841,25864,25888,25911,25935,25958,25981,26005,26028,26052,26075,26099,26123,26146,
\r
107 26170,26193,26217,26241,26264,26288,26312,26336,26359,26383,26407,26431,26455,26479,26502,26526,
\r
108 26550,26574,26598,26622,26646,26670,26695,26719,26743,26767,26791,26815,26839,26864,26888,26912,
\r
109 26937,26961,26985,27010,27034,27058,27083,27107,27132,27156,27181,27205,27230,27254,27279,27304,
\r
110 27328,27353,27378,27402,27427,27452,27477,27502,27526,27551,27576,27601,27626,27651,27676,27701,
\r
111 27726,27751,27776,27801,27826,27851,27876,27902,27927,27952,27977,28003,28028,28053,28078,28104,
\r
112 28129,28155,28180,28205,28231,28256,28282,28307,28333,28359,28384,28410,28435,28461,28487,28513,
\r
113 28538,28564,28590,28616,28642,28667,28693,28719,28745,28771,28797,28823,28849,28875,28901,28927,
\r
114 28953,28980,29006,29032,29058,29084,29111,29137,29163,29190,29216,29242,29269,29295,29322,29348,
\r
115 29375,29401,29428,29454,29481,29507,29534,29561,29587,29614,29641,29668,29694,29721,29748,29775,
\r
116 29802,29829,29856,29883,29910,29937,29964,29991,30018,30045,30072,30099,30126,30154,30181,30208,
\r
117 30235,30263,30290,30317,30345,30372,30400,30427,30454,30482,30509,30537,30565,30592,30620,30647,
\r
118 30675,30703,30731,30758,30786,30814,30842,30870,30897,30925,30953,30981,31009,31037,31065,31093,
\r
119 31121,31149,31178,31206,31234,31262,31290,31319,31347,31375,31403,31432,31460,31489,31517,31546,
\r
120 31574,31602,31631,31660,31688,31717,31745,31774,31803,31832,31860,31889,31918,31947,31975,32004,
\r
121 32033,32062,32091,32120,32149,32178,32207,32236,32265,32295,32324,32353,32382,32411,32441,32470,
\r
122 32499,32529,32558,32587,32617,32646,32676,32705,32735,32764,32794,32823,32853,32883,32912,32942,
\r
123 32972,33002,33031,33061,33091,33121,33151,33181,33211,33241,33271,33301,33331,33361,33391,33421
\r
129 #define LOGFAC 2*16
\r
132 LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862,
\r
133 LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814,
\r
134 LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768,
\r
135 LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725,
\r
136 LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684,
\r
137 LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646,
\r
138 LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610,
\r
139 LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575,
\r
140 LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543,
\r
141 LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513,
\r
142 LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484,
\r
143 LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457,
\r
144 LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431
\r
148 SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2)
\r
152 if(p1==p2) return v1;
\r
158 return v1 + ((SLONG)(di*dv) / dp);
\r
162 UWORD getlinearperiod(UBYTE note,UWORD fine)
\r
164 return((10L*12*16*4)-((UWORD)note*16*4)-(fine/2)+64);
\r
168 UWORD getlogperiod(UBYTE note,UWORD fine)
\r
175 i=(n<<3)+(fine>>4); /* n*8 + fine/16 */
\r
180 return(Interpolate(fine/16,0,15,p1,p2)>>o);
\r
184 UWORD getoldperiod(UBYTE note,UWORD c2spd)
\r
189 if(!c2spd) return 4242; /* <- prevent divide overflow.. (42 eheh) */
\r
193 period=((8363L*mytab[n]) >> o )/c2spd;
\r
199 UWORD GetPeriod(UBYTE note,UWORD c2spd)
\r
201 if(pf->flags&UF_XMPERIODS){
\r
202 return (pf->flags&UF_LINEAR) ? getlinearperiod(note,c2spd) : getlogperiod(note,c2spd);
\r
204 return(getoldperiod(note,c2spd));
\r
209 void DoEEffects(UBYTE dat)
\r
217 case 0x0: /* filter toggle, not supported */
\r
220 case 0x1: /* fineslide up */
\r
221 if(!vbtick) a->tmpperiod-=(nib<<2);
\r
224 case 0x2: /* fineslide dn */
\r
225 if(!vbtick) a->tmpperiod+=(nib<<2);
\r
228 case 0x3: /* glissando ctrl */
\r
232 case 0x4: /* set vibrato waveform */
\r
233 a->wavecontrol&=0xf0;
\r
234 a->wavecontrol|=nib;
\r
237 case 0x5: /* set finetune */
\r
238 /* a->c2spd=finetune[nib]; */
\r
239 /* a->tmpperiod=GetPeriod(a->note,pf->samples[a->sample].transpose,a->c2spd); */
\r
242 case 0x6: /* set patternloop */
\r
246 /* hmm.. this one is a real kludge. But now it
\r
249 if(nib){ /* set reppos or repcnt ? */
\r
251 /* set repcnt, so check if repcnt already is set,
\r
252 which means we are already looping */
\r
255 repcnt--; /* already looping, decrease counter */
\r
257 repcnt=nib; /* not yet looping, so set repcnt */
\r
259 if(repcnt) /* jump to reppos if repcnt>0 */
\r
263 reppos=mp_patpos-1; /* set reppos */
\r
268 case 0x7: /* set tremolo waveform */
\r
269 a->wavecontrol&=0x0f;
\r
270 a->wavecontrol|=nib<<4;
\r
273 case 0x8: /* set panning */
\r
277 pf->panning[mp_channel]=nib;
\r
281 case 0x9: /* retrig note */
\r
283 /* only retrigger if
\r
289 /* when retrig counter reaches 0,
\r
290 reset counter and restart the sample */
\r
295 a->retrig--; /* countdown */
\r
299 case 0xa: /* fine volume slide up */
\r
303 if(a->tmpvolume>64) a->tmpvolume=64;
\r
306 case 0xb: /* fine volume slide dn */
\r
310 if(a->tmpvolume<0) a->tmpvolume=0;
\r
313 case 0xc: /* cut note */
\r
315 /* When vbtick reaches the cut-note value,
\r
316 turn the volume to zero ( Just like
\r
320 a->tmpvolume=0; /* just turn the volume down */
\r
324 case 0xd: /* note delay */
\r
326 /* delay the start of the
\r
327 sample until vbtick==nib */
\r
335 case 0xe: /* pattern delay */
\r
337 if(!patdly2) patdly=nib+1; /* only once (when vbtick=0) */
\r
340 case 0xf: /* invert loop, not supported */
\r
346 void DoVibrato(void)
\r
351 q=(a->vibpos>>2)&0x1f;
\r
353 switch(a->wavecontrol&3){
\r
356 temp=VibratoTable[q];
\r
359 case 1: /* ramp down */
\r
361 if(a->vibpos<0) q=255-q;
\r
365 case 2: /* square wave */
\r
375 a->period=a->tmpperiod+temp;
\r
377 a->period=a->tmpperiod-temp;
\r
379 if(vbtick) a->vibpos+=a->vibspd; /* do not update when vbtick==0 */
\r
384 void DoTremolo(void)
\r
389 q=(a->trmpos>>2)&0x1f;
\r
391 switch((a->wavecontrol>>4)&3){
\r
394 temp=VibratoTable[q];
\r
397 case 1: /* ramp down */
\r
399 if(a->trmpos<0) q=255-q;
\r
403 case 2: /* square wave */
\r
412 a->volume=a->tmpvolume+temp;
\r
413 if(a->volume>64) a->volume=64;
\r
416 a->volume=a->tmpvolume-temp;
\r
417 if(a->volume<0) a->volume=0;
\r
420 if(vbtick) a->trmpos+=a->trmspd; /* do not update when vbtick==0 */
\r
424 void DoVolSlide(UBYTE dat)
\r
426 if(!vbtick) return; /* do not update when vbtick==0 */
\r
428 a->tmpvolume+=dat>>4; /* volume slide */
\r
429 a->tmpvolume-=dat&0xf;
\r
430 if(a->tmpvolume<0) a->tmpvolume=0;
\r
431 if(a->tmpvolume>64) a->tmpvolume=64;
\r
436 void DoS3MVolSlide(UBYTE inf)
\r
441 a->s3mvolslide=inf;
\r
443 inf=a->s3mvolslide;
\r
455 if(!vbtick) a->tmpvolume-=lo;
\r
458 if(!vbtick) a->tmpvolume+=hi;
\r
461 if(a->tmpvolume<0) a->tmpvolume=0;
\r
462 if(a->tmpvolume>64) a->tmpvolume=64;
\r
467 void DoXMVolSlide(UBYTE inf)
\r
472 a->s3mvolslide=inf;
\r
474 inf=a->s3mvolslide;
\r
476 if(!vbtick) return;
\r
486 if(a->tmpvolume<0) a->tmpvolume=0;
\r
487 else if(a->tmpvolume>64) a->tmpvolume=64;
\r
492 void DoXMGlobalSlide(UBYTE inf)
\r
501 if(!vbtick) return;
\r
511 if(globalvolume<0) globalvolume=0;
\r
512 else if(globalvolume>64) globalvolume=64;
\r
517 void DoXMPanSlide(UBYTE inf)
\r
523 if(inf!=0) a->pansspd=inf;
\r
524 else inf=a->pansspd;
\r
526 if(!vbtick) return;
\r
531 /* slide right has absolute priority: */
\r
541 if(pan>255) pan=255;
\r
548 void DoS3MSlideDn(UBYTE inf)
\r
552 if(inf!=0) a->slidespeed=inf;
\r
553 else inf=a->slidespeed;
\r
559 if(!vbtick) a->tmpperiod+=(UWORD)lo<<2;
\r
562 if(!vbtick) a->tmpperiod+=lo;
\r
565 if(vbtick) a->tmpperiod+=(UWORD)inf<<2;
\r
571 void DoS3MSlideUp(UBYTE inf)
\r
575 if(inf!=0) a->slidespeed=inf;
\r
576 else inf=a->slidespeed;
\r
582 if(!vbtick) a->tmpperiod-=(UWORD)lo<<2;
\r
585 if(!vbtick) a->tmpperiod-=lo;
\r
588 if(vbtick) a->tmpperiod-=(UWORD)inf<<2;
\r
594 void DoS3MTremor(UBYTE inf)
\r
598 if(inf!=0) a->s3mtronof=inf;
\r
599 else inf=a->s3mtronof;
\r
601 if(!vbtick) return;
\r
606 a->s3mtremor%=(on+off);
\r
607 a->volume=(a->s3mtremor < on ) ? a->tmpvolume:0;
\r
613 void DoS3MRetrig(UBYTE inf)
\r
629 /* only retrigger if
\r
632 if(a->s3mrtgspeed>0){
\r
635 /* when retrig counter reaches 0,
\r
636 reset counter and restart the sample */
\r
639 a->retrig=a->s3mrtgspeed;
\r
641 if(vbtick){ /* don't slide on first retrig */
\r
642 switch(a->s3mrtgslide){
\r
649 a->tmpvolume-=(1<<(a->s3mrtgslide-1));
\r
653 a->tmpvolume=(2*a->tmpvolume)/3;
\r
657 a->tmpvolume=a->tmpvolume>>1;
\r
665 a->tmpvolume+=(1<<(a->s3mrtgslide-9));
\r
669 a->tmpvolume=(3*a->tmpvolume)/2;
\r
673 a->tmpvolume=a->tmpvolume<<1;
\r
676 if(a->tmpvolume<0) a->tmpvolume=0;
\r
677 if(a->tmpvolume>64) a->tmpvolume=64;
\r
680 a->retrig--; /* countdown */
\r
685 void DoS3MSpeed(UBYTE speed)
\r
687 if(vbtick || patdly2) return;
\r
689 if(speed){ /* <- v0.44 bugfix */
\r
696 void DoS3MTempo(UBYTE tempo)
\r
698 if(vbtick || patdly2) return;
\r
703 void DoToneSlide(void)
\r
708 a->tmpperiod=a->period;
\r
712 /* We have to slide a->period towards a->wantedperiod, so
\r
713 compute the difference between those two values */
\r
715 dist=a->period-a->wantedperiod;
\r
717 if( dist==0 || /* if they are equal */
\r
718 a->portspeed>abs(dist) ){ /* or if portamentospeed is too big */
\r
720 a->period=a->wantedperiod; /* make tmpperiod equal tperiod */
\r
722 else if(dist>0){ /* dist>0 ? */
\r
723 a->period-=a->portspeed; /* then slide up */
\r
726 a->period+=a->portspeed; /* dist<0 -> slide down */
\r
728 /* if(a->glissando){
\r
730 If glissando is on, find the nearest
\r
731 halfnote to a->tmpperiod
\r
734 if(a->tmpperiod>=npertab[a->finetune][t]) break;
\r
737 a->period=npertab[a->finetune][t];
\r
741 a->tmpperiod=a->period;
\r
745 void DoPTEffect0(UBYTE dat)
\r
754 note+=(dat>>4); break;
\r
756 note+=(dat&0xf); break;
\r
758 a->period=GetPeriod(note+a->transpose,a->c2spd);
\r
764 void PlayNote(void)
\r
772 if(a->row==NULL) return;
\r
776 while(c=UniGetByte()){
\r
783 if(note==96){ /* key off ? */
\r
785 if(a->i && !(a->i->volflg & EF_ON)){
\r
792 period=GetPeriod(note+a->transpose,a->c2spd);
\r
794 a->wantedperiod=period;
\r
795 a->tmpperiod=period;
\r
800 /* retrig tremolo and vibrato waves ? */
\r
802 if(!(a->wavecontrol&0x80)) a->trmpos=0;
\r
803 if(!(a->wavecontrol&0x08)) a->vibpos=0;
\r
807 case UNI_INSTRUMENT:
\r
809 if(inst>=pf->numins) break; /* <- safety valve */
\r
813 i=&pf->instruments[inst];
\r
816 if(i->samplenumber[a->note]>=i->numsmp) break;
\r
818 s=&i->samples[i->samplenumber[a->note]];
\r
821 /* channel or instrument determined panning ? */
\r
823 if(s->flags& SF_OWNPAN){
\r
824 a->panning=s->panning;
\r
827 a->panning=pf->panning[mp_channel];
\r
830 a->transpose=s->transpose;
\r
831 a->handle=s->handle;
\r
832 a->tmpvolume=s->volume;
\r
833 a->volume=s->volume;
\r
838 period=GetPeriod(a->note+a->transpose,a->c2spd);
\r
840 a->wantedperiod=period;
\r
841 a->tmpperiod=period;
\r
854 void PlayEffects(void)
\r
858 if(a->row==NULL) return;
\r
865 while(c=UniGetByte()){
\r
870 case UNI_INSTRUMENT:
\r
874 case UNI_PTEFFECT0:
\r
875 DoPTEffect0(UniGetByte());
\r
878 case UNI_PTEFFECT1:
\r
880 if(dat!=0) a->slidespeed=(UWORD)dat<<2;
\r
881 if(vbtick) a->tmpperiod-=a->slidespeed;
\r
884 case UNI_PTEFFECT2:
\r
886 if(dat!=0) a->slidespeed=(UWORD)dat<<2;
\r
887 if(vbtick) a->tmpperiod+=a->slidespeed;
\r
890 case UNI_PTEFFECT3:
\r
892 a->kick=0; /* temp XM fix */
\r
901 case UNI_PTEFFECT4:
\r
903 if(dat&0x0f) a->vibdepth=dat&0xf;
\r
904 if(dat&0xf0) a->vibspd=(dat&0xf0)>>2;
\r
909 case UNI_PTEFFECT5:
\r
917 case UNI_PTEFFECT6:
\r
924 case UNI_PTEFFECT7:
\r
926 if(dat&0x0f) a->trmdepth=dat&0xf;
\r
927 if(dat&0xf0) a->trmspd=(dat&0xf0)>>2;
\r
932 case UNI_PTEFFECT8:
\r
936 pf->panning[mp_channel]=dat;
\r
940 case UNI_PTEFFECT9:
\r
942 if(dat) a->soffset=(UWORD)dat<<8; /* <- 0.43 fix.. */
\r
943 a->start=a->soffset;
\r
944 if(a->start>a->s->length) a->start=a->s->length;
\r
947 case UNI_PTEFFECTA:
\r
948 DoVolSlide(UniGetByte());
\r
951 case UNI_PTEFFECTB:
\r
959 case UNI_PTEFFECTC:
\r
966 case UNI_PTEFFECTD:
\r
970 int hi=(dat&0xf0)>>4;
\r
974 if(patbrk>64) patbrk=64; /* <- v0.42 fix */
\r
978 case UNI_PTEFFECTE:
\r
979 DoEEffects(UniGetByte());
\r
982 case UNI_PTEFFECTF:
\r
985 if(vbtick || patdly2) break;
\r
987 if(mp_extspd && dat>=0x20){
\r
991 if(dat){ /* <- v0.44 bugfix */
\r
998 case UNI_S3MEFFECTD:
\r
999 DoS3MVolSlide(UniGetByte());
\r
1002 case UNI_S3MEFFECTE:
\r
1003 DoS3MSlideDn(UniGetByte());
\r
1006 case UNI_S3MEFFECTF:
\r
1007 DoS3MSlideUp(UniGetByte());
\r
1010 case UNI_S3MEFFECTI:
\r
1011 DoS3MTremor(UniGetByte());
\r
1015 case UNI_S3MEFFECTQ:
\r
1016 DoS3MRetrig(UniGetByte());
\r
1019 case UNI_S3MEFFECTA:
\r
1020 DoS3MSpeed(UniGetByte());
\r
1023 case UNI_S3MEFFECTT:
\r
1024 DoS3MTempo(UniGetByte());
\r
1027 case UNI_XMEFFECTA:
\r
1028 DoXMVolSlide(UniGetByte());
\r
1031 case UNI_XMEFFECTG:
\r
1032 globalvolume=UniGetByte();
\r
1035 case UNI_XMEFFECTH:
\r
1036 DoXMGlobalSlide(UniGetByte());
\r
1039 case UNI_XMEFFECTP:
\r
1040 DoXMPanSlide(UniGetByte());
\r
1050 a->period=a->tmpperiod;
\r
1054 a->volume=a->tmpvolume;
\r
1061 SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b)
\r
1063 return(Interpolate(p,a->pos,b->pos,a->val,b->val));
\r
1067 SWORD DoPan(SWORD envpan,SWORD pan)
\r
1069 return(pan + (((envpan-128)*(128-abs(pan-128)))/128));
\r
1074 void StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE sus,UBYTE beg,UBYTE end,ENVPT *p)
\r
1089 SWORD ProcessEnvelope(ENVPR *t,SWORD v,UBYTE keyon)
\r
1091 if(t->flg & EF_ON){
\r
1093 /* panning active? -> copy variables */
\r
1102 /* compute the envelope value between points a and b */
\r
1104 v=InterpolateEnv(p,&t->env[a],&t->env[b]);
\r
1106 /* Should we sustain? (sustain flag on, key-on, point a is the sustain
\r
1107 point, and the pointer is exactly on point a) */
\r
1109 if((t->flg & EF_SUSTAIN) && keyon && a==t->sus && p==t->env[a].pos){
\r
1113 /* don't sustain, so increase pointer. */
\r
1117 /* pointer reached point b? */
\r
1119 if(p >= t->env[b].pos){
\r
1121 /* shift points a and b */
\r
1125 if(t->flg & EF_LOOP){
\r
1148 long GetFreq2(long period)
\r
1152 frequency=8363.0*pow(2,((6*12*16*4.0)-period)/(12*16*4.0));
\r
1153 return(floor(frequency));
\r
1157 long GetFreq2(long period)
\r
1161 period=7680-period;
\r
1163 frequency=lintab[period%768];
\r
1165 return(frequency>>(7-okt));
\r
1168 void MP_HandleTick(void)
\r
1174 /* don't handle the very first ticks, this allows the
\r
1175 other hardware to settle down so we don't loose any
\r
1182 if(forbid) return; /* don't go any further when forbid is true */
\r
1184 if(MP_Ready()) return;
\r
1186 if(++vbtick>=mp_sngspd){
\r
1198 /* patterndelay active */
\r
1201 mp_patpos--; /* so turn back mp_patpos by 1 */
\r
1205 /* Do we have to get a new patternpointer ?
\r
1206 (when mp_patpos reaches 64 or when
\r
1207 a patternbreak is active) */
\r
1209 if( mp_patpos == numrow ) posjmp=3;
\r
1214 mp_sngpos+=(posjmp-2);
\r
1216 if(mp_sngpos>=pf->numpos){
\r
1217 if(!mp_loop) return;
\r
1218 mp_sngpos=pf->reppos;
\r
1220 if(mp_sngpos<0) mp_sngpos=pf->numpos-1;
\r
1226 for(t=0;t<pf->numchn;t++){
\r
1228 tr=pf->patterns[(pf->positions[mp_sngpos]*pf->numchn)+t];
\r
1229 numrow=pf->pattrows[pf->positions[mp_sngpos]];
\r
1233 a->row=(tr<pf->numtrk) ? UniFindRow(pf->tracks[tr],mp_patpos) : NULL;
\r
1240 /* Update effects */
\r
1242 for(t=0;t<pf->numchn;t++){
\r
1248 for(t=0;t<pf->numchn;t++){
\r
1251 SWORD envpan,envvol;
\r
1257 if(i==NULL || s==NULL) continue;
\r
1259 if(a->period<40) a->period=40;
\r
1260 if(a->period>8000) a->period=8000;
\r
1263 MD_VoicePlay(t,a->handle,a->start,s->length,s->loopstart,s->loopend,s->flags);
\r
1269 StartEnvelope(&a->venv,i->volflg,i->volpts,i->volsus,i->volbeg,i->volend,i->volenv);
\r
1270 StartEnvelope(&a->penv,i->panflg,i->panpts,i->pansus,i->panbeg,i->panend,i->panenv);
\r
1273 envvol=ProcessEnvelope(&a->venv,256,a->keyon);
\r
1274 envpan=ProcessEnvelope(&a->penv,128,a->keyon);
\r
1276 tmpvol=a->fadevol; /* max 32768 */
\r
1277 tmpvol*=envvol; /* * max 256 */
\r
1278 tmpvol*=a->volume; /* * max 64 */
\r
1279 tmpvol/=16384; /* tmpvol/(256*64) => tmpvol is max 32768 */
\r
1281 tmpvol*=globalvolume; /* * max 64 */
\r
1282 tmpvol*=mp_volume; /* * max 100 */
\r
1283 tmpvol/=3276800UL; /* tmpvol/(64*100*512) => tmpvol is max 64 */
\r
1285 MD_VoiceSetVolume(t,tmpvol);
\r
1287 if(s->flags& SF_OWNPAN){
\r
1288 MD_VoiceSetPanning(t,DoPan(envpan,a->panning));
\r
1291 MD_VoiceSetPanning(t,a->panning);
\r
1294 if(pf->flags&UF_LINEAR)
\r
1295 MD_VoiceSetFrequency(t,GetFreq2(a->period));
\r
1297 MD_VoiceSetFrequency(t,(3579546UL<<2)/a->period);
\r
1299 /* if key-off, start substracting
\r
1300 fadeoutspeed from fadevol: */
\r
1303 if(a->fadevol>=i->volfade)
\r
1304 a->fadevol-=i->volfade;
\r
1313 void MP_Init(UNIMOD *m)
\r
1321 mp_sngspd=m->initspeed;
\r
1326 mp_bpm=m->inittempo;
\r
1330 posjmp=2; /* <- make sure the player fetches the first note */
\r
1333 isfirst=2; /* delay start by 2 ticks */
\r
1335 globalvolume=64; /* reset global volume */
\r
1337 /* Make sure the player doesn't start with garbage: */
\r
1339 for(t=0;t<pf->numchn;t++){
\r
1340 mp_audio[t].kick=0;
\r
1341 mp_audio[t].tmpvolume=0;
\r
1342 mp_audio[t].retrig=0;
\r
1343 mp_audio[t].wavecontrol=0;
\r
1344 mp_audio[t].glissando=0;
\r
1345 mp_audio[t].soffset=0;
\r
1351 int MP_Ready(void)
\r
1353 return(mp_sngpos>=pf->numpos);
\r
1357 void MP_NextPosition(void)
\r
1367 void MP_PrevPosition(void)
\r
1377 void MP_SetPosition(UWORD pos)
\r
1379 if(pos>=pf->numpos) pos=pf->numpos;
\r