1 /*
2 PLIB - A Suite of Portable Game Libraries
3 Copyright (C) 1998,2002 Steve Baker
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library 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 GNU
13 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 02111-1307 USA
18
19 For further information visit http://plib.sourceforge.net
20
21 $Id: slMODnote.cxx 1568 2002-09-02 06:05:49Z sjbaker $
22 */
23
24
25 #include "slMODPrivate.h"
26
27 static SampleInfo *smp ;
28 static unsigned char chToPlay[32];
29
30 static int masterVol = 0x30 * 4/3;
31 static int globalVol = 0x40;
32 static int mono;
33 static int outRate = DEF_OUTRATE ;
34 static int tempo = DEF_TEMPO ; /* BPM = rows/minute/4 */
35 static int speed = DEF_SPEED ; /* frames/row */
36 static int frameLen = DEF_OUTRATE * 60 / ( DEF_TEMPO * 24 ) ;
37 static int patRepeat = 0 ;
38
39
40
commonWork(Note * np)41 static void commonWork ( Note *np )
42 {
43 _MOD_instClearPFW();
44
45 if (np->ins)
46 _MOD_instSample(&smp[np->ins - 1], 0);
47
48 if (np->note != 255)
49 if (np->note == 254)
50 _MOD_instNoteOff(0);
51 else
52 _MOD_instNote((np->note/16) * 12 + np->note%16, 0);
53
54 if (np->vol != 255)
55 _MOD_instVol(np->vol, 0);
56 }
57
58
noEffect(Note * np)59 static void noEffect ( Note *np )
60 {
61 if ( np->cmd == 255 )
62 _MOD_instEmptyCmd () ;
63
64 commonWork ( np ) ;
65 }
66
67
unknownEffect(Note * np)68 static void unknownEffect ( Note *np )
69 {
70 ulSetError ( UL_WARNING, "Unknown effect: %c%02X", np->cmd + '@', np->info ) ;
71 commonWork ( np ) ;
72 }
73
74 #define X (np->info/16)
75 #define Y (np->info%16)
76
77 /* Dxy, Kxy, Lxy common work */
78
dklCommonWork(Note * np)79 static void dklCommonWork ( Note *np )
80 {
81 if ( np->info )
82 {
83 if ( Y == 0 ) /* Dx0=up */
84 _MOD_instSetVolSlideParams ( X, 1, 1, 1, 0 ) ;
85 else
86 if ( X > 0 && Y == 0xf ) /* DxF=fine up */
87 _MOD_instSetVolSlideParams ( X, 1, 1, 1, 1 ) ;
88 else
89 if ( X == 0xf ) /* DFy=fine down */
90 _MOD_instSetVolSlideParams ( -Y, 1, 1, 1, 1 ) ;
91 else /* D0y=down, but also D46 or something is here */
92 _MOD_instSetVolSlideParams ( -Y, 1, 1, 1, 0 ) ;
93 }
94
95 _MOD_instVolSlide () ;
96 }
97
98 /* Dxy = volume slide */
99
dCmd(Note * np)100 static void dCmd ( Note *np )
101 {
102 commonWork ( np ) ;
103 dklCommonWork ( np ) ;
104 }
105
106 /* Exx, Fxx common work */
107
efCommonWork(Note * np)108 static void efCommonWork ( Note *np )
109 {
110 if (np->info)
111 {
112 switch (X)
113 {
114 case 0xf: /* [EF]Fx = fine */
115 _MOD_instSetPeriodSlideParams((np->info%16)*4, 1);
116 break;
117
118 case 0xe: /* [EF]Ex = extra fine */
119 /* ST3 plays [EF]E0 and [EF]F0 differently */
120 /* so it may be incompatible.. */
121 _MOD_instSetPeriodSlideParams(np->info%16, 1);
122 break;
123
124 default:
125 _MOD_instSetPeriodSlideParams(np->info*4, 0);
126 break;
127 }
128 }
129 }
130
131 /* Exx = slide down */
132
eCmd(Note * np)133 static void eCmd(Note *np)
134 {
135 commonWork(np);
136 efCommonWork(np);
137 _MOD_instPeriodSlideDown();
138 }
139
140 /* Fxx = slide up */
141
fCmd(Note * np)142 static void fCmd(Note *np)
143 {
144 commonWork(np);
145 efCommonWork(np);
146 _MOD_instPeriodSlideUp();
147 }
148
149 /* Gxx = portamento */
150
gCmd(Note * np)151 static void gCmd(Note *np)
152 {
153 _MOD_instClearPFW();
154
155 if (np->ins) _MOD_instSetPortamentoDefaultVol(); /* only set default volume */
156 if (np->vol != 255) _MOD_instVol(np->vol, 0);
157 if (np->note < 254 ) _MOD_instSetPortamentoTo((np->note/16)*12 + np->note%16);
158 if (np->info) _MOD_instSetPortamentoSpeed(np->info*4);
159
160 _MOD_instPortamento();
161 }
162
163 /* Hxy = vibrato */
164
hCmd(Note * np)165 static void hCmd(Note *np)
166 {
167 commonWork(np);
168 if (np->info) _MOD_instSetVibratoParams(X, Y*8);
169 _MOD_instVibrato();
170 }
171
172 /* Ixy = tremor */
173
iCmd(Note * np)174 static void iCmd(Note *np)
175 {
176 commonWork(np);
177 if (np->info) _MOD_instSetTremorParams(X+1, Y+1);
178 _MOD_instTremor();
179 }
180
181 /* Jxy = arpeggio */
182
jCmd(Note * np)183 static void jCmd(Note *np)
184 {
185 commonWork(np);
186 if (np->info) _MOD_instSetArpeggioParams(X, Y);
187 _MOD_instArpeggio();
188 }
189
190 /* Kxy = H00 and Dxy */
191
kCmd(Note * np)192 static void kCmd(Note *np)
193 {
194 commonWork(np);
195 _MOD_instVibrato(); /* H00 */
196 dklCommonWork(np);
197 }
198
199 /* Lxy = G00 and Dxy */
200
lCmd(Note * np)201 static void lCmd(Note *np)
202 {
203 commonWork(np);
204 _MOD_instPortamento(); /* G00 */
205 dklCommonWork(np);
206 }
207
208 /* Oxx = sample offset */
209
oCmd(Note * np)210 static void oCmd(Note *np)
211 {
212 commonWork(np);
213 _MOD_instSampleOffset(np->info * 0x100);
214 }
215
216 /* Qxy = retrig + volumeslide */
217
qCmd(Note * np)218 static void qCmd(Note *np)
219 {
220 static int add[16]={0,-1,-2,-4,-8,-16,0,0,0,1,2,4,8,16,0,0};
221 static int mul[16]={1,1,1,1,1,1,2,1,1,1,1,1,1,1,3,2};
222 static int div[16]={1,1,1,1,1,1,3,2,1,1,1,1,1,1,2,1};
223
224 commonWork(np);
225
226 if (np->info)
227 {
228 _MOD_instSetVolSlideParams(add[X], mul[X], div[X], Y, 0);
229 _MOD_instSetRetrigParam(Y);
230 }
231
232 _MOD_instVolSlide();
233 _MOD_instRetrig();
234 }
235
236 /* Rxy = tremolo */
237
rCmd(Note * np)238 static void rCmd(Note *np)
239 {
240 commonWork(np);
241 if (np->info) _MOD_instSetTremoloParams(X, Y*2);
242 _MOD_instTremolo();
243 }
244
245 /* Uxy = fine vibrato */
246
uCmd(Note * np)247 static void uCmd(Note *np)
248 {
249 commonWork(np);
250 if (np->info) _MOD_instSetVibratoParams(X, Y*2);
251 _MOD_instVibrato();
252 }
253
254 /* Sxy = misc */
255
sCmd(Note * np)256 static void sCmd(Note *np)
257 {
258 if (X == 0xd) /* notedelay */
259 {
260 _MOD_instClearPFW();
261
262 if (np->ins)
263 _MOD_instSample(&smp[np->ins - 1], Y);
264
265 if (np->note != 255)
266 if (np->note == 254)
267 _MOD_instNoteOff(Y);
268 else
269 _MOD_instNote((np->note/16) * 12 + np->note%16, Y);
270
271 if (np->vol != 255)
272 _MOD_instVol(np->vol, Y);
273 }
274 else
275 {
276 commonWork ( np ) ;
277
278 switch ( X )
279 {
280 case 1: /* set glissando control */
281 _MOD_instSetPortamentoGlissando(Y);
282 break;
283 case 2: /* set finetune */
284 /* ...but not tested yet. which tune use this? */
285 ulSetError ( UL_DEBUG, "Got it! Set Finetune");
286 {
287 static int freq[16] =
288 {
289 8363,8413,8463,8529,8581,8651,8723,8757,
290 7895,7941,7985,8046,8107,8169,8232,8280
291 };
292 _MOD_instTuning(freq[Y]);
293 /* the tuning effects from next key-on */
294 }
295 break;
296 case 3: /* set vibrato waveform */
297 _MOD_instSetVibratoWave(Y%4, Y/4);
298 break;
299 case 4: /* set tremolo waveform */
300 _MOD_instSetTremoloWave(Y%4, Y/4);
301 break;
302 case 8: /* set pan position */
303 _MOD_instPanPosition(Y*64/15);
304 break;
305 case 0xc: /* notecut */
306 _MOD_instNoteCut(Y);
307 break;
308 case 0xb: /* pattern loop */
309 case 0xe: /* pattern delay */
310 break;
311 default:
312 ulSetError ( UL_WARNING, "%c%02X not supported.", np->cmd+'@', np->info);
313 }
314 }
315 }
316
317 /* Vxx = set global volume */
318
319
setGlobalVol(void)320 static void setGlobalVol(void)
321 {
322 dacioGlobalVol ( masterVol * globalVol ) ;
323 }
324
325
_MOD_playNoteSetMono(int m)326 void _MOD_playNoteSetMono(int m)
327 {
328 mono = m;
329 _MOD_instMono(m);
330 }
331
_MOD_playNoteSetMasterVol(int mv)332 void _MOD_playNoteSetMasterVol(int mv)
333 {
334 masterVol = mono? mv : mv * 4 / 3;
335 setGlobalVol();
336 }
337
_MOD_playNoteSetGlobalVol(int gv)338 void _MOD_playNoteSetGlobalVol(int gv)
339 {
340 globalVol = gv;
341 setGlobalVol();
342 }
343
vCmd(Note * np)344 static void vCmd(Note *np)
345 {
346 commonWork(np);
347 _MOD_playNoteSetGlobalVol(np->info);
348 }
349
350 /* Xxx = DMP style pan position */
351
xCmd(Note * np)352 static void xCmd(Note *np)
353 {
354 commonWork(np);
355
356 if (np->info <= 0x80)
357 _MOD_instPanPosition(np->info * 64 / 0x80);
358 else
359 if (np->info == 0xa4)
360 _MOD_instPanPosition(-1); /* surround */
361 else
362 _MOD_instPanPosition(32); /* unknown -> center */
363 }
364
365
366 static void (*cmdTbl[])( Note *np ) =
367 {
368 /*@*/ unknownEffect, /*A*/ noEffect , /*B*/ noEffect, /*C*/noEffect,
369 /*D*/ dCmd , /*E*/ eCmd , /*F*/ fCmd , /*G*/gCmd,
370 /*H*/ hCmd , /*I*/ iCmd , /*J*/ jCmd , /*K*/kCmd,
371 /*L*/ lCmd , /*M*/ unknownEffect, /*N*/ unknownEffect, /*O*/oCmd,
372 /*P*/ unknownEffect, /*Q*/ qCmd , /*R*/ rCmd , /*S*/sCmd,
373 /*T*/ noEffect , /*U*/ uCmd , /*V*/ vCmd , /*W*/unknownEffect,
374 /*X*/ xCmd , /*Y*/ unknownEffect, /*Z*/ unknownEffect
375 } ;
376
377
_MOD_playNoteSetSample(SampleInfo * sip)378 void _MOD_playNoteSetSample ( SampleInfo *sip )
379 {
380 smp = sip ;
381 }
382
383
_MOD_playNoteInit(void)384 void _MOD_playNoteInit ( void )
385 {
386 _MOD_instInit () ;
387 }
388
setFrameLen(void)389 static void setFrameLen ( void )
390 {
391 frameLen = outRate * 60 / (tempo * 24) ;
392 _MOD_instHirevSetFrameLen ( frameLen ) ;
393 }
394
395
_MOD_playNoteSetOutRate(int _or)396 void _MOD_playNoteSetOutRate ( int _or )
397 {
398 if ( _or > MAX_OUTRATE )
399 {
400 ulSetError ( UL_FATAL, "Too high output sample rate." ) ;
401 }
402
403 _MOD_instOutRate ( _or ) ;
404 outRate = _or ;
405 setFrameLen () ;
406 }
407
408
_MOD_playNoteSetTempo(int n)409 void _MOD_playNoteSetTempo ( int n )
410 {
411 if ( n < MIN_TEMPO )
412 {
413 ulSetError ( UL_WARNING, "Illegal tempo (%d) ignored.", n ) ;
414 return ;
415 }
416
417 tempo = n ;
418 setFrameLen () ;
419 }
420
421
_MOD_playNoteSetSpeed(int n)422 void _MOD_playNoteSetSpeed ( int n )
423 {
424 speed = n ;
425 }
426
427
_MOD_playNoteSetNote(int ch,Note * np)428 void _MOD_playNoteSetNote ( int ch, Note *np )
429 {
430 chToPlay [ ch ] = 1 ;
431 _MOD_instSelectCh ( ch ) ;
432
433 if ( np->cmd == 255 )
434 noEffect ( np ) ;
435 else
436 (*cmdTbl[np->cmd]) ( np ) ;
437 }
438
439
_MOD_playNoteSetPatRepeat(int n)440 void _MOD_playNoteSetPatRepeat ( int n )
441 {
442 patRepeat = n ;
443 }
444
_MOD_playNote(void)445 void _MOD_playNote ( void )
446 {
447 for ( int r = 0 ; r <= patRepeat ; r++ )
448 for ( int f = 0 ; f < speed ; f++ )
449 {
450 _MOD_instHirevEraseBuf () ;
451
452 for ( int ch = 0 ; ch < 32 ; ch++ )
453 if ( chToPlay [ ch ] )
454 {
455 _MOD_instSelectCh ( ch ) ;
456 _MOD_instDoPerFrameWorks ( f ) ;
457 _MOD_instLoop () ;
458 }
459
460 _MOD_instHirevFlushBuf () ;
461 }
462
463 patRepeat = 0 ;
464
465 for ( int ch = 0 ; ch < 32 ; ch++ )
466 chToPlay [ ch ] = 0 ;
467 }
468
469
470