1 //
2 // GOATTRACKER v2 playroutine
3 //
4 
5 #define GPLAY_C
6 
7 #include "goattrk2.h"
8 
9 unsigned char freqtbllo[] = {
10   0x17,0x27,0x39,0x4b,0x5f,0x74,0x8a,0xa1,0xba,0xd4,0xf0,0x0e,
11   0x2d,0x4e,0x71,0x96,0xbe,0xe8,0x14,0x43,0x74,0xa9,0xe1,0x1c,
12   0x5a,0x9c,0xe2,0x2d,0x7c,0xcf,0x28,0x85,0xe8,0x52,0xc1,0x37,
13   0xb4,0x39,0xc5,0x5a,0xf7,0x9e,0x4f,0x0a,0xd1,0xa3,0x82,0x6e,
14   0x68,0x71,0x8a,0xb3,0xee,0x3c,0x9e,0x15,0xa2,0x46,0x04,0xdc,
15   0xd0,0xe2,0x14,0x67,0xdd,0x79,0x3c,0x29,0x44,0x8d,0x08,0xb8,
16   0xa1,0xc5,0x28,0xcd,0xba,0xf1,0x78,0x53,0x87,0x1a,0x10,0x71,
17   0x42,0x89,0x4f,0x9b,0x74,0xe2,0xf0,0xa6,0x0e,0x33,0x20,0xff,
18   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
19   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
20   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
21   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
22 
23 unsigned char freqtblhi[] = {
24   0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,
25   0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x04,
26   0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x06,0x06,0x07,0x07,0x08,
27   0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0c,0x0d,0x0d,0x0e,0x0f,0x10,
28   0x11,0x12,0x13,0x14,0x15,0x17,0x18,0x1a,0x1b,0x1d,0x1f,0x20,
29   0x22,0x24,0x27,0x29,0x2b,0x2e,0x31,0x34,0x37,0x3a,0x3e,0x41,
30   0x45,0x49,0x4e,0x52,0x57,0x5c,0x62,0x68,0x6e,0x75,0x7c,0x83,
31   0x8b,0x93,0x9c,0xa5,0xaf,0xb9,0xc4,0xd0,0xdd,0xea,0xf8,0xff,
32   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
33   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
34   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
35   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
36 
37 CHN chn[MAX_CHN];
38 unsigned char filterctrl = 0;
39 unsigned char filtertype = 0;
40 unsigned char filtercutoff = 0;
41 unsigned char filtertime = 0;
42 unsigned char filterptr = 0;
43 unsigned char funktable[2];
44 unsigned char masterfader = 0x0f;
45 int psnum = 0;
46 int songinit = 0;
47 int lastsonginit = 0;
48 int startpattpos = 0;
49 
50 void sequencer(int c, CHN *cptr);
51 
initchannels(void)52 void initchannels(void)
53 {
54   int c;
55   CHN *cptr = &chn[0];
56 
57   memset(chn, 0, sizeof chn);
58 
59   for (c = 0; c < MAX_CHN; c++)
60   {
61     chn[c].trans = 0;
62     chn[c].instr = 1;
63     if (multiplier)
64       cptr->tempo = 6*multiplier-1;
65     else
66       cptr->tempo = 6-1;
67     cptr++;
68   }
69 
70   if (multiplier)
71   {
72     funktable[0] = 9*multiplier-1;
73     funktable[1] = 6*multiplier-1;
74   }
75   else
76   {
77     funktable[0] = 9-1;
78     funktable[1] = 6-1;
79   }
80 }
81 
initsong(int num,int mode)82 void initsong(int num, int mode)
83 {
84   sound_suspend();
85   songinit = PLAY_STOPPED;
86   psnum = num;
87   songinit = mode;
88   startpattpos = 0;
89   sound_flush();
90 }
91 
initsongpos(int num,int mode,int pattpos)92 void initsongpos(int num, int mode, int pattpos)
93 {
94   sound_suspend();
95   songinit = PLAY_STOPPED;
96   psnum = num;
97   songinit = mode;
98   startpattpos = pattpos;
99   sound_flush();
100 }
101 
stopsong(void)102 void stopsong(void)
103 {
104   if (songinit != PLAY_STOPPED)
105   {
106     sound_suspend();
107     songinit = PLAY_STOP;
108     sound_flush();
109   }
110 }
111 
rewindsong(void)112 void rewindsong(void)
113 {
114   if (lastsonginit == PLAY_BEGINNING) lastsonginit = PLAY_POS;
115   initsong(psnum, lastsonginit);
116 }
117 
playtestnote(int note,int ins,int chnnum)118 void playtestnote(int note, int ins, int chnnum)
119 {
120   if (note == KEYON) return;
121   if ((note == REST) || (note == KEYOFF))
122   {
123     releasenote(chnnum);
124     return;
125   }
126 
127   if (!(instr[ins].gatetimer & 0x40))
128   {
129     chn[chnnum].gate = 0xfe; // Keyoff
130     if (!(instr[ins].gatetimer & 0x80))
131     {
132       sidreg[0x5+chnnum*7] = adparam>>8; // Hardrestart
133       sidreg[0x6+chnnum*7] = adparam&0xff;
134     }
135   }
136 
137   chn[chnnum].instr = ins;
138   chn[chnnum].newnote = note;
139   if (songinit == PLAY_STOPPED)
140   {
141     chn[chnnum].tick = (instr[ins].gatetimer & 0x3f)+1;
142     chn[chnnum].gatetimer = instr[ins].gatetimer & 0x3f;
143   }
144 }
145 
releasenote(int chnnum)146 void releasenote(int chnnum)
147 {
148   chn[chnnum].gate = 0xfe;
149 }
150 
mutechannel(int chnnum)151 void mutechannel(int chnnum)
152 {
153   chn[chnnum].mute ^= 1;
154 }
155 
isplaying(void)156 int isplaying(void)
157 {
158   return (songinit != PLAY_STOPPED);
159 }
160 
playroutine(void)161 void playroutine(void)
162 {
163   INSTR *iptr;
164   CHN *cptr = &chn[0];
165   int c;
166 
167   if (songinit == PLAY_STOP)
168     followplay = 0;
169 
170   if ((songinit > 0) && (songinit < PLAY_STOPPED))
171   {
172     lastsonginit = songinit;
173 
174     filterctrl = 0;
175     filterptr = 0;
176 
177     resettime();
178 
179     if ((songinit == 0x02) || (songinit == 0x03))
180     {
181       if ((espos[0] >= songlen[psnum][0]) || (espos[1] >= songlen[psnum][1]) || (espos[2] >= songlen[psnum][2]))
182          songinit = 0x01;
183     }
184 
185     for (c = 0; c < MAX_CHN; c++)
186     {
187       cptr->songptr = 0;
188       cptr->command = 0;
189       cptr->cmddata = 0;
190       cptr->newcommand = 0;
191       cptr->newcmddata = 0;
192       cptr->advance = 1;
193       cptr->wave = 0;
194       cptr->ptr[WTBL] = 0;
195       cptr->newnote = 0;
196       cptr->repeat = 0;
197       if (multiplier)
198         cptr->tick = 6*multiplier-1;
199       else
200         cptr->tick = 6-1;
201       cptr->gatetimer = instr[1].gatetimer & 0x3f;
202       cptr->pattptr = 0x7fffffff;
203       if (cptr->tempo < 2) cptr->tempo = 0;
204 
205       switch (songinit)
206       {
207         case PLAY_BEGINNING:
208         if (multiplier)
209         {
210           funktable[0] = 9*multiplier-1;
211           funktable[1] = 6*multiplier-1;
212           cptr->tempo = 6*multiplier-1;
213         }
214         else
215         {
216           funktable[0] = 9-1;
217           funktable[1] = 6-1;
218           cptr->tempo = 6-1;
219         }
220         if ((instr[MAX_INSTR-1].ad >= 2) && (!(instr[MAX_INSTR-1].ptr[WTBL])))
221           cptr->tempo = instr[MAX_INSTR-1].ad - 1;
222         cptr->trans = 0;
223         cptr->instr = 1;
224         sequencer(c, cptr);
225         break;
226 
227         case PLAY_PATTERN:
228         cptr->advance = 0;
229         cptr->pattptr = startpattpos * 4;
230         cptr->pattnum = epnum[c];
231         if (cptr->pattptr >= (pattlen[cptr->pattnum] * 4))
232           cptr->pattptr = 0;
233         break;
234 
235         case PLAY_POS:
236         cptr->songptr = espos[c];
237         sequencer(c, cptr);
238         break;
239       }
240       cptr++;
241     }
242     if (songinit != PLAY_STOP)
243       songinit = 0;
244     else
245       songinit = PLAY_STOPPED;
246     if ((!songlen[psnum][0]) || (!songlen[psnum][1]) || (!songlen[psnum][2]))
247       songinit = PLAY_STOPPED; // Zero length song
248 
249     startpattpos = 0;
250   }
251   else
252   {
253     if (filterptr)
254     {
255       // Filter jump
256       if (ltable[FTBL][filterptr-1] == 0xff)
257       {
258         filterptr = rtable[FTBL][filterptr-1];
259         if (!filterptr) goto FILTERSTOP;
260       }
261 
262       if (!filtertime)
263       {
264         // Filter set
265         if (ltable[FTBL][filterptr-1] >= 0x80)
266         {
267           filtertype = ltable[FTBL][filterptr-1] & 0x70;
268           filterctrl = rtable[FTBL][filterptr-1];
269           filterptr++;
270           // Can be combined with cutoff set
271           if (ltable[FTBL][filterptr-1] == 0x00)
272           {
273             filtercutoff = rtable[FTBL][filterptr-1];
274             filterptr++;
275           }
276         }
277         else
278         {
279           // New modulation step
280           if (ltable[FTBL][filterptr-1])
281             filtertime = ltable[FTBL][filterptr-1];
282           else
283           {
284             // Cutoff set
285             filtercutoff = rtable[FTBL][filterptr-1];
286             filterptr++;
287           }
288         }
289       }
290       // Filter modulation
291       if (filtertime)
292       {
293         filtercutoff += rtable[FTBL][filterptr-1];
294         filtertime--;
295         if (!filtertime) filterptr++;
296       }
297     }
298     FILTERSTOP:
299     sidreg[0x15] = 0x00;
300     sidreg[0x16] = filtercutoff;
301     sidreg[0x17] = filterctrl;
302     sidreg[0x18] = filtertype | masterfader;
303 
304     for (c = 0; c < MAX_CHN; c++)
305     {
306       iptr = &instr[cptr->instr];
307 
308       // Reset tempo in jammode
309       if ((songinit == PLAY_STOPPED) && (cptr->tempo < 2))
310       {
311         if (multiplier)
312           cptr->tempo = 6*multiplier-1;
313         else
314           cptr->tempo = 6-1;
315       }
316 
317       // Decrease tick
318       cptr->tick--;
319       if (!cptr->tick) goto TICK0;
320 
321       // Tick N
322       // Reload counter
323       if (cptr->tick >= 0x80)
324       {
325         if (cptr->tempo >= 2)
326           cptr->tick = cptr->tempo;
327         else
328         {
329           // Set funktempo, switch between 2 values
330           cptr->tick = funktable[cptr->tempo];
331           cptr->tempo ^= 1;
332         }
333         // Check for illegally high gatetimer and stop the song in this case
334         if (chn->gatetimer > cptr->tick)
335           stopsong();
336       }
337       goto WAVEEXEC;
338 
339       // Tick 0
340       TICK0:
341       // Advance in sequencer
342       sequencer(c, cptr);
343 
344       // Get gatetimer compare-value
345       cptr->gatetimer = iptr->gatetimer & 0x3f;
346 
347       // New note init
348       if (cptr->newnote)
349       {
350         cptr->note = cptr->newnote-FIRSTNOTE;
351         cptr->command = 0;
352         cptr->vibdelay = iptr->vibdelay;
353         cptr->cmddata = iptr->ptr[STBL];
354         if (cptr->newcommand != CMD_TONEPORTA)
355         {
356           if (iptr->firstwave)
357           {
358             if (iptr->firstwave >= 0xfe) cptr->gate = iptr->firstwave;
359             else
360             {
361               cptr->wave = iptr->firstwave;
362               cptr->gate = 0xff;
363             }
364           }
365 
366 
367           cptr->ptr[WTBL] = iptr->ptr[WTBL];
368 
369           if (cptr->ptr[WTBL])
370           {
371             // Stop the song in case of jumping into a jump
372             if (ltable[WTBL][cptr->ptr[WTBL]-1] == 0xff)
373               stopsong();
374           }
375           if (iptr->ptr[PTBL])
376           {
377             cptr->ptr[PTBL] = iptr->ptr[PTBL];
378             cptr->pulsetime = 0;
379             if (cptr->ptr[PTBL])
380             {
381               // Stop the song in case of jumping into a jump
382               if (ltable[PTBL][cptr->ptr[PTBL]-1] == 0xff)
383                 stopsong();
384             }
385           }
386           if (iptr->ptr[FTBL])
387           {
388             filterptr = iptr->ptr[FTBL];
389             filtertime = 0;
390             if (filterptr)
391             {
392               // Stop the song in case of jumping into a jump
393               if (ltable[FTBL][filterptr-1] == 0xff)
394                 stopsong();
395             }
396           }
397           sidreg[0x5+7*c] = iptr->ad;
398           sidreg[0x6+7*c] = iptr->sr;
399         }
400       }
401 
402       // Tick 0 effects
403 
404       switch (cptr->newcommand)
405       {
406         case CMD_DONOTHING:
407         cptr->command = 0;
408         cptr->cmddata = iptr->ptr[STBL];
409         break;
410 
411         case CMD_PORTAUP:
412         case CMD_PORTADOWN:
413         cptr->vibtime = 0;
414         cptr->command = cptr->newcommand;
415         cptr->cmddata = cptr->newcmddata;
416         break;
417 
418         case CMD_TONEPORTA:
419         case CMD_VIBRATO:
420         cptr->command = cptr->newcommand;
421         cptr->cmddata = cptr->newcmddata;
422         break;
423 
424         case CMD_SETAD:
425         sidreg[0x5+7*c] = cptr->newcmddata;
426         break;
427 
428         case CMD_SETSR:
429         sidreg[0x6+7*c] = cptr->newcmddata;
430         break;
431 
432         case CMD_SETWAVE:
433         cptr->wave = cptr->newcmddata;
434         break;
435 
436         case CMD_SETWAVEPTR:
437         cptr->ptr[WTBL] = cptr->newcmddata;
438         cptr->wavetime = 0;
439         if (cptr->ptr[WTBL])
440         {
441           // Stop the song in case of jumping into a jump
442           if (ltable[WTBL][cptr->ptr[WTBL]-1] == 0xff)
443             stopsong();
444         }
445         break;
446 
447         case CMD_SETPULSEPTR:
448         cptr->ptr[PTBL] = cptr->newcmddata;
449         cptr->pulsetime = 0;
450         if (cptr->ptr[PTBL])
451         {
452           // Stop the song in case of jumping into a jump
453           if (ltable[PTBL][cptr->ptr[PTBL]-1] == 0xff)
454             stopsong();
455         }
456         break;
457 
458         case CMD_SETFILTERPTR:
459         filterptr = cptr->newcmddata;
460         filtertime = 0;
461         if (filterptr)
462         {
463           // Stop the song in case of jumping into a jump
464           if (ltable[FTBL][filterptr-1] == 0xff)
465             stopsong();
466         }
467         break;
468 
469         case CMD_SETFILTERCTRL:
470         filterctrl = cptr->newcmddata;
471         if (!filterctrl) filterptr = 0;
472         break;
473 
474         case CMD_SETFILTERCUTOFF:
475         filtercutoff = cptr->newcmddata;
476         break;
477 
478         case CMD_SETMASTERVOL:
479         if (cptr->newcmddata < 0x10)
480           masterfader = cptr->newcmddata;
481         break;
482 
483         case CMD_FUNKTEMPO:
484         if (cptr->newcmddata)
485         {
486           funktable[0] = ltable[STBL][cptr->newcmddata-1]-1;
487           funktable[1] = rtable[STBL][cptr->newcmddata-1]-1;
488         }
489         chn[0].tempo = 0;
490         chn[1].tempo = 0;
491         chn[2].tempo = 0;
492         break;
493 
494         case CMD_SETTEMPO:
495         {
496           unsigned char newtempo = cptr->newcmddata & 0x7f;
497 
498           if (newtempo >= 3) newtempo--;
499           if (cptr->newcmddata >= 0x80)
500             cptr->tempo = newtempo;
501           else
502           {
503             chn[0].tempo = newtempo;
504             chn[1].tempo = newtempo;
505             chn[2].tempo = newtempo;
506           }
507         }
508         break;
509       }
510       if (cptr->newnote)
511       {
512         cptr->newnote = 0;
513         if (cptr->newcommand != CMD_TONEPORTA) goto NEXTCHN;
514       }
515 
516       WAVEEXEC:
517       if (cptr->ptr[WTBL])
518       {
519         unsigned char wave = ltable[WTBL][cptr->ptr[WTBL]-1];
520         unsigned char note = rtable[WTBL][cptr->ptr[WTBL]-1];
521 
522         if (wave > WAVELASTDELAY)
523         {
524           // Normal waveform values
525           if (wave < WAVESILENT) cptr->wave = wave;
526           // Values without waveform selected
527           if ((wave >= WAVESILENT) && (wave <= WAVELASTSILENT)) cptr->wave = wave & 0xf;
528           // Command execution from wavetable
529           if ((wave >= WAVECMD) && (wave <= WAVELASTCMD))
530           {
531             unsigned char param = rtable[WTBL][cptr->ptr[WTBL]-1];
532             switch (wave & 0xf)
533             {
534               case CMD_DONOTHING:
535               case CMD_SETWAVEPTR:
536               case CMD_FUNKTEMPO:
537               stopsong();
538               break;
539 
540               case CMD_PORTAUP:
541               {
542                 unsigned short speed = 0;
543                 if (param)
544                 {
545                   speed = (ltable[STBL][param-1] << 8) | rtable[STBL][param-1];
546                 }
547                 if (speed >= 0x8000)
548                 {
549                   speed = freqtbllo[cptr->lastnote + 1] | (freqtblhi[cptr->lastnote + 1] << 8);
550                   speed -= freqtbllo[cptr->lastnote] | (freqtblhi[cptr->lastnote] << 8);
551                   speed >>= rtable[STBL][param-1];
552                 }
553                 cptr->freq += speed;
554               }
555               break;
556 
557               case CMD_PORTADOWN:
558               {
559                 unsigned short speed = 0;
560                 if (param)
561                 {
562                   speed = (ltable[STBL][param-1] << 8) | rtable[STBL][param-1];
563                 }
564                 if (speed >= 0x8000)
565                 {
566                   speed = freqtbllo[cptr->lastnote + 1] | (freqtblhi[cptr->lastnote + 1] << 8);
567                   speed -= freqtbllo[cptr->lastnote] | (freqtblhi[cptr->lastnote] << 8);
568                   speed >>= rtable[STBL][param-1];
569                 }
570                 cptr->freq -= speed;
571               }
572               break;
573 
574               case CMD_TONEPORTA:
575               {
576                 unsigned short targetfreq = freqtbllo[cptr->note] | (freqtblhi[cptr->note] << 8);
577                 unsigned short speed = 0;
578 
579                 if (!param)
580                 {
581                   cptr->freq = targetfreq;
582                   cptr->vibtime = 0;
583                 }
584                 else
585                 {
586                   speed = (ltable[STBL][param-1] << 8) | rtable[STBL][param-1];
587                   if (speed >= 0x8000)
588                   {
589                     speed = freqtbllo[cptr->lastnote + 1] | (freqtblhi[cptr->lastnote + 1] << 8);
590                     speed -= freqtbllo[cptr->lastnote] | (freqtblhi[cptr->lastnote] << 8);
591                     speed >>= rtable[STBL][param-1];
592                   }
593                   if (cptr->freq < targetfreq)
594                   {
595                     cptr->freq += speed;
596                     if (cptr->freq > targetfreq)
597                     {
598                       cptr->freq = targetfreq;
599                       cptr->vibtime = 0;
600                     }
601                   }
602                   if (cptr->freq > targetfreq)
603                   {
604                     cptr->freq -= speed;
605                     if (cptr->freq < targetfreq)
606                     {
607                       cptr->freq = targetfreq;
608                       cptr->vibtime = 0;
609                     }
610                   }
611                 }
612               }
613               break;
614 
615               case CMD_VIBRATO:
616               {
617                 unsigned short speed = 0;
618                 unsigned char cmpvalue = 0;
619 
620                 if (param)
621                 {
622                   cmpvalue = ltable[STBL][param-1];
623                   speed = rtable[STBL][param-1];
624                 }
625                 if (cmpvalue >= 0x80)
626                 {
627                   cmpvalue &= 0x7f;
628                   speed = freqtbllo[cptr->lastnote + 1] | (freqtblhi[cptr->lastnote + 1] << 8);
629                   speed -= freqtbllo[cptr->lastnote] | (freqtblhi[cptr->lastnote] << 8);
630                   speed >>= rtable[STBL][param-1];
631                 }
632 
633                 if ((cptr->vibtime < 0x80) && (cptr->vibtime > cmpvalue))
634                   cptr->vibtime ^= 0xff;
635                 cptr->vibtime += 0x02;
636                 if (cptr->vibtime & 0x01)
637                   cptr->freq -= speed;
638                 else
639                   cptr->freq += speed;
640               }
641               break;
642 
643               case CMD_SETAD:
644               sidreg[0x5+7*c] = param;
645               break;
646 
647               case CMD_SETSR:
648               sidreg[0x6+7*c] = param;;
649               break;
650 
651               case CMD_SETWAVE:
652               cptr->wave = param;
653               break;
654 
655               case CMD_SETPULSEPTR:
656               cptr->ptr[PTBL] = param;
657               cptr->pulsetime = 0;
658               if (cptr->ptr[PTBL])
659               {
660                 // Stop the song in case of jumping into a jump
661                 if (ltable[PTBL][cptr->ptr[PTBL]-1] == 0xff)
662                   stopsong();
663               }
664               break;
665 
666               case CMD_SETFILTERPTR:
667               filterptr = param;
668               filtertime = 0;
669               if (filterptr)
670               {
671                 // Stop the song in case of jumping into a jump
672                 if (ltable[FTBL][filterptr-1] == 0xff)
673                 stopsong();
674               }
675               break;
676 
677               case CMD_SETFILTERCTRL:
678               filterctrl = param;
679               if (!filterctrl) filterptr = 0;
680               break;
681 
682               case CMD_SETFILTERCUTOFF:
683               filtercutoff = param;
684               break;
685 
686               case CMD_SETMASTERVOL:
687               if (param < 0x10)
688                 masterfader = param;
689               break;
690             }
691           }
692         }
693         else
694         {
695           // Wavetable delay
696           if (cptr->wavetime != wave)
697           {
698             cptr->wavetime++;
699             goto TICKNEFFECTS;
700           }
701         }
702 
703         cptr->wavetime = 0;
704         cptr->ptr[WTBL]++;
705         // Wavetable jump
706         if (ltable[WTBL][cptr->ptr[WTBL]-1] == 0xff)
707         {
708           cptr->ptr[WTBL] = rtable[WTBL][cptr->ptr[WTBL]-1];
709         }
710 
711         if ((wave >= WAVECMD) && (wave <= WAVELASTCMD))
712           goto PULSEEXEC;
713 
714         if (note != 0x80)
715         {
716           if (note < 0x80)
717             note += cptr->note;
718           note &= 0x7f;
719           cptr->freq = freqtbllo[note] | (freqtblhi[note]<<8);
720           cptr->vibtime = 0;
721           cptr->lastnote = note;
722           goto PULSEEXEC;
723         }
724       }
725 
726       // Tick N command
727       TICKNEFFECTS:
728       if ((!optimizerealtime) || (cptr->tick))
729       {
730         switch(cptr->command)
731         {
732           case CMD_PORTAUP:
733           {
734             unsigned short speed = 0;
735             if (cptr->cmddata)
736             {
737               speed = (ltable[STBL][cptr->cmddata-1] << 8) | rtable[STBL][cptr->cmddata-1];
738             }
739             if (speed >= 0x8000)
740             {
741               speed = freqtbllo[cptr->lastnote + 1] | (freqtblhi[cptr->lastnote + 1] << 8);
742               speed -= freqtbllo[cptr->lastnote] | (freqtblhi[cptr->lastnote] << 8);
743               speed >>= rtable[STBL][cptr->cmddata-1];
744             }
745             cptr->freq += speed;
746           }
747           break;
748 
749           case CMD_PORTADOWN:
750           {
751             unsigned short speed = 0;
752             if (cptr->cmddata)
753             {
754               speed = (ltable[STBL][cptr->cmddata-1] << 8) | rtable[STBL][cptr->cmddata-1];
755             }
756             if (speed >= 0x8000)
757             {
758               speed = freqtbllo[cptr->lastnote + 1] | (freqtblhi[cptr->lastnote + 1] << 8);
759               speed -= freqtbllo[cptr->lastnote] | (freqtblhi[cptr->lastnote] << 8);
760               speed >>= rtable[STBL][cptr->cmddata-1];
761             }
762             cptr->freq -= speed;
763           }
764           break;
765 
766           case CMD_DONOTHING:
767           if ((!cptr->cmddata) || (!cptr->vibdelay))
768             break;
769           if (cptr->vibdelay > 1)
770           {
771             cptr->vibdelay--;
772             break;
773           }
774           case CMD_VIBRATO:
775           {
776             unsigned short speed = 0;
777             unsigned char cmpvalue = 0;
778 
779             if (cptr->cmddata)
780             {
781               cmpvalue = ltable[STBL][cptr->cmddata-1];
782               speed = rtable[STBL][cptr->cmddata-1];
783             }
784             if (cmpvalue >= 0x80)
785             {
786               cmpvalue &= 0x7f;
787               speed = freqtbllo[cptr->lastnote + 1] | (freqtblhi[cptr->lastnote + 1] << 8);
788               speed -= freqtbllo[cptr->lastnote] | (freqtblhi[cptr->lastnote] << 8);
789               speed >>= rtable[STBL][cptr->cmddata-1];
790             }
791 
792             if ((cptr->vibtime < 0x80) && (cptr->vibtime > cmpvalue))
793               cptr->vibtime ^= 0xff;
794             cptr->vibtime += 0x02;
795             if (cptr->vibtime & 0x01)
796               cptr->freq -= speed;
797             else
798               cptr->freq += speed;
799           }
800           break;
801 
802           case CMD_TONEPORTA:
803           {
804             unsigned short targetfreq = freqtbllo[cptr->note] | (freqtblhi[cptr->note] << 8);
805             unsigned short speed = 0;
806 
807             if (!cptr->cmddata)
808             {
809               cptr->freq = targetfreq;
810               cptr->vibtime = 0;
811             }
812             else
813             {
814               speed = (ltable[STBL][cptr->cmddata-1] << 8) | rtable[STBL][cptr->cmddata-1];
815               if (speed >= 0x8000)
816               {
817                 speed = freqtbllo[cptr->lastnote + 1] | (freqtblhi[cptr->lastnote + 1] << 8);
818                 speed -= freqtbllo[cptr->lastnote] | (freqtblhi[cptr->lastnote] << 8);
819                 speed >>= rtable[STBL][cptr->cmddata-1];
820               }
821               if (cptr->freq < targetfreq)
822               {
823                 cptr->freq += speed;
824                 if (cptr->freq > targetfreq)
825                 {
826                   cptr->freq = targetfreq;
827                   cptr->vibtime = 0;
828                 }
829               }
830               if (cptr->freq > targetfreq)
831               {
832                 cptr->freq -= speed;
833                 if (cptr->freq < targetfreq)
834                 {
835                   cptr->freq = targetfreq;
836                   cptr->vibtime = 0;
837                 }
838               }
839             }
840           }
841           break;
842         }
843       }
844 
845       PULSEEXEC:
846       if (optimizepulse)
847       {
848         if ((songinit != PLAY_STOPPED) && (cptr->tick == cptr->gatetimer)) goto GETNEWNOTES;
849       }
850 
851       if (cptr->ptr[PTBL])
852       {
853         // Skip pulse when sequencer has been executed
854         if (optimizepulse)
855         {
856           if ((!cptr->tick) && (!cptr->pattptr)) goto NEXTCHN;
857         }
858 
859         // Pulsetable jump
860         if (ltable[PTBL][cptr->ptr[PTBL]-1] == 0xff)
861         {
862           cptr->ptr[PTBL] = rtable[PTBL][cptr->ptr[PTBL]-1];
863           if (!cptr->ptr[PTBL]) goto PULSEEXEC;
864         }
865 
866         if (!cptr->pulsetime)
867         {
868           // Set pulse
869           if (ltable[PTBL][cptr->ptr[PTBL]-1] >= 0x80)
870           {
871             cptr->pulse = (ltable[PTBL][cptr->ptr[PTBL]-1] & 0xf) << 8;
872             cptr->pulse |= rtable[PTBL][cptr->ptr[PTBL]-1];
873             cptr->ptr[PTBL]++;
874           }
875           else
876           {
877             cptr->pulsetime = ltable[PTBL][cptr->ptr[PTBL]-1];
878           }
879         }
880         // Pulse modulation
881         if (cptr->pulsetime)
882         {
883           unsigned char speed = rtable[PTBL][cptr->ptr[PTBL]-1];
884           if (speed < 0x80)
885           {
886             cptr->pulse += speed;
887             cptr->pulse &= 0xfff;
888           }
889           else
890           {
891             cptr->pulse += speed;
892             cptr->pulse -= 0x100;
893             cptr->pulse &= 0xfff;
894           }
895           cptr->pulsetime--;
896           if (!cptr->pulsetime) cptr->ptr[PTBL]++;
897         }
898       }
899       if ((songinit == PLAY_STOPPED) || (cptr->tick != cptr->gatetimer)) goto NEXTCHN;
900 
901       // New notes processing
902       GETNEWNOTES:
903       {
904         unsigned char newnote;
905 
906         newnote = pattern[cptr->pattnum][cptr->pattptr];
907         if (pattern[cptr->pattnum][cptr->pattptr+1])
908           cptr->instr = pattern[cptr->pattnum][cptr->pattptr+1];
909         cptr->newcommand = pattern[cptr->pattnum][cptr->pattptr+2];
910         cptr->newcmddata = pattern[cptr->pattnum][cptr->pattptr+3];
911         cptr->pattptr += 4;
912         if (pattern[cptr->pattnum][cptr->pattptr] == ENDPATT)
913           cptr->pattptr = 0x7fffffff;
914 
915         if (newnote == KEYOFF)
916           cptr->gate = 0xfe;
917         if (newnote == KEYON)
918           cptr->gate = 0xff;
919         if (newnote <= LASTNOTE)
920         {
921           cptr->newnote = newnote+cptr->trans;
922           if ((cptr->newcommand) != CMD_TONEPORTA)
923           {
924             if (!(instr[cptr->instr].gatetimer & 0x40))
925             {
926               cptr->gate = 0xfe;
927               if (!(instr[cptr->instr].gatetimer & 0x80))
928               {
929                 sidreg[0x5+7*c] = adparam>>8;
930                 sidreg[0x6+7*c] = adparam&0xff;
931               }
932             }
933           }
934         }
935       }
936       NEXTCHN:
937       if (cptr->mute)
938         sidreg[0x4+7*c] = cptr->wave = 0x08;
939       else
940       {
941         sidreg[0x0+7*c] = cptr->freq & 0xff;
942         sidreg[0x1+7*c] = cptr->freq >> 8;
943         sidreg[0x2+7*c] = cptr->pulse & 0xfe;
944         sidreg[0x3+7*c] = cptr->pulse >> 8;
945         sidreg[0x4+7*c] = cptr->wave & cptr->gate;
946       }
947       cptr++;
948     }
949   }
950   if (songinit != PLAY_STOPPED) incrementtime();
951 }
952 
sequencer(int c,CHN * cptr)953 void sequencer(int c, CHN *cptr)
954 {
955   if ((songinit != PLAY_STOPPED) && (cptr->pattptr == 0x7fffffff))
956   {
957     cptr->pattptr = startpattpos * 4;
958     if (!cptr->advance) goto SEQDONE;
959     // Song loop
960     if (songorder[psnum][c][cptr->songptr] == LOOPSONG)
961     {
962       cptr->songptr = songorder[psnum][c][cptr->songptr+1];
963       if (cptr->songptr >= songlen[psnum][c])
964       {
965         stopsong();
966         cptr->songptr = 0;
967         goto SEQDONE;
968       }
969     }
970     // Transpose
971     if ((songorder[psnum][c][cptr->songptr] >= TRANSDOWN) && (songorder[psnum][c][cptr->songptr] < LOOPSONG))
972     {
973       cptr->trans = songorder[psnum][c][cptr->songptr]-TRANSUP;
974       cptr->songptr++;
975     }
976     // Repeat
977     if ((songorder[psnum][c][cptr->songptr] >= REPEAT) && (songorder[psnum][c][cptr->songptr] < TRANSDOWN))
978     {
979       cptr->repeat = songorder[psnum][c][cptr->songptr]-REPEAT;
980       cptr->songptr++;
981     }
982     // Pattern number
983     cptr->pattnum = songorder[psnum][c][cptr->songptr];
984     if (cptr->repeat)
985       cptr->repeat--;
986     else
987       cptr->songptr++;
988 
989     // Check for illegal pattern now
990     if (cptr->pattnum >= MAX_PATT)
991     {
992       stopsong();
993       cptr->pattnum = 0;
994     }
995     if (cptr->pattptr >= (pattlen[cptr->pattnum] * 4))
996       cptr->pattptr = 0;
997 
998     // Check for playback endpos
999     if ((lastsonginit != PLAY_BEGINNING) && (esend[c] > 0) && (esend[c] > espos[c]) && (cptr->songptr > esend[c]) && (espos[c] < songlen[psnum][c]))
1000       cptr->songptr = espos[c];
1001   }
1002   SEQDONE: {}
1003 }
1004