-
Notifications
You must be signed in to change notification settings - Fork 1
/
WSAudio.s
448 lines (415 loc) · 10.7 KB
/
WSAudio.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
//
// WSAudio.s
// Bandai WonderSwan Sound emulation for GBA/NDS.
//
// Created by Fredrik Ahlström on 2006-07-23.
// Copyright © 2006-2024 Fredrik Ahlström. All rights reserved.
//
#ifdef __arm__
#include "Sphinx.i"
.global wsAudioReset
.global wsAudioMixer
.global setAllChVolume
.global setCh1Volume
.global setCh2Volume
.global setCh3Volume
.global setCh4Volume
.global setHyperVoiceValue
.global setSoundOutput
.global setTotalVolume
.global vol2_L
.syntax unified
.arm
.section .text
.align 2
;@----------------------------------------------------------------------------
wsAudioReset: ;@ spxptr=r12=pointer to struct
;@----------------------------------------------------------------------------
mov r0,#0x00000800
str r0,[spxptr,#pcm1CurrentAddr]
str r0,[spxptr,#pcm2CurrentAddr]
str r0,[spxptr,#pcm3CurrentAddr]
str r0,[spxptr,#pcm4CurrentAddr]
str r0,[spxptr,#sweep3CurrentAddr]
ldr r0,=0x00000408
str r0,[spxptr,#noise4CurrentAddr]
ldr r0,[spxptr,#gfxRAM]
str r0,[spxptr,#sampleBaseAddr]
;@----------------------------------------------------------------------------
setAllChVolume:
;@----------------------------------------------------------------------------
stmfd sp!,{lr}
ldrb r0,[spxptr,#wsvSound1Vol]
bl setCh1Volume
ldrb r0,[spxptr,#wsvSound2Vol]
bl setCh2Volume
ldrb r0,[spxptr,#wsvSound3Vol]
bl setCh3Volume
ldrb r0,[spxptr,#wsvSound4Vol]
bl setCh4Volume
ldmfd sp!,{pc}
;@----------------------------------------------------------------------------
setCh1Volume:
;@----------------------------------------------------------------------------
ldrb r1,[spxptr,#wsvSoundCtrl]
tst r1,#1 ;@ Ch 1 on?
moveq r0,#0
ldr r1,=vol1_L
and r2,r0,#0xF
mov r0,r0,lsr#4
strb r0,[r1,#vol1_L-vol1_L]
strb r2,[r1,#vol1_R-vol1_L]
bx lr
;@----------------------------------------------------------------------------
setCh2Volume:
;@----------------------------------------------------------------------------
ldrb r1,[spxptr,#wsvSoundCtrl]
tst r1,#0x20 ;@ Ch 2 voice on?
bne doCh2Voice
tst r1,#2 ;@ Ch 2 on?
moveq r0,#0
ldr r2,=vol2_L
and r1,r0,#0xF
mov r0,r0,lsr#4
strb r0,[r2]
strb r1,[r2,#4]
bx lr
doCh2Voice:
ldrb r2,[spxptr,#wsvCh2VoiceVol]
movs r1,r2,lsl#29 ;@ Left vol
movcs r1,r0,lsr#1 ;@ 50%
movmi r1,r0 ;@ 100%
movs r2,r2,lsl#31 ;@ Right vol
movcs r2,r0,lsr#1 ;@ 50%
movmi r2,r0 ;@ 100%
ldr r0,=vol2_L
strb r1,[r0]
strb r2,[r0,#4]
bx lr
;@----------------------------------------------------------------------------
setCh3Volume:
;@----------------------------------------------------------------------------
ldrb r1,[spxptr,#wsvSoundCtrl]
tst r1,#4 ;@ Ch 3 on?
moveq r0,#0
ldr r1,=vol1_L
and r2,r0,#0xF
mov r0,r0,lsr#4
strb r0,[r1,#vol3_L-vol1_L]
strb r2,[r1,#vol3_R-vol1_L]
bx lr
;@----------------------------------------------------------------------------
setCh4Volume:
;@----------------------------------------------------------------------------
ldrb r1,[spxptr,#wsvSoundCtrl]
tst r1,#8 ;@ Ch 4 on?
moveq r0,#0
ldr r1,=vol1_L
and r2,r0,#0xF
mov r0,r0,lsr#4
strb r0,[r1,#vol4_L-vol1_L]
strb r2,[r1,#vol4_R-vol1_L]
bx lr
;@----------------------------------------------------------------------------
setHyperVoiceValue:
;@----------------------------------------------------------------------------
ldrh r1,[spxptr,#wsvHyperVCtrl]
ldrb r2,[spxptr,#wsvSoundOutput]
tst r1,#0x80 ;@ HyperV Enabled
tstne r2,#0x80 ;@ HeadPhones Enabled
bxeq lr
movs r0,r0,lsl#24
orrmi r0,r0,#7
ands r2,r1,#0x0C
biceq r0,r0,#7
cmpne r2,#0x08 ;@ Sign extend?
orrmi r0,r0,#7 ;@ Unsigned negated
bichi r1,r1,#0x03 ;@ Ignore shift
and r2,r1,#0x03 ;@ Mask shift amount
mov r0,r0,ror r2
mov r0,r0,lsr#16 ;@ Left
ands r2,r1,#0x6000 ;@ Mode, 0=stereo, 1=left, 2=right, 3=mono both.
cmp r2,#0x4000
moveq r0,r0,lsl#16 ;@ Right
cmp r2,#0x6000
orreq r0,r0,r0,lsl#16 ;@ Mono
str r0,[spxptr,#currentSampleValue]
bx lr
;@----------------------------------------------------------------------------
setSoundOutput: ;@ r0 = wsvSoundOutput
;@----------------------------------------------------------------------------
and r1,r0,#0x6
tst r0,#0x80 ;@ Headphones?
movne r1,#0x8
adr r2,mixerVolumes
ldr r1,[r2,r1,lsl#1]
ldr r0,=vol1_L
str r1,[r0,#totalVolume-vol1_L]
bx lr
mixerVolumes:
mov r2,r2,lsl#8
mov r2,r2,lsl#7
mov r2,r2,lsl#6
mov r2,r2,lsl#5
add r2,r9,r2,lsl#5 ;@ Headphones
;@----------------------------------------------------------------------------
setTotalVolume:
;@----------------------------------------------------------------------------
ldrb r0,[spxptr,#wsvHWVolume]
adr r2,hw1Volumes
ldrb r1,[spxptr,#wsvSOC]
cmp r1,#SOC_ASWAN
adrne r2,hw2Volumes
ldr r0,[r2,r0,lsl#2]
ldr r1,=mix8Vol
str r0,[r1]
bx lr
hw1Volumes:
mov r2,r2,lsr#32
mov r2,r2,lsr#1
mov r2,r2,lsr#0
mov r2,r2,lsr#0
hw2Volumes:
mov r2,r2,lsr#32
mov r2,r2,lsr#2
mov r2,r2,lsr#1
mov r2,r2,lsr#0
;@----------------------------------------------------------------------------
#ifdef NDS
.section .itcm ;@ For the NDS ARM9
#elif GBA
.section .iwram, "ax", %progbits ;@ For the GBA
#endif
.align 2
#ifdef GBA
#define PSG_DIVIDE 24
#else
#define PSG_DIVIDE 16
#endif
#define PSG_ADDITION 0x00008000*PSG_DIVIDE
#define PSG_SWEEP_ADD 0x00020000*PSG_DIVIDE
;@----------------------------------------------------------------------------
#ifdef WSAUDIO_LOW
;@----------------------------------------------------------------------------
;@ r0 = Length
;@ r1 = Destination
;@ r2 = Mixer register
;@ r3 = Channel 1
;@ r4 = Channel 2
;@ r5 = Channel 3
;@ r6 = Channel 4
;@ r7 = Noise LFSR
;@ r8 = Ch3 Sweep
;@ r9 = HyperVoice sample.
;@ r10 = Sample pointer
;@ r11 = Current sample
;@ lr = Current volume
;@----------------------------------------------------------------------------
wsAudioMixer: ;@ r0=len, r1=dest, r12=spxptr
// IIIIIVCCCCCCCCCCC0001FFFFFFFFFFF
// I=sampleindex, V=overflow, C=counter, F=frequency
;@----------------------------------------------------------------------------
stmfd sp!,{r4-r11,lr}
add r2,spxptr,#pcm1CurrentAddr
ldmia r2,{r3-r10}
mov r0,r0,lsl#3
mixLoop:
mov r11,r3,lsl#20 ;@ Pre-load r11 & lr with frequency.
mov lr,r4,lsl#20
innerMixLoop:
add r3,r3,#PSG_ADDITION
tst r3,r3,lsl#6
addcs r3,r3,r11,lsr#5
add r4,r4,#PSG_ADDITION
tst r4,r4,lsl#6
addcs r4,r4,lr,lsr#5
add r5,r5,#PSG_ADDITION
tst r5,r5,lsl#6
mov r2,r5,lsl#20
addcs r5,r5,r2,lsr#5
add r6,r6,#PSG_ADDITION
tst r6,r6,lsl#6
mov r2,r6,lsl#20
addcs r6,r6,r2,lsr#5
movscs r2,r7,lsr#16 ;@ Mask LFSR and check noise calc enable.
addcs r7,r7,r2,lsl#16
ands r2,r7,r7,lsl#21
eorsne r2,r2,r7,lsl#21
orreq r7,r7,#0x00010000
sub r0,r0,#1
tst r0,#7
bne innerMixLoop
;@----------------------------------------------------------------------------
ldrb r11,[r10,r3,lsr#28] ;@ Channel 1
add r10,r10,#0x10
tst r3,#0x08000000
movne r11,r11,lsr#4
and r11,r11,#0xF
vol1_L:
mov lr,#0x00 ;@ Volume left
vol1_R:
orr lr,lr,#0xFF0000 ;@ Volume right
mul r2,lr,r11
ldrb r11,[r10,r4,lsr#28] ;@ Channel 2
add r10,r10,#0x10
tst r4,#0x08000000
movne r11,r11,lsr#4
ands r11,r11,#0xF
vol2_L:
mov lr,#0x00 ;@ Volume left
vol2_R:
orrsne lr,lr,#0xFF0000 ;@ Volume right
mlane r2,lr,r11,r2
ldrb r11,[r10,r5,lsr#28] ;@ Channel 3
add r10,r10,#0x10
tst r5,#0x08000000
movne r11,r11,lsr#4
ands r11,r11,#0xF
vol3_L:
mov lr,#0x00 ;@ Volume left
vol3_R:
orrsne lr,lr,#0xFF0000 ;@ Volume right
mlane r2,lr,r11,r2
tst r7,#0x4000 ;@ Channel 4 Noise enabled?
ldrbeq r11,[r10,r6,lsr#28] ;@ Channel 4 PCM
sub r10,r10,#0x30
andsne r11,r7,#0x00010000
movne r11,#0xFF
tst r6,#0x08000000
movne r11,r11,lsr#4
ands r11,r11,#0xF
vol4_L:
mov lr,#0x00 ;@ Volume left
vol4_R:
orrsne lr,lr,#0xFF0000 ;@ Volume right
mlane r2,lr,r11,r2
tst r8,r8,lsr#9 ;@ Ch3 Sweep?
bcc noSweep
addscs r8,r8,#PSG_SWEEP_ADD
bcc noSweep
subcs r8,r8,r8,lsl#26
ldrsb lr,[spxptr,#wsvSweepValue]
mov lr,lr,lsl#21
add r5,lr,r5,ror#11
mov r5,r5,ror#21
noSweep:
totalVolume:
add r2,r9,r2,lsl#5
cmp r0,#0
#ifdef GBA
add r2,r2,r2,lsr#16
mov r2,r2,lsr#9
strbpl r2,[r1],#1
#else
strpl r2,[r1],#4
#endif
bhi mixLoop ;@ ?? cycles according to No$gba
mov r2,r7,lsr#17
strh r2,[spxptr,#wsvNoiseCntr] ;@ Update Reg 0x92 for "rnd".
add r0,spxptr,#pcm1CurrentAddr ;@ Counters
stmia r0,{r3-r8}
ldmfd sp!,{r4-r11,pc}
#else
;@----------------------------------------------------------------------------
;@ r0 = Length
;@ r1 = Destination
;@ r2 = Mixer register
;@ r3 = Channel 1
;@ r4 = Channel 2
;@ r5 = Channel 3
;@ r6 = Channel 4
;@ r10 = Sample pointer
;@ r11 =
;@----------------------------------------------------------------------------
pcmMix: ;@ r0=len, r1=dest, r12=snptr
// IIIIIVCCCCCCCCCCC0001FFFFFFFFFFF
// I=sampleindex, V=overflow, C=counter, F=frequency
;@----------------------------------------------------------------------------
mixLoop:
mov r2,#0x80000000
innerMixLoop:
add r3,r3,#PSG_ADDITION
movs r9,r3,lsr#27
mov lr,r3,lsl#20
addcs r3,r3,lr,lsr#5
ldrb r11,[r10,r3,lsr#1] ;@ Channel 1
tst r9,#1
moveq r11,r11,lsr#4
ands r11,r11,#0xF
vol1_L:
mov lr,#0x00 ;@ Volume left
vol1_R:
orrsne lr,lr,#0xFF0000 ;@ Volume right
mlane r2,lr,r11,r2
add r4,r4,#PSG_ADDITION
movs r9,r4,lsr#27
add r9,r9,#0x20
mov lr,r4,lsl#20
addcs r4,r4,lr,lsr#5
ldrb r11,[r10,r9,lsr#1] ;@ Channel 2
tst r9,#1
moveq r11,r11,lsr#4
ands r11,r11,#0xF
vol2_L:
mov lr,#0x00 ;@ Volume left
vol2_R:
orrsne lr,lr,#0xFF0000 ;@ Volume right
mlane r2,lr,r11,r2
add r5,r5,#PSG_ADDITION
movs r9,r5,lsr#27
add r9,r9,#0x40
mov lr,r5,lsl#20
addcs r5,r5,lr,lsr#5
ldrb r11,[r10,r9,lsr#1] ;@ Channel 3
tst r9,#1
moveq r11,r11,lsr#4
ands r11,r11,#0xF
vol3_L:
mov lr,#0x00 ;@ Volume left
vol3_R:
orrsne lr,lr,#0xFF0000 ;@ Volume right
mlane r2,lr,r11,r2
add r6,r6,#PSG_ADDITION
movs r9,r6,lsr#27
add r9,r9,#0x60
mov lr,r6,lsl#20
addcs r6,r6,lr,lsr#5
movcs lr,r7,lsr#16
addscs r7,r7,lr,lsl#16
ldrcs lr,=PSG_NOISE_FEED
eorcs r7,r7,lr
tst r7,#0x80 ;@ Noise 4 enabled?
ldrbeq r11,[r10,r9,lsr#1] ;@ Channel 4
andsne r11,r7,#0x00000001
movne r11,#0xFF
tst r9,#1
moveq r11,r11,lsr#4
ands r11,r11,#0xF
vol4_L:
mov lr,#0x00 ;@ Volume left
vol4_R:
orrsne lr,lr,#0xFF0000 ;@ Volume right
mlane r2,lr,r11,r2
sub r0,r0,#1
tst r0,#3
bne innerMixLoop
// subs r8,r8,#PSG_SWEEP_ADD
// bhi noSweep
// ldrb lr,[spxptr,#wsvSweepTime]
// add lr,lr,#1
// add r8,r8,lr,lsl#26
// ldrsb lr,[spxptr,#wsvSweepValue]
// mov r5,r5,ror#11
// adds r5,r5,lr,lsl#21
// mov r5,r5,ror#21
noSweep:
eor r2,r2,#0x00008000
cmp r0,#0
strpl r2,[r1],#4
bhi mixLoop ;@ ?? cycles according to No$gba
mov r2,r7,lsr#17
strh r2,[spxptr,#wsvNoiseCntr]
b pcmMixReturn
;@----------------------------------------------------------------------------
#endif
#endif // #ifdef __arm__