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