-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathADVM1.asm
More file actions
424 lines (372 loc) · 9.06 KB
/
ADVM1.asm
File metadata and controls
424 lines (372 loc) · 9.06 KB
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
; ///////////////////////////////////////////////////////////////
; ____________ __ ______ ____ ____ __++++++__
; / | __ \| | / / \ / |/_ | | @ |
; / /| | | \ \ | / / \/ | | | | ------ |
; / /_| | | | | |/ /| |\ /| | | | | | | |
; / ___ | | | | / | | \ / | | | | | | | |
; / / | | |__/ / / | | \/ | |__| |__ | ------ |
; /__/ |__|_______/|___/ |__| |__|________| | _+_ o o |
; Audio Driver for (dreamcast) VMu (Variant 1) | + O O |
; jvsTSX / 2024 --______--
; ///////////////////////////////////////////////////////////////
;
; - Special thanks to Tildearrow for the duty formula
; - And the dreamcast community for incentivating this project
; - This sound driver is derivate from ADPM, but heavily cut down to
; suit the ultra slow nature of the VMU Quartz mode, forcing me to
; trade off complexity for faster playback rates, ADVM2 will instead
; focus on general complexity like ADPM as 1MHz mode is far more flexible
; >>> Features <<<
; - F-0 trough C-5 frequency range, thanks to Timer 1 Mode 3 clock double mode
; - PWM and SPM parameters, SPM being exclusive to Timer 1 Mode 3
; - up to 255 phrases, each phrase being variable length with effectively no limit
; - per-phrase transposition for effective data reusage
; - Nothing else really... all Block B automations had to be stripped off
; - But you still get a SFX Sub-driver
; >>> Resource Usage <<<
; RAM usage:
; Music - 18 bytes
; SFX - 6 bytes
; Size in Flash:
; Music - 291 bytes (driver) + 41 bytes (setup)
; SFX - 83 bytes
; Cycle Timing (Worst Case):
; Music -
; SFX -
; Cycle Timing (Common Case):
; Music -
; SFX -
; /////////////////////////////////////////////////////////////
; /// SETUP PROGRAM ///
; /////////////////////////////////////////////////////////////
; dw time line position
; dw phrase index list position
_ADVM1_SETUP:
xor ACC
st A1R_TmlPos
st A1R_CurrNote
st A1R_PWM
st A1R_SPM
st A1R_TspOld
ldc
st A1RH_TmlBaseL
mov #1, ACC
st A1R_RowsWait
ldc
st A1RH_TmlBaseH
mov #2, ACC
ldc
st A1RH_PhrIndxL
mov #3, ACC
ldc
st A1RH_PhrIndxH
mov #$FF, A1R_SFXReq
jmpf A1L_StepTmLine
; /////////////////////////////////////////////////////////////
; /// SFX PLAY BLOCK ///
; /////////////////////////////////////////////////////////////
_ADVM1_SFX:
; ESPNWWWW (WW) (NN) (PP) (SS)
; SFX are organized like groove table on ADVM2, across a single 256-byte table
ld A1R_SFXReq
be #$FF, .SfxExit ; if off exit
be #$FE, .SfxPlaying
st A1R_SFXPos ; or else setup new SFX
mov #1, A1R_SFXWait
mov #$FE, A1R_SFXReq
.SfxPlaying:
mov #%01110000, T1CNT ; force 2x mode
dec A1R_SFXWait
ld A1R_SFXWait
bnz .SfxExit
ld A1RH_SFXListL
st TRL
ld A1RH_SFXListH
st TRH
ld A1R_SFXPos
ldc
st B ; SFX header
and #%00001111 ; wait value (in frames)
bnz .NormalWait
inc A1R_SFXPos
ld A1R_SFXPos
ldc
.NormalWait:
st A1R_SFXWait
bn B, 4, .NoFreq
inc A1R_SFXPos
ld A1R_SFXPos
ldc
st T1LR
.NoFreq:
bn B, 5, .NoPWM
inc A1R_SFXPos
ld A1R_SFXPos
ldc
st T1LC
.NoPWM:
bn B, 6, .NoSPM
inc A1R_SFXPos
ld A1R_SFXPos
ldc
st T1HC
.NoSPM:
bn B, 7, .SfxDone
mov #$FF, A1R_SFXReq ; or else if set, disable SFXReq and exit
ret
.SfxDone:
ld T1CNT ; retrigger timer 1
mov #0, T1CNT
st T1CNT
inc A1R_SFXPos
.SfxExit
ret
; /////////////////////////////////////////////////////////////
; /// MUSIC PLAY BLOCK ///
; /////////////////////////////////////////////////////////////
; E0SPNWWW (WW) (NN) (WW) (SS) (00)
; too slow for Gmacro and any Block abstractions sadly, this should be available in ADVM2 instead
_ADVM1_RUN_MUSIC:
dec A1R_RowsWait
ld A1R_RowsWait
bz .RunSong
jmp A1L_RegisterGen
.RunSong:
ld A1R_PhrPosL
st TRL
ld A1R_PhrPosH
st TRH
xor ACC
st C
ldc ; get header
st B
and #%00000111
bnz .NormalWait
inc C
ld C
ldc
.NormalWait:
st A1R_RowsWait
bn B, 3, .NoNote
inc C
ld C
ldc
st A1R_CurrNote
ld A1R_TspNew
st A1R_TspOld
set1 A1R_Flags, 0
.NoNote:
bn B, 4, .NoPWM
inc C
ld C
ldc
st A1R_PWM
set1 A1R_Flags, 0
.NoPWM:
bn B, 5, .NoSPM
inc C
ld C
ldc
st A1R_SPM
set1 A1R_Flags, 0
.NoSPM:
bn B, 6, .NoTimer
inc C
ld C
ldc
st A1R_Tempo
set1 A1R_Flags, 1 ; signal a tempo update
.NoTimer:
bn B, 7, A1L_StepPhrase
A1L_StepTmLine: ; or else step timeline pos
ld A1RH_TmlBaseL
st TRL
ld A1RH_TmlBaseH
st TRH
ld A1R_TmlPos
add ACC
bn PSW, 7, .NoCarry
inc TRH
.NoCarry:
st C
ldc
bne #$FF, .TmNotEndedYet
ld A1RH_TmlBaseH ; reset TRH
st TRH
inc C ; get offset
ld C
ldc
st A1R_TmlPos
add ACC
bn PSW, 7, .NoCarry2
inc TRH
.NoCarry2:
st C
ldc ; get new phrase
.TmNotEndedYet:
st B ; save phrase index for later
inc C
ld C
ldc
st A1R_TspNew ; get transpose value
ld A1RH_PhrIndxL ; get index list
st TRL
ld A1RH_PhrIndxH
st TRH
ld B
add ACC
bn PSW, 7, .NoCarry3
inc TRH
.NoCarry3:
st B
ldc ; get two bytes from list location
st A1R_PhrPosL
inc B
ld B
ldc
st A1R_PhrPosH
; step timeline forwards
inc A1R_TmlPos
br A1L_RegisterGen ; done
A1L_StepPhrase:
inc C ; +1 to offset into the next event
ld C
add TRL
st A1R_PhrPosL
xor ACC
addc TRH
st A1R_PhrPosH
; /////////////////////////////////////////////////////////////
; /// REGISTER GEN ///
; /////////////////////////////////////////////////////////////
A1L_RegisterGen:
ld A1R_SFXReq
bne #$FF, .Exit
bpc A1R_Flags, 0, .Continue
ret
.Continue:
ld A1R_CurrNote
bne #$FF, .NotMuteNote
mov #0, T1CNT
ret
.NotMuteNote:
mov #<ADVM_NoteTable, TRL
mov #>ADVM_NoteTable, TRH
add A1R_TspOld
be #$12, .here ; if below this range, use non-doubled setting (11)
.here:
bn PSW, 7, .ClockDoubleOn ; carry is set if #value is below ACC
; set1 T1CNT, 7 ; off (11)
mov #%11110000, T1CNT
br .FreqDone
.ClockDoubleOn:
mov #%01110000, T1CNT
; clr1 T1CNT, 7 ; on (01)
.FreqDone:
ldc
st T1LR
xor #$FF
st C
ld A1R_PWM
st B
xor ACC
mul
xor #$FF
st T1LC
ld A1R_SPM
st T1HC
ld T1CNT ; retrigger to apply changes
mov #0, T1CNT
st T1CNT
.Exit:
ret
; worst case (step) = ~99 cycles
; worse case (tmrs) = ~194 cycles
; /////////////////////////////////////////////////////////////
; /// LIBRARY SPACE ///
; /////////////////////////////////////////////////////////////
ADVM_NoteTable:
.byte $06 ; F-0 00
.byte $14 ; F#0 01
.byte $21 ; G-0 02
.byte $2E ; G#0 03
.byte $39 ; A-0 04
.byte $45 ; A#0 05
.byte $4F ; B-0 06
.byte $59 ; C-1 07
.byte $62 ; C#1 08
.byte $6B ; D-1 09
.byte $73 ; D#1 0A
.byte $7C ; E-1 0B ; last using 11
.byte $06 ; F-1 0C
.byte $14 ; F#1 0D
.byte $21 ; G-1 0E
.byte $2E ; G#1 0F
.byte $39 ; A-1 10
.byte $45 ; A#1 11
.byte $4F ; B-1 12
.byte $59 ; C-2 13
.byte $62 ; C#2 14
.byte $6B ; D-2 15
.byte $73 ; D#2 16
.byte $7C ; E-2 17
.byte $83 ; F-2 18
.byte $8A ; F#2 19
.byte $90 ; G-2 1A
.byte $97 ; G#2 1B
.byte $9D ; A-2 1C
.byte $A2 ; A#2 1D
.byte $A8 ; B-2 1E
.byte $AC ; C-3 1F
.byte $B1 ; C#3 20
.byte $B6 ; D-3 21
.byte $BA ; D#3 22
.byte $BE ; E-3 23
.byte $C1 ; F-3 24
.byte $C5 ; F#3 25
.byte $C8 ; G-3 26
.byte $CB ; G#3 27
.byte $CE ; A-3 28
.byte $D1 ; A#3 29
.byte $D4 ; B-3 2A
.byte $D6 ; C-4 2B
.byte $D9 ; C#4 2C
.byte $DB ; D-4 2D
.byte $DD ; D#4 2E
.byte $DF ; E-4 2F
.byte $E1 ; F-4 30
.byte $E2 ; F#4 31
.byte $E4 ; G-4 32
.byte $E6 ; G#4 33
.byte $E7 ; A-4 34
.byte $E8 ; A#4 35
.byte $EA ; B-4 36
.byte $EB ; C-5 37
.byte $EC ; C#5 38
.byte $FC
.byte $FE
.byte $FF ; off $3B
; /////////////////////////////////////////////////////////////
; /// RAM DEFINITIONS ///
; /////////////////////////////////////////////////////////////
A1RH_TmlBaseL = $10
A1RH_TmlBaseH = $11
A1RH_PhrIndxL = $12
A1RH_PhrIndxH = $13
A1R_RowsWait = $14
A1R_PhrPosL = $15
A1R_PhrPosH = $16
A1R_TmlPos = $17
A1R_CurrNote = $18
A1R_SPM = $19
A1R_PWM = $1A
A1R_TspNew = $1B
A1R_TspOld = $1C
A1R_Flags = $1D
A1R_Tempo = $1E
A1RH_SFXListL = $1F
A1RH_SFXListH = $20
A1R_SFXReq = $21
A1R_SFXWait = $22
A1R_SFXPos = $23
; 18 bytes RAM total, 13 for music, 5 for SFX