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