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