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: slMODinst.cxx 1568 2002-09-02 06:05:49Z sjbaker $
22 */
23
24
25 #include "slMODPrivate.h"
26
27 /* note-period table */
28
29 #define NOTE_MAX (12*8-1) /* 8octave */
30 static short *note ;
31
32 #define shift(x,n) ((n) >= 0? (x) << (n) : (x) >> -(n)) /* x * 2**n */
33
34 static struct
35 {
36 int *p0 ;
37 int *p ;
38 int len ;
39 } hirev_buf ;
40
_MOD_instHirevInit(void)41 void _MOD_instHirevInit ( void )
42 {
43 hirev_buf.p0 = dacioGetBuffer () ;
44 }
45
_MOD_instHirevSetFrameLen(int l)46 void _MOD_instHirevSetFrameLen ( int l )
47 {
48 dacioIncomingBufLen ( l ) ;
49 hirev_buf.len = l ;
50 }
51
_MOD_instHirevEraseBuf(void)52 void _MOD_instHirevEraseBuf ( void )
53 {
54 memset ( hirev_buf.p0, 0, sizeof ( int ) * hirev_buf.len * 2 ) ;
55 }
56
_MOD_instHirevFlushBuf(void)57 void _MOD_instHirevFlushBuf ( void )
58 {
59 dacioOut () ;
60 }
61
62
fadeout(InstHirevInfo * ihip)63 static void fadeout ( InstHirevInfo *ihip )
64 {
65 int lastL = ihip->lastL / 64 ;
66 int lastR = ihip->lastR / 64 ;
67 int f = ihip->fadeout ;
68
69 if ( f > 63 )
70 f = 63 ;
71
72 if ( lastL || lastR )
73 {
74 int *bufp = hirev_buf.p ;
75 int n = ( hirev_buf.p0 + hirev_buf.len - bufp ) / 2 ;
76
77 if ( n > f ) n = f ;
78
79 for ( ; n > 0 ; n--,f-- )
80 {
81 *bufp++ += lastL * f ;
82 *bufp++ += lastR * f ;
83 }
84 }
85
86 ihip->fadeout = f ;
87
88 if ( !f )
89 ihip->lastL = ihip->lastR = 0 ;
90 }
91
92 /* vol zero optimization: just calculates phase progress within this frame */
93
vol0Opt(InstHirevInfo * ihip)94 static void vol0Opt ( InstHirevInfo *ihip )
95 {
96 if ( ihip->lastL || ihip->lastR )
97 {
98 /* suddenly volume is turned to 0 -> click ( chi_mai.s3m ) */
99
100 ihip->fadeout = 256 ;
101 fadeout ( ihip ) ;
102 ihip->fadeout = 0 ; /* don't note off ( ambient_power.mod ) */
103 }
104
105 ihip->wAcc = ( unsigned int ) ( unsigned short ) ihip->wAcc + ( unsigned short )( ihip->w * hirev_buf.len ) ;
106 ihip->ptr += ( ihip->w >> 16 ) * hirev_buf.len
107 + ( ( unsigned short ) ihip->w * hirev_buf.len >> 16 )
108 + ( ihip->wAcc >> 16 ) ;
109
110 if ( ihip->ptr >= ihip->end )
111 {
112 if ( ihip->loopBeg )
113 ihip->ptr = ihip->loopBeg + ( ihip->ptr - ihip->end ) % ( ihip->end - ihip->loopBeg ) ;
114 else
115 ihip->ptr = NULL ; /* note off */
116 }
117
118 ihip->lastL = ihip->lastR = 0 ;
119 }
120
121 static InstHirevInfo ihi ; /* cacheing */
122
hirevLoop0(unsigned int n)123 static void hirevLoop0 ( unsigned int n )
124 {
125 int *bufp = hirev_buf.p ;
126 unsigned char *ihiPtr = ihi.ptr ;
127 unsigned int ihiWAcc = ihi.wAcc ;
128
129 for ( ; n > 0 ; n-- )
130 {
131 int d = ( signed char ) *ihiPtr ;
132 *bufp++ += d * ihi.volL ;
133 *bufp++ += d * ihi.volR ;
134
135 ihiWAcc = ( unsigned short ) ihiWAcc + ihi.w ; /*ihiWAcc & 0xffff + w*/
136 ihiPtr += ihiWAcc >> 16 ;
137 }
138
139 hirev_buf.p = bufp ;
140 ihi.ptr = ihiPtr ;
141 ihi.wAcc = ihiWAcc ;
142 }
143
hirevLoop80(unsigned int n)144 static void hirevLoop80 ( unsigned int n )
145 {
146 int *bufp = hirev_buf.p ;
147 unsigned char *ihiPtr = ihi.ptr ;
148 unsigned int ihiWAcc = ihi.wAcc ;
149
150 for ( ; n > 0 ; n-- )
151 {
152 int d = ( signed char ) ( *ihiPtr ^ 0x80 ) ;
153 *bufp++ += d * ihi.volL ;
154 *bufp++ += d * ihi.volR ;
155
156 ihiWAcc = ( unsigned short ) ihiWAcc + ihi.w ; /*ihiWAcc & 0xffff + w*/
157 ihiPtr += ihiWAcc >> 16 ;
158 }
159
160 hirev_buf.p = bufp ;
161 ihi.ptr = ihiPtr ;
162 ihi.wAcc = ihiWAcc ;
163 }
164
165 #define hirevLoop(x) { if ( ihi.x_or ) hirevLoop80(x) ; else hirevLoop0(x) ; }
166
167
_MOD_instHirevLoop(InstHirevInfo * ihip)168 void _MOD_instHirevLoop ( InstHirevInfo *ihip )
169 {
170 unsigned int restF ;
171 unsigned int restS ;
172 int lastD ;
173
174 if ( ihip->ptr == NULL )
175 return ; /* note is off */
176
177 hirev_buf.p = hirev_buf.p0 ;
178
179 if ( ihip->fadeout )
180 {
181 fadeout ( ihip ) ;
182
183 if ( !ihip->fadeout )
184 ihip->ptr = NULL ; /* note off */
185
186 return ;
187 }
188
189 if ( !ihip->volL && !ihip->volR ) { vol0Opt ( ihip ) ; return ; }
190
191 ihi = *ihip ; /* load to cache */
192 restF = hirev_buf.len ;
193
194 do
195 {
196 int l8, l0 ;
197
198 ihi.wAcc = ( unsigned short ) ihi.wAcc ;
199
200 l8 = ( ihi.end - ihi.ptr ) << 8 ;
201
202 if ( !l8 && !ihi.wAcc )
203 { /* happens only on empty samples */
204
205 ihip->fadeout = 256 ;
206 fadeout ( ihip ) ;
207
208 if ( !ihip->fadeout )
209 ihip->ptr = NULL ; /* note off */
210
211 return ;
212 }
213
214 if ( l8 <= 0 )
215 {
216 ulSetError ( UL_WARNING, "bug: restF=%u",restF ) ;
217 ulSetError ( UL_WARNING, "end-ptr=%d w=%u",ihi.end-ihi.ptr,ihi.w ) ;
218 ulSetError ( UL_WARNING, "wAcc = %u",ihi.wAcc ) ;
219 }
220
221 l0 = ihi.w - 1 - ihi.wAcc ;
222 l8 += l0 >> 8 ;
223 l0 &= 0xff ;
224 restS = ( ( l8 / ihi.w ) << 8 ) + ( ( ( l8 % ihi.w ) << 8 ) + l0 ) / ihi.w ;
225
226 if ( restF < restS )
227 { /* sample is longer than frame */
228
229 hirevLoop ( restF ) ;
230 lastD = ( signed char ) ( * ( ihi.ptr - ( ihi.wAcc >> 16 ) ) ^ ihi.x_or ) ;
231
232 break ;
233 }
234
235 /* restF >= restS */
236 hirevLoop ( restS ) ;
237 lastD = ( signed char ) ( * ( ihi.ptr - ( ihi.wAcc >> 16 ) ) ^ ihi.x_or ) ;
238
239 if ( ihi.ptr < ihi.end || ihi.end <= ihi.ptr - ( ihi.wAcc >> 16 ) )
240 {
241 ulSetError ( UL_FATAL, "SL: Internal Error in _MOD_instHirevLoop." ) ;
242 /*
243 ulSetError ( UL_DEBUG, "bug: restS = %u restF=%u end-ptr = %d, ptr=%p",
244 restS, restF, ihi.end-ihi.ptr, ihi.ptr ) ;
245 ulSetError ( UL_DEBUG, "last ptr=%p", ( ihi.ptr - ( ihi.wAcc >> 16 ) ) ) ;
246 */
247 }
248
249 restF -= restS ;
250
251 if ( ihi.loopBeg )
252 {
253 ihi.ptr = ihi.loopBeg + ( ihi.ptr - ihi.end ) % ( ihi.end - ihi.loopBeg ) ;
254 }
255 else
256 {
257 ihi.lastL = lastD * ihi.volL ;
258 ihi.lastR = lastD * ihi.volR ;
259 ihi.fadeout = 256 ;
260
261 fadeout ( &ihi ) ;
262
263 if ( !ihi.fadeout )
264 ihi.ptr = NULL ; /* note off */
265
266 *ihip = ihi ; /* save cache */
267 return ;
268 }
269 } while ( restF ) ;
270
271 ihi.lastL = lastD * ihi.volL ;
272 ihi.lastR = lastD * ihi.volR ;
273 *ihip = ihi ; /* save cache */
274 }
275
makeNoteTable(void)276 static void makeNoteTable ( void )
277 {
278 static int oct4[] =
279 {
280 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 907
281 } ;
282
283 note = new short [ NOTE_MAX + 1 ] ;
284
285 for ( int i = 0 ; i <= NOTE_MAX ; i++ )
286 note[i] = shift ( oct4[i%12], 4-i/12 ) ;
287 }
288
289 /* period -> nearest note */
290
normalizePeriod(int * pp)291 static int normalizePeriod ( int *pp )
292 {
293 int i ;
294 int s ;
295 int p = *pp ;
296
297 if ( p >= note [ 0 ] ) { *pp = note [ 0 ] ; return 0 ; }
298 if ( p <= note [ NOTE_MAX ] ) { *pp = note [ NOTE_MAX ] ; return NOTE_MAX ; }
299
300 for ( i = 0, s = 64 ; s > 0 ; s /= 2 ) /* 64: =2**n, and 64*2 > NOTE_MAX */
301 if ( i + s < NOTE_MAX && note [ i + s ] > p ) /* i < NOTE_MAX !! */
302 i += s ;
303
304 if ( note [ i ] - p > p - note [ i + 1 ] )
305 i++ ; /* choose nearest */
306
307 *pp = note [ i ] ;
308
309 return i ;
310 }
311
312
313
314 struct ModulateInfo
315 {
316 int type ; /* sine,ramp,square,... */
317 int noRetrig ;
318 int phase ;
319 int d ; /* phase accumlates this for each frame */
320 int depth ; /* org * table[phase] * depth/MAX_IN_TABLE = cur */
321 } ;
322
323
324 /* output rate */
325
326 static unsigned int mclk ;
327
328 #define MCLK0 ((unsigned int)3579545*4)
329
_MOD_instOutRate(unsigned int rate)330 void _MOD_instOutRate ( unsigned int rate )
331 {
332 mclk = MCLK0 / rate * 65536 + MCLK0 % rate * 65536 / rate ;
333 }
334
335 #define PFW_MAX 3 /* note delay = note delay + sample delay + vol delay */
336
337 struct InstInfo
338 {
339 InstHirevInfo hirev ; /* for hirev loop */
340
341 struct
342 {
343 int cur ; /* current period */
344 int org ; /* original period */
345 int note ; /* note */
346 int notePer ; /* note period */
347 int mclk ; /* master clock in Hz (c4spd * 1712) */
348
349 struct
350 {
351 int speed ; /* added/sub'ed for each frame */
352 int fine ; /* fine slide */
353 } slide ;
354
355 struct
356 {
357 int speed ;
358 int glissando ;
359 int nextNote ; /* (glissando) next note */
360 } port ; /* portamento */
361
362 ModulateInfo mod ;
363
364 struct
365 {
366 int baseNote ;
367 int plus[2] ; /* baseNote + plus[n] halfnote is played */
368 } rpgo ; /* arpeggio */
369
370 struct
371 {
372 int n ;
373 int newNote ;
374 } delay ;
375
376 } per ; /* period */
377
378 struct
379 {
380 int cur ; /* current volume */
381 int org ;
382 int pan ; /* 0(left)..64(right) */
383
384 struct
385 {
386 int d ; /* added for each frame */
387 int mul ; /* multiply for each frame */
388 int div ; /* divide for each frame */
389 int nthFrame ; /* slide every nth frame */
390 int fine ; /* fine slide */
391 int count ; /* frame counter */
392 } slide ;
393
394 ModulateInfo mod ;
395
396 struct
397 {
398 int onOff ;
399 int count ;
400 int onTime ;
401 int offTime ;
402 } tremor ;
403
404 struct
405 {
406 int n ;
407 int newest ;
408 } delay ;
409
410 } vol ;
411
412 struct
413 {
414 int cur ; /* current frame */
415 int count ; /* decrement counter, 0 starts next frame */
416 } frame ;
417
418 struct
419 {
420 struct
421 {
422 int nthFrame ; /* retrig every nth frame */
423 int count ; /* frame counter */
424 } retrig ;
425
426 SampleInfo *sip ;
427 SampleInfo *newSip ;
428 int c4spd ;
429
430 struct
431 {
432 int n ;
433 SampleInfo *sip ;
434 } delay ;
435
436 int cutFrame ;
437 } smp ;
438
439 struct
440 {
441 void (*func[PFW_MAX])(void) ;
442 int n ;
443 } pfw ; /* per frame works */
444
445 } ;
446
447 static InstInfo *instBank ;
448 static InstInfo *instp ;
449
450
451 /* select channel */
452
_MOD_instSelectCh(int ch)453 void _MOD_instSelectCh(int ch)
454 {
455 instp = &instBank[ch];
456 }
457
458
459 /* per frame work */
460
_MOD_instClearPFW(void)461 void _MOD_instClearPFW(void)
462 {
463 instp->pfw.n = 0;
464 }
465
_MOD_instDoPerFrameWorks(int frame)466 void _MOD_instDoPerFrameWorks(int frame)
467 {
468 instp->frame.cur = frame;
469
470 for (int i = 0; i < instp->pfw.n; i++)
471 (*instp->pfw.func[i])();
472 }
473
addPerFrameWork(void (* f)(void))474 static void addPerFrameWork(void (*f)(void))
475 {
476 if (instp->pfw.n >= PFW_MAX)
477 {
478 ulSetError ( UL_FATAL, "Too many PFWs");
479 }
480
481 instp->pfw.func[instp->pfw.n++] = f;
482 }
483
484
485 /* hirev loop */
486
_MOD_instLoop(void)487 void _MOD_instLoop(void)
488 {
489 _MOD_instHirevLoop(&instp->hirev);
490 }
491
492
493 /* initialize */
494
_MOD_instInit(void)495 void _MOD_instInit(void)
496 {
497 static SampleInfo si0 ;
498
499 _MOD_instHirevInit () ;
500 makeNoteTable () ;
501
502 instBank = new InstInfo [ 32 ] ;
503
504 si0.beg = si0.end = NULL ;
505 si0.c4spd = 8363 ;
506 si0.mag = 1 ;
507
508 for ( int i = 0 ; i < 32 ; i++ )
509 {
510 /* prepare for "note w/o inst and volume" */
511 instBank[i].smp.sip = instBank[i].smp.newSip = &si0 ;
512 instBank[i].smp.c4spd = 8363; /* dope.mod ch14 begins with GF0 */
513 instBank[i].hirev.end = instBank[i].hirev.ptr = NULL;
514 instBank[i].vol.slide.div = 1;
515 }
516 }
517
518
setW(void)519 static void setW(void)
520 {
521 instp->hirev.w = (mclk * instp->smp.sip->mag) /
522 (instp->per.cur < 16? 16 : instp->per.cur);
523 }
524
525 #define noteToPeriod(n) ((int)note[(n)] * 8363 / instp->smp.c4spd)
526
setPeriod(void)527 static void setPeriod(void)
528 {
529 if (instp->smp.sip != instp->smp.newSip)
530 {
531 /* actual sample switching is carried out here */
532 instp->smp.sip = instp->smp.newSip ;
533 instp->hirev.end = instp->smp.sip->end ;
534 instp->hirev.loopBeg = instp->smp.sip->loopBeg ;
535 instp->hirev.x_or = instp->smp.sip->x_or ;
536 }
537
538 instp->per.note = instp->per.delay.newNote;
539 instp->per.cur =
540 instp->per.org =
541 instp->per.notePer = noteToPeriod(instp->per.note);
542
543 instp->hirev.ptr = instp->smp.sip->beg; /* key-on */
544 instp->hirev.wAcc = 0;
545 instp->hirev.fadeout = 0;
546
547 if ( ! instp->per.mod.noRetrig ) instp->per.mod.phase = 0 ;
548 if ( ! instp->vol.mod.noRetrig ) instp->vol.mod.phase = 0 ;
549
550 setW () ;
551 }
552
setPeriodPFW(void)553 static void setPeriodPFW(void)
554 {
555 if (instp->per.delay.n == instp->frame.cur)
556 setPeriod() ;
557 }
558
559
_MOD_instNote(int n,int delay)560 void _MOD_instNote(int n, int delay)
561 {
562 instp->per.delay.newNote = n;
563
564 if (delay == 0)
565 setPeriod();
566 else
567 {
568 instp->per.delay.n = delay;
569 addPerFrameWork(setPeriodPFW);
570 }
571 }
572
573
574 /* set volume */
575
576 static int mono;
577
_MOD_instMono(int n)578 void _MOD_instMono(int n)
579 {
580 mono = n;
581 }
582
setHirevVol(void)583 static void setHirevVol(void)
584 {
585 if ( mono )
586 {
587 instp->hirev.volL = instp->vol.cur ;
588 return ;
589 }
590
591 /* currently linear, which makes front sounds rather weaker */
592
593 if (instp->vol.pan >= 0)
594 {
595 instp->hirev.volL = instp->vol.cur * (64 - instp->vol.pan)/64;
596 instp->hirev.volR = instp->vol.cur * instp->vol.pan/64;
597 }
598 else
599 { /* surround!! */
600 instp->hirev.volL = instp->vol.cur / 2;
601 instp->hirev.volR = -instp->vol.cur / 2;
602 }
603 }
604
setVol(void)605 static void setVol(void)
606 {
607 instp->vol.cur = instp->vol.org = instp->vol.delay.newest;
608 setHirevVol();
609 }
610
setVolPFW(void)611 static void setVolPFW(void)
612 {
613 if (instp->vol.delay.n == instp->frame.cur) setVol();
614 }
615
_MOD_instVol(int v,int delay)616 void _MOD_instVol(int v, int delay)
617 {
618 instp->vol.delay.newest = v > 64? 64: v;
619
620 if (delay == 0)
621 setVol();
622 else
623 {
624 instp->vol.delay.n = delay;
625 addPerFrameWork(setVolPFW);
626 }
627 }
628
629
630 /* tuning */
631
_MOD_instTuning(int c4spd)632 void _MOD_instTuning(int c4spd)
633 {
634 instp->smp.c4spd = c4spd;
635 }
636
637
638 /* set sample */
639
setSample()640 static void setSample()
641 {
642 /* actual sample switching is not done here.. */
643
644 instp->smp.newSip = instp->smp.delay.sip;
645
646 /* set smp's default vol.. */
647
648 instp->vol.cur = instp->vol.org = instp->smp.newSip->vol;
649
650 /* set smp's c4spd.. */
651
652 instp->smp.c4spd = instp->smp.newSip->c4spd;
653 setHirevVol();
654 }
655
656
setSamplePFW(void)657 static void setSamplePFW(void)
658 {
659 if (instp->smp.delay.n == instp->frame.cur) setSample();
660 }
661
_MOD_instSample(SampleInfo * sip,int delay)662 void _MOD_instSample(SampleInfo *sip, int delay)
663 {
664 instp->smp.delay.sip = sip;
665
666 if (delay)
667 {
668 instp->smp.delay.n = delay;
669 addPerFrameWork(setSamplePFW);
670 } else setSample();
671 }
672
673
674 /* volume slide */
675
limitVol(int v)676 inline int limitVol ( int v )
677 {
678 if ( v > 64 )
679 return 64 ;
680
681 if ( v < 0 )
682 return 0 ;
683
684 return v ;
685 }
686
687 static int fastVolSlide;
688
volSlidePFW(void)689 static void volSlidePFW(void)
690 {
691 if (!fastVolSlide && !instp->frame.cur) return; /* skip frame 0 */
692 if (--instp->vol.slide.count <= 0) {
693 instp->vol.slide.count = instp->vol.slide.nthFrame;
694 instp->vol.cur =
695 instp->vol.cur * instp->vol.slide.mul / instp->vol.slide.div
696 + instp->vol.slide.d;
697
698 instp->vol.cur = limitVol ( instp->vol.cur ) ;
699 setHirevVol();
700 }
701 }
702
_MOD_instVolSlide(void)703 void _MOD_instVolSlide(void)
704 {
705 if (instp->vol.slide.fine) {
706 instp->vol.cur =
707 instp->vol.cur * instp->vol.slide.mul / instp->vol.slide.div
708 + instp->vol.slide.d;
709
710 instp->vol.cur = limitVol ( instp->vol.cur ) ;
711 setHirevVol();
712 } else addPerFrameWork(volSlidePFW);
713 }
714
_MOD_instSetVolSlideParams(int d,int mul,int div,int nthFrame,int fine)715 void _MOD_instSetVolSlideParams(int d, int mul, int div, int nthFrame, int fine)
716 {
717 instp->vol.slide.d = d;
718 instp->vol.slide.mul = mul;
719 instp->vol.slide.div = div;
720 instp->vol.slide.nthFrame = instp->vol.slide.count = nthFrame;
721 instp->vol.slide.fine = fine;
722 }
723
_MOD_instSetVolSlideFast(int onOff)724 void _MOD_instSetVolSlideFast(int onOff)
725 {
726 fastVolSlide = onOff;
727 }
728
729
730 /* period slide */
731
732 #define noteOff() { instp->hirev.fadeout = 256; } /* eventually note-off */
733
734 static int amigaLimit;
735
limitPeriod(void)736 static void limitPeriod(void)
737 {
738 #define p instp->per.cur
739 if (amigaLimit) {
740 if ((p) > note[3*12]) (p) = note[3*12];
741 else if ((p) < note[5*12+11]) (p) = note[5*12+11];
742 } else {
743 if ((p) > 32000) (p) = 32000;
744 else if ((p) < 0) { (p) = 0; noteOff(); /*panic.s3m needs this*/ }
745 }
746 #undef p
747 }
748
periodSlideUpPFW(void)749 static void periodSlideUpPFW(void)
750 {
751 if (!instp->frame.cur) return; /* skip frame 0 */
752 instp->per.cur -= instp->per.slide.speed; /* ignore per.org */
753 limitPeriod(/*instp->per.cur*/);
754 instp->per.org = instp->per.cur;
755 setW();
756 }
757
periodSlideDownPFW(void)758 static void periodSlideDownPFW(void)
759 {
760 if (!instp->frame.cur) return; /* skip frame 0 */
761 instp->per.cur += instp->per.slide.speed;
762 limitPeriod(/*instp->per.cur*/);
763 instp->per.org = instp->per.cur;
764 setW();
765 }
766
_MOD_instPeriodSlideUp(void)767 void _MOD_instPeriodSlideUp(void)
768 {
769 if (instp->per.slide.fine) {
770 instp->per.cur -= instp->per.slide.speed;
771 limitPeriod(/*instp->per.cur*/);
772 instp->per.org = instp->per.cur;
773 setW();
774 } else addPerFrameWork(periodSlideUpPFW);
775 }
776
_MOD_instPeriodSlideDown(void)777 void _MOD_instPeriodSlideDown(void)
778 {
779 if (instp->per.slide.fine) {
780 instp->per.cur += instp->per.slide.speed;
781 limitPeriod(/*instp->per.cur*/);
782 instp->per.org = instp->per.cur;
783 setW();
784 } else addPerFrameWork(periodSlideDownPFW);
785 }
786
_MOD_instSetPeriodSlideParams(int speed,int fine)787 void _MOD_instSetPeriodSlideParams(int speed, int fine)
788 {
789 instp->per.slide.speed = speed;
790 instp->per.slide.fine = fine;
791 }
792
_MOD_instSetPeriodAmigaLimit(int onOff)793 void _MOD_instSetPeriodAmigaLimit(int onOff)
794 {
795 amigaLimit = onOff;
796 }
797
798
799 /* portamento */
800
portamentoPFW(void)801 static void portamentoPFW(void)
802 {
803 if (!instp->frame.cur) return; /* which S3M slides at frame 0? */
804 if (instp->per.org > instp->per.notePer) { /* port up now */
805 instp->per.org -= instp->per.port.speed;
806 if (instp->per.org < instp->per.notePer)
807 instp->per.cur = instp->per.org = instp->per.notePer;
808 else {
809 instp->per.cur = instp->per.org;
810 if (instp->per.port.glissando) normalizePeriod(&instp->per.cur);
811 }
812 } else { /* port down now */
813 instp->per.org += instp->per.port.speed;
814 if (instp->per.org > instp->per.notePer)
815 instp->per.cur = instp->per.org = instp->per.notePer;
816 else {
817 instp->per.cur = instp->per.org;
818 if (instp->per.port.glissando) normalizePeriod(&instp->per.cur);
819 }
820 }
821 setW();
822 }
823
_MOD_instPortamento(void)824 void _MOD_instPortamento(void)
825 {
826 addPerFrameWork(portamentoPFW);
827 }
828
_MOD_instSetPortamentoTo(int to)829 void _MOD_instSetPortamentoTo(int to)
830 {
831 instp->per.note = to;
832 instp->per.notePer = noteToPeriod(to);
833 }
834
_MOD_instSetPortamentoSpeed(int speed)835 void _MOD_instSetPortamentoSpeed(int speed)
836 {
837 instp->per.port.speed = speed;
838 }
839
_MOD_instSetPortamentoDefaultVol(void)840 void _MOD_instSetPortamentoDefaultVol(void)
841 {
842 instp->vol.cur = instp->vol.org = instp->smp.sip->vol;
843 setHirevVol();
844 }
845
_MOD_instSetPortamentoGlissando(int onOff)846 void _MOD_instSetPortamentoGlissando(int onOff)
847 {
848 instp->per.port.glissando = onOff;
849 }
850
851
852 /* arpeggio */
853
arpeggioPFW(void)854 static void arpeggioPFW(void)
855 {
856 if (instp->frame.cur % 3) {
857 instp->per.cur = note[instp->per.note
858 + instp->per.rpgo.plus[instp->frame.cur%3 - 1]];
859 } else instp->per.cur = instp->per.notePer;
860 setW();
861 }
862
_MOD_instArpeggio(void)863 void _MOD_instArpeggio(void)
864 {
865 addPerFrameWork(arpeggioPFW);
866 }
867
_MOD_instSetArpeggioParams(int plus1,int plus2)868 void _MOD_instSetArpeggioParams(int plus1, int plus2)
869 {
870 instp->per.rpgo.plus[0] = plus1;
871 instp->per.rpgo.plus[1] = plus2;
872 }
873
874
875 /* retrig */
876
retrigPFW(void)877 static void retrigPFW(void)
878 {
879 if (--instp->smp.retrig.count <= 0) {
880 instp->smp.retrig.count = instp->smp.retrig.nthFrame;
881 instp->hirev.ptr = instp->smp.sip->beg;
882 setW();
883 }
884 }
885
_MOD_instRetrig(void)886 void _MOD_instRetrig(void)
887 {
888 addPerFrameWork(retrigPFW);
889 }
890
_MOD_instSetRetrigParam(int nthFrame)891 void _MOD_instSetRetrigParam(int nthFrame)
892 {
893 instp->smp.retrig.nthFrame = nthFrame;
894 instp->smp.retrig.count = 0;
895 }
896
897
898 /* sample offset */
899
_MOD_instSampleOffset(int offset)900 void _MOD_instSampleOffset(int offset)
901 {
902 instp->hirev.ptr = instp->smp.sip->beg + offset * instp->smp.sip->mag;
903 if (instp->hirev.ptr >= instp->hirev.end) {
904 if (instp->hirev.loopBeg) {
905 instp->hirev.ptr =
906 instp->hirev.loopBeg +
907 (instp->hirev.ptr - instp->hirev.end) %
908 (instp->hirev.end - instp->hirev.loopBeg);
909 } else { noteOff(); }
910 }
911 }
912
913
914 /* modulation */
915
916 static unsigned char sine[] = {
917 000, 25, 50, 74, 98, 120, 142, 162,
918 180, 197, 212, 225, 236, 244, 250, 254,
919 255
920 }; /* sin(x), 0 <= x < pi/4, max = 255 */
921
922
wave(ModulateInfo * mip)923 static int wave(ModulateInfo *mip)
924 {
925 int i;
926
927 switch (mip->type) {
928 case 1: /* ramp up (period: down) */
929 i = (255 * 2 * mip->phase)/63 - 255;
930 break;
931 case 2: /* square */
932 i = (mip->phase < 32)? 255 : 0; /* yes, not 255/-255 */
933 break;
934 default: /* sine */
935 if (mip->phase < 16) i = sine[mip->phase];
936 else if (mip->phase < 32) i = sine[32 - mip->phase];
937 else if (mip->phase < 48) i = -sine[mip->phase - 32];
938 else i = -sine[64 - mip->phase];
939 }
940 return mip->depth * i / 255;
941 }
942
vibratoPFW(void)943 static void vibratoPFW(void)
944 {
945 if (!instp->frame.cur) return; /* skip frame 0 */
946 instp->per.mod.phase += instp->per.mod.d;
947 instp->per.mod.phase %= 64;
948 /* per.org: no change.. */
949 instp->per.cur = instp->per.org + wave(&instp->per.mod);
950 limitPeriod(/*instp->per.cur*/);
951 setW();
952 }
953
_MOD_instVibrato(void)954 void _MOD_instVibrato(void)
955 {
956 addPerFrameWork(vibratoPFW);
957 }
958
959 /* depth = period */
_MOD_instSetVibratoParams(int d,int depth)960 void _MOD_instSetVibratoParams(int d, int depth)
961 {
962 if (d) instp->per.mod.d = d;
963 instp->per.mod.depth = depth;
964 /*if (!instp->per.mod.noRetrig) instp->per.mod.phase = 0;*/
965 }
966
_MOD_instSetVibratoWave(int type,int noRetrig)967 void _MOD_instSetVibratoWave(int type, int noRetrig)
968 {
969 if (type == 3) type = rand() % 3;
970 instp->per.mod.type = type;
971 instp->per.mod.noRetrig = noRetrig;
972 }
973
974
tremoloPFW(void)975 static void tremoloPFW(void)
976 {
977 if (!instp->frame.cur) return; /* skip frame 0 */
978 instp->vol.mod.phase += instp->vol.mod.d;
979 instp->vol.mod.phase %= 64;
980 instp->vol.cur = instp->vol.org + wave(&instp->vol.mod);
981 instp->vol.cur = limitVol ( instp->vol.cur ) ;
982 setHirevVol();
983 }
984
_MOD_instTremolo(void)985 void _MOD_instTremolo(void)
986 {
987 addPerFrameWork(tremoloPFW);
988 }
989
_MOD_instSetTremoloParams(int d,int depth)990 void _MOD_instSetTremoloParams(int d, int depth)
991 {
992 if (d) instp->vol.mod.d = d;
993 instp->vol.mod.depth = depth;
994 /*if (!instp->vol.mod.noRetrig) instp->vol.mod.phase = 0;*/
995 }
996
_MOD_instSetTremoloWave(int type,int noRetrig)997 void _MOD_instSetTremoloWave(int type, int noRetrig)
998 {
999 if (type == 3) type = rand() % 3;
1000 instp->vol.mod.type = type;
1001 instp->vol.mod.noRetrig = noRetrig;
1002 }
1003
1004
1005 /* note cut */
1006
noteCutPFW(void)1007 static void noteCutPFW(void)
1008 {
1009 /* said to be vol := 0, but ST3 seems to key-off */
1010 if (instp->smp.cutFrame == instp->frame.cur) noteOff();
1011 }
1012
_MOD_instNoteCut(int frame)1013 void _MOD_instNoteCut(int frame)
1014 {
1015 if (frame) {
1016 instp->smp.cutFrame = frame;
1017 addPerFrameWork(noteCutPFW);
1018 } else noteOff();
1019 }
1020
1021
1022 /* tremor */
1023
tremorPFW(void)1024 static void tremorPFW(void)
1025 {
1026 if (--instp->vol.tremor.count <= 0) {
1027 if (instp->vol.tremor.onOff) {
1028 instp->vol.cur = 0;
1029 setHirevVol();
1030 instp->vol.tremor.onOff = 0;
1031 instp->vol.tremor.count = instp->vol.tremor.offTime;
1032 } else {
1033 instp->vol.cur = instp->vol.org;
1034 setHirevVol();
1035 instp->vol.tremor.onOff = 1;
1036 instp->vol.tremor.count = instp->vol.tremor.onTime;
1037 }
1038 }
1039 }
1040
_MOD_instTremor(void)1041 void _MOD_instTremor(void)
1042 {
1043 addPerFrameWork(tremorPFW);
1044 }
1045
_MOD_instSetTremorParams(int onTime,int offTime)1046 void _MOD_instSetTremorParams(int onTime, int offTime)
1047 {
1048 instp->vol.tremor.onTime = onTime;
1049 instp->vol.tremor.offTime = offTime;
1050 instp->vol.tremor.count = 0;
1051 instp->vol.tremor.onOff = 0;
1052 }
1053
1054
1055 /* note off */
1056
noteOffPFW(void)1057 static void noteOffPFW(void)
1058 {
1059 if (instp->per.delay.n == instp->frame.cur) noteOff();
1060 }
1061
_MOD_instNoteOff(int delay)1062 void _MOD_instNoteOff(int delay)
1063 {
1064 if (delay) {
1065 instp->per.delay.n = delay;
1066 addPerFrameWork(noteOffPFW);
1067 } else { noteOff(); }
1068 }
1069
_MOD_instIsNoteOff(void)1070 int _MOD_instIsNoteOff(void)
1071 {
1072 return instp->hirev.ptr == NULL;
1073 }
1074
1075
1076 /* pan position */
1077
1078 /* pos = 0(left)..64(right), -1(surround) */
1079
_MOD_instPanPosition(int pos)1080 void _MOD_instPanPosition(int pos)
1081 {
1082 instp->vol.pan = pos;
1083 setHirevVol();
1084 }
1085
1086
1087 /* empty command */
1088
_MOD_instEmptyCmd(void)1089 void _MOD_instEmptyCmd(void)
1090 {
1091 instp->per.cur = instp->per.org;
1092 setW();
1093 /* empty command has some special meanings...
1094 (when after glissando portamento or vibrato) */
1095 }
1096
1097