-
Notifications
You must be signed in to change notification settings - Fork 7
/
rmtplayr.a65
2306 lines (2076 loc) · 65.1 KB
/
rmtplayr.a65
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;*
;* Raster Music Tracker, RMT Atari routine version Patch16-3.2
;* (c) Radek Sterba, Raster/C.P.U., 2002 - 2009
;* http://raster.atari.org
;*
;* Unofficial version by VinsCool, 2021 - 2022
;* https://github.com/VinsCool/RMT-Patch16
;*
;* TO DO: A lot... So much to re-order and cleanup...
;* I must recalculate everything, once the full code cleanup and optimisation is done.
;* Currently, all infos are incorrect due to the massive amount of changes I have done into the code.
;* I apologise for the inconvenience, I am doing my best to clean everything to make sense again.
;*
;---------------------------------------------------------------------------------------------------------------------------------------------;
;* RMT FEATures definitions file
icl "rmt_feat.a65"
;* For optimizations of RMT player routine to concrete RMT module only!
;---------------------------------------------------------------------------------------------------------------------------------------------;
;* start of RMT definitions...
IFT FEAT_IS_SIMPLEP
PLAYER equ $3100 ; VUPlayer export driver
ELS
PLAYER equ $3400 ; tracker.obx driver and everything else by default
EIF
IFT STEREOMODE==1
TRACKS equ 8
ELS
TRACKS equ 4
EIF
TABLES equ $B000 ; This may be moved elsewhere if necessary
INSTRPAR equ 12
;* RMT ZeroPage addresses
org 203 ;* org $CB
p_tis
ptrInstrumentTbl org *+2 ; ptr to Instrument table ptrs
ptrTracksTblLo org *+2 ; ptr to low byte of track ptrs
ptrTracksTblHi org *+2 ; ptr to high byte of track ptrs
ptrSongLines org *+2 ; ptr to song data
ns org *+2
nr org *+2
nt org *+2
reg1 org *+1
reg2 org *+1
reg3 org *+1
tmp org *+1
IFT FEAT_COMMAND2
frqaddcmd2 org *+1
EIF
;* possible improvement: setting variables after the RMT driver itself?
;* That would make adjustments easier to manage, if this works as I expect...
IFT TRACKS>4
org PLAYER-$400+$40
ELS
org PLAYER-$400+$e0
EIF
track_variables
trackn_TblLo org *+TRACKS ; low byte of ptrs to each track's data
trackn_TblHi org *+TRACKS ; Hi byte of ptrs to each track's data
trackn_idx org *+TRACKS ; How far into each track
trackn_pause org *+TRACKS ; 1 new note, 0 nothing new
trackn_note org *+TRACKS
trackn_volume org *+TRACKS
trackn_volumeenvelope org *+TRACKS
trackn_command org *+TRACKS
trackn_effectparameter org *+TRACKS
trackn_shiftfrq org *+TRACKS
IFT FEAT_PORTAMENTO
trackn_portafrqc org *+TRACKS
trackn_portafrqa org *+TRACKS
trackn_portaspeed org *+TRACKS
trackn_portaspeeda org *+TRACKS
trackn_portadepth org *+TRACKS
EIF
trackn_instrx2 org *+TRACKS ; New instrument init required (-1 = new new instrument)
trackn_instrdb org *+TRACKS
trackn_instrhb org *+TRACKS
trackn_instridx org *+TRACKS
trackn_instrlen org *+TRACKS
trackn_instrlop org *+TRACKS
trackn_instrreachend org *+TRACKS
trackn_volumeslidedepth org *+TRACKS
trackn_volumeslidevalue org *+TRACKS
IFT FEAT_VOLUMEMIN
trackn_volumemin org *+TRACKS
EIF
FEAT_EFFECTS equ FEAT_EFFECTVIBRATO||FEAT_EFFECTFSHIFT
IFT FEAT_EFFECTS
trackn_effdelay org *+TRACKS
EIF
IFT FEAT_EFFECTVIBRATO
trackn_effvibratoa org *+TRACKS
EIF
IFT FEAT_EFFECTFSHIFT
trackn_effshift org *+TRACKS
EIF
trackn_tabletypespeed org *+TRACKS
IFT FEAT_TABLEMODE
trackn_tablemode org *+TRACKS
EIF
trackn_tablenote org *+TRACKS
trackn_tablea org *+TRACKS
trackn_tableend org *+TRACKS
IFT FEAT_TABLEGO
trackn_tablelop org *+TRACKS
EIF
trackn_tablespeeda org *+TRACKS
IFT FEAT_FILTER
trackn_filter org *+TRACKS ;* POTENTIAL OPTIMISATION: it is NOT necessary to use all tracks... only channel 1 and 2 will use it to offset the other...
EIF
IFT FEAT_FULL_16BIT||FEAT_BASS16 ;* EXPERIMENTAL METHOD: full 16-bit values, Sawtooth and Filter may also benefit from this approach...
trackn_bass16 org *+TRACKS
EIF
IFT FEAT_FULL_16BIT||FEAT_BASS16||FEAT_FULL_SAWTOOTH
g_flag org *+TRACKS
EIF
IFT FEAT_TABLE_MANUAL
trackn_pointertable org *+TRACKS
EIF
IFT FEAT_AUDCTLMANUALSET
trackn_audctl org *+TRACKS
EIF
trackn_audf org *+TRACKS
trackn_audc org *+TRACKS
v_aspeed org *+1
track_endvariables
;* end of RMT definitions...
;---------------------------------------------------------------------------------------------------------------------------------------------;
;* start of RMT data... maybe this could be moved elsewhere, much like the tuning tables?
org PLAYER-$0200 ; I need to improve the label organisation here as well, also do I really need to org there? my memory is hazy, why did even do this...?
IFT FEAT_AUDCTLMANUALSET
AUDCTLBITS ; bits to test for AUDCTL lookup tables
POLY9 dta $80 ; bit 7
CH1_179 dta $40 ; bit 6
CH3_179 dta $20 ; bit 5
JOIN_12 dta $10 ; bit 4
JOIN_34 dta $08 ; bit 3
HPF_CH1 dta $04 ; bit 2
HPF_CH2 dta $02 ; bit 1
CLOCK15 dta $01 ; bit 0
EIF
TABLES_MSB
DISTORTIONS equ *+1
dta >PAGE_DISTORTION_A,$00
dta >PAGE_DISTORTION_2,$20
dta >PAGE_DISTORTION_4,$40
dta >PAGE_DISTORTION_A,$A0
dta >PAGE_DISTORTION_A,$80
dta >PAGE_DISTORTION_A,$A0
dta >PAGE_DISTORTION_C,$C0
dta >PAGE_DISTORTION_E,$C0
IFT FEAT_EFFECTVIBRATO
vibtabbeg
dta 0,vib1-vib0,vib2-vib0,vib3-vib0
vib0 dta 0
vib1 dta 1,-1,-1,1
vib2 dta 1,0,-1,-1,0,1
vib3 dta 1,1,0,-1,-1,-1,-1,0,1,1
vibtabnext
dta vib0-vib0+0
dta vib1-vib0+1,vib1-vib0+2,vib1-vib0+3,vib1-vib0+0
dta vib2-vib0+1,vib2-vib0+2,vib2-vib0+3,vib2-vib0+4,vib2-vib0+5,vib2-vib0+0
dta vib3-vib0+1,vib3-vib0+2,vib3-vib0+3,vib3-vib0+4,vib3-vib0+5,vib3-vib0+6,vib3-vib0+7,vib3-vib0+8,vib3-vib0+9,vib3-vib0+0
EIF
org PLAYER-$0100 ;* it may be possible to reduce this table by half the size it is... this was something I did for the older RMT Patch16 code, so the option is still valuable...
volumetab
dta $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
dta $00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$01,$01,$01,$01,$01,$01
dta $00,$00,$00,$00,$01,$01,$01,$01,$01,$01,$01,$01,$02,$02,$02,$02
dta $00,$00,$00,$01,$01,$01,$01,$01,$02,$02,$02,$02,$02,$03,$03,$03
dta $00,$00,$01,$01,$01,$01,$02,$02,$02,$02,$03,$03,$03,$03,$04,$04
dta $00,$00,$01,$01,$01,$02,$02,$02,$03,$03,$03,$04,$04,$04,$05,$05
dta $00,$00,$01,$01,$02,$02,$02,$03,$03,$04,$04,$04,$05,$05,$06,$06
dta $00,$00,$01,$01,$02,$02,$03,$03,$04,$04,$05,$05,$06,$06,$07,$07
dta $00,$01,$01,$02,$02,$03,$03,$04,$04,$05,$05,$06,$06,$07,$07,$08
dta $00,$01,$01,$02,$02,$03,$04,$04,$05,$05,$06,$07,$07,$08,$08,$09
dta $00,$01,$01,$02,$03,$03,$04,$05,$05,$06,$07,$07,$08,$09,$09,$0A
dta $00,$01,$01,$02,$03,$04,$04,$05,$06,$07,$07,$08,$09,$0A,$0A,$0B
dta $00,$01,$02,$02,$03,$04,$05,$06,$06,$07,$08,$09,$0A,$0A,$0B,$0C
dta $00,$01,$02,$03,$03,$04,$05,$06,$07,$08,$09,$0A,$0A,$0B,$0C,$0D
dta $00,$01,$02,$03,$04,$05,$06,$07,$07,$08,$09,$0A,$0B,$0C,$0D,$0E
dta $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F
;* end of RMT data...
;---------------------------------------------------------------------------------------------------------------------------------------------;
;* start of RMT jump table...
org PLAYER ;* Possible improvement: give proper labels to each JMPs below... to avoid confusion, and also make things easier to map in memory, unless the destination is being JSR'ed directly...
RASTERMUSICTRACKER
jmp rmt_init ;* Must be run first, to clear memory and initialise the player... Once this is done, run rmt_play afterwards, or Set_Pokey if you want to manually time certain things.
jmp rmt_play ;* One play each subroutine call. SetPokey is executed first, then all the play code is ran once, until the RTS. rmt_play could be called multiple times per frame if wanted.
jmp rmt_p3 ;* Similar to rmt_play, but will also skip SetPokey and the instruments/songlines/tracklines initialisation, very useful for playing simple things.
jmp rmt_silence ;* Run this to stop the driver, and reset all POKEY registers to 0. This is also part of rmt_init when it is executed first.
jmp SetPokey ;* Run to copy the contents of the Shadow POKEY registers (v_audctl, v_skctl, trackn_audf,x etc) into the real ones. Will be run first each time rmt_play is called.
IFT FEAT_SFX
jmp rmt_sfx ;* A=note(0,..,60),X=channel(0,..,3 or 0,..,7),Y=instrument*2(0,2,4,..,126)
EIF
;* end of RMT jump table... from here, all the main driver code is being executed, have fun playing around! ;)
;---------------------------------------------------------------------------------------------------------------------------------------------;
;* start of rmt_init code...
; A = Starting song line
; X = low byte of the RMT module
; Y = hi byte of the RMT module
rmt_init
; (ns) -> module data
stx ns
sty ns+1
IFT FEAT_NOSTARTINGSONGLINE==0
pha ; backup the song line into the stack for now... I wonder if I could just use tmp in zeropage instead...
EIF
; Clear the RMT variables
IFT track_endvariables-track_variables>255
; more than 255 bytes in variables memory...
; so clear from the front and 256 bytes from the end |>--->----|
ldy #0
tya
ri_clear_loop
sta track_variables,y
sta track_endvariables-$100,y
iny
bne ri_clear_loop
ELS
; Clear from the back |----<|
ldy #track_endvariables-track_variables ; How many bytes to clear
lda #0
ri_clear_loop
sta track_variables-1,y
dey
bne ri_clear_loop
EIF
; Parse the RMT module data
; Track length: +4
ldy #4
lda (ns),y
sta smc_maxtracklen ; Change the code to store the track length
; Song speed: +5
iny
IFT FEAT_CONSTANTSPEED==0
lda (ns),y
sta smc_speed ; Change the code to store the song speed
EIF
; Instrument speed: +6
IFT FEAT_INSTRSPEED==0
iny
lda (ns),y
sta smc_instrspeed ; Change the code to store the instrument speed
sta smc_silence_instrspeed
ELI FEAT_INSTRSPEED>1
lda #FEAT_INSTRSPEED
sta smc_silence_instrspeed
EIF
; Copy 4 pointers: +8
; -> InstrumentPtrs[] 2 bytes
; -> TracksPtrsLow[] 2 bytes
; -> TracksPtrsHi 2 bytes
; -> SongData 2 bytes
ldy #8
ri_copy_loop
lda (ns),y
sta p_tis-8,y
iny
cpy #8+8 ; loop until y is 16
bne ri_copy_loop
IFT FEAT_NOSTARTINGSONGLINE==0
; Set the starting song line by moving ptrSongLines forward
pla ; Get the saved starting song line
pha
IFT TRACKS>4
; Stereo
; ptrSongLines += song_line * 8
asl @ ; offset * 8
asl @
asl @
clc
adc ptrSongLines ; ptrSongLines += offset * 8 (low) part
sta ptrSongLines
pla ; restore offset, but keep carry bit
php ; store flags on stack (carry bit!)
and #$e0
asl @
rol @
rol @
rol @
ELS
; Mono
; ptrSongLines += song_line * 4
asl @
asl @
clc
adc ptrSongLines
sta ptrSongLines
pla
php
and #$c0
asl @
rol @
rol @
EIF
plp ; restore the carry bit
adc ptrSongLines+1
sta ptrSongLines+1
EIF
jsr GetSongLine ; Setup the first song line
;* end of rmt_init code... rmt_silence will always be executed after the JSR above.
;---------------------------------------------------------------------------------------------------------------------------------------------;
; RMT_SILENCE
; Reset POKEY causes all sound to be stopped
rmt_silence
; Reset POKEY
IFT STEREOMODE>0
lda #0
sta $d208 ; AUDCTL
sta $d218
ldy #3
sty $d20f ; SKCTL
sty $d21f
; Clear AUDFx & AUDCx
ldy #8
silence_loop
sta $d200,y
sta $d210,y
dey
bpl silence_loop
ELS
lda #0
sta $d208
ldy #3
sty $d20f
ldy #8
silence_loop
sta $d200,y
dey
bpl silence_loop
EIF
IFT FEAT_IS_TRACKER ; reset the tables pointers
lda #<frqtabsawtooth_ch1 ; reset the Sawtooth table inversion
sta saw_ch1
lda #<frqtabsawtooth_ch3
sta saw_ch3
lda #$0A ; reset the Distortion 6 16-bit pointer
sta bass16_pointer
lda #3 ; reset the SKCTL state to normal
sta v_skctl
sta v_skctl2
EIF
IFT FEAT_INSTRSPEED==0
lda #$ff
smc_silence_instrspeed equ *-1 ; return instrument speed, does not seem to matter after rmt_init?
ELS
lda #FEAT_INSTRSPEED
EIF
rts
;* end of rmt_silence code...
;---------------------------------------------------------------------------------------------------------------------------------------------;
;* start of mainloop code here... most of it is related to the songlines, tracklines and instruments initialisation...
GetSongLine
ldx #0
stx smc_abeat ; set the pattern row to 0 for the new songline... This could be exploited with an effect command related to premature pattern end, or pattern goto...
gsl_continueProcessing
IFT FEAT_IS_SIMPLEP
IFT EXPORTXEX ; Simple RMT Player hack for colour cycling, change the rasterbar colour every new pattern played
lda loop+1 ; the #RASTERBAR colour defined will be loaded there specifically
add #16 ; offset the value by #$10 for a simple colour shuffle
sta loop+1 ; store back where it was loaded, overwriting the previous value
lda ptrSongLines ; calculate the songline position below, this is done once every new songline
sub MODUL+14 ; TODO: relocate this code elsewhere, so toggling it would be easier
sta v_ord
lda ptrSongLines+1
sbc MODUL+15
lsr @
ror v_ord
lsr @
ror v_ord
IFT TRACKS>4
lsr @
ror v_ord
EIF
EIF
EIF
gsl_nextSongLine
txa ; A = X = Y = 0,1,2,3
tay
lda (ptrSongLines),y ; Get track info from the songline[y]
cmp #$fe ; #$FE = Goto songline, #$FF = Empty track
bcs gsl_GotoOrEmpty ; if A >= $FE --> gsl_GotoOrEmpty
; (A) = Real track #
; Get the ptr to the track data and store it in ptrTracksTblLo
tay
lda (ptrTracksTblLo),y ; trackn_TblLo[x] = ptrTracksTblLo[y]
sta trackn_TblLo,x
lda (ptrTracksTblHi),y ; trackn_TblHi[x] = ptrTracksTblHi[y]
sta trackn_TblHi,x
lda #0
sta trackn_idx,x ; reset the track index to 0 trackn_idx[x] = 0
lda #1
gsl_initTrack
sta trackn_pause,x ; #1 is a new track, #0 is no new track
lda #$80 ; Mark that there is no new instrument
sta trackn_instrx2,x ; #$80 is negative, will BMI when encountered, meaning no new instrument initialisation
inx ; ++x
cpx #TRACKS ; if x < TRACKS --> gsl_nextSongLine
bne gsl_nextSongLine
; Done with data points of a song line, move to the next line
lda ptrSongLines ; ptrSontLines += #TRACKS (4 or 8)
clc
adc #TRACKS
sta ptrSongLines
bcc GetTrackLine
inc ptrSongLines+1
jmp GetTrackLine ; Now progress the notes in a track
gsl_GotoOrEmpty
beq gsl_thisIsAGoto ; branch if equal to #$FE, this is a Goto songline command
lda #0 ; Used to set the instrument to 0, meaning no new track
beq gsl_initTrack ; unconditional
gsl_thisIsAGoto
; Data format: 0xFE, 0x00, low, high bytes of ptr to next song line
ldy #2
lda (ptrSongLines),y ; lo = ptrSongLines[2]
tax
iny
lda (ptrSongLines),y ; hi = ptrSongLinex[3]
sta ptrSongLines+1
stx ptrSongLines ; (ptrSongLines) = ptrSongLines[2,3]
ldx #0
beq gsl_continueProcessing
; Process one line of a track
GetTrackLine
IFT FEAT_CONSTANTSPEED==0
lda #$ff ; This value is changed by the code
smc_speed equ *-1 ; ptr to #$ff location in the code
sta smc_bspeed
EIF
ldx #$ff ;-1 track data index
gtl_loopTracks
inx ; 0,1, .. #TRACKS
dec trackn_pause,x ; --trackn_pause[x]
bne gtl_checkEndOfLoop ; if trackn_pause[x] != 0 --> gtl_checkEndOfLoop
; Setup ptr to track data
lda trackn_TblLo,x ; (ns) = trackn_TblLo/hi[x]
sta ns
lda trackn_TblHi,x
sta ns+1
oo1i
ldy trackn_idx,x ; Y = index into track data
inc trackn_idx,x ; ++trackn_idx[x]
; Get a track data point
; 0 - 60 = Note, instr and volume data
; 61 - Volume only
; 62 = Pause/empty line
; 63 - Speed, go loop or end
lda (ns),y ; reg1 = A = ns[y]
sta reg1
and #$3f ; 0-63
cmp #61 ; 61 = Volume only
beq gtl_ProcessVolumeData
bcs gtl_Is62or63
; Not a command so store the note
sta trackn_note,x ; note[x] = data & 0x3f
; Process the instrument #
iny
lda (ns),y ; instr = (data & 0xfc) >> 1
lsr
and #$3f*2
sta trackn_instrx2,x ; trackn_instrx2[x] = instrument # * 2
gtl_ProcessVolumeData
lda #1
sta trackn_pause,x ; got a note
; Get the volume
ldy trackn_idx,x ; y = track index
inc trackn_idx,x ; move to the next data point in the track
lda (ns),y
lsr
ror reg1
lsr
ror reg1
lda reg1
IFT FEAT_GLOBALVOLUMEFADE
sec
sbc #$00
RMTGLOBALVOLUMEFADE equ *-1
bcs voig
lda #0
voig
EIF
and #$f0
sta trackn_volume,x
gtl_checkEndOfLoop
cpx #TRACKS-1
bne gtl_loopTracks
IFT FEAT_CONSTANTSPEED==0
lda #$ff ; This value is changed by the code
smc_bspeed equ *-1 ; ptr to #$ff location in the code
sta smc_speed
ELS
lda #FEAT_CONSTANTSPEED
EIF
sta v_aspeed
jmp InitOfNewSetInstrumentsOnly
gtl_Is62or63
cmp #63
beq oo63
lda reg1
and #$c0
beq oo62_b
asl @
rol @
rol @
sta trackn_pause,x
jmp gtl_checkEndOfLoop
oo62_b
iny
lda (ns),y
sta trackn_pause,x
inc trackn_idx,x
jmp gtl_checkEndOfLoop
oo63
lda reg1
IFT FEAT_CONSTANTSPEED==0
bmi oo63_1X
iny
lda (ns),y
sta smc_bspeed ; Set the song speed
inc trackn_idx,x
jmp oo1i
oo63_1X
EIF
cmp #255
beq oo63_11
iny
lda (ns),y
sta trackn_idx,x
jmp oo1i
oo63_11
jmp GetSongLine
p2xrmtp3
jmp rmt_p3
p2x0
dex
bmi p2xrmtp3
InitOfNewSetInstrumentsOnly
p2x1
ldy trackn_instrx2,x
bmi p2x0 ; if negative, there is no new instrument to initialise for this channel
;---------------------------------------------------------------------------------------------------------------------------------------------;
;* start of RMT_SFX code...
IFT FEAT_SFX
jsr SetUpInstrumentY2
jmp p2x0
rmt_sfx
sta trackn_note,x
lda #$f0 ;* sfx note volume*16
RMTSFXVOLUME equ *-1 ;* label for sfx note volume parameter overwriting
sta trackn_volume,x
EIF
;* end of RMT_SFX code...
;---------------------------------------------------------------------------------------------------------------------------------------------;
SetUpInstrumentY2
lda (ptrInstrumentTbl),y
sta trackn_instrdb,x
sta nt
iny
lda (ptrInstrumentTbl),y
sta trackn_instrhb,x
sta nt+1
IFT FEAT_FILTER
; lda #1
lda #0 ;* EXPERIMENTAL approach for more precise manipulation of the PWM
sta trackn_filter,x ; set the offset value to 0 on new notes always
ora #1 ; the value of 1 is expected here, so just provide it I guess
EIF
IFT FEAT_TABLEGO
IFT FEAT_FILTER
tay
ELS
ldy #1
EIF
lda (nt),y
sta trackn_tablelop,x
iny
ELS
ldy #2
EIF
lda (nt),y
sta trackn_instrlen,x
iny
lda (nt),y
sta trackn_instrlop,x
iny
lda (nt),y
sta trackn_tabletypespeed,x
IFT FEAT_TABLETYPE||FEAT_TABLEMODE
and #$3f
EIF
sta trackn_tablespeeda,x
IFT FEAT_TABLEMODE
lda (nt),y
and #$40
sta trackn_tablemode,x
EIF
IFT FEAT_AUDCTLMANUALSET
iny
lda (nt),y
sta trackn_audctl,x
iny
ELS
ldy #6
EIF
lda (nt),y
sta trackn_volumeslidedepth,x
IFT FEAT_VOLUMEMIN
iny
lda (nt),y
sta trackn_volumemin,x
IFT FEAT_EFFECTS
iny
EIF
ELS
IFT FEAT_EFFECTS
ldy #8
EIF
EIF
IFT FEAT_EFFECTS
lda (nt),y
sta trackn_effdelay,x
IFT FEAT_EFFECTVIBRATO
iny
lda (nt),y
tay
lda vibtabbeg,y
sta trackn_effvibratoa,x
EIF
IFT FEAT_EFFECTFSHIFT
ldy #10
lda (nt),y
sta trackn_effshift,x
EIF
EIF
IFT FEAT_TABLE_MANUAL ; Manual tuning table loaded from instruments, based on the unused 12th byte, this is not yet fully implemented into RMT
ldy #11
lda (nt),y
sta trackn_pointertable,x
EIF
lda #128
sta trackn_volumeslidevalue,x
sta trackn_instrx2,x
asl @
sta trackn_instrreachend,x
sta trackn_shiftfrq,x
tay
lda (nt),y
sta trackn_tableend,x
adc #0
sta trackn_instridx,x
lda #INSTRPAR
sta trackn_tablea,x
tay
lda (nt),y
sta trackn_tablenote,x
IFT FEAT_SFX||FEAT_IS_TRACKER
rts
;* a rts is mandatory for the 'tracker.obx' binary, else a lot of things break in RMT!
;* look inside 'rmtextra.a65' for the exclusive tracker.obx code
ELS
jmp p2x0 ; go process the next channel's instrument
EIF
;---------------------------------------------------------------------------------------------------------------------------------------------;
rmt_play
rmt_p0
jsr SetPokey
rmt_p1
IFT FEAT_INSTRSPEED==0||FEAT_INSTRSPEED>1
dec smc_silence_instrspeed
bne rmt_p3
EIF
IFT FEAT_INSTRSPEED==0
lda #$ff
smc_instrspeed equ *-1 ; ptr to #$ff location in the code
sta smc_silence_instrspeed
ELI FEAT_INSTRSPEED>1
lda #FEAT_INSTRSPEED
sta smc_silence_instrspeed
EIF
rmt_p2
dec v_aspeed
bne rmt_p3
inc smc_abeat ; ++smc_abeat
lda #$ff ; if (smc_abeat == smc_maxtracklen) GetSongLine else GetTrackLine
smc_abeat equ *-1 ; smc_abeat is the index into the track
cmp #$ff
smc_maxtracklen equ *-1
beq p2o3
jmp GetTrackLine
p2o3
jmp GetSongLine
rmt_p3
ldx #TRACKS-1
;*
;* Aggressive initialisation every new player call here, the method was originally done to get the AUDCTL early, but many things can be exploited here the same way.
;* Combining the aggressive init and rmt_p3 in 1 thing, this is now an even more aggressive approach!
;*
;* POSSIBLE IMPROVEMENT: process ALL effect commands here instead... Meaning there won't be workarounds necessary later, for several commands.
;* Example: Get AUDCTL early, get Effect values early, process instrument accordingly afterwards.
;* Doing certain things in a different order might drastically speed up several parts that end up being redundant or even overwritten later during certain effects like AUTOFILTER or BASS16.
;* Let's say, process 16-bit here... in such case, there won't be anything stopping the player to know it can safely skip a channel's instrument if it was going to be overwritten anyway...
;* This is purely speculation, however, so what is done here currently does the job, at least. This is still very different from the original RMT driver code as it is.
;*
dodex
lda trackn_instrhb,x
beq dexnext ; process the next channel's bytes immediately if empty
sta ns+1
lda trackn_instrdb,x
sta ns
ldy trackn_instridx,x
lda (ns),y ; volume byte
sta trackn_volumeenvelope,x ; sta reg1
iny
lda (ns),y ; command and distortion byte
sta trackn_command,x ; sta reg2
iny
lda (ns),y ; $XY parameter byte
sta trackn_effectparameter,x ; sta reg3
iny
tya
cmp trackn_instrlen,x
bcc dodex_a
beq dodex_a
lda #$80
sta trackn_instrreachend,x
lda trackn_instrlop,x
dodex_a
sta trackn_instridx,x
IFT FEAT_AUDCTLMANUALSET&&FEAT_COMMAND7 ; POSSIBLE IMPROVEMENT: process the Two-Tone Filter commands here instead, leaving CMD7 only useful for Volume Only checks later
dex_cmd7
lda trackn_command,x
and #$70 ; clear distortion and other bits
cmp #$70 ; command 7?
bne dexnext ; skip if not equal
lda trackn_effectparameter,x
dex_xy
cmp #$FD ; failsafe -> Volume Only Mode or SKCTL toggle
bcs dexnext ; skip if above or equal #$FD
sta trackn_audctl,x ; overwrite the previous value
EIF
dexnext
dex
bpl dodex ; continue until x is negative
;* FORCE ALL INSTRUMENTS TO USE THE SAME AUDCTL TO NOT OVERLAP IN PRIORITY-- DOESNT WORK LIKE THAT FUCK, HOW COULD I FORCE A AUDCTL CLEAR ON A CHANNEL ABOVE ONE I AM USING?
;* Ideally... what would be even better is to have a global effect channel... y'know, like a music tracker? That could also be useful for setting certain global values like tempo, note offset, etc
pp0
;* get AUDCTL as early as possible, properly this time!
IFT FEAT_AUDCTLMANUALSET
lda trackn_audctl+0
ora trackn_audctl+1
ora trackn_audctl+2
ora trackn_audctl+3
sta v_audctl
;* Assign flags early here as soon as possible
IFT FEAT_FULL_16BIT||FEAT_BASS16||FEAT_FULL_SAWTOOTH
tay ; backup the now combined audctl for the flags attribution
and #1 ; 64khz == 0, 15khz == 1 always, the other flags will then take priority over this
sta g_flag+0 ; ch1
sta g_flag+1 ; ch2
sta g_flag+2 ; ch3
sta g_flag+3 ; ch4
tya ; get the AUDCTL back for the BIT tests below
pp0_a
bit CH1_179
beq pp0_d ; BNE => 1.79mhz, BEQ => Nothing, skip the next BIT test
bit JOIN_12
bne pp0_b ; BNE => 16-bit, BEQ => 1.79mhz
ldx #$40 ; 1.79mhz pointer
bne pp0_c ; unconditional
pp0_b
ldx #$80 ; 16-bit pointer
stx g_flag+1 ; flag set in ch2
dex ; #$80 becomes #$7F
pp0_c
stx g_flag+0 ; flag set in ch1
pp0_d
bit CH3_179
beq pp0_g ; BNE => 1.79mhz, BEQ => Nothing, skip the next BIT test
bit JOIN_34
bne pp0_e ; BNE => 16-bit, BEQ => 1.79mhz
ldx #$40 ; 1.79mhz pointer
bne pp0_f ; unconditional
pp0_e
ldx #$80 ; 16-bit pointer
stx g_flag+3 ; flag set in ch4
dex ; #$80 becomes #$7F
pp0_f
stx g_flag+2 ; flag set in ch3
pp0_g
EIF
IFT TRACKS>4 ; Stereo
lda trackn_audctl+4
ora trackn_audctl+5
ora trackn_audctl+6
ora trackn_audctl+7
sta v_audctl2
IFT FEAT_FULL_16BIT||FEAT_BASS16||FEAT_FULL_SAWTOOTH
tay ; backup the now combined audctl for the flags attribution
and #1 ; 64khz == 0, 15khz == 1 always, the other flags will then take priority over this
sta g_flag+0+4 ; ch1
sta g_flag+1+4 ; ch2
sta g_flag+2+4 ; ch3
sta g_flag+3+4 ; ch4
tya ; get the AUDCTL back for the BIT tests below
pp0_h
bit CH1_179
beq pp0_k ; BNE => 1.79mhz, BEQ => Nothing, skip the next BIT test
bit JOIN_12
bne pp0_i ; BNE => 16-bit, BEQ => 1.79mhz
ldx #$40 ; 1.79mhz pointer
bne pp0_j ; unconditional
pp0_i
ldx #$80 ; 16-bit pointer
stx g_flag+1+4 ; flag set in ch2
dex ; #$80 becomes #$7F
pp0_j
stx g_flag+0+4 ; flag set in ch1
pp0_k
bit CH3_179
beq pp0_n ; BNE => 1.79mhz, BEQ => Nothing, skip the next BIT test
bit JOIN_34
bne pp0_l ; BNE => 16-bit, BEQ => 1.79mhz
ldx #$40 ; 1.79mhz pointer
bne pp0_m ; unconditional
pp0_l
ldx #$80 ; 16-bit pointer
stx g_flag+3+4 ; flag set in ch4
dex ; #$80 becomes #$7F
pp0_m
stx g_flag+2+4 ; flag set in ch3
pp0_n
EIF
EIF
ELS
lda #0
sta v_audctl
IFT TRACKS>4
sta v_audctl2
EIF
EIF
pp0_o
ldx #TRACKS-1 ; must get the tracks value again before the next part
pp1 ; copying the values to the zeropage to make things faster... but not all bytes need this...
;* OPTIMISATION: reg1 is now free to use for a different purpose!
lda trackn_instrhb,x
bne pp1_b ; continue if not equal
jmp ppnext ; skip this channel and process the next one
pp1_b
lda g_flag,x ; AUDCTL flags
sta reg1 ; backup to the zeropage for quicker accesses
lda trackn_command,x ; command and distortion byte
sta reg2 ; backup to the zeropage for quicker accesses
lda trackn_effectparameter,x ; $XY parameter byte
sta reg3 ; backup to the zeropage for quicker accesses
pp2
lda trackn_volumeenvelope,x ; volume envelope byte
IFT TRACKS>4
cpx #4
bcc pp2s
lsr @
lsr @
lsr @
lsr @
EIF
pp2s
and #$0f
ora trackn_volume,x
tay
lda volumetab,y
sta tmp ; backup the resulting volume here, it will then used to make the AUDC value a bit later
;---------------------------------------------------------------------------------------------------------------------------------------------;
;* start of manual tables code (unfinished)...
IFT FEAT_TABLE_MANUAL ; Manual tuning table loaded from instruments, this is currently not fully implemented into RMT...
lda trackn_pointertable,x
beq do_tuning_tables ; a value of 0 means no pointer will be used, thus, can be skipped immediately
tay
and #$0F
ora #$B0
sta nr+1 ; Bx00, where x is manipulated
;* hack for Reverse-16 proof of concept, won't be used later
lda #0
cpx #1