added an old version of mikmod for dos
[dosdemo] / libs / oldmik / src / mplayer.c
1 /*\r
2 \r
3 Name:\r
4 MPLAYER.C\r
5 \r
6 Description:\r
7 The actual modplaying routines\r
8 \r
9 Portability:\r
10 All systems - all compilers\r
11 \r
12 */\r
13 #include <stdlib.h>\r
14 #include "mikmod.h"\r
15 \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
27 \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
32                                                 */\r
33 int   forbid;                   /* forbidflag */\r
34 static int isfirst;\r
35 \r
36 /*\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
40 */\r
41 \r
42 \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
53 \r
54 static SBYTE globalvolume=64;   /* global volume */\r
55 static UBYTE globalslide;\r
56 \r
57 AUDTMP *a;                              /* current AUDTMP it's working on */\r
58 \r
59 \r
60 UWORD mytab[12]={\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
63 };\r
64 \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
70 };\r
71 \r
72 \r
73 /* linear periods to frequency translation table: */\r
74 \r
75 UWORD lintab[768]={\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
124 };\r
125 \r
126 \r
127 \r
128 \r
129 #define LOGFAC 2*16\r
130 \r
131 UWORD logtab[]={\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
145 };\r
146 \r
147 \r
148 SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2)\r
149 {\r
150         SWORD dp,dv,di;\r
151 \r
152         if(p1==p2) return v1;\r
153 \r
154         dv=v2-v1;\r
155         dp=p2-p1;\r
156         di=p-p1;\r
157 \r
158         return v1 + ((SLONG)(di*dv) / dp);\r
159 }\r
160 \r
161 \r
162 UWORD getlinearperiod(UBYTE note,UWORD fine)\r
163 {\r
164         return((10L*12*16*4)-((UWORD)note*16*4)-(fine/2)+64);\r
165 }\r
166 \r
167 \r
168 UWORD getlogperiod(UBYTE note,UWORD fine)\r
169 {\r
170         UBYTE n,o;\r
171         UWORD p1,p2,i;\r
172 \r
173         n=note%12;\r
174         o=note/12;\r
175         i=(n<<3)+(fine>>4);                     /* n*8 + fine/16 */\r
176 \r
177         p1=logtab[i];\r
178         p2=logtab[i+1];\r
179 \r
180         return(Interpolate(fine/16,0,15,p1,p2)>>o);\r
181 }\r
182 \r
183 \r
184 UWORD getoldperiod(UBYTE note,UWORD c2spd)\r
185 {\r
186         UBYTE n,o;\r
187         ULONG period;\r
188 \r
189         if(!c2spd) return 4242;         /* <- prevent divide overflow.. (42 eheh) */\r
190 \r
191         n=note%12;\r
192         o=note/12;\r
193         period=((8363L*mytab[n]) >> o )/c2spd;\r
194         return period;\r
195 }\r
196 \r
197 \r
198 \r
199 UWORD GetPeriod(UBYTE note,UWORD c2spd)\r
200 {\r
201         if(pf->flags&UF_XMPERIODS){\r
202                 return (pf->flags&UF_LINEAR) ? getlinearperiod(note,c2spd) : getlogperiod(note,c2spd);\r
203         }\r
204         return(getoldperiod(note,c2spd));\r
205 }\r
206 \r
207 \r
208 \r
209 void DoEEffects(UBYTE dat)\r
210 {\r
211         UBYTE nib;\r
212 \r
213         nib=dat&0xf;\r
214 \r
215         switch(dat>>4){\r
216 \r
217                 case 0x0:       /* filter toggle, not supported */\r
218                                 break;\r
219 \r
220                 case 0x1:       /* fineslide up */\r
221                                 if(!vbtick) a->tmpperiod-=(nib<<2);\r
222                                 break;\r
223 \r
224                 case 0x2:       /* fineslide dn */\r
225                                 if(!vbtick) a->tmpperiod+=(nib<<2);\r
226                                 break;\r
227 \r
228                 case 0x3:       /* glissando ctrl */\r
229                                 a->glissando=nib;\r
230                                 break;\r
231 \r
232                 case 0x4:       /* set vibrato waveform */\r
233                                 a->wavecontrol&=0xf0;\r
234                                 a->wavecontrol|=nib;\r
235                                 break;\r
236 \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
240                                 break;\r
241 \r
242                 case 0x6:       /* set patternloop */\r
243 \r
244                                 if(vbtick) break;\r
245 \r
246                                 /* hmm.. this one is a real kludge. But now it\r
247                                    works. */\r
248 \r
249                                 if(nib){                /* set reppos or repcnt ? */\r
250 \r
251                                         /* set repcnt, so check if repcnt already is set,\r
252                                            which means we are already looping */\r
253 \r
254                                         if(repcnt>0)\r
255                                                 repcnt--;               /* already looping, decrease counter */\r
256                                         else\r
257                                                 repcnt=nib;             /* not yet looping, so set repcnt */\r
258 \r
259                                         if(repcnt)                      /* jump to reppos if repcnt>0 */\r
260                                                 mp_patpos=reppos;\r
261                                 }\r
262                                 else{\r
263                                         reppos=mp_patpos-1;     /* set reppos */\r
264                                 }\r
265                                 break;\r
266 \r
267 \r
268                 case 0x7:       /* set tremolo waveform */\r
269                                 a->wavecontrol&=0x0f;\r
270                                 a->wavecontrol|=nib<<4;\r
271                                 break;\r
272 \r
273                 case 0x8:       /* set panning */\r
274                                 if(mp_panning){\r
275                                         nib<<=4;\r
276                                         a->panning=nib;\r
277                                         pf->panning[mp_channel]=nib;\r
278                                 }\r
279                                 break;\r
280 \r
281                 case 0x9:       /* retrig note */\r
282 \r
283                                 /* only retrigger if\r
284                                    data nibble > 0 */\r
285 \r
286                                 if(nib>0){\r
287                                         if(a->retrig==0){\r
288 \r
289                                                 /* when retrig counter reaches 0,\r
290                                                    reset counter and restart the sample */\r
291 \r
292                                                 a->kick=1;\r
293                                                 a->retrig=nib;\r
294                                         }\r
295                                         a->retrig--; /* countdown */\r
296                                 }\r
297                                 break;\r
298 \r
299                 case 0xa:       /* fine volume slide up */\r
300                                 if(vbtick) break;\r
301 \r
302                                 a->tmpvolume+=nib;\r
303                                 if(a->tmpvolume>64) a->tmpvolume=64;\r
304                                 break;\r
305 \r
306                 case 0xb:       /* fine volume slide dn */\r
307                                 if(vbtick) break;\r
308 \r
309                                 a->tmpvolume-=nib;\r
310                                 if(a->tmpvolume<0) a->tmpvolume=0;\r
311                                 break;\r
312 \r
313                 case 0xc:       /* cut note */\r
314 \r
315                                 /* When vbtick reaches the cut-note value,\r
316                                    turn the volume to zero ( Just like\r
317                                    on the amiga) */\r
318 \r
319                                 if(vbtick>=nib){\r
320                                         a->tmpvolume=0;                 /* just turn the volume down */\r
321                                 }\r
322                                 break;\r
323 \r
324                 case 0xd:       /* note delay */\r
325 \r
326                                 /* delay the start of the\r
327                                    sample until vbtick==nib */\r
328 \r
329                                 if(vbtick==nib){\r
330                                         a->kick=1;\r
331                                 }\r
332                                 else a->kick=0;\r
333                                 break;\r
334 \r
335                 case 0xe:       /* pattern delay */\r
336                                 if(vbtick) break;\r
337                                 if(!patdly2) patdly=nib+1;                              /* only once (when vbtick=0) */\r
338                                 break;\r
339 \r
340                 case 0xf:       /* invert loop, not supported */\r
341                                 break;\r
342         }\r
343 }\r
344 \r
345 \r
346 void DoVibrato(void)\r
347 {\r
348         UBYTE q;\r
349         UWORD temp;\r
350 \r
351         q=(a->vibpos>>2)&0x1f;\r
352 \r
353         switch(a->wavecontrol&3){\r
354 \r
355                 case 0: /* sine */\r
356                         temp=VibratoTable[q];\r
357                         break;\r
358 \r
359                 case 1: /* ramp down */\r
360                         q<<=3;\r
361                         if(a->vibpos<0) q=255-q;\r
362                         temp=q;\r
363                         break;\r
364 \r
365                 case 2: /* square wave */\r
366                         temp=255;\r
367                         break;\r
368         }\r
369 \r
370         temp*=a->vibdepth;\r
371         temp>>=7;\r
372         temp<<=2;\r
373 \r
374         if(a->vibpos>=0)\r
375                 a->period=a->tmpperiod+temp;\r
376         else\r
377                 a->period=a->tmpperiod-temp;\r
378 \r
379         if(vbtick) a->vibpos+=a->vibspd;        /* do not update when vbtick==0 */\r
380 }\r
381 \r
382 \r
383 \r
384 void DoTremolo(void)\r
385 {\r
386         UBYTE q;\r
387         UWORD temp;\r
388 \r
389         q=(a->trmpos>>2)&0x1f;\r
390 \r
391         switch((a->wavecontrol>>4)&3){\r
392 \r
393                 case 0: /* sine */\r
394                         temp=VibratoTable[q];\r
395                         break;\r
396 \r
397                 case 1: /* ramp down */\r
398                         q<<=3;\r
399                         if(a->trmpos<0) q=255-q;\r
400                         temp=q;\r
401                         break;\r
402 \r
403                 case 2: /* square wave */\r
404                         temp=255;\r
405                         break;\r
406         }\r
407 \r
408         temp*=a->trmdepth;\r
409         temp>>=6;\r
410 \r
411         if(a->trmpos>=0){\r
412                 a->volume=a->tmpvolume+temp;\r
413                 if(a->volume>64) a->volume=64;\r
414         }\r
415         else{\r
416                 a->volume=a->tmpvolume-temp;\r
417                 if(a->volume<0) a->volume=0;\r
418         }\r
419 \r
420         if(vbtick) a->trmpos+=a->trmspd;        /* do not update when vbtick==0 */\r
421 }\r
422 \r
423 \r
424 void DoVolSlide(UBYTE dat)\r
425 {\r
426         if(!vbtick) return;             /* do not update when vbtick==0 */\r
427 \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
432 }\r
433 \r
434 \r
435 \r
436 void DoS3MVolSlide(UBYTE inf)\r
437 {\r
438         UBYTE lo,hi;\r
439 \r
440         if(inf){\r
441                 a->s3mvolslide=inf;\r
442         }\r
443         inf=a->s3mvolslide;\r
444 \r
445         lo=inf&0xf;\r
446         hi=inf>>4;\r
447 \r
448         if(hi==0){\r
449                 a->tmpvolume-=lo;\r
450         }\r
451         else if(lo==0){\r
452                 a->tmpvolume+=hi;\r
453         }\r
454         else if(hi==0xf){\r
455                 if(!vbtick) a->tmpvolume-=lo;\r
456         }\r
457         else if(lo==0xf){\r
458                 if(!vbtick) a->tmpvolume+=hi;\r
459         }\r
460 \r
461         if(a->tmpvolume<0) a->tmpvolume=0;\r
462         if(a->tmpvolume>64) a->tmpvolume=64;\r
463 }\r
464 \r
465 \r
466 \r
467 void DoXMVolSlide(UBYTE inf)\r
468 {\r
469         UBYTE lo,hi;\r
470 \r
471         if(inf){\r
472                 a->s3mvolslide=inf;\r
473         }\r
474         inf=a->s3mvolslide;\r
475 \r
476         if(!vbtick) return;\r
477 \r
478         lo=inf&0xf;\r
479         hi=inf>>4;\r
480 \r
481         if(hi==0)\r
482                 a->tmpvolume-=lo;\r
483         else\r
484                 a->tmpvolume+=hi;\r
485 \r
486         if(a->tmpvolume<0) a->tmpvolume=0;\r
487         else if(a->tmpvolume>64) a->tmpvolume=64;\r
488 }\r
489 \r
490 \r
491 \r
492 void DoXMGlobalSlide(UBYTE inf)\r
493 {\r
494         UBYTE lo,hi;\r
495 \r
496         if(inf){\r
497                 globalslide=inf;\r
498         }\r
499         inf=globalslide;\r
500 \r
501         if(!vbtick) return;\r
502 \r
503         lo=inf&0xf;\r
504         hi=inf>>4;\r
505 \r
506         if(hi==0)\r
507                 globalvolume-=lo;\r
508         else\r
509                 globalvolume+=hi;\r
510 \r
511         if(globalvolume<0) globalvolume=0;\r
512         else if(globalvolume>64) globalvolume=64;\r
513 }\r
514 \r
515 \r
516 \r
517 void DoXMPanSlide(UBYTE inf)\r
518 {\r
519         UBYTE lo,hi;\r
520         SWORD pan;\r
521 \r
522 \r
523         if(inf!=0) a->pansspd=inf;\r
524         else inf=a->pansspd;\r
525 \r
526         if(!vbtick) return;\r
527 \r
528         lo=inf&0xf;\r
529         hi=inf>>4;\r
530 \r
531         /* slide right has absolute priority: */\r
532 \r
533         if(hi) lo=0;\r
534 \r
535         pan=a->panning;\r
536 \r
537         pan-=lo;\r
538         pan+=hi;\r
539 \r
540         if(pan<0) pan=0;\r
541         if(pan>255) pan=255;\r
542 \r
543         a->panning=pan;\r
544 }\r
545 \r
546 \r
547 \r
548 void DoS3MSlideDn(UBYTE inf)\r
549 {\r
550         UBYTE hi,lo;\r
551 \r
552         if(inf!=0) a->slidespeed=inf;\r
553         else inf=a->slidespeed;\r
554 \r
555         hi=inf>>4;\r
556         lo=inf&0xf;\r
557 \r
558         if(hi==0xf){\r
559                 if(!vbtick) a->tmpperiod+=(UWORD)lo<<2;\r
560         }\r
561         else if(hi==0xe){\r
562                 if(!vbtick) a->tmpperiod+=lo;\r
563         }\r
564         else{\r
565                 if(vbtick) a->tmpperiod+=(UWORD)inf<<2;\r
566         }\r
567 }\r
568 \r
569 \r
570 \r
571 void DoS3MSlideUp(UBYTE inf)\r
572 {\r
573         UBYTE hi,lo;\r
574 \r
575         if(inf!=0) a->slidespeed=inf;\r
576         else inf=a->slidespeed;\r
577 \r
578         hi=inf>>4;\r
579         lo=inf&0xf;\r
580 \r
581         if(hi==0xf){\r
582                 if(!vbtick) a->tmpperiod-=(UWORD)lo<<2;\r
583         }\r
584         else if(hi==0xe){\r
585                 if(!vbtick) a->tmpperiod-=lo;\r
586         }\r
587         else{\r
588                 if(vbtick) a->tmpperiod-=(UWORD)inf<<2;\r
589         }\r
590 }\r
591 \r
592 \r
593 \r
594 void DoS3MTremor(UBYTE inf)\r
595 {\r
596         UBYTE on,off;\r
597 \r
598         if(inf!=0) a->s3mtronof=inf;\r
599         else inf=a->s3mtronof;\r
600 \r
601         if(!vbtick) return;\r
602 \r
603         on=(inf>>4)+1;\r
604         off=(inf&0xf)+1;\r
605 \r
606         a->s3mtremor%=(on+off);\r
607         a->volume=(a->s3mtremor < on ) ? a->tmpvolume:0;\r
608         a->s3mtremor++;\r
609 }\r
610 \r
611 \r
612 \r
613 void DoS3MRetrig(UBYTE inf)\r
614 {\r
615         UBYTE hi,lo;\r
616 \r
617         hi=inf>>4;\r
618         lo=inf&0xf;\r
619 \r
620         if(lo){\r
621                 a->s3mrtgslide=hi;\r
622                 a->s3mrtgspeed=lo;\r
623         }\r
624 \r
625         if(hi){\r
626                 a->s3mrtgslide=hi;\r
627         }\r
628 \r
629         /* only retrigger if\r
630            lo nibble > 0 */\r
631 \r
632         if(a->s3mrtgspeed>0){\r
633                 if(a->retrig==0){\r
634 \r
635                         /* when retrig counter reaches 0,\r
636                            reset counter and restart the sample */\r
637 \r
638                         a->kick=1;\r
639                         a->retrig=a->s3mrtgspeed;\r
640 \r
641                         if(vbtick){                     /* don't slide on first retrig */\r
642                                 switch(a->s3mrtgslide){\r
643 \r
644                                         case 1:\r
645                                         case 2:\r
646                                         case 3:\r
647                                         case 4:\r
648                                         case 5:\r
649                                                 a->tmpvolume-=(1<<(a->s3mrtgslide-1));\r
650                                                 break;\r
651 \r
652                                         case 6:\r
653                                                 a->tmpvolume=(2*a->tmpvolume)/3;\r
654                                                 break;\r
655 \r
656                                         case 7:\r
657                                                 a->tmpvolume=a->tmpvolume>>1;\r
658                                                 break;\r
659 \r
660                                         case 9:\r
661                                         case 0xa:\r
662                                         case 0xb:\r
663                                         case 0xc:\r
664                                         case 0xd:\r
665                                                 a->tmpvolume+=(1<<(a->s3mrtgslide-9));\r
666                                                 break;\r
667 \r
668                                         case 0xe:\r
669                                                 a->tmpvolume=(3*a->tmpvolume)/2;\r
670                                                 break;\r
671 \r
672                                         case 0xf:\r
673                                                 a->tmpvolume=a->tmpvolume<<1;\r
674                                                 break;\r
675                                 }\r
676                                 if(a->tmpvolume<0) a->tmpvolume=0;\r
677                                 if(a->tmpvolume>64) a->tmpvolume=64;\r
678                         }\r
679                 }\r
680                 a->retrig--; /* countdown */\r
681         }\r
682 }\r
683 \r
684 \r
685 void DoS3MSpeed(UBYTE speed)\r
686 {\r
687         if(vbtick || patdly2) return;\r
688 \r
689         if(speed){                      /* <- v0.44 bugfix */\r
690                 mp_sngspd=speed;\r
691                 vbtick=0;\r
692         }\r
693 }\r
694 \r
695 \r
696 void DoS3MTempo(UBYTE tempo)\r
697 {\r
698         if(vbtick || patdly2) return;\r
699         mp_bpm=tempo;\r
700 }\r
701 \r
702 \r
703 void DoToneSlide(void)\r
704 {\r
705         int dist,t;\r
706 \r
707         if(!vbtick){\r
708                 a->tmpperiod=a->period;\r
709                 return;\r
710         }\r
711 \r
712         /* We have to slide a->period towards a->wantedperiod, so\r
713            compute the difference between those two values */\r
714 \r
715         dist=a->period-a->wantedperiod;\r
716 \r
717         if( dist==0 ||                          /* if they are equal */\r
718                 a->portspeed>abs(dist) ){       /* or if portamentospeed is too big */\r
719 \r
720                 a->period=a->wantedperiod;      /* make tmpperiod equal tperiod */\r
721         }\r
722         else if(dist>0){                                /* dist>0 ? */\r
723                 a->period-=a->portspeed;        /* then slide up */\r
724         }\r
725         else\r
726                 a->period+=a->portspeed;        /* dist<0 -> slide down */\r
727 \r
728 /*      if(a->glissando){\r
729 \r
730                  If glissando is on, find the nearest\r
731                    halfnote to a->tmpperiod\r
732 \r
733                 for(t=0;t<60;t++){\r
734                         if(a->tmpperiod>=npertab[a->finetune][t]) break;\r
735                 }\r
736 \r
737                 a->period=npertab[a->finetune][t];\r
738         }\r
739         else\r
740 */\r
741         a->tmpperiod=a->period;\r
742 }\r
743 \r
744 \r
745 void DoPTEffect0(UBYTE dat)\r
746 {\r
747         UBYTE note;\r
748 \r
749         note=a->note;\r
750 \r
751         if(dat!=0){\r
752                 switch(vbtick%3){\r
753                         case 1:\r
754                                 note+=(dat>>4); break;\r
755                         case 2:\r
756                                 note+=(dat&0xf); break;\r
757                 }\r
758                 a->period=GetPeriod(note+a->transpose,a->c2spd);\r
759                 a->ownper=1;\r
760         }\r
761 }\r
762 \r
763 \r
764 void PlayNote(void)\r
765 {\r
766         INSTRUMENT *i;\r
767         SAMPLE *s;\r
768         UWORD period;\r
769         UBYTE inst,c;\r
770         UBYTE note;\r
771 \r
772         if(a->row==NULL) return;\r
773 \r
774         UniSetRow(a->row);\r
775 \r
776         while(c=UniGetByte()){\r
777 \r
778                 switch(c){\r
779 \r
780                         case UNI_NOTE:\r
781                                 note=UniGetByte();\r
782 \r
783                                 if(note==96){                   /* key off ? */\r
784                                         a->keyon=0;\r
785                                         if(a->i && !(a->i->volflg & EF_ON)){\r
786                                                 a->tmpvolume=0;\r
787                                         }\r
788                                 }\r
789                                 else{\r
790                                         a->note=note;\r
791 \r
792                                         period=GetPeriod(note+a->transpose,a->c2spd);\r
793 \r
794                                         a->wantedperiod=period;\r
795                                         a->tmpperiod=period;\r
796 \r
797                                         a->kick=1;\r
798                                         a->start=0;\r
799 \r
800                                         /* retrig tremolo and vibrato waves ? */\r
801 \r
802                                         if(!(a->wavecontrol&0x80)) a->trmpos=0;\r
803                                         if(!(a->wavecontrol&0x08)) a->vibpos=0;\r
804                                 }\r
805                                 break;\r
806 \r
807                         case UNI_INSTRUMENT:\r
808                                 inst=UniGetByte();\r
809                                 if(inst>=pf->numins) break;             /* <- safety valve */\r
810 \r
811                                 a->sample=inst;\r
812 \r
813                                 i=&pf->instruments[inst];\r
814                                 a->i=i;\r
815 \r
816                                 if(i->samplenumber[a->note]>=i->numsmp) break;\r
817 \r
818                                 s=&i->samples[i->samplenumber[a->note]];\r
819                                 a->s=s;\r
820 \r
821                                 /* channel or instrument determined panning ? */\r
822 \r
823                                 if(s->flags& SF_OWNPAN){\r
824                                         a->panning=s->panning;\r
825                                 }\r
826                                 else{\r
827                                         a->panning=pf->panning[mp_channel];\r
828                                 }\r
829 \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
834                                 a->c2spd=s->c2spd;\r
835                                 a->retrig=0;\r
836                                 a->s3mtremor=0;\r
837 \r
838                                 period=GetPeriod(a->note+a->transpose,a->c2spd);\r
839 \r
840                                 a->wantedperiod=period;\r
841                                 a->tmpperiod=period;\r
842                                 break;\r
843 \r
844                         default:\r
845                                 UniSkipOpcode(c);\r
846                                 break;\r
847                 }\r
848         }\r
849 }\r
850 \r
851 \r
852 \r
853 \r
854 void PlayEffects(void)\r
855 {\r
856         UBYTE c,dat;\r
857 \r
858         if(a->row==NULL) return;\r
859 \r
860         UniSetRow(a->row);\r
861 \r
862         a->ownper=0;\r
863         a->ownvol=0;\r
864 \r
865         while(c=UniGetByte()){\r
866 \r
867                 switch(c){\r
868 \r
869                         case UNI_NOTE:\r
870                         case UNI_INSTRUMENT:\r
871                                 UniSkipOpcode(c);\r
872                                 break;\r
873 \r
874                         case UNI_PTEFFECT0:\r
875                                 DoPTEffect0(UniGetByte());\r
876                                 break;\r
877 \r
878                         case UNI_PTEFFECT1:\r
879                                 dat=UniGetByte();\r
880                                 if(dat!=0) a->slidespeed=(UWORD)dat<<2;\r
881                                 if(vbtick) a->tmpperiod-=a->slidespeed;\r
882                                 break;\r
883 \r
884                         case UNI_PTEFFECT2:\r
885                                 dat=UniGetByte();\r
886                                 if(dat!=0) a->slidespeed=(UWORD)dat<<2;\r
887                                 if(vbtick) a->tmpperiod+=a->slidespeed;\r
888                                 break;\r
889 \r
890                         case UNI_PTEFFECT3:\r
891                                 dat=UniGetByte();\r
892                                 a->kick=0;                              /* temp XM fix */\r
893                                 if(dat!=0){\r
894                                         a->portspeed=dat;\r
895                                         a->portspeed<<=2;\r
896                                 }\r
897                                 DoToneSlide();\r
898                                 a->ownper=1;\r
899                                 break;\r
900 \r
901                         case UNI_PTEFFECT4:\r
902                                 dat=UniGetByte();\r
903                                 if(dat&0x0f) a->vibdepth=dat&0xf;\r
904                                 if(dat&0xf0) a->vibspd=(dat&0xf0)>>2;\r
905                                 DoVibrato();\r
906                                 a->ownper=1;\r
907                                 break;\r
908 \r
909                         case UNI_PTEFFECT5:\r
910                                 dat=UniGetByte();\r
911                                 a->kick=0;\r
912                                 DoToneSlide();\r
913                                 DoVolSlide(dat);\r
914                                 a->ownper=1;\r
915                                 break;\r
916 \r
917                         case UNI_PTEFFECT6:\r
918                                 dat=UniGetByte();\r
919                                 DoVibrato();\r
920                                 DoVolSlide(dat);\r
921                                 a->ownper=1;\r
922                                 break;\r
923 \r
924                         case UNI_PTEFFECT7:\r
925                                 dat=UniGetByte();\r
926                                 if(dat&0x0f) a->trmdepth=dat&0xf;\r
927                                 if(dat&0xf0) a->trmspd=(dat&0xf0)>>2;\r
928                                 DoTremolo();\r
929                                 a->ownvol=1;\r
930                                 break;\r
931 \r
932                         case UNI_PTEFFECT8:\r
933                                 dat=UniGetByte();\r
934                                 if(mp_panning){\r
935                                         a->panning=dat;\r
936                                         pf->panning[mp_channel]=dat;\r
937                                 }\r
938                                 break;\r
939 \r
940                         case UNI_PTEFFECT9:\r
941                                 dat=UniGetByte();\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
945                                 break;\r
946 \r
947                         case UNI_PTEFFECTA:\r
948                                 DoVolSlide(UniGetByte());\r
949                                 break;\r
950 \r
951                         case UNI_PTEFFECTB:\r
952                                 dat=UniGetByte();\r
953                                 if(patdly2) break;\r
954                                 patbrk=0;\r
955                                 mp_sngpos=dat-1;\r
956                                 posjmp=3;\r
957                                 break;\r
958 \r
959                         case UNI_PTEFFECTC:\r
960                                 dat=UniGetByte();\r
961                                 if(vbtick) break;\r
962                                 if(dat>64) dat=64;\r
963                                 a->tmpvolume=dat;\r
964                                 break;\r
965 \r
966                         case UNI_PTEFFECTD:\r
967                                 dat=UniGetByte();\r
968                                 if(patdly2) break;\r
969                                 {\r
970                                         int hi=(dat&0xf0)>>4;\r
971                                         int     lo=(dat&0xf);\r
972                                         patbrk=(hi*10)+lo;\r
973                                 }\r
974                                 if(patbrk>64) patbrk=64;        /* <- v0.42 fix */\r
975                                 posjmp=3;\r
976                                 break;\r
977 \r
978                         case UNI_PTEFFECTE:\r
979                                 DoEEffects(UniGetByte());\r
980                                 break;\r
981 \r
982                         case UNI_PTEFFECTF:\r
983                                 dat=UniGetByte();\r
984 \r
985                                 if(vbtick || patdly2) break;\r
986 \r
987                                 if(mp_extspd && dat>=0x20){\r
988                                         mp_bpm=dat;\r
989                                 }\r
990                                 else{\r
991                                         if(dat){                        /* <- v0.44 bugfix */\r
992                                                 mp_sngspd=dat;\r
993                                                 vbtick=0;\r
994                                         }\r
995                                 }\r
996                                 break;\r
997 \r
998                         case UNI_S3MEFFECTD:\r
999                                 DoS3MVolSlide(UniGetByte());\r
1000                                 break;\r
1001 \r
1002                         case UNI_S3MEFFECTE:\r
1003                                 DoS3MSlideDn(UniGetByte());\r
1004                                 break;\r
1005 \r
1006                         case UNI_S3MEFFECTF:\r
1007                                 DoS3MSlideUp(UniGetByte());\r
1008                                 break;\r
1009 \r
1010                         case UNI_S3MEFFECTI:\r
1011                                 DoS3MTremor(UniGetByte());\r
1012                                 a->ownvol=1;\r
1013                                 break;\r
1014 \r
1015                         case UNI_S3MEFFECTQ:\r
1016                                 DoS3MRetrig(UniGetByte());\r
1017                                 break;\r
1018 \r
1019                         case UNI_S3MEFFECTA:\r
1020                                 DoS3MSpeed(UniGetByte());\r
1021                                 break;\r
1022 \r
1023                         case UNI_S3MEFFECTT:\r
1024                                 DoS3MTempo(UniGetByte());\r
1025                                 break;\r
1026 \r
1027                         case UNI_XMEFFECTA:\r
1028                                 DoXMVolSlide(UniGetByte());\r
1029                                 break;\r
1030 \r
1031                         case UNI_XMEFFECTG:\r
1032                                 globalvolume=UniGetByte();\r
1033                                 break;\r
1034 \r
1035                         case UNI_XMEFFECTH:\r
1036                                 DoXMGlobalSlide(UniGetByte());\r
1037                                 break;\r
1038 \r
1039                         case UNI_XMEFFECTP:\r
1040                                 DoXMPanSlide(UniGetByte());\r
1041                                 break;\r
1042 \r
1043                         default:\r
1044                                 UniSkipOpcode(c);\r
1045                                 break;\r
1046                 }\r
1047         }\r
1048 \r
1049         if(!a->ownper){\r
1050                 a->period=a->tmpperiod;\r
1051         }\r
1052 \r
1053         if(!a->ownvol){\r
1054                 a->volume=a->tmpvolume;\r
1055         }\r
1056 }\r
1057 \r
1058 \r
1059 \r
1060 \r
1061 SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b)\r
1062 {\r
1063         return(Interpolate(p,a->pos,b->pos,a->val,b->val));\r
1064 }\r
1065 \r
1066 \r
1067 SWORD DoPan(SWORD envpan,SWORD pan)\r
1068 {\r
1069         return(pan + (((envpan-128)*(128-abs(pan-128)))/128));\r
1070 }\r
1071 \r
1072 \r
1073 \r
1074 void StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE sus,UBYTE beg,UBYTE end,ENVPT *p)\r
1075 {\r
1076         t->flg=flg;\r
1077         t->pts=pts;\r
1078         t->sus=sus;\r
1079         t->beg=beg;\r
1080         t->end=end;\r
1081         t->env=p;\r
1082         t->p=0;\r
1083         t->a=0;\r
1084         t->b=1;\r
1085 }\r
1086 \r
1087 \r
1088 \r
1089 SWORD ProcessEnvelope(ENVPR *t,SWORD v,UBYTE keyon)\r
1090 {\r
1091         if(t->flg & EF_ON){\r
1092 \r
1093                 /* panning active? -> copy variables */\r
1094 \r
1095                 UBYTE a,b;\r
1096                 UWORD p;\r
1097 \r
1098                 a=t->a;\r
1099                 b=t->b;\r
1100                 p=t->p;\r
1101 \r
1102                 /* compute the envelope value between points a and b */\r
1103 \r
1104                 v=InterpolateEnv(p,&t->env[a],&t->env[b]);\r
1105 \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
1108 \r
1109                 if((t->flg & EF_SUSTAIN) && keyon && a==t->sus && p==t->env[a].pos){\r
1110                         /* do nothing */\r
1111                 }\r
1112                 else{\r
1113                         /* don't sustain, so increase pointer. */\r
1114 \r
1115                         p++;\r
1116 \r
1117                         /* pointer reached point b? */\r
1118 \r
1119                         if(p >= t->env[b].pos){\r
1120 \r
1121                                 /* shift points a and b */\r
1122 \r
1123                                 a=b; b++;\r
1124 \r
1125                                 if(t->flg & EF_LOOP){\r
1126                                         if(b > t->end){\r
1127                                                 a=t->beg;\r
1128                                                 b=a+1;\r
1129                                                 p=t->env[a].pos;\r
1130                                         }\r
1131                                 }\r
1132                                 else{\r
1133                                         if(b >= t->pts){\r
1134                                                 b--;\r
1135                                                 p--;\r
1136                                         }\r
1137                                 }\r
1138                         }\r
1139                 }\r
1140                 t->a=a;\r
1141                 t->b=b;\r
1142                 t->p=p;\r
1143         }\r
1144         return v;\r
1145 }\r
1146 \r
1147 /*\r
1148 long GetFreq2(long period)\r
1149 {\r
1150         float frequency;\r
1151 \r
1152         frequency=8363.0*pow(2,((6*12*16*4.0)-period)/(12*16*4.0));\r
1153         return(floor(frequency));\r
1154 }\r
1155 */\r
1156 \r
1157 long GetFreq2(long period)\r
1158 {\r
1159         int okt;\r
1160         long frequency;\r
1161         period=7680-period;\r
1162         okt=period/768;\r
1163         frequency=lintab[period%768];\r
1164         frequency<<=2;\r
1165         return(frequency>>(7-okt));\r
1166 }\r
1167 \r
1168 void MP_HandleTick(void)\r
1169 {\r
1170         int z,t,tr;\r
1171         ULONG tmpvol;\r
1172 \r
1173         if(isfirst){           \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
1176                    starting notes\r
1177                 */\r
1178                 isfirst--;\r
1179                 return;\r
1180         }\r
1181 \r
1182         if(forbid) return;      /* don't go any further when forbid is true */\r
1183 \r
1184         if(MP_Ready()) return;\r
1185 \r
1186         if(++vbtick>=mp_sngspd){\r
1187 \r
1188                 mp_patpos++;\r
1189                 vbtick=0;\r
1190 \r
1191                 if(patdly){\r
1192                         patdly2=patdly;\r
1193                         patdly=0;\r
1194                 }\r
1195 \r
1196                 if(patdly2){\r
1197 \r
1198                         /* patterndelay active */\r
1199 \r
1200                         if(--patdly2){\r
1201                                 mp_patpos--;    /* so turn back mp_patpos by 1 */\r
1202                         }\r
1203                 }\r
1204 \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
1208 \r
1209                 if( mp_patpos == numrow ) posjmp=3;\r
1210 \r
1211 \r
1212                 if( posjmp ){\r
1213                         mp_patpos=patbrk;\r
1214                         mp_sngpos+=(posjmp-2);\r
1215                         patbrk=posjmp=0;\r
1216                         if(mp_sngpos>=pf->numpos){\r
1217                                 if(!mp_loop) return;\r
1218                                 mp_sngpos=pf->reppos;\r
1219                         }\r
1220                         if(mp_sngpos<0) mp_sngpos=pf->numpos-1;\r
1221                 }\r
1222 \r
1223 \r
1224                 if(!patdly2){\r
1225 \r
1226                         for(t=0;t<pf->numchn;t++){\r
1227 \r
1228                                 tr=pf->patterns[(pf->positions[mp_sngpos]*pf->numchn)+t];\r
1229                                 numrow=pf->pattrows[pf->positions[mp_sngpos]];\r
1230 \r
1231                                 mp_channel=t;\r
1232                                 a=&mp_audio[t];\r
1233                                 a->row=(tr<pf->numtrk) ? UniFindRow(pf->tracks[tr],mp_patpos) : NULL;\r
1234 \r
1235                                 PlayNote();\r
1236                         }\r
1237                 }\r
1238         }\r
1239 \r
1240         /* Update effects */\r
1241 \r
1242         for(t=0;t<pf->numchn;t++){\r
1243                 mp_channel=t;\r
1244                 a=&mp_audio[t];\r
1245                 PlayEffects();\r
1246         }\r
1247 \r
1248         for(t=0;t<pf->numchn;t++){\r
1249                 INSTRUMENT *i;\r
1250                 SAMPLE *s;\r
1251                 SWORD envpan,envvol;\r
1252 \r
1253                 a=&mp_audio[t];\r
1254                 i=a->i;\r
1255                 s=a->s;\r
1256 \r
1257                 if(i==NULL || s==NULL) continue;\r
1258 \r
1259                 if(a->period<40) a->period=40;\r
1260                 if(a->period>8000) a->period=8000;\r
1261 \r
1262                 if(a->kick){\r
1263                         MD_VoicePlay(t,a->handle,a->start,s->length,s->loopstart,s->loopend,s->flags);\r
1264                         a->kick=0;\r
1265                         a->keyon=1;\r
1266 \r
1267                         a->fadevol=32768;\r
1268 \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
1271                 }\r
1272 \r
1273                 envvol=ProcessEnvelope(&a->venv,256,a->keyon);\r
1274                 envpan=ProcessEnvelope(&a->penv,128,a->keyon);\r
1275 \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
1280 \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
1284 \r
1285                 MD_VoiceSetVolume(t,tmpvol);\r
1286 \r
1287                 if(s->flags& SF_OWNPAN){\r
1288                         MD_VoiceSetPanning(t,DoPan(envpan,a->panning));\r
1289                 }\r
1290                 else{\r
1291                         MD_VoiceSetPanning(t,a->panning);\r
1292                 }\r
1293 \r
1294                 if(pf->flags&UF_LINEAR)\r
1295                         MD_VoiceSetFrequency(t,GetFreq2(a->period));\r
1296                 else\r
1297                         MD_VoiceSetFrequency(t,(3579546UL<<2)/a->period);\r
1298 \r
1299                 /*  if key-off, start substracting\r
1300                         fadeoutspeed from fadevol: */\r
1301 \r
1302                 if(!a->keyon){\r
1303                         if(a->fadevol>=i->volfade)\r
1304                                 a->fadevol-=i->volfade;\r
1305                         else\r
1306                                 a->fadevol=0;\r
1307                 }\r
1308         }\r
1309 }\r
1310 \r
1311 \r
1312 \r
1313 void MP_Init(UNIMOD *m)\r
1314 {\r
1315         int t;\r
1316 \r
1317         pf=m;\r
1318         reppos=0;\r
1319         repcnt=0;\r
1320         mp_sngpos=0;\r
1321         mp_sngspd=m->initspeed;\r
1322 \r
1323         vbtick=mp_sngspd;\r
1324         patdly=0;\r
1325         patdly2=0;\r
1326         mp_bpm=m->inittempo;\r
1327 \r
1328         forbid=0;\r
1329         mp_patpos=0;\r
1330         posjmp=2;               /* <- make sure the player fetches the first note */\r
1331         patbrk=0;\r
1332 \r
1333         isfirst=2;              /* delay start by 2 ticks */\r
1334 \r
1335         globalvolume=64;                /* reset global volume */\r
1336 \r
1337         /* Make sure the player doesn't start with garbage: */\r
1338 \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
1346         }\r
1347 }\r
1348 \r
1349 \r
1350 \r
1351 int MP_Ready(void)\r
1352 {\r
1353         return(mp_sngpos>=pf->numpos);\r
1354 }\r
1355 \r
1356 \r
1357 void MP_NextPosition(void)\r
1358 {\r
1359         forbid=1;\r
1360         posjmp=3;\r
1361         patbrk=0;\r
1362         vbtick=mp_sngspd;\r
1363         forbid=0;\r
1364 }\r
1365 \r
1366 \r
1367 void MP_PrevPosition(void)\r
1368 {\r
1369         forbid=1;\r
1370         posjmp=1;\r
1371         patbrk=0;\r
1372         vbtick=mp_sngspd;\r
1373         forbid=0;\r
1374 }\r
1375 \r
1376 \r
1377 void MP_SetPosition(UWORD pos)\r
1378 {\r
1379         if(pos>=pf->numpos) pos=pf->numpos;\r
1380         forbid=1;\r
1381         posjmp=2;\r
1382         patbrk=0;\r
1383         mp_sngpos=pos;\r
1384         vbtick=mp_sngspd;\r
1385         forbid=0;\r
1386 }\r