FS#12756 by Marek Salaba - update Czech translation
[maemo-rb.git] / apps / plugins / mikmod / mplayer.c
blob88d6a81af4c029c94a1c9c680e9531b0d3ab9f20
1 /* MikMod sound library
2 (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
3 for complete list.
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.
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.
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.
21 /*==============================================================================
23 $Id: mplayer.c,v 1.4 2006/08/08 00:06:31 realtech Exp $
25 The Protracker Player Driver
27 The protracker driver supports all base Protracker 3.x commands and features.
29 ==============================================================================*/
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #include <string.h>
36 #include <stdarg.h>
37 #ifdef SRANDOM_IN_MATH_H
38 #include <math.h>
39 #else
40 #include <stdlib.h>
41 #endif
43 #include "mikmod_internals.h"
45 #ifdef SUNOS
46 extern int fprintf(FILE *, const char *, ...);
47 extern long int random(void);
48 #endif
50 /* The currently playing module */
51 MODULE *pf = NULL;
53 #define HIGH_OCTAVE 2 /* number of above-range octaves */
55 static UWORD oldperiods[OCTAVE*2]={
56 0x6b00, 0x6800, 0x6500, 0x6220, 0x5f50, 0x5c80,
57 0x5a00, 0x5740, 0x54d0, 0x5260, 0x5010, 0x4dc0,
58 0x4b90, 0x4960, 0x4750, 0x4540, 0x4350, 0x4160,
59 0x3f90, 0x3dc0, 0x3c10, 0x3a40, 0x38b0, 0x3700
62 static UBYTE VibratoTable[32]={
63 0, 24, 49, 74, 97,120,141,161,180,197,212,224,235,244,250,253,
64 255,253,250,244,235,224,212,197,180,161,141,120, 97, 74, 49, 24
67 static UBYTE avibtab[128]={
68 0, 1, 3, 4, 6, 7, 9,10,12,14,15,17,18,20,21,23,
69 24,25,27,28,30,31,32,34,35,36,38,39,40,41,42,44,
70 45,46,47,48,49,50,51,52,53,54,54,55,56,57,57,58,
71 59,59,60,60,61,61,62,62,62,63,63,63,63,63,63,63,
72 64,63,63,63,63,63,63,63,62,62,62,61,61,60,60,59,
73 59,58,57,57,56,55,54,54,53,52,51,50,49,48,47,46,
74 45,44,42,41,40,39,38,36,35,34,32,31,30,28,27,25,
75 24,23,21,20,18,17,15,14,12,10, 9, 7, 6, 4, 3, 1
78 /* Triton's linear periods to frequency translation table (for XM modules) */
79 static 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
178 #define LOGFAC 2*16
179 static 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
208 static 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
227 /* returns a random value between 0 and ceil-1, ceil must be a power of two */
228 static int getrandom(int ceil)
230 #ifdef HAVE_SRANDOM
231 return random()&(ceil-1);
232 #else
233 return (rand()*ceil)/(RAND_MAX+1.0);
234 #endif
237 /* New Note Action Scoring System :
238 --------------------------------
239 1) total-volume (fadevol, chanvol, volume) is the main scorer.
240 2) a looping sample is a bonus x2
241 3) a foreground channel is a bonus x4
242 4) an active envelope with keyoff is a handicap -x2
244 static int MP_FindEmptyChannel(MODULE *mod)
246 MP_VOICE *a;
247 ULONG t,k,tvol,pp;
249 for (t=0;t<md_sngchn;t++)
250 if (((mod->voice[t].main.kick==KICK_ABSENT)||
251 (mod->voice[t].main.kick==KICK_ENV))&&
252 Voice_Stopped_internal(t))
253 return t;
255 tvol=0xffffffUL;t=-1;a=mod->voice;
256 for (k=0;k<md_sngchn;k++,a++) {
257 /* allow us to take over a nonexisting sample */
258 if (!a->main.s)
259 return k;
261 if ((a->main.kick==KICK_ABSENT)||(a->main.kick==KICK_ENV)) {
262 pp=a->totalvol<<((a->main.s->flags&SF_LOOP)?1:0);
263 if ((a->master)&&(a==a->master->slave))
264 pp<<=2;
266 if (pp<tvol) {
267 tvol=pp;
268 t=k;
273 if (tvol>8000*7) return -1;
274 return t;
277 static SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2)
279 if ((p1==p2)||(p==p1)) return v1;
280 return v1+((SLONG)((p-p1)*(v2-v1))/(p2-p1));
283 UWORD getlinearperiod(UWORD note,ULONG fine)
285 UWORD t;
287 t=((20L+2*HIGH_OCTAVE)*OCTAVE+2-note)*32L-(fine>>1);
288 return t;
291 static UWORD getlogperiod(UWORD note,ULONG fine)
293 UWORD n,o;
294 UWORD p1,p2;
295 ULONG i;
297 n=note%(2*OCTAVE);
298 o=note/(2*OCTAVE);
299 i=(n<<2)+(fine>>4); /* n*8 + fine/16 */
301 p1=logtab[i];
302 p2=logtab[i+1];
304 return (Interpolate(fine>>4,0,15,p1,p2)>>o);
307 static UWORD getoldperiod(UWORD note,ULONG speed)
309 UWORD n,o;
311 /* This happens sometimes on badly converted AMF, and old MOD */
312 if (!speed) {
313 #ifdef MIKMOD_DEBUG
314 fprintf(stderr,"\rmplayer: getoldperiod() called with note=%d, speed=0 !\n",note);
315 #endif
316 return 4242; /* <- prevent divide overflow.. (42 hehe) */
319 n=note%(2*OCTAVE);
320 o=note/(2*OCTAVE);
321 return ((8363L*(ULONG)oldperiods[n])>>o)/speed;
324 static UWORD GetPeriod(UWORD flags, UWORD note, ULONG speed)
326 if (flags & UF_XMPERIODS) {
327 if (flags & UF_LINEAR)
328 return getlinearperiod(note, speed);
329 else
330 return getlogperiod(note, speed);
331 } else
332 return getoldperiod(note, speed);
335 static SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b)
337 return (Interpolate(p,a->pos,b->pos,a->val,b->val));
340 static SWORD DoPan(SWORD envpan,SWORD pan)
342 int newpan;
344 newpan=pan+(((envpan-PAN_CENTER)*(128-abs(pan-PAN_CENTER)))/128);
346 return (newpan<PAN_LEFT)?PAN_LEFT:(newpan>PAN_RIGHT?PAN_RIGHT:newpan);
349 static SWORD StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE susbeg,UBYTE susend,UBYTE beg,UBYTE end,ENVPT *p,UBYTE keyoff)
351 t->flg=flg;
352 t->pts=pts;
353 t->susbeg=susbeg;
354 t->susend=susend;
355 t->beg=beg;
356 t->end=end;
357 t->env=p;
358 t->p=0;
359 t->a=0;
360 t->b=((t->flg&EF_SUSTAIN)&&(!(keyoff&KEY_OFF)))?0:1;
362 /* Imago Orpheus sometimes stores an extra initial point in the envelope */
363 if ((t->pts>=2)&&(t->env[0].pos==t->env[1].pos)) {
364 t->a++;t->b++;
367 /* Fit in the envelope, still */
368 if (t->a >= t->pts)
369 t->a = t->pts - 1;
370 if (t->b >= t->pts)
371 t->b = t->pts-1;
373 return t->env[t->a].val;
376 /* This procedure processes all envelope types, include volume, pitch, and
377 panning. Envelopes are defined by a set of points, each with a magnitude
378 [relating either to volume, panning position, or pitch modifier] and a tick
379 position.
381 Envelopes work in the following manner:
383 (a) Each tick the envelope is moved a point further in its progression. For
384 an accurate progression, magnitudes between two envelope points are
385 interpolated.
387 (b) When progression reaches a defined point on the envelope, values are
388 shifted to interpolate between this point and the next, and checks for
389 loops or envelope end are done.
391 Misc:
392 Sustain loops are loops that are only active as long as the keyoff flag is
393 clear. When a volume envelope terminates, so does the current fadeout.
395 static SWORD ProcessEnvelope(MP_VOICE *aout, ENVPR *t, SWORD v)
397 if (t->flg & EF_ON) {
398 UBYTE a, b; /* actual points in the envelope */
399 UWORD p; /* the 'tick counter' - real point being played */
401 a = t->a;
402 b = t->b;
403 p = t->p;
406 * Sustain loop on one point (XM type).
407 * Not processed if KEYOFF.
408 * Don't move and don't interpolate when the point is reached
410 if ((t->flg & EF_SUSTAIN) && t->susbeg == t->susend &&
411 (!(aout->main.keyoff & KEY_OFF) && p == t->env[t->susbeg].pos)) {
412 v = t->env[t->susbeg].val;
413 } else {
415 * All following situations will require interpolation between
416 * two envelope points.
420 * Sustain loop between two points (IT type).
421 * Not processed if KEYOFF.
423 /* if we were on a loop point, loop now */
424 if ((t->flg & EF_SUSTAIN) && !(aout->main.keyoff & KEY_OFF) &&
425 a >= t->susend) {
426 a = t->susbeg;
427 b = (t->susbeg==t->susend)?a:a+1;
428 p = t->env[a].pos;
429 v = t->env[a].val;
430 } else
432 * Regular loop.
433 * Be sure to correctly handle single point loops.
435 if ((t->flg & EF_LOOP) && a >= t->end) {
436 a = t->beg;
437 b = t->beg == t->end ? a : a + 1;
438 p = t->env[a].pos;
439 v = t->env[a].val;
440 } else
442 * Non looping situations.
444 if (a != b)
445 v = InterpolateEnv(p, &t->env[a], &t->env[b]);
446 else
447 v = t->env[a].val;
450 * Start to fade if the volume envelope is finished.
452 if (p >= t->env[t->pts - 1].pos) {
453 if (t->flg & EF_VOLENV) {
454 aout->main.keyoff |= KEY_FADE;
455 if (!v)
456 aout->main.fadevol = 0;
458 } else {
459 p++;
460 /* did pointer reach point b? */
461 if (p >= t->env[b].pos)
462 a = b++; /* shift points a and b */
464 t->a = a;
465 t->b = b;
466 t->p = p;
469 return v;
472 /* XM linear period to frequency conversion */
473 ULONG getfrequency(UWORD flags,ULONG period)
475 if (flags & UF_LINEAR) {
476 SLONG shift = ((SLONG)period / 768) - HIGH_OCTAVE;
478 if (shift >= 0)
479 return lintab[period % 768] >> shift;
480 else
481 return lintab[period % 768] << (-shift);
482 } else
483 return (8363L*1712L)/(period?period:1);
486 /*========== Protracker effects */
488 static void DoArpeggio(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE style)
490 UBYTE note=a->main.note;
492 if (a->arpmem) {
493 switch (style) {
494 case 0: /* mod style: N, N+x, N+y */
495 switch (tick % 3) {
496 /* case 0: unchanged */
497 case 1:
498 note += (a->arpmem >> 4);
499 break;
500 case 2:
501 note += (a->arpmem & 0xf);
502 break;
504 break;
505 case 3: /* okt arpeggio 3: N-x, N, N+y */
506 switch (tick % 3) {
507 case 0:
508 note -= (a->arpmem >> 4);
509 break;
510 /* case 1: unchanged */
511 case 2:
512 note += (a->arpmem & 0xf);
513 break;
515 break;
516 case 4: /* okt arpeggio 4: N, N+y, N, N-x */
517 switch (tick % 4) {
518 /* case 0, case 2: unchanged */
519 case 1:
520 note += (a->arpmem & 0xf);
521 break;
522 case 3:
523 note -= (a->arpmem >> 4);
524 break;
526 break;
527 case 5: /* okt arpeggio 5: N-x, N+y, N, and nothing at tick 0 */
528 if (!tick)
529 break;
530 switch (tick % 3) {
531 /* case 0: unchanged */
532 case 1:
533 note -= (a->arpmem >> 4);
534 break;
535 case 2:
536 note += (a->arpmem & 0xf);
537 break;
539 break;
541 a->main.period = GetPeriod(flags, (UWORD)note << 1, a->speed);
542 a->ownper = 1;
546 static int DoPTEffect0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
548 UBYTE dat;
549 (void)mod;
550 (void)channel;
552 dat = UniGetByte();
553 if (!tick) {
554 if (!dat && (flags & UF_ARPMEM))
555 dat=a->arpmem;
556 else
557 a->arpmem=dat;
559 if (a->main.period)
560 DoArpeggio(tick, flags, a, 0);
562 return 0;
565 static int DoPTEffect1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
567 UBYTE dat;
568 (void)flags;
569 (void)mod;
570 (void)channel;
572 dat = UniGetByte();
573 if (!tick && dat)
574 a->slidespeed = (UWORD)dat << 2;
575 if (a->main.period)
576 if (tick)
577 a->tmpperiod -= a->slidespeed;
579 return 0;
582 static int DoPTEffect2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
584 UBYTE dat;
585 (void)flags;
586 (void)mod;
587 (void)channel;
589 dat = UniGetByte();
590 if (!tick && dat)
591 a->slidespeed = (UWORD)dat << 2;
592 if (a->main.period)
593 if (tick)
594 a->tmpperiod += a->slidespeed;
596 return 0;
599 static void DoToneSlide(UWORD tick, MP_CONTROL *a)
601 if (!a->main.fadevol)
602 a->main.kick = (a->main.kick == KICK_NOTE)? KICK_NOTE : KICK_KEYOFF;
603 else
604 a->main.kick = (a->main.kick == KICK_NOTE)? KICK_ENV : KICK_ABSENT;
606 if (tick != 0) {
607 int dist;
609 /* We have to slide a->main.period towards a->wantedperiod, so compute
610 the difference between those two values */
611 dist=a->main.period-a->wantedperiod;
613 /* if they are equal or if portamentospeed is too big ...*/
614 if (dist == 0 || a->portspeed > abs(dist))
615 /* ...make tmpperiod equal tperiod */
616 a->tmpperiod=a->main.period=a->wantedperiod;
617 else if (dist>0) {
618 a->tmpperiod-=a->portspeed;
619 a->main.period-=a->portspeed; /* dist>0, slide up */
620 } else {
621 a->tmpperiod+=a->portspeed;
622 a->main.period+=a->portspeed; /* dist<0, slide down */
624 } else
625 a->tmpperiod=a->main.period;
626 a->ownper = 1;
629 static int DoPTEffect3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
631 UBYTE dat;
632 (void)flags;
633 (void)mod;
634 (void)channel;
636 dat=UniGetByte();
637 if ((!tick)&&(dat)) a->portspeed=(UWORD)dat<<2;
638 if (a->main.period)
639 DoToneSlide(tick, a);
641 return 0;
644 static void DoVibrato(UWORD tick, MP_CONTROL *a)
646 UBYTE q;
647 UWORD temp = 0; /* silence warning */
649 if (!tick)
650 return;
652 q=(a->vibpos>>2)&0x1f;
654 switch (a->wavecontrol&3) {
655 case 0: /* sine */
656 temp=VibratoTable[q];
657 break;
658 case 1: /* ramp down */
659 q<<=3;
660 if (a->vibpos<0) q=255-q;
661 temp=q;
662 break;
663 case 2: /* square wave */
664 temp=255;
665 break;
666 case 3: /* random wave */
667 temp=getrandom(256);
668 break;
671 temp*=a->vibdepth;
672 temp>>=7;temp<<=2;
674 if (a->vibpos>=0)
675 a->main.period=a->tmpperiod+temp;
676 else
677 a->main.period=a->tmpperiod-temp;
678 a->ownper = 1;
680 if (tick != 0)
681 a->vibpos+=a->vibspd;
684 static int DoPTEffect4(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
686 UBYTE dat;
687 (void)flags;
688 (void)mod;
689 (void)channel;
691 dat=UniGetByte();
692 if (!tick) {
693 if (dat&0x0f) a->vibdepth=dat&0xf;
694 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
696 if (a->main.period)
697 DoVibrato(tick, a);
699 return 0;
702 static void DoVolSlide(MP_CONTROL *a, UBYTE dat)
704 if (dat&0xf) {
705 a->tmpvolume-=(dat&0x0f);
706 if (a->tmpvolume<0)
707 a->tmpvolume=0;
708 } else {
709 a->tmpvolume+=(dat>>4);
710 if (a->tmpvolume>64)
711 a->tmpvolume=64;
715 static int DoPTEffect5(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
717 UBYTE dat;
718 (void)flags;
719 (void)mod;
720 (void)channel;
722 dat=UniGetByte();
723 if (a->main.period)
724 DoToneSlide(tick, a);
726 if (tick)
727 DoVolSlide(a, dat);
729 return 0;
732 /* DoPTEffect6 after DoPTEffectA */
734 static int DoPTEffect7(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
736 UBYTE dat;
737 UBYTE q;
738 UWORD temp = 0; /* silence warning */
739 (void)flags;
740 (void)mod;
741 (void)channel;
743 dat=UniGetByte();
744 if (!tick) {
745 if (dat&0x0f) a->trmdepth=dat&0xf;
746 if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;
748 if (a->main.period) {
749 q=(a->trmpos>>2)&0x1f;
751 switch ((a->wavecontrol>>4)&3) {
752 case 0: /* sine */
753 temp=VibratoTable[q];
754 break;
755 case 1: /* ramp down */
756 q<<=3;
757 if (a->trmpos<0) q=255-q;
758 temp=q;
759 break;
760 case 2: /* square wave */
761 temp=255;
762 break;
763 case 3: /* random wave */
764 temp=getrandom(256);
765 break;
767 temp*=a->trmdepth;
768 temp>>=6;
770 if (a->trmpos>=0) {
771 a->volume=a->tmpvolume+temp;
772 if (a->volume>64) a->volume=64;
773 } else {
774 a->volume=a->tmpvolume-temp;
775 if (a->volume<0) a->volume=0;
777 a->ownvol = 1;
779 if (tick)
780 a->trmpos+=a->trmspd;
783 return 0;
786 static int DoPTEffect8(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
788 UBYTE dat;
789 (void)tick;
790 (void)flags;
792 dat = UniGetByte();
793 if (mod->panflag)
794 a->main.panning = mod->panning[channel] = dat;
796 return 0;
799 static int DoPTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
801 UBYTE dat;
802 (void)flags;
803 (void)mod;
804 (void)channel;
806 dat=UniGetByte();
807 if (!tick) {
808 if (dat) a->soffset=(UWORD)dat<<8;
809 a->main.start=a->hioffset|a->soffset;
811 if ((a->main.s)&&(a->main.start > (SLONG)a->main.s->length))
812 a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
813 a->main.s->loopstart:a->main.s->length;
816 return 0;
819 static int DoPTEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
821 UBYTE dat;
822 (void)flags;
823 (void)mod;
824 (void)channel;
826 dat=UniGetByte();
827 if (tick)
828 DoVolSlide(a, dat);
830 return 0;
833 static int DoPTEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
835 if (a->main.period)
836 DoVibrato(tick, a);
837 DoPTEffectA(tick, flags, a, mod, channel);
839 return 0;
842 static int DoPTEffectB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
844 UBYTE dat;
845 (void)a;
846 (void)channel;
848 dat=UniGetByte();
850 if (tick || mod->patdly2)
851 return 0;
853 /* Vincent Voois uses a nasty trick in "Universal Bolero" */
854 if (dat == mod->sngpos && mod->patbrk == mod->patpos)
855 return 0;
857 if (!mod->loop && !mod->patbrk &&
858 (dat < mod->sngpos ||
859 (mod->sngpos == (mod->numpos - 1) && !mod->patbrk) ||
860 (dat == mod->sngpos && (flags & UF_NOWRAP))
861 )) {
862 /* if we don't loop, better not to skip the end of the
863 pattern, after all... so:
864 mod->patbrk=0; */
865 mod->posjmp=3;
866 } else {
867 /* if we were fading, adjust... */
868 if (mod->sngpos == (mod->numpos-1))
869 mod->volume=mod->initvolume>128?128:mod->initvolume;
870 mod->sngpos=dat;
871 mod->posjmp=2;
872 mod->patpos=0;
875 return 0;
878 static int DoPTEffectC(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
880 UBYTE dat;
881 (void)flags;
882 (void)mod;
883 (void)channel;
885 dat=UniGetByte();
886 if (tick) return 0;
887 if (dat==(UBYTE)-1) a->anote=dat=0; /* note cut */
888 else if (dat>64) dat=64;
889 a->tmpvolume=dat;
891 return 0;
894 static int DoPTEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
896 UBYTE dat;
897 (void)a;
898 (void)channel;
900 dat=UniGetByte();
901 if ((tick)||(mod->patdly2)) return 0;
902 if ((mod->positions[mod->sngpos]!=LAST_PATTERN)&&
903 (dat>mod->pattrows[mod->positions[mod->sngpos]]))
904 dat=mod->pattrows[mod->positions[mod->sngpos]];
905 mod->patbrk=dat;
906 if (!mod->posjmp) {
907 /* don't ask me to explain this code - it makes
908 backwards.s3m and children.xm (heretic's version) play
909 correctly, among others. Take that for granted, or write
910 the page of comments yourself... you might need some
911 aspirin - Miod */
912 if ((mod->sngpos==mod->numpos-1)&&(dat)&&((mod->loop)||
913 (mod->positions[mod->sngpos]==(mod->numpat-1)
914 && !(flags&UF_NOWRAP)))) {
915 mod->sngpos=0;
916 mod->posjmp=2;
917 } else
918 mod->posjmp=3;
921 return 0;
924 static void DoEEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod,
925 SWORD channel, UBYTE dat)
927 UBYTE nib = dat & 0xf;
929 switch (dat>>4) {
930 case 0x0: /* hardware filter toggle, not supported */
931 break;
932 case 0x1: /* fineslide up */
933 if (a->main.period)
934 if (!tick)
935 a->tmpperiod-=(nib<<2);
936 break;
937 case 0x2: /* fineslide dn */
938 if (a->main.period)
939 if (!tick)
940 a->tmpperiod+=(nib<<2);
941 break;
942 case 0x3: /* glissando ctrl */
943 a->glissando=nib;
944 break;
945 case 0x4: /* set vibrato waveform */
946 a->wavecontrol&=0xf0;
947 a->wavecontrol|=nib;
948 break;
949 case 0x5: /* set finetune */
950 if (a->main.period) {
951 if (flags&UF_XMPERIODS)
952 a->speed=nib+128;
953 else
954 a->speed=finetune[nib];
955 a->tmpperiod=GetPeriod(flags, (UWORD)a->main.note<<1,a->speed);
957 break;
958 case 0x6: /* set patternloop */
959 if (tick)
960 break;
961 if (nib) { /* set reppos or repcnt ? */
962 /* set repcnt, so check if repcnt already is set, which means we
963 are already looping */
964 if (a->pat_repcnt)
965 a->pat_repcnt--; /* already looping, decrease counter */
966 else {
967 #if 0
968 /* this would make walker.xm, shipped with Xsoundtracker,
969 play correctly, but it's better to remain compatible
970 with FT2 */
971 if ((!(flags&UF_NOWRAP))||(a->pat_reppos!=POS_NONE))
972 #endif
973 a->pat_repcnt=nib; /* not yet looping, so set repcnt */
976 if (a->pat_repcnt) { /* jump to reppos if repcnt>0 */
977 if (a->pat_reppos==POS_NONE)
978 a->pat_reppos=mod->patpos-1;
979 if (a->pat_reppos==-1) {
980 mod->pat_repcrazy=1;
981 mod->patpos=0;
982 } else
983 mod->patpos=a->pat_reppos;
984 } else a->pat_reppos=POS_NONE;
985 } else
986 a->pat_reppos=mod->patpos-1; /* set reppos - can be (-1) */
987 break;
988 case 0x7: /* set tremolo waveform */
989 a->wavecontrol&=0x0f;
990 a->wavecontrol|=nib<<4;
991 break;
992 case 0x8: /* set panning */
993 if (mod->panflag) {
994 if (nib<=8) nib<<=4;
995 else nib*=17;
996 a->main.panning=mod->panning[channel]=nib;
998 break;
999 case 0x9: /* retrig note */
1000 /* do not retrigger on tick 0, until we are emulating FT2 and effect
1001 data is zero */
1002 if (!tick && !((flags & UF_FT2QUIRKS) && (!nib)))
1003 break;
1004 /* only retrigger if data nibble > 0, or if tick 0 (FT2 compat) */
1005 if (nib || !tick) {
1006 if (!a->retrig) {
1007 /* when retrig counter reaches 0, reset counter and restart
1008 the sample */
1009 if (a->main.period) a->main.kick=KICK_NOTE;
1010 a->retrig=nib;
1012 a->retrig--; /* countdown */
1014 break;
1015 case 0xa: /* fine volume slide up */
1016 if (tick)
1017 break;
1018 a->tmpvolume+=nib;
1019 if (a->tmpvolume>64) a->tmpvolume=64;
1020 break;
1021 case 0xb: /* fine volume slide dn */
1022 if (tick)
1023 break;
1024 a->tmpvolume-=nib;
1025 if (a->tmpvolume<0)a->tmpvolume=0;
1026 break;
1027 case 0xc: /* cut note */
1028 /* When tick reaches the cut-note value, turn the volume to
1029 zero (just like on the amiga) */
1030 if (tick>=nib)
1031 a->tmpvolume=0; /* just turn the volume down */
1032 break;
1033 case 0xd: /* note delay */
1034 /* delay the start of the sample until tick==nib */
1035 if (!tick)
1036 a->main.notedelay=nib;
1037 else if (a->main.notedelay)
1038 a->main.notedelay--;
1039 break;
1040 case 0xe: /* pattern delay */
1041 if (!tick)
1042 if (!mod->patdly2)
1043 mod->patdly=nib+1; /* only once, when tick=0 */
1044 break;
1045 case 0xf: /* invert loop, not supported */
1046 break;
1050 static int DoPTEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1052 DoEEffects(tick, flags, a, mod, channel, UniGetByte());
1054 return 0;
1057 static int DoPTEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1059 UBYTE dat;
1060 (void)flags;
1061 (void)a;
1062 (void)channel;
1064 dat=UniGetByte();
1065 if (tick||mod->patdly2) return 0;
1066 if (mod->extspd&&(dat>=mod->bpmlimit))
1067 mod->bpm=dat;
1068 else
1069 if (dat) {
1070 mod->sngspd=(dat>=mod->bpmlimit)?mod->bpmlimit-1:dat;
1071 mod->vbtick=0;
1074 return 0;
1077 /*========== Scream Tracker effects */
1079 static int DoS3MEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1081 UBYTE speed;
1082 (void)flags;
1083 (void)a;
1084 (void)channel;
1086 speed = UniGetByte();
1088 if (tick || mod->patdly2)
1089 return 0;
1091 if (speed > 128)
1092 speed -= 128;
1093 if (speed) {
1094 mod->sngspd = speed;
1095 mod->vbtick = 0;
1098 return 0;
1101 static void DoS3MVolSlide(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE inf)
1103 UBYTE lo, hi;
1105 if (inf)
1106 a->s3mvolslide=inf;
1107 else
1108 inf=a->s3mvolslide;
1110 lo=inf&0xf;
1111 hi=inf>>4;
1113 if (!lo) {
1114 if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume+=hi;
1115 } else
1116 if (!hi) {
1117 if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume-=lo;
1118 } else
1119 if (lo==0xf) {
1120 if (!tick) a->tmpvolume+=(hi?hi:0xf);
1121 } else
1122 if (hi==0xf) {
1123 if (!tick) a->tmpvolume-=(lo?lo:0xf);
1124 } else
1125 return;
1127 if (a->tmpvolume<0)
1128 a->tmpvolume=0;
1129 else if (a->tmpvolume>64)
1130 a->tmpvolume=64;
1133 static int DoS3MEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1135 (void)mod;
1136 (void)channel;
1138 DoS3MVolSlide(tick, flags, a, UniGetByte());
1140 return 1;
1143 static void DoS3MSlideDn(UWORD tick, MP_CONTROL *a, UBYTE inf)
1145 UBYTE hi,lo;
1147 if (inf)
1148 a->slidespeed=inf;
1149 else
1150 inf=a->slidespeed;
1152 hi=inf>>4;
1153 lo=inf&0xf;
1155 if (hi==0xf) {
1156 if (!tick) a->tmpperiod+=(UWORD)lo<<2;
1157 } else
1158 if (hi==0xe) {
1159 if (!tick) a->tmpperiod+=lo;
1160 } else {
1161 if (tick) a->tmpperiod+=(UWORD)inf<<2;
1165 static int DoS3MEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1167 UBYTE dat;
1168 (void)flags;
1169 (void)mod;
1170 (void)channel;
1172 dat=UniGetByte();
1173 if (a->main.period)
1174 DoS3MSlideDn(tick, a,dat);
1176 return 0;
1179 static void DoS3MSlideUp(UWORD tick, MP_CONTROL *a, UBYTE inf)
1181 UBYTE hi,lo;
1183 if (inf) a->slidespeed=inf;
1184 else inf=a->slidespeed;
1186 hi=inf>>4;
1187 lo=inf&0xf;
1189 if (hi==0xf) {
1190 if (!tick) a->tmpperiod-=(UWORD)lo<<2;
1191 } else
1192 if (hi==0xe) {
1193 if (!tick) a->tmpperiod-=lo;
1194 } else {
1195 if (tick) a->tmpperiod-=(UWORD)inf<<2;
1199 static int DoS3MEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1201 UBYTE dat;
1202 (void)flags;
1203 (void)mod;
1204 (void)channel;
1206 dat=UniGetByte();
1207 if (a->main.period)
1208 DoS3MSlideUp(tick, a,dat);
1210 return 0;
1213 static int DoS3MEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1215 UBYTE inf, on, off;
1216 (void)flags;
1217 (void)mod;
1218 (void)channel;
1220 inf = UniGetByte();
1221 if (inf)
1222 a->s3mtronof = inf;
1223 else {
1224 inf = a->s3mtronof;
1225 if (!inf)
1226 return 0;
1229 if (!tick)
1230 return 0;
1232 on=(inf>>4)+1;
1233 off=(inf&0xf)+1;
1234 a->s3mtremor%=(on+off);
1235 a->volume=(a->s3mtremor<on)?a->tmpvolume:0;
1236 a->ownvol=1;
1237 a->s3mtremor++;
1239 return 0;
1242 static int DoS3MEffectQ(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1244 UBYTE inf;
1245 (void)mod;
1246 (void)channel;
1248 inf = UniGetByte();
1249 if (a->main.period) {
1250 if (inf) {
1251 a->s3mrtgslide=inf>>4;
1252 a->s3mrtgspeed=inf&0xf;
1255 /* only retrigger if low nibble > 0 */
1256 if (a->s3mrtgspeed>0) {
1257 if (!a->retrig) {
1258 /* when retrig counter reaches 0, reset counter and restart the
1259 sample */
1260 if (a->main.kick!=KICK_NOTE) a->main.kick=KICK_KEYOFF;
1261 a->retrig=a->s3mrtgspeed;
1263 if ((tick)||(flags&UF_S3MSLIDES)) {
1264 switch (a->s3mrtgslide) {
1265 case 1:
1266 case 2:
1267 case 3:
1268 case 4:
1269 case 5:
1270 a->tmpvolume-=(1<<(a->s3mrtgslide-1));
1271 break;
1272 case 6:
1273 a->tmpvolume=(2*a->tmpvolume)/3;
1274 break;
1275 case 7:
1276 a->tmpvolume>>=1;
1277 break;
1278 case 9:
1279 case 0xa:
1280 case 0xb:
1281 case 0xc:
1282 case 0xd:
1283 a->tmpvolume+=(1<<(a->s3mrtgslide-9));
1284 break;
1285 case 0xe:
1286 a->tmpvolume=(3*a->tmpvolume)>>1;
1287 break;
1288 case 0xf:
1289 a->tmpvolume=a->tmpvolume<<1;
1290 break;
1292 if (a->tmpvolume<0)
1293 a->tmpvolume=0;
1294 else if (a->tmpvolume>64)
1295 a->tmpvolume=64;
1298 a->retrig--; /* countdown */
1302 return 0;
1305 static int DoS3MEffectR(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1307 UBYTE dat, q;
1308 UWORD temp=0; /* silence warning */
1309 (void)flags;
1310 (void)mod;
1311 (void)channel;
1313 dat = UniGetByte();
1314 if (!tick) {
1315 if (dat&0x0f) a->trmdepth=dat&0xf;
1316 if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;
1319 q=(a->trmpos>>2)&0x1f;
1321 switch ((a->wavecontrol>>4)&3) {
1322 case 0: /* sine */
1323 temp=VibratoTable[q];
1324 break;
1325 case 1: /* ramp down */
1326 q<<=3;
1327 if (a->trmpos<0) q=255-q;
1328 temp=q;
1329 break;
1330 case 2: /* square wave */
1331 temp=255;
1332 break;
1333 case 3: /* random */
1334 temp=getrandom(256);
1335 break;
1338 temp*=a->trmdepth;
1339 temp>>=7;
1341 if (a->trmpos>=0) {
1342 a->volume=a->tmpvolume+temp;
1343 if (a->volume>64) a->volume=64;
1344 } else {
1345 a->volume=a->tmpvolume-temp;
1346 if (a->volume<0) a->volume=0;
1348 a->ownvol = 1;
1350 if (tick)
1351 a->trmpos+=a->trmspd;
1353 return 0;
1356 static int DoS3MEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1358 UBYTE tempo;
1359 (void)flags;
1360 (void)a;
1361 (void)channel;
1363 tempo = UniGetByte();
1365 if (tick || mod->patdly2)
1366 return 0;
1368 mod->bpm = (tempo < 32) ? 32 : tempo;
1370 return 0;
1373 static int DoS3MEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1375 UBYTE dat, q;
1376 UWORD temp = 0; /* silence warning */
1377 (void)flags;
1378 (void)mod;
1379 (void)channel;
1381 dat = UniGetByte();
1382 if (!tick) {
1383 if (dat&0x0f) a->vibdepth=dat&0xf;
1384 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
1385 } else
1386 if (a->main.period) {
1387 q=(a->vibpos>>2)&0x1f;
1389 switch (a->wavecontrol&3) {
1390 case 0: /* sine */
1391 temp=VibratoTable[q];
1392 break;
1393 case 1: /* ramp down */
1394 q<<=3;
1395 if (a->vibpos<0) q=255-q;
1396 temp=q;
1397 break;
1398 case 2: /* square wave */
1399 temp=255;
1400 break;
1401 case 3: /* random */
1402 temp=getrandom(256);
1403 break;
1406 temp*=a->vibdepth;
1407 temp>>=8;
1409 if (a->vibpos>=0)
1410 a->main.period=a->tmpperiod+temp;
1411 else
1412 a->main.period=a->tmpperiod-temp;
1413 a->ownper = 1;
1415 a->vibpos+=a->vibspd;
1418 return 0;
1421 /*========== Envelope helpers */
1423 static int DoKeyOff(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1425 (void)tick;
1426 (void)flags;
1427 (void)mod;
1428 (void)channel;
1429 a->main.keyoff|=KEY_OFF;
1430 if ((!(a->main.volflg&EF_ON))||(a->main.volflg&EF_LOOP))
1431 a->main.keyoff=KEY_KILL;
1433 return 0;
1436 static int DoKeyFade(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1438 UBYTE dat;
1439 (void)flags;
1440 (void)channel;
1442 dat=UniGetByte();
1443 if ((tick>=dat)||(tick==mod->sngspd-1)) {
1444 a->main.keyoff=KEY_KILL;
1445 if (!(a->main.volflg&EF_ON))
1446 a->main.fadevol=0;
1449 return 0;
1452 /*========== Fast Tracker effects */
1454 /* DoXMEffect6 after DoXMEffectA */
1456 static int DoXMEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1458 UBYTE inf, lo, hi;
1459 (void)flags;
1460 (void)mod;
1461 (void)channel;
1463 inf = UniGetByte();
1464 if (inf)
1465 a->s3mvolslide = inf;
1466 else
1467 inf = a->s3mvolslide;
1469 if (tick) {
1470 lo=inf&0xf;
1471 hi=inf>>4;
1473 if (!hi) {
1474 a->tmpvolume-=lo;
1475 if (a->tmpvolume<0) a->tmpvolume=0;
1476 } else {
1477 a->tmpvolume+=hi;
1478 if (a->tmpvolume>64) a->tmpvolume=64;
1482 return 0;
1485 static int DoXMEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1487 (void)flags;
1488 (void)mod;
1489 (void)channel;
1490 if (a->main.period)
1491 DoVibrato(tick, a);
1493 return DoXMEffectA(tick, flags, a, mod, channel);
1496 static int DoXMEffectE1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1498 UBYTE dat;
1499 (void)flags;
1500 (void)mod;
1501 (void)channel;
1503 dat=UniGetByte();
1504 if (!tick) {
1505 if (dat) a->fportupspd=dat;
1506 if (a->main.period)
1507 a->tmpperiod-=(a->fportupspd<<2);
1510 return 0;
1513 static int DoXMEffectE2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1515 UBYTE dat;
1516 (void)flags;
1517 (void)mod;
1518 (void)channel;
1520 dat=UniGetByte();
1521 if (!tick) {
1522 if (dat) a->fportdnspd=dat;
1523 if (a->main.period)
1524 a->tmpperiod+=(a->fportdnspd<<2);
1527 return 0;
1530 static int DoXMEffectEA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1532 UBYTE dat;
1533 (void)flags;
1534 (void)mod;
1535 (void)channel;
1537 dat=UniGetByte();
1538 if (!tick)
1539 if (dat) a->fslideupspd=dat;
1540 a->tmpvolume+=a->fslideupspd;
1541 if (a->tmpvolume>64) a->tmpvolume=64;
1543 return 0;
1546 static int DoXMEffectEB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1548 UBYTE dat;
1549 (void)flags;
1550 (void)mod;
1551 (void)channel;
1553 dat=UniGetByte();
1554 if (!tick)
1555 if (dat) a->fslidednspd=dat;
1556 a->tmpvolume-=a->fslidednspd;
1557 if (a->tmpvolume<0) a->tmpvolume=0;
1559 return 0;
1562 static int DoXMEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1564 (void)tick;
1565 (void)flags;
1566 (void)a;
1567 (void)channel;
1568 mod->volume=UniGetByte()<<1;
1569 if (mod->volume>128) mod->volume=128;
1571 return 0;
1574 static int DoXMEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1576 UBYTE inf;
1577 (void)flags;
1578 (void)a;
1579 (void)channel;
1581 inf = UniGetByte();
1583 if (tick) {
1584 if (inf) mod->globalslide=inf;
1585 else inf=mod->globalslide;
1586 if (inf & 0xf0) inf&=0xf0;
1587 mod->volume=mod->volume+((inf>>4)-(inf&0xf))*2;
1589 if (mod->volume<0)
1590 mod->volume=0;
1591 else if (mod->volume>128)
1592 mod->volume=128;
1595 return 0;
1598 static int DoXMEffectL(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1600 UBYTE dat;
1601 (void)flags;
1602 (void)mod;
1603 (void)channel;
1605 dat=UniGetByte();
1606 if ((!tick)&&(a->main.i)) {
1607 UWORD points;
1608 INSTRUMENT *i=a->main.i;
1609 MP_VOICE *aout;
1611 if ((aout=a->slave)) {
1612 if (aout->venv.env) {
1613 points=i->volenv[i->volpts-1].pos;
1614 aout->venv.p=aout->venv.env[(dat>points)?points:dat].pos;
1616 if (aout->penv.env) {
1617 points=i->panenv[i->panpts-1].pos;
1618 aout->penv.p=aout->penv.env[(dat>points)?points:dat].pos;
1623 return 0;
1626 static int DoXMEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1628 UBYTE inf, lo, hi;
1629 SWORD pan;
1630 (void)flags;
1631 (void)channel;
1633 inf = UniGetByte();
1634 if (!mod->panflag)
1635 return 0;
1637 if (inf)
1638 a->pansspd = inf;
1639 else
1640 inf =a->pansspd;
1642 if (tick) {
1643 lo=inf&0xf;
1644 hi=inf>>4;
1646 /* slide right has absolute priority */
1647 if (hi)
1648 lo = 0;
1650 pan=((a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning)+hi-lo;
1651 a->main.panning=(pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);
1654 return 0;
1657 static int DoXMEffectX1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1659 UBYTE dat;
1660 (void)flags;
1661 (void)mod;
1662 (void)channel;
1664 dat = UniGetByte();
1665 if (dat)
1666 a->ffportupspd = dat;
1667 else
1668 dat = a->ffportupspd;
1670 if (a->main.period)
1671 if (!tick) {
1672 a->main.period-=dat;
1673 a->tmpperiod-=dat;
1674 a->ownper = 1;
1677 return 0;
1680 static int DoXMEffectX2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1682 UBYTE dat;
1683 (void)flags;
1684 (void)mod;
1685 (void)channel;
1687 dat = UniGetByte();
1688 if (dat)
1689 a->ffportdnspd=dat;
1690 else
1691 dat = a->ffportdnspd;
1693 if (a->main.period)
1694 if (!tick) {
1695 a->main.period+=dat;
1696 a->tmpperiod+=dat;
1697 a->ownper = 1;
1700 return 0;
1703 /*========== Impulse Tracker effects */
1705 static void DoITToneSlide(UWORD tick, MP_CONTROL *a, UBYTE dat)
1707 if (dat)
1708 a->portspeed = dat;
1710 /* if we don't come from another note, ignore the slide and play the note
1711 as is */
1712 if (!a->oldnote || !a->main.period)
1713 return;
1715 if ((!tick)&&(a->newsamp)){
1716 a->main.kick=KICK_NOTE;
1717 a->main.start=-1;
1718 } else
1719 a->main.kick=(a->main.kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT;
1721 if (tick) {
1722 int dist;
1724 /* We have to slide a->main.period towards a->wantedperiod, compute the
1725 difference between those two values */
1726 dist=a->main.period-a->wantedperiod;
1728 /* if they are equal or if portamentospeed is too big... */
1729 if ((!dist)||((a->portspeed<<2)>abs(dist)))
1730 /* ... make tmpperiod equal tperiod */
1731 a->tmpperiod=a->main.period=a->wantedperiod;
1732 else
1733 if (dist>0) {
1734 a->tmpperiod-=a->portspeed<<2;
1735 a->main.period-=a->portspeed<<2; /* dist>0 slide up */
1736 } else {
1737 a->tmpperiod+=a->portspeed<<2;
1738 a->main.period+=a->portspeed<<2; /* dist<0 slide down */
1740 } else
1741 a->tmpperiod=a->main.period;
1742 a->ownper=1;
1745 static int DoITEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1747 (void)flags;
1748 (void)mod;
1749 (void)channel;
1750 DoITToneSlide(tick, a, UniGetByte());
1752 return 0;
1755 static void DoITVibrato(UWORD tick, MP_CONTROL *a, UBYTE dat)
1757 UBYTE q;
1758 UWORD temp=0;
1760 if (!tick) {
1761 if (dat&0x0f) a->vibdepth=dat&0xf;
1762 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
1764 if (!a->main.period)
1765 return;
1767 q=(a->vibpos>>2)&0x1f;
1769 switch (a->wavecontrol&3) {
1770 case 0: /* sine */
1771 temp=VibratoTable[q];
1772 break;
1773 case 1: /* square wave */
1774 temp=255;
1775 break;
1776 case 2: /* ramp down */
1777 q<<=3;
1778 if (a->vibpos<0) q=255-q;
1779 temp=q;
1780 break;
1781 case 3: /* random */
1782 temp=getrandom(256);
1783 break;
1786 temp*=a->vibdepth;
1787 temp>>=8;
1788 temp<<=2;
1790 if (a->vibpos>=0)
1791 a->main.period=a->tmpperiod+temp;
1792 else
1793 a->main.period=a->tmpperiod-temp;
1794 a->ownper=1;
1796 a->vibpos+=a->vibspd;
1799 static int DoITEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1801 (void)flags;
1802 (void)mod;
1803 (void)channel;
1804 DoITVibrato(tick, a, UniGetByte());
1806 return 0;
1809 static int DoITEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1811 UBYTE inf, on, off;
1812 (void)tick;
1813 (void)flags;
1814 (void)mod;
1815 (void)channel;
1817 inf = UniGetByte();
1818 if (inf)
1819 a->s3mtronof = inf;
1820 else {
1821 inf = a->s3mtronof;
1822 if (!inf)
1823 return 0;
1826 on=(inf>>4);
1827 off=(inf&0xf);
1829 a->s3mtremor%=(on+off);
1830 a->volume=(a->s3mtremor<on)?a->tmpvolume:0;
1831 a->ownvol = 1;
1832 a->s3mtremor++;
1834 return 0;
1837 static int DoITEffectM(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1839 (void)tick;
1840 (void)flags;
1841 (void)mod;
1842 (void)channel;
1843 a->main.chanvol=UniGetByte();
1844 if (a->main.chanvol>64)
1845 a->main.chanvol=64;
1846 else if (a->main.chanvol<0)
1847 a->main.chanvol=0;
1849 return 0;
1852 static int DoITEffectN(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1854 UBYTE inf, lo, hi;
1855 (void)tick;
1856 (void)flags;
1857 (void)mod;
1858 (void)channel;
1860 inf = UniGetByte();
1862 if (inf)
1863 a->chanvolslide = inf;
1864 else
1865 inf = a->chanvolslide;
1867 lo=inf&0xf;
1868 hi=inf>>4;
1870 if (!hi)
1871 a->main.chanvol-=lo;
1872 else
1873 if (!lo) {
1874 a->main.chanvol+=hi;
1875 } else
1876 if (hi==0xf) {
1877 if (!tick) a->main.chanvol-=lo;
1878 } else
1879 if (lo==0xf) {
1880 if (!tick) a->main.chanvol+=hi;
1883 if (a->main.chanvol<0)
1884 a->main.chanvol=0;
1885 else if (a->main.chanvol>64)
1886 a->main.chanvol=64;
1888 return 0;
1891 static int DoITEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1893 UBYTE inf, lo, hi;
1894 SWORD pan;
1895 (void)flags;
1896 (void)mod;
1897 (void)channel;
1899 inf = UniGetByte();
1900 if (inf)
1901 a->pansspd = inf;
1902 else
1903 inf = a->pansspd;
1905 if (!mod->panflag)
1906 return 0;
1908 lo=inf&0xf;
1909 hi=inf>>4;
1911 pan=(a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning;
1913 if (!hi)
1914 pan+=lo<<2;
1915 else
1916 if (!lo) {
1917 pan-=hi<<2;
1918 } else
1919 if (hi==0xf) {
1920 if (!tick) pan+=lo<<2;
1921 } else
1922 if (lo==0xf) {
1923 if (!tick) pan-=hi<<2;
1925 a->main.panning=
1926 (pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);
1928 return 0;
1931 static int DoITEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1933 UBYTE tempo;
1934 SWORD temp;
1935 (void)tick;
1936 (void)flags;
1937 (void)a;
1938 (void)channel;
1940 tempo = UniGetByte();
1942 if (mod->patdly2)
1943 return 0;
1945 temp = mod->bpm;
1946 if (tempo & 0x10)
1947 temp += (tempo & 0x0f);
1948 else
1949 temp -= tempo;
1951 mod->bpm=(temp>255)?255:(temp<1?1:temp);
1953 return 0;
1956 static int DoITEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1958 UBYTE dat, q;
1959 UWORD temp = 0; /* silence warning */
1960 (void)flags;
1961 (void)mod;
1962 (void)channel;
1964 dat = UniGetByte();
1965 if (!tick) {
1966 if (dat&0x0f) a->vibdepth=dat&0xf;
1967 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
1969 if (a->main.period) {
1970 q=(a->vibpos>>2)&0x1f;
1972 switch (a->wavecontrol&3) {
1973 case 0: /* sine */
1974 temp=VibratoTable[q];
1975 break;
1976 case 1: /* square wave */
1977 temp=255;
1978 break;
1979 case 2: /* ramp down */
1980 q<<=3;
1981 if (a->vibpos<0) q=255-q;
1982 temp=q;
1983 break;
1984 case 3: /* random */
1985 temp=getrandom(256);
1986 break;
1989 temp*=a->vibdepth;
1990 temp>>=8;
1992 if (a->vibpos>=0)
1993 a->main.period=a->tmpperiod+temp;
1994 else
1995 a->main.period=a->tmpperiod-temp;
1996 a->ownper = 1;
1998 a->vibpos+=a->vibspd;
2001 return 0;
2004 static int DoITEffectW(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2006 UBYTE inf, lo, hi;
2007 (void)flags;
2008 (void)a;
2009 (void)channel;
2011 inf = UniGetByte();
2013 if (inf)
2014 mod->globalslide = inf;
2015 else
2016 inf = mod->globalslide;
2018 lo=inf&0xf;
2019 hi=inf>>4;
2021 if (!lo) {
2022 if (tick) mod->volume+=hi;
2023 } else
2024 if (!hi) {
2025 if (tick) mod->volume-=lo;
2026 } else
2027 if (lo==0xf) {
2028 if (!tick) mod->volume+=hi;
2029 } else
2030 if (hi==0xf) {
2031 if (!tick) mod->volume-=lo;
2034 if (mod->volume<0)
2035 mod->volume=0;
2036 else if (mod->volume>128)
2037 mod->volume=128;
2039 return 0;
2042 static int DoITEffectY(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2044 UBYTE dat, q;
2045 SLONG temp = 0; /* silence warning */
2046 (void)flags;
2049 dat=UniGetByte();
2050 if (!tick) {
2051 if (dat&0x0f) a->panbdepth=(dat&0xf);
2052 if (dat&0xf0) a->panbspd=(dat&0xf0)>>4;
2054 if (mod->panflag) {
2055 q=a->panbpos;
2057 switch (a->panbwave) {
2058 case 0: /* sine */
2059 temp=PanbrelloTable[q];
2060 break;
2061 case 1: /* square wave */
2062 temp=(q<0x80)?64:0;
2063 break;
2064 case 2: /* ramp down */
2065 q<<=3;
2066 temp=q;
2067 break;
2068 case 3: /* random */
2069 temp=getrandom(256);
2070 break;
2073 temp*=a->panbdepth;
2074 temp=(temp/8)+mod->panning[channel];
2076 a->main.panning=
2077 (temp<PAN_LEFT)?PAN_LEFT:(temp>PAN_RIGHT?PAN_RIGHT:temp);
2078 a->panbpos+=a->panbspd;
2082 return 0;
2085 static void DoNNAEffects(MODULE *, MP_CONTROL *, UBYTE);
2087 /* Impulse/Scream Tracker Sxx effects.
2088 All Sxx effects share the same memory space. */
2089 static int DoITEffectS0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2091 UBYTE dat, inf, c;
2093 dat = UniGetByte();
2094 inf=dat&0xf;
2095 c=dat>>4;
2097 if (!dat) {
2098 c=a->sseffect;
2099 inf=a->ssdata;
2100 } else {
2101 a->sseffect=c;
2102 a->ssdata=inf;
2105 switch (c) {
2106 case SS_GLISSANDO: /* S1x set glissando voice */
2107 DoEEffects(tick, flags, a, mod, channel, 0x30|inf);
2108 break;
2109 case SS_FINETUNE: /* S2x set finetune */
2110 DoEEffects(tick, flags, a, mod, channel, 0x50|inf);
2111 break;
2112 case SS_VIBWAVE: /* S3x set vibrato waveform */
2113 DoEEffects(tick, flags, a, mod, channel, 0x40|inf);
2114 break;
2115 case SS_TREMWAVE: /* S4x set tremolo waveform */
2116 DoEEffects(tick, flags, a, mod, channel, 0x70|inf);
2117 break;
2118 case SS_PANWAVE: /* S5x panbrello */
2119 a->panbwave=inf;
2120 break;
2121 case SS_FRAMEDELAY: /* S6x delay x number of frames (patdly) */
2122 DoEEffects(tick, flags, a, mod, channel, 0xe0|inf);
2123 break;
2124 case SS_S7EFFECTS: /* S7x instrument / NNA commands */
2125 DoNNAEffects(mod, a, inf);
2126 break;
2127 case SS_PANNING: /* S8x set panning position */
2128 DoEEffects(tick, flags, a, mod, channel, 0x80 | inf);
2129 break;
2130 case SS_SURROUND: /* S9x set surround sound */
2131 if (mod->panflag)
2132 a->main.panning = mod->panning[channel] = PAN_SURROUND;
2133 break;
2134 case SS_HIOFFSET: /* SAy set high order sample offset yxx00h */
2135 if (!tick) {
2136 a->hioffset=inf<<16;
2137 a->main.start=a->hioffset|a->soffset;
2139 if ((a->main.s)&&(a->main.start > (SLONG)a->main.s->length))
2140 a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
2141 a->main.s->loopstart:a->main.s->length;
2143 break;
2144 case SS_PATLOOP: /* SBx pattern loop */
2145 DoEEffects(tick, flags, a, mod, channel, 0x60|inf);
2146 break;
2147 case SS_NOTECUT: /* SCx notecut */
2148 if (!inf) inf = 1;
2149 DoEEffects(tick, flags, a, mod, channel, 0xC0|inf);
2150 break;
2151 case SS_NOTEDELAY: /* SDx notedelay */
2152 DoEEffects(tick, flags, a, mod, channel, 0xD0|inf);
2153 break;
2154 case SS_PATDELAY: /* SEx patterndelay */
2155 DoEEffects(tick, flags, a, mod, channel, 0xE0|inf);
2156 break;
2159 return 0;
2162 /*========== Impulse Tracker Volume/Pan Column effects */
2165 * All volume/pan column effects share the same memory space.
2168 static int DoVolEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2170 UBYTE c, inf;
2171 (void)channel;
2173 c = UniGetByte();
2174 inf = UniGetByte();
2176 if ((!c)&&(!inf)) {
2177 c=a->voleffect;
2178 inf=a->voldata;
2179 } else {
2180 a->voleffect=c;
2181 a->voldata=inf;
2184 if (c)
2185 switch (c) {
2186 case VOL_VOLUME:
2187 if (tick) break;
2188 if (inf>64) inf=64;
2189 a->tmpvolume=inf;
2190 break;
2191 case VOL_PANNING:
2192 if (mod->panflag)
2193 a->main.panning=inf;
2194 break;
2195 case VOL_VOLSLIDE:
2196 DoS3MVolSlide(tick, flags, a, inf);
2197 return 1;
2198 case VOL_PITCHSLIDEDN:
2199 if (a->main.period)
2200 DoS3MSlideDn(tick, a, inf);
2201 break;
2202 case VOL_PITCHSLIDEUP:
2203 if (a->main.period)
2204 DoS3MSlideUp(tick, a, inf);
2205 break;
2206 case VOL_PORTAMENTO:
2207 DoITToneSlide(tick, a, inf);
2208 break;
2209 case VOL_VIBRATO:
2210 DoITVibrato(tick, a, inf);
2211 break;
2214 return 0;
2217 /*========== UltraTracker effects */
2219 static int DoULTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2221 UWORD offset=UniGetWord();
2222 (void)tick;
2223 (void)flags;
2224 (void)mod;
2225 (void)channel;
2227 if (offset)
2228 a->ultoffset=offset;
2230 a->main.start=a->ultoffset<<2;
2231 if ((a->main.s)&&(a->main.start > (SLONG)a->main.s->length))
2232 a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
2233 a->main.s->loopstart:a->main.s->length;
2235 return 0;
2238 /*========== OctaMED effects */
2240 static int DoMEDSpeed(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2242 UWORD speed=UniGetWord();
2243 (void)tick;
2244 (void)flags;
2245 (void)a;
2246 (void)channel;
2248 mod->bpm=speed;
2250 return 0;
2253 static int DoMEDEffectF1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2255 DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/2));
2257 return 0;
2260 static int DoMEDEffectF2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2262 DoEEffects(tick, flags, a, mod, channel, 0xd0|(mod->sngspd/2));
2264 return 0;
2267 static int DoMEDEffectF3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2269 DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/3));
2271 return 0;
2274 /*========== Oktalyzer effects */
2276 static int DoOktArp(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2278 UBYTE dat, dat2;
2279 (void)mod;
2280 (void)channel;
2282 dat2 = UniGetByte(); /* arpeggio style */
2283 dat = UniGetByte();
2284 if (!tick) {
2285 if (!dat && (flags & UF_ARPMEM))
2286 dat=a->arpmem;
2287 else
2288 a->arpmem=dat;
2290 if (a->main.period)
2291 DoArpeggio(tick, flags, a, dat2);
2293 return 0;
2296 /*========== General player functions */
2298 static int DoNothing(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2300 (void)tick;
2301 (void)flags;
2302 (void)a;
2303 (void)mod;
2304 (void)channel;
2305 UniSkipOpcode();
2307 return 0;
2310 typedef int (*effect_func) (UWORD, UWORD, MP_CONTROL *, MODULE *, SWORD);
2312 static effect_func effects[UNI_LAST] = {
2313 DoNothing, /* 0 */
2314 DoNothing, /* UNI_NOTE */
2315 DoNothing, /* UNI_INSTRUMENT */
2316 DoPTEffect0, /* UNI_PTEFFECT0 */
2317 DoPTEffect1, /* UNI_PTEFFECT1 */
2318 DoPTEffect2, /* UNI_PTEFFECT2 */
2319 DoPTEffect3, /* UNI_PTEFFECT3 */
2320 DoPTEffect4, /* UNI_PTEFFECT4 */
2321 DoPTEffect5, /* UNI_PTEFFECT5 */
2322 DoPTEffect6, /* UNI_PTEFFECT6 */
2323 DoPTEffect7, /* UNI_PTEFFECT7 */
2324 DoPTEffect8, /* UNI_PTEFFECT8 */
2325 DoPTEffect9, /* UNI_PTEFFECT9 */
2326 DoPTEffectA, /* UNI_PTEFFECTA */
2327 DoPTEffectB, /* UNI_PTEFFECTB */
2328 DoPTEffectC, /* UNI_PTEFFECTC */
2329 DoPTEffectD, /* UNI_PTEFFECTD */
2330 DoPTEffectE, /* UNI_PTEFFECTE */
2331 DoPTEffectF, /* UNI_PTEFFECTF */
2332 DoS3MEffectA, /* UNI_S3MEFFECTA */
2333 DoS3MEffectD, /* UNI_S3MEFFECTD */
2334 DoS3MEffectE, /* UNI_S3MEFFECTE */
2335 DoS3MEffectF, /* UNI_S3MEFFECTF */
2336 DoS3MEffectI, /* UNI_S3MEFFECTI */
2337 DoS3MEffectQ, /* UNI_S3MEFFECTQ */
2338 DoS3MEffectR, /* UNI_S3MEFFECTR */
2339 DoS3MEffectT, /* UNI_S3MEFFECTT */
2340 DoS3MEffectU, /* UNI_S3MEFFECTU */
2341 DoKeyOff, /* UNI_KEYOFF */
2342 DoKeyFade, /* UNI_KEYFADE */
2343 DoVolEffects, /* UNI_VOLEFFECTS */
2344 DoPTEffect4, /* UNI_XMEFFECT4 */
2345 DoXMEffect6, /* UNI_XMEFFECT6 */
2346 DoXMEffectA, /* UNI_XMEFFECTA */
2347 DoXMEffectE1, /* UNI_XMEFFECTE1 */
2348 DoXMEffectE2, /* UNI_XMEFFECTE2 */
2349 DoXMEffectEA, /* UNI_XMEFFECTEA */
2350 DoXMEffectEB, /* UNI_XMEFFECTEB */
2351 DoXMEffectG, /* UNI_XMEFFECTG */
2352 DoXMEffectH, /* UNI_XMEFFECTH */
2353 DoXMEffectL, /* UNI_XMEFFECTL */
2354 DoXMEffectP, /* UNI_XMEFFECTP */
2355 DoXMEffectX1, /* UNI_XMEFFECTX1 */
2356 DoXMEffectX2, /* UNI_XMEFFECTX2 */
2357 DoITEffectG, /* UNI_ITEFFECTG */
2358 DoITEffectH, /* UNI_ITEFFECTH */
2359 DoITEffectI, /* UNI_ITEFFECTI */
2360 DoITEffectM, /* UNI_ITEFFECTM */
2361 DoITEffectN, /* UNI_ITEFFECTN */
2362 DoITEffectP, /* UNI_ITEFFECTP */
2363 DoITEffectT, /* UNI_ITEFFECTT */
2364 DoITEffectU, /* UNI_ITEFFECTU */
2365 DoITEffectW, /* UNI_ITEFFECTW */
2366 DoITEffectY, /* UNI_ITEFFECTY */
2367 DoNothing, /* UNI_ITEFFECTZ */
2368 DoITEffectS0, /* UNI_ITEFFECTS0 */
2369 DoULTEffect9, /* UNI_ULTEFFECT9 */
2370 DoMEDSpeed, /* UNI_MEDSPEED */
2371 DoMEDEffectF1, /* UNI_MEDEFFECTF1 */
2372 DoMEDEffectF2, /* UNI_MEDEFFECTF2 */
2373 DoMEDEffectF3, /* UNI_MEDEFFECTF3 */
2374 DoOktArp, /* UNI_OKTARP */
2377 static int pt_playeffects(MODULE *mod, SWORD channel, MP_CONTROL *a)
2379 UWORD tick = mod->vbtick;
2380 UWORD flags = mod->flags;
2381 UBYTE c;
2382 int explicitslides = 0;
2383 effect_func f;
2385 while((c=UniGetByte())) {
2386 f = effects[c];
2387 if (f != DoNothing)
2388 a->sliding = 0;
2389 explicitslides |= f(tick, flags, a, mod, channel);
2391 return explicitslides;
2394 static void DoNNAEffects(MODULE *mod, MP_CONTROL *a, UBYTE dat)
2396 int t;
2397 MP_VOICE *aout;
2399 dat&=0xf;
2400 aout=(a->slave)?a->slave:NULL;
2402 switch (dat) {
2403 case 0x0: /* past note cut */
2404 for (t=0;t<md_sngchn;t++)
2405 if (mod->voice[t].master==a)
2406 mod->voice[t].main.fadevol=0;
2407 break;
2408 case 0x1: /* past note off */
2409 for (t=0;t<md_sngchn;t++)
2410 if (mod->voice[t].master==a) {
2411 mod->voice[t].main.keyoff|=KEY_OFF;
2412 if ((!(mod->voice[t].venv.flg & EF_ON))||
2413 (mod->voice[t].venv.flg & EF_LOOP))
2414 mod->voice[t].main.keyoff=KEY_KILL;
2416 break;
2417 case 0x2: /* past note fade */
2418 for (t=0;t<md_sngchn;t++)
2419 if (mod->voice[t].master==a)
2420 mod->voice[t].main.keyoff|=KEY_FADE;
2421 break;
2422 case 0x3: /* set NNA note cut */
2423 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CUT;
2424 break;
2425 case 0x4: /* set NNA note continue */
2426 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CONTINUE;
2427 break;
2428 case 0x5: /* set NNA note off */
2429 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_OFF;
2430 break;
2431 case 0x6: /* set NNA note fade */
2432 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_FADE;
2433 break;
2434 case 0x7: /* disable volume envelope */
2435 if (aout)
2436 aout->main.volflg&=~EF_ON;
2437 break;
2438 case 0x8: /* enable volume envelope */
2439 if (aout)
2440 aout->main.volflg|=EF_ON;
2441 break;
2442 case 0x9: /* disable panning envelope */
2443 if (aout)
2444 aout->main.panflg&=~EF_ON;
2445 break;
2446 case 0xa: /* enable panning envelope */
2447 if (aout)
2448 aout->main.panflg|=EF_ON;
2449 break;
2450 case 0xb: /* disable pitch envelope */
2451 if (aout)
2452 aout->main.pitflg&=~EF_ON;
2453 break;
2454 case 0xc: /* enable pitch envelope */
2455 if (aout)
2456 aout->main.pitflg|=EF_ON;
2457 break;
2461 static void pt_UpdateVoices(MODULE *mod, int max_volume)
2463 SWORD envpan,envvol,envpit,channel;
2464 UWORD playperiod;
2465 SLONG vibval,vibdpt;
2466 ULONG tmpvol;
2468 MP_VOICE *aout;
2469 INSTRUMENT *i;
2470 SAMPLE *s;
2472 mod->totalchn=mod->realchn=0;
2473 for (channel=0;channel<md_sngchn;channel++) {
2474 aout=&mod->voice[channel];
2475 i=aout->main.i;
2476 s=aout->main.s;
2478 if (!s || !s->length) continue;
2480 if (aout->main.period<40)
2481 aout->main.period=40;
2482 else if (aout->main.period>50000)
2483 aout->main.period=50000;
2485 if ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_KEYOFF)) {
2486 Voice_Play_internal(channel,s,(aout->main.start==-1)?
2487 ((s->flags&SF_UST_LOOP) ? (SLONG)s->loopstart : 0) : aout->main.start);
2488 aout->main.fadevol=32768;
2489 aout->aswppos=0;
2492 envvol = 256;
2493 envpan = PAN_CENTER;
2494 envpit = 32;
2495 if (i && ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_ENV))) {
2496 if (aout->main.volflg & EF_ON)
2497 envvol = StartEnvelope(&aout->venv,aout->main.volflg,
2498 i->volpts,i->volsusbeg,i->volsusend,
2499 i->volbeg,i->volend,i->volenv,aout->main.keyoff);
2500 if (aout->main.panflg & EF_ON)
2501 envpan = StartEnvelope(&aout->penv,aout->main.panflg,
2502 i->panpts,i->pansusbeg,i->pansusend,
2503 i->panbeg,i->panend,i->panenv,aout->main.keyoff);
2504 if (aout->main.pitflg & EF_ON)
2505 envpit = StartEnvelope(&aout->cenv,aout->main.pitflg,
2506 i->pitpts,i->pitsusbeg,i->pitsusend,
2507 i->pitbeg,i->pitend,i->pitenv,aout->main.keyoff);
2509 if (aout->cenv.flg & EF_ON)
2510 aout->masterperiod=GetPeriod(mod->flags,
2511 (UWORD)aout->main.note<<1, aout->master->speed);
2512 } else {
2513 if (aout->main.volflg & EF_ON)
2514 envvol = ProcessEnvelope(aout,&aout->venv,256);
2515 if (aout->main.panflg & EF_ON)
2516 envpan = ProcessEnvelope(aout,&aout->penv,PAN_CENTER);
2517 if (aout->main.pitflg & EF_ON)
2518 envpit = ProcessEnvelope(aout,&aout->cenv,32);
2520 if (aout->main.kick == KICK_NOTE) {
2521 aout->main.kick_flag = 1;
2523 aout->main.kick=KICK_ABSENT;
2525 tmpvol = aout->main.fadevol; /* max 32768 */
2526 tmpvol *= aout->main.chanvol; /* * max 64 */
2527 tmpvol *= aout->main.outvolume; /* * max 256 */
2528 tmpvol /= (256 * 64); /* tmpvol is max 32768 again */
2529 aout->totalvol = tmpvol >> 2; /* used to determine samplevolume */
2530 tmpvol *= envvol; /* * max 256 */
2531 tmpvol *= mod->volume; /* * max 128 */
2532 tmpvol /= (128 * 256 * 128);
2534 /* fade out */
2535 if (mod->sngpos>=mod->numpos)
2536 tmpvol=0;
2537 else
2538 tmpvol=(tmpvol*max_volume)/128;
2540 if ((aout->masterchn!=-1)&& mod->control[aout->masterchn].muted)
2541 Voice_SetVolume_internal(channel,0);
2542 else {
2543 Voice_SetVolume_internal(channel,tmpvol);
2544 if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))
2545 mod->realchn++;
2546 mod->totalchn++;
2549 if (aout->main.panning==PAN_SURROUND)
2550 Voice_SetPanning_internal(channel,PAN_SURROUND);
2551 else
2552 if ((mod->panflag)&&(aout->penv.flg & EF_ON))
2553 Voice_SetPanning_internal(channel,
2554 DoPan(envpan,aout->main.panning));
2555 else
2556 Voice_SetPanning_internal(channel,aout->main.panning);
2558 if (aout->main.period && s->vibdepth)
2559 switch (s->vibtype) {
2560 case 0:
2561 vibval=avibtab[s->avibpos&127];
2562 if (aout->avibpos & 0x80) vibval=-vibval;
2563 break;
2564 case 1:
2565 vibval=64;
2566 if (aout->avibpos & 0x80) vibval=-vibval;
2567 break;
2568 case 2:
2569 vibval=63-(((aout->avibpos+128)&255)>>1);
2570 break;
2571 default:
2572 vibval=(((aout->avibpos+128)&255)>>1)-64;
2573 break;
2575 else
2576 vibval=0;
2578 if (s->vibflags & AV_IT) {
2579 if ((aout->aswppos>>8)<s->vibdepth) {
2580 aout->aswppos += s->vibsweep;
2581 vibdpt=aout->aswppos;
2582 } else
2583 vibdpt=s->vibdepth<<8;
2584 vibval=(vibval*vibdpt)>>16;
2585 if (aout->mflag) {
2586 if (!(mod->flags&UF_LINEAR)) vibval>>=1;
2587 aout->main.period-=vibval;
2589 } else {
2590 /* do XM style auto-vibrato */
2591 if (!(aout->main.keyoff & KEY_OFF)) {
2592 if (aout->aswppos<s->vibsweep) {
2593 vibdpt=(aout->aswppos*s->vibdepth)/s->vibsweep;
2594 aout->aswppos++;
2595 } else
2596 vibdpt=s->vibdepth;
2597 } else {
2598 /* keyoff -> depth becomes 0 if final depth wasn't reached or
2599 stays at final level if depth WAS reached */
2600 if (aout->aswppos>=s->vibsweep)
2601 vibdpt=s->vibdepth;
2602 else
2603 vibdpt=0;
2605 vibval=(vibval*vibdpt)>>8;
2606 aout->main.period-=vibval;
2609 /* update vibrato position */
2610 aout->avibpos=(aout->avibpos+s->vibrate)&0xff;
2612 /* process pitch envelope */
2613 playperiod=aout->main.period;
2615 if ((aout->main.pitflg&EF_ON)&&(envpit!=32)) {
2616 long p1;
2618 envpit-=32;
2619 if ((aout->main.note<<1)+envpit<=0) envpit=-(aout->main.note<<1);
2621 p1=GetPeriod(mod->flags, ((UWORD)aout->main.note<<1)+envpit,
2622 aout->master->speed)-aout->masterperiod;
2623 if (p1>0) {
2624 if ((UWORD)(playperiod+p1)<=playperiod) {
2625 p1=0;
2626 aout->main.keyoff|=KEY_OFF;
2628 } else if (p1<0) {
2629 if ((UWORD)(playperiod+p1)>=playperiod) {
2630 p1=0;
2631 aout->main.keyoff|=KEY_OFF;
2634 playperiod+=p1;
2637 if (!aout->main.fadevol) { /* check for a dead note (fadevol=0) */
2638 Voice_Stop_internal(channel);
2639 mod->totalchn--;
2640 if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))
2641 mod->realchn--;
2642 } else {
2643 Voice_SetFrequency_internal(channel,
2644 getfrequency(mod->flags,playperiod));
2646 /* if keyfade, start substracting fadeoutspeed from fadevol: */
2647 if ((i)&&(aout->main.keyoff&KEY_FADE)) {
2648 if (aout->main.fadevol>=i->volfade)
2649 aout->main.fadevol-=i->volfade;
2650 else
2651 aout->main.fadevol=0;
2655 md_bpm=mod->bpm+mod->relspd;
2656 if (md_bpm<32)
2657 md_bpm=32;
2658 else if ((!(mod->flags&UF_HIGHBPM)) && md_bpm>255)
2659 md_bpm=255;
2663 /* Handles new notes or instruments */
2664 static void pt_Notes(MODULE *mod)
2666 SWORD channel;
2667 MP_CONTROL *a;
2668 UBYTE c,inst;
2669 int tr,funky; /* funky is set to indicate note or instrument change */
2671 for (channel=0;channel<mod->numchn;channel++) {
2672 a=&mod->control[channel];
2674 if (mod->sngpos>=mod->numpos) {
2675 tr=mod->numtrk;
2676 mod->numrow=0;
2677 } else {
2678 tr=mod->patterns[(mod->positions[mod->sngpos]*mod->numchn)+channel];
2679 mod->numrow=mod->pattrows[mod->positions[mod->sngpos]];
2682 a->row=(tr<mod->numtrk)?UniFindRow(mod->tracks[tr],mod->patpos):NULL;
2683 a->newsamp=0;
2684 if (!mod->vbtick) a->main.notedelay=0;
2686 if (!a->row) continue;
2687 UniSetRow(a->row);
2688 funky=0;
2690 while((c=UniGetByte()))
2691 switch (c) {
2692 case UNI_NOTE:
2693 funky|=1;
2694 a->oldnote=a->anote,a->anote=UniGetByte();
2695 a->main.kick =KICK_NOTE;
2696 a->main.start=-1;
2697 a->sliding=0;
2699 /* retrig tremolo and vibrato waves ? */
2700 if (!(a->wavecontrol & 0x80)) a->trmpos=0;
2701 if (!(a->wavecontrol & 0x08)) a->vibpos=0;
2702 if (!a->panbwave) a->panbpos=0;
2703 break;
2704 case UNI_INSTRUMENT:
2705 inst=UniGetByte();
2706 if (inst>=mod->numins) break; /* safety valve */
2707 funky|=2;
2708 a->main.i=(mod->flags & UF_INST)?&mod->instruments[inst]:NULL;
2709 a->retrig=0;
2710 a->s3mtremor=0;
2711 a->ultoffset=0;
2712 a->main.sample=inst;
2713 break;
2714 default:
2715 UniSkipOpcode();
2716 break;
2719 if (funky) {
2720 INSTRUMENT *i;
2721 SAMPLE *s;
2723 if ((i=a->main.i)) {
2724 if (i->samplenumber[a->anote] >= mod->numsmp) continue;
2725 s=&mod->samples[i->samplenumber[a->anote]];
2726 a->main.note=i->samplenote[a->anote];
2727 } else {
2728 a->main.note=a->anote;
2729 s=&mod->samples[a->main.sample];
2732 if (a->main.s!=s) {
2733 a->main.s=s;
2734 a->newsamp=a->main.period;
2737 /* channel or instrument determined panning ? */
2738 a->main.panning=mod->panning[channel];
2739 if (s->flags & SF_OWNPAN)
2740 a->main.panning=s->panning;
2741 else if ((i)&&(i->flags & IF_OWNPAN))
2742 a->main.panning=i->panning;
2744 a->main.handle=s->handle;
2745 a->speed=s->speed;
2747 if (i) {
2748 if ((mod->panflag)&&(i->flags & IF_PITCHPAN)
2749 &&(a->main.panning!=PAN_SURROUND)){
2750 a->main.panning+=
2751 ((a->anote-i->pitpancenter)*i->pitpansep)/8;
2752 if (a->main.panning<PAN_LEFT)
2753 a->main.panning=PAN_LEFT;
2754 else if (a->main.panning>PAN_RIGHT)
2755 a->main.panning=PAN_RIGHT;
2757 a->main.pitflg=i->pitflg;
2758 a->main.volflg=i->volflg;
2759 a->main.panflg=i->panflg;
2760 a->main.nna=i->nnatype;
2761 a->dca=i->dca;
2762 a->dct=i->dct;
2763 } else {
2764 a->main.pitflg=a->main.volflg=a->main.panflg=0;
2765 a->main.nna=a->dca=0;
2766 a->dct=DCT_OFF;
2769 if (funky&2) /* instrument change */ {
2770 /* IT random volume variations: 0:8 bit fixed, and one bit for
2771 sign. */
2772 a->volume=a->tmpvolume=s->volume;
2773 if ((s)&&(i)) {
2774 if (i->rvolvar) {
2775 a->volume=a->tmpvolume=s->volume+
2776 ((s->volume*((SLONG)i->rvolvar*(SLONG)getrandom(512)
2777 ))/25600);
2778 if (a->volume<0)
2779 a->volume=a->tmpvolume=0;
2780 else if (a->volume>64)
2781 a->volume=a->tmpvolume=64;
2783 if ((mod->panflag)&&(a->main.panning!=PAN_SURROUND)) {
2784 a->main.panning+=((a->main.panning*((SLONG)i->rpanvar*
2785 (SLONG)getrandom(512)))/25600);
2786 if (a->main.panning<PAN_LEFT)
2787 a->main.panning=PAN_LEFT;
2788 else if (a->main.panning>PAN_RIGHT)
2789 a->main.panning=PAN_RIGHT;
2794 a->wantedperiod=a->tmpperiod=
2795 GetPeriod(mod->flags, (UWORD)a->main.note<<1,a->speed);
2796 a->main.keyoff=KEY_KICK;
2801 /* Handles effects */
2802 static void pt_EffectsPass1(MODULE *mod)
2804 SWORD channel;
2805 MP_CONTROL *a;
2806 MP_VOICE *aout;
2807 int explicitslides;
2809 for (channel=0;channel<mod->numchn;channel++) {
2810 a=&mod->control[channel];
2812 if ((aout=a->slave)) {
2813 a->main.fadevol=aout->main.fadevol;
2814 a->main.period=aout->main.period;
2815 if (a->main.kick==KICK_KEYOFF)
2816 a->main.keyoff=aout->main.keyoff;
2819 if (!a->row) continue;
2820 UniSetRow(a->row);
2822 a->ownper=a->ownvol=0;
2823 explicitslides = pt_playeffects(mod, channel, a);
2825 /* continue volume slide if necessary for XM and IT */
2826 if (mod->flags&UF_BGSLIDES) {
2827 if (!explicitslides && a->sliding)
2828 DoS3MVolSlide(mod->vbtick, mod->flags, a, 0);
2829 else if (a->tmpvolume)
2830 a->sliding = explicitslides;
2833 if (!a->ownper)
2834 a->main.period=a->tmpperiod;
2835 if (!a->ownvol)
2836 a->volume=a->tmpvolume;
2838 if (a->main.s) {
2839 if (a->main.i)
2840 a->main.outvolume=
2841 (a->volume*a->main.s->globvol*a->main.i->globvol)>>10;
2842 else
2843 a->main.outvolume=(a->volume*a->main.s->globvol)>>4;
2844 if (a->main.outvolume>256)
2845 a->main.outvolume=256;
2846 else if (a->main.outvolume<0)
2847 a->main.outvolume=0;
2852 /* NNA management */
2853 static void pt_NNA(MODULE *mod)
2855 SWORD channel;
2856 MP_CONTROL *a;
2858 for (channel=0;channel<mod->numchn;channel++) {
2859 a=&mod->control[channel];
2861 if (a->main.kick==KICK_NOTE) {
2862 int kill=0;
2864 if (a->slave) {
2865 MP_VOICE *aout;
2867 aout=a->slave;
2868 if (aout->main.nna & NNA_MASK) {
2869 /* Make sure the old MP_VOICE channel knows it has no
2870 master now ! */
2871 a->slave=NULL;
2872 /* assume the channel is taken by NNA */
2873 aout->mflag=0;
2875 switch (aout->main.nna) {
2876 case NNA_CONTINUE: /* continue note, do nothing */
2877 break;
2878 case NNA_OFF: /* note off */
2879 aout->main.keyoff|=KEY_OFF;
2880 if ((!(aout->main.volflg & EF_ON))||
2881 (aout->main.volflg & EF_LOOP))
2882 aout->main.keyoff=KEY_KILL;
2883 break;
2884 case NNA_FADE:
2885 aout->main.keyoff |= KEY_FADE;
2886 break;
2891 if (a->dct!=DCT_OFF) {
2892 int t;
2894 for (t=0;t<md_sngchn;t++)
2895 if ((!Voice_Stopped_internal(t))&&
2896 (mod->voice[t].masterchn==channel)&&
2897 (a->main.sample==mod->voice[t].main.sample)) {
2898 kill=0;
2899 switch (a->dct) {
2900 case DCT_NOTE:
2901 if (a->main.note==mod->voice[t].main.note)
2902 kill=1;
2903 break;
2904 case DCT_SAMPLE:
2905 if (a->main.handle==mod->voice[t].main.handle)
2906 kill=1;
2907 break;
2908 case DCT_INST:
2909 kill=1;
2910 break;
2912 if (kill)
2913 switch (a->dca) {
2914 case DCA_CUT:
2915 mod->voice[t].main.fadevol=0;
2916 break;
2917 case DCA_OFF:
2918 mod->voice[t].main.keyoff|=KEY_OFF;
2919 if ((!(mod->voice[t].main.volflg&EF_ON))||
2920 (mod->voice[t].main.volflg&EF_LOOP))
2921 mod->voice[t].main.keyoff=KEY_KILL;
2922 break;
2923 case DCA_FADE:
2924 mod->voice[t].main.keyoff|=KEY_FADE;
2925 break;
2929 } /* if (a->main.kick==KICK_NOTE) */
2933 /* Setup module and NNA voices */
2934 static void pt_SetupVoices(MODULE *mod)
2936 SWORD channel;
2937 MP_CONTROL *a;
2938 MP_VOICE *aout;
2940 for (channel=0;channel<mod->numchn;channel++) {
2941 a=&mod->control[channel];
2943 if (a->main.notedelay) continue;
2944 if (a->main.kick==KICK_NOTE) {
2945 /* if no channel was cut above, find an empty or quiet channel
2946 here */
2947 if (mod->flags&UF_NNA) {
2948 if (!a->slave) {
2949 int newchn;
2951 if ((newchn=MP_FindEmptyChannel(mod))!=-1)
2952 a->slave=&mod->voice[a->slavechn=newchn];
2954 } else
2955 a->slave=&mod->voice[a->slavechn=channel];
2957 /* assign parts of MP_VOICE only done for a KICK_NOTE */
2958 if ((aout=a->slave)) {
2959 if (aout->mflag && aout->master) aout->master->slave=NULL;
2960 aout->master=a;
2961 a->slave=aout;
2962 aout->masterchn=channel;
2963 aout->mflag=1;
2965 } else
2966 aout=a->slave;
2968 if (aout)
2969 aout->main=a->main;
2970 a->main.kick=KICK_ABSENT;
2974 /* second effect pass */
2975 static void pt_EffectsPass2(MODULE *mod)
2977 SWORD channel;
2978 MP_CONTROL *a;
2979 UBYTE c;
2981 for (channel=0;channel<mod->numchn;channel++) {
2982 a=&mod->control[channel];
2984 if (!a->row) continue;
2985 UniSetRow(a->row);
2987 while((c=UniGetByte()))
2988 if (c==UNI_ITEFFECTS0) {
2989 c=UniGetByte();
2990 if ((c>>4)==SS_S7EFFECTS)
2991 DoNNAEffects(mod, a, c&0xf);
2992 } else
2993 UniSkipOpcode();
2997 void Player_HandleTick(void)
2999 SWORD channel;
3000 int max_volume;
3002 #if 0
3003 /* don't handle the very first ticks, this allows the other hardware to
3004 settle down so we don't loose any starting notes */
3005 if (isfirst) {
3006 isfirst--;
3007 return;
3009 #endif
3011 if ((!pf)||(pf->forbid)||(pf->sngpos>=pf->numpos)) return;
3013 /* update time counter (sngtime is in milliseconds (in fact 2^-10)) */
3014 pf->sngremainder+=(1<<9)*5; /* thus 2.5*(1<<10), since fps=0.4xtempo */
3015 pf->sngtime+=pf->sngremainder/pf->bpm;
3016 pf->sngremainder%=pf->bpm;
3018 if (++pf->vbtick>=pf->sngspd) {
3019 if (pf->pat_repcrazy)
3020 pf->pat_repcrazy=0; /* play 2 times row 0 */
3021 else
3022 pf->patpos++;
3023 pf->vbtick=0;
3025 /* process pattern-delay. pf->patdly2 is the counter and pf->patdly is
3026 the command memory. */
3027 if (pf->patdly)
3028 pf->patdly2=pf->patdly,pf->patdly=0;
3029 if (pf->patdly2) {
3030 /* patterndelay active */
3031 if (--pf->patdly2)
3032 /* so turn back pf->patpos by 1 */
3033 if (pf->patpos) pf->patpos--;
3036 /* do we have to get a new patternpointer ? (when pf->patpos reaches the
3037 pattern size, or when a patternbreak is active) */
3038 if (((pf->patpos>=pf->numrow)&&(pf->numrow>0))&&(!pf->posjmp))
3039 pf->posjmp=3;
3041 if (pf->posjmp) {
3042 pf->patpos=pf->numrow?(pf->patbrk%pf->numrow):0;
3043 pf->pat_repcrazy=0;
3044 pf->sngpos+=(pf->posjmp-2);
3045 for (channel=0;channel<pf->numchn;channel++)
3046 pf->control[channel].pat_reppos=-1;
3048 pf->patbrk=pf->posjmp=0;
3049 /* handle the "---" (end of song) pattern since it can occur
3050 *inside* the module in some formats */
3051 if ((pf->sngpos>=pf->numpos)||
3052 (pf->positions[pf->sngpos]==LAST_PATTERN)) {
3053 if (!pf->wrap) return;
3054 if (!(pf->sngpos=pf->reppos)) {
3055 pf->volume=pf->initvolume>128?128:pf->initvolume;
3056 if(pf->initspeed!=0)
3057 pf->sngspd=pf->initspeed<32?pf->initspeed:32;
3058 else
3059 pf->sngspd=6;
3060 pf->bpm=pf->inittempo<32?32:pf->inittempo;
3063 if (pf->sngpos<0) pf->sngpos=pf->numpos-1;
3066 if (!pf->patdly2)
3067 pt_Notes(pf);
3070 /* Fade global volume if enabled and we're playing the last pattern */
3071 if (((pf->sngpos==pf->numpos-1)||
3072 (pf->positions[pf->sngpos+1]==LAST_PATTERN))&&
3073 (pf->fadeout))
3074 max_volume=pf->numrow?((pf->numrow-pf->patpos)*128)/pf->numrow:0;
3075 else
3076 max_volume=128;
3078 pt_EffectsPass1(pf);
3079 if (pf->flags&UF_NNA)
3080 pt_NNA(pf);
3081 pt_SetupVoices(pf);
3082 pt_EffectsPass2(pf);
3084 /* now set up the actual hardware channel playback information */
3085 pt_UpdateVoices(pf, max_volume);
3088 static void Player_Init_internal(MODULE* mod)
3090 int t;
3092 for (t=0;t<mod->numchn;t++) {
3093 mod->control[t].main.chanvol=mod->chanvol[t];
3094 mod->control[t].main.panning=mod->panning[t];
3097 mod->sngtime=0;
3098 mod->sngremainder=0;
3100 mod->pat_repcrazy=0;
3101 mod->sngpos=0;
3102 if(mod->initspeed!=0)
3103 mod->sngspd=mod->initspeed<32?mod->initspeed:32;
3104 else
3105 mod->sngspd=6;
3106 mod->volume=mod->initvolume>128?128:mod->initvolume;
3108 mod->vbtick=mod->sngspd;
3109 mod->patdly=0;
3110 mod->patdly2=0;
3111 mod->bpm=mod->inittempo<32?32:mod->inittempo;
3112 mod->realchn=0;
3114 mod->patpos=0;
3115 mod->posjmp=2; /* make sure the player fetches the first note */
3116 mod->numrow=-1;
3117 mod->patbrk=0;
3120 int Player_Init(MODULE* mod)
3122 mod->extspd=1;
3123 mod->panflag=1;
3124 mod->wrap=0;
3125 mod->loop=1;
3126 mod->fadeout=0;
3128 mod->relspd=0;
3130 /* make sure the player doesn't start with garbage */
3131 if (!(mod->control=(MP_CONTROL*)MikMod_calloc(mod->numchn,sizeof(MP_CONTROL))))
3132 return 1;
3133 if (!(mod->voice=(MP_VOICE*)MikMod_calloc(md_sngchn,sizeof(MP_VOICE))))
3134 return 1;
3136 Player_Init_internal(mod);
3137 return 0;
3140 void Player_Exit_internal(MODULE* mod)
3142 if (!mod)
3143 return;
3145 /* Stop playback if necessary */
3146 if (mod==pf) {
3147 Player_Stop_internal();
3148 pf=NULL;
3151 if (mod->control)
3152 MikMod_free(mod->control);
3153 if (mod->voice)
3154 MikMod_free(mod->voice);
3155 mod->control=NULL;
3156 mod->voice=NULL;
3159 void Player_Exit(MODULE* mod)
3161 MUTEX_LOCK(vars);
3162 Player_Exit_internal(mod);
3163 MUTEX_UNLOCK(vars);
3166 MIKMODAPI void Player_SetVolume(SWORD volume)
3168 MUTEX_LOCK(vars);
3169 if (pf)
3170 pf->volume=(volume<0)?0:(volume>128)?128:volume;
3171 MUTEX_UNLOCK(vars);
3174 MIKMODAPI MODULE* Player_GetModule(void)
3176 MODULE* result;
3178 MUTEX_LOCK(vars);
3179 result=pf;
3180 MUTEX_UNLOCK(vars);
3182 return result;
3185 MIKMODAPI void Player_Start(MODULE *mod)
3187 int t;
3189 if (!mod)
3190 return;
3192 if (!MikMod_Active())
3193 MikMod_EnableOutput();
3195 mod->forbid=0;
3197 MUTEX_LOCK(vars);
3198 if (pf!=mod) {
3199 /* new song is being started, so completely stop out the old one. */
3200 if (pf) pf->forbid=1;
3201 for (t=0;t<md_sngchn;t++) Voice_Stop_internal(t);
3203 pf=mod;
3204 MUTEX_UNLOCK(vars);
3207 void Player_Stop_internal(void)
3209 if (!md_sfxchn) MikMod_DisableOutput_internal();
3210 if (pf) pf->forbid=1;
3211 pf=NULL;
3214 MIKMODAPI void Player_Stop(void)
3216 MUTEX_LOCK(vars);
3217 Player_Stop_internal();
3218 MUTEX_UNLOCK(vars);
3221 MIKMODAPI int Player_Active(void)
3223 int result=0;
3225 MUTEX_LOCK(vars);
3226 if (pf)
3227 result=(!(pf->sngpos>=pf->numpos));
3228 MUTEX_UNLOCK(vars);
3230 return result;
3233 MIKMODAPI void Player_NextPosition(void)
3235 MUTEX_LOCK(vars);
3236 if (pf) {
3237 int t;
3239 pf->forbid=1;
3240 pf->posjmp=3;
3241 pf->patbrk=0;
3242 pf->vbtick=pf->sngspd;
3244 for (t=0;t<md_sngchn;t++) {
3245 Voice_Stop_internal(t);
3246 pf->voice[t].main.i=NULL;
3247 pf->voice[t].main.s=NULL;
3249 for (t=0;t<pf->numchn;t++) {
3250 pf->control[t].main.i=NULL;
3251 pf->control[t].main.s=NULL;
3253 pf->forbid=0;
3255 MUTEX_UNLOCK(vars);
3258 MIKMODAPI void Player_PrevPosition(void)
3260 MUTEX_LOCK(vars);
3261 if (pf) {
3262 int t;
3264 pf->forbid=1;
3265 pf->posjmp=1;
3266 pf->patbrk=0;
3267 pf->vbtick=pf->sngspd;
3269 for (t=0;t<md_sngchn;t++) {
3270 Voice_Stop_internal(t);
3271 pf->voice[t].main.i=NULL;
3272 pf->voice[t].main.s=NULL;
3274 for (t=0;t<pf->numchn;t++) {
3275 pf->control[t].main.i=NULL;
3276 pf->control[t].main.s=NULL;
3278 pf->forbid=0;
3280 MUTEX_UNLOCK(vars);
3283 MIKMODAPI void Player_SetPosition(UWORD pos)
3285 MUTEX_LOCK(vars);
3286 if (pf) {
3287 int t;
3289 pf->forbid=1;
3290 if (pos>=pf->numpos) pos=pf->numpos;
3291 pf->posjmp=2;
3292 pf->patbrk=0;
3293 pf->sngpos=pos;
3294 pf->vbtick=pf->sngspd;
3296 for (t=0;t<md_sngchn;t++) {
3297 Voice_Stop_internal(t);
3298 pf->voice[t].main.i=NULL;
3299 pf->voice[t].main.s=NULL;
3301 for (t=0;t<pf->numchn;t++) {
3302 pf->control[t].main.i=NULL;
3303 pf->control[t].main.s=NULL;
3305 pf->forbid=0;
3307 if (!pos)
3308 Player_Init_internal(pf);
3310 MUTEX_UNLOCK(vars);
3313 static void Player_Unmute_internal(SLONG arg1,va_list ap)
3315 SLONG t,arg2,arg3=0;
3317 if (pf) {
3318 switch (arg1) {
3319 case MUTE_INCLUSIVE:
3320 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3321 (arg2>arg3)||(arg3>=pf->numchn))
3322 return;
3323 for (;arg2<pf->numchn && arg2<=arg3;arg2++)
3324 pf->control[arg2].muted=0;
3325 break;
3326 case MUTE_EXCLUSIVE:
3327 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3328 (arg2>arg3)||(arg3>=pf->numchn))
3329 return;
3330 for (t=0;t<pf->numchn;t++) {
3331 if ((t>=arg2) && (t<=arg3))
3332 continue;
3333 pf->control[t].muted=0;
3335 break;
3336 default:
3337 if (arg1<pf->numchn) pf->control[arg1].muted=0;
3338 break;
3343 MIKMODAPI void Player_Unmute(SLONG arg1, ...)
3345 va_list args;
3347 va_start(args,arg1);
3348 MUTEX_LOCK(vars);
3349 Player_Unmute_internal(arg1,args);
3350 MUTEX_UNLOCK(vars);
3351 va_end(args);
3354 static void Player_Mute_internal(SLONG arg1,va_list ap)
3356 SLONG t,arg2,arg3=0;
3358 if (pf) {
3359 switch (arg1) {
3360 case MUTE_INCLUSIVE:
3361 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3362 (arg2>arg3)||(arg3>=pf->numchn))
3363 return;
3364 for (;arg2<pf->numchn && arg2<=arg3;arg2++)
3365 pf->control[arg2].muted=1;
3366 break;
3367 case MUTE_EXCLUSIVE:
3368 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3369 (arg2>arg3)||(arg3>=pf->numchn))
3370 return;
3371 for (t=0;t<pf->numchn;t++) {
3372 if ((t>=arg2) && (t<=arg3))
3373 continue;
3374 pf->control[t].muted=1;
3376 break;
3377 default:
3378 if (arg1<pf->numchn)
3379 pf->control[arg1].muted=1;
3380 break;
3385 MIKMODAPI void Player_Mute(SLONG arg1,...)
3387 va_list args;
3389 va_start(args,arg1);
3390 MUTEX_LOCK(vars);
3391 Player_Mute_internal(arg1,args);
3392 MUTEX_UNLOCK(vars);
3393 va_end(args);
3396 static void Player_ToggleMute_internal(SLONG arg1,va_list ap)
3398 SLONG arg2,arg3=0;
3399 SLONG t;
3401 if (pf) {
3402 switch (arg1) {
3403 case MUTE_INCLUSIVE:
3404 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3405 (arg2>arg3)||(arg3>=pf->numchn))
3406 return;
3407 for (;arg2<pf->numchn && arg2<=arg3;arg2++)
3408 pf->control[arg2].muted=1-pf->control[arg2].muted;
3409 break;
3410 case MUTE_EXCLUSIVE:
3411 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3412 (arg2>arg3)||(arg3>=pf->numchn))
3413 return;
3414 for (t=0;t<pf->numchn;t++) {
3415 if ((t>=arg2) && (t<=arg3))
3416 continue;
3417 pf->control[t].muted=1-pf->control[t].muted;
3419 break;
3420 default:
3421 if (arg1<pf->numchn)
3422 pf->control[arg1].muted=1-pf->control[arg1].muted;
3423 break;
3428 MIKMODAPI void Player_ToggleMute(SLONG arg1,...)
3430 va_list args;
3432 va_start(args,arg1);
3433 MUTEX_LOCK(vars);
3434 Player_ToggleMute_internal(arg1,args);
3435 MUTEX_UNLOCK(vars);
3436 va_end(args);
3439 MIKMODAPI int Player_Muted(UBYTE chan)
3441 int result=1;
3443 MUTEX_LOCK(vars);
3444 if (pf)
3445 result=(chan<pf->numchn)?pf->control[chan].muted:1;
3446 MUTEX_UNLOCK(vars);
3448 return result;
3451 MIKMODAPI int Player_GetChannelVoice(UBYTE chan)
3453 int result=0;
3455 MUTEX_LOCK(vars);
3456 if (pf)
3457 result=(chan<pf->numchn)?pf->control[chan].slavechn:-1;
3458 MUTEX_UNLOCK(vars);
3460 return result;
3463 MIKMODAPI UWORD Player_GetChannelPeriod(UBYTE chan)
3465 UWORD result=0;
3467 MUTEX_LOCK(vars);
3468 if (pf)
3469 result=(chan<pf->numchn)?pf->control[chan].main.period:0;
3470 MUTEX_UNLOCK(vars);
3472 return result;
3475 int Player_Paused_internal(void)
3477 return pf?pf->forbid:1;
3480 MIKMODAPI int Player_Paused(void)
3482 int result;
3484 MUTEX_LOCK(vars);
3485 result=Player_Paused_internal();
3486 MUTEX_UNLOCK(vars);
3488 return result;
3491 MIKMODAPI void Player_TogglePause(void)
3493 MUTEX_LOCK(vars);
3494 if (pf)
3495 pf->forbid=1-pf->forbid;
3496 MUTEX_UNLOCK(vars);
3499 MIKMODAPI void Player_SetSpeed(UWORD speed)
3501 MUTEX_LOCK(vars);
3502 if (pf)
3503 pf->sngspd=speed?(speed<32?speed:32):1;
3504 MUTEX_UNLOCK(vars);
3507 MIKMODAPI void Player_SetTempo(UWORD tempo)
3509 if (tempo<32) tempo=32;
3510 MUTEX_LOCK(vars);
3511 if (pf) {
3512 if ((!(pf->flags&UF_HIGHBPM))&&(tempo>255)) tempo=255;
3513 pf->bpm=tempo;
3515 MUTEX_UNLOCK(vars);
3518 MIKMODAPI int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo)
3520 int i;
3522 if (numvoices > md_sngchn)
3523 numvoices = md_sngchn;
3525 MUTEX_LOCK(vars);
3526 if (pf)
3527 for (i = 0; i < md_sngchn; i++) {
3528 vinfo [i].i = pf->voice[i].main.i;
3529 vinfo [i].s = pf->voice[i].main.s;
3530 vinfo [i].panning = pf->voice [i].main.panning;
3531 vinfo [i].volume = pf->voice [i].main.chanvol;
3532 vinfo [i].period = pf->voice [i].main.period;
3533 vinfo [i].kick = pf->voice [i].main.kick_flag;
3534 pf->voice [i].main.kick_flag = 0;
3536 MUTEX_UNLOCK(vars);
3538 return numvoices;
3542 // Get current module order
3543 MIKMODAPI int Player_GetOrder(void)
3545 int ret;
3546 MUTEX_LOCK(vars);
3547 ret = pf ? pf->sngpos :0; // pf->positions[pf->sngpos ? pf->sngpos-1 : 0]: 0;
3548 MUTEX_UNLOCK(vars);
3549 return ret;
3552 // Get current module row
3553 MIKMODAPI int Player_GetRow(void)
3555 int ret;
3556 MUTEX_LOCK(vars);
3557 ret = pf ? pf->patpos : 0;
3558 MUTEX_UNLOCK(vars);
3559 return ret;
3563 /* ex:set ts=4: */