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