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