diff --git a/agb/src/sound/mixer/mixer.s b/agb/src/sound/mixer/mixer.s index ac31a91..d81d247 100644 --- a/agb/src/sound/mixer/mixer.s +++ b/agb/src/sound/mixer/mixer.s @@ -150,13 +150,13 @@ agb_arm_func agb_rs__init_buffer push {r4-r5} @ zero registers r3-r5 - mov r2, #constant_zero + ldr r2, =constant_zero ldm r2, {r3-r5,r12} 1: @ zero 4 words worth of the buffer - stmia r0, {r3-r5,r12} - subs r1, r1, #16 + stmia r0!, {r3-r5,r12} + subs r1, r1, #(4 * 4) @ loop if we haven't zeroed everything bne 1b diff --git a/agb/src/sound/mixer/sw_mixer.rs b/agb/src/sound/mixer/sw_mixer.rs index 02b54fe..c8ed7b4 100644 --- a/agb/src/sound/mixer/sw_mixer.rs +++ b/agb/src/sound/mixer/sw_mixer.rs @@ -1,4 +1,6 @@ use core::cell::RefCell; +use core::mem; +use core::mem::MaybeUninit; use bare_metal::{CriticalSection, Mutex}; @@ -27,6 +29,8 @@ extern "C" { fn agb_rs__mixer_add_stereo(sound_data: *const u8, sound_buffer: *mut Num); fn agb_rs__mixer_collapse(sound_buffer: *mut i8, input_buffer: *const Num); + + fn agb_rs__init_buffer(buffer: *mut MaybeUninit>, size_in_bytes: usize); } pub struct Mixer { @@ -231,8 +235,28 @@ impl MixerBuffer { } fn write_channels<'a>(&mut self, channels: impl Iterator) { - let mut buffer: [Num; constants::SOUND_BUFFER_SIZE * 2] = - [Num::new(0); constants::SOUND_BUFFER_SIZE * 2]; + // This code is equivalent to: + // let mut buffer: [Num; constants::SOUND_BUFFER_SIZE * 2] = + // [Num::new(0); constants::SOUND_BUFFER_SIZE * 2]; + // but the above uses approximately 7% of the CPU time if running at 32kHz + let mut buffer: [Num; constants::SOUND_BUFFER_SIZE * 2] = { + // Create an uninitialized array of `MaybeUninit`. The `assume_init` is + // safe because the type we are claiming to have initialized here is a + // bunch of `MaybeUninit`s, which do not require initialization. + let mut data: [MaybeUninit>; constants::SOUND_BUFFER_SIZE * 2] = + unsafe { MaybeUninit::uninit().assume_init() }; + + // Actually init the array (by filling it with zeros) and then transmute it (which is safe because + // we have now zeroed everything) + unsafe { + agb_rs__init_buffer( + data.as_mut_ptr(), + mem::size_of::>() * data.len(), + ); + + mem::transmute(data) + } + }; for channel in channels { if channel.is_done {