fox32rom/audio.asm

255 lines
5.8 KiB
NASM

; audio routines
; use ffmpeg to convert an audio file for playback:
; ffmpeg -i input.mp3 -f s16le -ac 1 -ar 22050 audio.raw
const AUDIO_POINTER_0: 0x01FFFF00 ; 4 bytes
const AUDIO_POINTER_1: 0x01FFFF04 ; 4 bytes
const AUDIO_POINTER_2: 0x01FFFF08 ; 4 bytes
const AUDIO_POINTER_3: 0x01FFFF0C ; 4 bytes
const AUDIO_LENGTH_0: 0x01FFFF10 ; 4 bytes
const AUDIO_LENGTH_1: 0x01FFFF14 ; 4 bytes
const AUDIO_LENGTH_2: 0x01FFFF18 ; 4 bytes
const AUDIO_LENGTH_3: 0x01FFFF1C ; 4 bytes
const OLD_BUFFER_SWAP_VECTOR_0: 0x01FFFF20 ; 4 bytes
const OLD_BUFFER_SWAP_VECTOR_1: 0x01FFFF24 ; 4 bytes
const OLD_BUFFER_SWAP_VECTOR_2: 0x01FFFF28 ; 4 bytes
const OLD_BUFFER_SWAP_VECTOR_3: 0x01FFFF2C ; 4 bytes
; play an audio clip (does not block)
; inputs:
; r0: pointer to audio clip
; r1: length of audio clip in bytes (must be a multiple of 32768 bytes)
; r2: audio sample rate
; r3: audio channel (0-3)
; outputs:
; none
play_audio:
push r0
push r1
cmp r3, 0
ifz jmp play_audio_0
cmp r3, 1
ifz jmp play_audio_1
cmp r3, 2
ifz jmp play_audio_2
cmp r3, 3
ifz jmp play_audio_3
jmp play_audio_done
play_audio_0:
; set the interrupt vector for interrupt 0xFE
; save the old one only if it wasn't already saved earlier
cmp [OLD_BUFFER_SWAP_VECTOR_0], refill_buffer_0
ifnz mov [OLD_BUFFER_SWAP_VECTOR_0], [0x000003F8]
mov [0x000003F8], refill_buffer_0
; store audio pointer
mov [AUDIO_POINTER_0], r0
; store audio length
; floor it to the nearest multiple of 32768
and r1, 0xFFFF8000
mov [AUDIO_LENGTH_0], r1
; enable audio playback and set sample rate
mov r0, 0x80000600
out r0, r2
; initial buffer fill
int 0xFE
jmp play_audio_done
play_audio_1:
; set the interrupt vector for interrupt 0xFD
; save the old one only if it wasn't already saved earlier
cmp [OLD_BUFFER_SWAP_VECTOR_1], refill_buffer_1
ifnz mov [OLD_BUFFER_SWAP_VECTOR_1], [0x000003F4]
mov [0x000003F4], refill_buffer_1
; store audio pointer
mov [AUDIO_POINTER_1], r0
; store audio length
; floor it to the nearest multiple of 32768
and r1, 0xFFFF8000
mov [AUDIO_LENGTH_1], r1
; enable audio playback and set sample rate
mov r0, 0x80000601
out r0, r2
; initial buffer fill
int 0xFD
jmp play_audio_done
play_audio_2:
; set the interrupt vector for interrupt 0xFC
; save the old one only if it wasn't already saved earlier
cmp [OLD_BUFFER_SWAP_VECTOR_2], refill_buffer_2
ifnz mov [OLD_BUFFER_SWAP_VECTOR_2], [0x000003F0]
mov [0x000003F0], refill_buffer_2
; store audio pointer
mov [AUDIO_POINTER_2], r0
; store audio length
; floor it to the nearest multiple of 32768
and r1, 0xFFFF8000
mov [AUDIO_LENGTH_2], r1
; enable audio playback and set sample rate
mov r0, 0x80000602
out r0, r2
; initial buffer fill
int 0xFC
jmp play_audio_done
play_audio_3:
; set the interrupt vector for interrupt 0xFB
; save the old one only if it wasn't already saved earlier
cmp [OLD_BUFFER_SWAP_VECTOR_3], refill_buffer_3
ifnz mov [OLD_BUFFER_SWAP_VECTOR_3], [0x000003EC]
mov [0x000003EC], refill_buffer_3
; store audio pointer
mov [AUDIO_POINTER_3], r0
; store audio length
; floor it to the nearest multiple of 32768
and r1, 0xFFFF8000
mov [AUDIO_LENGTH_3], r1
; enable audio playback and set sample rate
mov r0, 0x80000603
out r0, r2
; initial buffer fill
int 0xFB
play_audio_done:
pop r1
pop r0
ret
; stop audio playback
; inputs:
; r0: audio channel (0-3)
; outputs:
; none
stop_audio:
push r0
; disable audio playback
or r0, 0x80000600
out r0, 0
; restore the old buffer refill vector
cmp.8 r0, 0
ifz mov [0x000003F8], [OLD_BUFFER_SWAP_VECTOR_0]
cmp.8 r0, 1
ifz mov [0x000003F4], [OLD_BUFFER_SWAP_VECTOR_1]
cmp.8 r0, 2
ifz mov [0x000003F0], [OLD_BUFFER_SWAP_VECTOR_2]
cmp.8 r0, 3
ifz mov [0x000003EC], [OLD_BUFFER_SWAP_VECTOR_3]
pop r0
ret
refill_buffer_0:
add rsp, 4
push r0
push r1
push r31
mov r31, 8192 ; 32768 bytes = 8192 words
mov r0, [AUDIO_POINTER_0]
mov r1, 0x0212C000 ; buffer 0 address
refill_buffer_0_loop:
mov [r1], [r0]
add r0, 4
add r1, 4
loop refill_buffer_0_loop
mov [AUDIO_POINTER_0], r0
sub [AUDIO_LENGTH_0], 32768
ifz mov r0, 0
ifz call stop_audio
pop r31
pop r1
pop r0
reti
refill_buffer_1:
add rsp, 4
push r0
push r1
push r31
mov r31, 8192 ; 32768 bytes = 8192 words
mov r0, [AUDIO_POINTER_1]
mov r1, 0x02134000 ; buffer 1 address
refill_buffer_1_loop:
mov [r1], [r0]
add r0, 4
add r1, 4
loop refill_buffer_1_loop
mov [AUDIO_POINTER_1], r0
sub [AUDIO_LENGTH_1], 32768
ifz mov r0, 1
ifz call stop_audio
pop r31
pop r1
pop r0
reti
refill_buffer_2:
add rsp, 4
push r0
push r1
push r31
mov r31, 8192 ; 32768 bytes = 8192 words
mov r0, [AUDIO_POINTER_2]
mov r1, 0x02290000 ; buffer 2 address
refill_buffer_2_loop:
mov [r1], [r0]
add r0, 4
add r1, 4
loop refill_buffer_2_loop
mov [AUDIO_POINTER_2], r0
sub [AUDIO_LENGTH_2], 32768
ifz mov r0, 2
ifz call stop_audio
pop r31
pop r1
pop r0
reti
refill_buffer_3:
add rsp, 4
push r0
push r1
push r31
mov r31, 8192 ; 32768 bytes = 8192 words
mov r0, [AUDIO_POINTER_3]
mov r1, 0x02298000 ; buffer 3 address
refill_buffer_3_loop:
mov [r1], [r0]
add r0, 4
add r1, 4
loop refill_buffer_3_loop
mov [AUDIO_POINTER_3], r0
sub [AUDIO_LENGTH_3], 32768
ifz mov r0, 3
ifz call stop_audio
pop r31
pop r1
pop r0
reti