-
Notifications
You must be signed in to change notification settings - Fork 0
/
famistudio_ca65.s
6609 lines (5816 loc) · 208 KB
/
famistudio_ca65.s
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
;======================================================================================================================
; FAMISTUDIO SOUND ENGINE (4.1.0)
; Copyright (c) 2019-2023 Mathieu Gauthier
;
; Copying and distribution of this file, with or without
; modification, are permitted in any medium without royalty provided
; the copyright notice and this notice are preserved in all source
; code copies. This file is offered as-is, without any warranty.
;======================================================================================================================
;======================================================================================================================
; This is the FamiStudio sound engine. It is used by the NSF and ROM exporter of FamiStudio and can be used to make
; games. It supports every feature from FamiStudio, some of them are toggeable to save CPU/memory.
;
; This is essentially a heavily modified version of FamiTone2 by Shiru. A lot of his code and comments are still
; present here, so massive thanks to him!! I am not trying to steal his work or anything, i renamed a lot of functions
; and variables because at some point it was becoming a mess of coding standards and getting hard to maintain.
;
; Moderately advanced users can probably figure out how to use the sound engine simply by reading these comments.
; For more in-depth documentation, please go to:
;
; https://famistudio.org/doc/soundengine/
;======================================================================================================================
;======================================================================================================================
; INTERFACE
; bzk список подпрограмм, для подробностей искать (public) вместе со скобками
;
; The interface is pretty much the same as FamiTone2, with a slightly different naming convention. The subroutines you
; can call from your game are:
;
; - famistudio_init : Initialize the engine with some music data.
; - famistudio_music_play : Start music playback with a specific song.
; - famistudio_music_pause : Pause/unpause music playback.
; - famistudio_music_stop : Stops music playback.
; - famistudio_sfx_init : Initialize SFX engine with SFX data.
; - famistudio_sfx_play : Play a SFX.
; - famistudio_sfx_sample_play : Play a DPCM SFX.
; - famistudio_update : Updates the music/SFX engine, call once per frame, ideally from NMI.
;
; You can check the demo ROM to see how they are used or check out the online documentation for more info.
;======================================================================================================================
;======================================================================================================================
; CONFIGURATION
;
; There are 2 main ways of configuring the engine.
;
; 1) The simplest way is right here, in the section below. Simply comment/uncomment these defines, and move on
; with your life.
;
; 2) The second way is "externally", using definitions coming from elsewhere in your app or the command line. If you
; wish do so, simply define FAMISTUDIO_CFG_EXTERNAL=1 and this whole section will be ignored. You are then
; responsible for providing all configuration. This is useful if you have multiple projects that needs
; different configurations, while pointing to the same code file. This is how the provided demos and FamiStudio
; uses it.
;
; Note that unless specified, the engine uses "if" and not "ifdef" for all boolean values so you need to define these
; to non-zero values. Undefined values will be assumed to be zero.
;
; There are 4 main things to configure, each of them will be detailed below.
;
; 1) Segments (ZP/RAM/PRG)
; 2) Audio expansion
; 3) Global engine parameters
; 4) Supported features
;======================================================================================================================
.ifndef FAMISTUDIO_CFG_EXTERNAL
FAMISTUDIO_CFG_EXTERNAL = 0
.endif
; Set this to configure the sound engine from outside (in your app, or from the command line)
.if !FAMISTUDIO_CFG_EXTERNAL
;======================================================================================================================
; 1) SEGMENT CONFIGURATION
;
; You need to tell where you want to allocate the zeropage, RAM and code. This section will be slightly different for
; each assembler.
;
; For CA65, you need to specify the name of your ZEROPAGE, RAM/BSS and CODE/PRG segments as c-style macros (.define)
; like the example below.
;======================================================================================================================
.define FAMISTUDIO_CA65_ZP_SEGMENT ZP_FS
.define FAMISTUDIO_CA65_RAM_SEGMENT RAM_FS
.define FAMISTUDIO_CA65_CODE_SEGMENT BANK_0E_FS
;======================================================================================================================
; 2) AUDIO EXPANSION CONFIGURATION
;
; You can enable up to one audio expansion (FAMISTUDIO_EXP_XXX). Enabling more than one expansion will lead to
; undefined behavior. Memory usage goes up as more complex expansions are used. The audio expansion you choose
; **MUST MATCH** with the data you will load in the engine. Loading a FDS song while enabling VRC6 will lead to
; undefined behavior.
;======================================================================================================================
; Konami VRC6 (2 extra square + saw)
; FAMISTUDIO_EXP_VRC6 = 1
; Konami VRC7 (6 FM channels)
; FAMISTUDIO_EXP_VRC7 = 1
; Nintendo MMC5 (2 extra squares, extra DPCM not supported)
; FAMISTUDIO_EXP_MMC5 = 1
; Sunsoft S5B (2 extra squares, advanced features not supported.)
; FAMISTUDIO_EXP_S5B = 1
; Famicom Disk System (extra wavetable channel)
; FAMISTUDIO_EXP_FDS = 1
; Namco 163 (between 1 and 8 extra wavetable channels) + number of channels.
; FAMISTUDIO_EXP_N163 = 1
; FAMISTUDIO_EXP_N163_CHN_CNT = 4
; EPSM (Expansion Port Sound Module)
; FAMISTUDIO_EXP_EPSM = 1
;======================================================================================================================
; 3) GLOBAL ENGINE CONFIGURATION
;
; These are parameters that configures the engine, but are independent of the data you will be importing, such as
; which platform (PAL/NTSC) you want to support playback for, whether SFX are enabled or not, etc. They all have the
; form FAMISTUDIO_CFG_XXX.
;======================================================================================================================
; One of these MUST be defined (PAL or NTSC playback). Note that only NTSC support is supported when using any of the audio expansions.
; FAMISTUDIO_CFG_PAL_SUPPORT = 1
FAMISTUDIO_CFG_NTSC_SUPPORT = 1
; Support for sound effects playback + number of SFX that can play at once.
; FAMISTUDIO_CFG_SFX_SUPPORT = 1
; FAMISTUDIO_CFG_SFX_STREAMS = 2
; Blaarg's smooth vibrato technique. Eliminates phase resets ("pops") on square channels.
; FAMISTUDIO_CFG_SMOOTH_VIBRATO = 1
; Enables DPCM playback support.
FAMISTUDIO_CFG_DPCM_SUPPORT = 1
; Must be enabled if you are calling sound effects from a different thread than the sound engine update.
; FAMISTUDIO_CFG_THREAD = 1
; Enable to use the CC65 compatible entrypoints via the provided header file
; FAMISTUDIO_CFG_C_BINDINGS = 1
;======================================================================================================================
; 4) SUPPORTED FEATURES CONFIGURATION
;
; Every feature supported in FamiStudio is supported by this sound engine. If you know for sure that you are not using
; specific features in your music, you can disable them to save memory/processing time. Using a feature in your song
; and failing to enable it will likely lead to crashes (BRK), or undefined behavior. They all have the form
; FAMISTUDIO_USE_XXX.
;======================================================================================================================
; Must be enabled if the songs you will be importing have been created using FamiTracker tempo mode. If you are using
; FamiStudio tempo mode, this must be undefined. You cannot mix and match tempo modes, the engine can only run in one
; mode or the other.
; More information at: https://famistudio.org/doc/song/#tempo-modes
; FAMISTUDIO_USE_FAMITRACKER_TEMPO = 1
; Must be enabled if the songs uses delayed notes or delayed cuts. This is obviously only available when using
; FamiTracker tempo mode as FamiStudio tempo mode does not need this.
; FAMISTUDIO_USE_FAMITRACKER_DELAYED_NOTES_OR_CUTS = 1
; Must be enabled if the songs uses release notes.
; More information at: https://famistudio.org/doc/pianoroll/#release-point
FAMISTUDIO_USE_RELEASE_NOTES = 1
; Must be enabled if any song uses the volume track. The volume track allows manipulating the volume at the track level
; independently from instruments.
; More information at: https://famistudio.org/doc/pianoroll/#editing-volume-tracks-effects
FAMISTUDIO_USE_VOLUME_TRACK = 1
; Must be enabled if any song uses slides on the volume track. Volume track must be enabled too.
; More information at: https://famistudio.org/doc/pianoroll/#editing-volume-tracks-effects
; FAMISTUDIO_USE_VOLUME_SLIDES = 1
; Must be enabled if any song uses the pitch track. The pitch track allows manipulating the pitch at the track level
; independently from instruments.
; More information at: https://famistudio.org/doc/pianoroll/#pitch
FAMISTUDIO_USE_PITCH_TRACK = 1
; Must be enabled if any song uses slide notes. Slide notes allows portamento and slide effects.
; More information at: https://famistudio.org/doc/pianoroll/#slide-notes
FAMISTUDIO_USE_SLIDE_NOTES = 1
; Must be enabled if any song uses slide notes on the noise channel too.
; More information at: https://famistudio.org/doc/pianoroll/#slide-notes
; FAMISTUDIO_USE_NOISE_SLIDE_NOTES = 1
; Must be enabled if any song uses the vibrato speed/depth effect track.
; More information at: https://famistudio.org/doc/pianoroll/#vibrato-depth-speed
FAMISTUDIO_USE_VIBRATO = 1
; Must be enabled if any song uses arpeggios (not to be confused with instrument arpeggio envelopes, those are always
; supported).
; More information at: (TODO)
FAMISTUDIO_USE_ARPEGGIO = 1
; Must be enabled if any song uses the "Duty Cycle" effect (equivalent of FamiTracker Vxx, also called "Timbre").
; FAMISTUDIO_USE_DUTYCYCLE_EFFECT = 1
; Must be enabled if any song uses the DPCM delta counter. Only makes sense if DPCM samples
; are enabled (FAMISTUDIO_CFG_DPCM_SUPPORT).
; More information at: (TODO)
; FAMISTUDIO_USE_DELTA_COUNTER = 1
; Must be enabled if your project uses more than 1 bank of DPCM samples.
; When using this, you must implement the "famistudio_dpcm_bank_callback" callback
; and switch to the correct bank every time a sample is played.
; FAMISTUDIO_USE_DPCM_BANKSWITCHING = 1
; Must be enabled if your project uses more than 63 unique DPCM mappings (a mapping is DPCM sample
; assigned to a note, with a specific pitch/loop, etc.). Implied when using FAMISTUDIO_USE_DPCM_BANKSWITCHING.
; FAMISTUDIO_USE_DPCM_EXTENDED_RANGE = 1
; Must be enabled if your project uses the "Phase Reset" effect.
; FAMISTUDIO_USE_PHASE_RESET = 1
.endif
; Memory location of the DPCM samples. Must be between $c000 and $ffc0, and a multiple of 64.
.ifndef FAMISTUDIO_DPCM_OFF
FAMISTUDIO_DPCM_OFF = $c000
.endif
;======================================================================================================================
; END OF CONFIGURATION
;
; Ideally, you should not have to change anything below this line.
;======================================================================================================================
;======================================================================================================================
; INTERNAL DEFINES (Do not touch)
;======================================================================================================================
.ifndef FAMISTUDIO_EXP_VRC6
FAMISTUDIO_EXP_VRC6 = 0
.endif
.ifndef FAMISTUDIO_EXP_VRC7
FAMISTUDIO_EXP_VRC7 = 0
.endif
.ifndef FAMISTUDIO_EXP_EPSM
FAMISTUDIO_EXP_EPSM = 0
.endif
.ifndef FAMISTUDIO_EXP_MMC5
FAMISTUDIO_EXP_MMC5 = 0
.endif
.ifndef FAMISTUDIO_EXP_S5B
FAMISTUDIO_EXP_S5B = 0
.endif
.ifndef FAMISTUDIO_EXP_FDS
FAMISTUDIO_EXP_FDS = 0
.endif
.ifndef FAMISTUDIO_EXP_N163
FAMISTUDIO_EXP_N163 = 0
.endif
.ifndef FAMISTUDIO_EXP_N163_CHN_CNT
FAMISTUDIO_EXP_N163_CHN_CNT = 1
.endif
.ifndef FAMISTUDIO_CFG_PAL_SUPPORT
FAMISTUDIO_CFG_PAL_SUPPORT = 0
.endif
.ifndef FAMISTUDIO_CFG_NTSC_SUPPORT
.if FAMISTUDIO_CFG_PAL_SUPPORT
FAMISTUDIO_CFG_NTSC_SUPPORT = 0
.else
FAMISTUDIO_CFG_NTSC_SUPPORT = 1
.endif
.endif
.if FAMISTUDIO_CFG_NTSC_SUPPORT && FAMISTUDIO_CFG_PAL_SUPPORT
FAMISTUDIO_DUAL_SUPPORT = 1
.else
FAMISTUDIO_DUAL_SUPPORT = 0
.endif
.ifndef FAMISTUDIO_CFG_SFX_SUPPORT
FAMISTUDIO_CFG_SFX_SUPPORT = 0
FAMISTUDIO_CFG_SFX_STREAMS = 0
.endif
.ifndef FAMISTUDIO_CFG_SFX_STREAMS
FAMISTUDIO_CFG_SFX_STREAMS = 1
.endif
.ifndef FAMISTUDIO_CFG_C_BINDINGS
FAMISTUDIO_CFG_C_BINDINGS = 0
.endif
.ifndef FAMISTUDIO_CFG_SMOOTH_VIBRATO
FAMISTUDIO_CFG_SMOOTH_VIBRATO = 0
.endif
.ifndef FAMISTUDIO_CFG_DPCM_SUPPORT
FAMISTUDIO_CFG_DPCM_SUPPORT = 0
.endif
.ifndef FAMISTUDIO_CFG_EQUALIZER
FAMISTUDIO_CFG_EQUALIZER = 0
.endif
.ifndef FAMISTUDIO_USE_FAMITRACKER_TEMPO
FAMISTUDIO_USE_FAMITRACKER_TEMPO = 0
.endif
.ifndef FAMISTUDIO_USE_FAMITRACKER_DELAYED_NOTES_OR_CUTS
FAMISTUDIO_USE_FAMITRACKER_DELAYED_NOTES_OR_CUTS = 0
.endif
.ifndef FAMISTUDIO_USE_VOLUME_TRACK
FAMISTUDIO_USE_VOLUME_TRACK = 0
.endif
.ifndef FAMISTUDIO_USE_VOLUME_SLIDES
FAMISTUDIO_USE_VOLUME_SLIDES = 0
.endif
.ifndef FAMISTUDIO_USE_PITCH_TRACK
FAMISTUDIO_USE_PITCH_TRACK = 0
.endif
.ifndef FAMISTUDIO_USE_SLIDE_NOTES
FAMISTUDIO_USE_SLIDE_NOTES = 0
.endif
.ifndef FAMISTUDIO_USE_NOISE_SLIDE_NOTES
FAMISTUDIO_USE_NOISE_SLIDE_NOTES = 0
.endif
.ifndef FAMISTUDIO_USE_VIBRATO
FAMISTUDIO_USE_VIBRATO = 0
.endif
.ifndef FAMISTUDIO_USE_ARPEGGIO
FAMISTUDIO_USE_ARPEGGIO = 0
.endif
.ifndef FAMISTUDIO_USE_DUTYCYCLE_EFFECT
FAMISTUDIO_USE_DUTYCYCLE_EFFECT = 0
.endif
.ifndef FAMISTUDIO_USE_DELTA_COUNTER
FAMISTUDIO_USE_DELTA_COUNTER = 0
.endif
.ifndef FAMISTUDIO_USE_PHASE_RESET
FAMISTUDIO_USE_PHASE_RESET = 0
.endif
.ifndef FAMISTUDIO_USE_RELEASE_NOTES
FAMISTUDIO_USE_RELEASE_NOTES = 0
.endif
.ifndef FAMISTUDIO_USE_DPCM_EXTENDED_RANGE
FAMISTUDIO_USE_DPCM_EXTENDED_RANGE = 0
.endif
.ifndef FAMISTUDIO_USE_DPCM_BANKSWITCHING
FAMISTUDIO_USE_DPCM_BANKSWITCHING = 0
.endif
.ifndef FAMISTUDIO_CFG_THREAD
FAMISTUDIO_CFG_THREAD = 0
.endif
.if (FAMISTUDIO_EXP_VRC6 + FAMISTUDIO_EXP_VRC7 + FAMISTUDIO_EXP_EPSM + FAMISTUDIO_EXP_MMC5 + FAMISTUDIO_EXP_S5B + FAMISTUDIO_EXP_FDS + FAMISTUDIO_EXP_N163) = 0
FAMISTUDIO_EXP_NONE = 1
.else
FAMISTUDIO_EXP_NONE = 0
.endif
.if (FAMISTUDIO_EXP_VRC7 + FAMISTUDIO_EXP_EPSM + FAMISTUDIO_EXP_N163 + FAMISTUDIO_EXP_FDS + FAMISTUDIO_EXP_S5B)
FAMISTUDIO_EXP_NOTE_START = 5
.endif
.if FAMISTUDIO_EXP_VRC6
FAMISTUDIO_EXP_NOTE_START = 7
.endif
.if FAMISTUDIO_USE_NOISE_SLIDE_NOTES && (FAMISTUDIO_USE_SLIDE_NOTES = 0)
.error "Noise slide notes can only be used when regular slide notes are enabled too."
.endif
.if FAMISTUDIO_USE_VOLUME_SLIDES && (FAMISTUDIO_USE_VOLUME_TRACK = 0)
.error "Volume slides can only be used when the volume track is enabled too."
.endif
.if FAMISTUDIO_USE_FAMITRACKER_DELAYED_NOTES_OR_CUTS && (FAMISTUDIO_USE_FAMITRACKER_TEMPO = 0)
.error "Delayed notes or cuts only make sense when using FamiTracker tempo."
.endif
.if (FAMISTUDIO_EXP_VRC6 + FAMISTUDIO_EXP_VRC7 + FAMISTUDIO_EXP_EPSM + FAMISTUDIO_EXP_MMC5 + FAMISTUDIO_EXP_S5B + FAMISTUDIO_EXP_FDS + FAMISTUDIO_EXP_N163) > 1
.error "Only one audio expansion can be enabled."
.endif
.if FAMISTUDIO_EXP_N163 && ((FAMISTUDIO_EXP_N163_CHN_CNT < 1) || (FAMISTUDIO_EXP_N163_CHN_CNT > 8))
.error "N163 only supports between 1 and 8 channels."
.endif
.if FAMISTUDIO_USE_DELTA_COUNTER && (FAMISTUDIO_CFG_DPCM_SUPPORT = 0)
.error "Delta counter only makes sense if DPCM samples are enabled."
.endif
.if FAMISTUDIO_USE_DPCM_BANKSWITCHING && (FAMISTUDIO_CFG_DPCM_SUPPORT = 0)
.error "DPCM bankswitching only makes sense if DPCM samples are enabled."
.endif
; This is the best way i found to test if a C-style macro is defined or not...
.if .xmatch(.string(FAMISTUDIO_CA65_ZP_SEGMENT), "FAMISTUDIO_CA65_ZP_SEGMENT")
.error "You must .define FAMISTUDIO_CA65_ZP_SEGMENT with the name of your zeropage segment."
.endif
.if .xmatch(.string(FAMISTUDIO_CA65_RAM_SEGMENT), "FAMISTUDIO_CA65_RAM_SEGMENT")
.error "You must .define FAMISTUDIO_CA65_RAM_SEGMENT with the name of your RAM/BSS segment."
.endif
.if .xmatch(.string(FAMISTUDIO_CA65_CODE_SEGMENT), "FAMISTUDIO_CA65_CODE_SEGMENT")
.error "You must .define FAMISTUDIO_CA65_CODE_SEGMENT with the name of your CODE/PRG segment."
.endif
FAMISTUDIO_DPCM_PTR = (FAMISTUDIO_DPCM_OFF & $3fff) >> 6
.if FAMISTUDIO_EXP_NONE
FAMISTUDIO_NUM_ENVELOPES = 3+3+2+3
FAMISTUDIO_NUM_PITCH_ENVELOPES = 3
FAMISTUDIO_NUM_CHANNELS = 5
FAMISTUDIO_NUM_DUTY_CYCLES = 3
.endif
.if FAMISTUDIO_EXP_VRC6
FAMISTUDIO_NUM_ENVELOPES = 3+3+2+3+3+3+3
FAMISTUDIO_NUM_PITCH_ENVELOPES = 6
FAMISTUDIO_NUM_CHANNELS = 8
FAMISTUDIO_NUM_DUTY_CYCLES = 6
.endif
.if FAMISTUDIO_EXP_VRC7
FAMISTUDIO_NUM_ENVELOPES = 3+3+2+3+2+2+2+2+2+2
FAMISTUDIO_NUM_PITCH_ENVELOPES = 9
FAMISTUDIO_NUM_CHANNELS = 11
FAMISTUDIO_NUM_DUTY_CYCLES = 3
.endif
.if FAMISTUDIO_EXP_EPSM
FAMISTUDIO_EXP_EPSM_CHANNELS = 15
FAMISTUDIO_NUM_ENVELOPES = 3+3+2+3+(FAMISTUDIO_EXP_EPSM_CHANNELS*2)+2+2+2
FAMISTUDIO_NUM_PITCH_ENVELOPES = 18
FAMISTUDIO_NUM_CHANNELS = 20
FAMISTUDIO_NUM_DUTY_CYCLES = 3
.endif
.if FAMISTUDIO_EXP_FDS
FAMISTUDIO_NUM_ENVELOPES = 3+3+2+3+2
FAMISTUDIO_NUM_PITCH_ENVELOPES = 4
FAMISTUDIO_NUM_CHANNELS = 6
FAMISTUDIO_NUM_DUTY_CYCLES = 3
.endif
.if FAMISTUDIO_EXP_MMC5
FAMISTUDIO_NUM_ENVELOPES = 3+3+2+3+3+3
FAMISTUDIO_NUM_PITCH_ENVELOPES = 5
FAMISTUDIO_NUM_CHANNELS = 7
FAMISTUDIO_NUM_DUTY_CYCLES = 5
.endif
.if FAMISTUDIO_EXP_N163
FAMISTUDIO_NUM_ENVELOPES = 3+3+2+3+(FAMISTUDIO_EXP_N163_CHN_CNT*3)
FAMISTUDIO_NUM_PITCH_ENVELOPES = 3+FAMISTUDIO_EXP_N163_CHN_CNT
FAMISTUDIO_NUM_CHANNELS = 5+FAMISTUDIO_EXP_N163_CHN_CNT
FAMISTUDIO_NUM_DUTY_CYCLES = 3
.endif
.if FAMISTUDIO_EXP_S5B
FAMISTUDIO_NUM_ENVELOPES = 3+3+2+3+4+4+4
FAMISTUDIO_NUM_PITCH_ENVELOPES = 6
FAMISTUDIO_NUM_CHANNELS = 8
FAMISTUDIO_NUM_DUTY_CYCLES = 3
.endif
.if FAMISTUDIO_EXP_NONE
FAMISTUDIO_NUM_VOLUME_SLIDES = 4
.else
FAMISTUDIO_NUM_VOLUME_SLIDES = FAMISTUDIO_NUM_CHANNELS ; DPCM volume is unused.
.endif
.if FAMISTUDIO_USE_NOISE_SLIDE_NOTES
FAMISTUDIO_NUM_SLIDES = FAMISTUDIO_NUM_PITCH_ENVELOPES + 1
.else
FAMISTUDIO_NUM_SLIDES = FAMISTUDIO_NUM_PITCH_ENVELOPES
.endif
; Keep the noise slide at the end so the pitch envelopes/slides are in sync.
FAMISTUDIO_NOISE_SLIDE_INDEX = FAMISTUDIO_NUM_SLIDES - 1
.if FAMISTUDIO_EXP_VRC6
FAMISTUDIO_VRC6_CH0_PITCH_ENV_IDX = 3
FAMISTUDIO_VRC6_CH1_PITCH_ENV_IDX = 4
FAMISTUDIO_VRC6_CH2_PITCH_ENV_IDX = 5
.endif
.if FAMISTUDIO_EXP_VRC7
FAMISTUDIO_VRC7_CH0_PITCH_ENV_IDX = 3
FAMISTUDIO_VRC7_CH1_PITCH_ENV_IDX = 4
FAMISTUDIO_VRC7_CH2_PITCH_ENV_IDX = 5
FAMISTUDIO_VRC7_CH3_PITCH_ENV_IDX = 6
FAMISTUDIO_VRC7_CH4_PITCH_ENV_IDX = 7
FAMISTUDIO_VRC7_CH5_PITCH_ENV_IDX = 8
.endif
.if FAMISTUDIO_EXP_FDS
FAMISTUDIO_FDS_CH0_PITCH_ENV_IDX = 3
.endif
.if FAMISTUDIO_EXP_MMC5
FAMISTUDIO_MMC5_CH0_PITCH_ENV_IDX = 3
FAMISTUDIO_MMC5_CH1_PITCH_ENV_IDX = 4
.endif
.if FAMISTUDIO_EXP_N163
FAMISTUDIO_N163_CH0_PITCH_ENV_IDX = 3
FAMISTUDIO_N163_CH1_PITCH_ENV_IDX = 4
FAMISTUDIO_N163_CH2_PITCH_ENV_IDX = 5
FAMISTUDIO_N163_CH3_PITCH_ENV_IDX = 6
FAMISTUDIO_N163_CH4_PITCH_ENV_IDX = 7
FAMISTUDIO_N163_CH5_PITCH_ENV_IDX = 8
FAMISTUDIO_N163_CH6_PITCH_ENV_IDX = 9
FAMISTUDIO_N163_CH7_PITCH_ENV_IDX = 10
.endif
.if FAMISTUDIO_EXP_S5B
FAMISTUDIO_S5B_CH0_PITCH_ENV_IDX = 3
FAMISTUDIO_S5B_CH1_PITCH_ENV_IDX = 4
FAMISTUDIO_S5B_CH2_PITCH_ENV_IDX = 5
.endif
.if FAMISTUDIO_EXP_EPSM
FAMISTUDIO_EPSM_CH0_PITCH_ENV_IDX = 3
FAMISTUDIO_EPSM_CH1_PITCH_ENV_IDX = 4
FAMISTUDIO_EPSM_CH2_PITCH_ENV_IDX = 5
FAMISTUDIO_EPSM_CH3_PITCH_ENV_IDX = 6
FAMISTUDIO_EPSM_CH4_PITCH_ENV_IDX = 7
FAMISTUDIO_EPSM_CH5_PITCH_ENV_IDX = 8
FAMISTUDIO_EPSM_CH6_PITCH_ENV_IDX = 9
FAMISTUDIO_EPSM_CH7_PITCH_ENV_IDX = 10
FAMISTUDIO_EPSM_CH8_PITCH_ENV_IDX = 11
FAMISTUDIO_EPSM_CH9_PITCH_ENV_IDX = 12
FAMISTUDIO_EPSM_CH10_PITCH_ENV_IDX = 13
FAMISTUDIO_EPSM_CH11_PITCH_ENV_IDX = 14
FAMISTUDIO_EPSM_CH12_PITCH_ENV_IDX = 15
FAMISTUDIO_EPSM_CH13_PITCH_ENV_IDX = 16
FAMISTUDIO_EPSM_CH14_PITCH_ENV_IDX = 17
.endif
; TODO: Investigate reshuffling the envelopes to keep them contiguously
; by type (all volumes envelopes, all arp envelopes, etc.) instead of
; by channel. This *may* simplify a lot of places where we need a lookup
; table (famistudio_channel_to_volume_env, etc.)
FAMISTUDIO_CH0_ENVS = 0
FAMISTUDIO_CH1_ENVS = 3
FAMISTUDIO_CH2_ENVS = 6
FAMISTUDIO_CH3_ENVS = 8
.if FAMISTUDIO_EXP_VRC6
FAMISTUDIO_VRC6_CH0_ENVS = 11
FAMISTUDIO_VRC6_CH1_ENVS = 14
FAMISTUDIO_VRC6_CH2_ENVS = 17
.endif
.if FAMISTUDIO_EXP_VRC7
FAMISTUDIO_VRC7_CH0_ENVS = 11
FAMISTUDIO_VRC7_CH1_ENVS = 13
FAMISTUDIO_VRC7_CH2_ENVS = 15
FAMISTUDIO_VRC7_CH3_ENVS = 17
FAMISTUDIO_VRC7_CH4_ENVS = 19
FAMISTUDIO_VRC7_CH5_ENVS = 21
.endif
.if FAMISTUDIO_EXP_FDS
FAMISTUDIO_FDS_CH0_ENVS = 11
.endif
.if FAMISTUDIO_EXP_MMC5
FAMISTUDIO_MMC5_CH0_ENVS = 11
FAMISTUDIO_MMC5_CH1_ENVS = 14
.endif
.if FAMISTUDIO_EXP_N163
FAMISTUDIO_N163_CH0_ENVS = 11
FAMISTUDIO_N163_CH1_ENVS = 14
FAMISTUDIO_N163_CH2_ENVS = 17
FAMISTUDIO_N163_CH3_ENVS = 20
FAMISTUDIO_N163_CH4_ENVS = 23
FAMISTUDIO_N163_CH5_ENVS = 26
FAMISTUDIO_N163_CH6_ENVS = 29
FAMISTUDIO_N163_CH7_ENVS = 32
.endif
.if FAMISTUDIO_EXP_S5B
FAMISTUDIO_S5B_CH0_ENVS = 11
FAMISTUDIO_S5B_CH1_ENVS = 15
FAMISTUDIO_S5B_CH2_ENVS = 19
.endif
.if FAMISTUDIO_EXP_EPSM
FAMISTUDIO_EPSM_CH0_ENVS = 11
FAMISTUDIO_EPSM_CH1_ENVS = 15
FAMISTUDIO_EPSM_CH2_ENVS = 19
FAMISTUDIO_EPSM_CH3_ENVS = 23
FAMISTUDIO_EPSM_CH4_ENVS = 25
FAMISTUDIO_EPSM_CH5_ENVS = 27
FAMISTUDIO_EPSM_CH6_ENVS = 29
FAMISTUDIO_EPSM_CH7_ENVS = 31
FAMISTUDIO_EPSM_CH8_ENVS = 33
FAMISTUDIO_EPSM_CH9_ENVS = 35
FAMISTUDIO_EPSM_CH10_ENVS = 37
FAMISTUDIO_EPSM_CH11_ENVS = 39
FAMISTUDIO_EPSM_CH12_ENVS = 41
FAMISTUDIO_EPSM_CH13_ENVS = 43
FAMISTUDIO_EPSM_CH14_ENVS = 45
.endif
FAMISTUDIO_ENV_VOLUME_OFF = 0
FAMISTUDIO_ENV_NOTE_OFF = 1
FAMISTUDIO_ENV_DUTY_OFF = 2
FAMISTUDIO_ENV_N163_WAVE_IDX_OFF = 2
FAMISTUDIO_ENV_MIXER_IDX_OFF = 2
FAMISTUDIO_ENV_NOISE_IDX_OFF = 3
.if FAMISTUDIO_EXP_VRC6
FAMISTUDIO_VRC6_CH0_DUTY_IDX = 3
FAMISTUDIO_VRC6_CH1_DUTY_IDX = 4
FAMISTUDIO_VRC6_CH2_DUTY_IDX = 5
.endif
.if FAMISTUDIO_EXP_MMC5
FAMISTUDIO_MMC5_CH0_DUTY_IDX = 3
FAMISTUDIO_MMC5_CH1_DUTY_IDX = 4
.endif
.if FAMISTUDIO_EXP_VRC6
FAMISTUDIO_VRC6_CH0_IDX = 5
FAMISTUDIO_VRC6_CH1_IDX = 6
FAMISTUDIO_VRC6_CH2_IDX = 7
.else
FAMISTUDIO_VRC6_CH0_IDX = -1
FAMISTUDIO_VRC6_CH1_IDX = -1
FAMISTUDIO_VRC6_CH2_IDX = -1
.endif
.if FAMISTUDIO_EXP_VRC7
FAMISTUDIO_VRC7_CH0_IDX = 5
FAMISTUDIO_VRC7_CH1_IDX = 6
FAMISTUDIO_VRC7_CH2_IDX = 7
FAMISTUDIO_VRC7_CH3_IDX = 8
FAMISTUDIO_VRC7_CH4_IDX = 9
FAMISTUDIO_VRC7_CH5_IDX = 10
.endif
.if FAMISTUDIO_EXP_FDS
FAMISTUDIO_FDS_CH0_IDX = 5
.endif
.if FAMISTUDIO_EXP_MMC5
FAMISTUDIO_MMC5_CH0_IDX = 5
FAMISTUDIO_MMC5_CH1_IDX = 6
.else
FAMISTUDIO_MMC5_CH0_IDX = -1
FAMISTUDIO_MMC5_CH1_IDX = -1
.endif
.if FAMISTUDIO_EXP_N163
FAMISTUDIO_N163_CH0_IDX = 5
FAMISTUDIO_N163_CH1_IDX = 6
FAMISTUDIO_N163_CH2_IDX = 7
FAMISTUDIO_N163_CH3_IDX = 8
FAMISTUDIO_N163_CH4_IDX = 9
FAMISTUDIO_N163_CH5_IDX = 10
FAMISTUDIO_N163_CH6_IDX = 11
FAMISTUDIO_N163_CH7_IDX = 12
.endif
.if FAMISTUDIO_EXP_S5B
FAMISTUDIO_S5B_CH0_IDX = 5
FAMISTUDIO_S5B_CH1_IDX = 6
FAMISTUDIO_S5B_CH2_IDX = 7
.endif
.if FAMISTUDIO_EXP_EPSM
FAMISTUDIO_EPSM_CH0_IDX = 5
FAMISTUDIO_EPSM_CH1_IDX = 6
FAMISTUDIO_EPSM_CH2_IDX = 7
FAMISTUDIO_EPSM_CHAN_FM_START = 8
FAMISTUDIO_EPSM_CH3_IDX = 8
FAMISTUDIO_EPSM_CH4_IDX = 9
FAMISTUDIO_EPSM_CH5_IDX = 10
FAMISTUDIO_EPSM_CH6_IDX = 11
FAMISTUDIO_EPSM_CH7_IDX = 12
FAMISTUDIO_EPSM_CH8_IDX = 13
FAMISTUDIO_EPSM_CHAN_RHYTHM_START = 14
FAMISTUDIO_EPSM_CH9_IDX = 14
FAMISTUDIO_EPSM_CH10_IDX = 15
FAMISTUDIO_EPSM_CH11_IDX = 16
FAMISTUDIO_EPSM_CH12_IDX = 17
FAMISTUDIO_EPSM_CH13_IDX = 18
FAMISTUDIO_EPSM_CH14_IDX = 19
.endif
FAMISTUDIO_VRC7_PITCH_SHIFT = 3
FAMISTUDIO_EPSM_PITCH_SHIFT = 3
.if (FAMISTUDIO_EXP_N163_CHN_CNT > 4)
FAMISTUDIO_N163_PITCH_SHIFT = 5
.endif
.if (FAMISTUDIO_EXP_N163_CHN_CNT > 2) & (FAMISTUDIO_EXP_N163_CHN_CNT <= 4)
FAMISTUDIO_N163_PITCH_SHIFT = 4
.endif
.if (FAMISTUDIO_EXP_N163_CHN_CNT > 1) & (FAMISTUDIO_EXP_N163_CHN_CNT <= 2)
FAMISTUDIO_N163_PITCH_SHIFT = 3
.endif
.if (FAMISTUDIO_EXP_N163_CHN_CNT = 1)
FAMISTUDIO_N163_PITCH_SHIFT = 2
.endif
.if FAMISTUDIO_EXP_VRC7
FAMISTUDIO_PITCH_SHIFT = FAMISTUDIO_VRC7_PITCH_SHIFT
.else
.if FAMISTUDIO_EXP_EPSM
FAMISTUDIO_PITCH_SHIFT = FAMISTUDIO_EPSM_PITCH_SHIFT
.else
.if FAMISTUDIO_EXP_N163
FAMISTUDIO_PITCH_SHIFT = FAMISTUDIO_N163_PITCH_SHIFT
.else
FAMISTUDIO_PITCH_SHIFT = 0
.endif
.endif
.endif
.if FAMISTUDIO_EXP_N163
FAMISTUDIO_N163_CHN_MASK = (FAMISTUDIO_EXP_N163_CHN_CNT - 1) << 4
.endif
.if FAMISTUDIO_CFG_SFX_SUPPORT
FAMISTUDIO_SFX_STRUCT_SIZE = 15
FAMISTUDIO_SFX_CH0 = FAMISTUDIO_SFX_STRUCT_SIZE * 0
FAMISTUDIO_SFX_CH1 = FAMISTUDIO_SFX_STRUCT_SIZE * 1
FAMISTUDIO_SFX_CH2 = FAMISTUDIO_SFX_STRUCT_SIZE * 2
FAMISTUDIO_SFX_CH3 = FAMISTUDIO_SFX_STRUCT_SIZE * 3
.endif
FAMISTUDIO_FIRST_EXP_INST_CHANNEL = 5
.if FAMISTUDIO_EXP_EPSM
FAMISTUDIO_FIRST_POSITIVE_SLIDE_CHANNEL = 6
.else
FAMISTUDIO_FIRST_POSITIVE_SLIDE_CHANNEL = 3
.endif
;======================================================================================================================
; RAM VARIABLES (You should not have to play with these)
;======================================================================================================================
.segment .string(FAMISTUDIO_CA65_RAM_SEGMENT)
famistudio_env_value: .res FAMISTUDIO_NUM_ENVELOPES
famistudio_env_repeat: .res FAMISTUDIO_NUM_ENVELOPES
famistudio_env_addr_lo: .res FAMISTUDIO_NUM_ENVELOPES
famistudio_env_addr_hi: .res FAMISTUDIO_NUM_ENVELOPES
famistudio_env_ptr: .res FAMISTUDIO_NUM_ENVELOPES
famistudio_pitch_env_value_lo: .res FAMISTUDIO_NUM_PITCH_ENVELOPES
famistudio_pitch_env_value_hi: .res FAMISTUDIO_NUM_PITCH_ENVELOPES
famistudio_pitch_env_repeat: .res FAMISTUDIO_NUM_PITCH_ENVELOPES
famistudio_pitch_env_addr_lo: .res FAMISTUDIO_NUM_PITCH_ENVELOPES
famistudio_pitch_env_addr_hi: .res FAMISTUDIO_NUM_PITCH_ENVELOPES
famistudio_pitch_env_ptr: .res FAMISTUDIO_NUM_PITCH_ENVELOPES
.if FAMISTUDIO_USE_PITCH_TRACK
famistudio_pitch_env_fine_value: .res FAMISTUDIO_NUM_PITCH_ENVELOPES
.endif
.if FAMISTUDIO_USE_SLIDE_NOTES
famistudio_slide_step: .res FAMISTUDIO_NUM_SLIDES
famistudio_slide_pitch_lo: .res FAMISTUDIO_NUM_SLIDES
famistudio_slide_pitch_hi: .res FAMISTUDIO_NUM_SLIDES
.endif
famistudio_chn_ptr_lo: .res FAMISTUDIO_NUM_CHANNELS
famistudio_chn_ptr_hi: .res FAMISTUDIO_NUM_CHANNELS
famistudio_chn_note: .res FAMISTUDIO_NUM_CHANNELS
famistudio_chn_instrument: .res FAMISTUDIO_NUM_CHANNELS
famistudio_chn_repeat: .res FAMISTUDIO_NUM_CHANNELS
famistudio_chn_return_lo: .res FAMISTUDIO_NUM_CHANNELS
famistudio_chn_return_hi: .res FAMISTUDIO_NUM_CHANNELS
famistudio_chn_ref_len: .res FAMISTUDIO_NUM_CHANNELS
.if FAMISTUDIO_USE_VOLUME_TRACK
famistudio_chn_volume_track: .res FAMISTUDIO_NUM_CHANNELS
.if FAMISTUDIO_USE_VOLUME_SLIDES
famistudio_chn_volume_slide_step: .res FAMISTUDIO_NUM_VOLUME_SLIDES
famistudio_chn_volume_slide_target: .res FAMISTUDIO_NUM_VOLUME_SLIDES
.endif
.endif
.if FAMISTUDIO_USE_VIBRATO || FAMISTUDIO_USE_ARPEGGIO
famistudio_chn_env_override: .res FAMISTUDIO_NUM_CHANNELS ; bit 7 = pitch, bit 0 = arpeggio.
.endif
.if FAMISTUDIO_USE_FAMITRACKER_DELAYED_NOTES_OR_CUTS
famistudio_chn_note_delay: .res FAMISTUDIO_NUM_CHANNELS
famistudio_chn_cut_delay: .res FAMISTUDIO_NUM_CHANNELS
.endif
.if FAMISTUDIO_EXP_N163 || FAMISTUDIO_EXP_VRC7 || FAMISTUDIO_EXP_FDS || FAMISTUDIO_EXP_EPSM
famistudio_chn_inst_changed: .res FAMISTUDIO_NUM_CHANNELS - FAMISTUDIO_FIRST_EXP_INST_CHANNEL
.endif
.if FAMISTUDIO_CFG_EQUALIZER
famistudio_chn_note_counter: .res FAMISTUDIO_NUM_CHANNELS
.endif
.if FAMISTUDIO_USE_PHASE_RESET
famistudio_phase_reset: .res 1 ; bit 0/1 = 2a03, bit 2/3/4 = vrc6, 5/6 = mmc5, bit 7 = fds
.if FAMISTUDIO_EXP_N163
famistudio_phase_reset_n163: .res 1 ; bit 0...7 = n163
.endif
.endif
.if FAMISTUDIO_USE_DELTA_COUNTER
famistudio_dmc_delta_counter: .res 1
.endif
.if FAMISTUDIO_EXP_VRC6
famistudio_vrc6_saw_volume: .res 1 ; -1 = 1/4, 0 = 1/2, 1 = Full
.endif
.if FAMISTUDIO_EXP_VRC7
famistudio_chn_vrc7_prev_hi: .res 6
famistudio_chn_vrc7_patch: .res 6
famistudio_chn_vrc7_trigger: .res 6 ; bit 0 = new note triggered, bit 7 = note released.
.endif
.if FAMISTUDIO_EXP_EPSM
famistudio_chn_epsm_trigger: .res 6 ; bit 0 = new note triggered, bit 7 = note released.
famistudio_chn_epsm_rhythm_key: .res 6
famistudio_chn_epsm_rhythm_stereo: .res 6
famistudio_chn_epsm_fm_stereo: .res 6
famistudio_chn_epsm_alg: .res 6
famistudio_chn_epsm_vol_op1: .res 6
famistudio_chn_epsm_vol_op2: .res 6
famistudio_chn_epsm_vol_op3: .res 6
famistudio_chn_epsm_vol_op4: .res 6
.endif
.if FAMISTUDIO_EXP_N163
famistudio_chn_n163_wave_index: .res FAMISTUDIO_EXP_N163_CHN_CNT
famistudio_chn_n163_wave_len: .res FAMISTUDIO_EXP_N163_CHN_CNT
.endif
.if FAMISTUDIO_USE_DUTYCYCLE_EFFECT
famistudio_duty_cycle: .res FAMISTUDIO_NUM_DUTY_CYCLES
.endif
.if FAMISTUDIO_USE_FAMITRACKER_TEMPO
famistudio_tempo_step_lo: .res 1
famistudio_tempo_step_hi: .res 1
famistudio_tempo_acc_lo: .res 1
famistudio_tempo_acc_hi: .res 1
.if FAMISTUDIO_USE_FAMITRACKER_DELAYED_NOTES_OR_CUTS
famistudio_tempo_advance_row: .res 1
.endif
.else
famistudio_tempo_env_ptr_lo: .res 1
famistudio_tempo_env_ptr_hi: .res 1
famistudio_tempo_env_counter: .res 1
famistudio_tempo_env_idx: .res 1
famistudio_tempo_frame_num: .res 1
famistudio_tempo_frame_cnt: .res 1
.endif
famistudio_pal_adjust: .res 1
famistudio_song_list_lo: .res 1
famistudio_song_list_hi: .res 1
famistudio_instrument_lo: .res 1
famistudio_instrument_hi: .res 1
famistudio_dpcm_list_lo: .res 1 ; TODO: Not needed if DPCM support is disabled.
famistudio_dpcm_list_hi: .res 1 ; TODO: Not needed if DPCM support is disabled.
famistudio_dpcm_effect: .res 1 ; TODO: Not needed if DPCM support is disabled.
famistudio_pulse1_prev: .res 1
famistudio_pulse2_prev: .res 1
famistudio_song_speed = famistudio_chn_instrument+4
.if FAMISTUDIO_EXP_MMC5
famistudio_mmc5_pulse1_prev: .res 1
famistudio_mmc5_pulse2_prev: .res 1
.endif
.if FAMISTUDIO_EXP_FDS
famistudio_fds_mod_speed: .res 2
famistudio_fds_mod_depth: .res 1
famistudio_fds_mod_delay: .res 1
famistudio_fds_override_flags: .res 1 ; Bit 7 = mod speed overriden, bit 6 mod depth overriden
.endif
.if FAMISTUDIO_EXP_VRC7
famistudio_vrc7_dummy: .res 1 ; TODO: Find a dummy address i can simply write to without side effects.
.endif
; FDS, N163 and VRC7 have very different instrument layout and are 16-bytes, so we keep them seperate.
.if FAMISTUDIO_EXP_FDS || FAMISTUDIO_EXP_N163 || FAMISTUDIO_EXP_VRC7 || FAMISTUDIO_EXP_EPSM || FAMISTUDIO_EXP_S5B
famistudio_exp_instrument_lo: .res 1
famistudio_exp_instrument_hi: .res 1
.endif
.if FAMISTUDIO_CFG_SFX_SUPPORT
famistudio_output_buf: .res 11
famistudio_sfx_addr_lo: .res 1
famistudio_sfx_addr_hi: .res 1
famistudio_sfx_base_addr: .res (FAMISTUDIO_CFG_SFX_STREAMS * FAMISTUDIO_SFX_STRUCT_SIZE)
; TODO: Refactor SFX memory layout. These uses a AoS approach, not fan.
famistudio_sfx_repeat = famistudio_sfx_base_addr + 0
famistudio_sfx_ptr_lo = famistudio_sfx_base_addr + 1
famistudio_sfx_ptr_hi = famistudio_sfx_base_addr + 2
famistudio_sfx_offset = famistudio_sfx_base_addr + 3
famistudio_sfx_buffer = famistudio_sfx_base_addr + 4
.endif
;======================================================================================================================
; ZEROPAGE VARIABLES
;
; These are only used as temporary variable during the famistudio_xxx calls.
; Feel free to alias those with other ZP values in your programs to save a few bytes.
;======================================================================================================================
.segment .string(FAMISTUDIO_CA65_ZP_SEGMENT) : zeropage
famistudio_r0: .res 1
famistudio_r1: .res 1
famistudio_r2: .res 1
famistudio_ptr0: .res 2
famistudio_ptr1: .res 2
famistudio_ptr0_lo = famistudio_ptr0+0
famistudio_ptr0_hi = famistudio_ptr0+1
famistudio_ptr1_lo = famistudio_ptr1+0
famistudio_ptr1_hi = famistudio_ptr1+1
;======================================================================================================================
; CODE
;======================================================================================================================
.export famistudio_init
.export famistudio_music_play
.export famistudio_music_pause
.export famistudio_music_stop
.export famistudio_update
.if FAMISTUDIO_CFG_SFX_SUPPORT
.if FAMISTUDIO_CFG_DPCM_SUPPORT
.export famistudio_sfx_sample_play
.endif
.export famistudio_sfx_init
.export famistudio_sfx_play
.exportzp FAMISTUDIO_SFX_CH0
.exportzp FAMISTUDIO_SFX_CH1
.exportzp FAMISTUDIO_SFX_CH2
.exportzp FAMISTUDIO_SFX_CH3
.endif
.if FAMISTUDIO_USE_DPCM_BANKSWITCHING
.global famistudio_dpcm_bank_callback
.endif
.segment .string(FAMISTUDIO_CA65_CODE_SEGMENT)
.org $8000
.byte con_bank_id + $0E ;
FAMISTUDIO_APU_PL1_VOL = $4000
FAMISTUDIO_APU_PL1_SWEEP = $4001
FAMISTUDIO_APU_PL1_LO = $4002
FAMISTUDIO_APU_PL1_HI = $4003
FAMISTUDIO_APU_PL2_VOL = $4004
FAMISTUDIO_APU_PL2_SWEEP = $4005
FAMISTUDIO_APU_PL2_LO = $4006
FAMISTUDIO_APU_PL2_HI = $4007
FAMISTUDIO_APU_TRI_LINEAR = $4008
FAMISTUDIO_APU_TRI_LO = $400a
FAMISTUDIO_APU_TRI_HI = $400b
FAMISTUDIO_APU_NOISE_VOL = $400c
FAMISTUDIO_APU_NOISE_LO = $400e
FAMISTUDIO_APU_NOISE_HI = $400f
FAMISTUDIO_APU_DMC_FREQ = $4010
FAMISTUDIO_APU_DMC_RAW = $4011
FAMISTUDIO_APU_DMC_START = $4012
FAMISTUDIO_APU_DMC_LEN = $4013
FAMISTUDIO_APU_SND_CHN = $4015
FAMISTUDIO_APU_FRAME_CNT = $4017
.if FAMISTUDIO_EXP_VRC6
FAMISTUDIO_VRC6_PL1_VOL = $9000
FAMISTUDIO_VRC6_PL1_LO = $9001
FAMISTUDIO_VRC6_PL1_HI = $9002
FAMISTUDIO_VRC6_PL2_VOL = $a000
FAMISTUDIO_VRC6_PL2_LO = $a001
FAMISTUDIO_VRC6_PL2_HI = $a002
FAMISTUDIO_VRC6_SAW_VOL = $b000
FAMISTUDIO_VRC6_SAW_LO = $b001
FAMISTUDIO_VRC6_SAW_HI = $b002
.endif
.if FAMISTUDIO_EXP_VRC7
FAMISTUDIO_VRC7_SILENCE = $e000
FAMISTUDIO_VRC7_REG_SEL = $9010
FAMISTUDIO_VRC7_REG_WRITE = $9030
FAMISTUDIO_VRC7_REG_LO_1 = $10
FAMISTUDIO_VRC7_REG_LO_2 = $11
FAMISTUDIO_VRC7_REG_LO_3 = $12
FAMISTUDIO_VRC7_REG_LO_4 = $13
FAMISTUDIO_VRC7_REG_LO_5 = $14
FAMISTUDIO_VRC7_REG_LO_6 = $15
FAMISTUDIO_VRC7_REG_HI_1 = $20
FAMISTUDIO_VRC7_REG_HI_2 = $21
FAMISTUDIO_VRC7_REG_HI_3 = $22
FAMISTUDIO_VRC7_REG_HI_4 = $23