1;-------------------------------------------------------------------------------
2; GoatTracker V2.73 playroutine
3;
4; NOTE: This playroutine source code does not fall under the GPL license!
5; Use it, or song binaries created from it freely for any purpose, commercial
6; or noncommercial.
7;
8; NOTE 2: This code is in the format of Magnus Lind's assembler from Exomizer.
9; Does not directly compile on DASM etc.
10;-------------------------------------------------------------------------------
11
12        ;Defines will be inserted by the relocator here
13
14              .IF (ZPGHOSTREGS == 0)
15mt_temp1        = zpbase+0
16mt_temp2        = zpbase+1
17              .ELSE
18ghostfreqlo     = zpbase+0
19ghostfreqhi     = zpbase+1
20ghostpulselo    = zpbase+2
21ghostpulsehi    = zpbase+3
22ghostwave       = zpbase+4
23ghostad         = zpbase+5
24ghostsr         = zpbase+6
25ghostfiltcutlow = zpbase+21
26ghostfiltcutoff = zpbase+22
27ghostfiltctrl   = zpbase+23
28ghostfilttype   = zpbase+24
29mt_temp1        = zpbase+25
30mt_temp2        = zpbase+26
31              .ENDIF
32
33        ;Defines for the music data
34        ;Patterndata notes
35
36ENDPATT         = $00
37INS             = $00
38FX              = $40
39FXONLY          = $50
40NOTE            = $60
41REST            = $bd
42KEYOFF          = $be
43KEYON           = $bf
44FIRSTPACKEDREST = $c0
45PACKEDREST      = $00
46
47        ;Effects
48
49DONOTHING       = $00
50PORTAUP         = $01
51PORTADOWN       = $02
52TONEPORTA       = $03
53VIBRATO         = $04
54SETAD           = $05
55SETSR           = $06
56SETWAVE         = $07
57SETWAVEPTR      = $08
58SETPULSEPTR     = $09
59SETFILTPTR      = $0a
60SETFILTCTRL     = $0b
61SETFILTCUTOFF   = $0c
62SETMASTERVOL    = $0d
63SETFUNKTEMPO    = $0e
64SETTEMPO        = $0f
65
66        ;Orderlist commands
67
68REPEAT          = $d0
69TRANSDOWN       = $e0
70TRANS           = $f0
71TRANSUP         = $f0
72LOOPSONG        = $ff
73
74        ;Wave,pulse,filttable comands
75
76LOOPWAVE        = $ff
77LOOPPULSE       = $ff
78LOOPFILT        = $ff
79SETPULSE        = $80
80SETFILTER       = $80
81SETCUTOFF       = $00
82
83                .ORG (base)
84
85        ;Jump table
86
87                jmp mt_init
88                jmp mt_play
89              .IF (SOUNDSUPPORT != 0)
90                jmp mt_playsfx
91              .ENDIF
92              .IF (VOLSUPPORT != 0)
93                jmp mt_setmastervol
94              .ENDIF
95
96        ;Author info
97
98              .IF (NOAUTHORINFO == 0)
99
100authorinfopos   = base + $20
101checkpos1:
102              .IF ((authorinfopos - checkpos1) > 15)
103mt_tick0jumptbl:
104                .BYTE (mt_tick0_0 % 256)
105                .BYTE (mt_tick0_12 % 256)
106                .BYTE (mt_tick0_12 % 256)
107                .BYTE (mt_tick0_34 % 256)
108                .BYTE (mt_tick0_34 % 256)
109                .BYTE (mt_tick0_5 % 256)
110                .BYTE (mt_tick0_6 % 256)
111                .BYTE (mt_tick0_7 % 256)
112                .BYTE (mt_tick0_8 % 256)
113                .BYTE (mt_tick0_9 % 256)
114                .BYTE (mt_tick0_a % 256)
115                .BYTE (mt_tick0_b % 256)
116                .BYTE (mt_tick0_c % 256)
117                .BYTE (mt_tick0_d % 256)
118                .BYTE (mt_tick0_e % 256)
119                .BYTE (mt_tick0_f % 256)
120              .ENDIF
121
122checkpos2:
123              .IF ((authorinfopos - checkpos2) > 4)
124mt_effectjumptbl:
125                .BYTE (mt_effect_0 % 256)
126                .BYTE (mt_effect_12 % 256)
127                .BYTE (mt_effect_12 % 256)
128                .BYTE (mt_effect_3 % 256)
129                .BYTE (mt_effect_4 % 256)
130              .ENDIF
131
132checkpos3:
133              .IF ((authorinfopos - checkpos3) > 1)
134mt_funktempotbl:
135                .BYTE (8,5)
136              .ENDIF
137
138        ;This is pretty stupid way of filling left-out space, but .ORG
139        ;seemed to bug
140
141checkpos4:
142              .IF ((authorinfopos - checkpos4) > 0) .BYTE (0) .ENDIF
143checkpos5:
144              .IF ((authorinfopos - checkpos5) > 0) .BYTE (0) .ENDIF
145checkpos6:
146              .IF ((authorinfopos - checkpos6) > 0) .BYTE (0) .ENDIF
147
148mt_author:
149
150                .BYTE (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
151                .BYTE (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
152              .ENDIF
153
154        ;0 Instrument vibrato
155
156mt_tick0_0:
157              .IF (NOEFFECTS == 0)
158              .IF (NOINSTRVIB == 0)
159                lda mt_insvibparam-1,y
160                jmp mt_tick0_34
161              .ELSE
162              .IF (NOVIB == 0)
163                lda #$00
164                jmp mt_tick0_34
165              .ENDIF
166              .ENDIF
167              .ENDIF
168
169        ;1,2 Portamentos
170
171
172mt_tick0_12:
173              .IF (NOVIB == 0)
174                tay
175                lda #$00
176                sta mt_chnvibtime,x
177                tya
178              .ENDIF
179
180        ;3,4 Toneportamento, Vibrato
181
182mt_tick0_34:
183              .IF (NOEFFECTS == 0)
184              .IF ((NOTONEPORTA == 0) || (NOPORTAMENTO == 0) || (NOVIB == 0))
185                sta mt_chnparam,x
186                lda mt_chnnewfx,x
187                sta mt_chnfx,x
188              .ENDIF
189                rts
190              .ENDIF
191
192        ;5 Set AD
193
194mt_tick0_5:
195              .IF (NOSETAD == 0)
196              .IF (BUFFEREDWRITES == 0)
197                sta SIDBASE+$05,x
198              .ELSE
199              .IF (GHOSTREGS == 0)
200                sta mt_chnad,x
201              .ELSE
202                sta <ghostad,x
203              .ENDIF
204              .ENDIF
205                rts
206              .ENDIF
207
208        ;6 Set Sustain/Release
209
210mt_tick0_6:
211              .IF (NOSETSR == 0)
212              .IF (BUFFEREDWRITES == 0)
213                sta SIDBASE+$06,x
214              .ELSE
215              .IF (GHOSTREGS == 0)
216                sta mt_chnsr,x
217              .ELSE
218                sta <ghostsr,x
219              .ENDIF
220              .ENDIF
221                rts
222              .ENDIF
223
224        ;7 Set waveform
225
226mt_tick0_7:
227              .IF (NOSETWAVE == 0)
228                sta mt_chnwave,x
229                rts
230              .ENDIF
231
232        ;8 Set wavepointer
233
234mt_tick0_8:
235              .IF (NOSETWAVEPTR == 0)
236                sta mt_chnwaveptr,x
237              .IF (NOWAVEDELAY == 0)
238                lda #$00                        ;Make sure possible delayed
239                sta mt_chnwavetime,x            ;waveform execution goes
240              .ENDIF                            ;correctly
241                rts
242              .ENDIF
243
244        ;9 Set pulsepointer
245
246mt_tick0_9:
247              .IF (NOSETPULSEPTR == 0)
248                sta mt_chnpulseptr,x
249                lda #$00                        ;Reset pulse step duration
250                sta mt_chnpulsetime,x
251                rts
252              .ENDIF
253
254        ;a Set filtpointer
255
256mt_tick0_a:
257              .IF (NOSETFILTPTR == 0)
258              .IF (NOFILTERMOD == 0)
259                ldy #$00
260                sty mt_filttime+1
261              .ENDIF
262mt_tick0_a_step:
263                sta mt_filtstep+1
264                rts
265              .ENDIF
266
267        ;b Set filtcontrol (channels & resonance)
268
269mt_tick0_b:
270              .IF (NOSETFILTCTRL == 0)
271                sta mt_filtctrl+1
272              .IF (NOSETFILTPTR == 0)
273                beq mt_tick0_a_step          ;If 0, stop also step-programming
274              .ELSE
275                bne mt_tick0_b_noset
276                sta mt_filtstep+1
277mt_tick0_b_noset:
278              .ENDIF
279                rts
280              .ENDIF
281
282        ;c Set cutoff
283
284mt_tick0_c:
285              .IF (NOSETFILTCUTOFF == 0)
286                sta mt_filtcutoff+1
287                rts
288              .ENDIF
289
290        ;d Set mastervolume / timing mark
291
292mt_tick0_d:
293              .IF (NOSETMASTERVOL == 0)
294              .IF (NOAUTHORINFO == 0)
295                cmp #$10
296                bcs mt_tick0_d_timing
297              .ENDIF
298mt_setmastervol:
299                sta mt_masterfader+1
300                rts
301              .IF (NOAUTHORINFO == 0)
302mt_tick0_d_timing:
303                sta mt_author+31
304                rts
305              .ENDIF
306              .ENDIF
307
308        ;e Funktempo
309
310mt_tick0_e:
311              .IF (NOFUNKTEMPO == 0)
312                tay
313                lda mt_speedlefttbl-1,y
314                sta mt_funktempotbl
315                lda mt_speedrighttbl-1,y
316                sta mt_funktempotbl+1
317                lda #$00
318              .IF (NOCHANNELTEMPO == 0)
319                beq mt_tick0_f_setglobaltempo
320              .ENDIF
321              .ENDIF
322
323        ;f Set Tempo
324
325mt_tick0_f:
326              .IF ((NOCHANNELTEMPO == 0) && (NOGLOBALTEMPO == 0))
327                bmi mt_tick0_f_setchantempo     ;Channel or global tempo?
328              .ENDIF
329mt_tick0_f_setglobaltempo:
330              .IF (NOGLOBALTEMPO == 0)
331                sta mt_chntempo
332              .IF (NUMCHANNELS > 1)
333                sta mt_chntempo+7
334              .ENDIF
335              .IF (NUMCHANNELS > 2)
336                sta mt_chntempo+14
337              .ENDIF
338                rts
339              .ENDIF
340mt_tick0_f_setchantempo:
341              .IF (NOCHANNELTEMPO == 0)
342                and #$7f
343                sta mt_chntempo,x
344                rts
345              .ENDIF
346
347        ;Continuous effect code
348
349        ;0 Instrument vibrato
350
351              .IF (NOINSTRVIB == 0)
352mt_effect_0_delay:
353                dec mt_chnvibdelay,x
354mt_effect_0_donothing:
355                jmp mt_done
356mt_effect_0:    beq mt_effect_0_donothing         ;Speed 0 = no vibrato at all
357                lda mt_chnvibdelay,x
358                bne mt_effect_0_delay
359              .ELSE
360mt_effect_0:
361mt_effect_0_donothing:
362                jmp mt_done
363              .ENDIF
364
365        ;4 Vibrato
366
367mt_effect_4:
368              .IF (NOVIB == 0)
369              .IF (NOCALCULATEDSPEED == 0)
370                lda mt_speedlefttbl-1,y
371              .IF (NONORMALSPEED == 0)
372                bmi mt_effect_4_nohibyteclear
373                ldy #$00                        ;Clear speed highbyte
374                sty <mt_temp2
375              .ENDIF
376mt_effect_4_nohibyteclear:
377                and #$7f
378                sta mt_effect_4_speedcmp+1
379              .ELSE
380                lda #$00                        ;Clear speed highbyte
381                sta <mt_temp2
382              .ENDIF
383                lda mt_chnvibtime,x
384                bmi mt_effect_4_nodir
385              .IF (NOCALCULATEDSPEED != 0)
386                cmp mt_speedlefttbl-1,y
387              .ELSE
388mt_effect_4_speedcmp:
389                cmp #$00
390              .ENDIF
391                bcc mt_effect_4_nodir2
392                beq mt_effect_4_nodir
393                eor #$ff
394mt_effect_4_nodir:
395                clc
396mt_effect_4_nodir2:
397                adc #$02
398mt_vibdone:
399                sta mt_chnvibtime,x
400                lsr
401                bcc mt_freqadd
402                bcs mt_freqsub
403              .ENDIF
404
405        ;1,2,3 Portamentos
406
407mt_effect_3:
408              .IF (NOTONEPORTA == 0)
409                tya
410                beq mt_effect_3_found           ;Speed $00 = tie note
411              .ENDIF
412mt_effect_12:
413              .IF ((NOTONEPORTA == 0) || (NOPORTAMENTO == 0))
414              .IF (NOCALCULATEDSPEED != 0)
415                lda mt_speedlefttbl-1,y
416                sta <mt_temp2
417              .ENDIF
418              .ENDIF
419              .IF (NOPORTAMENTO == 0)
420
421              .IF (NOWAVECMD != 0)
422                lda mt_chnfx,x
423              .ELSE
424mt_effectnum:
425                lda #$00
426              .ENDIF
427                cmp #$02
428                bcc mt_freqadd
429                beq mt_freqsub
430              .ELSE
431              .IF (NOTONEPORTA == 0)
432                sec
433              .ENDIF
434              .ENDIF
435              .IF (NOTONEPORTA == 0)
436                ldy mt_chnnote,y
437              .IF (GHOSTREGS == 0)
438                lda mt_chnfreqlo,x              ;Calculate offset to the
439                sbc mt_freqtbllo-FIRSTNOTE,y    ;right frequency
440                pha
441                lda mt_chnfreqhi,x
442              .ELSE
443                lda <ghostfreqlo,x              ;Calculate offset to the
444                sbc mt_freqtbllo-FIRSTNOTE,y    ;right frequency
445                pha
446                lda <ghostfreqhi,x
447              .ENDIF
448                sbc mt_freqtblhi-FIRSTNOTE,y
449                tay
450                pla
451                bcs mt_effect_3_down            ;If positive, have to go down
452
453mt_effect_3_up:
454                adc <mt_temp1                   ;Add speed to offset
455                tya                             ;If changes sign, we're done
456                adc <mt_temp2
457                bpl mt_effect_3_found
458              .ENDIF
459
460
461              .IF ((NOTONEPORTA == 0) || (NOPORTAMENTO == 0) || (NOVIB == 0))
462mt_freqadd:
463              .IF (GHOSTREGS == 0)
464                lda mt_chnfreqlo,x
465                adc <mt_temp1
466                sta mt_chnfreqlo,x
467                lda mt_chnfreqhi,x
468              .ELSE
469                lda <ghostfreqlo,x
470                adc <mt_temp1
471                sta <ghostfreqlo,x
472                lda <ghostfreqhi,x
473              .ENDIF
474                adc <mt_temp2
475                jmp mt_storefreqhi
476              .ENDIF
477
478              .IF (NOTONEPORTA == 0)
479mt_effect_3_down:
480                sbc <mt_temp1                   ;Subtract speed from offset
481                tya                             ;If changes sign, we're done
482                sbc <mt_temp2
483                bmi mt_effect_3_found
484              .ENDIF
485
486              .IF ((NOTONEPORTA == 0) || (NOPORTAMENTO == 0) || (NOVIB == 0))
487mt_freqsub:
488              .IF (GHOSTREGS == 0)
489                lda mt_chnfreqlo,x
490                sbc <mt_temp1
491                sta mt_chnfreqlo,x
492                lda mt_chnfreqhi,x
493              .ELSE
494                lda <ghostfreqlo,x
495                sbc <mt_temp1
496                sta <ghostfreqlo,x
497                lda <ghostfreqhi,x
498              .ENDIF
499                sbc <mt_temp2
500                jmp mt_storefreqhi
501              .ENDIF
502
503mt_effect_3_found:
504              .IF (NOTONEPORTA == 0)
505              .IF (NOCALCULATEDSPEED == 0)
506                lda mt_chnnote,x
507                jmp mt_wavenoteabs
508              .ELSE
509                ldy mt_chnnote,y
510                jmp mt_wavenote
511              .ENDIF
512              .ENDIF
513
514        ;Init routine
515
516mt_init:
517              .IF (NUMSONGS > 1)
518                sta mt_init+5
519                asl
520                adc #$00
521              .ENDIF
522                sta mt_initsongnum+1
523                rts
524
525        ;Play soundeffect -routine
526
527              .IF (SOUNDSUPPORT != 0)
528        ;Sound FX init routine
529
530mt_playsfx:     sta mt_playsfxlo+1
531                sty mt_playsfxhi+1
532                lda mt_chnsfx,x                   ;Need a priority check?
533                beq mt_playsfxok
534                tya                               ;Check address highbyte
535                cmp mt_chnsfxhi,x
536                bcc mt_playsfxskip                ;Lower than current -> skip
537                bne mt_playsfxok                  ;Higher than current -> OK
538                lda mt_playsfxlo+1                ;Check address lowbyte
539                cmp mt_chnsfxlo,x
540                bcc mt_playsfxskip                ;Lower than current -> skip
541mt_playsfxok:   lda #$01
542                sta mt_chnsfx,x
543mt_playsfxlo:   lda #$00
544                sta mt_chnsfxlo,x
545mt_playsfxhi:   lda #$00
546                sta mt_chnsfxhi,x
547mt_playsfxskip: rts
548              .ENDIF
549
550        ;Set mastervolume -routine
551
552              .IF ((VOLSUPPORT != 0) && (NOSETMASTERVOL != 0))
553mt_setmastervol:
554                sta mt_masterfader+1
555                rts
556              .ENDIF
557
558        ;Playroutine
559
560mt_play:
561                .IF ((ZPGHOSTREGS == 0) && (GHOSTREGS != 0))
562                ldx #24                         ;In full ghosting mode copy
563mt_copyregs:    lda ghostregs,x                 ;previous frame's SID values in one step
564                sta SIDBASE,x
565                dex
566                bpl mt_copyregs
567                .ENDIF
568
569                ldx #$00                        ;Channel index
570
571        ;Song initialization
572
573mt_initsongnum:
574                ldy #$00
575                bmi mt_filtstep
576                txa
577                ldx #NUMCHANNELS * 14 - 1
578mt_resetloop:
579                sta mt_chnsongptr,x             ;Reset sequencer + voice
580                dex                             ;variables on all channels
581                bpl mt_resetloop
582              .IF (GHOSTREGS == 0)
583              .IF (NUMCHANNELS == 2)
584                sta SIDBASE+$12
585              .ENDIF
586              .IF (NUMCHANNELS == 1)
587                sta SIDBASE+$0b
588                sta SIDBASE+$12
589              .ENDIF
590                sta SIDBASE+$15                       ;Reset filter cutoff lowbyte
591              .ELSE
592                sta <ghostfiltcutlow
593              .ENDIF
594                sta mt_filtctrl+1             ;Switch filter off & reset
595              .IF (NOFILTER == 0)
596                sta mt_filtstep+1             ;step-programming
597              .ENDIF
598                stx mt_initsongnum+1          ;Reset initflag
599                tax
600              .IF (NUMCHANNELS == 3)
601                jsr mt_initchn
602                ldx #$07
603                jsr mt_initchn
604                ldx #$0e
605              .ENDIF
606              .IF (NUMCHANNELS == 2)
607                jsr mt_initchn
608                ldx #$07
609              .ENDIF
610mt_initchn:
611              .IF (NUMSONGS > 1)
612                tya
613                iny
614                sta mt_chnsongnum,x             ;Store index to songtable
615              .ENDIF
616mt_defaulttempo:
617                lda #DEFAULTTEMPO               ;Set default tempo
618                sta mt_chntempo,x
619                lda #$01
620                sta mt_chncounter,x             ;Reset counter
621                sta mt_chninstr,x               ;Reset instrument
622                jmp mt_loadregswaveonly          ;Load waveform
623
624        ;Filter execution
625
626mt_filtstep:
627              .IF (NOFILTER == 0)
628                ldy #$00                        ;See if filter stopped
629                beq mt_filtdone
630              .IF (NOFILTERMOD == 0)
631mt_filttime:
632                lda #$00                        ;See if time left for mod.
633                bne mt_filtmod                  ;step
634              .ENDIF
635mt_newfiltstep:
636                lda mt_filttimetbl-1,y          ;$80-> = set filt parameters
637                beq mt_setcutoff                ;$00 = set cutoff
638              .IF (NOFILTERMOD == 0)
639                bpl mt_newfiltmod
640              .ENDIF
641mt_setfilt:
642                asl                             ;Set passband
643                sta mt_filttype+1
644                lda mt_filtspdtbl-1,y           ;Set resonance/channel
645                sta mt_filtctrl+1
646                lda mt_filttimetbl,y            ;Check for cutoff setting
647                bne mt_nextfiltstep2            ;following immediately
648mt_setcutoff2:
649                iny
650mt_setcutoff:
651                lda mt_filtspdtbl-1,y           ;Take cutoff value
652                sta mt_filtcutoff+1
653              .IF (NOFILTERMOD == 0)
654                jmp mt_nextfiltstep
655mt_newfiltmod:
656                sta mt_filttime+1               ;$01-$7f = new modulation step
657mt_filtmod:
658                lda mt_filtspdtbl-1,y           ;Take filt speed
659                clc
660                adc mt_filtcutoff+1
661                sta mt_filtcutoff+1
662                dec mt_filttime+1
663                bne mt_storecutoff
664              .ENDIF
665mt_nextfiltstep:
666                lda mt_filttimetbl,y           ;Jump in filttable?
667mt_nextfiltstep2:
668                cmp #LOOPFILT
669                iny
670                tya
671                bcc mt_nofiltjump
672                lda mt_filtspdtbl-1,y          ;Take jump point
673mt_nofiltjump:
674                sta mt_filtstep+1
675mt_filtdone:
676mt_filtcutoff:
677                lda #$00
678mt_storecutoff:
679              .IF (GHOSTREGS == 0)
680                sta SIDBASE+$16
681              .ELSE
682                sta <ghostfiltcutoff
683              .ENDIF
684              .ENDIF
685mt_filtctrl:
686                lda #$00
687              .IF (GHOSTREGS == 0)
688                sta SIDBASE+$17
689              .ELSE
690                sta <ghostfiltctrl
691              .ENDIF
692mt_filttype:
693                lda #$00
694mt_masterfader:
695                ora #$0f                        ;Master volume fader
696              .IF (GHOSTREGS == 0)
697                sta SIDBASE+$18
698              .ELSE
699                sta <ghostfilttype
700              .ENDIF
701
702              .IF (NUMCHANNELS == 3)
703                jsr mt_execchn
704                ldx #$07
705                jsr mt_execchn
706                ldx #$0e
707              .ENDIF
708              .IF (NUMCHANNELS == 2)
709                jsr mt_execchn
710                ldx #$07
711              .ENDIF
712
713        ;Channel execution
714
715mt_execchn:
716                dec mt_chncounter,x               ;See if tick 0
717                beq mt_tick0
718
719        ;Ticks 1-n
720
721mt_notick0:
722                bpl mt_effects
723                lda mt_chntempo,x               ;Reload tempo if negative
724
725              .IF (NOFUNKTEMPO == 0)
726                cmp #$02
727                bcs mt_nofunktempo              ;Funktempo: bounce between
728                tay                             ;funktable indexes 0,1
729                eor #$01
730                sta mt_chntempo,x
731                lda mt_funktempotbl,y
732                sbc #$00
733              .ENDIF
734
735mt_nofunktempo:
736                sta mt_chncounter,x
737mt_effects:
738                jmp mt_waveexec
739
740        ;Sequencer repeat
741
742mt_repeat:
743              .IF (NOREPEAT == 0)
744                sbc #REPEAT
745                inc mt_chnrepeat,x
746                cmp mt_chnrepeat,x
747                bne mt_nonewpatt
748mt_repeatdone:
749                lda #$00
750                sta mt_chnrepeat,x
751                beq mt_repeatdone2
752              .ENDIF
753
754        ;Tick 0
755
756mt_tick0:
757              .IF (NOEFFECTS == 0)
758                ldy mt_chnnewfx,y               ;Setup tick 0 FX jumps
759                lda mt_tick0jumptbl,y
760                sta mt_tick0jump1+1
761                sta mt_tick0jump2+1
762              .ENDIF
763
764        ;Sequencer advance
765
766mt_checknewpatt:
767                lda mt_chnpattptr,x             ;Fetch next pattern?
768                bne mt_nonewpatt
769mt_sequencer:
770                ldy mt_chnsongnum,y
771                lda mt_songtbllo,y              ;Get address of sequence
772                sta <mt_temp1
773                lda mt_songtblhi,y
774                sta <mt_temp2
775                ldy mt_chnsongptr,y
776                lda (mt_temp1),y                ;Get pattern from sequence
777                cmp #LOOPSONG                   ;Check for loop
778                bcc mt_noloop
779                iny
780                lda (mt_temp1),y
781                tay
782                lda (mt_temp1),y
783mt_noloop:
784              .IF (NOTRANS == 0)
785                cmp #TRANSDOWN                  ;Check for transpose
786                bcc mt_notrans
787                sbc #TRANS
788                sta mt_chntrans,x
789                iny
790                lda (mt_temp1),y
791              .ENDIF
792mt_notrans:
793              .IF (NOREPEAT == 0)
794                cmp #REPEAT                     ;Check for repeat
795                bcs mt_repeat
796              .ENDIF
797                sta mt_chnpattnum,x             ;Store pattern number
798mt_repeatdone2:
799                iny
800                tya
801                sta mt_chnsongptr,x             ;Store songposition
802
803        ;New note start
804
805mt_nonewpatt:
806                ldy mt_chninstr,y
807              .IF (FIXEDPARAMS == 0)
808                lda mt_insgatetimer-1,y
809                sta mt_chngatetimer,x
810              .ENDIF
811                lda mt_chnnewnote,x             ;Test new note init flag
812                beq mt_nonewnoteinit
813mt_newnoteinit:
814                sec
815                sbc #NOTE
816                sta mt_chnnote,x
817                lda #$00
818              .IF (NOEFFECTS == 0)
819              .IF ((NOTONEPORTA == 0) || (NOPORTAMENTO == 0) || (NOVIB == 0))
820                sta mt_chnfx,x                  ;Reset effect
821              .ENDIF
822              .ENDIF
823                sta mt_chnnewnote,x             ;Reset newnote action
824              .IF (NOINSTRVIB == 0)
825                lda mt_insvibdelay-1,y          ;Load instrument vibrato
826                sta mt_chnvibdelay,x
827              .IF (NOEFFECTS == 0)
828                lda mt_insvibparam-1,y
829                sta mt_chnparam,x
830              .ENDIF
831              .ENDIF
832              .IF (NOTONEPORTA == 0)
833                lda mt_chnnewfx,x               ;If toneportamento, skip
834                cmp #TONEPORTA                  ;most of note init
835                beq mt_nonewnoteinit
836              .ENDIF
837
838              .IF (FIXEDPARAMS == 0)
839                lda mt_insfirstwave-1,y         ;Load first frame waveform
840              .IF (NOFIRSTWAVECMD == 0)
841                beq mt_skipwave
842                cmp #$fe
843                bcs mt_skipwave2                ;Skip waveform but load gate
844              .ENDIF
845              .ELSE
846                lda #FIRSTWAVEPARAM
847              .ENDIF
848                sta mt_chnwave,x
849              .IF ((NUMLEGATOINSTR > 0) || (NOFIRSTWAVECMD == 0))
850                lda #$ff
851mt_skipwave2:
852                sta mt_chngate,x                ;Reset gateflag
853              .ELSE
854                inc mt_chngate,x
855              .ENDIF
856mt_skipwave:
857
858              .IF (NOPULSE == 0)
859                lda mt_inspulseptr-1,y          ;Load pulseptr (if nonzero)
860                beq mt_skippulse
861                sta mt_chnpulseptr,x
862              .IF (NOPULSEMOD == 0)
863                lda #$00                        ;Reset pulse step duration
864                sta mt_chnpulsetime,x
865              .ENDIF
866              .ENDIF
867mt_skippulse:
868              .IF (NOFILTER == 0)
869                lda mt_insfiltptr-1,y           ;Load filtptr (if nonzero)
870                beq mt_skipfilt
871                sta mt_filtstep+1
872              .IF (NOFILTERMOD == 0)
873                lda #$00
874                sta mt_filttime+1
875              .ENDIF
876              .ENDIF
877mt_skipfilt:
878
879                lda mt_inswaveptr-1,y           ;Load waveptr
880                sta mt_chnwaveptr,x
881
882                lda mt_inssr-1,y                ;Load Sustain/Release
883              .IF (BUFFEREDWRITES == 0)
884                sta SIDBASE+$06,x
885              .ELSE
886              .IF (GHOSTREGS == 0)
887                sta mt_chnsr,x
888              .ELSE
889                sta <ghostsr,x
890              .ENDIF
891              .ENDIF
892                lda mt_insad-1,y                ;Load Attack/Decay
893              .IF (BUFFEREDWRITES == 0)
894                sta SIDBASE+$05,x
895              .ELSE
896              .IF (GHOSTREGS == 0)
897                sta mt_chnad,x
898              .ELSE
899                sta <ghostad,x
900              .ENDIF
901              .ENDIF
902
903              .IF (NOEFFECTS == 0)
904                lda mt_chnnewparam,x            ;Execute tick 0 FX after
905mt_tick0jump1:                                  ;newnote init
906                jsr mt_tick0_0
907              .ENDIF
908              .IF (BUFFEREDWRITES == 0)
909                jmp mt_loadregswaveonly
910              .ELSE
911                jmp mt_loadregs
912              .ENDIF
913
914              .IF (NOWAVECMD == 0)
915mt_wavecmd:
916                jmp mt_execwavecmd
917              .ENDIF
918
919        ;Tick 0 effect execution
920
921mt_nonewnoteinit:
922              .IF (NOEFFECTS == 0)
923                lda mt_chnnewparam,x            ;No new note init: exec tick 0
924mt_tick0jump2:
925                jsr mt_tick0_0                  ;FX, and wavetable afterwards
926              .ENDIF
927
928        ;Wavetable execution
929
930mt_waveexec:
931                ldy mt_chnwaveptr,y
932                beq mt_wavedone
933                lda mt_wavetbl-1,y
934              .IF (NOWAVEDELAY == 0)
935                cmp #$10                        ;0-15 used as delay
936                bcs mt_nowavedelay              ;+ no wave change
937                cmp mt_chnwavetime,x
938                beq mt_nowavechange
939                inc mt_chnwavetime,x
940                bne mt_wavedone
941mt_nowavedelay:
942                sbc #$10
943              .ELSE
944                beq mt_nowavechange
945              .ENDIF
946              .IF (NOWAVECMD == 0)
947                cmp #$e0
948                bcs mt_nowavechange
949              .ENDIF
950                sta mt_chnwave,x
951mt_nowavechange:
952                lda mt_wavetbl,y
953                cmp #LOOPWAVE                  ;Check for wavetable jump
954                iny
955                tya
956                bcc mt_nowavejump
957              .IF (NOWAVECMD != 0)
958                clc
959              .ENDIF
960                lda mt_notetbl-1,y
961mt_nowavejump:
962                sta mt_chnwaveptr,x
963              .IF (NOWAVEDELAY == 0)
964                lda #$00
965                sta mt_chnwavetime,x
966              .ENDIF
967
968              .IF (NOWAVECMD == 0)
969                lda mt_wavetbl-2,y
970                cmp #$e0
971                bcs mt_wavecmd
972              .ENDIF
973
974                lda mt_notetbl-2,y
975
976              .IF ((NOTONEPORTA == 0) || (NOPORTAMENTO == 0) || (NOVIB == 0))
977                bne mt_wavefreq                 ;No frequency-change?
978
979        ;No frequency-change / continuous effect execution
980
981mt_wavedone:
982              .IF (REALTIMEOPTIMIZATION != 0)
983                lda mt_chncounter,x             ;No continuous effects on tick0
984              .IF (PULSEOPTIMIZATION != 0)
985                beq mt_gatetimer
986              .ELSE
987                beq mt_done
988              .ENDIF
989              .ENDIF
990              .IF (NOEFFECTS == 0)
991                ldy mt_chnfx,y
992              .IF (NOWAVECMD == 0)
993              .IF (.DEFINED(mt_effectnum))
994                sty mt_effectnum+1
995              .ENDIF
996              .ENDIF
997                lda mt_effectjumptbl,y
998                sta mt_effectjump+1
999                ldy mt_chnparam,y
1000              .ELSE
1001                ldy mt_chninstr,y
1002                lda mt_insvibparam-1,y
1003                tay
1004              .ENDIF
1005mt_setspeedparam:
1006              .IF (NOCALCULATEDSPEED != 0)
1007                lda mt_speedrighttbl-1,y
1008                sta <mt_temp1
1009              .ELSE
1010              .IF (NONORMALSPEED == 0)
1011                lda mt_speedlefttbl-1,y
1012                bmi mt_calculatedspeed
1013mt_normalspeed:
1014                sta <mt_temp2
1015                lda mt_speedrighttbl-1,y
1016                sta <mt_temp1
1017                jmp mt_effectjump
1018              .ELSE
1019              .IF (NOZEROSPEED == 0)
1020                bne mt_calculatedspeed
1021mt_zerospeed:
1022                sty <mt_temp1
1023                sty <mt_temp2
1024                beq mt_effectjump
1025              .ENDIF
1026              .ENDIF
1027mt_calculatedspeed:
1028                lda mt_speedrighttbl-1,y
1029                sta mt_cscount+1
1030                sty mt_csresty+1
1031                ldy mt_chnlastnote,y
1032                lda mt_freqtbllo+1-FIRSTNOTE,y
1033                sec
1034                sbc mt_freqtbllo-FIRSTNOTE,y
1035                sta <mt_temp1
1036                lda mt_freqtblhi+1-FIRSTNOTE,y
1037                sbc mt_freqtblhi-FIRSTNOTE,y
1038mt_cscount:     ldy #$00
1039                beq mt_csresty
1040mt_csloop:      lsr
1041                ror <mt_temp1
1042                dey
1043                bne mt_csloop
1044mt_csresty:     ldy #$00
1045                sta <mt_temp2
1046              .ENDIF
1047mt_effectjump:
1048                jmp mt_effect_0
1049              .ELSE
1050                beq mt_wavedone
1051              .ENDIF
1052
1053        ;Setting note frequency
1054
1055mt_wavefreq:
1056                bpl mt_wavenoteabs
1057                adc mt_chnnote,x
1058                and #$7f
1059mt_wavenoteabs:
1060              .IF (NOCALCULATEDSPEED == 0)
1061                sta mt_chnlastnote,x
1062              .ENDIF
1063                tay
1064mt_wavenote:
1065              .IF (NOVIB == 0)
1066                lda #$00                        ;Reset vibrato phase
1067                sta mt_chnvibtime,x
1068              .ENDIF
1069                lda mt_freqtbllo-FIRSTNOTE,y
1070              .IF (GHOSTREGS == 0)
1071                sta mt_chnfreqlo,x
1072                lda mt_freqtblhi-FIRSTNOTE,y
1073mt_storefreqhi:
1074                sta mt_chnfreqhi,x
1075              .ELSE
1076                sta <ghostfreqlo,x
1077                lda mt_freqtblhi-FIRSTNOTE,y
1078mt_storefreqhi:
1079                sta <ghostfreqhi,x
1080              .ENDIF
1081
1082        ;Check for new note fetch
1083
1084              .IF ((NOTONEPORTA != 0) && (NOPORTAMENTO != 0) && (NOVIB != 0))
1085mt_wavedone:
1086              .ENDIF
1087mt_done:
1088              .IF (PULSEOPTIMIZATION != 0)
1089                lda mt_chncounter,x             ;Check for gateoff timer
1090mt_gatetimer:
1091              .IF (FIXEDPARAMS == 0)
1092                cmp mt_chngatetimer,x
1093              .ELSE
1094                cmp #GATETIMERPARAM
1095              .ENDIF
1096
1097                beq mt_getnewnote               ;Fetch new notes if equal
1098              .ENDIF
1099
1100        ;Pulse execution
1101              .IF (NOPULSE == 0)
1102mt_pulseexec:
1103                ldy mt_chnpulseptr,y            ;See if pulse stopped
1104                beq mt_pulseskip
1105              .IF (PULSEOPTIMIZATION != 0)
1106                ora mt_chnpattptr,x             ;Skip when sequencer executed
1107                beq mt_pulseskip
1108              .ENDIF
1109              .IF (NOPULSEMOD == 0)
1110                lda mt_chnpulsetime,x           ;Pulse step counter time left?
1111                bne mt_pulsemod
1112              .ENDIF
1113mt_newpulsestep:
1114                lda mt_pulsetimetbl-1,y         ;Set pulse, or new modulation
1115              .IF (NOPULSEMOD == 0)
1116                bpl mt_newpulsemod              ;step?
1117              .ENDIF
1118mt_setpulse:
1119              .IF (SIMPLEPULSE == 0)
1120              .IF (GHOSTREGS == 0)
1121                sta mt_chnpulsehi,x             ;Highbyte
1122              .ELSE
1123                sta <ghostpulsehi,x
1124              .ENDIF
1125              .ENDIF
1126                lda mt_pulsespdtbl-1,y          ;Lowbyte
1127              .IF (GHOSTREGS == 0)
1128                sta mt_chnpulselo,x
1129              .ELSE
1130                sta <ghostpulselo,x
1131              .IF (SIMPLEPULSE != 0)
1132                sta <ghostpulsehi,x
1133              .ENDIF
1134              .ENDIF
1135              .IF (NOPULSEMOD == 0)
1136                jmp mt_nextpulsestep
1137mt_newpulsemod:
1138                sta mt_chnpulsetime,x
1139mt_pulsemod:
1140              .IF (SIMPLEPULSE == 0)
1141                lda mt_pulsespdtbl-1,y          ;Take pulse speed
1142                clc
1143                bpl mt_pulseup
1144              .IF (GHOSTREGS == 0)
1145                dec mt_chnpulsehi,x
1146mt_pulseup:
1147                adc mt_chnpulselo,x             ;Add pulse lowbyte
1148                sta mt_chnpulselo,x
1149                bcc mt_pulsenotover
1150                inc mt_chnpulsehi,x
1151              .ELSE
1152                dec <ghostpulsehi,x
1153mt_pulseup:
1154                adc <ghostpulselo,x             ;Add pulse lowbyte
1155                sta <ghostpulselo,x
1156                bcc mt_pulsenotover
1157                inc <ghostpulsehi,x
1158              .ENDIF
1159mt_pulsenotover:
1160              .ELSE
1161              .IF (GHOSTREGS == 0)
1162                lda mt_chnpulselo,x
1163                clc
1164                adc mt_pulsespdtbl-1,y
1165                adc #$00
1166                sta mt_chnpulselo,x
1167              .ELSE
1168                lda <ghostpulselo,x
1169                clc
1170                adc mt_pulsespdtbl-1,y
1171                adc #$00
1172                sta <ghostpulselo,x
1173                sta <ghostpulsehi,x
1174              .ENDIF
1175              .ENDIF
1176                dec mt_chnpulsetime,x
1177                bne mt_pulsedone2
1178              .ENDIF
1179
1180mt_nextpulsestep:
1181                lda mt_pulsetimetbl,y           ;Jump in pulsetable?
1182                cmp #LOOPPULSE
1183                iny
1184                tya
1185                bcc mt_nopulsejump
1186                lda mt_pulsespdtbl-1,y          ;Take jump point
1187mt_nopulsejump:
1188                sta mt_chnpulseptr,x
1189mt_pulsedone:
1190              .IF (BUFFEREDWRITES == 0)
1191                lda mt_chnpulselo,x
1192              .ENDIF
1193mt_pulsedone2:
1194              .IF (BUFFEREDWRITES == 0)
1195                sta SIDBASE+$02,x
1196              .IF (SIMPLEPULSE == 0)
1197                lda mt_chnpulsehi,x
1198              .ENDIF
1199                sta SIDBASE+$03,x
1200              .ENDIF
1201mt_pulseskip:
1202              .ENDIF
1203
1204              .IF (PULSEOPTIMIZATION == 0)
1205                lda mt_chncounter,x             ;Check for gateoff timer
1206mt_gatetimer:
1207              .IF (FIXEDPARAMS == 0)
1208                cmp mt_chngatetimer,x
1209              .ELSE
1210                cmp #GATETIMERPARAM
1211              .ENDIF
1212
1213                beq mt_getnewnote               ;Fetch new notes if equal
1214              .ENDIF
1215
1216                jmp mt_loadregs
1217
1218        ;New note fetch
1219
1220mt_getnewnote:
1221                ldy mt_chnpattnum,y
1222                lda mt_patttbllo,y
1223                sta <mt_temp1
1224                lda mt_patttblhi,y
1225                sta <mt_temp2
1226                ldy mt_chnpattptr,y
1227                lda (mt_temp1),y
1228                cmp #FX
1229                bcc mt_instr                    ;Instr. change
1230              .IF (NOEFFECTS == 0)
1231                cmp #NOTE
1232                bcc mt_fx                       ;FX
1233              .ENDIF
1234                cmp #FIRSTPACKEDREST
1235                bcc mt_note                     ;Note only
1236
1237        ;Packed rest handling
1238
1239mt_packedrest:
1240                lda mt_chnpackedrest,x
1241                bne mt_packedrestnonew
1242                lda (mt_temp1),y
1243mt_packedrestnonew:
1244                adc #$00
1245                sta mt_chnpackedrest,x
1246                beq mt_rest
1247                bne mt_loadregs
1248
1249        ;Instrument change
1250
1251mt_instr:
1252                sta mt_chninstr,x               ;Instrument change, followed
1253                iny
1254                lda (mt_temp1),y                ;by either FX or note
1255
1256              .IF (NOEFFECTS == 0)
1257                cmp #NOTE
1258                bcs mt_note
1259
1260        ;Effect change
1261
1262mt_fx:
1263                cmp #FXONLY                     ;Note follows?
1264                and #$0f
1265                sta mt_chnnewfx,x
1266                beq mt_fx_noparam               ;Effect 0 - no param.
1267                iny
1268                lda (mt_temp1),y
1269                sta mt_chnnewparam,x
1270mt_fx_noparam:
1271                bcs mt_rest
1272mt_fx_getnote:
1273                iny
1274                lda (mt_temp1),y
1275              .ENDIF
1276
1277        ;Note handling
1278
1279mt_note:
1280                cmp #REST                   ;Rest or gateoff/on?
1281              .IF (NOGATE == 0)
1282                bcc mt_normalnote
1283              .ENDIF
1284                beq mt_rest
1285mt_gate:
1286              .IF (NOGATE == 0)
1287                ora #$f0
1288                bne mt_setgate
1289              .ENDIF
1290
1291        ;Prepare for note start; perform hardrestart
1292
1293mt_normalnote:
1294              .IF (NOTRANS == 0)
1295                adc mt_chntrans,x
1296              .ENDIF
1297                sta mt_chnnewnote,x
1298              .IF (NOTONEPORTA == 0)
1299                lda mt_chnnewfx,x           ;If toneportamento, no gateoff
1300                cmp #TONEPORTA
1301                beq mt_rest
1302              .ENDIF
1303              .IF (((NUMHRINSTR > 0) && (NUMNOHRINSTR > 0)) || (NUMLEGATOINSTR > 0))
1304                lda mt_chninstr,x
1305                cmp #FIRSTNOHRINSTR         ;Instrument order:
1306              .IF (NUMLEGATOINSTR > 0)
1307                bcs mt_nohr_legato          ;With HR - no HR - legato
1308              .ELSE
1309                bcs mt_skiphr
1310              .ENDIF
1311              .ENDIF
1312              .IF (NUMHRINSTR > 0)
1313                lda #SRPARAM                ;Hard restart
1314              .IF (BUFFEREDWRITES == 0)
1315                sta SIDBASE+$06,x
1316              .ELSE
1317              .IF (GHOSTREGS == 0)
1318                sta mt_chnsr,x
1319              .ELSE
1320                sta <ghostsr,x
1321              .ENDIF
1322              .ENDIF
1323                lda #ADPARAM
1324              .IF (BUFFEREDWRITES == 0)
1325                sta SIDBASE+$05,x
1326              .ELSE
1327              .IF (GHOSTREGS == 0)
1328                sta mt_chnad,x
1329              .ELSE
1330                sta <ghostad,x
1331              .ENDIF
1332              .ENDIF
1333
1334              .ENDIF
1335mt_skiphr:
1336                lda #$fe
1337mt_setgate:
1338                sta mt_chngate,x
1339
1340        ;Check for end of pattern
1341
1342mt_rest:
1343                iny
1344                lda (mt_temp1),y
1345                beq mt_endpatt
1346                tya
1347mt_endpatt:
1348                sta mt_chnpattptr,x
1349
1350        ;Load voice registers
1351
1352mt_loadregs:
1353              .IF (BUFFEREDWRITES == 0)
1354                lda mt_chnfreqlo,x
1355                sta SIDBASE+$00,x
1356                lda mt_chnfreqhi,x
1357                sta SIDBASE+$01,x
1358mt_loadregswaveonly:
1359                lda mt_chnwave,x
1360                and mt_chngate,x
1361                sta SIDBASE+$04,x
1362              .ELSE
1363              .IF (SOUNDSUPPORT != 0)
1364                ldy mt_chnsfx,y
1365                bne mt_sfxexec
1366              .ENDIF
1367              .IF (GHOSTREGS == 0)
1368                lda mt_chnad,x
1369                sta SIDBASE+$05,x
1370                lda mt_chnsr,x
1371                sta SIDBASE+$06,x
1372                lda mt_chnpulselo,x
1373              .IF (SIMPLEPULSE == 0)
1374                sta SIDBASE+$02,x
1375                lda mt_chnpulsehi,x
1376                sta SIDBASE+$03,x
1377              .ELSE
1378                sta SIDBASE+$02,x
1379                sta SIDBASE+$03,x
1380              .ENDIF
1381mt_loadregswavefreq:
1382                lda mt_chnfreqlo,x
1383                sta SIDBASE+$00,x
1384                lda mt_chnfreqhi,x
1385                sta SIDBASE+$01,x
1386mt_loadregswaveonly:
1387                lda mt_chnwave,x
1388                and mt_chngate,x
1389                sta SIDBASE+$04,x
1390              .ELSE
1391mt_loadregswaveonly:
1392                lda mt_chnwave,x
1393                and mt_chngate,x
1394                sta <ghostwave,x
1395              .ENDIF
1396              .ENDIF
1397                rts
1398
1399              .IF (NUMLEGATOINSTR > 0)
1400mt_nohr_legato:
1401                cmp #FIRSTLEGATOINSTR
1402                bcc mt_skiphr
1403                bcs mt_rest
1404              .ENDIF
1405
1406        ;Sound FX code
1407
1408              .IF (SOUNDSUPPORT != 0)
1409              .IF (GHOSTREGS == 0)
1410
1411        ;Sound FX code without ghostregs
1412
1413mt_sfxexec:     lda mt_chnsfxlo,x
1414                sta <mt_temp1
1415                lda mt_chnsfxhi,x
1416                sta <mt_temp2
1417                lda #$fe
1418                sta mt_chngate,x
1419                lda #$00
1420                sta mt_chnwaveptr,x
1421                inc mt_chnsfx,x
1422                cpy #$02
1423                beq mt_sfxexec_frame0
1424                bcs mt_sfxexec_framen
1425                sta SIDBASE+$06,x                ;Hardrestart before sound FX
1426                sta SIDBASE+$05,x                ;begins
1427                bcc mt_loadregswavefreq
1428mt_sfxexec_frame0:
1429                tay
1430                lda (mt_temp1),y           ;Load ADSR
1431                sta SIDBASE+$05,x
1432                iny
1433                lda (mt_temp1),y
1434                sta SIDBASE+$06,x
1435                iny
1436                lda (mt_temp1),y           ;Load pulse
1437                sta SIDBASE+$02,x
1438                sta SIDBASE+$03,x
1439                lda #$09                   ;Testbit
1440mt_sfxexec_wavechg:
1441                sta mt_chnwave,x
1442                sta SIDBASE+$04,x
1443mt_sfxexec_done:
1444                rts
1445mt_sfxexec_framen:
1446                lda (mt_temp1),y
1447                bne mt_sfxexec_noend
1448mt_sfxexec_end:
1449                sta mt_chnsfx,x
1450                beq mt_sfxexec_wavechg
1451mt_sfxexec_noend:
1452                tay
1453                lda mt_freqtbllo-$80,y        ;Get frequency
1454                sta SIDBASE+$00,x
1455                lda mt_freqtblhi-$80,y
1456                sta SIDBASE+$01,x
1457                ldy mt_chnsfx,y
1458                lda (mt_temp1),y              ;Then take a look at the next
1459                beq mt_sfxexec_done           ;byte
1460                cmp #$82                      ;Is it a waveform or a note?
1461                bcs mt_sfxexec_done
1462                inc mt_chnsfx,x
1463                bcc mt_sfxexec_wavechg
1464
1465              .ELSE
1466
1467        ;Sound FX code with ghostregs
1468
1469mt_sfxexec:
1470                lda mt_chnsfxlo,x
1471                sta <mt_temp1
1472                lda mt_chnsfxhi,x
1473                sta <mt_temp2
1474                lda #$fe
1475                sta mt_chngate,x
1476                lda #$00
1477                sta mt_chnwaveptr,x
1478                inc mt_chnsfx,x
1479                cpy #$02
1480                bcc mt_sfxexec_fr1                  ;Hardrestart frame?
1481                beq mt_sfxexec_fr2                  ;First or nth frame?
1482mt_sfxexec_fr3:
1483                lda (mt_temp1),y
1484                bne mt_sfxexec_noend
1485mt_sfxexec_end:
1486                sta mt_chnsfx,x
1487                beq mt_sfxexec_wavechg
1488mt_sfxexec_noend:
1489                tay
1490                lda mt_freqtbllo-$80,y        ;Get frequency
1491                sta <ghostfreqlo,x
1492                lda mt_freqtblhi-$80,y
1493                sta <ghostfreqhi,x
1494                ldy mt_chnsfx,y
1495                lda (mt_temp1),y              ;Then take a look at the next
1496                beq mt_sfxexec_done           ;byte
1497                cmp #$82                      ;Is it a waveform or a note?
1498                bcs mt_sfxexec_done
1499                inc mt_chnsfx,x
1500mt_sfxexec_wavechg:
1501                sta mt_chnwave,x
1502                sta <ghostwave,x
1503mt_sfxexec_done:
1504                ldy #$00
1505                lda (mt_temp1),y             ;Load ADSR
1506                sta <ghostad,x
1507                iny
1508                lda (mt_temp1),y
1509                sta <ghostsr,x
1510                iny
1511                lda (mt_temp1),y             ;Load pulse
1512                sta <ghostpulselo,x
1513                sta <ghostpulsehi,x
1514                rts
1515
1516mt_sfxexec_fr1:
1517                sta <ghostad,x               ;Hardrestart before sound FX
1518                sta <ghostsr,x               ;begins
1519                bcc mt_loadregswaveonly
1520
1521mt_sfxexec_fr2:
1522                lda #$09
1523                bne mt_sfxexec_wavechg
1524
1525              .ENDIF
1526              .ENDIF
1527
1528        ;Wavetable command exec
1529
1530              .IF (NOWAVECMD == 0)
1531mt_execwavecmd:
1532                and #$0f
1533                sta <mt_temp1
1534                lda mt_notetbl-2,y
1535                sta <mt_temp2
1536                ldy <mt_temp1
1537              .IF ((NOTONEPORTA == 0) || (NOPORTAMENTO == 0) || (NOVIB == 0))
1538                cpy #$05
1539                bcs mt_execwavetick0
1540mt_execwavetickn:
1541              .IF (.DEFINED(mt_effectnum))
1542                sty mt_effectnum+1
1543              .ENDIF
1544                lda mt_effectjumptbl,y
1545                sta mt_effectjump+1
1546                ldy <mt_temp2
1547                jmp mt_setspeedparam
1548              .ENDIF
1549mt_execwavetick0:
1550                lda mt_tick0jumptbl,y
1551                sta mt_execwavetick0jump+1
1552                lda <mt_temp2
1553mt_execwavetick0jump:
1554                jsr mt_tick0_0
1555                jmp mt_done
1556              .ENDIF
1557
1558              .IF (NOEFFECTS == 0)
1559              .IF (!.DEFINED(mt_tick0jumptbl))
1560mt_tick0jumptbl:
1561                .BYTE (mt_tick0_0 % 256)
1562                .BYTE (mt_tick0_12 % 256)
1563                .BYTE (mt_tick0_12 % 256)
1564                .BYTE (mt_tick0_34 % 256)
1565                .BYTE (mt_tick0_34 % 256)
1566                .BYTE (mt_tick0_5 % 256)
1567                .BYTE (mt_tick0_6 % 256)
1568                .BYTE (mt_tick0_7 % 256)
1569                .BYTE (mt_tick0_8 % 256)
1570                .BYTE (mt_tick0_9 % 256)
1571                .BYTE (mt_tick0_a % 256)
1572                .BYTE (mt_tick0_b % 256)
1573                .BYTE (mt_tick0_c % 256)
1574                .BYTE (mt_tick0_d % 256)
1575                .BYTE (mt_tick0_e % 256)
1576                .BYTE (mt_tick0_f % 256)
1577              .ENDIF
1578              .ENDIF
1579
1580              .IF (NOEFFECTS == 0)
1581              .IF (!.DEFINED(mt_effectjumptbl))
1582              .IF ((NOTONEPORTA == 0) || (NOPORTAMENTO == 0) || (NOVIB == 0))
1583mt_effectjumptbl:
1584                .BYTE (mt_effect_0 % 256)
1585                .BYTE (mt_effect_12 % 256)
1586                .BYTE (mt_effect_12 % 256)
1587                .BYTE (mt_effect_3 % 256)
1588                .BYTE (mt_effect_4 % 256)
1589              .ENDIF
1590              .ENDIF
1591              .ENDIF
1592
1593              .IF (!.DEFINED(mt_funktempotbl))
1594              .IF (NOFUNKTEMPO == 0)
1595mt_funktempotbl:
1596                .BYTE (8,5)
1597              .ENDIF
1598              .ENDIF
1599
1600              .IF ((NOEFFECTS == 0) || (NOWAVEDELAY == 0) || (NOTRANS == 0) || (NOREPEAT == 0) || (FIXEDPARAMS == 0) || (GHOSTREGS != 0) || (BUFFEREDWRITES != 0) || (NOCALCULATEDSPEED == 0))
1601
1602              ;Normal channel variables
1603
1604mt_chnsongptr:
1605                .BYTE (0)
1606mt_chntrans:
1607                .BYTE (0)
1608mt_chnrepeat:
1609                .BYTE (0)
1610mt_chnpattptr:
1611                .BYTE (0)
1612mt_chnpackedrest:
1613                .BYTE (0)
1614mt_chnnewfx:
1615                .BYTE (0)
1616mt_chnnewparam:
1617                .BYTE (0)
1618
1619              .IF (NUMCHANNELS > 1)
1620                .BYTE (0,0,0,0,0,0,0)
1621              .ENDIF
1622              .IF (NUMCHANNELS > 2)
1623                .BYTE (0,0,0,0,0,0,0)
1624              .ENDIF
1625
1626mt_chnfx:
1627                .BYTE (0)
1628mt_chnparam:
1629                .BYTE (0)
1630mt_chnnewnote:
1631                .BYTE (0)
1632mt_chnwaveptr:
1633                .BYTE (0)
1634mt_chnwave:
1635                .BYTE (0)
1636mt_chnpulseptr:
1637                .BYTE (0)
1638mt_chnpulsetime:
1639                .BYTE (0)
1640
1641              .IF (NUMCHANNELS > 1)
1642                .BYTE (0,0,0,0,0,0,0)
1643              .ENDIF
1644              .IF (NUMCHANNELS > 2)
1645                .BYTE (0,0,0,0,0,0,0)
1646              .ENDIF
1647
1648mt_chnsongnum:
1649                .BYTE (0)
1650mt_chnpattnum:
1651                .BYTE (0)
1652mt_chntempo:
1653                .BYTE (0)
1654mt_chncounter:
1655                .BYTE (0)
1656mt_chnnote:
1657                .BYTE (0)
1658mt_chninstr:
1659                .BYTE (1)
1660mt_chngate:
1661                .BYTE ($fe)
1662
1663              .IF (NUMCHANNELS > 1)
1664                .BYTE (1,0,0,0,0,1,$fe)
1665              .ENDIF
1666              .IF (NUMCHANNELS > 2)
1667                .BYTE (2,0,0,0,0,1,$fe)
1668              .ENDIF
1669
1670              .IF ((GHOSTREGS == 0) || (NOCALCULATEDSPEED == 0))
1671
1672mt_chnvibtime:
1673                .BYTE (0)
1674mt_chnvibdelay:
1675                .BYTE (0)
1676mt_chnwavetime:
1677                .BYTE (0)
1678mt_chnfreqlo:
1679                .BYTE (0)
1680mt_chnfreqhi:
1681                .BYTE (0)
1682mt_chnpulselo:
1683                .BYTE (0)
1684mt_chnpulsehi:
1685                .BYTE (0)
1686
1687              .IF (NUMCHANNELS > 1)
1688                .BYTE (0,0,0,0,0,0,0)
1689              .ENDIF
1690              .IF (NUMCHANNELS > 2)
1691                .BYTE (0,0,0,0,0,0,0)
1692              .ENDIF
1693
1694              .IF ((BUFFEREDWRITES != 0) || (FIXEDPARAMS == 0) || (NOCALCULATEDSPEED == 0))
1695mt_chnad:
1696                .BYTE (0)
1697mt_chnsr:
1698                .BYTE (0)
1699mt_chnsfx:
1700                .BYTE (0)
1701mt_chnsfxlo:
1702                .BYTE (0)
1703mt_chnsfxhi:
1704                .BYTE (0)
1705mt_chngatetimer:
1706                .BYTE (0)
1707mt_chnlastnote:
1708                .BYTE (0)
1709
1710              .IF (NUMCHANNELS > 1)
1711                .BYTE (0,0,0,0,0,0,0)
1712              .ENDIF
1713              .IF (NUMCHANNELS > 2)
1714                .BYTE (0,0,0,0,0,0,0)
1715              .ENDIF
1716
1717              .ENDIF
1718
1719              .ELSE
1720
1721mt_chnvibtime:
1722                .BYTE (0)
1723mt_chnvibdelay:
1724                .BYTE (0)
1725mt_chnwavetime:
1726                .BYTE (0)
1727mt_chnsfx:
1728                .BYTE (0)
1729mt_chnsfxlo:
1730                .BYTE (0)
1731mt_chnsfxhi:
1732                .BYTE (0)
1733mt_chngatetimer:
1734                .BYTE (0)
1735
1736              .IF (NUMCHANNELS > 1)
1737                .BYTE (0,0,0,0,0,0,0)
1738              .ENDIF
1739              .IF (NUMCHANNELS > 2)
1740                .BYTE (0,0,0,0,0,0,0)
1741              .ENDIF
1742
1743              .ENDIF
1744
1745              .ELSE
1746
1747              ;Optimized channel variables
1748
1749mt_chnsongptr:
1750                .BYTE (0)
1751mt_chnpattptr:
1752                .BYTE (0)
1753mt_chnpackedrest:
1754                .BYTE (0)
1755mt_chnnewnote:
1756                .BYTE (0)
1757mt_chnwaveptr:
1758                .BYTE (0)
1759mt_chnwave:
1760                .BYTE (0)
1761mt_chnpulseptr:
1762                .BYTE (0)
1763
1764              .IF (NUMCHANNELS > 1)
1765                .BYTE (0,0,0,0,0,0,0)
1766              .ENDIF
1767              .IF (NUMCHANNELS > 2)
1768                .BYTE (0,0,0,0,0,0,0)
1769              .ENDIF
1770
1771mt_chnpulsetime:
1772                .BYTE (0)
1773mt_chnpulselo:
1774                .BYTE (0)
1775mt_chnpulsehi:
1776                .BYTE (0)
1777mt_chnvibtime:
1778                .BYTE (0)
1779mt_chnvibdelay:
1780                .BYTE (0)
1781mt_chnfreqlo:
1782                .BYTE (0)
1783mt_chnfreqhi:
1784                .BYTE (0)
1785
1786              .IF (NUMCHANNELS > 1)
1787                .BYTE (0,0,0,0,0,0,0)
1788              .ENDIF
1789              .IF (NUMCHANNELS > 2)
1790                .BYTE (0,0,0,0,0,0,0)
1791              .ENDIF
1792
1793mt_chnsongnum:
1794                .BYTE (0)
1795mt_chnpattnum:
1796                .BYTE (0)
1797mt_chntempo:
1798                .BYTE (0)
1799mt_chncounter:
1800                .BYTE (0)
1801mt_chnnote:
1802                .BYTE (0)
1803mt_chninstr:
1804                .BYTE (1)
1805mt_chngate:
1806                .BYTE ($fe)
1807
1808              .IF (NUMCHANNELS > 1)
1809                .BYTE (1,0,0,0,0,1,$fe)
1810              .ENDIF
1811              .IF (NUMCHANNELS > 2)
1812                .BYTE (2,0,0,0,0,1,$fe)
1813              .ENDIF
1814
1815              .ENDIF
1816
1817              .IF ((GHOSTREGS != 0) && (ZPGHOSTREGS == 0))
1818ghostregs:    .BYTE (0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0)
1819ghostfreqlo     = ghostregs+0
1820ghostfreqhi     = ghostregs+1
1821ghostpulselo    = ghostregs+2
1822ghostpulsehi    = ghostregs+3
1823ghostwave       = ghostregs+4
1824ghostad         = ghostregs+5
1825ghostsr         = ghostregs+6
1826ghostfiltcutlow = ghostregs+21
1827ghostfiltcutoff = ghostregs+22
1828ghostfiltctrl   = ghostregs+23
1829ghostfilttype   = ghostregs+24
1830              .ENDIF
1831
1832        ;Songdata & frequencytable will be inserted by the relocator here
1833
1834