Manual: Fix part 1 of FS#11874 - touchscreen region in the manual isn't 100% correct.
[kugel-rb.git] / apps / plugins / mikmod / mplayer.c
blob92585f03203d77f9531fcebe8abd7de3dd7015f4
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;
550 dat = UniGetByte();
551 if (!tick) {
552 if (!dat && (flags & UF_ARPMEM))
553 dat=a->arpmem;
554 else
555 a->arpmem=dat;
557 if (a->main.period)
558 DoArpeggio(tick, flags, a, 0);
560 return 0;
563 static int DoPTEffect1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
565 UBYTE dat;
567 dat = UniGetByte();
568 if (!tick && dat)
569 a->slidespeed = (UWORD)dat << 2;
570 if (a->main.period)
571 if (tick)
572 a->tmpperiod -= a->slidespeed;
574 return 0;
577 static int DoPTEffect2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
579 UBYTE dat;
581 dat = UniGetByte();
582 if (!tick && dat)
583 a->slidespeed = (UWORD)dat << 2;
584 if (a->main.period)
585 if (tick)
586 a->tmpperiod += a->slidespeed;
588 return 0;
591 static void DoToneSlide(UWORD tick, MP_CONTROL *a)
593 if (!a->main.fadevol)
594 a->main.kick = (a->main.kick == KICK_NOTE)? KICK_NOTE : KICK_KEYOFF;
595 else
596 a->main.kick = (a->main.kick == KICK_NOTE)? KICK_ENV : KICK_ABSENT;
598 if (tick != 0) {
599 int dist;
601 /* We have to slide a->main.period towards a->wantedperiod, so compute
602 the difference between those two values */
603 dist=a->main.period-a->wantedperiod;
605 /* if they are equal or if portamentospeed is too big ...*/
606 if (dist == 0 || a->portspeed > abs(dist))
607 /* ...make tmpperiod equal tperiod */
608 a->tmpperiod=a->main.period=a->wantedperiod;
609 else if (dist>0) {
610 a->tmpperiod-=a->portspeed;
611 a->main.period-=a->portspeed; /* dist>0, slide up */
612 } else {
613 a->tmpperiod+=a->portspeed;
614 a->main.period+=a->portspeed; /* dist<0, slide down */
616 } else
617 a->tmpperiod=a->main.period;
618 a->ownper = 1;
621 static int DoPTEffect3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
623 UBYTE dat;
625 dat=UniGetByte();
626 if ((!tick)&&(dat)) a->portspeed=(UWORD)dat<<2;
627 if (a->main.period)
628 DoToneSlide(tick, a);
630 return 0;
633 static void DoVibrato(UWORD tick, MP_CONTROL *a)
635 UBYTE q;
636 UWORD temp = 0; /* silence warning */
638 if (!tick)
639 return;
641 q=(a->vibpos>>2)&0x1f;
643 switch (a->wavecontrol&3) {
644 case 0: /* sine */
645 temp=VibratoTable[q];
646 break;
647 case 1: /* ramp down */
648 q<<=3;
649 if (a->vibpos<0) q=255-q;
650 temp=q;
651 break;
652 case 2: /* square wave */
653 temp=255;
654 break;
655 case 3: /* random wave */
656 temp=getrandom(256);
657 break;
660 temp*=a->vibdepth;
661 temp>>=7;temp<<=2;
663 if (a->vibpos>=0)
664 a->main.period=a->tmpperiod+temp;
665 else
666 a->main.period=a->tmpperiod-temp;
667 a->ownper = 1;
669 if (tick != 0)
670 a->vibpos+=a->vibspd;
673 static int DoPTEffect4(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
675 UBYTE dat;
677 dat=UniGetByte();
678 if (!tick) {
679 if (dat&0x0f) a->vibdepth=dat&0xf;
680 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
682 if (a->main.period)
683 DoVibrato(tick, a);
685 return 0;
688 static void DoVolSlide(MP_CONTROL *a, UBYTE dat)
690 if (dat&0xf) {
691 a->tmpvolume-=(dat&0x0f);
692 if (a->tmpvolume<0)
693 a->tmpvolume=0;
694 } else {
695 a->tmpvolume+=(dat>>4);
696 if (a->tmpvolume>64)
697 a->tmpvolume=64;
701 static int DoPTEffect5(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
703 UBYTE dat;
705 dat=UniGetByte();
706 if (a->main.period)
707 DoToneSlide(tick, a);
709 if (tick)
710 DoVolSlide(a, dat);
712 return 0;
715 /* DoPTEffect6 after DoPTEffectA */
717 static int DoPTEffect7(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
719 UBYTE dat;
720 UBYTE q;
721 UWORD temp = 0; /* silence warning */
723 dat=UniGetByte();
724 if (!tick) {
725 if (dat&0x0f) a->trmdepth=dat&0xf;
726 if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;
728 if (a->main.period) {
729 q=(a->trmpos>>2)&0x1f;
731 switch ((a->wavecontrol>>4)&3) {
732 case 0: /* sine */
733 temp=VibratoTable[q];
734 break;
735 case 1: /* ramp down */
736 q<<=3;
737 if (a->trmpos<0) q=255-q;
738 temp=q;
739 break;
740 case 2: /* square wave */
741 temp=255;
742 break;
743 case 3: /* random wave */
744 temp=getrandom(256);
745 break;
747 temp*=a->trmdepth;
748 temp>>=6;
750 if (a->trmpos>=0) {
751 a->volume=a->tmpvolume+temp;
752 if (a->volume>64) a->volume=64;
753 } else {
754 a->volume=a->tmpvolume-temp;
755 if (a->volume<0) a->volume=0;
757 a->ownvol = 1;
759 if (tick)
760 a->trmpos+=a->trmspd;
763 return 0;
766 static int DoPTEffect8(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
768 UBYTE dat;
770 dat = UniGetByte();
771 if (mod->panflag)
772 a->main.panning = mod->panning[channel] = dat;
774 return 0;
777 static int DoPTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
779 UBYTE dat;
781 dat=UniGetByte();
782 if (!tick) {
783 if (dat) a->soffset=(UWORD)dat<<8;
784 a->main.start=a->hioffset|a->soffset;
786 if ((a->main.s)&&(a->main.start>a->main.s->length))
787 a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
788 a->main.s->loopstart:a->main.s->length;
791 return 0;
794 static int DoPTEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
796 UBYTE dat;
798 dat=UniGetByte();
799 if (tick)
800 DoVolSlide(a, dat);
802 return 0;
805 static int DoPTEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
807 if (a->main.period)
808 DoVibrato(tick, a);
809 DoPTEffectA(tick, flags, a, mod, channel);
811 return 0;
814 static int DoPTEffectB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
816 UBYTE dat;
818 dat=UniGetByte();
820 if (tick || mod->patdly2)
821 return 0;
823 /* Vincent Voois uses a nasty trick in "Universal Bolero" */
824 if (dat == mod->sngpos && mod->patbrk == mod->patpos)
825 return 0;
827 if (!mod->loop && !mod->patbrk &&
828 (dat < mod->sngpos ||
829 (mod->sngpos == (mod->numpos - 1) && !mod->patbrk) ||
830 (dat == mod->sngpos && (flags & UF_NOWRAP))
831 )) {
832 /* if we don't loop, better not to skip the end of the
833 pattern, after all... so:
834 mod->patbrk=0; */
835 mod->posjmp=3;
836 } else {
837 /* if we were fading, adjust... */
838 if (mod->sngpos == (mod->numpos-1))
839 mod->volume=mod->initvolume>128?128:mod->initvolume;
840 mod->sngpos=dat;
841 mod->posjmp=2;
842 mod->patpos=0;
845 return 0;
848 static int DoPTEffectC(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
850 UBYTE dat;
852 dat=UniGetByte();
853 if (tick) return 0;
854 if (dat==(UBYTE)-1) a->anote=dat=0; /* note cut */
855 else if (dat>64) dat=64;
856 a->tmpvolume=dat;
858 return 0;
861 static int DoPTEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
863 UBYTE dat;
865 dat=UniGetByte();
866 if ((tick)||(mod->patdly2)) return 0;
867 if ((mod->positions[mod->sngpos]!=LAST_PATTERN)&&
868 (dat>mod->pattrows[mod->positions[mod->sngpos]]))
869 dat=mod->pattrows[mod->positions[mod->sngpos]];
870 mod->patbrk=dat;
871 if (!mod->posjmp) {
872 /* don't ask me to explain this code - it makes
873 backwards.s3m and children.xm (heretic's version) play
874 correctly, among others. Take that for granted, or write
875 the page of comments yourself... you might need some
876 aspirin - Miod */
877 if ((mod->sngpos==mod->numpos-1)&&(dat)&&((mod->loop)||
878 (mod->positions[mod->sngpos]==(mod->numpat-1)
879 && !(flags&UF_NOWRAP)))) {
880 mod->sngpos=0;
881 mod->posjmp=2;
882 } else
883 mod->posjmp=3;
886 return 0;
889 static void DoEEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod,
890 SWORD channel, UBYTE dat)
892 UBYTE nib = dat & 0xf;
894 switch (dat>>4) {
895 case 0x0: /* hardware filter toggle, not supported */
896 break;
897 case 0x1: /* fineslide up */
898 if (a->main.period)
899 if (!tick)
900 a->tmpperiod-=(nib<<2);
901 break;
902 case 0x2: /* fineslide dn */
903 if (a->main.period)
904 if (!tick)
905 a->tmpperiod+=(nib<<2);
906 break;
907 case 0x3: /* glissando ctrl */
908 a->glissando=nib;
909 break;
910 case 0x4: /* set vibrato waveform */
911 a->wavecontrol&=0xf0;
912 a->wavecontrol|=nib;
913 break;
914 case 0x5: /* set finetune */
915 if (a->main.period) {
916 if (flags&UF_XMPERIODS)
917 a->speed=nib+128;
918 else
919 a->speed=finetune[nib];
920 a->tmpperiod=GetPeriod(flags, (UWORD)a->main.note<<1,a->speed);
922 break;
923 case 0x6: /* set patternloop */
924 if (tick)
925 break;
926 if (nib) { /* set reppos or repcnt ? */
927 /* set repcnt, so check if repcnt already is set, which means we
928 are already looping */
929 if (a->pat_repcnt)
930 a->pat_repcnt--; /* already looping, decrease counter */
931 else {
932 #if 0
933 /* this would make walker.xm, shipped with Xsoundtracker,
934 play correctly, but it's better to remain compatible
935 with FT2 */
936 if ((!(flags&UF_NOWRAP))||(a->pat_reppos!=POS_NONE))
937 #endif
938 a->pat_repcnt=nib; /* not yet looping, so set repcnt */
941 if (a->pat_repcnt) { /* jump to reppos if repcnt>0 */
942 if (a->pat_reppos==POS_NONE)
943 a->pat_reppos=mod->patpos-1;
944 if (a->pat_reppos==-1) {
945 mod->pat_repcrazy=1;
946 mod->patpos=0;
947 } else
948 mod->patpos=a->pat_reppos;
949 } else a->pat_reppos=POS_NONE;
950 } else
951 a->pat_reppos=mod->patpos-1; /* set reppos - can be (-1) */
952 break;
953 case 0x7: /* set tremolo waveform */
954 a->wavecontrol&=0x0f;
955 a->wavecontrol|=nib<<4;
956 break;
957 case 0x8: /* set panning */
958 if (mod->panflag) {
959 if (nib<=8) nib<<=4;
960 else nib*=17;
961 a->main.panning=mod->panning[channel]=nib;
963 break;
964 case 0x9: /* retrig note */
965 /* do not retrigger on tick 0, until we are emulating FT2 and effect
966 data is zero */
967 if (!tick && !((flags & UF_FT2QUIRKS) && (!nib)))
968 break;
969 /* only retrigger if data nibble > 0, or if tick 0 (FT2 compat) */
970 if (nib || !tick) {
971 if (!a->retrig) {
972 /* when retrig counter reaches 0, reset counter and restart
973 the sample */
974 if (a->main.period) a->main.kick=KICK_NOTE;
975 a->retrig=nib;
977 a->retrig--; /* countdown */
979 break;
980 case 0xa: /* fine volume slide up */
981 if (tick)
982 break;
983 a->tmpvolume+=nib;
984 if (a->tmpvolume>64) a->tmpvolume=64;
985 break;
986 case 0xb: /* fine volume slide dn */
987 if (tick)
988 break;
989 a->tmpvolume-=nib;
990 if (a->tmpvolume<0)a->tmpvolume=0;
991 break;
992 case 0xc: /* cut note */
993 /* When tick reaches the cut-note value, turn the volume to
994 zero (just like on the amiga) */
995 if (tick>=nib)
996 a->tmpvolume=0; /* just turn the volume down */
997 break;
998 case 0xd: /* note delay */
999 /* delay the start of the sample until tick==nib */
1000 if (!tick)
1001 a->main.notedelay=nib;
1002 else if (a->main.notedelay)
1003 a->main.notedelay--;
1004 break;
1005 case 0xe: /* pattern delay */
1006 if (!tick)
1007 if (!mod->patdly2)
1008 mod->patdly=nib+1; /* only once, when tick=0 */
1009 break;
1010 case 0xf: /* invert loop, not supported */
1011 break;
1015 static int DoPTEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1017 DoEEffects(tick, flags, a, mod, channel, UniGetByte());
1019 return 0;
1022 static int DoPTEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1024 UBYTE dat;
1026 dat=UniGetByte();
1027 if (tick||mod->patdly2) return 0;
1028 if (mod->extspd&&(dat>=mod->bpmlimit))
1029 mod->bpm=dat;
1030 else
1031 if (dat) {
1032 mod->sngspd=(dat>=mod->bpmlimit)?mod->bpmlimit-1:dat;
1033 mod->vbtick=0;
1036 return 0;
1039 /*========== Scream Tracker effects */
1041 static int DoS3MEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1043 UBYTE speed;
1045 speed = UniGetByte();
1047 if (tick || mod->patdly2)
1048 return 0;
1050 if (speed > 128)
1051 speed -= 128;
1052 if (speed) {
1053 mod->sngspd = speed;
1054 mod->vbtick = 0;
1057 return 0;
1060 static void DoS3MVolSlide(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE inf)
1062 UBYTE lo, hi;
1064 if (inf)
1065 a->s3mvolslide=inf;
1066 else
1067 inf=a->s3mvolslide;
1069 lo=inf&0xf;
1070 hi=inf>>4;
1072 if (!lo) {
1073 if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume+=hi;
1074 } else
1075 if (!hi) {
1076 if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume-=lo;
1077 } else
1078 if (lo==0xf) {
1079 if (!tick) a->tmpvolume+=(hi?hi:0xf);
1080 } else
1081 if (hi==0xf) {
1082 if (!tick) a->tmpvolume-=(lo?lo:0xf);
1083 } else
1084 return;
1086 if (a->tmpvolume<0)
1087 a->tmpvolume=0;
1088 else if (a->tmpvolume>64)
1089 a->tmpvolume=64;
1092 static int DoS3MEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1094 DoS3MVolSlide(tick, flags, a, UniGetByte());
1096 return 1;
1099 static void DoS3MSlideDn(UWORD tick, MP_CONTROL *a, UBYTE inf)
1101 UBYTE hi,lo;
1103 if (inf)
1104 a->slidespeed=inf;
1105 else
1106 inf=a->slidespeed;
1108 hi=inf>>4;
1109 lo=inf&0xf;
1111 if (hi==0xf) {
1112 if (!tick) a->tmpperiod+=(UWORD)lo<<2;
1113 } else
1114 if (hi==0xe) {
1115 if (!tick) a->tmpperiod+=lo;
1116 } else {
1117 if (tick) a->tmpperiod+=(UWORD)inf<<2;
1121 static int DoS3MEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1123 UBYTE dat;
1125 dat=UniGetByte();
1126 if (a->main.period)
1127 DoS3MSlideDn(tick, a,dat);
1129 return 0;
1132 static void DoS3MSlideUp(UWORD tick, MP_CONTROL *a, UBYTE inf)
1134 UBYTE hi,lo;
1136 if (inf) a->slidespeed=inf;
1137 else inf=a->slidespeed;
1139 hi=inf>>4;
1140 lo=inf&0xf;
1142 if (hi==0xf) {
1143 if (!tick) a->tmpperiod-=(UWORD)lo<<2;
1144 } else
1145 if (hi==0xe) {
1146 if (!tick) a->tmpperiod-=lo;
1147 } else {
1148 if (tick) a->tmpperiod-=(UWORD)inf<<2;
1152 static int DoS3MEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1154 UBYTE dat;
1156 dat=UniGetByte();
1157 if (a->main.period)
1158 DoS3MSlideUp(tick, a,dat);
1160 return 0;
1163 static int DoS3MEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1165 UBYTE inf, on, off;
1167 inf = UniGetByte();
1168 if (inf)
1169 a->s3mtronof = inf;
1170 else {
1171 inf = a->s3mtronof;
1172 if (!inf)
1173 return 0;
1176 if (!tick)
1177 return 0;
1179 on=(inf>>4)+1;
1180 off=(inf&0xf)+1;
1181 a->s3mtremor%=(on+off);
1182 a->volume=(a->s3mtremor<on)?a->tmpvolume:0;
1183 a->ownvol=1;
1184 a->s3mtremor++;
1186 return 0;
1189 static int DoS3MEffectQ(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1191 UBYTE inf;
1193 inf = UniGetByte();
1194 if (a->main.period) {
1195 if (inf) {
1196 a->s3mrtgslide=inf>>4;
1197 a->s3mrtgspeed=inf&0xf;
1200 /* only retrigger if low nibble > 0 */
1201 if (a->s3mrtgspeed>0) {
1202 if (!a->retrig) {
1203 /* when retrig counter reaches 0, reset counter and restart the
1204 sample */
1205 if (a->main.kick!=KICK_NOTE) a->main.kick=KICK_KEYOFF;
1206 a->retrig=a->s3mrtgspeed;
1208 if ((tick)||(flags&UF_S3MSLIDES)) {
1209 switch (a->s3mrtgslide) {
1210 case 1:
1211 case 2:
1212 case 3:
1213 case 4:
1214 case 5:
1215 a->tmpvolume-=(1<<(a->s3mrtgslide-1));
1216 break;
1217 case 6:
1218 a->tmpvolume=(2*a->tmpvolume)/3;
1219 break;
1220 case 7:
1221 a->tmpvolume>>=1;
1222 break;
1223 case 9:
1224 case 0xa:
1225 case 0xb:
1226 case 0xc:
1227 case 0xd:
1228 a->tmpvolume+=(1<<(a->s3mrtgslide-9));
1229 break;
1230 case 0xe:
1231 a->tmpvolume=(3*a->tmpvolume)>>1;
1232 break;
1233 case 0xf:
1234 a->tmpvolume=a->tmpvolume<<1;
1235 break;
1237 if (a->tmpvolume<0)
1238 a->tmpvolume=0;
1239 else if (a->tmpvolume>64)
1240 a->tmpvolume=64;
1243 a->retrig--; /* countdown */
1247 return 0;
1250 static int DoS3MEffectR(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1252 UBYTE dat, q;
1253 UWORD temp=0; /* silence warning */
1255 dat = UniGetByte();
1256 if (!tick) {
1257 if (dat&0x0f) a->trmdepth=dat&0xf;
1258 if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;
1261 q=(a->trmpos>>2)&0x1f;
1263 switch ((a->wavecontrol>>4)&3) {
1264 case 0: /* sine */
1265 temp=VibratoTable[q];
1266 break;
1267 case 1: /* ramp down */
1268 q<<=3;
1269 if (a->trmpos<0) q=255-q;
1270 temp=q;
1271 break;
1272 case 2: /* square wave */
1273 temp=255;
1274 break;
1275 case 3: /* random */
1276 temp=getrandom(256);
1277 break;
1280 temp*=a->trmdepth;
1281 temp>>=7;
1283 if (a->trmpos>=0) {
1284 a->volume=a->tmpvolume+temp;
1285 if (a->volume>64) a->volume=64;
1286 } else {
1287 a->volume=a->tmpvolume-temp;
1288 if (a->volume<0) a->volume=0;
1290 a->ownvol = 1;
1292 if (tick)
1293 a->trmpos+=a->trmspd;
1295 return 0;
1298 static int DoS3MEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1300 UBYTE tempo;
1302 tempo = UniGetByte();
1304 if (tick || mod->patdly2)
1305 return 0;
1307 mod->bpm = (tempo < 32) ? 32 : tempo;
1309 return 0;
1312 static int DoS3MEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1314 UBYTE dat, q;
1315 UWORD temp = 0; /* silence warning */
1317 dat = UniGetByte();
1318 if (!tick) {
1319 if (dat&0x0f) a->vibdepth=dat&0xf;
1320 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
1321 } else
1322 if (a->main.period) {
1323 q=(a->vibpos>>2)&0x1f;
1325 switch (a->wavecontrol&3) {
1326 case 0: /* sine */
1327 temp=VibratoTable[q];
1328 break;
1329 case 1: /* ramp down */
1330 q<<=3;
1331 if (a->vibpos<0) q=255-q;
1332 temp=q;
1333 break;
1334 case 2: /* square wave */
1335 temp=255;
1336 break;
1337 case 3: /* random */
1338 temp=getrandom(256);
1339 break;
1342 temp*=a->vibdepth;
1343 temp>>=8;
1345 if (a->vibpos>=0)
1346 a->main.period=a->tmpperiod+temp;
1347 else
1348 a->main.period=a->tmpperiod-temp;
1349 a->ownper = 1;
1351 a->vibpos+=a->vibspd;
1354 return 0;
1357 /*========== Envelope helpers */
1359 static int DoKeyOff(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1361 a->main.keyoff|=KEY_OFF;
1362 if ((!(a->main.volflg&EF_ON))||(a->main.volflg&EF_LOOP))
1363 a->main.keyoff=KEY_KILL;
1365 return 0;
1368 static int DoKeyFade(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1370 UBYTE dat;
1372 dat=UniGetByte();
1373 if ((tick>=dat)||(tick==mod->sngspd-1)) {
1374 a->main.keyoff=KEY_KILL;
1375 if (!(a->main.volflg&EF_ON))
1376 a->main.fadevol=0;
1379 return 0;
1382 /*========== Fast Tracker effects */
1384 /* DoXMEffect6 after DoXMEffectA */
1386 static int DoXMEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1388 UBYTE inf, lo, hi;
1390 inf = UniGetByte();
1391 if (inf)
1392 a->s3mvolslide = inf;
1393 else
1394 inf = a->s3mvolslide;
1396 if (tick) {
1397 lo=inf&0xf;
1398 hi=inf>>4;
1400 if (!hi) {
1401 a->tmpvolume-=lo;
1402 if (a->tmpvolume<0) a->tmpvolume=0;
1403 } else {
1404 a->tmpvolume+=hi;
1405 if (a->tmpvolume>64) a->tmpvolume=64;
1409 return 0;
1412 static int DoXMEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1414 if (a->main.period)
1415 DoVibrato(tick, a);
1417 return DoXMEffectA(tick, flags, a, mod, channel);
1420 static int DoXMEffectE1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1422 UBYTE dat;
1424 dat=UniGetByte();
1425 if (!tick) {
1426 if (dat) a->fportupspd=dat;
1427 if (a->main.period)
1428 a->tmpperiod-=(a->fportupspd<<2);
1431 return 0;
1434 static int DoXMEffectE2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1436 UBYTE dat;
1438 dat=UniGetByte();
1439 if (!tick) {
1440 if (dat) a->fportdnspd=dat;
1441 if (a->main.period)
1442 a->tmpperiod+=(a->fportdnspd<<2);
1445 return 0;
1448 static int DoXMEffectEA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1450 UBYTE dat;
1452 dat=UniGetByte();
1453 if (!tick)
1454 if (dat) a->fslideupspd=dat;
1455 a->tmpvolume+=a->fslideupspd;
1456 if (a->tmpvolume>64) a->tmpvolume=64;
1458 return 0;
1461 static int DoXMEffectEB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1463 UBYTE dat;
1465 dat=UniGetByte();
1466 if (!tick)
1467 if (dat) a->fslidednspd=dat;
1468 a->tmpvolume-=a->fslidednspd;
1469 if (a->tmpvolume<0) a->tmpvolume=0;
1471 return 0;
1474 static int DoXMEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1476 mod->volume=UniGetByte()<<1;
1477 if (mod->volume>128) mod->volume=128;
1479 return 0;
1482 static int DoXMEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1484 UBYTE inf;
1486 inf = UniGetByte();
1488 if (tick) {
1489 if (inf) mod->globalslide=inf;
1490 else inf=mod->globalslide;
1491 if (inf & 0xf0) inf&=0xf0;
1492 mod->volume=mod->volume+((inf>>4)-(inf&0xf))*2;
1494 if (mod->volume<0)
1495 mod->volume=0;
1496 else if (mod->volume>128)
1497 mod->volume=128;
1500 return 0;
1503 static int DoXMEffectL(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1505 UBYTE dat;
1507 dat=UniGetByte();
1508 if ((!tick)&&(a->main.i)) {
1509 UWORD points;
1510 INSTRUMENT *i=a->main.i;
1511 MP_VOICE *aout;
1513 if ((aout=a->slave)) {
1514 if (aout->venv.env) {
1515 points=i->volenv[i->volpts-1].pos;
1516 aout->venv.p=aout->venv.env[(dat>points)?points:dat].pos;
1518 if (aout->penv.env) {
1519 points=i->panenv[i->panpts-1].pos;
1520 aout->penv.p=aout->penv.env[(dat>points)?points:dat].pos;
1525 return 0;
1528 static int DoXMEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1530 UBYTE inf, lo, hi;
1531 SWORD pan;
1533 inf = UniGetByte();
1534 if (!mod->panflag)
1535 return 0;
1537 if (inf)
1538 a->pansspd = inf;
1539 else
1540 inf =a->pansspd;
1542 if (tick) {
1543 lo=inf&0xf;
1544 hi=inf>>4;
1546 /* slide right has absolute priority */
1547 if (hi)
1548 lo = 0;
1550 pan=((a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning)+hi-lo;
1551 a->main.panning=(pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);
1554 return 0;
1557 static int DoXMEffectX1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1559 UBYTE dat;
1561 dat = UniGetByte();
1562 if (dat)
1563 a->ffportupspd = dat;
1564 else
1565 dat = a->ffportupspd;
1567 if (a->main.period)
1568 if (!tick) {
1569 a->main.period-=dat;
1570 a->tmpperiod-=dat;
1571 a->ownper = 1;
1574 return 0;
1577 static int DoXMEffectX2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1579 UBYTE dat;
1581 dat = UniGetByte();
1582 if (dat)
1583 a->ffportdnspd=dat;
1584 else
1585 dat = a->ffportdnspd;
1587 if (a->main.period)
1588 if (!tick) {
1589 a->main.period+=dat;
1590 a->tmpperiod+=dat;
1591 a->ownper = 1;
1594 return 0;
1597 /*========== Impulse Tracker effects */
1599 static void DoITToneSlide(UWORD tick, MP_CONTROL *a, UBYTE dat)
1601 if (dat)
1602 a->portspeed = dat;
1604 /* if we don't come from another note, ignore the slide and play the note
1605 as is */
1606 if (!a->oldnote || !a->main.period)
1607 return;
1609 if ((!tick)&&(a->newsamp)){
1610 a->main.kick=KICK_NOTE;
1611 a->main.start=-1;
1612 } else
1613 a->main.kick=(a->main.kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT;
1615 if (tick) {
1616 int dist;
1618 /* We have to slide a->main.period towards a->wantedperiod, compute the
1619 difference between those two values */
1620 dist=a->main.period-a->wantedperiod;
1622 /* if they are equal or if portamentospeed is too big... */
1623 if ((!dist)||((a->portspeed<<2)>abs(dist)))
1624 /* ... make tmpperiod equal tperiod */
1625 a->tmpperiod=a->main.period=a->wantedperiod;
1626 else
1627 if (dist>0) {
1628 a->tmpperiod-=a->portspeed<<2;
1629 a->main.period-=a->portspeed<<2; /* dist>0 slide up */
1630 } else {
1631 a->tmpperiod+=a->portspeed<<2;
1632 a->main.period+=a->portspeed<<2; /* dist<0 slide down */
1634 } else
1635 a->tmpperiod=a->main.period;
1636 a->ownper=1;
1639 static int DoITEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1641 DoITToneSlide(tick, a, UniGetByte());
1643 return 0;
1646 static void DoITVibrato(UWORD tick, MP_CONTROL *a, UBYTE dat)
1648 UBYTE q;
1649 UWORD temp=0;
1651 if (!tick) {
1652 if (dat&0x0f) a->vibdepth=dat&0xf;
1653 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
1655 if (!a->main.period)
1656 return;
1658 q=(a->vibpos>>2)&0x1f;
1660 switch (a->wavecontrol&3) {
1661 case 0: /* sine */
1662 temp=VibratoTable[q];
1663 break;
1664 case 1: /* square wave */
1665 temp=255;
1666 break;
1667 case 2: /* ramp down */
1668 q<<=3;
1669 if (a->vibpos<0) q=255-q;
1670 temp=q;
1671 break;
1672 case 3: /* random */
1673 temp=getrandom(256);
1674 break;
1677 temp*=a->vibdepth;
1678 temp>>=8;
1679 temp<<=2;
1681 if (a->vibpos>=0)
1682 a->main.period=a->tmpperiod+temp;
1683 else
1684 a->main.period=a->tmpperiod-temp;
1685 a->ownper=1;
1687 a->vibpos+=a->vibspd;
1690 static int DoITEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1692 DoITVibrato(tick, a, UniGetByte());
1694 return 0;
1697 static int DoITEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1699 UBYTE inf, on, off;
1701 inf = UniGetByte();
1702 if (inf)
1703 a->s3mtronof = inf;
1704 else {
1705 inf = a->s3mtronof;
1706 if (!inf)
1707 return 0;
1710 on=(inf>>4);
1711 off=(inf&0xf);
1713 a->s3mtremor%=(on+off);
1714 a->volume=(a->s3mtremor<on)?a->tmpvolume:0;
1715 a->ownvol = 1;
1716 a->s3mtremor++;
1718 return 0;
1721 static int DoITEffectM(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1723 a->main.chanvol=UniGetByte();
1724 if (a->main.chanvol>64)
1725 a->main.chanvol=64;
1726 else if (a->main.chanvol<0)
1727 a->main.chanvol=0;
1729 return 0;
1732 static int DoITEffectN(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1734 UBYTE inf, lo, hi;
1736 inf = UniGetByte();
1738 if (inf)
1739 a->chanvolslide = inf;
1740 else
1741 inf = a->chanvolslide;
1743 lo=inf&0xf;
1744 hi=inf>>4;
1746 if (!hi)
1747 a->main.chanvol-=lo;
1748 else
1749 if (!lo) {
1750 a->main.chanvol+=hi;
1751 } else
1752 if (hi==0xf) {
1753 if (!tick) a->main.chanvol-=lo;
1754 } else
1755 if (lo==0xf) {
1756 if (!tick) a->main.chanvol+=hi;
1759 if (a->main.chanvol<0)
1760 a->main.chanvol=0;
1761 else if (a->main.chanvol>64)
1762 a->main.chanvol=64;
1764 return 0;
1767 static int DoITEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1769 UBYTE inf, lo, hi;
1770 SWORD pan;
1772 inf = UniGetByte();
1773 if (inf)
1774 a->pansspd = inf;
1775 else
1776 inf = a->pansspd;
1778 if (!mod->panflag)
1779 return 0;
1781 lo=inf&0xf;
1782 hi=inf>>4;
1784 pan=(a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning;
1786 if (!hi)
1787 pan+=lo<<2;
1788 else
1789 if (!lo) {
1790 pan-=hi<<2;
1791 } else
1792 if (hi==0xf) {
1793 if (!tick) pan+=lo<<2;
1794 } else
1795 if (lo==0xf) {
1796 if (!tick) pan-=hi<<2;
1798 a->main.panning=
1799 (pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);
1801 return 0;
1804 static int DoITEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1806 UBYTE tempo;
1807 SWORD temp;
1809 tempo = UniGetByte();
1811 if (mod->patdly2)
1812 return 0;
1814 temp = mod->bpm;
1815 if (tempo & 0x10)
1816 temp += (tempo & 0x0f);
1817 else
1818 temp -= tempo;
1820 mod->bpm=(temp>255)?255:(temp<1?1:temp);
1822 return 0;
1825 static int DoITEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1827 UBYTE dat, q;
1828 UWORD temp = 0; /* silence warning */
1830 dat = UniGetByte();
1831 if (!tick) {
1832 if (dat&0x0f) a->vibdepth=dat&0xf;
1833 if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
1835 if (a->main.period) {
1836 q=(a->vibpos>>2)&0x1f;
1838 switch (a->wavecontrol&3) {
1839 case 0: /* sine */
1840 temp=VibratoTable[q];
1841 break;
1842 case 1: /* square wave */
1843 temp=255;
1844 break;
1845 case 2: /* ramp down */
1846 q<<=3;
1847 if (a->vibpos<0) q=255-q;
1848 temp=q;
1849 break;
1850 case 3: /* random */
1851 temp=getrandom(256);
1852 break;
1855 temp*=a->vibdepth;
1856 temp>>=8;
1858 if (a->vibpos>=0)
1859 a->main.period=a->tmpperiod+temp;
1860 else
1861 a->main.period=a->tmpperiod-temp;
1862 a->ownper = 1;
1864 a->vibpos+=a->vibspd;
1867 return 0;
1870 static int DoITEffectW(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1872 UBYTE inf, lo, hi;
1874 inf = UniGetByte();
1876 if (inf)
1877 mod->globalslide = inf;
1878 else
1879 inf = mod->globalslide;
1881 lo=inf&0xf;
1882 hi=inf>>4;
1884 if (!lo) {
1885 if (tick) mod->volume+=hi;
1886 } else
1887 if (!hi) {
1888 if (tick) mod->volume-=lo;
1889 } else
1890 if (lo==0xf) {
1891 if (!tick) mod->volume+=hi;
1892 } else
1893 if (hi==0xf) {
1894 if (!tick) mod->volume-=lo;
1897 if (mod->volume<0)
1898 mod->volume=0;
1899 else if (mod->volume>128)
1900 mod->volume=128;
1902 return 0;
1905 static int DoITEffectY(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1907 UBYTE dat, q;
1908 SLONG temp = 0; /* silence warning */
1911 dat=UniGetByte();
1912 if (!tick) {
1913 if (dat&0x0f) a->panbdepth=(dat&0xf);
1914 if (dat&0xf0) a->panbspd=(dat&0xf0)>>4;
1916 if (mod->panflag) {
1917 q=a->panbpos;
1919 switch (a->panbwave) {
1920 case 0: /* sine */
1921 temp=PanbrelloTable[q];
1922 break;
1923 case 1: /* square wave */
1924 temp=(q<0x80)?64:0;
1925 break;
1926 case 2: /* ramp down */
1927 q<<=3;
1928 temp=q;
1929 break;
1930 case 3: /* random */
1931 temp=getrandom(256);
1932 break;
1935 temp*=a->panbdepth;
1936 temp=(temp/8)+mod->panning[channel];
1938 a->main.panning=
1939 (temp<PAN_LEFT)?PAN_LEFT:(temp>PAN_RIGHT?PAN_RIGHT:temp);
1940 a->panbpos+=a->panbspd;
1944 return 0;
1947 static void DoNNAEffects(MODULE *, MP_CONTROL *, UBYTE);
1949 /* Impulse/Scream Tracker Sxx effects.
1950 All Sxx effects share the same memory space. */
1951 static int DoITEffectS0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
1953 UBYTE dat, inf, c;
1955 dat = UniGetByte();
1956 inf=dat&0xf;
1957 c=dat>>4;
1959 if (!dat) {
1960 c=a->sseffect;
1961 inf=a->ssdata;
1962 } else {
1963 a->sseffect=c;
1964 a->ssdata=inf;
1967 switch (c) {
1968 case SS_GLISSANDO: /* S1x set glissando voice */
1969 DoEEffects(tick, flags, a, mod, channel, 0x30|inf);
1970 break;
1971 case SS_FINETUNE: /* S2x set finetune */
1972 DoEEffects(tick, flags, a, mod, channel, 0x50|inf);
1973 break;
1974 case SS_VIBWAVE: /* S3x set vibrato waveform */
1975 DoEEffects(tick, flags, a, mod, channel, 0x40|inf);
1976 break;
1977 case SS_TREMWAVE: /* S4x set tremolo waveform */
1978 DoEEffects(tick, flags, a, mod, channel, 0x70|inf);
1979 break;
1980 case SS_PANWAVE: /* S5x panbrello */
1981 a->panbwave=inf;
1982 break;
1983 case SS_FRAMEDELAY: /* S6x delay x number of frames (patdly) */
1984 DoEEffects(tick, flags, a, mod, channel, 0xe0|inf);
1985 break;
1986 case SS_S7EFFECTS: /* S7x instrument / NNA commands */
1987 DoNNAEffects(mod, a, inf);
1988 break;
1989 case SS_PANNING: /* S8x set panning position */
1990 DoEEffects(tick, flags, a, mod, channel, 0x80 | inf);
1991 break;
1992 case SS_SURROUND: /* S9x set surround sound */
1993 if (mod->panflag)
1994 a->main.panning = mod->panning[channel] = PAN_SURROUND;
1995 break;
1996 case SS_HIOFFSET: /* SAy set high order sample offset yxx00h */
1997 if (!tick) {
1998 a->hioffset=inf<<16;
1999 a->main.start=a->hioffset|a->soffset;
2001 if ((a->main.s)&&(a->main.start>a->main.s->length))
2002 a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
2003 a->main.s->loopstart:a->main.s->length;
2005 break;
2006 case SS_PATLOOP: /* SBx pattern loop */
2007 DoEEffects(tick, flags, a, mod, channel, 0x60|inf);
2008 break;
2009 case SS_NOTECUT: /* SCx notecut */
2010 if (!inf) inf = 1;
2011 DoEEffects(tick, flags, a, mod, channel, 0xC0|inf);
2012 break;
2013 case SS_NOTEDELAY: /* SDx notedelay */
2014 DoEEffects(tick, flags, a, mod, channel, 0xD0|inf);
2015 break;
2016 case SS_PATDELAY: /* SEx patterndelay */
2017 DoEEffects(tick, flags, a, mod, channel, 0xE0|inf);
2018 break;
2021 return 0;
2024 /*========== Impulse Tracker Volume/Pan Column effects */
2027 * All volume/pan column effects share the same memory space.
2030 static int DoVolEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2032 UBYTE c, inf;
2034 c = UniGetByte();
2035 inf = UniGetByte();
2037 if ((!c)&&(!inf)) {
2038 c=a->voleffect;
2039 inf=a->voldata;
2040 } else {
2041 a->voleffect=c;
2042 a->voldata=inf;
2045 if (c)
2046 switch (c) {
2047 case VOL_VOLUME:
2048 if (tick) break;
2049 if (inf>64) inf=64;
2050 a->tmpvolume=inf;
2051 break;
2052 case VOL_PANNING:
2053 if (mod->panflag)
2054 a->main.panning=inf;
2055 break;
2056 case VOL_VOLSLIDE:
2057 DoS3MVolSlide(tick, flags, a, inf);
2058 return 1;
2059 case VOL_PITCHSLIDEDN:
2060 if (a->main.period)
2061 DoS3MSlideDn(tick, a, inf);
2062 break;
2063 case VOL_PITCHSLIDEUP:
2064 if (a->main.period)
2065 DoS3MSlideUp(tick, a, inf);
2066 break;
2067 case VOL_PORTAMENTO:
2068 DoITToneSlide(tick, a, inf);
2069 break;
2070 case VOL_VIBRATO:
2071 DoITVibrato(tick, a, inf);
2072 break;
2075 return 0;
2078 /*========== UltraTracker effects */
2080 static int DoULTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2082 UWORD offset=UniGetWord();
2084 if (offset)
2085 a->ultoffset=offset;
2087 a->main.start=a->ultoffset<<2;
2088 if ((a->main.s)&&(a->main.start>a->main.s->length))
2089 a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
2090 a->main.s->loopstart:a->main.s->length;
2092 return 0;
2095 /*========== OctaMED effects */
2097 static int DoMEDSpeed(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2099 UWORD speed=UniGetWord();
2101 mod->bpm=speed;
2103 return 0;
2106 static int DoMEDEffectF1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2108 DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/2));
2110 return 0;
2113 static int DoMEDEffectF2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2115 DoEEffects(tick, flags, a, mod, channel, 0xd0|(mod->sngspd/2));
2117 return 0;
2120 static int DoMEDEffectF3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2122 DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/3));
2124 return 0;
2127 /*========== Oktalyzer effects */
2129 static int DoOktArp(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2131 UBYTE dat, dat2;
2133 dat2 = UniGetByte(); /* arpeggio style */
2134 dat = UniGetByte();
2135 if (!tick) {
2136 if (!dat && (flags & UF_ARPMEM))
2137 dat=a->arpmem;
2138 else
2139 a->arpmem=dat;
2141 if (a->main.period)
2142 DoArpeggio(tick, flags, a, dat2);
2144 return 0;
2147 /*========== General player functions */
2149 static int DoNothing(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2151 UniSkipOpcode();
2153 return 0;
2156 typedef int (*effect_func) (UWORD, UWORD, MP_CONTROL *, MODULE *, SWORD);
2158 static effect_func effects[UNI_LAST] = {
2159 DoNothing, /* 0 */
2160 DoNothing, /* UNI_NOTE */
2161 DoNothing, /* UNI_INSTRUMENT */
2162 DoPTEffect0, /* UNI_PTEFFECT0 */
2163 DoPTEffect1, /* UNI_PTEFFECT1 */
2164 DoPTEffect2, /* UNI_PTEFFECT2 */
2165 DoPTEffect3, /* UNI_PTEFFECT3 */
2166 DoPTEffect4, /* UNI_PTEFFECT4 */
2167 DoPTEffect5, /* UNI_PTEFFECT5 */
2168 DoPTEffect6, /* UNI_PTEFFECT6 */
2169 DoPTEffect7, /* UNI_PTEFFECT7 */
2170 DoPTEffect8, /* UNI_PTEFFECT8 */
2171 DoPTEffect9, /* UNI_PTEFFECT9 */
2172 DoPTEffectA, /* UNI_PTEFFECTA */
2173 DoPTEffectB, /* UNI_PTEFFECTB */
2174 DoPTEffectC, /* UNI_PTEFFECTC */
2175 DoPTEffectD, /* UNI_PTEFFECTD */
2176 DoPTEffectE, /* UNI_PTEFFECTE */
2177 DoPTEffectF, /* UNI_PTEFFECTF */
2178 DoS3MEffectA, /* UNI_S3MEFFECTA */
2179 DoS3MEffectD, /* UNI_S3MEFFECTD */
2180 DoS3MEffectE, /* UNI_S3MEFFECTE */
2181 DoS3MEffectF, /* UNI_S3MEFFECTF */
2182 DoS3MEffectI, /* UNI_S3MEFFECTI */
2183 DoS3MEffectQ, /* UNI_S3MEFFECTQ */
2184 DoS3MEffectR, /* UNI_S3MEFFECTR */
2185 DoS3MEffectT, /* UNI_S3MEFFECTT */
2186 DoS3MEffectU, /* UNI_S3MEFFECTU */
2187 DoKeyOff, /* UNI_KEYOFF */
2188 DoKeyFade, /* UNI_KEYFADE */
2189 DoVolEffects, /* UNI_VOLEFFECTS */
2190 DoPTEffect4, /* UNI_XMEFFECT4 */
2191 DoXMEffect6, /* UNI_XMEFFECT6 */
2192 DoXMEffectA, /* UNI_XMEFFECTA */
2193 DoXMEffectE1, /* UNI_XMEFFECTE1 */
2194 DoXMEffectE2, /* UNI_XMEFFECTE2 */
2195 DoXMEffectEA, /* UNI_XMEFFECTEA */
2196 DoXMEffectEB, /* UNI_XMEFFECTEB */
2197 DoXMEffectG, /* UNI_XMEFFECTG */
2198 DoXMEffectH, /* UNI_XMEFFECTH */
2199 DoXMEffectL, /* UNI_XMEFFECTL */
2200 DoXMEffectP, /* UNI_XMEFFECTP */
2201 DoXMEffectX1, /* UNI_XMEFFECTX1 */
2202 DoXMEffectX2, /* UNI_XMEFFECTX2 */
2203 DoITEffectG, /* UNI_ITEFFECTG */
2204 DoITEffectH, /* UNI_ITEFFECTH */
2205 DoITEffectI, /* UNI_ITEFFECTI */
2206 DoITEffectM, /* UNI_ITEFFECTM */
2207 DoITEffectN, /* UNI_ITEFFECTN */
2208 DoITEffectP, /* UNI_ITEFFECTP */
2209 DoITEffectT, /* UNI_ITEFFECTT */
2210 DoITEffectU, /* UNI_ITEFFECTU */
2211 DoITEffectW, /* UNI_ITEFFECTW */
2212 DoITEffectY, /* UNI_ITEFFECTY */
2213 DoNothing, /* UNI_ITEFFECTZ */
2214 DoITEffectS0, /* UNI_ITEFFECTS0 */
2215 DoULTEffect9, /* UNI_ULTEFFECT9 */
2216 DoMEDSpeed, /* UNI_MEDSPEED */
2217 DoMEDEffectF1, /* UNI_MEDEFFECTF1 */
2218 DoMEDEffectF2, /* UNI_MEDEFFECTF2 */
2219 DoMEDEffectF3, /* UNI_MEDEFFECTF3 */
2220 DoOktArp, /* UNI_OKTARP */
2223 static int pt_playeffects(MODULE *mod, SWORD channel, MP_CONTROL *a)
2225 UWORD tick = mod->vbtick;
2226 UWORD flags = mod->flags;
2227 UBYTE c;
2228 int explicitslides = 0;
2229 effect_func f;
2231 while((c=UniGetByte())) {
2232 f = effects[c];
2233 if (f != DoNothing)
2234 a->sliding = 0;
2235 explicitslides |= f(tick, flags, a, mod, channel);
2237 return explicitslides;
2240 static void DoNNAEffects(MODULE *mod, MP_CONTROL *a, UBYTE dat)
2242 int t;
2243 MP_VOICE *aout;
2245 dat&=0xf;
2246 aout=(a->slave)?a->slave:NULL;
2248 switch (dat) {
2249 case 0x0: /* past note cut */
2250 for (t=0;t<md_sngchn;t++)
2251 if (mod->voice[t].master==a)
2252 mod->voice[t].main.fadevol=0;
2253 break;
2254 case 0x1: /* past note off */
2255 for (t=0;t<md_sngchn;t++)
2256 if (mod->voice[t].master==a) {
2257 mod->voice[t].main.keyoff|=KEY_OFF;
2258 if ((!(mod->voice[t].venv.flg & EF_ON))||
2259 (mod->voice[t].venv.flg & EF_LOOP))
2260 mod->voice[t].main.keyoff=KEY_KILL;
2262 break;
2263 case 0x2: /* past note fade */
2264 for (t=0;t<md_sngchn;t++)
2265 if (mod->voice[t].master==a)
2266 mod->voice[t].main.keyoff|=KEY_FADE;
2267 break;
2268 case 0x3: /* set NNA note cut */
2269 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CUT;
2270 break;
2271 case 0x4: /* set NNA note continue */
2272 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CONTINUE;
2273 break;
2274 case 0x5: /* set NNA note off */
2275 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_OFF;
2276 break;
2277 case 0x6: /* set NNA note fade */
2278 a->main.nna=(a->main.nna&~NNA_MASK)|NNA_FADE;
2279 break;
2280 case 0x7: /* disable volume envelope */
2281 if (aout)
2282 aout->main.volflg&=~EF_ON;
2283 break;
2284 case 0x8: /* enable volume envelope */
2285 if (aout)
2286 aout->main.volflg|=EF_ON;
2287 break;
2288 case 0x9: /* disable panning envelope */
2289 if (aout)
2290 aout->main.panflg&=~EF_ON;
2291 break;
2292 case 0xa: /* enable panning envelope */
2293 if (aout)
2294 aout->main.panflg|=EF_ON;
2295 break;
2296 case 0xb: /* disable pitch envelope */
2297 if (aout)
2298 aout->main.pitflg&=~EF_ON;
2299 break;
2300 case 0xc: /* enable pitch envelope */
2301 if (aout)
2302 aout->main.pitflg|=EF_ON;
2303 break;
2307 void pt_UpdateVoices(MODULE *mod, int max_volume)
2309 SWORD envpan,envvol,envpit,channel;
2310 UWORD playperiod;
2311 SLONG vibval,vibdpt;
2312 ULONG tmpvol;
2314 MP_VOICE *aout;
2315 INSTRUMENT *i;
2316 SAMPLE *s;
2318 mod->totalchn=mod->realchn=0;
2319 for (channel=0;channel<md_sngchn;channel++) {
2320 aout=&mod->voice[channel];
2321 i=aout->main.i;
2322 s=aout->main.s;
2324 if (!s || !s->length) continue;
2326 if (aout->main.period<40)
2327 aout->main.period=40;
2328 else if (aout->main.period>50000)
2329 aout->main.period=50000;
2331 if ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_KEYOFF)) {
2332 Voice_Play_internal(channel,s,(aout->main.start==-1)?
2333 ((s->flags&SF_UST_LOOP)?s->loopstart:0):aout->main.start);
2334 aout->main.fadevol=32768;
2335 aout->aswppos=0;
2338 envvol = 256;
2339 envpan = PAN_CENTER;
2340 envpit = 32;
2341 if (i && ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_ENV))) {
2342 if (aout->main.volflg & EF_ON)
2343 envvol = StartEnvelope(&aout->venv,aout->main.volflg,
2344 i->volpts,i->volsusbeg,i->volsusend,
2345 i->volbeg,i->volend,i->volenv,aout->main.keyoff);
2346 if (aout->main.panflg & EF_ON)
2347 envpan = StartEnvelope(&aout->penv,aout->main.panflg,
2348 i->panpts,i->pansusbeg,i->pansusend,
2349 i->panbeg,i->panend,i->panenv,aout->main.keyoff);
2350 if (aout->main.pitflg & EF_ON)
2351 envpit = StartEnvelope(&aout->cenv,aout->main.pitflg,
2352 i->pitpts,i->pitsusbeg,i->pitsusend,
2353 i->pitbeg,i->pitend,i->pitenv,aout->main.keyoff);
2355 if (aout->cenv.flg & EF_ON)
2356 aout->masterperiod=GetPeriod(mod->flags,
2357 (UWORD)aout->main.note<<1, aout->master->speed);
2358 } else {
2359 if (aout->main.volflg & EF_ON)
2360 envvol = ProcessEnvelope(aout,&aout->venv,256);
2361 if (aout->main.panflg & EF_ON)
2362 envpan = ProcessEnvelope(aout,&aout->penv,PAN_CENTER);
2363 if (aout->main.pitflg & EF_ON)
2364 envpit = ProcessEnvelope(aout,&aout->cenv,32);
2366 if (aout->main.kick == KICK_NOTE) {
2367 aout->main.kick_flag = 1;
2369 aout->main.kick=KICK_ABSENT;
2371 tmpvol = aout->main.fadevol; /* max 32768 */
2372 tmpvol *= aout->main.chanvol; /* * max 64 */
2373 tmpvol *= aout->main.outvolume; /* * max 256 */
2374 tmpvol /= (256 * 64); /* tmpvol is max 32768 again */
2375 aout->totalvol = tmpvol >> 2; /* used to determine samplevolume */
2376 tmpvol *= envvol; /* * max 256 */
2377 tmpvol *= mod->volume; /* * max 128 */
2378 tmpvol /= (128 * 256 * 128);
2380 /* fade out */
2381 if (mod->sngpos>=mod->numpos)
2382 tmpvol=0;
2383 else
2384 tmpvol=(tmpvol*max_volume)/128;
2386 if ((aout->masterchn!=-1)&& mod->control[aout->masterchn].muted)
2387 Voice_SetVolume_internal(channel,0);
2388 else {
2389 Voice_SetVolume_internal(channel,tmpvol);
2390 if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))
2391 mod->realchn++;
2392 mod->totalchn++;
2395 if (aout->main.panning==PAN_SURROUND)
2396 Voice_SetPanning_internal(channel,PAN_SURROUND);
2397 else
2398 if ((mod->panflag)&&(aout->penv.flg & EF_ON))
2399 Voice_SetPanning_internal(channel,
2400 DoPan(envpan,aout->main.panning));
2401 else
2402 Voice_SetPanning_internal(channel,aout->main.panning);
2404 if (aout->main.period && s->vibdepth)
2405 switch (s->vibtype) {
2406 case 0:
2407 vibval=avibtab[s->avibpos&127];
2408 if (aout->avibpos & 0x80) vibval=-vibval;
2409 break;
2410 case 1:
2411 vibval=64;
2412 if (aout->avibpos & 0x80) vibval=-vibval;
2413 break;
2414 case 2:
2415 vibval=63-(((aout->avibpos+128)&255)>>1);
2416 break;
2417 default:
2418 vibval=(((aout->avibpos+128)&255)>>1)-64;
2419 break;
2421 else
2422 vibval=0;
2424 if (s->vibflags & AV_IT) {
2425 if ((aout->aswppos>>8)<s->vibdepth) {
2426 aout->aswppos += s->vibsweep;
2427 vibdpt=aout->aswppos;
2428 } else
2429 vibdpt=s->vibdepth<<8;
2430 vibval=(vibval*vibdpt)>>16;
2431 if (aout->mflag) {
2432 if (!(mod->flags&UF_LINEAR)) vibval>>=1;
2433 aout->main.period-=vibval;
2435 } else {
2436 /* do XM style auto-vibrato */
2437 if (!(aout->main.keyoff & KEY_OFF)) {
2438 if (aout->aswppos<s->vibsweep) {
2439 vibdpt=(aout->aswppos*s->vibdepth)/s->vibsweep;
2440 aout->aswppos++;
2441 } else
2442 vibdpt=s->vibdepth;
2443 } else {
2444 /* keyoff -> depth becomes 0 if final depth wasn't reached or
2445 stays at final level if depth WAS reached */
2446 if (aout->aswppos>=s->vibsweep)
2447 vibdpt=s->vibdepth;
2448 else
2449 vibdpt=0;
2451 vibval=(vibval*vibdpt)>>8;
2452 aout->main.period-=vibval;
2455 /* update vibrato position */
2456 aout->avibpos=(aout->avibpos+s->vibrate)&0xff;
2458 /* process pitch envelope */
2459 playperiod=aout->main.period;
2461 if ((aout->main.pitflg&EF_ON)&&(envpit!=32)) {
2462 long p1;
2464 envpit-=32;
2465 if ((aout->main.note<<1)+envpit<=0) envpit=-(aout->main.note<<1);
2467 p1=GetPeriod(mod->flags, ((UWORD)aout->main.note<<1)+envpit,
2468 aout->master->speed)-aout->masterperiod;
2469 if (p1>0) {
2470 if ((UWORD)(playperiod+p1)<=playperiod) {
2471 p1=0;
2472 aout->main.keyoff|=KEY_OFF;
2474 } else if (p1<0) {
2475 if ((UWORD)(playperiod+p1)>=playperiod) {
2476 p1=0;
2477 aout->main.keyoff|=KEY_OFF;
2480 playperiod+=p1;
2483 if (!aout->main.fadevol) { /* check for a dead note (fadevol=0) */
2484 Voice_Stop_internal(channel);
2485 mod->totalchn--;
2486 if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))
2487 mod->realchn--;
2488 } else {
2489 Voice_SetFrequency_internal(channel,
2490 getfrequency(mod->flags,playperiod));
2492 /* if keyfade, start substracting fadeoutspeed from fadevol: */
2493 if ((i)&&(aout->main.keyoff&KEY_FADE)) {
2494 if (aout->main.fadevol>=i->volfade)
2495 aout->main.fadevol-=i->volfade;
2496 else
2497 aout->main.fadevol=0;
2501 md_bpm=mod->bpm+mod->relspd;
2502 if (md_bpm<32)
2503 md_bpm=32;
2504 else if ((!(mod->flags&UF_HIGHBPM)) && md_bpm>255)
2505 md_bpm=255;
2509 /* Handles new notes or instruments */
2510 void pt_Notes(MODULE *mod)
2512 SWORD channel;
2513 MP_CONTROL *a;
2514 UBYTE c,inst;
2515 int tr,funky; /* funky is set to indicate note or instrument change */
2517 for (channel=0;channel<mod->numchn;channel++) {
2518 a=&mod->control[channel];
2520 if (mod->sngpos>=mod->numpos) {
2521 tr=mod->numtrk;
2522 mod->numrow=0;
2523 } else {
2524 tr=mod->patterns[(mod->positions[mod->sngpos]*mod->numchn)+channel];
2525 mod->numrow=mod->pattrows[mod->positions[mod->sngpos]];
2528 a->row=(tr<mod->numtrk)?UniFindRow(mod->tracks[tr],mod->patpos):NULL;
2529 a->newsamp=0;
2530 if (!mod->vbtick) a->main.notedelay=0;
2532 if (!a->row) continue;
2533 UniSetRow(a->row);
2534 funky=0;
2536 while((c=UniGetByte()))
2537 switch (c) {
2538 case UNI_NOTE:
2539 funky|=1;
2540 a->oldnote=a->anote,a->anote=UniGetByte();
2541 a->main.kick =KICK_NOTE;
2542 a->main.start=-1;
2543 a->sliding=0;
2545 /* retrig tremolo and vibrato waves ? */
2546 if (!(a->wavecontrol & 0x80)) a->trmpos=0;
2547 if (!(a->wavecontrol & 0x08)) a->vibpos=0;
2548 if (!a->panbwave) a->panbpos=0;
2549 break;
2550 case UNI_INSTRUMENT:
2551 inst=UniGetByte();
2552 if (inst>=mod->numins) break; /* safety valve */
2553 funky|=2;
2554 a->main.i=(mod->flags & UF_INST)?&mod->instruments[inst]:NULL;
2555 a->retrig=0;
2556 a->s3mtremor=0;
2557 a->ultoffset=0;
2558 a->main.sample=inst;
2559 break;
2560 default:
2561 UniSkipOpcode();
2562 break;
2565 if (funky) {
2566 INSTRUMENT *i;
2567 SAMPLE *s;
2569 if ((i=a->main.i)) {
2570 if (i->samplenumber[a->anote] >= mod->numsmp) continue;
2571 s=&mod->samples[i->samplenumber[a->anote]];
2572 a->main.note=i->samplenote[a->anote];
2573 } else {
2574 a->main.note=a->anote;
2575 s=&mod->samples[a->main.sample];
2578 if (a->main.s!=s) {
2579 a->main.s=s;
2580 a->newsamp=a->main.period;
2583 /* channel or instrument determined panning ? */
2584 a->main.panning=mod->panning[channel];
2585 if (s->flags & SF_OWNPAN)
2586 a->main.panning=s->panning;
2587 else if ((i)&&(i->flags & IF_OWNPAN))
2588 a->main.panning=i->panning;
2590 a->main.handle=s->handle;
2591 a->speed=s->speed;
2593 if (i) {
2594 if ((mod->panflag)&&(i->flags & IF_PITCHPAN)
2595 &&(a->main.panning!=PAN_SURROUND)){
2596 a->main.panning+=
2597 ((a->anote-i->pitpancenter)*i->pitpansep)/8;
2598 if (a->main.panning<PAN_LEFT)
2599 a->main.panning=PAN_LEFT;
2600 else if (a->main.panning>PAN_RIGHT)
2601 a->main.panning=PAN_RIGHT;
2603 a->main.pitflg=i->pitflg;
2604 a->main.volflg=i->volflg;
2605 a->main.panflg=i->panflg;
2606 a->main.nna=i->nnatype;
2607 a->dca=i->dca;
2608 a->dct=i->dct;
2609 } else {
2610 a->main.pitflg=a->main.volflg=a->main.panflg=0;
2611 a->main.nna=a->dca=0;
2612 a->dct=DCT_OFF;
2615 if (funky&2) /* instrument change */ {
2616 /* IT random volume variations: 0:8 bit fixed, and one bit for
2617 sign. */
2618 a->volume=a->tmpvolume=s->volume;
2619 if ((s)&&(i)) {
2620 if (i->rvolvar) {
2621 a->volume=a->tmpvolume=s->volume+
2622 ((s->volume*((SLONG)i->rvolvar*(SLONG)getrandom(512)
2623 ))/25600);
2624 if (a->volume<0)
2625 a->volume=a->tmpvolume=0;
2626 else if (a->volume>64)
2627 a->volume=a->tmpvolume=64;
2629 if ((mod->panflag)&&(a->main.panning!=PAN_SURROUND)) {
2630 a->main.panning+=((a->main.panning*((SLONG)i->rpanvar*
2631 (SLONG)getrandom(512)))/25600);
2632 if (a->main.panning<PAN_LEFT)
2633 a->main.panning=PAN_LEFT;
2634 else if (a->main.panning>PAN_RIGHT)
2635 a->main.panning=PAN_RIGHT;
2640 a->wantedperiod=a->tmpperiod=
2641 GetPeriod(mod->flags, (UWORD)a->main.note<<1,a->speed);
2642 a->main.keyoff=KEY_KICK;
2647 /* Handles effects */
2648 void pt_EffectsPass1(MODULE *mod)
2650 SWORD channel;
2651 MP_CONTROL *a;
2652 MP_VOICE *aout;
2653 int explicitslides;
2655 for (channel=0;channel<mod->numchn;channel++) {
2656 a=&mod->control[channel];
2658 if ((aout=a->slave)) {
2659 a->main.fadevol=aout->main.fadevol;
2660 a->main.period=aout->main.period;
2661 if (a->main.kick==KICK_KEYOFF)
2662 a->main.keyoff=aout->main.keyoff;
2665 if (!a->row) continue;
2666 UniSetRow(a->row);
2668 a->ownper=a->ownvol=0;
2669 explicitslides = pt_playeffects(mod, channel, a);
2671 /* continue volume slide if necessary for XM and IT */
2672 if (mod->flags&UF_BGSLIDES) {
2673 if (!explicitslides && a->sliding)
2674 DoS3MVolSlide(mod->vbtick, mod->flags, a, 0);
2675 else if (a->tmpvolume)
2676 a->sliding = explicitslides;
2679 if (!a->ownper)
2680 a->main.period=a->tmpperiod;
2681 if (!a->ownvol)
2682 a->volume=a->tmpvolume;
2684 if (a->main.s) {
2685 if (a->main.i)
2686 a->main.outvolume=
2687 (a->volume*a->main.s->globvol*a->main.i->globvol)>>10;
2688 else
2689 a->main.outvolume=(a->volume*a->main.s->globvol)>>4;
2690 if (a->main.outvolume>256)
2691 a->main.outvolume=256;
2692 else if (a->main.outvolume<0)
2693 a->main.outvolume=0;
2698 /* NNA management */
2699 void pt_NNA(MODULE *mod)
2701 SWORD channel;
2702 MP_CONTROL *a;
2704 for (channel=0;channel<mod->numchn;channel++) {
2705 a=&mod->control[channel];
2707 if (a->main.kick==KICK_NOTE) {
2708 int kill=0;
2710 if (a->slave) {
2711 MP_VOICE *aout;
2713 aout=a->slave;
2714 if (aout->main.nna & NNA_MASK) {
2715 /* Make sure the old MP_VOICE channel knows it has no
2716 master now ! */
2717 a->slave=NULL;
2718 /* assume the channel is taken by NNA */
2719 aout->mflag=0;
2721 switch (aout->main.nna) {
2722 case NNA_CONTINUE: /* continue note, do nothing */
2723 break;
2724 case NNA_OFF: /* note off */
2725 aout->main.keyoff|=KEY_OFF;
2726 if ((!(aout->main.volflg & EF_ON))||
2727 (aout->main.volflg & EF_LOOP))
2728 aout->main.keyoff=KEY_KILL;
2729 break;
2730 case NNA_FADE:
2731 aout->main.keyoff |= KEY_FADE;
2732 break;
2737 if (a->dct!=DCT_OFF) {
2738 int t;
2740 for (t=0;t<md_sngchn;t++)
2741 if ((!Voice_Stopped_internal(t))&&
2742 (mod->voice[t].masterchn==channel)&&
2743 (a->main.sample==mod->voice[t].main.sample)) {
2744 kill=0;
2745 switch (a->dct) {
2746 case DCT_NOTE:
2747 if (a->main.note==mod->voice[t].main.note)
2748 kill=1;
2749 break;
2750 case DCT_SAMPLE:
2751 if (a->main.handle==mod->voice[t].main.handle)
2752 kill=1;
2753 break;
2754 case DCT_INST:
2755 kill=1;
2756 break;
2758 if (kill)
2759 switch (a->dca) {
2760 case DCA_CUT:
2761 mod->voice[t].main.fadevol=0;
2762 break;
2763 case DCA_OFF:
2764 mod->voice[t].main.keyoff|=KEY_OFF;
2765 if ((!(mod->voice[t].main.volflg&EF_ON))||
2766 (mod->voice[t].main.volflg&EF_LOOP))
2767 mod->voice[t].main.keyoff=KEY_KILL;
2768 break;
2769 case DCA_FADE:
2770 mod->voice[t].main.keyoff|=KEY_FADE;
2771 break;
2775 } /* if (a->main.kick==KICK_NOTE) */
2779 /* Setup module and NNA voices */
2780 void pt_SetupVoices(MODULE *mod)
2782 SWORD channel;
2783 MP_CONTROL *a;
2784 MP_VOICE *aout;
2786 for (channel=0;channel<mod->numchn;channel++) {
2787 a=&mod->control[channel];
2789 if (a->main.notedelay) continue;
2790 if (a->main.kick==KICK_NOTE) {
2791 /* if no channel was cut above, find an empty or quiet channel
2792 here */
2793 if (mod->flags&UF_NNA) {
2794 if (!a->slave) {
2795 int newchn;
2797 if ((newchn=MP_FindEmptyChannel(mod))!=-1)
2798 a->slave=&mod->voice[a->slavechn=newchn];
2800 } else
2801 a->slave=&mod->voice[a->slavechn=channel];
2803 /* assign parts of MP_VOICE only done for a KICK_NOTE */
2804 if ((aout=a->slave)) {
2805 if (aout->mflag && aout->master) aout->master->slave=NULL;
2806 aout->master=a;
2807 a->slave=aout;
2808 aout->masterchn=channel;
2809 aout->mflag=1;
2811 } else
2812 aout=a->slave;
2814 if (aout)
2815 aout->main=a->main;
2816 a->main.kick=KICK_ABSENT;
2820 /* second effect pass */
2821 void pt_EffectsPass2(MODULE *mod)
2823 SWORD channel;
2824 MP_CONTROL *a;
2825 UBYTE c;
2827 for (channel=0;channel<mod->numchn;channel++) {
2828 a=&mod->control[channel];
2830 if (!a->row) continue;
2831 UniSetRow(a->row);
2833 while((c=UniGetByte()))
2834 if (c==UNI_ITEFFECTS0) {
2835 c=UniGetByte();
2836 if ((c>>4)==SS_S7EFFECTS)
2837 DoNNAEffects(mod, a, c&0xf);
2838 } else
2839 UniSkipOpcode();
2843 void Player_HandleTick(void)
2845 SWORD channel;
2846 int max_volume;
2848 #if 0
2849 /* don't handle the very first ticks, this allows the other hardware to
2850 settle down so we don't loose any starting notes */
2851 if (isfirst) {
2852 isfirst--;
2853 return;
2855 #endif
2857 if ((!pf)||(pf->forbid)||(pf->sngpos>=pf->numpos)) return;
2859 /* update time counter (sngtime is in milliseconds (in fact 2^-10)) */
2860 pf->sngremainder+=(1<<9)*5; /* thus 2.5*(1<<10), since fps=0.4xtempo */
2861 pf->sngtime+=pf->sngremainder/pf->bpm;
2862 pf->sngremainder%=pf->bpm;
2864 if (++pf->vbtick>=pf->sngspd) {
2865 if (pf->pat_repcrazy)
2866 pf->pat_repcrazy=0; /* play 2 times row 0 */
2867 else
2868 pf->patpos++;
2869 pf->vbtick=0;
2871 /* process pattern-delay. pf->patdly2 is the counter and pf->patdly is
2872 the command memory. */
2873 if (pf->patdly)
2874 pf->patdly2=pf->patdly,pf->patdly=0;
2875 if (pf->patdly2) {
2876 /* patterndelay active */
2877 if (--pf->patdly2)
2878 /* so turn back pf->patpos by 1 */
2879 if (pf->patpos) pf->patpos--;
2882 /* do we have to get a new patternpointer ? (when pf->patpos reaches the
2883 pattern size, or when a patternbreak is active) */
2884 if (((pf->patpos>=pf->numrow)&&(pf->numrow>0))&&(!pf->posjmp))
2885 pf->posjmp=3;
2887 if (pf->posjmp) {
2888 pf->patpos=pf->numrow?(pf->patbrk%pf->numrow):0;
2889 pf->pat_repcrazy=0;
2890 pf->sngpos+=(pf->posjmp-2);
2891 for (channel=0;channel<pf->numchn;channel++)
2892 pf->control[channel].pat_reppos=-1;
2894 pf->patbrk=pf->posjmp=0;
2895 /* handle the "---" (end of song) pattern since it can occur
2896 *inside* the module in some formats */
2897 if ((pf->sngpos>=pf->numpos)||
2898 (pf->positions[pf->sngpos]==LAST_PATTERN)) {
2899 if (!pf->wrap) return;
2900 if (!(pf->sngpos=pf->reppos)) {
2901 pf->volume=pf->initvolume>128?128:pf->initvolume;
2902 if(pf->initspeed!=0)
2903 pf->sngspd=pf->initspeed<32?pf->initspeed:32;
2904 else
2905 pf->sngspd=6;
2906 pf->bpm=pf->inittempo<32?32:pf->inittempo;
2909 if (pf->sngpos<0) pf->sngpos=pf->numpos-1;
2912 if (!pf->patdly2)
2913 pt_Notes(pf);
2916 /* Fade global volume if enabled and we're playing the last pattern */
2917 if (((pf->sngpos==pf->numpos-1)||
2918 (pf->positions[pf->sngpos+1]==LAST_PATTERN))&&
2919 (pf->fadeout))
2920 max_volume=pf->numrow?((pf->numrow-pf->patpos)*128)/pf->numrow:0;
2921 else
2922 max_volume=128;
2924 pt_EffectsPass1(pf);
2925 if (pf->flags&UF_NNA)
2926 pt_NNA(pf);
2927 pt_SetupVoices(pf);
2928 pt_EffectsPass2(pf);
2930 /* now set up the actual hardware channel playback information */
2931 pt_UpdateVoices(pf, max_volume);
2934 static void Player_Init_internal(MODULE* mod)
2936 int t;
2938 for (t=0;t<mod->numchn;t++) {
2939 mod->control[t].main.chanvol=mod->chanvol[t];
2940 mod->control[t].main.panning=mod->panning[t];
2943 mod->sngtime=0;
2944 mod->sngremainder=0;
2946 mod->pat_repcrazy=0;
2947 mod->sngpos=0;
2948 if(mod->initspeed!=0)
2949 mod->sngspd=mod->initspeed<32?mod->initspeed:32;
2950 else
2951 mod->sngspd=6;
2952 mod->volume=mod->initvolume>128?128:mod->initvolume;
2954 mod->vbtick=mod->sngspd;
2955 mod->patdly=0;
2956 mod->patdly2=0;
2957 mod->bpm=mod->inittempo<32?32:mod->inittempo;
2958 mod->realchn=0;
2960 mod->patpos=0;
2961 mod->posjmp=2; /* make sure the player fetches the first note */
2962 mod->numrow=-1;
2963 mod->patbrk=0;
2966 int Player_Init(MODULE* mod)
2968 mod->extspd=1;
2969 mod->panflag=1;
2970 mod->wrap=0;
2971 mod->loop=1;
2972 mod->fadeout=0;
2974 mod->relspd=0;
2976 /* make sure the player doesn't start with garbage */
2977 if (!(mod->control=(MP_CONTROL*)MikMod_calloc(mod->numchn,sizeof(MP_CONTROL))))
2978 return 1;
2979 if (!(mod->voice=(MP_VOICE*)MikMod_calloc(md_sngchn,sizeof(MP_VOICE))))
2980 return 1;
2982 Player_Init_internal(mod);
2983 return 0;
2986 void Player_Exit_internal(MODULE* mod)
2988 if (!mod)
2989 return;
2991 /* Stop playback if necessary */
2992 if (mod==pf) {
2993 Player_Stop_internal();
2994 pf=NULL;
2997 if (mod->control)
2998 MikMod_free(mod->control);
2999 if (mod->voice)
3000 MikMod_free(mod->voice);
3001 mod->control=NULL;
3002 mod->voice=NULL;
3005 void Player_Exit(MODULE* mod)
3007 MUTEX_LOCK(vars);
3008 Player_Exit_internal(mod);
3009 MUTEX_UNLOCK(vars);
3012 MIKMODAPI void Player_SetVolume(SWORD volume)
3014 MUTEX_LOCK(vars);
3015 if (pf)
3016 pf->volume=(volume<0)?0:(volume>128)?128:volume;
3017 MUTEX_UNLOCK(vars);
3020 MIKMODAPI MODULE* Player_GetModule(void)
3022 MODULE* result;
3024 MUTEX_LOCK(vars);
3025 result=pf;
3026 MUTEX_UNLOCK(vars);
3028 return result;
3031 MIKMODAPI void Player_Start(MODULE *mod)
3033 int t;
3035 if (!mod)
3036 return;
3038 if (!MikMod_Active())
3039 MikMod_EnableOutput();
3041 mod->forbid=0;
3043 MUTEX_LOCK(vars);
3044 if (pf!=mod) {
3045 /* new song is being started, so completely stop out the old one. */
3046 if (pf) pf->forbid=1;
3047 for (t=0;t<md_sngchn;t++) Voice_Stop_internal(t);
3049 pf=mod;
3050 MUTEX_UNLOCK(vars);
3053 void Player_Stop_internal(void)
3055 if (!md_sfxchn) MikMod_DisableOutput_internal();
3056 if (pf) pf->forbid=1;
3057 pf=NULL;
3060 MIKMODAPI void Player_Stop(void)
3062 MUTEX_LOCK(vars);
3063 Player_Stop_internal();
3064 MUTEX_UNLOCK(vars);
3067 MIKMODAPI int Player_Active(void)
3069 int result=0;
3071 MUTEX_LOCK(vars);
3072 if (pf)
3073 result=(!(pf->sngpos>=pf->numpos));
3074 MUTEX_UNLOCK(vars);
3076 return result;
3079 MIKMODAPI void Player_NextPosition(void)
3081 MUTEX_LOCK(vars);
3082 if (pf) {
3083 int t;
3085 pf->forbid=1;
3086 pf->posjmp=3;
3087 pf->patbrk=0;
3088 pf->vbtick=pf->sngspd;
3090 for (t=0;t<md_sngchn;t++) {
3091 Voice_Stop_internal(t);
3092 pf->voice[t].main.i=NULL;
3093 pf->voice[t].main.s=NULL;
3095 for (t=0;t<pf->numchn;t++) {
3096 pf->control[t].main.i=NULL;
3097 pf->control[t].main.s=NULL;
3099 pf->forbid=0;
3101 MUTEX_UNLOCK(vars);
3104 MIKMODAPI void Player_PrevPosition(void)
3106 MUTEX_LOCK(vars);
3107 if (pf) {
3108 int t;
3110 pf->forbid=1;
3111 pf->posjmp=1;
3112 pf->patbrk=0;
3113 pf->vbtick=pf->sngspd;
3115 for (t=0;t<md_sngchn;t++) {
3116 Voice_Stop_internal(t);
3117 pf->voice[t].main.i=NULL;
3118 pf->voice[t].main.s=NULL;
3120 for (t=0;t<pf->numchn;t++) {
3121 pf->control[t].main.i=NULL;
3122 pf->control[t].main.s=NULL;
3124 pf->forbid=0;
3126 MUTEX_UNLOCK(vars);
3129 MIKMODAPI void Player_SetPosition(UWORD pos)
3131 MUTEX_LOCK(vars);
3132 if (pf) {
3133 int t;
3135 pf->forbid=1;
3136 if (pos>=pf->numpos) pos=pf->numpos;
3137 pf->posjmp=2;
3138 pf->patbrk=0;
3139 pf->sngpos=pos;
3140 pf->vbtick=pf->sngspd;
3142 for (t=0;t<md_sngchn;t++) {
3143 Voice_Stop_internal(t);
3144 pf->voice[t].main.i=NULL;
3145 pf->voice[t].main.s=NULL;
3147 for (t=0;t<pf->numchn;t++) {
3148 pf->control[t].main.i=NULL;
3149 pf->control[t].main.s=NULL;
3151 pf->forbid=0;
3153 if (!pos)
3154 Player_Init_internal(pf);
3156 MUTEX_UNLOCK(vars);
3159 static void Player_Unmute_internal(SLONG arg1,va_list ap)
3161 SLONG t,arg2,arg3=0;
3163 if (pf) {
3164 switch (arg1) {
3165 case MUTE_INCLUSIVE:
3166 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3167 (arg2>arg3)||(arg3>=pf->numchn))
3168 return;
3169 for (;arg2<pf->numchn && arg2<=arg3;arg2++)
3170 pf->control[arg2].muted=0;
3171 break;
3172 case MUTE_EXCLUSIVE:
3173 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3174 (arg2>arg3)||(arg3>=pf->numchn))
3175 return;
3176 for (t=0;t<pf->numchn;t++) {
3177 if ((t>=arg2) && (t<=arg3))
3178 continue;
3179 pf->control[t].muted=0;
3181 break;
3182 default:
3183 if (arg1<pf->numchn) pf->control[arg1].muted=0;
3184 break;
3189 MIKMODAPI void Player_Unmute(SLONG arg1, ...)
3191 va_list args;
3193 va_start(args,arg1);
3194 MUTEX_LOCK(vars);
3195 Player_Unmute_internal(arg1,args);
3196 MUTEX_UNLOCK(vars);
3197 va_end(args);
3200 static void Player_Mute_internal(SLONG arg1,va_list ap)
3202 SLONG t,arg2,arg3=0;
3204 if (pf) {
3205 switch (arg1) {
3206 case MUTE_INCLUSIVE:
3207 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3208 (arg2>arg3)||(arg3>=pf->numchn))
3209 return;
3210 for (;arg2<pf->numchn && arg2<=arg3;arg2++)
3211 pf->control[arg2].muted=1;
3212 break;
3213 case MUTE_EXCLUSIVE:
3214 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3215 (arg2>arg3)||(arg3>=pf->numchn))
3216 return;
3217 for (t=0;t<pf->numchn;t++) {
3218 if ((t>=arg2) && (t<=arg3))
3219 continue;
3220 pf->control[t].muted=1;
3222 break;
3223 default:
3224 if (arg1<pf->numchn)
3225 pf->control[arg1].muted=1;
3226 break;
3231 MIKMODAPI void Player_Mute(SLONG arg1,...)
3233 va_list args;
3235 va_start(args,arg1);
3236 MUTEX_LOCK(vars);
3237 Player_Mute_internal(arg1,args);
3238 MUTEX_UNLOCK(vars);
3239 va_end(args);
3242 static void Player_ToggleMute_internal(SLONG arg1,va_list ap)
3244 SLONG arg2,arg3=0;
3245 ULONG t;
3247 if (pf) {
3248 switch (arg1) {
3249 case MUTE_INCLUSIVE:
3250 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3251 (arg2>arg3)||(arg3>=pf->numchn))
3252 return;
3253 for (;arg2<pf->numchn && arg2<=arg3;arg2++)
3254 pf->control[arg2].muted=1-pf->control[arg2].muted;
3255 break;
3256 case MUTE_EXCLUSIVE:
3257 if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
3258 (arg2>arg3)||(arg3>=pf->numchn))
3259 return;
3260 for (t=0;t<pf->numchn;t++) {
3261 if ((t>=arg2) && (t<=arg3))
3262 continue;
3263 pf->control[t].muted=1-pf->control[t].muted;
3265 break;
3266 default:
3267 if (arg1<pf->numchn)
3268 pf->control[arg1].muted=1-pf->control[arg1].muted;
3269 break;
3274 MIKMODAPI void Player_ToggleMute(SLONG arg1,...)
3276 va_list args;
3278 va_start(args,arg1);
3279 MUTEX_LOCK(vars);
3280 Player_ToggleMute_internal(arg1,args);
3281 MUTEX_UNLOCK(vars);
3282 va_end(args);
3285 MIKMODAPI int Player_Muted(UBYTE chan)
3287 int result=1;
3289 MUTEX_LOCK(vars);
3290 if (pf)
3291 result=(chan<pf->numchn)?pf->control[chan].muted:1;
3292 MUTEX_UNLOCK(vars);
3294 return result;
3297 MIKMODAPI int Player_GetChannelVoice(UBYTE chan)
3299 int result=0;
3301 MUTEX_LOCK(vars);
3302 if (pf)
3303 result=(chan<pf->numchn)?pf->control[chan].slavechn:-1;
3304 MUTEX_UNLOCK(vars);
3306 return result;
3309 MIKMODAPI UWORD Player_GetChannelPeriod(UBYTE chan)
3311 UWORD result=0;
3313 MUTEX_LOCK(vars);
3314 if (pf)
3315 result=(chan<pf->numchn)?pf->control[chan].main.period:0;
3316 MUTEX_UNLOCK(vars);
3318 return result;
3321 int Player_Paused_internal(void)
3323 return pf?pf->forbid:1;
3326 MIKMODAPI int Player_Paused(void)
3328 int result;
3330 MUTEX_LOCK(vars);
3331 result=Player_Paused_internal();
3332 MUTEX_UNLOCK(vars);
3334 return result;
3337 MIKMODAPI void Player_TogglePause(void)
3339 MUTEX_LOCK(vars);
3340 if (pf)
3341 pf->forbid=1-pf->forbid;
3342 MUTEX_UNLOCK(vars);
3345 MIKMODAPI void Player_SetSpeed(UWORD speed)
3347 MUTEX_LOCK(vars);
3348 if (pf)
3349 pf->sngspd=speed?(speed<32?speed:32):1;
3350 MUTEX_UNLOCK(vars);
3353 MIKMODAPI void Player_SetTempo(UWORD tempo)
3355 if (tempo<32) tempo=32;
3356 MUTEX_LOCK(vars);
3357 if (pf) {
3358 if ((!(pf->flags&UF_HIGHBPM))&&(tempo>255)) tempo=255;
3359 pf->bpm=tempo;
3361 MUTEX_UNLOCK(vars);
3364 MIKMODAPI int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo)
3366 int i;
3368 if (numvoices > md_sngchn)
3369 numvoices = md_sngchn;
3371 MUTEX_LOCK(vars);
3372 if (pf)
3373 for (i = 0; i < md_sngchn; i++) {
3374 vinfo [i].i = pf->voice[i].main.i;
3375 vinfo [i].s = pf->voice[i].main.s;
3376 vinfo [i].panning = pf->voice [i].main.panning;
3377 vinfo [i].volume = pf->voice [i].main.chanvol;
3378 vinfo [i].period = pf->voice [i].main.period;
3379 vinfo [i].kick = pf->voice [i].main.kick_flag;
3380 pf->voice [i].main.kick_flag = 0;
3382 MUTEX_UNLOCK(vars);
3384 return numvoices;
3388 // Get current module order
3389 MIKMODAPI int Player_GetOrder(void)
3391 int ret;
3392 MUTEX_LOCK(vars);
3393 ret = pf ? pf->sngpos :0; // pf->positions[pf->sngpos ? pf->sngpos-1 : 0]: 0;
3394 MUTEX_UNLOCK(vars);
3395 return ret;
3398 // Get current module row
3399 MIKMODAPI int Player_GetRow(void)
3401 int ret;
3402 MUTEX_LOCK(vars);
3403 ret = pf ? pf->patpos : 0;
3404 MUTEX_UNLOCK(vars);
3405 return ret;
3409 /* ex:set ts=4: */