-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathbank0.inc
1845 lines (1784 loc) · 61.2 KB
/
bank0.inc
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
ORG $A000
ECHO "PROGRAM BEGIN"
ECHO "-------------"
BANK_START $F0
; ---------------------------------------------------------------------------
; -------------M-A-I-N--M-U-S-I-C--A-N-D--S-E--E-N-G-I-N-E-------------------
; ---------------------------------------------------------------------------
; =============== S U B R O U T I N E =======================================
_apu_play:
LDA _ptr0 ; FIX, since we using common _switch
PHA ; here, need to save common ptr0 var
LDA _ptr0+1 ; which can be used by random code
PHA
LDA #$C0 ; hmm, why every time disable frame-irq?
STA _PAD1_REG ; it were disabled once at the boot
LDA _apu_dpcm_disable_flag
BPL loc_A014 ; mask out dpcm channel if forbidden
LDA _APU_STATUS
AND #$0F
STA _APU_STATUS
loc_A014:
JSR _apu_play_mus
JSR _apu_play_se0
JSR _apu_play_se1
LDA #$00 ; hmmm, these will clear mus/se requests
STA _apu_mus_idx_req ; one more time, but they already cleared
STA _apu_se_idx_req ; inside play routines.
STA _apu_se_idx_req+1
PLA
STA _ptr0+1
PLA
STA _ptr0
RTS
; =============== S U B R O U T I N E =======================================
_apu_init:
LDA #$40
STA _PAD1_REG ; once more frame-irq disable here
; LDA #$80 ; debug leftovers
; STA byte_4083
; ASL
LDA #$00
STA _APU_DMC_FREQ
STA _APU_DMC_LOAD
; STA byte_4083 ; debug leftovers
STA _apu_mus_fade_out_timer
LDA #$0F
STA _APU_STATUS ; enable channels except dpcm
RTS
; =============== S U B R O U T I N E =======================================
_apu_all_stop:
LDA #$00
STA _apu_mus_seq_ofs
STA _apu_mus_cur_idx
STA _apu_mus_fade_out_timer
STA _APU_TRI_COUNT
; !FALLTHROUGH!
; =============== S U B R O U T I N E =======================================
_apu_all_reset:
LDX #$00
STX _APU_STATUS
LDX #$0F
STX _APU_STATUS
RTS
; =============== S U B R O U T I N E =======================================
_apu_play_mus:
LDA _apu_mus_idx_req ; hi-bit or request means stop all
BMI _apu_all_stop ; if non-zero - request to music reload
BNE .apu_mus_load ; value is an encoded bit-field
LDA _apu_mus_seq_ofs ; non-zero offset means mus currently playing
BNE .j_mus_play
RTS
.j_mus_play:
JMP .mus_play
.apu_mus_load:
STA _apu_mus_cur_idx ; currently played mus idx as bit-field
; TODO, optimize me
CMP #_MUS_IDX_TITLE0 ; check for special mus tracks that should
BEQ .apu_mus_stop_reload ; stop current mus instantly and start immediately
CMP #_MUS_IDX_SETUP ; tracks 01, 04, 21 and 60 are such tracks
BEQ .apu_mus_stop_reload ; (title, game setup, alert, game message)
CMP #_MUS_IDX_ALERT0
BEQ .apu_mus_stop_reload
CMP #_MUS_IDX_NOTICE0
BEQ .apu_mus_stop_reload
; -
; OPTIMIZED, speed
; TAX
; LDA _mus_fade_require_list,X
; BEQ .apu_mus_stop_reload
; -
LDA _apu_mus_seq_ofs ; the rest of tracks are fadable, when requested
BEQ .apu_mus_stop_reload ; to play new sound, fade out timer loaded
BMI .apu_mus_stop_reload ; it will fade out all tracks until zero, then
LDA #$C0 ; jump to reload new music idx
STA _apu_mus_fade_out_timer
BNE .j_mus_play
.apu_mus_stop_reload:
LDA _apu_mus_cur_idx ; stop before reload
JSR _apu_all_reset ; A is safe here
.apu_mus_reload:
; REDUNDANT: optimize me!
; TAX ; decode bitfields:
; ASL ; 01 02 04 05 10 20 21 22 40 41 42 44 48 50 60
; BMI loc_A09D ; 00 01 02 03 04 05 0D 0E 0C 06 07 08 09 0A 0B
; ASL ; &40!=0 + 6 (40<=X<=60 -> 06-0C)
; BPL loc_A0A1 ; &23!=0 + D (21<=X<=22 -> 0D-0E)
; ASL ; rest + 0 (01<=X<=20 -> 00-05)
; BEQ loc_A0A1 ; very criptic
; LDY #$0C
; BNE loc_A0A3
;loc_A09D:
; LDY #$05
; BNE loc_A0A3
;loc_A0A1:
; LDY #$FF
;loc_A0A3:
; TXA
;loc_A0A4:
; INY
; LSR
; BCC loc_A0A4 ; extract lower bit-field idx
; -
; OPTIMIZED, that's IT! one byte decode for sequential indexes instead of bitfields!!!
TAY
; -
; LDA _apu_mus_seq_ofs_list,Y ; REDUNDANT, load sequence offset
LDA _apu_mus_seq_ofs_list-1,Y ; OPTIMIZED, load sequence offset
STA _apu_mus_seq_ofs
TAY
.mus_trk_data_ofs_load:
LDA _apu_mus_seq_ofs_list,Y ; load track data offset in sequence
; BEQ _apu_all_stop ; REDUNDANT, there are no zero values there
CMP #$FF
BNE loc_A0BE ; sequence REPEAT code test
LDA _apu_mus_cur_idx ; reload current idx and start from the beginning
; LDY #$FF ; REDUNDANT, Y will be initialized by the reload code
BNE .apu_mus_reload ; since we store encoded value, go to decode it again
loc_A0BE:
CMP #$FE ; sequence NEXT code test
BNE .mus_trk_data_load
; REDUNDANT: optimize me!
; LDA _apu_mus_cur_idx ; calculate next mus idx to continue
; ASL ; since this is still a bitfield, we need some more
; BPL loc_A0CC ; criptic calculations to get the next encoded
; ORA #$40 ; bitfield value.
; BNE loc_A0D8 ; we need to convert 01 to 02, 08 to 10 (<<1, easy)
;loc_A0CC: ; also 48 to 50 ((<<1&$7F)|$40, easy?), and finally
; TAX ; 21 to 22 ((<<1&$3F)|$20), EASY?!)
; ASL
; BPL loc_A0D7
; TXA
; AND #$3F
; ORA #$20
; BNE loc_A0D8
;loc_A0D7:
; TXA
;loc_A0D8:
; AND #$7F
; STA _apu_mus_cur_idx
; LDY #$FF ; REDUNDANT, Y will be initialized by the reload code
; BNE .apu_mus_reload ; unconditional jump
; -
; OPTIMIZED,
INC _apu_mus_cur_idx
LDA _apu_mus_cur_idx
BNE .apu_mus_reload ; unconditional jump
; -
.mus_trk_data_load:
TAY
LDA [_trk00._tempo]-1],Y ; duration table offset for current track common for all channels
STA _apu_mus_tempo
LDA [_trk00._ptr]-1],Y ; mus data block ptr for all channels
STA _apu_trk_data_ptr
LDA [_trk00._ptr],Y
STA _apu_trk_data_ptr+1
LDA [_trk00._p2]-1],Y ; starting offset for SQUARE2 data
STA _apu_mus_p2_data_pos
LDA [_trk00._tri]-1],Y
STA _apu_mus_tri_data_pos ; starting offset for TRIANGLE data
LDA [_trk00._env]-1],Y
STA _apu_mus_envelope ; common envelope parameter for all channels
LDA [_trk00._dmc]-1],Y
STA _apu_mus_dmc_data_pos ; starting offset for DMC data
LDA #$01
STA _apu_mus_p1_timer ; init timers to load the channel data immediately
STA _apu_mus_p2_timer ; at the start (decrement->zero test->fetch)
STA _apu_mus_tri_timer
STA _apu_mus_dmc_timer
LDA #$00
STA _apu_mus_p1_data_pos ; starting offset for SQUARE1 always 0 in data block
LDA _APU_STATUS ; reset TRIANGLE channel
AND #$1B
STA _APU_STATUS
; LDA _APU_STATUS ; REDUNDANT, already loaded and properly masked
; AND #$10
ORA #$0F ; re-enable channels
STA _APU_STATUS
.mus_play:
LDA _apu_mus_fade_out_timer ; if fade out timer is zero, skip
BEQ .mus_p1_play
DEC _apu_mus_fade_out_timer ; else decrement until zero
BNE .mus_p1_play
LDA _apu_mus_cur_idx ; when zero, load another mus track
JMP .apu_mus_stop_reload
; -
; - start of SQUARE1 channel work
.mus_p1_play:
DEC _apu_mus_p1_timer
BNE .mus_p1_do_envelope ; note loaded and played, do special envelope work
LDY _apu_mus_p1_data_pos ; fetch track cmd, always present in data
INC _apu_mus_p1_data_pos
LDA (_apu_trk_data_ptr),Y ; CMD: ab--cccc
BNE .mus_p1_continues ; CMD=0, end of sequence
INC _apu_mus_seq_ofs ; fetch next track offset in sequence
LDY _apu_mus_seq_ofs
JMP .mus_trk_data_ofs_load
.mus_p1_continues:
BPL .mus_p1_load ; a = 0, branch (one-byte 00-7F raw codes)
TAX ; a = 1, backup for now
ASL ;
BMI .mus_p1_cmdC0 ; b test
LDA #$00 ; b = 0, two-bytes cmd80 codes
; STA _apu_mus_p1_release_mode ; p1time recalc mode flag = 0
; TXA ; restore actual code without shift
; BNE .mus_p1_extra_fetch
BEQ .mus_p1_extra_fetch
.mus_p1_cmdC0:
LDA #$80 ; b = 1, three-bytes cmdC0 codes
; STA _apu_mus_p1_release_mode ; p1time recalc mode flag != 0
; REDUNDANT, no such commands here!, even more, they aren't useful actually
; since we have only 0-15 note lengths (use only 9) indexes, we could store
; C0 commands in two-byte codes as well.
; LDY _apu_mus_p1_data_pos ; read second envelope data byte
; INC _apu_mus_p1_data_pos
; LDA (_apu_trk_data_ptr),Y
; -
; OPTIMIZED
.mus_p1_extra_fetch:
STA _apu_mus_p1_release_mode ; p1time recalc mode flag != 0
TXA
; -
AND #$0F ; mask out note duration
CLC
ADC _apu_mus_tempo ; select from duration table
TAY
LDA _apu_mus_duration_table,Y ; and calc an actual delay for a note
STA _apu_mus_p1_delay
LDY _apu_mus_p1_data_pos
INC _apu_mus_p1_data_pos
LDA (_apu_trk_data_ptr),Y ; read actual p1time freq
.mus_p1_load:
JSR _apu_p1_time_load ; finally load an actual channe freq
LDA _apu_mus_p1_delay ; reload timer with delay value for SQUARE1
STA _apu_mus_p1_timer
JSR _apu_mus_tempo_delta_calc
STA _apu_mus_p1_tempo_delta
LDA #$00
STA _apu_mus_p1_tempo_cnt ; reset env counter for SQIARE1
.mus_p1_do_envelope:
INC _apu_mus_p1_tempo_cnt
LDY _apu_mus_p1_tempo_delta
BEQ loc_A1A6
DEC _apu_mus_p1_tempo_delta
loc_A1A6:
LDA _apu_mus_envelope
AND #$70
LSR
LSR
LSR
LSR
TAX
LDA _apu_mus_p1_delay
JSR _apu_mus_p_sweep_calc
JSR _apu_mus_p_fade_out
STA _APU_PULSE1_ENV
LDA #$7F
STA _APU_PULSE1_SWEEP
LDX _apu_mus_p1_time_lo ; OPTIMIZED
BEQ .mus_p2_play
LDA _apu_mus_p1_tempo_cnt
; LDX _apu_mus_p1_time_lo ; REDUNDANT
LDY _apu_mus_p1_release_mode
BNE loc_A1D7
JSR _apu_mus_p_releaseA
JMP loc_A1DC
loc_A1D7:
LDY #$00
JSR _apu_mus_p_releaseB
loc_A1DC:
STX _APU_PULSE1_TIME
; - end of SQUARE1 channel work
;
; - start of SQUARE2 channel work
.mus_p2_play:
DEC _apu_mus_p2_timer
BNE .mus_p2_do_envelope
LDY _apu_mus_p2_data_pos
BNE .mus_p2_continues ; if no SQAURE2 data (offset = 0)
LDA #$50 ; then force it to mute, skip to TRI
STA _APU_PULSE2_ENV
JMP .mus_tri_play
.mus_p2_continues:
INC _apu_mus_p2_data_pos
LDA (_apu_trk_data_ptr),Y ; fetch data cmd
BPL .mus_p2_load ; if cmd 00-7F, load as raw data
TAX ; the rest is the same as for SQUARE1
ASL
BMI .mus_p2_cmdC0 ; once more redundant
LDA #$00
; STA _apu_mus_p2_release_mode ; recalc mode for SQUARE2
; TXA
; BNE .mus_p2_extra_fetch
BEQ .mus_p2_extra_fetch
; REDUNDANT as well, there aren't such codes in current music data
;
.mus_p2_cmdC0:
LDA #$80
; STA _apu_mus_p2_release_mode
; LDY _apu_mus_p2_data_pos
; INC _apu_mus_p2_data_pos
; LDA (_apu_trk_data_ptr),Y
.mus_p2_extra_fetch:
STA _apu_mus_p2_release_mode
TXA
; -
AND #$0F ; similar to SQUARE2 load of durations
CLC
ADC _apu_mus_tempo
TAY
LDA _apu_mus_duration_table,Y
STA _apu_mus_p2_delay
LDY _apu_mus_p2_data_pos
INC _apu_mus_p2_data_pos
LDA (_apu_trk_data_ptr),Y ; load an actual data byte
.mus_p2_load:
LDX _apu_se_loop_counters+1 ; SE1 can be either DMC or SQIARE2, so we may check
BNE .mus_p2_skip_load ; only if loop counter is active. for SE0 any can be
LDX _apu_se_loop_idx ; SUARE2, so check the loop_idx is active
BNE .mus_p2_skip_load ; SE have priority here, skip load music channel here
; LDX #$97 ; BUG, makes SQUARE2 cracking sometimes
LDX #$90 ; FIX, for crackling sounds by Chris Covell
STX _APU_PULSE2_ENV
LDX #$7F
STX _APU_PULSE2_SWEEP ; or set the default envelope first...
JSR _apu_p2_time_load ; ...then actually load a SQUARE2 data
.mus_p2_skip_load:
LDA _apu_mus_p2_delay
STA _apu_mus_p2_timer
JSR _apu_mus_tempo_delta_calc
STA _apu_mus_p2_tempo_delta
LDA #$00
STA _apu_mus_p2_tempo_cnt
.mus_p2_do_envelope:
INC _apu_mus_p2_tempo_cnt
LDY _apu_mus_p2_tempo_delta
BEQ loc_A257
DEC _apu_mus_p2_tempo_delta
loc_A257:
LDA _apu_se_loop_counters+1 ; here we skip the envelope settings as well
BNE .mus_tri_play ; for SE proiority on SQUARE2, but still need calc it!
LDA _apu_se_loop_idx ; or else when SE is over, music will garbled
BNE .mus_tri_play
LDA _apu_mus_envelope
AND #$07
TAX
LDA _apu_mus_p2_delay
JSR _apu_mus_p_sweep_calc
JSR _apu_mus_p_fade_out
TAX
LDA _apu_mus_envelope
AND #$07
CMP #$03
BEQ loc_A292
CMP #$06
BEQ loc_A292
TXA
AND #$0F
BEQ loc_A288
SEC
SBC #$03
BPL loc_A288
LDA #$01
loc_A288:
STA _apu_tmpF6
TXA
AND #$F0
ORA _apu_tmpF6
JMP loc_A293
loc_A292:
TXA
loc_A293:
STA _APU_PULSE2_ENV
LDA #$7F
STA _APU_PULSE2_SWEEP
LDX _apu_mus_p2_time_lo ; OPTIMIZED
BEQ .mus_tri_play
LDA _apu_mus_p2_tempo_cnt
; LDX _apu_mus_p2_time_lo ; REDUNDANT
LDY _apu_mus_p2_release_mode
BNE loc_A2B1
JSR _apu_mus_p_releaseA
JMP loc_A2B6
loc_A2B1:
LDY #$04
JSR _apu_mus_p_releaseB
loc_A2B6:
STX _APU_PULSE2_TIME
; - end of SQIARE2 channel work
;
; - start TRIANGLE chanel work
.mus_tri_play:
LDA _apu_mus_fade_out_timer ; the last 16 clocks of fade out
BEQ .mus_tri_continues ; TRI/DMC channels are mute, no need to fetch data then
AND #$C0
BNE .mus_tri_continues ; fade out is over, stop sounds
LDA _APU_STATUS ; reset TRIANGLE/NOISE/DMC channels
AND #$03
STA _APU_STATUS ; activate all except DMC
ORA #$0F
STA _APU_STATUS
RTS
.mus_tri_continues:
DEC _apu_mus_tri_timer
BNE .mus_dmc_play
LDY _apu_mus_tri_data_pos
INC _apu_mus_tri_data_pos
LDA (_apu_trk_data_ptr),Y
BPL loc_A2F4
AND #$0F
CLC
ADC _apu_mus_tempo ; no custom codes for tri channel
TAY
LDA _apu_mus_duration_table,Y
STA _apu_mus_tri_delay
LDY _apu_mus_tri_data_pos
INC _apu_mus_tri_data_pos
LDA (_apu_trk_data_ptr),Y
loc_A2F4:
LDX _apu_se_loop_idx
BNE loc_A318
LDX _apu_se_loop_idx+1
BNE loc_A318
STA _apu_tmpF6
LDX #$2F
LDY _apu_mus_envelope
BPL loc_A310
TYA
AND #$08
BNE loc_A30E
LDX #$FF
BNE loc_A310
loc_A30E:
LDX #$49
loc_A310:
STX _APU_TRI_COUNT
LDA _apu_tmpF6
JSR _apu_tritime_load
loc_A318:
LDA _apu_mus_tri_delay
STA _apu_mus_tri_timer
; - end TRIANGLE chanel work
;
; - start DMC chanel work
.mus_dmc_play:
DEC _apu_mus_dmc_timer
BNE .mus_exit
LDY _apu_mus_dmc_data_pos ; also skip fetch if pos = 0
BEQ .mus_exit
INC _apu_mus_dmc_data_pos ; fetch data
LDA (_apu_trk_data_ptr),Y
STA _apu_tmpF6
AND #$0F
CLC
ADC _apu_mus_tempo ; no custom codes for dmc channel as well
TAY
LDA _apu_mus_duration_table,Y
STA _apu_mus_dmc_delay
LDX _apu_se_loop_idx+1 ; test for any other SE are active now
BNE .mus_dmc_load_skip ; then skip DMC load
LDX _apu_se_loop_idx
BNE .mus_dmc_load_skip
LDA _APU_STATUS
AND #$10
BNE .mus_dmc_load_skip ; dmc active, reload timers only
LDA _apu_tmpF6
AND #$70
BEQ .mus_dmc_load_skip
AND #$10
BEQ loc_A366
LDA #_DPCM_IDX2 ; select between two DMC notes
STA _APU_DMC_ADDR ; data the same, len/freq are different
LDA #$03
STA _APU_DMC_LEN
LDA #$06
STA _APU_DMC_FREQ
BNE loc_A375
loc_A366:
LDA #_DPCM_IDX2
STA _APU_DMC_ADDR
LDA #$08
STA _APU_DMC_LEN
LDA #$0F
STA _APU_DMC_FREQ
loc_A375:
LDA _apu_dpcm_disable_flag ; enable dmc when loaded
BMI .mus_dmc_load_skip
LDA _APU_STATUS
ORA #$10
STA _APU_STATUS
.mus_dmc_load_skip:
LDA _apu_mus_dmc_delay
STA _apu_mus_dmc_timer
; - end DMC chanel work
.mus_exit:
RTS
; OPTIMIZED
;_mus_fade_require_list:
; .BYTE $00,$01,$00,$01,$01,$01,$01,$01,$01,$01,$01,$00,$01,$00,$01
; -
; =============== S U B R O U T I N E =======================================
_apu_mus_tempo_delta_calc:
CLC
CMP #$13
BCS loc_A391
LDA #$17
BNE locret_A393
loc_A391:
LDA #$3F
locret_A393:
RTS
; =============== S U B R O U T I N E =======================================
_apu_mus_p_sweep_calc:
CLC
CMP #$13
BCS loc_A3AE
INX
LDA #$E8
CLC
loc_A39D:
ADC #$18
DEX
BNE loc_A39D
STA _apu_tmpF6
TYA
CLC
ADC _apu_tmpF6
TAY
LDA _mus_p_sweep_tbl0,Y
BNE locret_A3CE
loc_A3AE:
STX _apu_tmpF7
INX
LDA #$C0
loc_A3B3:
CLC
ADC #$40
DEX
BNE loc_A3B3
STA _apu_tmpF6
TYA
CLC
ADC _apu_tmpF6
TAY
LDA _apu_tmpF7
AND #$04
BNE loc_A3CB
LDA _mus_p_sweep_tbl1,Y
BNE locret_A3CE
loc_A3CB:
LDA _mus_p_sweep_tbl2,Y
locret_A3CE:
RTS
; =============== S U B R O U T I N E =======================================
_apu_mus_p_releaseA:
SEC
CMP #$19
BCC locret_A3DE
LSR
LSR
LSR
LSR
BCS loc_A3DD
DEX
BNE locret_A3DE
loc_A3DD:
INX
locret_A3DE:
RTS
; =============== S U B R O U T I N E =======================================
_apu_mus_p_releaseB:
AND #$08
BNE loc_A3ED
TXA
CLC
ADC #$02
BCC loc_A3F5
LDA #$FF
BNE loc_A3F5
loc_A3ED:
TXA
SEC
SBC #$02
BCS loc_A3F5
LDA #$00
loc_A3F5:
STA _apu_mus_p1_time_lo,Y
RTS
; =============== S U B R O U T I N E =======================================
_apu_mus_p_fade_out:
LDY _apu_mus_fade_out_timer
BEQ locret_A41E
TAX
TYA
LSR
LSR
LSR
LSR
LSR
EOR #$FF
AND #$07
STA _apu_tmpF6
TXA
AND #$0F
BEQ loc_A417
SEC
SBC _apu_tmpF6
BPL loc_A417
LDA #$01
loc_A417:
STA _apu_tmpF6
TXA
AND #$F0
ORA _apu_tmpF6
locret_A41E:
RTS
; =============== S U B R O U T I N E =======================================
;_unref_7:
; LDY #$7F
; STY _APU_PULSE1_SWEEP
; =============== S U B R O U T I N E =======================================
_apu_tritime_load:
LDX #$08 ; loads TRIANGLE
BNE _apu_time_load
; =============== S U B R O U T I N E =======================================
_apu_p2_time_load:
LDX #$04 ; loads SQUARE2
BNE _apu_time_load
; =============== S U B R O U T I N E =======================================
_apu_p1_time_load:
LDX #$00 ; LOADS SQUARE1
; !FALLTHROUGH!
; =============== S U B R O U T I N E =======================================
_apu_time_load:
TAY
LDA _apu_note_tbl-1,Y ; low 8-bit nibble of frequency
STA _apu_mus_p1_time_lo,X ; store shadow value to RAM
BEQ _apu_mute_load ; if zero, mute note instead
STA _APU_PULSE1_TIME,X ; load APU with value
LDA _apu_note_tbl-2,Y ; high 3-bit nibble of frequency
; !FALLTHROUGH!
; =============== S U B R O U T I N E =======================================
_apu_len_load:
ORA #$08 ; set default time 1
STA _APU_PULSE1_LEN,X ; load APU with value
RTS
; =============== S U B R O U T I N E =======================================
_apu_mute_load:
LDA #$50 ; playback rate 0, duty 75%, fixed env
STA _APU_PULSE1_ENV,X
LDA #$00 ; frequency 0
STA _APU_PULSE1_TIME,X
BEQ _apu_len_load
; =============== S U B R O U T I N E =======================================
_apu_p2_reset_tri_mute:
LDA _APU_STATUS
AND #$19
STA _APU_STATUS
ORA #$0F
STA _APU_STATUS
BNE _apu_tri_mute_common ; OPTIMIZED
; LDA #$01 ; REDUNDANT
; STA _APU_TRI_COUNT
; LDA #$FF
; STA _APU_TRI_TIME
; LDA #$0F
; STA _APU_TRI_LEN
; RTS
; =============== S U B R O U T I N E =======================================
_apu_dmc_reset_tri_mute:
LDA _APU_STATUS
AND #$0F
ORA #$0F
STA _APU_STATUS
; !FALLTHROUGH!
; =============== S U B R O U T I N E =======================================
_apu_tri_mute_common:
LDA #$01
STA _APU_TRI_COUNT
LDA #$FF
STA _APU_TRI_TIME
LDA #$0F
STA _APU_TRI_LEN
RTS
; =============== S U B R O U T I N E =======================================
_apu_p2_reset:
LDA _APU_STATUS
AND #$1D
STA _APU_STATUS
ORA #$0F
STA _APU_STATUS
RTS
; =============== S U B R O U T I N E =======================================
_apu_play_se0:
LDY _apu_se_idx_req
BEQ .apu_loop_se0 ; if request is zero, then either do loop or nothing
LDA #$00 ; and manually clear request flag now
STA _apu_se_idx_req
STY _apu_se_loop_idx ; store at once here, instead of in every single routine
DEY
TYA
JSR _switch
.WORD _apu_se1_start
.WORD _apu_se2_start
.WORD _apu_se4_start
.WORD _apu_se8_start
.WORD _apu_se10_start
.WORD _apu_se20_start
.WORD _apu_se40_start
.WORD _apu_se80_start
.apu_loop_se0:
LDY _apu_se_loop_idx ; if zero, idle
BEQ _apu_se0_done
DEY
TYA
JSR _switch
.WORD _apu_se1_loop
.WORD _apu_se2_loop
.WORD _apu_se4_loop
.WORD _apu_se8_loop
.WORD _apu_se10_loop
.WORD _apu_se20_loop
.WORD _apu_se40_loop
.WORD _apu_se80_loop
_apu_se0_done:
RTS
; =============== S U B R O U T I N E =======================================
_apu_play_se1:
LDY _apu_se_idx_req+1
BEQ .apu_loop_se1
LDA #$00
STA _apu_se_idx_req+1
STY _apu_se_loop_idx+1
DEY
TYA
JSR _switch
.WORD _apu_se100_start
.WORD _apu_se200_start
.WORD _apu_se400_start
.WORD _apu_se800_start
.WORD _apu_se1000_start
.WORD _apu_se2000_start
.WORD _apu_se3000_start
.WORD _apu_se4000_start
.WORD _apu_se8000_start
.apu_loop_se1:
LDY _apu_se_loop_idx+1 ; if zero, idle
BEQ _apu_se1_done
DEY
TYA
JSR _switch
.WORD _apu_se100_loop
.WORD _apu_se200_loop
.WORD _apu_se400_loop
.WORD _apu_se800_loop
.WORD _apu_se1000_loop
.WORD _apu_se2000_loop
.WORD _apu_se3000_loop
.WORD _apu_se4000_loop
.WORD _apu_se8000_loop
_apu_se1_done:
RTS
; REDUNDANT
; =============== S U B R O U T I N E =======================================
;_apu_play_se0:
; LDY _apu_se_idx_req ; load requested flags byte
; LDA _apu_se_loop_idx ; load currently playing flags
; LSR _apu_se_idx_req ; extract bit from requested flags
; BCS _apu_se1_start ; non-zero on the first run, zero
; LSR ; on all following steps, so single exec here
; BCS _apu_se1_loop ; while here still 0, so no loop exec
; LSR _apu_se_idx_req ; and so on for all bits
; BCS _j_apu_se2_start ; this system is good for old simple games
; LSR ; where it taken, but when your se
; BCS _j_apu_se2_loop ; library grow, this may be a problem
; LSR _apu_se_idx_req
; BCS _j_apu_se4_start
; LSR
; BCS _j_apu_se4_loop
; LSR _apu_se_idx_req
; BCS _j_apu_se8_start
; LSR
; BCS _j_apu_se8_loop
; LSR _apu_se_idx_req
; BCS _j_apu_se10_start
; LSR
; BCS _j_apu_se10_loop
; LSR _apu_se_idx_req
; BCS _j_apu_se20_start
; LSR
; BCS _j_apu_se20_loop
; LSR _apu_se_idx_req
; BCS _j_apu_se40_start
; LSR
; BCS _j_apu_se40_loop
; LSR _apu_se_idx_req ; re-enable unused sound effect
; BCS _j_apu_se80_start
; LSR
; BCS _j_apu_se80_loop
; RTS
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se2_start:
; JMP _apu_se2_start
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se2_loop:
; JMP _apu_se2_loop
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se4_start:
; JMP _apu_se4_start
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se4_loop:
; JMP _apu_se4_loop
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se8_start:
; JMP _apu_se8_start
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se8_loop:
; JMP _apu_se8_loop
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se10_start:
; JMP _apu_se10_start
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se10_loop:
; JMP _apu_se10_loop
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se20_start:
; JMP _apu_se20_start
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se20_loop:
; JMP _apu_se20_loop
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se40_start:
; JMP _apu_se40_start
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se40_loop:
; JMP _apu_se40_loop
;
; FIX: re-enabled, TODO: find where it may be used
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se80_start:
; JMP _apu_se80_start
;
; =============== S U B R O U T I N E =======================================
;_j_apu_se80_loop:
; JMP _apu_se80_loop
; =============== S U B R O U T I N E =======================================
_apu_se1_start:
; STY _apu_se_loop_idx
LDA #$02
STA _apu_se_loop_counters
JSR _apu_p2_reset_tri_mute
LDA #$01
STA _APU_TRI_COUNT
LDA #$83
STA _APU_PULSE2_ENV
LDA #$7F
STA _APU_PULSE2_SWEEP
; =============== S U B R O U T I N E =======================================
_apu_se1_loop:
LDA #$6E
JSR _apu_tritime_load
LDA #$6E
JSR _apu_p2_time_load
DEC _apu_se_loop_counters
BNE locret_A4DC
JSR _apu_p2_reset
LDA #$00
STA _apu_se_loop_idx
locret_A4DC:
RTS
; =============== S U B R O U T I N E =======================================
_apu_se2_start:
; STY _apu_se_loop_idx
LDA #$18
STA _apu_se_loop_counters
JSR _apu_p2_reset_tri_mute
LDA #$01
STA _APU_TRI_COUNT
LDA #$7F
STA _APU_PULSE2_SWEEP
LDA #$96
STA _APU_PULSE2_ENV
; =============== S U B R O U T I N E =======================================
_apu_se2_loop:
LDY _apu_se_loop_counters
LDA byte_A51C,Y
STA _APU_TRI_TIME
BEQ loc_A505
LDA #$7C
LDX #$09
BNE loc_A507
loc_A505:
LDX #$08
loc_A507:
STA _APU_PULSE2_TIME
STX _APU_PULSE2_LEN
STX _APU_TRI_LEN
DEC _apu_se_loop_counters
BNE locret_A51B
LDA #$00
STA _apu_se_loop_idx
JMP _apu_p2_reset
locret_A51B:
RTS
byte_A51C:
.BYTE $D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$00,$00,$00,$00
.BYTE $00,$00,$D4,$D4,$D4,$D4,$D4,$D4
; =============== S U B R O U T I N E =======================================
_apu_se4_start:
; STY _apu_se_loop_idx
LDA #$03
STA _apu_se_loop_counters
JSR _apu_p2_reset_tri_mute
LDA #$01
STA _APU_TRI_COUNT
LDA #$83
STA _APU_PULSE2_ENV
; =============== S U B R O U T I N E =======================================
_apu_se4_loop:
LDY _apu_se_loop_counters
LDA byte_A5A3-1,Y
JSR _apu_tritime_load
LDY _apu_se_loop_counters
LDA byte_A5A3,Y
JSR _apu_p2_time_load
DEC _apu_se_loop_counters
BNE locret_A5A2
LDA #$00