romdevtools 0.71.1 → 0.84.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/AGENTS.md +19 -16
  2. package/CHANGELOG.md +184 -0
  3. package/README.md +5 -5
  4. package/examples/README.md +1 -0
  5. package/examples/gametank/templates/gt_draw.h +91 -0
  6. package/examples/gametank/templates/gt_hud.h +89 -0
  7. package/examples/gametank/templates/gt_palette.h +59 -0
  8. package/examples/gametank/templates/gt_sound.h +90 -0
  9. package/examples/gametank/templates/gt_sprites.h +53 -0
  10. package/examples/gametank/templates/platformer.c +318 -0
  11. package/examples/gametank/templates/puzzle.c +295 -0
  12. package/examples/gametank/templates/racing.c +139 -0
  13. package/examples/gametank/templates/shmup.c +277 -0
  14. package/examples/gametank/templates/sports.c +119 -0
  15. package/package.json +24 -22
  16. package/src/cores/capabilities.js +24 -0
  17. package/src/cores/registry.js +7 -1
  18. package/src/host/LibretroHost.js +90 -17
  19. package/src/host/callbacks.js +20 -2
  20. package/src/host/cpu-state.js +17 -0
  21. package/src/host/gametank-acp-state.js +53 -0
  22. package/src/http/skill-doc.js +10 -6
  23. package/src/mcp/tools/audio.js +1 -1
  24. package/src/mcp/tools/cart-parts.js +76 -0
  25. package/src/mcp/tools/lifecycle.js +1 -1
  26. package/src/mcp/tools/platform-tools.js +9 -1
  27. package/src/platforms/gametank/lib/gt/audio/acp_image.bin +0 -0
  28. package/src/platforms/gametank/lib/gt/audio/audio_coprocessor.c +55 -0
  29. package/src/platforms/gametank/lib/gt/audio/audio_coprocessor.h +34 -0
  30. package/src/platforms/gametank/lib/gt/audio/audio_fw.asm +223 -0
  31. package/src/platforms/gametank/lib/gt/audio/audio_fw_blob.s +8 -0
  32. package/src/platforms/gametank/lib/gt/audio/instruments.c +79 -0
  33. package/src/platforms/gametank/lib/gt/audio/instruments.h +25 -0
  34. package/src/platforms/gametank/lib/gt/audio/music.c +370 -0
  35. package/src/platforms/gametank/lib/gt/audio/music.h +35 -0
  36. package/src/platforms/gametank/lib/gt/audio/note_numbers.h +132 -0
  37. package/src/platforms/gametank/lib/gt/audio/scaled_sines.raw +0 -0
  38. package/src/platforms/gametank/lib/gt/audio/sine_256_-63_63.bin +0 -0
  39. package/src/platforms/gametank/lib/gt/banking.c +29 -0
  40. package/src/platforms/gametank/lib/gt/banking.h +8 -0
  41. package/src/platforms/gametank/lib/gt/banking2.s +41 -0
  42. package/src/platforms/gametank/lib/gt/crt0.s +102 -0
  43. package/src/platforms/gametank/lib/gt/draw_logo.s +55 -0
  44. package/src/platforms/gametank/lib/gt/feature/persist/persist.c +103 -0
  45. package/src/platforms/gametank/lib/gt/feature/persist/persist.h +13 -0
  46. package/src/platforms/gametank/lib/gt/feature/random/random.c +40 -0
  47. package/src/platforms/gametank/lib/gt/feature/random/random.h +18 -0
  48. package/src/platforms/gametank/lib/gt/feature/text/text.c +111 -0
  49. package/src/platforms/gametank/lib/gt/feature/text/text.h +25 -0
  50. package/src/platforms/gametank/lib/gt/gametank.c +12 -0
  51. package/src/platforms/gametank/lib/gt/gametank.h +80 -0
  52. package/src/platforms/gametank/lib/gt/gametank_logo.inc +393 -0
  53. package/src/platforms/gametank/lib/gt/gen/assets/assets_index.h +9 -0
  54. package/src/platforms/gametank/lib/gt/gen/assets/sdk_default.h +5 -0
  55. package/src/platforms/gametank/lib/gt/gen/bank_nums.h +11 -0
  56. package/src/platforms/gametank/lib/gt/gen/modules_enabled.h +4 -0
  57. package/src/platforms/gametank/lib/gt/gen/modules_enabled.inc +4 -0
  58. package/src/platforms/gametank/lib/gt/gfx/draw_direct.c +132 -0
  59. package/src/platforms/gametank/lib/gt/gfx/draw_direct.h +75 -0
  60. package/src/platforms/gametank/lib/gt/gfx/draw_queue.c +177 -0
  61. package/src/platforms/gametank/lib/gt/gfx/draw_queue.h +35 -0
  62. package/src/platforms/gametank/lib/gt/gfx/draw_util.s +157 -0
  63. package/src/platforms/gametank/lib/gt/gfx/gfx_sys.c +43 -0
  64. package/src/platforms/gametank/lib/gt/gfx/gfx_sys.h +46 -0
  65. package/src/platforms/gametank/lib/gt/gfx/sprites.c +216 -0
  66. package/src/platforms/gametank/lib/gt/gfx/sprites.h +41 -0
  67. package/src/platforms/gametank/lib/gt/init.c +9 -0
  68. package/src/platforms/gametank/lib/gt/input.c +26 -0
  69. package/src/platforms/gametank/lib/gt/input.h +20 -0
  70. package/src/platforms/gametank/lib/gt/interrupt.s +67 -0
  71. package/src/platforms/gametank/lib/gt/vectors.s +14 -0
  72. package/src/platforms/gametank/lib/gt/wait.s +53 -0
  73. package/src/playtest/playtest.js +174 -26
  74. package/src/toolchains/arm-none-eabi-gcc/gcc.js +39 -188
  75. package/src/toolchains/asar/asar.js +10 -15
  76. package/src/toolchains/cc65/cc65.js +82 -92
  77. package/src/toolchains/cc65/da65.js +12 -17
  78. package/src/toolchains/cc65/preset-resolver.js +13 -2
  79. package/src/toolchains/cc65/presets/gametank/gametank.h +80 -0
  80. package/src/toolchains/cc65/presets/gametank/sdk.cfg +32 -0
  81. package/src/toolchains/cc65/presets/gametank/sdk.crt0.s +61 -0
  82. package/src/toolchains/cc65/presets/gametank/sdk.vectors.s +11 -0
  83. package/src/toolchains/cc65/presets/gametank/single-bank.cfg +28 -0
  84. package/src/toolchains/cc65/presets/gametank/single-bank.crt0.s +71 -0
  85. package/src/toolchains/cc65/presets/gametank/single-bank.vectors.s +12 -0
  86. package/src/toolchains/common/c-build.js +109 -0
  87. package/src/toolchains/common/gcc-toolchain.js +164 -0
  88. package/src/toolchains/common/wasm-tool.js +101 -0
  89. package/src/toolchains/dasm/dasm.js +12 -18
  90. package/src/toolchains/gba-c/gba-c.js +253 -305
  91. package/src/toolchains/genesis-c/genesis-c.js +196 -225
  92. package/src/toolchains/index.js +58 -4
  93. package/src/toolchains/m68k-elf-gcc/gcc.js +39 -202
  94. package/src/toolchains/mips-c/mips-c.js +68 -78
  95. package/src/toolchains/mips-elf-gcc/gcc.js +55 -118
  96. package/src/toolchains/rgbds/rgbds.js +7 -19
  97. package/src/toolchains/sdcc/sdcc.js +35 -26
  98. package/src/toolchains/sh-c/sh-c.js +44 -52
  99. package/src/toolchains/sh-elf-gcc/gcc.js +55 -110
  100. package/src/toolchains/sjasm/sjasm.js +10 -14
  101. package/src/toolchains/snes-c/snes-c.js +125 -150
  102. package/src/toolchains/tcc816/tcc816.js +10 -15
  103. package/src/toolchains/vasm68k/vasm68k.js +11 -16
  104. package/src/toolchains/wladx/wladx.js +5 -17
  105. package/src/toolchains/z80/binutils.js +5 -11
@@ -0,0 +1,223 @@
1
+ DAC = $8000
2
+ AccBuf = $00
3
+ WavePTR = $02
4
+ WavePTR_MSB = $03
5
+ FeedbackAmount = $04
6
+ ;reserve $05
7
+ ;reserve $06
8
+ ;reserve $07
9
+ LastSample = $08
10
+ ;reserve $09
11
+ ;reserve $0A
12
+ ;reserve $0B
13
+ FreqsH = $10
14
+ FreqsL = $20
15
+ BufferedAmplitudes = $30
16
+ WaveStatesH = $50
17
+ WaveStatesL = $60
18
+ Inputs = $70
19
+ .zeropage
20
+ ;AccBuf
21
+ .byte 0, 0
22
+ ;WavePTR
23
+ .byte 0, 0
24
+ ;Feedback
25
+ .byte $80, $80, $80, $80
26
+ ;UNUSED
27
+ .repeat 8
28
+ .byte 0
29
+ .endrep
30
+ ;Frequencies
31
+ .repeat $20
32
+ .byte 0
33
+ .endrep
34
+ ;Amplitudes
35
+ .repeat $10
36
+ .byte $80
37
+ .endrep
38
+ ;Wave States
39
+ .repeat $80
40
+ .byte 0
41
+ .endrep
42
+
43
+ .code
44
+ RESET:
45
+ CLI
46
+ LDA #<Sine
47
+ STA WavePTR
48
+ LDA #>Sine
49
+ STA WavePTR+1
50
+ Forever:
51
+ WAI
52
+ JMP Forever
53
+
54
+ .macro tickWave op, out
55
+ CLC
56
+ LDA WaveStatesL+op
57
+ ADC FreqsL+op
58
+ STA WaveStatesL+op
59
+ LDA out
60
+ ADC FreqsH+op
61
+ STA out
62
+ .endmacro
63
+
64
+ .macro doChannel ch
65
+ .local Op1
66
+ .local Op1State
67
+ .local Op1Param
68
+ .local Op2
69
+ .local Op2Param
70
+ .local Op3
71
+ .local Op3Param
72
+ .local Op4
73
+ .local Op4Param
74
+ .local SaveFeedback
75
+ .local SampleFeedback
76
+ .local LastSample
77
+
78
+ LDA BufferedAmplitudes+(ch*4)+0
79
+ STA Op1+1
80
+ LDA BufferedAmplitudes+(ch*4)+1
81
+ STA Op2+1
82
+ LDA BufferedAmplitudes+(ch*4)+2
83
+ STA Op3+1
84
+ LDA BufferedAmplitudes+(ch*4)+3
85
+ STA Op4+1
86
+
87
+ tickWave (ch*4)+1, Op2Param+1
88
+ tickWave (ch*4)+2, Op3Param+1
89
+ tickWave (ch*4)+3, Op4Param+1
90
+
91
+ tickWave (ch * 4), Op1State+1
92
+ Op1State:
93
+ LDA #0
94
+ LastSample:
95
+ ADC #0
96
+
97
+ TAY
98
+ CLC
99
+ SampleFeedback:
100
+ ADC FeedbackAmount+ch
101
+ TAX
102
+ CLC
103
+ LDA Sine, y
104
+ ADC Sine, x
105
+
106
+ SaveFeedback:
107
+ STA LastSample+1
108
+ TYA
109
+
110
+ CLC
111
+ Op1:
112
+ ADC #0
113
+ TAX
114
+ CLC
115
+ LDA Sine, y
116
+ ADC Sine, x
117
+
118
+ CLC
119
+ Op2Param:
120
+ ADC #0
121
+ TAY
122
+ CLC
123
+ Op2:
124
+ ADC #0
125
+ TAX
126
+ CLC
127
+ LDA Sine, y
128
+ ADC Sine, x
129
+
130
+ CLC
131
+ Op3Param:
132
+ ADC #0
133
+ TAY
134
+ CLC
135
+ Op3:
136
+ ADC #0
137
+ TAX
138
+ CLC
139
+ LDA Sine, y
140
+ ADC Sine, x
141
+
142
+ CLC
143
+ Op4Param:
144
+ ADC #0
145
+ TAY
146
+ CLC
147
+ Op4:
148
+ ADC #0
149
+ TAX
150
+ CLC
151
+ LDA Sine, y
152
+ ADC Sine, x
153
+
154
+ CMP #$80
155
+ ROR
156
+ CMP #$80
157
+ ROR
158
+
159
+ CLC
160
+ ADC AccBuf
161
+ STA AccBuf
162
+ .endmacro
163
+
164
+ .macro GetSine
165
+ .local ScaleConstant
166
+ ; Returns sin(Acc + X) + sin(Acc - X)
167
+ TAY
168
+ STX ScaleConstant+1
169
+ CLC
170
+ ScaleConstant:
171
+ ADC #0
172
+ TAX
173
+ CLC
174
+ LDA Sine, y
175
+ ADC Sine, x
176
+ .endmacro
177
+
178
+
179
+ IRQ:
180
+ ;Clear sum buffer
181
+ STZ AccBuf
182
+
183
+ doChannel 0
184
+ doChannel 1
185
+ doChannel 2
186
+ doChannel 3
187
+
188
+ LDA AccBuf
189
+ CLC
190
+ ADC #$80
191
+ STA DAC
192
+
193
+ RTI ;6
194
+
195
+ ;Read inputs addr, val until addr=0
196
+ NMI_handler:
197
+ PHY
198
+ PHX
199
+ PHA
200
+ LDY #0
201
+ NMI_Loop:
202
+ LDX Inputs, y
203
+ BEQ NMI_Done
204
+ INY
205
+ LDA Inputs, y
206
+ STA $00, x
207
+ INY
208
+ JMP NMI_Loop
209
+
210
+ NMI_Done:
211
+ PLA
212
+ PLX
213
+ PLY
214
+ RTI
215
+
216
+ .segment "WAVES"
217
+ Sine:
218
+ .incbin "sine_256_-63_63.bin"
219
+
220
+ .segment "VECTORS"
221
+ .addr NMI_handler
222
+ .addr RESET
223
+ .addr IRQ
@@ -0,0 +1,8 @@
1
+ ; romdev single-bank GameTank: the ACP firmware embedded UNCOMPRESSED (the SDK
2
+ ; deflate-compresses it + inflatemem()s it; the bare path has no zopfli, so we
3
+ ; assemble audio_fw.asm to a raw 4 KB ACP image and memcpy it in). The build
4
+ ; stages the assembled image next to this file as acp_image.bin.
5
+ .export _AudioFWPkg
6
+ .segment "COMMON"
7
+ _AudioFWPkg:
8
+ .incbin "acp_image.bin"
@@ -0,0 +1,79 @@
1
+ #include "instruments.h"
2
+
3
+ const Instrument piano = {
4
+ 0x30, 0x40, 0x40, 0x5f,
5
+ 0x04, 0x02, 0x10, 0x02,
6
+ 0x04, 0x02, 0x10, 0x30,
7
+ 0, 0, 0, 0,
8
+ 0,
9
+ 0
10
+ };
11
+
12
+ const Instrument guitar = {
13
+ 0x6f, 0x40, 0x68, 0x5f, //initial amplitudes
14
+ 0x00, 0xFF, 0x02, 0x08, //decay rates
15
+ 0x00, 0x00, 0x40, 0x08, //sustain values
16
+ 12, 36, 0, 24, //per operator note offsets
17
+ 8, //feedback amount
18
+ -12 //channel note offset
19
+ };
20
+
21
+ const Instrument guitar2 = {
22
+ 0x60, 0x40, 0x88, 0x4f,
23
+ 0x00, 0xFF, 0x02, 0x01,
24
+ 0x00, 0x00, 0x40, 0x30,
25
+ 12, 36, 0, 24,
26
+ 8,
27
+ -12
28
+ };
29
+
30
+ const Instrument slapbass = {
31
+ 0x58, 0x88, 0x58, 0x5f,
32
+ 0x18, 0x08, 0x04, 0x02,
33
+ 0x18, 0x08, 0x04, 0x02,
34
+ 28, 12, 0, 12,
35
+ 0,
36
+ -24
37
+ };
38
+
39
+ const Instrument snare = {
40
+ 0x88, 0x8f, 0x8f, 0x38,
41
+ 0x18, 0x02, 0x04, 0x04,
42
+ 0x18, 0x08, 0x08, 0x04,
43
+ 36, 0, 0, 0,
44
+ 8,
45
+ -8
46
+ };
47
+
48
+ const Instrument sitar = {
49
+ 0x60, 0x40, 0x01, 0x10,
50
+ 0x00, 0xFF, 0xF8, 0xFF,
51
+ 0x00, 0x60, 0x60, 0x30,
52
+ 12, 36, 12, 24,
53
+ 4,
54
+ -24
55
+ };
56
+
57
+ const Instrument horn = {
58
+ 0x00, 0x00, 0x01, 0x10,
59
+ 0x00, 0x00, 0xFC, 0xFC,
60
+ 0x00, 0x00, 0x30, 0x50,
61
+ 12, 36, 12, 24,
62
+ 0,
63
+ -12
64
+ };
65
+
66
+ Instrument* instrument_table[] = {
67
+ (Instrument*) 0xFFFF,
68
+ &piano,
69
+ &guitar,
70
+ &guitar2,
71
+ &slapbass,
72
+ &snare,
73
+ &sitar,
74
+ &horn
75
+ };
76
+
77
+ Instrument* get_instrument_ptr(char idx) {
78
+ return instrument_table[idx];
79
+ }
@@ -0,0 +1,25 @@
1
+ #ifndef INSTRUMENTS_H
2
+ #define INSTRUMENTS_H
3
+
4
+ #include "audio_coprocessor.h"
5
+
6
+ typedef struct {
7
+ unsigned char env_initial[OPS_PER_CHANNEL];
8
+ unsigned char env_decay[OPS_PER_CHANNEL];
9
+ unsigned char env_sustain[OPS_PER_CHANNEL];
10
+ unsigned char op_transpose[OPS_PER_CHANNEL];
11
+ unsigned char feedback;
12
+ signed char transpose;
13
+ } Instrument;
14
+
15
+ #define INSTR_IDX_PIANO 1
16
+ #define INSTR_IDX_GUITAR 2
17
+ #define INSTR_IDX_DISTGUITAR 3
18
+ #define INSTR_IDX_SLAPBASS 4
19
+ #define INSTR_IDX_SNARE 5
20
+ #define INSTR_IDX_SITAR 6
21
+ #define INSTR_IDX_HORN 7
22
+
23
+ Instrument* get_instrument_ptr(char idx);
24
+
25
+ #endif
@@ -0,0 +1,370 @@
1
+ #include "music.h"
2
+ #include "gametank.h"
3
+ #include "note_numbers.h"
4
+ #include "banking.h"
5
+
6
+ #include "bank_nums.h"
7
+ #include "assets_index.h"
8
+
9
+ typedef struct music_state_t {
10
+ const unsigned char* cursor;
11
+ unsigned char bank;
12
+ unsigned char cfg; //file flags
13
+ unsigned char delay;
14
+ const unsigned char* repeat_ptr;
15
+ unsigned char flags; //playback flags
16
+ const Instrument* instruments[NUM_FM_CHANNELS];
17
+ } music_state_t;
18
+
19
+ #define MUSIC_STACK_SIZE 8
20
+
21
+ music_state_t music_state;
22
+ music_state_t music_stack[MUSIC_STACK_SIZE];
23
+ unsigned char music_stack_idx = 0;
24
+
25
+ void push_song_stack() {
26
+ music_stack[music_stack_idx++] = music_state;
27
+ if(music_stack_idx == MUSIC_STACK_SIZE) { music_stack_idx = 0; }
28
+ }
29
+
30
+ void pop_song_stack() {
31
+ if(music_stack_idx == 0) {
32
+ music_stack_idx = MUSIC_STACK_SIZE-1;
33
+ } else {
34
+ --music_stack_idx;
35
+ }
36
+ music_state = music_stack[music_stack_idx];
37
+ load_instrument(0, music_state.instruments[0]);
38
+ load_instrument(0, music_state.instruments[1]);
39
+ load_instrument(0, music_state.instruments[2]);
40
+ load_instrument(0, music_state.instruments[3]);
41
+ }
42
+
43
+ unsigned char channel_masks[NUM_FM_CHANNELS] = {1, 2, 4, 8};
44
+ signed char channel_note_offset[NUM_FM_CHANNELS] = {0, 0, 0, 0};
45
+ unsigned char audio_amplitudes[NUM_FM_OPS] = { 0, 0, 0, 0,
46
+ 0, 0, 0, 0,
47
+ 0, 0, 0, 0,
48
+ 0, 0, 0, 0 };
49
+ unsigned char env_initial[NUM_FM_OPS] = { 0x00, 0x00, 0x00, 0x00,
50
+ 0x00, 0x00, 0x00, 0x00,
51
+ 0x00, 0x00, 0x00, 0x00,
52
+ 0x00, 0x00, 0x00, 0x00 };
53
+ unsigned char env_decay[NUM_FM_OPS] = { 0x00, 0x00, 0x00, 0x00,
54
+ 0x00, 0x00, 0x00, 0x00,
55
+ 0x00, 0x00, 0x00, 0x00,
56
+ 0x00, 0x00, 0x00, 0x00 };
57
+ unsigned char env_sustain[NUM_FM_OPS] = { 0x00, 0x00, 0x00, 0x00,
58
+ 0x00, 0x00, 0x00, 0x00,
59
+ 0x00, 0x00, 0x00, 0x00,
60
+ 0x00, 0x00, 0x00, 0x00 };
61
+
62
+ unsigned char op_transpose[NUM_FM_OPS] = { 0, 0, 0, 0,
63
+ 28, 12, 0, 19,
64
+ 36, 0, 0, 0,
65
+ 0, 0, 0, 0 };
66
+
67
+ #define MUSIC_CFG_VELOCITY 1
68
+ #define MUSIC_CFG_PROGCHANGE 2
69
+
70
+ #define MUSIC_FLAG_POP_AT_END 1
71
+
72
+ const unsigned char* paused_cursor = 0;
73
+ unsigned char paused_bank = 0;
74
+ unsigned char paused_cfg = 0;
75
+ unsigned char paused_delay;
76
+ unsigned char music_mode = REPEAT_NONE;
77
+
78
+ unsigned char music_channel_mask;
79
+ unsigned char percussion_channel_mask;
80
+ unsigned char note_held_mask;
81
+ const unsigned char* sound_effect_ptr[NUM_FM_CHANNELS];
82
+ unsigned char sound_effect_bank[NUM_FM_CHANNELS];
83
+ unsigned char sound_effect_length[NUM_FM_CHANNELS];
84
+ unsigned char saved_feedback_value[NUM_FM_CHANNELS];
85
+ unsigned char sound_effect_priority[NUM_FM_CHANNELS];
86
+
87
+ void init_music() {
88
+ char i;
89
+ music_stack_idx = 0;
90
+ music_state.cursor = 0;
91
+ music_state.delay = 0;
92
+ music_channel_mask = 255;
93
+ note_held_mask = 0;
94
+ for(i = 0; i < NUM_FM_CHANNELS; ++i) {
95
+ sound_effect_length[i] = 0;
96
+ sound_effect_priority[i] = 0;
97
+ }
98
+ stop_music();
99
+ }
100
+
101
+ void load_instrument(char channel, const Instrument* instr) {
102
+ if(instr == ((Instrument*) 0xFFFF)) {
103
+ percussion_channel_mask |= channel_masks[channel];
104
+ return;
105
+ }
106
+ percussion_channel_mask &= ~channel_masks[channel];
107
+ music_state.instruments[channel] = instr;
108
+ channel_note_offset[channel] = instr->transpose;
109
+ aram[FEEDBACK_AMT + channel] = (instr->feedback << 3) + 128;
110
+ channel = channel << 2;
111
+ env_initial[channel] = instr->env_initial[0];
112
+ env_decay[channel] = instr->env_decay[0];
113
+ env_sustain[channel] = instr->env_sustain[0];
114
+ op_transpose[channel] = instr->op_transpose[0];
115
+ ++channel;
116
+ env_initial[channel] = instr->env_initial[1];
117
+ env_decay[channel] = instr->env_decay[1];
118
+ env_sustain[channel] = instr->env_sustain[1];
119
+ op_transpose[channel] = instr->op_transpose[1];
120
+ ++channel;
121
+ env_initial[channel] = instr->env_initial[2];
122
+ env_decay[channel] = instr->env_decay[2];
123
+ env_sustain[channel] = instr->env_sustain[2];
124
+ op_transpose[channel] = instr->op_transpose[2];
125
+ ++channel;
126
+ env_initial[channel] = instr->env_initial[3];
127
+ env_decay[channel] = instr->env_decay[3];
128
+ env_sustain[channel] = instr->env_sustain[3];
129
+ op_transpose[channel] = instr->op_transpose[3];
130
+ }
131
+
132
+ char n_mul;
133
+ void set_note(char ch, char n) {
134
+ n_mul = op_transpose[ch] + n;
135
+ n_mul += n_mul;
136
+ set_audio_param(PITCH_MSB + ch, pitch_table[n_mul]);
137
+ set_audio_param(PITCH_LSB + ch, pitch_table[n_mul + 1]);
138
+ ++ch;
139
+ n_mul = op_transpose[ch] + n;
140
+ n_mul += n_mul;
141
+ set_audio_param(PITCH_MSB + ch, pitch_table[n_mul]);
142
+ set_audio_param(PITCH_LSB + ch, pitch_table[n_mul + 1]);
143
+ ++ch;
144
+ n_mul = op_transpose[ch] + n;
145
+ n_mul += n_mul;
146
+ set_audio_param(PITCH_MSB + ch, pitch_table[n_mul]);
147
+ set_audio_param(PITCH_LSB + ch, pitch_table[n_mul + 1]);
148
+ ++ch;
149
+ n_mul = op_transpose[ch] + n;
150
+ n_mul += n_mul;
151
+ set_audio_param(PITCH_MSB + ch, pitch_table[n_mul]);
152
+ set_audio_param(PITCH_LSB + ch, pitch_table[n_mul + 1]);
153
+ }
154
+
155
+ void play_song(const unsigned char* song, char bank_num, char loop) {
156
+ char n;
157
+ push_song_stack();
158
+ music_state.bank = bank_num;
159
+ push_rom_bank();
160
+ change_rom_bank(music_state.bank);
161
+ music_state.cursor = song;
162
+
163
+ for(n = 0; n < NUM_FM_OPS; ++n) {
164
+ audio_amplitudes[n] = 0;
165
+ set_audio_param(AMPLITUDE+n, 128);
166
+ }
167
+
168
+ switch(loop) {
169
+ case REPEAT_NONE:
170
+ music_state.repeat_ptr = 0;
171
+ music_mode = REPEAT_NONE;
172
+ music_state.flags = 0;
173
+ break;
174
+ case REPEAT_LOOP:
175
+ music_state.repeat_ptr = music_state.cursor;
176
+ music_mode = REPEAT_LOOP;
177
+ music_state.flags = 0;
178
+ break;
179
+ case REPEAT_RESUME:
180
+ music_state.flags = MUSIC_FLAG_POP_AT_END;
181
+ break;
182
+ }
183
+
184
+ if(music_state.cursor) {
185
+ percussion_channel_mask = 0;
186
+ music_state.cfg = *(music_state.cursor++);
187
+ load_instrument(0, get_instrument_ptr(*(music_state.cursor++)));
188
+ load_instrument(1, get_instrument_ptr(*(music_state.cursor++)));
189
+ load_instrument(2, get_instrument_ptr(*(music_state.cursor++)));
190
+ load_instrument(3, get_instrument_ptr(*(music_state.cursor++)));
191
+ music_state.delay = *(music_state.cursor++);
192
+ }
193
+
194
+ pop_rom_bank();
195
+ }
196
+
197
+ void pause_music() {
198
+ push_song_stack();
199
+ music_state.cursor = 0;
200
+ note_held_mask = 0;
201
+ }
202
+
203
+ void unpause_music() {
204
+ pop_song_stack();
205
+ }
206
+
207
+ void tick_music() {
208
+ static unsigned char n, noteMask, ch;
209
+ register unsigned char a, op;
210
+ push_rom_bank();
211
+ for(n = 0; n < NUM_FM_CHANNELS; ++n) {
212
+ if(sound_effect_length[n]) {
213
+ --sound_effect_length[n];
214
+ if(sound_effect_length[n]) {
215
+
216
+ change_rom_bank(sound_effect_bank[n]);
217
+
218
+ op = n << 2;
219
+ set_audio_param(AMPLITUDE + op, (*(sound_effect_ptr[n]+0) << 3) + 128);
220
+ a = *(sound_effect_ptr[n]+4) << 1;
221
+ set_audio_param(PITCH_MSB + op, pitch_table[a]);
222
+ set_audio_param(PITCH_LSB + op, pitch_table[a+1]);
223
+
224
+ ++op;
225
+ set_audio_param(AMPLITUDE + op, (*(sound_effect_ptr[n]+1) << 3) + 128);
226
+ a = *(sound_effect_ptr[n]+5) << 1;
227
+ set_audio_param(PITCH_MSB + op, pitch_table[a]);
228
+ set_audio_param(PITCH_LSB + op, pitch_table[a+1]);
229
+
230
+ ++op;
231
+ set_audio_param(AMPLITUDE + op, (*(sound_effect_ptr[n]+2) << 3) + 128);
232
+ a = *(sound_effect_ptr[n]+6) << 1;
233
+ set_audio_param(PITCH_MSB + op, pitch_table[a]);
234
+ set_audio_param(PITCH_LSB + op, pitch_table[a+1]);
235
+
236
+ ++op;
237
+ set_audio_param(AMPLITUDE + op, (*(sound_effect_ptr[n]+3) << 3) + 128);
238
+ a = *(sound_effect_ptr[n]+7) << 1;
239
+ set_audio_param(PITCH_MSB + op, pitch_table[a]);
240
+ set_audio_param(PITCH_LSB + op, pitch_table[a+1]);
241
+
242
+ sound_effect_ptr[n] += 8;
243
+
244
+ } else {
245
+ op = n << 2;
246
+ set_audio_param(AMPLITUDE+(op+3), 128);
247
+ aram[FEEDBACK_AMT + n] = saved_feedback_value[n];
248
+ music_channel_mask |= channel_masks[n];
249
+ sound_effect_priority[n] = 0;
250
+ }
251
+ }
252
+ }
253
+
254
+ change_rom_bank(music_state.bank);
255
+ op = 0;
256
+ for(ch = 1; ch < 16; ch = ch << 1) {
257
+ if(ch & ~(music_channel_mask & note_held_mask)) {
258
+ op+=4;
259
+ continue;
260
+ }
261
+ for(a = 0; a < 4; ++a) {
262
+ if(((env_sustain[op] - audio_amplitudes[op]) ^ (env_decay[op])) & 0x80) {
263
+ audio_amplitudes[op] -= env_decay[op];
264
+ } else {
265
+ audio_amplitudes[op] = env_sustain[op];
266
+ }
267
+ set_audio_param(AMPLITUDE+op, (audio_amplitudes[op] >> 1) + 128);
268
+ ++op;
269
+ }
270
+ }
271
+
272
+ if(music_state.cursor) {
273
+ loadAudioEvent:
274
+ if(music_state.delay > 0) {
275
+ music_state.delay--;
276
+ } else {
277
+ noteMask = *(music_state.cursor++);
278
+ for(ch = 0; ch < NUM_FM_CHANNELS; ++ch) {
279
+ if(channel_masks[ch] & noteMask) {
280
+ n = *(music_state.cursor++);
281
+ if(music_state.cfg & MUSIC_CFG_VELOCITY)
282
+ a = *(music_state.cursor++);
283
+ if(channel_masks[ch] & percussion_channel_mask) {
284
+ if(n > 0) play_sound_effect(n - 1, ch);
285
+ } else if(channel_masks[ch] & music_channel_mask) {
286
+ op = ch << 2;
287
+ if(n > 0) {
288
+
289
+ set_note(op, n + channel_note_offset[ch]);
290
+ audio_amplitudes[op] = env_initial[op];
291
+ set_audio_param(AMPLITUDE+op, (audio_amplitudes[op] >> 1) + 128);
292
+ ++op;
293
+ audio_amplitudes[op] = env_initial[op];
294
+ set_audio_param(AMPLITUDE+op, (audio_amplitudes[op] >> 1) + 128);
295
+ ++op;
296
+ audio_amplitudes[op] = env_initial[op];
297
+ set_audio_param(AMPLITUDE+op, (audio_amplitudes[op] >> 1) + 128);
298
+ ++op;
299
+ if(music_state.cfg & MUSIC_CFG_VELOCITY)
300
+ audio_amplitudes[op] = a;
301
+ else
302
+ audio_amplitudes[op] = env_initial[op];
303
+ set_audio_param(AMPLITUDE+op, (audio_amplitudes[op] >> 1) + 128);
304
+ } else {
305
+ audio_amplitudes[op+3] = 0;
306
+ set_audio_param(AMPLITUDE+op+3, 128);
307
+ }
308
+ }
309
+ if(n) {
310
+ note_held_mask |= channel_masks[ch];
311
+ } else {
312
+ note_held_mask &= ~channel_masks[ch];
313
+ }
314
+ }
315
+ }
316
+ music_state.delay = *(music_state.cursor++);
317
+ if(music_state.delay == 0) {
318
+ if(music_state.flags & MUSIC_FLAG_POP_AT_END) {
319
+ pop_song_stack();
320
+ } else {
321
+ music_state.cursor = music_state.repeat_ptr;
322
+ if(music_state.cursor) {
323
+ music_state.cursor+=5; //skip cfg and instruments
324
+ music_state.delay = *(music_state.cursor++);
325
+ goto loadAudioEvent;
326
+ } else {
327
+ silence_all_channels();
328
+ }
329
+ }
330
+ } else {
331
+ --music_state.delay;
332
+ }
333
+ }
334
+ }
335
+
336
+ flush_audio_params();
337
+ pop_rom_bank();
338
+ }
339
+
340
+ void silence_all_channels() {
341
+ char n;
342
+ for(n = 0; n < NUM_FM_OPS; ++n) {
343
+ audio_amplitudes[n] = 0;
344
+ set_audio_param(AMPLITUDE+n, 128);
345
+ }
346
+ note_held_mask = 0;
347
+ }
348
+
349
+ void stop_music() {
350
+ music_state.cursor = 0;
351
+ silence_all_channels();
352
+ }
353
+
354
+ void play_sound_effect(char sfx_id, char channel) {
355
+ static char priority;
356
+ priority = channel & 0xF0;
357
+ channel &= 0x03;
358
+ if(priority < sound_effect_priority[channel]) return;
359
+ sound_effect_priority[channel] = priority;
360
+ push_rom_bank();
361
+ change_rom_bank(BANK_LOADERS);
362
+ sound_effect_bank[channel] = ASSET__sfx_bank_table[sfx_id];
363
+ sound_effect_ptr[channel] = ASSET__sfx_ptr_table[sfx_id];
364
+ change_rom_bank(sound_effect_bank[channel]);
365
+ sound_effect_length[channel] = *(sound_effect_ptr[channel]++) + 1;
366
+ saved_feedback_value[channel] = aram[FEEDBACK_AMT + channel];
367
+ aram[FEEDBACK_AMT + channel] = *(sound_effect_ptr[channel]++);
368
+ music_channel_mask &= ~(channel_masks[channel]);
369
+ pop_rom_bank();
370
+ }