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.
- package/AGENTS.md +19 -16
- package/CHANGELOG.md +184 -0
- package/README.md +5 -5
- package/examples/README.md +1 -0
- package/examples/gametank/templates/gt_draw.h +91 -0
- package/examples/gametank/templates/gt_hud.h +89 -0
- package/examples/gametank/templates/gt_palette.h +59 -0
- package/examples/gametank/templates/gt_sound.h +90 -0
- package/examples/gametank/templates/gt_sprites.h +53 -0
- package/examples/gametank/templates/platformer.c +318 -0
- package/examples/gametank/templates/puzzle.c +295 -0
- package/examples/gametank/templates/racing.c +139 -0
- package/examples/gametank/templates/shmup.c +277 -0
- package/examples/gametank/templates/sports.c +119 -0
- package/package.json +24 -22
- package/src/cores/capabilities.js +24 -0
- package/src/cores/registry.js +7 -1
- package/src/host/LibretroHost.js +90 -17
- package/src/host/callbacks.js +20 -2
- package/src/host/cpu-state.js +17 -0
- package/src/host/gametank-acp-state.js +53 -0
- package/src/http/skill-doc.js +10 -6
- package/src/mcp/tools/audio.js +1 -1
- package/src/mcp/tools/cart-parts.js +76 -0
- package/src/mcp/tools/lifecycle.js +1 -1
- package/src/mcp/tools/platform-tools.js +9 -1
- package/src/platforms/gametank/lib/gt/audio/acp_image.bin +0 -0
- package/src/platforms/gametank/lib/gt/audio/audio_coprocessor.c +55 -0
- package/src/platforms/gametank/lib/gt/audio/audio_coprocessor.h +34 -0
- package/src/platforms/gametank/lib/gt/audio/audio_fw.asm +223 -0
- package/src/platforms/gametank/lib/gt/audio/audio_fw_blob.s +8 -0
- package/src/platforms/gametank/lib/gt/audio/instruments.c +79 -0
- package/src/platforms/gametank/lib/gt/audio/instruments.h +25 -0
- package/src/platforms/gametank/lib/gt/audio/music.c +370 -0
- package/src/platforms/gametank/lib/gt/audio/music.h +35 -0
- package/src/platforms/gametank/lib/gt/audio/note_numbers.h +132 -0
- package/src/platforms/gametank/lib/gt/audio/scaled_sines.raw +0 -0
- package/src/platforms/gametank/lib/gt/audio/sine_256_-63_63.bin +0 -0
- package/src/platforms/gametank/lib/gt/banking.c +29 -0
- package/src/platforms/gametank/lib/gt/banking.h +8 -0
- package/src/platforms/gametank/lib/gt/banking2.s +41 -0
- package/src/platforms/gametank/lib/gt/crt0.s +102 -0
- package/src/platforms/gametank/lib/gt/draw_logo.s +55 -0
- package/src/platforms/gametank/lib/gt/feature/persist/persist.c +103 -0
- package/src/platforms/gametank/lib/gt/feature/persist/persist.h +13 -0
- package/src/platforms/gametank/lib/gt/feature/random/random.c +40 -0
- package/src/platforms/gametank/lib/gt/feature/random/random.h +18 -0
- package/src/platforms/gametank/lib/gt/feature/text/text.c +111 -0
- package/src/platforms/gametank/lib/gt/feature/text/text.h +25 -0
- package/src/platforms/gametank/lib/gt/gametank.c +12 -0
- package/src/platforms/gametank/lib/gt/gametank.h +80 -0
- package/src/platforms/gametank/lib/gt/gametank_logo.inc +393 -0
- package/src/platforms/gametank/lib/gt/gen/assets/assets_index.h +9 -0
- package/src/platforms/gametank/lib/gt/gen/assets/sdk_default.h +5 -0
- package/src/platforms/gametank/lib/gt/gen/bank_nums.h +11 -0
- package/src/platforms/gametank/lib/gt/gen/modules_enabled.h +4 -0
- package/src/platforms/gametank/lib/gt/gen/modules_enabled.inc +4 -0
- package/src/platforms/gametank/lib/gt/gfx/draw_direct.c +132 -0
- package/src/platforms/gametank/lib/gt/gfx/draw_direct.h +75 -0
- package/src/platforms/gametank/lib/gt/gfx/draw_queue.c +177 -0
- package/src/platforms/gametank/lib/gt/gfx/draw_queue.h +35 -0
- package/src/platforms/gametank/lib/gt/gfx/draw_util.s +157 -0
- package/src/platforms/gametank/lib/gt/gfx/gfx_sys.c +43 -0
- package/src/platforms/gametank/lib/gt/gfx/gfx_sys.h +46 -0
- package/src/platforms/gametank/lib/gt/gfx/sprites.c +216 -0
- package/src/platforms/gametank/lib/gt/gfx/sprites.h +41 -0
- package/src/platforms/gametank/lib/gt/init.c +9 -0
- package/src/platforms/gametank/lib/gt/input.c +26 -0
- package/src/platforms/gametank/lib/gt/input.h +20 -0
- package/src/platforms/gametank/lib/gt/interrupt.s +67 -0
- package/src/platforms/gametank/lib/gt/vectors.s +14 -0
- package/src/platforms/gametank/lib/gt/wait.s +53 -0
- package/src/playtest/playtest.js +174 -26
- package/src/toolchains/arm-none-eabi-gcc/gcc.js +39 -188
- package/src/toolchains/asar/asar.js +10 -15
- package/src/toolchains/cc65/cc65.js +82 -92
- package/src/toolchains/cc65/da65.js +12 -17
- package/src/toolchains/cc65/preset-resolver.js +13 -2
- package/src/toolchains/cc65/presets/gametank/gametank.h +80 -0
- package/src/toolchains/cc65/presets/gametank/sdk.cfg +32 -0
- package/src/toolchains/cc65/presets/gametank/sdk.crt0.s +61 -0
- package/src/toolchains/cc65/presets/gametank/sdk.vectors.s +11 -0
- package/src/toolchains/cc65/presets/gametank/single-bank.cfg +28 -0
- package/src/toolchains/cc65/presets/gametank/single-bank.crt0.s +71 -0
- package/src/toolchains/cc65/presets/gametank/single-bank.vectors.s +12 -0
- package/src/toolchains/common/c-build.js +109 -0
- package/src/toolchains/common/gcc-toolchain.js +164 -0
- package/src/toolchains/common/wasm-tool.js +101 -0
- package/src/toolchains/dasm/dasm.js +12 -18
- package/src/toolchains/gba-c/gba-c.js +253 -305
- package/src/toolchains/genesis-c/genesis-c.js +196 -225
- package/src/toolchains/index.js +58 -4
- package/src/toolchains/m68k-elf-gcc/gcc.js +39 -202
- package/src/toolchains/mips-c/mips-c.js +68 -78
- package/src/toolchains/mips-elf-gcc/gcc.js +55 -118
- package/src/toolchains/rgbds/rgbds.js +7 -19
- package/src/toolchains/sdcc/sdcc.js +35 -26
- package/src/toolchains/sh-c/sh-c.js +44 -52
- package/src/toolchains/sh-elf-gcc/gcc.js +55 -110
- package/src/toolchains/sjasm/sjasm.js +10 -14
- package/src/toolchains/snes-c/snes-c.js +125 -150
- package/src/toolchains/tcc816/tcc816.js +10 -15
- package/src/toolchains/vasm68k/vasm68k.js +11 -16
- package/src/toolchains/wladx/wladx.js +5 -17
- 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
|
+
}
|