added csprite stuff to the djgpp makefile
[dosdemo] / libs / mikmod / playercode / mplayer.c
1 /*      MikMod sound library
2         (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
3         for complete list.
4
5         This library is free software; you can redistribute it and/or modify
6         it under the terms of the GNU Library General Public License as
7         published by the Free Software Foundation; either version 2 of
8         the License, or (at your option) any later version.
9
10         This program is distributed in the hope that it will be useful,
11         but WITHOUT ANY WARRANTY; without even the implied warranty of
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13         GNU Library General Public License for more details.
14
15         You should have received a copy of the GNU Library General Public
16         License along with this library; if not, write to the Free Software
17         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18         02111-1307, USA.
19 */
20
21 /*==============================================================================
22
23   $Id$
24
25   The Protracker Player Driver
26
27   The protracker driver supports all base Protracker 3.x commands and features.
28
29 ==============================================================================*/
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <string.h>
36 #include <stdarg.h>
37 #ifdef SRANDOM_IN_MATH_H
38 #include <math.h>
39 #else
40 #include <stdlib.h>
41 #endif
42
43 #include "mikmod_internals.h"
44
45 #ifdef SUNOS
46 extern int fprintf(FILE *, const char *, ...);
47 extern long int random(void);
48 #endif
49
50 /* The currently playing module */
51 MODULE *pf = NULL;
52
53 #define NUMVOICES(mod) (md_sngchn < (mod)->numvoices ? md_sngchn : (mod)->numvoices)
54
55 #define HIGH_OCTAVE             2       /* number of above-range octaves */
56
57 static  const UWORD oldperiods[OCTAVE*2]={
58         0x6b00, 0x6800, 0x6500, 0x6220, 0x5f50, 0x5c80,
59         0x5a00, 0x5740, 0x54d0, 0x5260, 0x5010, 0x4dc0,
60         0x4b90, 0x4960, 0x4750, 0x4540, 0x4350, 0x4160,
61         0x3f90, 0x3dc0, 0x3c10, 0x3a40, 0x38b0, 0x3700
62 };
63
64 static  const UBYTE VibratoTable[32]={
65           0, 24, 49, 74, 97,120,141,161,180,197,212,224,235,244,250,253,
66         255,253,250,244,235,224,212,197,180,161,141,120, 97, 74, 49, 24
67 };
68
69 static  const UBYTE avibtab[128]={
70          0, 1, 3, 4, 6, 7, 9,10,12,14,15,17,18,20,21,23,
71         24,25,27,28,30,31,32,34,35,36,38,39,40,41,42,44,
72         45,46,47,48,49,50,51,52,53,54,54,55,56,57,57,58,
73         59,59,60,60,61,61,62,62,62,63,63,63,63,63,63,63,
74         64,63,63,63,63,63,63,63,62,62,62,61,61,60,60,59,
75         59,58,57,57,56,55,54,54,53,52,51,50,49,48,47,46,
76         45,44,42,41,40,39,38,36,35,34,32,31,30,28,27,25,
77         24,23,21,20,18,17,15,14,12,10, 9, 7, 6, 4, 3, 1
78 };
79
80 /* Triton's linear periods to frequency translation table (for XM modules) */
81 static  const ULONG lintab[768]={
82         535232,534749,534266,533784,533303,532822,532341,531861,
83         531381,530902,530423,529944,529466,528988,528511,528034,
84         527558,527082,526607,526131,525657,525183,524709,524236,
85         523763,523290,522818,522346,521875,521404,520934,520464,
86         519994,519525,519057,518588,518121,517653,517186,516720,
87         516253,515788,515322,514858,514393,513929,513465,513002,
88         512539,512077,511615,511154,510692,510232,509771,509312,
89         508852,508393,507934,507476,507018,506561,506104,505647,
90         505191,504735,504280,503825,503371,502917,502463,502010,
91         501557,501104,500652,500201,499749,499298,498848,498398,
92         497948,497499,497050,496602,496154,495706,495259,494812,
93         494366,493920,493474,493029,492585,492140,491696,491253,
94         490809,490367,489924,489482,489041,488600,488159,487718,
95         487278,486839,486400,485961,485522,485084,484647,484210,
96         483773,483336,482900,482465,482029,481595,481160,480726,
97         480292,479859,479426,478994,478562,478130,477699,477268,
98         476837,476407,475977,475548,475119,474690,474262,473834,
99         473407,472979,472553,472126,471701,471275,470850,470425,
100         470001,469577,469153,468730,468307,467884,467462,467041,
101         466619,466198,465778,465358,464938,464518,464099,463681,
102         463262,462844,462427,462010,461593,461177,460760,460345,
103         459930,459515,459100,458686,458272,457859,457446,457033,
104         456621,456209,455797,455386,454975,454565,454155,453745,
105         453336,452927,452518,452110,451702,451294,450887,450481,
106         450074,449668,449262,448857,448452,448048,447644,447240,
107         446836,446433,446030,445628,445226,444824,444423,444022,
108         443622,443221,442821,442422,442023,441624,441226,440828,
109         440430,440033,439636,439239,438843,438447,438051,437656,
110         437261,436867,436473,436079,435686,435293,434900,434508,
111         434116,433724,433333,432942,432551,432161,431771,431382,
112         430992,430604,430215,429827,429439,429052,428665,428278,
113         427892,427506,427120,426735,426350,425965,425581,425197,
114         424813,424430,424047,423665,423283,422901,422519,422138,
115         421757,421377,420997,420617,420237,419858,419479,419101,
116         418723,418345,417968,417591,417214,416838,416462,416086,
117         415711,415336,414961,414586,414212,413839,413465,413092,
118         412720,412347,411975,411604,411232,410862,410491,410121,
119         409751,409381,409012,408643,408274,407906,407538,407170,
120         406803,406436,406069,405703,405337,404971,404606,404241,
121         403876,403512,403148,402784,402421,402058,401695,401333,
122         400970,400609,400247,399886,399525,399165,398805,398445,
123         398086,397727,397368,397009,396651,396293,395936,395579,
124         395222,394865,394509,394153,393798,393442,393087,392733,
125         392378,392024,391671,391317,390964,390612,390259,389907,
126         389556,389204,388853,388502,388152,387802,387452,387102,
127         386753,386404,386056,385707,385359,385012,384664,384317,
128         383971,383624,383278,382932,382587,382242,381897,381552,
129         381208,380864,380521,380177,379834,379492,379149,378807,
130         378466,378124,377783,377442,377102,376762,376422,376082,
131         375743,375404,375065,374727,374389,374051,373714,373377,
132         373040,372703,372367,372031,371695,371360,371025,370690,
133         370356,370022,369688,369355,369021,368688,368356,368023,
134         367691,367360,367028,366697,366366,366036,365706,365376,
135         365046,364717,364388,364059,363731,363403,363075,362747,
136         362420,362093,361766,361440,361114,360788,360463,360137,
137         359813,359488,359164,358840,358516,358193,357869,357547,
138         357224,356902,356580,356258,355937,355616,355295,354974,
139         354654,354334,354014,353695,353376,353057,352739,352420,
140         352103,351785,351468,351150,350834,350517,350201,349885,
141         349569,349254,348939,348624,348310,347995,347682,347368,
142         347055,346741,346429,346116,345804,345492,345180,344869,
143         344558,344247,343936,343626,343316,343006,342697,342388,
144         342079,341770,341462,341154,340846,340539,340231,339924,
145         339618,339311,339005,338700,338394,338089,337784,337479,
146         337175,336870,336566,336263,335959,335656,335354,335051,
147         334749,334447,334145,333844,333542,333242,332941,332641,
148         332341,332041,331741,331442,331143,330844,330546,330247,
149         329950,329652,329355,329057,328761,328464,328168,327872,
150         327576,327280,326985,326690,326395,326101,325807,325513,
151         325219,324926,324633,324340,324047,323755,323463,323171,
152         322879,322588,322297,322006,321716,321426,321136,320846,
153         320557,320267,319978,319690,319401,319113,318825,318538,
154         318250,317963,317676,317390,317103,316817,316532,316246,
155         315961,315676,315391,315106,314822,314538,314254,313971,
156         313688,313405,313122,312839,312557,312275,311994,311712,
157         311431,311150,310869,310589,310309,310029,309749,309470,
158         309190,308911,308633,308354,308076,307798,307521,307243,
159         306966,306689,306412,306136,305860,305584,305308,305033,
160         304758,304483,304208,303934,303659,303385,303112,302838,
161         302565,302292,302019,301747,301475,301203,300931,300660,
162         300388,300117,299847,299576,299306,299036,298766,298497,
163         298227,297958,297689,297421,297153,296884,296617,296349,
164         296082,295815,295548,295281,295015,294749,294483,294217,
165         293952,293686,293421,293157,292892,292628,292364,292100,
166         291837,291574,291311,291048,290785,290523,290261,289999,
167         289737,289476,289215,288954,288693,288433,288173,287913,
168         287653,287393,287134,286875,286616,286358,286099,285841,
169         285583,285326,285068,284811,284554,284298,284041,283785,
170         283529,283273,283017,282762,282507,282252,281998,281743,
171         281489,281235,280981,280728,280475,280222,279969,279716,
172         279464,279212,278960,278708,278457,278206,277955,277704,
173         277453,277203,276953,276703,276453,276204,275955,275706,
174         275457,275209,274960,274712,274465,274217,273970,273722,
175         273476,273229,272982,272736,272490,272244,271999,271753,
176         271508,271263,271018,270774,270530,270286,270042,269798,
177         269555,269312,269069,268826,268583,268341,268099,267857
178 };
179
180 #define LOGFAC 2*16
181 static  const UWORD logtab[104]={
182         LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,
183         LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862,
184         LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,
185         LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814,
186         LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,
187         LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768,
188         LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,
189         LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725,
190         LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,
191         LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684,
192         LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,
193         LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646,
194         LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,
195         LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610,
196         LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,
197         LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575,
198         LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,
199         LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543,
200         LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,
201         LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513,
202         LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,
203         LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484,
204         LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,
205         LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457,
206         LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,
207         LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431
208 };
209
210 static  const SBYTE PanbrelloTable[256]={
211           0,  2,  3,  5,  6,  8,  9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
212          24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
213          45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
214          59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
215          64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60,
216          59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,
217          45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26,
218          24, 23, 22, 20, 19, 17, 16, 14, 12, 11,  9,  8,  6,  5,  3,  2,
219           0,- 2,- 3,- 5,- 6,- 8,- 9,-11,-12,-14,-16,-17,-19,-20,-22,-23,
220         -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44,
221         -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59,
222         -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64,
223         -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60,
224         -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,
225         -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26,
226         -24,-23,-22,-20,-19,-17,-16,-14,-12,-11,- 9,- 8,- 6,- 5,- 3,- 2
227 };
228
229 /* returns a random value between 0 and ceil-1, ceil must be a power of two */
230 static int getrandom(int ceilval)
231 {
232 #if defined(HAVE_SRANDOM) && !defined(_MIKMOD_AMIGA)
233         return random()&(ceilval-1);
234 #else
235         return (rand()*ceilval)/(RAND_MAX+1.0);
236 #endif
237 }
238
239 /*      New Note Action Scoring System :
240         --------------------------------
241         1)      total-volume (fadevol, chanvol, volume) is the main scorer.
242         2)      a looping sample is a bonus x2
243         3)      a foreground channel is a bonus x4
244         4)      an active envelope with keyoff is a handicap -x2
245 */
246 static int MP_FindEmptyChannel(MODULE *mod)
247 {
248         MP_VOICE *a;
249         ULONG t,k,tvol,pp;
250
251         for (t=0;t<NUMVOICES(mod);t++)
252                 if (((mod->voice[t].main.kick==KICK_ABSENT)||
253                          (mod->voice[t].main.kick==KICK_ENV))&&
254                    Voice_Stopped_internal(t))
255                         return t;
256
257         tvol=0xffffffUL;t=-1;a=mod->voice;
258         for (k=0;k<NUMVOICES(mod);k++,a++) {
259                 /* allow us to take over a nonexisting sample */
260                 if (!a->main.s)
261                         return k;
262
263                 if ((a->main.kick==KICK_ABSENT)||(a->main.kick==KICK_ENV)) {
264                         pp=a->totalvol<<((a->main.s->flags&SF_LOOP)?1:0);
265                         if ((a->master)&&(a==a->master->slave))
266                                 pp<<=2;
267
268                         if (pp<tvol) {
269                                 tvol=pp;
270                                 t=k;
271                         }
272                 }
273         }
274
275         if (tvol>8000*7) return -1;
276         return t;
277 }
278
279 static SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2)
280 {
281         if ((p1==p2)||(p==p1)) return v1;
282         return v1+((SLONG)((p-p1)*(v2-v1))/(p2-p1));
283 }
284
285 UWORD getlinearperiod(UWORD note,ULONG fine)
286 {
287         UWORD t;
288
289         t=((20L+2*HIGH_OCTAVE)*OCTAVE+2-note)*32L-(fine>>1);
290         return t;
291 }
292
293 static UWORD getlogperiod(UWORD note,ULONG fine)
294 {
295         UWORD n,o;
296         UWORD p1,p2;
297         ULONG i;
298
299         n=note%(2*OCTAVE);
300         o=note/(2*OCTAVE);
301         i=(n<<2)+(fine>>4); /* n*8 + fine/16 */
302
303         p1=logtab[i];
304         p2=logtab[i+1];
305
306         return (Interpolate(fine>>4,0,15,p1,p2)>>o);
307 }
308
309 static UWORD getoldperiod(UWORD note,ULONG speed)
310 {
311         UWORD n,o;
312
313         /* This happens sometimes on badly converted AMF, and old MOD */
314         if (!speed) {
315 #ifdef MIKMOD_DEBUG
316                 fprintf(stderr,"\rmplayer: getoldperiod() called with note=%d, speed=0 !\n",note);
317 #endif
318                 return 4242; /* <- prevent divide overflow.. (42 hehe) */
319         }
320
321         n=note%(2*OCTAVE);
322         o=note/(2*OCTAVE);
323         return ((8363L*(ULONG)oldperiods[n])>>o)/speed;
324 }
325
326 static UWORD GetPeriod(UWORD flags, UWORD note, ULONG speed)
327 {
328         if (flags & UF_XMPERIODS) {
329                 if (flags & UF_LINEAR)
330                         return getlinearperiod(note, speed);
331                 else
332                         return getlogperiod(note, speed);
333         } else
334                 return getoldperiod(note, speed);
335 }
336
337 static SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b)
338 {
339         return (Interpolate(p,a->pos,b->pos,a->val,b->val));
340 }
341
342 static SWORD DoPan(SWORD envpan,SWORD pan)
343 {
344         int newpan;
345
346         newpan=pan+(((envpan-PAN_CENTER)*(128-abs(pan-PAN_CENTER)))/128);
347
348         return (newpan<PAN_LEFT)?PAN_LEFT:(newpan>PAN_RIGHT?PAN_RIGHT:newpan);
349 }
350
351 static SWORD StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE susbeg,UBYTE susend,UBYTE beg,UBYTE end,ENVPT *p,UBYTE keyoff)
352 {
353         t->flg=flg;
354         t->pts=pts;
355         t->susbeg=susbeg;
356         t->susend=susend;
357         t->beg=beg;
358         t->end=end;
359         t->env=p;
360         t->p=0;
361         t->a=0;
362         t->b=((t->flg&EF_SUSTAIN)&&(!(keyoff&KEY_OFF)))?0:1;
363
364         /* Imago Orpheus sometimes stores an extra initial point in the envelope */
365         if ((t->pts>=2)&&(t->env[0].pos==t->env[1].pos)) {
366                 t->a++;
367                 t->b++;
368         }
369
370         /* Fit in the envelope, still */
371         if (t->a >= t->pts)
372                 t->a = t->pts - 1;
373         if (t->b >= t->pts)
374                 t->b = t->pts-1;
375
376         return t->env[t->a].val;
377 }
378
379 /* This procedure processes all envelope types, include volume, pitch, and
380    panning.  Envelopes are defined by a set of points, each with a magnitude
381    [relating either to volume, panning position, or pitch modifier] and a tick
382    position.
383
384    Envelopes work in the following manner:
385
386    (a) Each tick the envelope is moved a point further in its progression. For
387        an accurate progression, magnitudes between two envelope points are
388        interpolated.
389
390    (b) When progression reaches a defined point on the envelope, values are
391        shifted to interpolate between this point and the next, and checks for
392        loops or envelope end are done.
393
394    Misc:
395      Sustain loops are loops that are only active as long as the keyoff flag is
396      clear.  When a volume envelope terminates, so does the current fadeout.
397 */
398 static SWORD ProcessEnvelope(MP_VOICE *aout, ENVPR *t, SWORD v)
399 {
400         if (t->flg & EF_ON) {
401                 UBYTE a, b;             /* actual points in the envelope */
402                 UWORD p;                /* the 'tick counter' - real point being played */
403
404                 a = t->a;
405                 b = t->b;
406                 p = t->p;
407
408                 /*
409                  * Sustain loop on one point (XM type).
410                  * Not processed if KEYOFF.
411                  * Don't move and don't interpolate when the point is reached
412                  */
413                 if ((t->flg & EF_SUSTAIN) && t->susbeg == t->susend &&
414                    (!(aout->main.keyoff & KEY_OFF) && p == t->env[t->susbeg].pos)) {
415                         v = t->env[t->susbeg].val;
416                 } else {
417                         /*
418                          * All following situations will require interpolation between
419                          * two envelope points.
420                          */
421
422                         /*
423                          * Sustain loop between two points (IT type).
424                          * Not processed if KEYOFF.
425                          */
426                         /* if we were on a loop point, loop now */
427                         if ((t->flg & EF_SUSTAIN) && !(aout->main.keyoff & KEY_OFF) &&
428                            a >= t->susend) {
429                                 a = t->susbeg;
430                                 b = (t->susbeg==t->susend)?a:a+1;
431                                 p = t->env[a].pos;
432                                 v = t->env[a].val;
433                         } else
434                         /*
435                          * Regular loop.
436                          * Be sure to correctly handle single point loops.
437                          */
438                         if ((t->flg & EF_LOOP) && a >= t->end) {
439                                 a = t->beg;
440                                 b = t->beg == t->end ? a : a + 1;
441                                 p = t->env[a].pos;
442                                 v = t->env[a].val;
443                         } else
444                         /*
445                          * Non looping situations.
446                          */
447                         if (a != b)
448                                 v = InterpolateEnv(p, &t->env[a], &t->env[b]);
449                         else
450                                 v = t->env[a].val;
451
452                         /*
453                          * Start to fade if the volume envelope is finished.
454                          */
455                         if (p >= t->env[t->pts - 1].pos) {
456                                 if (t->flg & EF_VOLENV) {
457                                         aout->main.keyoff |= KEY_FADE;
458                                         if (!v)
459                                                 aout->main.fadevol = 0;
460                                 }
461                         } else {
462                                 p++;
463                                 /* did pointer reach point b? */
464                                 if (p >= t->env[b].pos)
465                                         a = b++; /* shift points a and b */
466                         }
467                         t->a = a;
468                         t->b = b;
469                         t->p = p;
470                 }
471         }
472         return v;
473 }
474
475 /* XM linear period to frequency conversion */
476 ULONG getfrequency(UWORD flags,ULONG period)
477 {
478         if (flags & UF_LINEAR) {
479                 SLONG shift = ((SLONG)period / 768) - HIGH_OCTAVE;
480
481                 if (shift >= 0)
482                         return lintab[period % 768] >> shift;
483                 else
484                         return lintab[period % 768] << (-shift);
485         } else
486                 return (8363L*1712L)/(period?period:1);
487 }
488
489 /*========== Protracker effects */
490
491 static void DoArpeggio(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE style)
492 {
493         UBYTE note=a->main.note;
494
495         if (a->arpmem) {
496                 switch (style) {
497                 case 0:         /* mod style: N, N+x, N+y */
498                         switch (tick % 3) {
499                         /* case 0: unchanged */
500                         case 1:
501                                 note += (a->arpmem >> 4);
502                                 break;
503                         case 2:
504                                 note += (a->arpmem & 0xf);
505                                 break;
506                         }
507                         break;
508                 case 3:         /* okt arpeggio 3: N-x, N, N+y */
509                         switch (tick % 3) {
510                         case 0:
511                                 note -= (a->arpmem >> 4);
512                                 break;
513                         /* case 1: unchanged */
514                         case 2:
515                                 note += (a->arpmem & 0xf);
516                                 break;
517                         }
518                         break;
519                 case 4:         /* okt arpeggio 4: N, N+y, N, N-x */
520                         switch (tick % 4) {
521                         /* case 0, case 2: unchanged */
522                         case 1:
523                                 note += (a->arpmem & 0xf);
524                                 break;
525                         case 3:
526                                 note -= (a->arpmem >> 4);
527                                 break;
528                         }
529                         break;
530                 case 5:         /* okt arpeggio 5: N-x, N+y, N, and nothing at tick 0 */
531                         if (!tick)
532                                 break;
533                         switch (tick % 3) {
534                         /* case 0: unchanged */
535                         case 1:
536                                 note -= (a->arpmem >> 4);
537                                 break;
538                         case 2:
539                                 note += (a->arpmem & 0xf);
540                                 break;
541                         }
542                         break;
543                 }
544                 a->main.period = GetPeriod(flags, (UWORD)note << 1, a->speed);
545                 a->ownper = 1;
546         }
547 }
548
549 static int DoPTEffect0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
550 {
551         UBYTE dat;
552
553         dat = UniGetByte();
554         if (!tick) {
555                 if (!dat && (flags & UF_ARPMEM))
556                         dat=a->arpmem;
557                 else
558                         a->arpmem=dat;
559         }
560         if (a->main.period)
561                 DoArpeggio(tick, flags, a, 0);
562
563         return 0;
564 }
565
566 static int DoPTEffect1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
567 {
568         UBYTE dat;
569
570         dat = UniGetByte();
571         if (!tick && dat)
572                 a->slidespeed = (UWORD)dat << 2;
573         if (a->main.period)
574                 if (tick)
575                         a->tmpperiod -= a->slidespeed;
576
577         return 0;
578 }
579
580 static int DoPTEffect2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
581 {
582         UBYTE dat;
583
584         dat = UniGetByte();
585         if (!tick && dat)
586                 a->slidespeed = (UWORD)dat << 2;
587         if (a->main.period)
588                 if (tick)
589                         a->tmpperiod += a->slidespeed;
590
591         return 0;
592 }
593
594 static void DoToneSlide(UWORD tick, MP_CONTROL *a)
595 {
596         if (!a->main.fadevol)
597                 a->main.kick = (a->main.kick == KICK_NOTE)? KICK_NOTE : KICK_KEYOFF;
598         else
599                 a->main.kick = (a->main.kick == KICK_NOTE)? KICK_ENV : KICK_ABSENT;
600
601         if (tick != 0) {
602                 int dist;
603
604                 /* We have to slide a->main.period towards a->wantedperiod, so compute
605                    the difference between those two values */
606                 dist=a->main.period-a->wantedperiod;
607
608                 /* if they are equal or if portamentospeed is too big ...*/
609                 if (dist == 0 || a->portspeed > abs(dist))
610                         /* ...make tmpperiod equal tperiod */
611                         a->tmpperiod=a->main.period=a->wantedperiod;
612                 else if (dist>0) {
613                         a->tmpperiod-=a->portspeed;
614                         a->main.period-=a->portspeed; /* dist>0, slide up */
615                 } else {
616                         a->tmpperiod+=a->portspeed;
617                         a->main.period+=a->portspeed; /* dist<0, slide down */
618                 }
619         } else
620                 a->tmpperiod=a->main.period;
621         a->ownper = 1;
622 }
623
624 static int DoPTEffect3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
625 {
626         UBYTE dat;
627
628         dat=UniGetByte();
629         if ((!tick)&&(dat)) a->portspeed=(UWORD)dat<<2;
630         if (a->main.period)
631                 DoToneSlide(tick, a);
632
633         return 0;
634 }
635
636 static void DoVibrato(UWORD tick, MP_CONTROL *a)
637 {
638         UBYTE q;
639         UWORD temp = 0; /* silence warning */
640
641         if (!tick)
642                 return;
643
644         q=(a->vibpos>>2)&0x1f;
645
646         switch (a->wavecontrol&3) {
647         case 0: /* sine */
648                 temp=VibratoTable[q];
649                 break;
650         case 1: /* ramp down */
651                 q<<=3;
652                 if (a->vibpos<0) q=255-q;
653                 temp=q;
654                 break;
655         case 2: /* square wave */
656                 temp=255;
657                 break;
658         case 3: /* random wave */
659                 temp=getrandom(256);
660                 break;
661         }
662
663         temp*=a->vibdepth;
664         temp>>=7;temp<<=2;
665
666         if (a->vibpos>=0)
667                 a->main.period=a->tmpperiod+temp;
668         else
669                 a->main.period=a->tmpperiod-temp;
670         a->ownper = 1;
671
672         if (tick != 0)
673                 a->vibpos+=a->vibspd;
674 }
675
676 static int DoPTEffect4(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
677 {
678         UBYTE dat;
679
680         dat=UniGetByte();
681         if (!tick) {
682                 if (dat&0x0f) a->vibdepth=dat&0xf;
683                 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
684         }
685         if (a->main.period)
686                 DoVibrato(tick, a);
687
688         return 0;
689 }
690
691 static void DoVolSlide(MP_CONTROL *a, UBYTE dat)
692 {
693         if (dat&0xf) {
694                 a->tmpvolume-=(dat&0x0f);
695                 if (a->tmpvolume<0)
696                         a->tmpvolume=0;
697         } else {
698                 a->tmpvolume+=(dat>>4);
699                 if (a->tmpvolume>64)
700                         a->tmpvolume=64;
701         }
702 }
703
704 static int DoPTEffect5(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
705 {
706         UBYTE dat;
707
708         dat=UniGetByte();
709         if (a->main.period)
710                 DoToneSlide(tick, a);
711
712         if (tick)
713                 DoVolSlide(a, dat);
714
715         return 0;
716 }
717
718 /* DoPTEffect6 after DoPTEffectA */
719
720 static int DoPTEffect7(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
721 {
722         UBYTE dat;
723         UBYTE q;
724         UWORD temp = 0; /* silence warning */
725
726         dat=UniGetByte();
727         if (!tick) {
728                 if (dat&0x0f) a->trmdepth=dat&0xf;
729                 if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;
730         }
731         if (a->main.period) {
732                 q=(a->trmpos>>2)&0x1f;
733
734                 switch ((a->wavecontrol>>4)&3) {
735                 case 0: /* sine */
736                         temp=VibratoTable[q];
737                         break;
738                 case 1: /* ramp down */
739                         q<<=3;
740                         if (a->trmpos<0) q=255-q;
741                         temp=q;
742                         break;
743                 case 2: /* square wave */
744                         temp=255;
745                         break;
746                 case 3: /* random wave */
747                         temp=getrandom(256);
748                         break;
749                 }
750                 temp*=a->trmdepth;
751                 temp>>=6;
752
753                 if (a->trmpos>=0) {
754                         a->volume=a->tmpvolume+temp;
755                         if (a->volume>64) a->volume=64;
756                 } else {
757                         a->volume=a->tmpvolume-temp;
758                         if (a->volume<0) a->volume=0;
759                 }
760                 a->ownvol = 1;
761
762                 if (tick)
763                         a->trmpos+=a->trmspd;
764         }
765
766         return 0;
767 }
768
769 static int DoPTEffect8(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
770 {
771         UBYTE dat;
772
773         dat = UniGetByte();
774         if (mod->panflag)
775                 a->main.panning = mod->panning[channel] = dat;
776
777         return 0;
778 }
779
780 static int DoPTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
781 {
782         UBYTE dat;
783
784         dat=UniGetByte();
785         if (!tick) {
786                 if (dat) a->soffset=(UWORD)dat<<8;
787                 a->main.start=a->hioffset|a->soffset;
788
789                 if ((a->main.s)&&(a->main.start>a->main.s->length))
790                         a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
791                             a->main.s->loopstart:a->main.s->length;
792         }
793
794         return 0;
795 }
796
797 static int DoPTEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
798 {
799         UBYTE dat;
800
801         dat=UniGetByte();
802         if (tick)
803                 DoVolSlide(a, dat);
804
805         return 0;
806 }
807
808 static int DoPTEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
809 {
810         if (a->main.period)
811                 DoVibrato(tick, a);
812         DoPTEffectA(tick, flags, a, mod, channel);
813
814         return 0;
815 }
816
817 static int DoPTEffectB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
818 {
819         UBYTE dat;
820
821         dat=UniGetByte();
822
823         if (tick || mod->patdly2)
824                 return 0;
825
826         /* Vincent Voois uses a nasty trick in "Universal Bolero" */
827         if (dat == mod->sngpos && mod->patbrk == mod->patpos)
828                 return 0;
829
830         if (!mod->loop && !mod->patbrk &&
831             (dat < mod->sngpos ||
832                  (mod->sngpos == (mod->numpos - 1) && !mod->patbrk) ||
833              (dat == mod->sngpos && (flags & UF_NOWRAP)) ) )
834         {
835                 /* if we don't loop, better not to skip the end of the
836                    pattern, after all... so:
837                 mod->patbrk=0; */
838                 mod->posjmp=3;
839         } else {
840                 /* if we were fading, adjust... */
841                 if (mod->sngpos == (mod->numpos-1))
842                         mod->volume=mod->initvolume>128?128:mod->initvolume;
843                 mod->sngpos=dat;
844                 mod->posjmp=2;
845                 mod->patpos=0;
846                 /* cancel the FT2 pattern loop (E60) bug.
847                  * also see DoEEffects() below for it. */
848                 if (flags & UF_FT2QUIRKS) mod->patbrk=0;
849         }
850
851         return 0;
852 }
853
854 static int DoPTEffectC(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
855 {
856         UBYTE dat;
857
858         dat=UniGetByte();
859         if (tick) return 0;
860         if (dat==(UBYTE)-1) a->anote=dat=0; /* note cut */
861         else if (dat>64) dat=64;
862         a->tmpvolume=dat;
863
864         return 0;
865 }
866
867 static int DoPTEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
868 {
869         UBYTE dat;
870
871         dat=UniGetByte();
872         if ((tick)||(mod->patdly2)) return 0;
873         if ((mod->positions[mod->sngpos]!=LAST_PATTERN)&&
874             (dat>mod->pattrows[mod->positions[mod->sngpos]])) {
875                 dat=mod->pattrows[mod->positions[mod->sngpos]];
876         }
877         mod->patbrk=dat;
878         if (!mod->posjmp) {
879                 /* don't ask me to explain this code - it makes
880                    backwards.s3m and children.xm (heretic's version) play
881                    correctly, among others. Take that for granted, or write
882                    the page of comments yourself... you might need some
883                    aspirin - Miod */
884                 if ((mod->sngpos==mod->numpos-1)&&(dat)&&
885                     ((mod->loop) || (mod->positions[mod->sngpos]==(mod->numpat-1) && !(flags&UF_NOWRAP)))) {
886                         mod->sngpos=0;
887                         mod->posjmp=2;
888                 } else
889                         mod->posjmp=3;
890         }
891
892         return 0;
893 }
894
895 static void DoEEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod,
896         SWORD channel, UBYTE dat)
897 {
898         UBYTE nib = dat & 0xf;
899
900         switch (dat>>4) {
901         case 0x0: /* hardware filter toggle, not supported */
902                 break;
903         case 0x1: /* fineslide up */
904                 if (a->main.period)
905                         if (!tick)
906                                 a->tmpperiod-=(nib<<2);
907                 break;
908         case 0x2: /* fineslide dn */
909                 if (a->main.period)
910                         if (!tick)
911                                 a->tmpperiod+=(nib<<2);
912                 break;
913         case 0x3: /* glissando ctrl */
914                 a->glissando=nib;
915                 break;
916         case 0x4: /* set vibrato waveform */
917                 a->wavecontrol&=0xf0;
918                 a->wavecontrol|=nib;
919                 break;
920         case 0x5: /* set finetune */
921                 if (a->main.period) {
922                         if (flags&UF_XMPERIODS)
923                                 a->speed=nib+128;
924                         else
925                                 a->speed=finetune[nib];
926                         a->tmpperiod=GetPeriod(flags, (UWORD)a->main.note<<1,a->speed);
927                 }
928                 break;
929         case 0x6: /* set patternloop */
930                 if (tick)
931                         break;
932                 if (nib) { /* set reppos or repcnt ? */
933                         /* set repcnt, so check if repcnt already is set, which means we
934                            are already looping */
935                         if (a->pat_repcnt)
936                                 a->pat_repcnt--; /* already looping, decrease counter */
937                         else {
938 #if 0
939                                 /* this would make walker.xm, shipped with Xsoundtracker,
940                                    play correctly, but it's better to remain compatible
941                                    with FT2 */
942                                 if ((!(flags&UF_NOWRAP))||(a->pat_reppos!=POS_NONE))
943 #endif
944                                         a->pat_repcnt=nib; /* not yet looping, so set repcnt */
945                         }
946
947                         if (a->pat_repcnt) { /* jump to reppos if repcnt>0 */
948                                 if (a->pat_reppos==POS_NONE)
949                                         a->pat_reppos=mod->patpos-1;
950                                 if (a->pat_reppos==-1) {
951                                         mod->pat_repcrazy=1;
952                                         mod->patpos=0;
953                                 } else
954                                         mod->patpos=a->pat_reppos;
955                         } else a->pat_reppos=POS_NONE;
956                 } else {
957                         a->pat_reppos=mod->patpos-1; /* set reppos - can be (-1) */
958                         /* emulate the FT2 pattern loop (E60) bug:
959                          * http://milkytracker.org/docs/MilkyTracker.html#fxE6x
960                          * roadblas.xm plays correctly with this. */
961                         if (flags & UF_FT2QUIRKS) mod->patbrk=mod->patpos;
962                 }
963                 break;
964         case 0x7: /* set tremolo waveform */
965                 a->wavecontrol&=0x0f;
966                 a->wavecontrol|=nib<<4;
967                 break;
968         case 0x8: /* set panning */
969                 if (mod->panflag) {
970                         if (nib<=8) nib<<=4;
971                         else nib*=17;
972                         a->main.panning=mod->panning[channel]=nib;
973                 }
974                 break;
975         case 0x9: /* retrig note */
976                 /* do not retrigger on tick 0, until we are emulating FT2 and effect
977                    data is zero */
978                 if (!tick && !((flags & UF_FT2QUIRKS) && (!nib)))
979                         break;
980                 /* only retrigger if data nibble > 0, or if tick 0 (FT2 compat) */
981                 if (nib || !tick) {
982                         if (!a->retrig) {
983                                 /* when retrig counter reaches 0, reset counter and restart
984                                    the sample */
985                                 if (a->main.period) a->main.kick=KICK_NOTE;
986                                 a->retrig=nib;
987                         }
988                         a->retrig--; /* countdown */
989                 }
990                 break;
991         case 0xa: /* fine volume slide up */
992                 if (tick)
993                         break;
994                 a->tmpvolume+=nib;
995                 if (a->tmpvolume>64) a->tmpvolume=64;
996                 break;
997         case 0xb: /* fine volume slide dn  */
998                 if (tick)
999                         break;
1000                 a->tmpvolume-=nib;
1001                 if (a->tmpvolume<0)a->tmpvolume=0;
1002                 break;
1003         case 0xc: /* cut note */
1004                 /* When tick reaches the cut-note value, turn the volume to
1005                    zero (just like on the amiga) */
1006                 if (tick>=nib)
1007                         a->tmpvolume=0; /* just turn the volume down */
1008                 break;
1009         case 0xd: /* note delay */
1010                 /* delay the start of the sample until tick==nib */
1011                 if (!tick)
1012                         a->main.notedelay=nib;
1013                 else if (a->main.notedelay)
1014                         a->main.notedelay--;
1015                 break;
1016         case 0xe: /* pattern delay */
1017                 if (!tick)
1018                         if (!mod->patdly2)
1019                                 mod->patdly=nib+1; /* only once, when tick=0 */
1020                 break;
1021         case 0xf: /* invert loop, not supported  */
1022                 break;
1023         }
1024 }
1025
1026 static int DoPTEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1027 {
1028         DoEEffects(tick, flags, a, mod, channel, UniGetByte());
1029
1030         return 0;
1031 }
1032
1033 static int DoPTEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1034 {
1035         UBYTE dat;
1036
1037         dat=UniGetByte();
1038         if (tick||mod->patdly2) return 0;
1039         if (mod->extspd&&(dat>=mod->bpmlimit))
1040                 mod->bpm=dat;
1041         else
1042           if (dat) {
1043                 mod->sngspd=(dat>=mod->bpmlimit)?mod->bpmlimit-1:dat;
1044                 mod->vbtick=0;
1045         }
1046
1047         return 0;
1048 }
1049
1050 /*========== Scream Tracker effects */
1051
1052 static int DoS3MEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1053 {
1054         UBYTE speed;
1055
1056         speed = UniGetByte();
1057
1058         if (tick || mod->patdly2)
1059                 return 0;
1060
1061         if (speed > 128)
1062                 speed -= 128;
1063         if (speed) {
1064                 mod->sngspd = speed;
1065                 mod->vbtick = 0;
1066         }
1067
1068         return 0;
1069 }
1070
1071 static void DoS3MVolSlide(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE inf)
1072 {
1073         UBYTE lo, hi;
1074
1075         if (inf)
1076                 a->s3mvolslide=inf;
1077         else
1078                 inf=a->s3mvolslide;
1079
1080         lo=inf&0xf;
1081         hi=inf>>4;
1082
1083         if (!lo) {
1084                 if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume+=hi;
1085         } else
1086           if (!hi) {
1087                 if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume-=lo;
1088         } else
1089           if (lo==0xf) {
1090                 if (!tick) a->tmpvolume+=(hi?hi:0xf);
1091         } else
1092           if (hi==0xf) {
1093                 if (!tick) a->tmpvolume-=(lo?lo:0xf);
1094         } else
1095           return;
1096
1097         if (a->tmpvolume<0)
1098                 a->tmpvolume=0;
1099         else if (a->tmpvolume>64)
1100                 a->tmpvolume=64;
1101 }
1102
1103 static int DoS3MEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1104 {
1105         DoS3MVolSlide(tick, flags, a, UniGetByte());
1106
1107         return 1;
1108 }
1109
1110 static void DoS3MSlideDn(UWORD tick, MP_CONTROL *a, UBYTE inf)
1111 {
1112         UBYTE hi,lo;
1113
1114         if (inf)
1115                 a->slidespeed=inf;
1116         else
1117                 inf=a->slidespeed;
1118
1119         hi=inf>>4;
1120         lo=inf&0xf;
1121
1122         if (hi==0xf) {
1123                 if (!tick) a->tmpperiod+=(UWORD)lo<<2;
1124         } else
1125           if (hi==0xe) {
1126                 if (!tick) a->tmpperiod+=lo;
1127         } else {
1128                 if (tick) a->tmpperiod+=(UWORD)inf<<2;
1129         }
1130 }
1131
1132 static int DoS3MEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1133 {
1134         UBYTE dat;
1135
1136         dat=UniGetByte();
1137         if (a->main.period)
1138                 DoS3MSlideDn(tick, a,dat);
1139
1140         return 0;
1141 }
1142
1143 static void DoS3MSlideUp(UWORD tick, MP_CONTROL *a, UBYTE inf)
1144 {
1145         UBYTE hi,lo;
1146
1147         if (inf) a->slidespeed=inf;
1148         else inf=a->slidespeed;
1149
1150         hi=inf>>4;
1151         lo=inf&0xf;
1152
1153         if (hi==0xf) {
1154                 if (!tick) a->tmpperiod-=(UWORD)lo<<2;
1155         } else
1156           if (hi==0xe) {
1157                 if (!tick) a->tmpperiod-=lo;
1158         } else {
1159                 if (tick) a->tmpperiod-=(UWORD)inf<<2;
1160         }
1161 }
1162
1163 static int DoS3MEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1164 {
1165         UBYTE dat;
1166
1167         dat=UniGetByte();
1168         if (a->main.period)
1169                 DoS3MSlideUp(tick, a,dat);
1170
1171         return 0;
1172 }
1173
1174 static int DoS3MEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1175 {
1176         UBYTE inf, on, off;
1177
1178         inf = UniGetByte();
1179         if (inf)
1180                 a->s3mtronof = inf;
1181         else {
1182                 inf = a->s3mtronof;
1183                 if (!inf)
1184                         return 0;
1185         }
1186
1187         if (!tick)
1188                 return 0;
1189
1190         on=(inf>>4)+1;
1191         off=(inf&0xf)+1;
1192         a->s3mtremor%=(on+off);
1193         a->volume=(a->s3mtremor<on)?a->tmpvolume:0;
1194         a->ownvol=1;
1195         a->s3mtremor++;
1196
1197         return 0;
1198 }
1199
1200 static int DoS3MEffectQ(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1201 {
1202         UBYTE inf;
1203
1204         inf = UniGetByte();
1205         if (a->main.period) {
1206                 if (inf) {
1207                         a->s3mrtgslide=inf>>4;
1208                         a->s3mrtgspeed=inf&0xf;
1209                 }
1210
1211                 /* only retrigger if low nibble > 0 */
1212                 if (a->s3mrtgspeed>0) {
1213                         if (!a->retrig) {
1214                                 /* when retrig counter reaches 0, reset counter and restart the
1215                                    sample */
1216                                 if (a->main.kick!=KICK_NOTE) a->main.kick=KICK_KEYOFF;
1217                                 a->retrig=a->s3mrtgspeed;
1218
1219                                 if ((tick)||(flags&UF_S3MSLIDES)) {
1220                                         switch (a->s3mrtgslide) {
1221                                         case 1:
1222                                         case 2:
1223                                         case 3:
1224                                         case 4:
1225                                         case 5:
1226                                                 a->tmpvolume-=(1<<(a->s3mrtgslide-1));
1227                                                 break;
1228                                         case 6:
1229                                                 a->tmpvolume=(2*a->tmpvolume)/3;
1230                                                 break;
1231                                         case 7:
1232                                                 a->tmpvolume>>=1;
1233                                                 break;
1234                                         case 9:
1235                                         case 0xa:
1236                                         case 0xb:
1237                                         case 0xc:
1238                                         case 0xd:
1239                                                 a->tmpvolume+=(1<<(a->s3mrtgslide-9));
1240                                                 break;
1241                                         case 0xe:
1242                                                 a->tmpvolume=(3*a->tmpvolume)>>1;
1243                                                 break;
1244                                         case 0xf:
1245                                                 a->tmpvolume=a->tmpvolume<<1;
1246                                                 break;
1247                                         }
1248                                         if (a->tmpvolume<0)
1249                                                 a->tmpvolume=0;
1250                                         else if (a->tmpvolume>64)
1251                                                 a->tmpvolume=64;
1252                                 }
1253                         }
1254                         a->retrig--; /* countdown  */
1255                 }
1256         }
1257
1258         return 0;
1259 }
1260
1261 static int DoS3MEffectR(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1262 {
1263         UBYTE dat, q;
1264         UWORD temp=0;   /* silence warning */
1265
1266         dat = UniGetByte();
1267         if (!tick) {
1268                 if (dat&0x0f) a->trmdepth=dat&0xf;
1269                 if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;
1270         }
1271
1272         q=(a->trmpos>>2)&0x1f;
1273
1274         switch ((a->wavecontrol>>4)&3) {
1275         case 0: /* sine */
1276                 temp=VibratoTable[q];
1277                 break;
1278         case 1: /* ramp down */
1279                 q<<=3;
1280                 if (a->trmpos<0) q=255-q;
1281                 temp=q;
1282                 break;
1283         case 2: /* square wave */
1284                 temp=255;
1285                 break;
1286         case 3: /* random */
1287                 temp=getrandom(256);
1288                 break;
1289         }
1290
1291         temp*=a->trmdepth;
1292         temp>>=7;
1293
1294         if (a->trmpos>=0) {
1295                 a->volume=a->tmpvolume+temp;
1296                 if (a->volume>64) a->volume=64;
1297         } else {
1298                 a->volume=a->tmpvolume-temp;
1299                 if (a->volume<0) a->volume=0;
1300         }
1301         a->ownvol = 1;
1302
1303         if (tick)
1304                 a->trmpos+=a->trmspd;
1305
1306         return 0;
1307 }
1308
1309 static int DoS3MEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1310 {
1311         UBYTE tempo;
1312
1313         tempo = UniGetByte();
1314
1315         if (tick || mod->patdly2)
1316                 return 0;
1317
1318         mod->bpm = (tempo < 32) ? 32 : tempo;
1319
1320         return 0;
1321 }
1322
1323 static int DoS3MEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1324 {
1325         UBYTE dat, q;
1326         UWORD temp = 0; /* silence warning */
1327
1328         dat = UniGetByte();
1329         if (!tick) {
1330                 if (dat&0x0f) a->vibdepth=dat&0xf;
1331                 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
1332         } else
1333                 if (a->main.period) {
1334                         q=(a->vibpos>>2)&0x1f;
1335
1336                         switch (a->wavecontrol&3) {
1337                         case 0: /* sine */
1338                                 temp=VibratoTable[q];
1339                                 break;
1340                         case 1: /* ramp down */
1341                                 q<<=3;
1342                                 if (a->vibpos<0) q=255-q;
1343                                 temp=q;
1344                                 break;
1345                         case 2: /* square wave */
1346                                 temp=255;
1347                                 break;
1348                         case 3: /* random */
1349                                 temp=getrandom(256);
1350                                 break;
1351                         }
1352
1353                         temp*=a->vibdepth;
1354                         temp>>=8;
1355
1356                         if (a->vibpos>=0)
1357                                 a->main.period=a->tmpperiod+temp;
1358                         else
1359                                 a->main.period=a->tmpperiod-temp;
1360                         a->ownper = 1;
1361
1362                         a->vibpos+=a->vibspd;
1363         }
1364
1365         return 0;
1366 }
1367
1368 /*========== Envelope helpers */
1369
1370 static int DoKeyOff(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1371 {
1372         a->main.keyoff|=KEY_OFF;
1373         if ((!(a->main.volflg&EF_ON))||(a->main.volflg&EF_LOOP))
1374                 a->main.keyoff=KEY_KILL;
1375
1376         return 0;
1377 }
1378
1379 static int DoKeyFade(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1380 {
1381         UBYTE dat;
1382
1383         dat=UniGetByte();
1384         if ((tick>=dat)||(tick==mod->sngspd-1)) {
1385                 a->main.keyoff=KEY_KILL;
1386                 if (!(a->main.volflg&EF_ON))
1387                         a->main.fadevol=0;
1388         }
1389
1390         return 0;
1391 }
1392
1393 /*========== Fast Tracker effects */
1394
1395 /* DoXMEffect6 after DoXMEffectA */
1396
1397 static int DoXMEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1398 {
1399         UBYTE inf, lo, hi;
1400
1401         inf = UniGetByte();
1402         if (inf)
1403                 a->s3mvolslide = inf;
1404         else
1405                 inf = a->s3mvolslide;
1406
1407         if (tick) {
1408                 lo=inf&0xf;
1409                 hi=inf>>4;
1410
1411                 if (!hi) {
1412                         a->tmpvolume-=lo;
1413                         if (a->tmpvolume<0) a->tmpvolume=0;
1414                 } else {
1415                         a->tmpvolume+=hi;
1416                         if (a->tmpvolume>64) a->tmpvolume=64;
1417                 }
1418         }
1419
1420         return 0;
1421 }
1422
1423 static int DoXMEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1424 {
1425         if (a->main.period)
1426                 DoVibrato(tick, a);
1427
1428         return DoXMEffectA(tick, flags, a, mod, channel);
1429 }
1430
1431 static int DoXMEffectE1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1432 {
1433         UBYTE dat;
1434
1435         dat=UniGetByte();
1436         if (!tick) {
1437                 if (dat) a->fportupspd=dat;
1438                 if (a->main.period)
1439                         a->tmpperiod-=(a->fportupspd<<2);
1440         }
1441
1442         return 0;
1443 }
1444
1445 static int DoXMEffectE2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1446 {
1447         UBYTE dat;
1448
1449         dat=UniGetByte();
1450         if (!tick) {
1451                 if (dat) a->fportdnspd=dat;
1452                 if (a->main.period)
1453                         a->tmpperiod+=(a->fportdnspd<<2);
1454         }
1455
1456         return 0;
1457 }
1458
1459 static int DoXMEffectEA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1460 {
1461         UBYTE dat;
1462
1463         dat=UniGetByte();
1464         if (!tick)
1465                 if (dat) a->fslideupspd=dat;
1466         a->tmpvolume+=a->fslideupspd;
1467         if (a->tmpvolume>64) a->tmpvolume=64;
1468
1469         return 0;
1470 }
1471
1472 static int DoXMEffectEB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1473 {
1474         UBYTE dat;
1475
1476         dat=UniGetByte();
1477         if (!tick)
1478                 if (dat) a->fslidednspd=dat;
1479         a->tmpvolume-=a->fslidednspd;
1480         if (a->tmpvolume<0) a->tmpvolume=0;
1481
1482         return 0;
1483 }
1484
1485 static int DoXMEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1486 {
1487         mod->volume=UniGetByte()<<1;
1488         if (mod->volume>128) mod->volume=128;
1489
1490         return 0;
1491 }
1492
1493 static int DoXMEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1494 {
1495         UBYTE inf;
1496
1497         inf = UniGetByte();
1498
1499         if (tick) {
1500                 if (inf) mod->globalslide=inf;
1501                 else inf=mod->globalslide;
1502                 if (inf & 0xf0) inf&=0xf0;
1503                 mod->volume=mod->volume+((inf>>4)-(inf&0xf))*2;
1504
1505                 if (mod->volume<0)
1506                         mod->volume=0;
1507                 else if (mod->volume>128)
1508                         mod->volume=128;
1509         }
1510
1511         return 0;
1512 }
1513
1514 static int DoXMEffectL(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1515 {
1516         UBYTE dat;
1517
1518         dat=UniGetByte();
1519         if ((!tick)&&(a->main.i)) {
1520                 UWORD points;
1521                 INSTRUMENT *i=a->main.i;
1522                 MP_VOICE *aout;
1523
1524                 if ((aout=a->slave) != NULL) {
1525                         if (aout->venv.env) {
1526                                 points=i->volenv[i->volpts-1].pos;
1527                                 aout->venv.p=aout->venv.env[(dat>points)?points:dat].pos;
1528                         }
1529                         if (aout->penv.env) {
1530                                 points=i->panenv[i->panpts-1].pos;
1531                                 aout->penv.p=aout->penv.env[(dat>points)?points:dat].pos;
1532                         }
1533                 }
1534         }
1535
1536         return 0;
1537 }
1538
1539 static int DoXMEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1540 {
1541         UBYTE inf, lo, hi;
1542         SWORD pan;
1543
1544         inf = UniGetByte();
1545         if (!mod->panflag)
1546                 return 0;
1547
1548         if (inf)
1549                 a->pansspd = inf;
1550         else
1551                 inf =a->pansspd;
1552
1553         if (tick) {
1554                 lo=inf&0xf;
1555                 hi=inf>>4;
1556
1557                 /* slide right has absolute priority */
1558                 if (hi)
1559                         lo = 0;
1560
1561                 pan=((a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning)+hi-lo;
1562                 a->main.panning=(pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);
1563         }
1564
1565         return 0;
1566 }
1567
1568 static int DoXMEffectX1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1569 {
1570         UBYTE dat;
1571
1572         dat = UniGetByte();
1573         if (dat)
1574                 a->ffportupspd = dat;
1575         else
1576                 dat = a->ffportupspd;
1577
1578         if (a->main.period)
1579                 if (!tick) {
1580                         a->main.period-=dat;
1581                         a->tmpperiod-=dat;
1582                         a->ownper = 1;
1583                 }
1584
1585         return 0;
1586 }
1587
1588 static int DoXMEffectX2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1589 {
1590         UBYTE dat;
1591
1592         dat = UniGetByte();
1593         if (dat)
1594                 a->ffportdnspd=dat;
1595         else
1596                 dat = a->ffportdnspd;
1597
1598         if (a->main.period)
1599                 if (!tick) {
1600                         a->main.period+=dat;
1601                         a->tmpperiod+=dat;
1602                         a->ownper = 1;
1603                 }
1604
1605         return 0;
1606 }
1607
1608 /*========== Impulse Tracker effects */
1609
1610 static void DoITToneSlide(UWORD tick, MP_CONTROL *a, UBYTE dat)
1611 {
1612         if (dat)
1613                 a->portspeed = dat;
1614
1615         /* if we don't come from another note, ignore the slide and play the note
1616            as is */
1617         if (!a->oldnote || !a->main.period)
1618                 return;
1619
1620         if ((!tick)&&(a->newsamp)){
1621                 a->main.kick=KICK_NOTE;
1622                 a->main.start=-1;
1623         } else
1624                 a->main.kick=(a->main.kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT;
1625
1626         if (tick) {
1627                 int dist;
1628
1629                 /* We have to slide a->main.period towards a->wantedperiod, compute the
1630                    difference between those two values */
1631                 dist=a->main.period-a->wantedperiod;
1632
1633                 /* if they are equal or if portamentospeed is too big... */
1634                 if ((!dist)||((a->portspeed<<2)>abs(dist)))
1635                         /* ... make tmpperiod equal tperiod */
1636                         a->tmpperiod=a->main.period=a->wantedperiod;
1637                 else
1638                   if (dist>0) {
1639                         a->tmpperiod-=a->portspeed<<2;
1640                         a->main.period-=a->portspeed<<2; /* dist>0 slide up */
1641                 } else {
1642                         a->tmpperiod+=a->portspeed<<2;
1643                         a->main.period+=a->portspeed<<2; /* dist<0 slide down */
1644                 }
1645         } else
1646                 a->tmpperiod=a->main.period;
1647         a->ownper=1;
1648 }
1649
1650 static int DoITEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1651 {
1652         DoITToneSlide(tick, a, UniGetByte());
1653
1654         return 0;
1655 }
1656
1657 static void DoITVibrato(UWORD tick, MP_CONTROL *a, UBYTE dat)
1658 {
1659         UBYTE q;
1660         UWORD temp=0;
1661
1662         if (!tick) {
1663                 if (dat&0x0f) a->vibdepth=dat&0xf;
1664                 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
1665         }
1666         if (!a->main.period)
1667                 return;
1668
1669         q=(a->vibpos>>2)&0x1f;
1670
1671         switch (a->wavecontrol&3) {
1672         case 0: /* sine */
1673                 temp=VibratoTable[q];
1674                 break;
1675         case 1: /* square wave */
1676                 temp=255;
1677                 break;
1678         case 2: /* ramp down */
1679                 q<<=3;
1680                 if (a->vibpos<0) q=255-q;
1681                 temp=q;
1682                 break;
1683         case 3: /* random */
1684                 temp=getrandom(256);
1685                 break;
1686         }
1687
1688         temp*=a->vibdepth;
1689         temp>>=8;
1690         temp<<=2;
1691
1692         if (a->vibpos>=0)
1693                 a->main.period=a->tmpperiod+temp;
1694         else
1695                 a->main.period=a->tmpperiod-temp;
1696         a->ownper=1;
1697
1698         a->vibpos+=a->vibspd;
1699 }
1700
1701 static int DoITEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1702 {
1703         DoITVibrato(tick, a, UniGetByte());
1704
1705         return 0;
1706 }
1707
1708 static int DoITEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1709 {
1710         UBYTE inf, on, off;
1711
1712         inf = UniGetByte();
1713         if (inf)
1714                 a->s3mtronof = inf;
1715         else {
1716                 inf = a->s3mtronof;
1717                 if (!inf)
1718                         return 0;
1719         }
1720
1721         on=(inf>>4);
1722         off=(inf&0xf);
1723
1724         a->s3mtremor%=(on+off);
1725         a->volume=(a->s3mtremor<on)?a->tmpvolume:0;
1726         a->ownvol = 1;
1727         a->s3mtremor++;
1728
1729         return 0;
1730 }
1731
1732 static int DoITEffectM(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1733 {
1734         a->main.chanvol=UniGetByte();
1735         if (a->main.chanvol>64)
1736                 a->main.chanvol=64;
1737         else if (a->main.chanvol<0)
1738                 a->main.chanvol=0;
1739
1740         return 0;
1741 }
1742
1743 static int DoITEffectN(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1744 {
1745         UBYTE inf, lo, hi;
1746
1747         inf = UniGetByte();
1748
1749         if (inf)
1750                 a->chanvolslide = inf;
1751         else
1752                 inf = a->chanvolslide;
1753
1754         lo=inf&0xf;
1755         hi=inf>>4;
1756
1757         if (!hi)
1758                 a->main.chanvol-=lo;
1759         else
1760           if (!lo) {
1761                 a->main.chanvol+=hi;
1762         } else
1763           if (hi==0xf) {
1764                 if (!tick) a->main.chanvol-=lo;
1765         } else
1766           if (lo==0xf) {
1767                 if (!tick) a->main.chanvol+=hi;
1768         }
1769
1770         if (a->main.chanvol<0)
1771                 a->main.chanvol=0;
1772         else if (a->main.chanvol>64)
1773                 a->main.chanvol=64;
1774
1775         return 0;
1776 }
1777
1778 static int DoITEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1779 {
1780         UBYTE inf, lo, hi;
1781         SWORD pan;
1782
1783         inf = UniGetByte();
1784         if (inf)
1785                 a->pansspd = inf;
1786         else
1787                 inf = a->pansspd;
1788
1789         if (!mod->panflag)
1790                 return 0;
1791
1792         lo=inf&0xf;
1793         hi=inf>>4;
1794
1795         pan=(a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning;
1796
1797         if (!hi)
1798                 pan+=lo<<2;
1799         else
1800           if (!lo) {
1801                 pan-=hi<<2;
1802         } else
1803           if (hi==0xf) {
1804                 if (!tick) pan+=lo<<2;
1805         } else
1806           if (lo==0xf) {
1807                 if (!tick) pan-=hi<<2;
1808         }
1809         a->main.panning=
1810           (pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);
1811
1812         return 0;
1813 }
1814
1815 static int DoITEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1816 {
1817         UBYTE tempo;
1818         SWORD temp;
1819
1820         tempo = UniGetByte();
1821
1822         if (mod->patdly2)
1823                 return 0;
1824
1825         temp = mod->bpm;
1826         if (tempo & 0x10)
1827                 temp += (tempo & 0x0f);
1828         else
1829                 temp -= tempo;
1830
1831         mod->bpm=(temp>255)?255:(temp<1?1:temp);
1832
1833         return 0;
1834 }
1835
1836 static int DoITEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1837 {
1838         UBYTE dat, q;
1839         UWORD temp = 0; /* silence warning */
1840
1841         dat = UniGetByte();
1842         if (!tick) {
1843                 if (dat&0x0f) a->vibdepth=dat&0xf;
1844                 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
1845         }
1846         if (a->main.period) {
1847                 q=(a->vibpos>>2)&0x1f;
1848
1849                 switch (a->wavecontrol&3) {
1850                 case 0: /* sine */
1851                         temp=VibratoTable[q];
1852                         break;
1853                 case 1: /* square wave */
1854                         temp=255;
1855                         break;
1856                 case 2: /* ramp down */
1857                         q<<=3;
1858                         if (a->vibpos<0) q=255-q;
1859                         temp=q;
1860                         break;
1861                 case 3: /* random */
1862                         temp=getrandom(256);
1863                         break;
1864                 }
1865
1866                 temp*=a->vibdepth;
1867                 temp>>=8;
1868
1869                 if (a->vibpos>=0)
1870                         a->main.period=a->tmpperiod+temp;
1871                 else
1872                         a->main.period=a->tmpperiod-temp;
1873                 a->ownper = 1;
1874
1875                 a->vibpos+=a->vibspd;
1876         }
1877
1878         return 0;
1879 }
1880
1881 static int DoITEffectW(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1882 {
1883         UBYTE inf, lo, hi;
1884
1885         inf = UniGetByte();
1886
1887         if (inf)
1888                 mod->globalslide = inf;
1889         else
1890                 inf = mod->globalslide;
1891
1892         lo=inf&0xf;
1893         hi=inf>>4;
1894
1895         if (!lo) {
1896                 if (tick) mod->volume+=hi;
1897         } else
1898           if (!hi) {
1899                 if (tick) mod->volume-=lo;
1900         } else
1901           if (lo==0xf) {
1902                 if (!tick) mod->volume+=hi;
1903         } else
1904           if (hi==0xf) {
1905                 if (!tick) mod->volume-=lo;
1906         }
1907
1908         if (mod->volume<0)
1909                 mod->volume=0;
1910         else if (mod->volume>128)
1911                 mod->volume=128;
1912
1913         return 0;
1914 }
1915
1916 static int DoITEffectY(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1917 {
1918         UBYTE dat, q;
1919         SLONG temp = 0; /* silence warning */
1920
1921
1922         dat=UniGetByte();
1923         if (!tick) {
1924                 if (dat&0x0f) a->panbdepth=(dat&0xf);
1925                 if (dat&0xf0) a->panbspd=(dat&0xf0)>>4;
1926         }
1927         if (mod->panflag) {
1928                 q=a->panbpos;
1929
1930                 switch (a->panbwave) {
1931                 case 0: /* sine */
1932                         temp=PanbrelloTable[q];
1933                         break;
1934                 case 1: /* square wave */
1935                         temp=(q<0x80)?64:0;
1936                         break;
1937                 case 2: /* ramp down */
1938                         q<<=3;
1939                         temp=q;
1940                         break;
1941                 case 3: /* random */
1942                         temp=getrandom(256);
1943                         break;
1944                 }
1945
1946                 temp*=a->panbdepth;
1947                 temp=(temp/8)+mod->panning[channel];
1948
1949                 a->main.panning=
1950                         (temp<PAN_LEFT)?PAN_LEFT:(temp>PAN_RIGHT?PAN_RIGHT:temp);
1951                 a->panbpos+=a->panbspd;
1952
1953         }
1954
1955         return 0;
1956 }
1957
1958 static void DoNNAEffects(MODULE *, MP_CONTROL *, UBYTE);
1959
1960 /* Impulse/Scream Tracker Sxx effects.
1961    All Sxx effects share the same memory space. */
1962 static int DoITEffectS0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1963 {
1964         UBYTE dat, inf, c;
1965
1966         dat = UniGetByte();
1967         inf=dat&0xf;
1968         c=dat>>4;
1969
1970         if (!dat) {
1971                 c=a->sseffect;
1972                 inf=a->ssdata;
1973         } else {
1974                 a->sseffect=c;
1975                 a->ssdata=inf;
1976         }
1977
1978         switch (c) {
1979         case SS_GLISSANDO: /* S1x set glissando voice */
1980                 DoEEffects(tick, flags, a, mod, channel, 0x30|inf);
1981                 break;
1982         case SS_FINETUNE: /* S2x set finetune */
1983                 DoEEffects(tick, flags, a, mod, channel, 0x50|inf);
1984                 break;
1985         case SS_VIBWAVE: /* S3x set vibrato waveform */
1986                 DoEEffects(tick, flags, a, mod, channel, 0x40|inf);
1987                 break;
1988         case SS_TREMWAVE: /* S4x set tremolo waveform */
1989                 DoEEffects(tick, flags, a, mod, channel, 0x70|inf);
1990                 break;
1991         case SS_PANWAVE: /* S5x panbrello */
1992                 a->panbwave=inf;
1993                 break;
1994         case SS_FRAMEDELAY: /* S6x delay x number of frames (patdly) */
1995                 DoEEffects(tick, flags, a, mod, channel, 0xe0|inf);
1996                 break;
1997         case SS_S7EFFECTS: /* S7x instrument / NNA commands */
1998                 DoNNAEffects(mod, a, inf);
1999                 break;
2000         case SS_PANNING: /* S8x set panning position */
2001                 DoEEffects(tick, flags, a, mod, channel, 0x80 | inf);
2002                 break;
2003         case SS_SURROUND: /* S9x set surround sound */
2004                 if (mod->panflag)
2005                         a->main.panning = mod->panning[channel] = PAN_SURROUND;
2006                 break;
2007         case SS_HIOFFSET: /* SAy set high order sample offset yxx00h */
2008                 if (!tick) {
2009                         a->hioffset=inf<<16;
2010                         a->main.start=a->hioffset|a->soffset;
2011
2012                         if ((a->main.s)&&(a->main.start>a->main.s->length))
2013                                 a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
2014                                     a->main.s->loopstart:a->main.s->length;
2015                 }
2016                 break;
2017         case SS_PATLOOP: /* SBx pattern loop */
2018                 DoEEffects(tick, flags, a, mod, channel, 0x60|inf);
2019                 break;
2020         case SS_NOTECUT: /* SCx notecut */
2021                 if (!inf) inf = 1;
2022                 DoEEffects(tick, flags, a, mod, channel, 0xC0|inf);
2023                 break;
2024         case SS_NOTEDELAY: /* SDx notedelay */
2025                 DoEEffects(tick, flags, a, mod, channel, 0xD0|inf);
2026                 break;
2027         case SS_PATDELAY: /* SEx patterndelay */
2028                 DoEEffects(tick, flags, a, mod, channel, 0xE0|inf);
2029                 break;
2030         }
2031
2032         return 0;
2033 }
2034
2035 /*========== Impulse Tracker Volume/Pan Column effects */
2036
2037 /*
2038  * All volume/pan column effects share the same memory space.
2039  */
2040
2041 static int DoVolEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2042 {
2043         UBYTE c, inf;
2044
2045         c = UniGetByte();
2046         inf = UniGetByte();
2047
2048         if ((!c)&&(!inf)) {
2049                 c=a->voleffect;
2050                 inf=a->voldata;
2051         } else {
2052                 a->voleffect=c;
2053                 a->voldata=inf;
2054         }
2055
2056         if (c)
2057                 switch (c) {
2058                 case VOL_VOLUME:
2059                         if (tick) break;
2060                         if (inf>64) inf=64;
2061                         a->tmpvolume=inf;
2062                         break;
2063                 case VOL_PANNING:
2064                         if (mod->panflag)
2065                                 a->main.panning=inf;
2066                         break;
2067                 case VOL_VOLSLIDE:
2068                         DoS3MVolSlide(tick, flags, a, inf);
2069                         return 1;
2070                 case VOL_PITCHSLIDEDN:
2071                         if (a->main.period)
2072                                 DoS3MSlideDn(tick, a, inf);
2073                         break;
2074                 case VOL_PITCHSLIDEUP:
2075                         if (a->main.period)
2076                                 DoS3MSlideUp(tick, a, inf);
2077                         break;
2078                 case VOL_PORTAMENTO:
2079                         DoITToneSlide(tick, a, inf);
2080                         break;
2081                 case VOL_VIBRATO:
2082                         DoITVibrato(tick, a, inf);
2083                         break;
2084         }
2085
2086         return 0;
2087 }
2088
2089 /*========== UltraTracker effects */
2090
2091 static int DoULTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2092 {
2093         UWORD offset=UniGetWord();
2094
2095         if (offset)
2096                 a->ultoffset=offset;
2097
2098         a->main.start=a->ultoffset<<2;
2099         if ((a->main.s)&&(a->main.start>a->main.s->length))
2100                 a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
2101                     a->main.s->loopstart:a->main.s->length;
2102
2103         return 0;
2104 }
2105
2106 /*========== OctaMED effects */
2107
2108 static int DoMEDSpeed(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2109 {
2110         UWORD speed=UniGetWord();
2111
2112         mod->bpm=speed;
2113
2114         return 0;
2115 }
2116
2117 static int DoMEDEffectF1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2118 {
2119         DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/2));
2120
2121         return 0;
2122 }
2123
2124 static int DoMEDEffectF2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2125 {
2126         DoEEffects(tick, flags, a, mod, channel, 0xd0|(mod->sngspd/2));
2127
2128         return 0;
2129 }
2130
2131 static int DoMEDEffectF3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2132 {
2133         DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/3));
2134
2135         return 0;
2136 }
2137
2138 /*========== Oktalyzer effects */
2139
2140 static int DoOktArp(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2141 {
2142         UBYTE dat, dat2;
2143
2144         dat2 = UniGetByte();    /* arpeggio style */
2145         dat = UniGetByte();
2146         if (!tick) {
2147                 if (!dat && (flags & UF_ARPMEM))
2148                         dat=a->arpmem;
2149                 else
2150                         a->arpmem=dat;
2151         }
2152         if (a->main.period)
2153                 DoArpeggio(tick, flags, a, dat2);
2154
2155         return 0;
2156 }
2157
2158 /*========== General player functions */
2159
2160 static int DoNothing(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2161 {
2162         UniSkipOpcode();
2163
2164         return 0;
2165 }
2166
2167 typedef int (*effect_func) (UWORD, UWORD, MP_CONTROL *, MODULE *, SWORD);
2168
2169 static effect_func effects[UNI_LAST] = {
2170         DoNothing,              /* 0 */
2171         DoNothing,              /* UNI_NOTE */
2172         DoNothing,              /* UNI_INSTRUMENT */
2173         DoPTEffect0,    /* UNI_PTEFFECT0 */
2174         DoPTEffect1,    /* UNI_PTEFFECT1 */
2175         DoPTEffect2,    /* UNI_PTEFFECT2 */
2176         DoPTEffect3,    /* UNI_PTEFFECT3 */
2177         DoPTEffect4,    /* UNI_PTEFFECT4 */
2178         DoPTEffect5,    /* UNI_PTEFFECT5 */
2179         DoPTEffect6,    /* UNI_PTEFFECT6 */
2180         DoPTEffect7,    /* UNI_PTEFFECT7 */
2181         DoPTEffect8,    /* UNI_PTEFFECT8 */
2182         DoPTEffect9,    /* UNI_PTEFFECT9 */
2183         DoPTEffectA,    /* UNI_PTEFFECTA */
2184         DoPTEffectB,    /* UNI_PTEFFECTB */
2185         DoPTEffectC,    /* UNI_PTEFFECTC */
2186         DoPTEffectD,    /* UNI_PTEFFECTD */
2187         DoPTEffectE,    /* UNI_PTEFFECTE */
2188         DoPTEffectF,    /* UNI_PTEFFECTF */
2189         DoS3MEffectA,   /* UNI_S3MEFFECTA */
2190         DoS3MEffectD,   /* UNI_S3MEFFECTD */
2191         DoS3MEffectE,   /* UNI_S3MEFFECTE */
2192         DoS3MEffectF,   /* UNI_S3MEFFECTF */
2193         DoS3MEffectI,   /* UNI_S3MEFFECTI */
2194         DoS3MEffectQ,   /* UNI_S3MEFFECTQ */
2195         DoS3MEffectR,   /* UNI_S3MEFFECTR */
2196         DoS3MEffectT,   /* UNI_S3MEFFECTT */
2197         DoS3MEffectU,   /* UNI_S3MEFFECTU */
2198         DoKeyOff,       /* UNI_KEYOFF */
2199         DoKeyFade,      /* UNI_KEYFADE */
2200         DoVolEffects,   /* UNI_VOLEFFECTS */
2201         DoPTEffect4,    /* UNI_XMEFFECT4 */
2202         DoXMEffect6,    /* UNI_XMEFFECT6 */
2203         DoXMEffectA,    /* UNI_XMEFFECTA */
2204         DoXMEffectE1,   /* UNI_XMEFFECTE1 */
2205         DoXMEffectE2,   /* UNI_XMEFFECTE2 */
2206         DoXMEffectEA,   /* UNI_XMEFFECTEA */
2207         DoXMEffectEB,   /* UNI_XMEFFECTEB */
2208         DoXMEffectG,    /* UNI_XMEFFECTG */
2209         DoXMEffectH,    /* UNI_XMEFFECTH */
2210         DoXMEffectL,    /* UNI_XMEFFECTL */
2211         DoXMEffectP,    /* UNI_XMEFFECTP */
2212         DoXMEffectX1,   /* UNI_XMEFFECTX1 */
2213         DoXMEffectX2,   /* UNI_XMEFFECTX2 */
2214         DoITEffectG,    /* UNI_ITEFFECTG */
2215         DoITEffectH,    /* UNI_ITEFFECTH */
2216         DoITEffectI,    /* UNI_ITEFFECTI */
2217         DoITEffectM,    /* UNI_ITEFFECTM */
2218         DoITEffectN,    /* UNI_ITEFFECTN */
2219         DoITEffectP,    /* UNI_ITEFFECTP */
2220         DoITEffectT,    /* UNI_ITEFFECTT */
2221         DoITEffectU,    /* UNI_ITEFFECTU */
2222         DoITEffectW,    /* UNI_ITEFFECTW */
2223         DoITEffectY,    /* UNI_ITEFFECTY */
2224         DoNothing,      /* UNI_ITEFFECTZ */
2225         DoITEffectS0,   /* UNI_ITEFFECTS0 */
2226         DoULTEffect9,   /* UNI_ULTEFFECT9 */
2227         DoMEDSpeed,     /* UNI_MEDSPEED */
2228         DoMEDEffectF1,  /* UNI_MEDEFFECTF1 */
2229         DoMEDEffectF2,  /* UNI_MEDEFFECTF2 */
2230         DoMEDEffectF3,  /* UNI_MEDEFFECTF3 */
2231         DoOktArp,       /* UNI_OKTARP */
2232 };
2233
2234 static int pt_playeffects(MODULE *mod, SWORD channel, MP_CONTROL *a)
2235 {
2236         UWORD tick = mod->vbtick;
2237         UWORD flags = mod->flags;
2238         UBYTE c;
2239         int explicitslides = 0;
2240         effect_func f;
2241
2242         while((c=UniGetByte()) != 0) {
2243 #if 0 /* this doesn't normally happen unless things go fubar elsewhere */
2244                 if (c >= UNI_LAST)
2245                     fprintf(stderr,"fubar'ed opcode %u\n",c);
2246 #endif
2247                 f = effects[c];
2248                 if (f != DoNothing)
2249                     a->sliding = 0;
2250                 explicitslides |= f(tick, flags, a, mod, channel);
2251         }
2252         return explicitslides;
2253 }
2254
2255 static void DoNNAEffects(MODULE *mod, MP_CONTROL *a, UBYTE dat)
2256 {
2257         int t;
2258         MP_VOICE *aout;
2259
2260         dat&=0xf;
2261         aout=(a->slave)?a->slave:NULL;
2262
2263         switch (dat) {
2264         case 0x0: /* past note cut */
2265                 for (t=0;t<NUMVOICES(mod);t++)
2266                         if (mod->voice[t].master==a)
2267                                 mod->voice[t].main.fadevol=0;
2268                 break;
2269         case 0x1: /* past note off */
2270                 for (t=0;t<NUMVOICES(mod);t++)
2271                         if (mod->voice[t].master==a) {
2272                                 mod->voice[t].main.keyoff|=KEY_OFF;
2273                                 if ((!(mod->voice[t].venv.flg & EF_ON))||
2274                                    (mod->voice[t].venv.flg & EF_LOOP))
2275                                         mod->voice[t].main.keyoff=KEY_KILL;
2276                         }
2277                 break;
2278         case 0x2: /* past note fade */
2279                 for (t=0;t<NUMVOICES(mod);t++)
2280                         if (mod->voice[t].master==a)
2281                                 mod->voice[t].main.keyoff|=KEY_FADE;
2282                 break;
2283         case 0x3: /* set NNA note cut */
2284                 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CUT;
2285                 break;
2286         case 0x4: /* set NNA note continue */
2287                 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CONTINUE;
2288                 break;
2289         case 0x5: /* set NNA note off */
2290                 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_OFF;
2291                 break;
2292         case 0x6: /* set NNA note fade */
2293                 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_FADE;
2294                 break;
2295         case 0x7: /* disable volume envelope */
2296                 if (aout)
2297                         aout->main.volflg&=~EF_ON;
2298                 break;
2299         case 0x8: /* enable volume envelope  */
2300                 if (aout)
2301                         aout->main.volflg|=EF_ON;
2302                 break;
2303         case 0x9: /* disable panning envelope */
2304                 if (aout)
2305                         aout->main.panflg&=~EF_ON;
2306                 break;
2307         case 0xa: /* enable panning envelope */
2308                 if (aout)
2309                         aout->main.panflg|=EF_ON;
2310                 break;
2311         case 0xb: /* disable pitch envelope */
2312                 if (aout)
2313                         aout->main.pitflg&=~EF_ON;
2314                 break;
2315         case 0xc: /* enable pitch envelope */
2316                 if (aout)
2317                         aout->main.pitflg|=EF_ON;
2318                 break;
2319         }
2320 }
2321
2322 static void pt_UpdateVoices(MODULE *mod, int max_volume)
2323 {
2324         SWORD envpan,envvol,envpit,channel;
2325         UWORD playperiod;
2326         SLONG vibval,vibdpt;
2327         ULONG tmpvol;
2328
2329         MP_VOICE *aout;
2330         INSTRUMENT *i;
2331         SAMPLE *s;
2332
2333         mod->totalchn=mod->realchn=0;
2334         for (channel=0;channel<NUMVOICES(mod);channel++) {
2335                 aout=&mod->voice[channel];
2336                 i=aout->main.i;
2337                 s=aout->main.s;
2338
2339                 if (!s || !s->length) continue;
2340
2341                 if (aout->main.period<40)
2342                         aout->main.period=40;
2343                 else if (aout->main.period>50000)
2344                         aout->main.period=50000;
2345
2346                 if ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_KEYOFF)) {
2347                         Voice_Play_internal(channel,s,(aout->main.start==-1)?
2348                             ((s->flags&SF_UST_LOOP)?s->loopstart:0):aout->main.start);
2349                         aout->main.fadevol=32768;
2350                         aout->aswppos=0;
2351                 }
2352
2353                 envvol = 256;
2354                 envpan = PAN_CENTER;
2355                 envpit = 32;
2356                 if (i && ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_ENV))) {
2357                         if (aout->main.volflg & EF_ON)
2358                                 envvol = StartEnvelope(&aout->venv,aout->main.volflg,
2359                                   i->volpts,i->volsusbeg,i->volsusend,
2360                                   i->volbeg,i->volend,i->volenv,aout->main.keyoff);
2361                         if (aout->main.panflg & EF_ON)
2362                                 envpan = StartEnvelope(&aout->penv,aout->main.panflg,
2363                                   i->panpts,i->pansusbeg,i->pansusend,
2364                                   i->panbeg,i->panend,i->panenv,aout->main.keyoff);
2365                         if (aout->main.pitflg & EF_ON)
2366                                 envpit = StartEnvelope(&aout->cenv,aout->main.pitflg,
2367                                   i->pitpts,i->pitsusbeg,i->pitsusend,
2368                                   i->pitbeg,i->pitend,i->pitenv,aout->main.keyoff);
2369
2370                         if (aout->cenv.flg & EF_ON)
2371                                 aout->masterperiod=GetPeriod(mod->flags,
2372                                   (UWORD)aout->main.note<<1, aout->master->speed);
2373                 } else {
2374                         if (aout->main.volflg & EF_ON)
2375                                 envvol = ProcessEnvelope(aout,&aout->venv,256);
2376                         if (aout->main.panflg & EF_ON)
2377                                 envpan = ProcessEnvelope(aout,&aout->penv,PAN_CENTER);
2378                         if (aout->main.pitflg & EF_ON)
2379                                 envpit = ProcessEnvelope(aout,&aout->cenv,32);
2380                 }
2381                 if (aout->main.kick == KICK_NOTE) {
2382                         aout->main.kick_flag = 1;
2383                 }
2384                 aout->main.kick=KICK_ABSENT;
2385
2386                 tmpvol = aout->main.fadevol;    /* max 32768 */
2387                 tmpvol *= aout->main.chanvol;   /* * max 64 */
2388                 tmpvol *= aout->main.outvolume; /* * max 256 */
2389                 tmpvol /= (256 * 64);                   /* tmpvol is max 32768 again */
2390                 aout->totalvol = tmpvol >> 2;   /* used to determine samplevolume */
2391                 tmpvol *= envvol;                               /* * max 256 */
2392                 tmpvol *= mod->volume;                  /* * max 128 */
2393                 tmpvol /= (128 * 256 * 128);
2394
2395                 /* fade out */
2396                 if (mod->sngpos>=mod->numpos)
2397                         tmpvol=0;
2398                 else
2399                         tmpvol=(tmpvol*max_volume)/128;
2400
2401                 if ((aout->masterchn!=-1)&& mod->control[aout->masterchn].muted)
2402                         Voice_SetVolume_internal(channel,0);
2403                 else {
2404                         Voice_SetVolume_internal(channel,tmpvol);
2405                         if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))
2406                                 mod->realchn++;
2407                         mod->totalchn++;
2408                 }
2409
2410                 if (aout->main.panning==PAN_SURROUND)
2411                         Voice_SetPanning_internal(channel,PAN_SURROUND);
2412                 else
2413                         if ((mod->panflag)&&(aout->penv.flg & EF_ON))
2414                                 Voice_SetPanning_internal(channel,
2415                                     DoPan(envpan,aout->main.panning));
2416                         else
2417                                 Voice_SetPanning_internal(channel,aout->main.panning);
2418
2419                 if (aout->main.period && s->vibdepth)
2420                         switch (s->vibtype) {
2421                         case 0:
2422                                 vibval=avibtab[s->avibpos&127];
2423                                 if (aout->avibpos & 0x80) vibval=-vibval;
2424                                 break;
2425                         case 1:
2426                                 vibval=64;
2427                                 if (aout->avibpos & 0x80) vibval=-vibval;
2428                                 break;
2429                         case 2:
2430                                 vibval=63-(((aout->avibpos+128)&255)>>1);
2431                                 break;
2432                         default:
2433                                 vibval=(((aout->avibpos+128)&255)>>1)-64;
2434                                 break;
2435                         }
2436                 else
2437                         vibval=0;
2438
2439                 if (s->vibflags & AV_IT) {
2440                         if ((aout->aswppos>>8)<s->vibdepth) {
2441                                 aout->aswppos += s->vibsweep;
2442                                 vibdpt=aout->aswppos;
2443                         } else
2444                                 vibdpt=s->vibdepth<<8;
2445                         vibval=(vibval*vibdpt)>>16;
2446                         if (aout->mflag) {
2447                                 if (!(mod->flags&UF_LINEAR)) vibval>>=1;
2448                                 aout->main.period-=vibval;
2449                         }
2450                 } else {
2451                         /* do XM style auto-vibrato */
2452                         if (!(aout->main.keyoff & KEY_OFF)) {
2453                                 if (aout->aswppos<s->vibsweep) {
2454                                         vibdpt=(aout->aswppos*s->vibdepth)/s->vibsweep;
2455                                         aout->aswppos++;
2456                                 } else
2457                                         vibdpt=s->vibdepth;
2458                         } else {
2459                                 /* keyoff -> depth becomes 0 if final depth wasn't reached or
2460                                    stays at final level if depth WAS reached */
2461                                 if (aout->aswppos>=s->vibsweep)
2462                                         vibdpt=s->vibdepth;
2463                                 else
2464                                         vibdpt=0;
2465                         }
2466                         vibval=(vibval*vibdpt)>>8;
2467                         aout->main.period-=vibval;
2468                 }
2469
2470                 /* update vibrato position */
2471                 aout->avibpos=(aout->avibpos+s->vibrate)&0xff;
2472
2473                 /* process pitch envelope */
2474                 playperiod=aout->main.period;
2475
2476                 if ((aout->main.pitflg&EF_ON)&&(envpit!=32)) {
2477                         long p1;
2478
2479                         envpit-=32;
2480                         if ((aout->main.note<<1)+envpit<=0) envpit=-(aout->main.note<<1);
2481
2482                         p1=GetPeriod(mod->flags, ((UWORD)aout->main.note<<1)+envpit,
2483                             aout->master->speed)-aout->masterperiod;
2484                         if (p1>0) {
2485                                 if ((UWORD)(playperiod+p1)<=playperiod) {
2486                                         p1=0;
2487                                         aout->main.keyoff|=KEY_OFF;
2488                                 }
2489                         } else if (p1<0) {
2490                                 if ((UWORD)(playperiod+p1)>=playperiod) {
2491                                         p1=0;
2492                                         aout->main.keyoff|=KEY_OFF;
2493                                 }
2494                         }
2495                         playperiod+=p1;
2496                 }
2497
2498                 if (!aout->main.fadevol) { /* check for a dead note (fadevol=0) */
2499                         Voice_Stop_internal(channel);
2500                         mod->totalchn--;
2501                         if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))
2502                                 mod->realchn--;
2503                 } else {
2504                         Voice_SetFrequency_internal(channel,
2505                                                     getfrequency(mod->flags,playperiod));
2506
2507                         /* if keyfade, start substracting fadeoutspeed from fadevol: */
2508                         if ((i)&&(aout->main.keyoff&KEY_FADE)) {
2509                                 if (aout->main.fadevol>=i->volfade)
2510                                         aout->main.fadevol-=i->volfade;
2511                                 else
2512                                         aout->main.fadevol=0;
2513                         }
2514                 }
2515
2516                 md_bpm=mod->bpm+mod->relspd;
2517                 if (md_bpm<32)
2518                         md_bpm=32;
2519                 else if ((!(mod->flags&UF_HIGHBPM)) && md_bpm>255)
2520                         md_bpm=255;
2521         }
2522 }
2523
2524 /* Handles new notes or instruments */
2525 static void pt_Notes(MODULE *mod)
2526 {
2527         SWORD channel;
2528         MP_CONTROL *a;
2529         UBYTE c,inst;
2530         int tr,funky; /* funky is set to indicate note or instrument change */
2531
2532         for (channel=0;channel<mod->numchn;channel++) {
2533                 a=&mod->control[channel];
2534
2535                 if (mod->sngpos>=mod->numpos) {
2536                         tr=mod->numtrk;
2537                         mod->numrow=0;
2538                 } else {
2539                         tr=mod->patterns[(mod->positions[mod->sngpos]*mod->numchn)+channel];
2540                         mod->numrow=mod->pattrows[mod->positions[mod->sngpos]];
2541                 }
2542
2543                 a->row=(tr<mod->numtrk)?UniFindRow(mod->tracks[tr],mod->patpos):NULL;
2544                 a->newsamp=0;
2545                 if (!mod->vbtick) a->main.notedelay=0;
2546
2547                 if (!a->row) continue;
2548                 UniSetRow(a->row);
2549                 funky=0;
2550
2551                 while((c=UniGetByte()) != 0)
2552                         switch (c) {
2553                         case UNI_NOTE:
2554                                 funky|=1;
2555                                 a->oldnote=a->anote,a->anote=UniGetByte();
2556                                 a->main.kick =KICK_NOTE;
2557                                 a->main.start=-1;
2558                                 a->sliding=0;
2559
2560                                 /* retrig tremolo and vibrato waves ? */
2561                                 if (!(a->wavecontrol & 0x80)) a->trmpos=0;
2562                                 if (!(a->wavecontrol & 0x08)) a->vibpos=0;
2563                                 if (!a->panbwave) a->panbpos=0;
2564                                 break;
2565                         case UNI_INSTRUMENT:
2566                                 inst=UniGetByte();
2567                                 if (inst>=mod->numins) break; /* safety valve */
2568                                 funky|=2;
2569                                 a->main.i=(mod->flags & UF_INST)?&mod->instruments[inst]:NULL;
2570                                 a->retrig=0;
2571                                 a->s3mtremor=0;
2572                                 a->ultoffset=0;
2573                                 a->main.sample=inst;
2574                                 break;
2575                         default:
2576                                 UniSkipOpcode();
2577                                 break;
2578                         }
2579
2580                 if (funky) {
2581                         INSTRUMENT *i;
2582                         SAMPLE *s;
2583
2584                         if ((i=a->main.i) != NULL) {
2585                                 if (i->samplenumber[a->anote] >= mod->numsmp) continue;
2586                                 s=&mod->samples[i->samplenumber[a->anote]];
2587                                 a->main.note=i->samplenote[a->anote];
2588                         } else {
2589                                 a->main.note=a->anote;
2590                                 s=&mod->samples[a->main.sample];
2591                         }
2592
2593                         if (a->main.s!=s) {
2594                                 a->main.s=s;
2595                                 a->newsamp=a->main.period;
2596                         }
2597
2598                         /* channel or instrument determined panning ? */
2599                         a->main.panning=mod->panning[channel];
2600                         if (s->flags & SF_OWNPAN)
2601                                 a->main.panning=s->panning;
2602                         else if ((i)&&(i->flags & IF_OWNPAN))
2603                                 a->main.panning=i->panning;
2604
2605                         a->main.handle=s->handle;
2606                         a->speed=s->speed;
2607
2608                         if (i) {
2609                                 if ((mod->panflag)&&(i->flags & IF_PITCHPAN)
2610                                    &&(a->main.panning!=PAN_SURROUND)){
2611                                         a->main.panning+=
2612                                             ((a->anote-i->pitpancenter)*i->pitpansep)/8;
2613                                         if (a->main.panning<PAN_LEFT)
2614                                                 a->main.panning=PAN_LEFT;
2615                                         else if (a->main.panning>PAN_RIGHT)
2616                                                 a->main.panning=PAN_RIGHT;
2617                                 }
2618                                 a->main.pitflg=i->pitflg;
2619                                 a->main.volflg=i->volflg;
2620                                 a->main.panflg=i->panflg;
2621                                 a->main.nna=i->nnatype;
2622                                 a->dca=i->dca;
2623                                 a->dct=i->dct;
2624                         } else {
2625                                 a->main.pitflg=a->main.volflg=a->main.panflg=0;
2626                                 a->main.nna=a->dca=0;
2627                                 a->dct=DCT_OFF;
2628                         }
2629
2630                         if (funky&2) /* instrument change */ {
2631                                 /* IT random volume variations: 0:8 bit fixed, and one bit for
2632                                    sign. */
2633                                 a->volume=a->tmpvolume=s->volume;
2634                                 if ((s)&&(i)) {
2635                                         if (i->rvolvar) {
2636                                                 a->volume=a->tmpvolume=s->volume+
2637                                                   ((s->volume*((SLONG)i->rvolvar*(SLONG)getrandom(512)
2638                                                   ))/25600);
2639                                                 if (a->volume<0)
2640                                                         a->volume=a->tmpvolume=0;
2641                                                 else if (a->volume>64)
2642                                                         a->volume=a->tmpvolume=64;
2643                                         }
2644                                         if ((mod->panflag)&&(a->main.panning!=PAN_SURROUND)) {
2645                                                 a->main.panning+=((a->main.panning*((SLONG)i->rpanvar*
2646                                                   (SLONG)getrandom(512)))/25600);
2647                                                 if (a->main.panning<PAN_LEFT)
2648                                                         a->main.panning=PAN_LEFT;
2649                                                 else if (a->main.panning>PAN_RIGHT)
2650                                                         a->main.panning=PAN_RIGHT;
2651                                         }
2652                                 }
2653                         }
2654
2655                         a->wantedperiod=a->tmpperiod=
2656                             GetPeriod(mod->flags, (UWORD)a->main.note<<1,a->speed);
2657                         a->main.keyoff=KEY_KICK;
2658                 }
2659         }
2660 }
2661
2662 /* Handles effects */
2663 static void pt_EffectsPass1(MODULE *mod)
2664 {
2665         SWORD channel;
2666         MP_CONTROL *a;
2667         MP_VOICE *aout;
2668         int explicitslides;
2669
2670         for (channel=0;channel<mod->numchn;channel++) {
2671                 a=&mod->control[channel];
2672
2673                 if ((aout=a->slave) != NULL) {
2674                         a->main.fadevol=aout->main.fadevol;
2675                         a->main.period=aout->main.period;
2676                         if (a->main.kick==KICK_KEYOFF)
2677                                 a->main.keyoff=aout->main.keyoff;
2678                 }
2679
2680                 if (!a->row) continue;
2681                 UniSetRow(a->row);
2682
2683                 a->ownper=a->ownvol=0;
2684                 explicitslides = pt_playeffects(mod, channel, a);
2685
2686                 /* continue volume slide if necessary for XM and IT */
2687                 if (mod->flags&UF_BGSLIDES) {
2688                         if (!explicitslides && a->sliding)
2689                                 DoS3MVolSlide(mod->vbtick, mod->flags, a, 0);
2690                         else if (a->tmpvolume)
2691                                 a->sliding = explicitslides;
2692                 }
2693
2694                 if (!a->ownper)
2695                         a->main.period=a->tmpperiod;
2696                 if (!a->ownvol)
2697                         a->volume=a->tmpvolume;
2698
2699                 if (a->main.s) {
2700                         if (a->main.i)
2701                                 a->main.outvolume=
2702                                     (a->volume*a->main.s->globvol*a->main.i->globvol)>>10;
2703                         else
2704                                 a->main.outvolume=(a->volume*a->main.s->globvol)>>4;
2705                         if (a->main.outvolume>256)
2706                                 a->main.outvolume=256;
2707                         else if (a->main.outvolume<0)
2708                                 a->main.outvolume=0;
2709                 }
2710         }
2711 }
2712
2713 /* NNA management */
2714 static void pt_NNA(MODULE *mod)
2715 {
2716         SWORD channel;
2717         MP_CONTROL *a;
2718
2719         for (channel=0;channel<mod->numchn;channel++) {
2720                 a=&mod->control[channel];
2721
2722                 if (a->main.kick==KICK_NOTE) {
2723                         BOOL kill=0;
2724
2725                         if (a->slave) {
2726                                 MP_VOICE *aout;
2727
2728                                 aout=a->slave;
2729                                 if (aout->main.nna & NNA_MASK) {
2730                                         /* Make sure the old MP_VOICE channel knows it has no
2731                                            master now ! */
2732                                         a->slave=NULL;
2733                                         /* assume the channel is taken by NNA */
2734                                         aout->mflag=0;
2735
2736                                         switch (aout->main.nna) {
2737                                         case NNA_CONTINUE: /* continue note, do nothing */
2738                                                 break;
2739                                         case NNA_OFF: /* note off */
2740                                                 aout->main.keyoff|=KEY_OFF;
2741                                                 if ((!(aout->main.volflg & EF_ON))||
2742                                                           (aout->main.volflg & EF_LOOP))
2743                                                         aout->main.keyoff=KEY_KILL;
2744                                                 break;
2745                                         case NNA_FADE:
2746                                                 aout->main.keyoff |= KEY_FADE;
2747                                                 break;
2748                                         }
2749                                 }
2750                         }
2751
2752                         if (a->dct!=DCT_OFF) {
2753                                 int t;
2754
2755                                 for (t=0;t<NUMVOICES(mod);t++)
2756                                         if ((!Voice_Stopped_internal(t))&&
2757                                            (mod->voice[t].masterchn==channel)&&
2758                                            (a->main.sample==mod->voice[t].main.sample)) {
2759                                                 kill=0;
2760                                                 switch (a->dct) {
2761                                                 case DCT_NOTE:
2762                                                         if (a->main.note==mod->voice[t].main.note)
2763                                                                 kill=1;
2764                                                         break;
2765                                                 case DCT_SAMPLE:
2766                                                         if (a->main.handle==mod->voice[t].main.handle)
2767                                                                 kill=1;
2768                                                         break;
2769                                                 case DCT_INST:
2770                                                         kill=1;
2771                                                         break;
2772                                                 }
2773                                                 if (kill)
2774                                                         switch (a->dca) {
2775                                                         case DCA_CUT:
2776                                                                 mod->voice[t].main.fadevol=0;
2777                                                                 break;
2778                                                         case DCA_OFF:
2779                                                                 mod->voice[t].main.keyoff|=KEY_OFF;
2780                                                                 if ((!(mod->voice[t].main.volflg&EF_ON))||
2781                                                                     (mod->voice[t].main.volflg&EF_LOOP))
2782                                                                         mod->voice[t].main.keyoff=KEY_KILL;
2783                                                                 break;
2784                                                         case DCA_FADE:
2785                                                                 mod->voice[t].main.keyoff|=KEY_FADE;
2786                                                                 break;
2787                                                         }
2788                                         }
2789                         }
2790                 } /* if (a->main.kick==KICK_NOTE) */
2791         }
2792 }
2793
2794 /* Setup module and NNA voices */
2795 static void pt_SetupVoices(MODULE *mod)
2796 {
2797         SWORD channel;
2798         MP_CONTROL *a;
2799         MP_VOICE *aout;
2800
2801         for (channel=0;channel<mod->numchn;channel++) {
2802                 a=&mod->control[channel];
2803
2804                 if (a->main.notedelay) continue;
2805                 if (a->main.kick==KICK_NOTE) {
2806                         /* if no channel was cut above, find an empty or quiet channel
2807                            here */
2808                         if (mod->flags&UF_NNA) {
2809                                 if (!a->slave) {
2810                                         int newchn;
2811
2812                                         if ((newchn=MP_FindEmptyChannel(mod))!=-1)
2813                                                 a->slave=&mod->voice[a->slavechn=newchn];
2814                                 }
2815                         } else
2816                                 a->slave=&mod->voice[a->slavechn=channel];
2817
2818                         /* assign parts of MP_VOICE only done for a KICK_NOTE */
2819                         if ((aout=a->slave) != NULL) {
2820                                 if (aout->mflag && aout->master) aout->master->slave=NULL;
2821                                 aout->master=a;
2822                                 a->slave=aout;
2823                                 aout->masterchn=channel;
2824                                 aout->mflag=1;
2825                         }
2826                 } else
2827                         aout=a->slave;
2828
2829                 if (aout)
2830                         aout->main=a->main;
2831                 a->main.kick=KICK_ABSENT;
2832         }
2833 }
2834
2835 /* second effect pass */
2836 static void pt_EffectsPass2(MODULE *mod)
2837 {
2838         SWORD channel;
2839         MP_CONTROL *a;
2840         UBYTE c;
2841
2842         for (channel=0;channel<mod->numchn;channel++) {
2843                 a=&mod->control[channel];
2844
2845                 if (!a->row) continue;
2846                 UniSetRow(a->row);
2847
2848                 while((c=UniGetByte()) != 0)
2849                         if (c==UNI_ITEFFECTS0) {
2850                                 c=UniGetByte();
2851                                 if ((c>>4)==SS_S7EFFECTS)
2852                                         DoNNAEffects(mod, a, c&0xf);
2853                         } else
2854                                 UniSkipOpcode();
2855         }
2856 }
2857
2858 void Player_HandleTick(void)
2859 {
2860         SWORD channel;
2861         int max_volume;
2862
2863 #if 0
2864         /* don't handle the very first ticks, this allows the other hardware to
2865            settle down so we don't loose any starting notes */
2866         if (isfirst) {
2867                 isfirst--;
2868                 return;
2869         }
2870 #endif
2871
2872         if ((!pf)||(pf->forbid)||(pf->sngpos>=pf->numpos)) return;
2873
2874         /* update time counter (sngtime is in milliseconds (in fact 2^-10)) */
2875         pf->sngremainder+=(1<<9)*5; /* thus 2.5*(1<<10), since fps=0.4xtempo */
2876         pf->sngtime+=pf->sngremainder/pf->bpm;
2877         pf->sngremainder%=pf->bpm;
2878
2879         if (++pf->vbtick>=pf->sngspd) {
2880                 if (pf->pat_repcrazy)
2881                         pf->pat_repcrazy=0; /* play 2 times row 0 */
2882                 else
2883                         pf->patpos++;
2884                 pf->vbtick=0;
2885
2886                 /* process pattern-delay. pf->patdly2 is the counter and pf->patdly is
2887                    the command memory. */
2888                 if (pf->patdly)
2889                         pf->patdly2=pf->patdly,pf->patdly=0;
2890                 if (pf->patdly2) {
2891                         /* patterndelay active */
2892                         if (--pf->patdly2)
2893                                 /* so turn back pf->patpos by 1 */
2894                                 if (pf->patpos) pf->patpos--;
2895                 }
2896
2897                 /* do we have to get a new patternpointer ? (when pf->patpos reaches the
2898                    pattern size, or when a patternbreak is active) */
2899                 if (((pf->patpos>=pf->numrow)&&(pf->numrow>0))&&(!pf->posjmp))
2900                         pf->posjmp=3;
2901
2902                 if (pf->posjmp) {
2903                         pf->patpos=pf->numrow?(pf->patbrk%pf->numrow):0;
2904                         pf->pat_repcrazy=0;
2905                         pf->sngpos+=(pf->posjmp-2);
2906                         for (channel=0;channel<pf->numchn;channel++)
2907                                 pf->control[channel].pat_reppos=-1;
2908
2909                         pf->patbrk=pf->posjmp=0;
2910
2911                         if (pf->sngpos<0) pf->sngpos=(SWORD)(pf->numpos-1);
2912
2913                         /* handle the "---" (end of song) pattern since it can occur
2914                            *inside* the module in some formats */
2915                         if ((pf->sngpos>=pf->numpos)||
2916                                 (pf->positions[pf->sngpos]==LAST_PATTERN)) {
2917                                 if (!pf->wrap) return;
2918                                 if (!(pf->sngpos=pf->reppos)) {
2919                                     pf->volume=pf->initvolume>128?128:pf->initvolume;
2920                                         if(pf->initspeed!=0)
2921                                                 pf->sngspd=pf->initspeed<32?pf->initspeed:32;
2922                                         else
2923                                                 pf->sngspd=6;
2924                                         pf->bpm=pf->inittempo<32?32:pf->inittempo;
2925                                 }
2926                         }
2927                 }
2928
2929                 if (!pf->patdly2)
2930                         pt_Notes(pf);
2931         }
2932
2933         /* Fade global volume if enabled and we're playing the last pattern */
2934         if (((pf->sngpos==pf->numpos-1)||
2935                  (pf->positions[pf->sngpos+1]==LAST_PATTERN))&&
2936             (pf->fadeout))
2937                 max_volume=pf->numrow?((pf->numrow-pf->patpos)*128)/pf->numrow:0;
2938         else
2939                 max_volume=128;
2940
2941         pt_EffectsPass1(pf);
2942         if (pf->flags&UF_NNA)
2943                 pt_NNA(pf);
2944         pt_SetupVoices(pf);
2945         pt_EffectsPass2(pf);
2946
2947         /* now set up the actual hardware channel playback information */
2948         pt_UpdateVoices(pf, max_volume);
2949 }
2950
2951 static void Player_Init_internal(MODULE* mod)
2952 {
2953         int t;
2954
2955         for (t=0;t<mod->numchn;t++) {
2956                 mod->control[t].main.chanvol=mod->chanvol[t];
2957                 mod->control[t].main.panning=mod->panning[t];
2958         }
2959
2960         mod->sngtime=0;
2961         mod->sngremainder=0;
2962
2963         mod->pat_repcrazy=0;
2964         mod->sngpos=0;
2965         if(mod->initspeed!=0)
2966                 mod->sngspd=mod->initspeed<32?mod->initspeed:32;
2967         else
2968                 mod->sngspd=6;
2969         mod->volume=mod->initvolume>128?128:mod->initvolume;
2970
2971         mod->vbtick=mod->sngspd;
2972         mod->patdly=0;
2973         mod->patdly2=0;
2974         mod->bpm=mod->inittempo<32?32:mod->inittempo;
2975         mod->realchn=0;
2976
2977         mod->patpos=0;
2978         mod->posjmp=2; /* make sure the player fetches the first note */
2979         mod->numrow=-1;
2980         mod->patbrk=0;
2981 }
2982
2983 int Player_Init(MODULE* mod)
2984 {
2985         mod->extspd=1;
2986         mod->panflag=1;
2987         mod->wrap=0;
2988         mod->loop=1;
2989         mod->fadeout=0;
2990
2991         mod->relspd=0;
2992
2993         /* make sure the player doesn't start with garbage */
2994         if (!(mod->control=(MP_CONTROL*)MikMod_calloc(mod->numchn,sizeof(MP_CONTROL))))
2995                 return 1;
2996         if (!(mod->voice=(MP_VOICE*)MikMod_calloc(md_sngchn,sizeof(MP_VOICE))))
2997                 return 1;
2998
2999         /* mod->numvoices was used during loading to clamp md_sngchn.
3000            After loading it's used to remember how big mod->voice is.
3001         */
3002         mod->numvoices = md_sngchn;
3003
3004         Player_Init_internal(mod);
3005         return 0;
3006 }
3007
3008 void Player_Exit_internal(MODULE* mod)
3009 {
3010         if (!mod)
3011                 return;
3012
3013         /* Stop playback if necessary */
3014         if (mod==pf) {
3015                 Player_Stop_internal();
3016                 pf=NULL;
3017         }
3018
3019         MikMod_free(mod->control);
3020         MikMod_free(mod->voice);
3021         mod->control=NULL;
3022         mod->voice=NULL;
3023 }
3024
3025 void Player_Exit(MODULE* mod)
3026 {
3027         MUTEX_LOCK(vars);
3028         Player_Exit_internal(mod);
3029         MUTEX_UNLOCK(vars);
3030 }
3031
3032 MIKMODAPI void Player_SetVolume(SWORD volume)
3033 {
3034         MUTEX_LOCK(vars);
3035         if (pf) {
3036                 pf->volume=(volume<0)?0:(volume>128)?128:volume;
3037                 pf->initvolume=pf->volume;
3038         }
3039         MUTEX_UNLOCK(vars);
3040 }
3041
3042 MIKMODAPI MODULE* Player_GetModule(void)
3043 {
3044         MODULE* result;
3045
3046         MUTEX_LOCK(vars);
3047         result=pf;
3048         MUTEX_UNLOCK(vars);
3049
3050         return result;
3051 }
3052
3053 MIKMODAPI void Player_Start(MODULE *mod)
3054 {
3055         int t;
3056
3057         if (!mod)
3058                 return;
3059
3060         if (!MikMod_Active())
3061                 MikMod_EnableOutput();
3062
3063         mod->forbid=0;
3064
3065         MUTEX_LOCK(vars);
3066         if (pf!=mod) {
3067                 /* new song is being started, so completely stop out the old one. */
3068                 if (pf) pf->forbid=1;
3069                 for (t=0;t<md_sngchn;t++) Voice_Stop_internal(t);
3070         }
3071         pf=mod;
3072         MUTEX_UNLOCK(vars);
3073 }
3074
3075 void Player_Stop_internal(void)
3076 {
3077         if (!md_sfxchn) MikMod_DisableOutput_internal();
3078         if (pf) pf->forbid=1;
3079         pf=NULL;
3080 }
3081
3082 MIKMODAPI void Player_Stop(void)
3083 {
3084         MUTEX_LOCK(vars);
3085                 Player_Stop_internal();
3086         MUTEX_UNLOCK(vars);
3087 }
3088
3089 MIKMODAPI BOOL Player_Active(void)
3090 {
3091         BOOL result=0;
3092
3093         MUTEX_LOCK(vars);
3094         if (pf)
3095                 result=(!(pf->sngpos>=pf->numpos));
3096         MUTEX_UNLOCK(vars);
3097
3098         return result;
3099 }
3100
3101 MIKMODAPI void Player_NextPosition(void)
3102 {
3103         MUTEX_LOCK(vars);
3104         if (pf) {
3105                 int t;
3106
3107                 pf->forbid=1;
3108                 pf->posjmp=3;
3109                 pf->patbrk=0;
3110                 pf->vbtick=pf->sngspd;
3111
3112                 for (t=0;t<NUMVOICES(pf);t++) {
3113                         Voice_Stop_internal(t);
3114                         pf->voice[t].main.i=NULL;
3115                         pf->voice[t].main.s=NULL;
3116                 }
3117                 for (t=0;t<pf->numchn;t++) {
3118                         pf->control[t].main.i=NULL;
3119                         pf->control[t].main.s=NULL;
3120                 }
3121                 pf->forbid=0;
3122         }
3123         MUTEX_UNLOCK(vars);
3124 }
3125
3126 MIKMODAPI void Player_PrevPosition(void)
3127 {
3128         MUTEX_LOCK(vars);
3129         if (pf) {
3130                 int t;
3131
3132                 pf->forbid=1;
3133                 pf->posjmp=1;
3134                 pf->patbrk=0;
3135                 pf->vbtick=pf->sngspd;
3136
3137                 for (t=0;t<NUMVOICES(pf);t++) {
3138                         Voice_Stop_internal(t);
3139                         pf->voice[t].main.i=NULL;
3140                         pf->voice[t].main.s=NULL;
3141                 }
3142                 for (t=0;t<pf->numchn;t++) {
3143                         pf->control[t].main.i=NULL;
3144                         pf->control[t].main.s=NULL;
3145                 }
3146                 pf->forbid=0;
3147         }
3148         MUTEX_UNLOCK(vars);
3149 }
3150
3151 MIKMODAPI void Player_SetPosition(UWORD pos)
3152 {
3153         MUTEX_LOCK(vars);
3154         if (pf) {
3155                 int t;
3156
3157                 pf->forbid=1;
3158                 if (pos>=pf->numpos) pos=pf->numpos;
3159                 pf->posjmp=2;
3160                 pf->patbrk=0;
3161                 pf->sngpos=pos;
3162                 pf->vbtick=pf->sngspd;
3163
3164                 for (t=0;t<NUMVOICES(pf);t++) {
3165                         Voice_Stop_internal(t);
3166                         pf->voice[t].main.i=NULL;
3167                         pf->voice[t].main.s=NULL;
3168                 }
3169                 for (t=0;t<pf->numchn;t++) {
3170                         pf->control[t].main.i=NULL;
3171                         pf->control[t].main.s=NULL;
3172                 }
3173                 pf->forbid=0;
3174
3175                 if (!pos)
3176                         Player_Init_internal(pf);
3177         }
3178         MUTEX_UNLOCK(vars);
3179 }
3180
3181 static void Player_Unmute_internal(SLONG arg1,va_list ap)
3182 {
3183         SLONG t,arg2,arg3=0;
3184
3185         if (pf) {
3186                 switch (arg1) {
3187                 case MUTE_INCLUSIVE:
3188                         if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3189                            (arg2>arg3)||(arg3>=pf->numchn))
3190                                 return;
3191                         for (;arg2<pf->numchn && arg2<=arg3;arg2++)
3192                                 pf->control[arg2].muted=0;
3193                         break;
3194                 case MUTE_EXCLUSIVE:
3195                         if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3196                            (arg2>arg3)||(arg3>=pf->numchn))
3197                                 return;
3198                         for (t=0;t<pf->numchn;t++) {
3199                                 if ((t>=arg2) && (t<=arg3))
3200                                         continue;
3201                                 pf->control[t].muted=0;
3202                         }
3203                         break;
3204                 default:
3205                         if (arg1<pf->numchn) pf->control[arg1].muted=0;
3206                         break;
3207                 }
3208         }
3209 }
3210
3211 MIKMODAPI void Player_Unmute(SLONG arg1, ...)
3212 {
3213         va_list args;
3214
3215         va_start(args,arg1);
3216         MUTEX_LOCK(vars);
3217         Player_Unmute_internal(arg1,args);
3218         MUTEX_UNLOCK(vars);
3219         va_end(args);
3220 }
3221
3222 static void Player_Mute_internal(SLONG arg1,va_list ap)
3223 {
3224         SLONG t,arg2,arg3=0;
3225
3226         if (pf) {
3227                 switch (arg1) {
3228                 case MUTE_INCLUSIVE:
3229                         if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3230                             (arg2>arg3)||(arg3>=pf->numchn))
3231                                 return;
3232                         for (;arg2<pf->numchn && arg2<=arg3;arg2++)
3233                                 pf->control[arg2].muted=1;
3234                         break;
3235                 case MUTE_EXCLUSIVE:
3236                         if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3237                             (arg2>arg3)||(arg3>=pf->numchn))
3238                                 return;
3239                         for (t=0;t<pf->numchn;t++) {
3240                                 if ((t>=arg2) && (t<=arg3))
3241                                         continue;
3242                                 pf->control[t].muted=1;
3243                         }
3244                         break;
3245                 default:
3246                         if (arg1<pf->numchn)
3247                                 pf->control[arg1].muted=1;
3248                         break;
3249                 }
3250         }
3251 }
3252
3253 MIKMODAPI void Player_Mute(SLONG arg1,...)
3254 {
3255         va_list args;
3256
3257         va_start(args,arg1);
3258         MUTEX_LOCK(vars);
3259         Player_Mute_internal(arg1,args);
3260         MUTEX_UNLOCK(vars);
3261         va_end(args);
3262 }
3263
3264 static void Player_ToggleMute_internal(SLONG arg1,va_list ap)
3265 {
3266         SLONG arg2,arg3=0;
3267         ULONG t;
3268
3269         if (pf) {
3270                 switch (arg1) {
3271                 case MUTE_INCLUSIVE:
3272                         if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3273                             (arg2>arg3)||(arg3>=pf->numchn))
3274                                 return;
3275                         for (;arg2<pf->numchn && arg2<=arg3;arg2++)
3276                                 pf->control[arg2].muted=1-pf->control[arg2].muted;
3277                         break;
3278                 case MUTE_EXCLUSIVE:
3279                         if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3280                             (arg2>arg3)||(arg3>=pf->numchn))
3281                                 return;
3282                         for (t=0;t<pf->numchn;t++) {
3283                                 if ((t>=arg2) && (t<=arg3))
3284                                         continue;
3285                                 pf->control[t].muted=1-pf->control[t].muted;
3286                         }
3287                         break;
3288                 default:
3289                         if (arg1<pf->numchn)
3290                                 pf->control[arg1].muted=1-pf->control[arg1].muted;
3291                         break;
3292                 }
3293         }
3294 }
3295
3296 MIKMODAPI void Player_ToggleMute(SLONG arg1,...)
3297 {
3298         va_list args;
3299
3300         va_start(args,arg1);
3301         MUTEX_LOCK(vars);
3302         Player_ToggleMute_internal(arg1,args);
3303         MUTEX_UNLOCK(vars);
3304         va_end(args);
3305 }
3306
3307 MIKMODAPI BOOL Player_Muted(UBYTE chan)
3308 {
3309         BOOL result=1;
3310
3311         MUTEX_LOCK(vars);
3312         if (pf)
3313                 result=(chan<pf->numchn)?pf->control[chan].muted:1;
3314         MUTEX_UNLOCK(vars);
3315
3316         return result;
3317 }
3318
3319 MIKMODAPI int Player_GetChannelVoice(UBYTE chan)
3320 {
3321         int result=0;
3322
3323         MUTEX_LOCK(vars);
3324         if (pf)
3325                 result=(chan<pf->numchn)?pf->control[chan].slavechn:-1;
3326         MUTEX_UNLOCK(vars);
3327
3328         return result;
3329 }
3330
3331 MIKMODAPI UWORD Player_GetChannelPeriod(UBYTE chan)
3332 {
3333         UWORD result=0;
3334
3335         MUTEX_LOCK(vars);
3336         if (pf)
3337             result=(chan<pf->numchn)?pf->control[chan].main.period:0;
3338         MUTEX_UNLOCK(vars);
3339
3340         return result;
3341 }
3342
3343 BOOL Player_Paused_internal(void)
3344 {
3345         return pf?pf->forbid:1;
3346 }
3347
3348 MIKMODAPI BOOL Player_Paused(void)
3349 {
3350         BOOL result;
3351
3352         MUTEX_LOCK(vars);
3353         result=Player_Paused_internal();
3354         MUTEX_UNLOCK(vars);
3355
3356         return result;
3357 }
3358
3359 MIKMODAPI void Player_TogglePause(void)
3360 {
3361         MUTEX_LOCK(vars);
3362         if (pf)
3363                 pf->forbid=1-pf->forbid;
3364         MUTEX_UNLOCK(vars);
3365 }
3366
3367 MIKMODAPI void Player_SetSpeed(UWORD speed)
3368 {
3369         MUTEX_LOCK(vars);
3370         if (pf)
3371                 pf->sngspd=speed?(speed<32?speed:32):1;
3372         MUTEX_UNLOCK(vars);
3373 }
3374
3375 MIKMODAPI void Player_SetTempo(UWORD tempo)
3376 {
3377         if (tempo<32) tempo=32;
3378         MUTEX_LOCK(vars);
3379         if (pf) {
3380                 if ((!(pf->flags&UF_HIGHBPM))&&(tempo>255)) tempo=255;
3381                 pf->bpm=tempo;
3382         }
3383         MUTEX_UNLOCK(vars);
3384 }
3385
3386 MIKMODAPI int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo)
3387 {
3388         int i;
3389
3390         if (numvoices > md_sngchn)
3391                 numvoices = md_sngchn;
3392
3393         MUTEX_LOCK(vars);
3394         if (pf)
3395                 for (i = 0; i < md_sngchn; i++) {
3396                         vinfo [i].i = pf->voice[i].main.i;
3397                         vinfo [i].s = pf->voice[i].main.s;
3398                         vinfo [i].panning = pf->voice [i].main.panning;
3399                         vinfo [i].volume = pf->voice [i].main.chanvol;
3400                         vinfo [i].period = pf->voice [i].main.period;
3401                         vinfo [i].kick = pf->voice [i].main.kick_flag;
3402                         pf->voice [i].main.kick_flag = 0;
3403                 }
3404         MUTEX_UNLOCK(vars);
3405
3406         return numvoices;
3407 }
3408
3409 /* Get current module order */
3410 MIKMODAPI int Player_GetOrder(void)
3411 {
3412         int ret;
3413         MUTEX_LOCK(vars);
3414         ret = pf ? pf->sngpos :0; /* pf->positions[pf->sngpos ? pf->sngpos-1 : 0]: 0; */
3415         MUTEX_UNLOCK(vars);
3416         return ret;
3417 }
3418
3419 /* Get current module row */
3420 MIKMODAPI int Player_GetRow(void)
3421 {
3422         int ret;
3423         MUTEX_LOCK(vars);
3424         ret = pf ? pf->patpos : 0;
3425         MUTEX_UNLOCK(vars);
3426         return ret;
3427 }
3428
3429 /* ex:set ts=4: */