From c7464fa4bca608c60ff3fab1749a4a595439e55a Mon Sep 17 00:00:00 2001 From: Ry Date: Mon, 20 Jun 2022 17:11:49 -0700 Subject: [PATCH] fox32rom: Add play_audio and stop_audio routines --- audio.asm | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fox32rom.def | 4 +++ main.asm | 6 ++++ 3 files changed, 107 insertions(+) create mode 100644 audio.asm diff --git a/audio.asm b/audio.asm new file mode 100644 index 0000000..394e543 --- /dev/null +++ b/audio.asm @@ -0,0 +1,97 @@ +; audio routines + +; use ffmpeg to convert an audio file for playback: +; ffmpeg -i input.mp3 -f s16le -ac 1 -ar 22050 audio.raw + +; fox32's audio output works by swapping between two buffers +; interrupt 0xFE (vector 0x000003F8) is fired when it's time to swap buffers +; when that interrupt fires, it calls `refill_buffer` which fills up the buffer + +const CURRENT_BUFFER: 0x01FFFF00 +const AUDIO_POINTER: 0x01FFFF01 +const AUDIO_LENGTH: 0x01FFFF05 +const OLD_BUFFER_SWAP_VECTOR: 0x01FFFF09 + +; 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) +; outputs: +; none +play_audio: + push r0 + push r1 + + ; set the interrupt vector for interrupt 0xFE and save the old one + mov [OLD_BUFFER_SWAP_VECTOR], [0x000003F8] + mov [0x000003F8], refill_buffer + + ; store audio pointer + mov [AUDIO_POINTER], r0 + + ; store audio length + ; floor it to the nearest multiple of 32768 + and r1, 0xFFFF8000 + mov [AUDIO_LENGTH], r1 + + ; reset the current buffer to zero + ; fox32 resets its current buffer to zero internally, so reset it to zero here to stay in sync + ; refill_buffer will bitwise not this before checking it, + ; so set it to 0xFF so that it becomes zero when checked for the first time + mov.8 [CURRENT_BUFFER], 0xFF + + ; enable audio playback + mov r0, 0x80000600 + out r0, 1 + + pop r1 + pop r0 + ret +refill_buffer: + push r0 + push r1 + push r31 + + not.8 [CURRENT_BUFFER] + cmp.8 [CURRENT_BUFFER], 0 + ifnz jmp refill_buffer_1 +refill_buffer_0: + mov r31, 8192 ; 32768 bytes = 8192 words + mov r0, [AUDIO_POINTER] + mov r1, 0x0212C000 ; buffer 0 address +refill_buffer_loop: + mov [r1], [r0] + add r0, 4 + add r1, 4 + loop refill_buffer_loop + mov [AUDIO_POINTER], r0 + sub [AUDIO_LENGTH], 32768 + ifz call stop_audio + + pop r31 + pop r1 + pop r0 + reti +refill_buffer_1: + mov r31, 8192 ; 32768 bytes = 8192 words + mov r0, [AUDIO_POINTER] + mov r1, 0x02134000 ; buffer 1 address + jmp refill_buffer_loop + +; stop audio playback +; inputs: +; none +; outputs: +; none +stop_audio: + push r0 + + ; disable audio playback + mov r0, 0x80000600 + out r0, 0 + + ; restore the old buffer swap vector + mov [0x000003F8], [OLD_BUFFER_SWAP_VECTOR] + + pop r0 + ret diff --git a/fox32rom.def b/fox32rom.def index 265a1e6..4936e8e 100644 --- a/fox32rom.def +++ b/fox32rom.def @@ -71,6 +71,10 @@ string_length: jmp [0xF0046018] ; integer jump table string_to_int: jmp [0xF0047000] +; audio jump table +play_audio: jmp [0xF0048000] +stop_audio: jmp [0xF0048004] + ; event types const EVENT_TYPE_MOUSE_CLICK: 0x00000000 const EVENT_TYPE_MOUSE_RELEASE: 0x00000001 diff --git a/main.asm b/main.asm index 886cbd0..f7f6285 100644 --- a/main.asm +++ b/main.asm @@ -112,6 +112,7 @@ get_rom_version: ret ; code + #include "audio.asm" #include "background.asm" #include "boot.asm" #include "cursor.asm" @@ -218,6 +219,11 @@ get_rom_version: org.pad 0xF0047000 data.32 string_to_int + ; audio jump table + org.pad 0xF0048000 + data.32 play_audio + data.32 stop_audio + org.pad 0xF004F000 standard_font_width: data.16 8