From 5d958d685c51471f8a3c7c88cadfe2b2bc527db6 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 22:18:18 +0100 Subject: [PATCH 01/19] Move mixer to its own folder --- agb/src/sound/{mixer.rs => mixer/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename agb/src/sound/{mixer.rs => mixer/mod.rs} (100%) diff --git a/agb/src/sound/mixer.rs b/agb/src/sound/mixer/mod.rs similarity index 100% rename from agb/src/sound/mixer.rs rename to agb/src/sound/mixer/mod.rs From 94d15de3f44ca5fe2d021993c9f7377a2c22dbca Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 22:20:37 +0100 Subject: [PATCH 02/19] Move GBA hardware related stuff to hw.rs --- agb/src/sound/mixer/hw.rs | 48 ++++++++++++++++++++++++++++++++ agb/src/sound/mixer/mod.rs | 57 ++++---------------------------------- 2 files changed, 53 insertions(+), 52 deletions(-) create mode 100644 agb/src/sound/mixer/hw.rs diff --git a/agb/src/sound/mixer/hw.rs b/agb/src/sound/mixer/hw.rs new file mode 100644 index 0000000..43d3bf7 --- /dev/null +++ b/agb/src/sound/mixer/hw.rs @@ -0,0 +1,48 @@ +use crate::memory_mapped::MemoryMapped; + +// Once we have proper DMA support, we should use that rather than hard coding these here too +const DMA1_SOURCE_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00bc) }; +const DMA1_DEST_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c0) }; +const _DMA1_WORD_COUNT: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c4) }; // sound ignores this for some reason +const DMA1_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c6) }; + +const FIFOA_DEST_ADDR: u32 = 0x0400_00a0; + +// Similarly for proper timer support +const TIMER0_COUNTER: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0100) }; +const TIMER0_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0102) }; + +const SOUND_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0082) }; +const SOUND_CONTROL_X: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0084) }; + +pub(super) fn enable_dma1_for_sound(sound_memory: &[i8]) { + let dest_fixed: u16 = 2 << 5; // dest addr control = fixed + let repeat: u16 = 1 << 9; + let transfer_type: u16 = 1 << 10; // transfer in words + let dma_start_timing: u16 = 3 << 12; // sound fifo timing + let enable: u16 = 1 << 15; // enable + + DMA1_CONTROL.set(0); + DMA1_SOURCE_ADDR.set(sound_memory.as_ptr() as u32); + DMA1_DEST_ADDR.set(FIFOA_DEST_ADDR); + DMA1_CONTROL.set(dest_fixed | repeat | transfer_type | dma_start_timing | enable); +} + +pub(super) fn set_sound_control_register_for_mixer() { + let sound_a_volume_100: u16 = 1 << 2; + let sound_a_rout: u16 = 1 << 8; + let sound_a_lout: u16 = 1 << 9; + let sound_a_fifo_reset: u16 = 1 << 11; + + SOUND_CONTROL.set(sound_a_volume_100 | sound_a_rout | sound_a_lout | sound_a_fifo_reset); + + // master sound enable + SOUND_CONTROL_X.set(1 << 7); +} + +pub(super) fn set_timer_counter_for_frequency_and_enable(frequency: i32) { + let counter = 65536 - (16777216 / frequency); + TIMER0_COUNTER.set(counter as u16); + + TIMER0_CONTROL.set(1 << 7); // enable the timer +} diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs index 3c0fbfd..3c23260 100644 --- a/agb/src/sound/mixer/mod.rs +++ b/agb/src/sound/mixer/mod.rs @@ -1,4 +1,4 @@ -use crate::memory_mapped::MemoryMapped; +mod hw; #[non_exhaustive] pub struct MixerController {} @@ -27,8 +27,8 @@ impl Mixer { } pub fn enable(&self) { - set_timer_counter_for_frequency_and_enable(SOUND_FREQUENCY); - set_sound_control_register_for_mixer(); + hw::set_timer_counter_for_frequency_and_enable(SOUND_FREQUENCY); + hw::set_sound_control_register_for_mixer(); } pub fn vblank(&mut self) { @@ -118,9 +118,9 @@ impl MixerBuffer { self.buffer_1_active = !self.buffer_1_active; if self.buffer_1_active { - enable_dma1_for_sound(&self.buffer1); + hw::enable_dma1_for_sound(&self.buffer1); } else { - enable_dma1_for_sound(&self.buffer2); + hw::enable_dma1_for_sound(&self.buffer2); } } @@ -146,50 +146,3 @@ impl MixerBuffer { } } } - -// Once we have proper DMA support, we should use that rather than hard coding these here too -const DMA1_SOURCE_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00bc) }; -const DMA1_DEST_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c0) }; -const _DMA1_WORD_COUNT: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c4) }; // sound ignores this for some reason -const DMA1_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c6) }; - -const FIFOA_DEST_ADDR: u32 = 0x0400_00a0; - -// Similarly for proper timer support -const TIMER0_COUNTER: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0100) }; -const TIMER0_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0102) }; - -const SOUND_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0082) }; -const SOUND_CONTROL_X: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0084) }; - -fn enable_dma1_for_sound(sound_memory: &[i8]) { - let dest_fixed: u16 = 2 << 5; // dest addr control = fixed - let repeat: u16 = 1 << 9; - let transfer_type: u16 = 1 << 10; // transfer in words - let dma_start_timing: u16 = 3 << 12; // sound fifo timing - let enable: u16 = 1 << 15; // enable - - DMA1_CONTROL.set(0); - DMA1_SOURCE_ADDR.set(sound_memory.as_ptr() as u32); - DMA1_DEST_ADDR.set(FIFOA_DEST_ADDR); - DMA1_CONTROL.set(dest_fixed | repeat | transfer_type | dma_start_timing | enable); -} - -fn set_sound_control_register_for_mixer() { - let sound_a_volume_100: u16 = 1 << 2; - let sound_a_rout: u16 = 1 << 8; - let sound_a_lout: u16 = 1 << 9; - let sound_a_fifo_reset: u16 = 1 << 11; - - SOUND_CONTROL.set(sound_a_volume_100 | sound_a_rout | sound_a_lout | sound_a_fifo_reset); - - // master sound enable - SOUND_CONTROL_X.set(1 << 7); -} - -fn set_timer_counter_for_frequency_and_enable(frequency: i32) { - let counter = 65536 - (16777216 / frequency); - TIMER0_COUNTER.set(counter as u16); - - TIMER0_CONTROL.set(1 << 7); // enable the timer -} From ffd4f8e773f6d00510238f3049d1380240bed3d3 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 22:25:33 +0100 Subject: [PATCH 03/19] Extract mixer code to mixer.rs --- agb/src/sound/mixer/mixer.rs | 115 ++++++++++++++++++++++++++++++++++ agb/src/sound/mixer/mod.rs | 116 +---------------------------------- 2 files changed, 118 insertions(+), 113 deletions(-) create mode 100644 agb/src/sound/mixer/mixer.rs diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs new file mode 100644 index 0000000..323f7d6 --- /dev/null +++ b/agb/src/sound/mixer/mixer.rs @@ -0,0 +1,115 @@ +use super::hw; +use super::SoundChannel; + +pub struct Mixer { + buffer: MixerBuffer, + channels: [Option; 16], +} + +impl Mixer { + pub(super) fn new() -> Self { + Mixer { + buffer: MixerBuffer::new(), + channels: Default::default(), + } + } + + pub fn enable(&self) { + hw::set_timer_counter_for_frequency_and_enable(SOUND_FREQUENCY); + hw::set_sound_control_register_for_mixer(); + } + + pub fn vblank(&mut self) { + self.buffer.swap(); + self.buffer.clear(); + + for channel in self.channels.iter_mut() { + let mut has_finished = false; + + if let Some(some_channel) = channel { + self.buffer.write_channel(some_channel); + some_channel.pos += SOUND_BUFFER_SIZE; + + if some_channel.pos >= some_channel.data.len() { + if some_channel.should_loop { + some_channel.pos = 0; + } else { + has_finished = true; + } + } + } + + if has_finished { + channel.take(); + } + } + } + + pub fn play_sound(&mut self, new_channel: SoundChannel) { + for channel in self.channels.iter_mut() { + if channel.is_some() { + continue; + } + + channel.replace(new_channel); + return; + } + + panic!("Cannot play more than 16 sounds at once"); + } +} + +// I've picked one frequency that works nicely. But there are others that work nicely +// which we may want to consider in the future: https://web.archive.org/web/20070608011909/http://deku.gbadev.org/program/sound1.html +const SOUND_FREQUENCY: i32 = 10512; +const SOUND_BUFFER_SIZE: usize = 176; + +struct MixerBuffer { + buffer1: [i8; SOUND_BUFFER_SIZE], + buffer2: [i8; SOUND_BUFFER_SIZE], + + buffer_1_active: bool, +} + +impl MixerBuffer { + fn new() -> Self { + MixerBuffer { + buffer1: [0; SOUND_BUFFER_SIZE], + buffer2: [0; SOUND_BUFFER_SIZE], + + buffer_1_active: true, + } + } + + fn swap(&mut self) { + self.buffer_1_active = !self.buffer_1_active; + + if self.buffer_1_active { + hw::enable_dma1_for_sound(&self.buffer1); + } else { + hw::enable_dma1_for_sound(&self.buffer2); + } + } + + fn clear(&mut self) { + self.get_write_buffer().fill(0); + } + + fn write_channel(&mut self, channel: &SoundChannel) { + let data_to_copy = &channel.data[channel.pos..]; + let place_to_write_to = self.get_write_buffer(); + + for (i, v) in data_to_copy.iter().take(SOUND_BUFFER_SIZE).enumerate() { + let v = *v as i8; + place_to_write_to[i] = place_to_write_to[i].saturating_add(v); + } + } + + fn get_write_buffer(&mut self) -> &mut [i8; SOUND_BUFFER_SIZE] { + if self.buffer_1_active { + &mut self.buffer2 + } else { + &mut self.buffer1 + } + } +} diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs index 3c23260..5e6f801 100644 --- a/agb/src/sound/mixer/mod.rs +++ b/agb/src/sound/mixer/mod.rs @@ -1,4 +1,7 @@ mod hw; +mod mixer; + +pub use mixer::Mixer; #[non_exhaustive] pub struct MixerController {} @@ -13,64 +16,6 @@ impl MixerController { } } -pub struct Mixer { - buffer: MixerBuffer, - channels: [Option; 16], -} - -impl Mixer { - fn new() -> Self { - Mixer { - buffer: MixerBuffer::new(), - channels: Default::default(), - } - } - - pub fn enable(&self) { - hw::set_timer_counter_for_frequency_and_enable(SOUND_FREQUENCY); - hw::set_sound_control_register_for_mixer(); - } - - pub fn vblank(&mut self) { - self.buffer.swap(); - self.buffer.clear(); - - for channel in self.channels.iter_mut() { - let mut has_finished = false; - - if let Some(some_channel) = channel { - self.buffer.write_channel(some_channel); - some_channel.pos += SOUND_BUFFER_SIZE; - - if some_channel.pos >= some_channel.data.len() { - if some_channel.should_loop { - some_channel.pos = 0; - } else { - has_finished = true; - } - } - } - - if has_finished { - channel.take(); - } - } - } - - pub fn play_sound(&mut self, new_channel: SoundChannel) { - for channel in self.channels.iter_mut() { - if channel.is_some() { - continue; - } - - channel.replace(new_channel); - return; - } - - panic!("Cannot play more than 16 sounds at once"); - } -} - pub struct SoundChannel { data: &'static [u8], pos: usize, @@ -91,58 +36,3 @@ impl SoundChannel { self } } - -// I've picked one frequency that works nicely. But there are others that work nicely -// which we may want to consider in the future: https://web.archive.org/web/20070608011909/http://deku.gbadev.org/program/sound1.html -const SOUND_FREQUENCY: i32 = 10512; -const SOUND_BUFFER_SIZE: usize = 176; - -struct MixerBuffer { - buffer1: [i8; SOUND_BUFFER_SIZE], - buffer2: [i8; SOUND_BUFFER_SIZE], - - buffer_1_active: bool, -} - -impl MixerBuffer { - fn new() -> Self { - MixerBuffer { - buffer1: [0; SOUND_BUFFER_SIZE], - buffer2: [0; SOUND_BUFFER_SIZE], - - buffer_1_active: true, - } - } - - fn swap(&mut self) { - self.buffer_1_active = !self.buffer_1_active; - - if self.buffer_1_active { - hw::enable_dma1_for_sound(&self.buffer1); - } else { - hw::enable_dma1_for_sound(&self.buffer2); - } - } - - fn clear(&mut self) { - self.get_write_buffer().fill(0); - } - - fn write_channel(&mut self, channel: &SoundChannel) { - let data_to_copy = &channel.data[channel.pos..]; - let place_to_write_to = self.get_write_buffer(); - - for (i, v) in data_to_copy.iter().take(SOUND_BUFFER_SIZE).enumerate() { - let v = *v as i8; - place_to_write_to[i] = place_to_write_to[i].saturating_add(v); - } - } - - fn get_write_buffer(&mut self) -> &mut [i8; SOUND_BUFFER_SIZE] { - if self.buffer_1_active { - &mut self.buffer2 - } else { - &mut self.buffer1 - } - } -} From c5d58e83a7af213655f6f02a1c08afd851c8dcf4 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 22:32:02 +0100 Subject: [PATCH 04/19] Add ability for DMA2 to do something --- agb/src/sound/mixer/hw.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/agb/src/sound/mixer/hw.rs b/agb/src/sound/mixer/hw.rs index 43d3bf7..c8abe42 100644 --- a/agb/src/sound/mixer/hw.rs +++ b/agb/src/sound/mixer/hw.rs @@ -6,7 +6,13 @@ const DMA1_DEST_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c0 const _DMA1_WORD_COUNT: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c4) }; // sound ignores this for some reason const DMA1_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c6) }; +const DMA2_SOURCE_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00ca) }; +const DMA2_DEST_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00cc) }; +const _DMA2_WORD_COUNT: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00d0) }; +const DMA2_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00d2) }; + const FIFOA_DEST_ADDR: u32 = 0x0400_00a0; +const FIFOB_DEST_ADDR: u32 = 0x0400_00a4; // Similarly for proper timer support const TIMER0_COUNTER: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0100) }; @@ -15,17 +21,28 @@ const TIMER0_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0102 const SOUND_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0082) }; const SOUND_CONTROL_X: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0084) }; -pub(super) fn enable_dma1_for_sound(sound_memory: &[i8]) { +const DMA_CONTROL_SETTING_FOR_SOUND: u16 = { let dest_fixed: u16 = 2 << 5; // dest addr control = fixed let repeat: u16 = 1 << 9; let transfer_type: u16 = 1 << 10; // transfer in words let dma_start_timing: u16 = 3 << 12; // sound fifo timing let enable: u16 = 1 << 15; // enable + dest_fixed | repeat | transfer_type | dma_start_timing | enable +}; + +pub(super) fn enable_dma1_for_sound(sound_memory: &[i8]) { DMA1_CONTROL.set(0); DMA1_SOURCE_ADDR.set(sound_memory.as_ptr() as u32); DMA1_DEST_ADDR.set(FIFOA_DEST_ADDR); - DMA1_CONTROL.set(dest_fixed | repeat | transfer_type | dma_start_timing | enable); + DMA1_CONTROL.set(DMA_CONTROL_SETTING_FOR_SOUND); +} + +pub(super) fn enable_dma2_for_sound(sound_memory: &[i8]) { + DMA2_CONTROL.set(0); + DMA2_SOURCE_ADDR.set(sound_memory.as_ptr() as u32); + DMA2_DEST_ADDR.set(FIFOB_DEST_ADDR); + DMA2_CONTROL.set(DMA_CONTROL_SETTING_FOR_SOUND); } pub(super) fn set_sound_control_register_for_mixer() { From 74f2fdbc8bf0ff157260b1ee582e8404a4d2ba3b Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 22:34:04 +0100 Subject: [PATCH 05/19] Tell GBA that we want 2 channels --- agb/src/sound/mixer/hw.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/agb/src/sound/mixer/hw.rs b/agb/src/sound/mixer/hw.rs index c8abe42..313e9a0 100644 --- a/agb/src/sound/mixer/hw.rs +++ b/agb/src/sound/mixer/hw.rs @@ -47,11 +47,25 @@ pub(super) fn enable_dma2_for_sound(sound_memory: &[i8]) { pub(super) fn set_sound_control_register_for_mixer() { let sound_a_volume_100: u16 = 1 << 2; - let sound_a_rout: u16 = 1 << 8; + let sound_a_rout: u16 = 0 << 8; // sound A is for left channel only let sound_a_lout: u16 = 1 << 9; let sound_a_fifo_reset: u16 = 1 << 11; - SOUND_CONTROL.set(sound_a_volume_100 | sound_a_rout | sound_a_lout | sound_a_fifo_reset); + let sound_b_volume_100: u16 = 1 << 3; + let sound_b_rout: u16 = 1 << 12; + let sound_b_lout: u16 = 1 << 13; + let sound_b_fifo_reset: u16 = 1 << 15; + + SOUND_CONTROL.set( + sound_a_volume_100 + | sound_a_rout + | sound_a_lout + | sound_a_fifo_reset + | sound_b_volume_100 + | sound_b_rout + | sound_b_lout + | sound_b_fifo_reset, + ); // master sound enable SOUND_CONTROL_X.set(1 << 7); From a41bb0b89be052f2eb6164aa41a5c40e4228ba13 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 22:42:04 +0100 Subject: [PATCH 06/19] Have 2 buffers for left or right control --- agb/src/sound/mixer/hw.rs | 17 +++++++++++++++-- agb/src/sound/mixer/mixer.rs | 25 +++++++++++++++++-------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/agb/src/sound/mixer/hw.rs b/agb/src/sound/mixer/hw.rs index 313e9a0..2c10275 100644 --- a/agb/src/sound/mixer/hw.rs +++ b/agb/src/sound/mixer/hw.rs @@ -31,14 +31,27 @@ const DMA_CONTROL_SETTING_FOR_SOUND: u16 = { dest_fixed | repeat | transfer_type | dma_start_timing | enable }; -pub(super) fn enable_dma1_for_sound(sound_memory: &[i8]) { +#[derive(Copy, Clone)] +pub(super) enum LeftOrRight { + Left, + Right, +} + +pub(super) fn enable_dma_for_sound(sound_memory: &[i8], lr: LeftOrRight) { + match lr { + LeftOrRight::Left => enable_dma1_for_sound(sound_memory), + LeftOrRight::Right => enable_dma2_for_sound(sound_memory), + } +} + +fn enable_dma1_for_sound(sound_memory: &[i8]) { DMA1_CONTROL.set(0); DMA1_SOURCE_ADDR.set(sound_memory.as_ptr() as u32); DMA1_DEST_ADDR.set(FIFOA_DEST_ADDR); DMA1_CONTROL.set(DMA_CONTROL_SETTING_FOR_SOUND); } -pub(super) fn enable_dma2_for_sound(sound_memory: &[i8]) { +fn enable_dma2_for_sound(sound_memory: &[i8]) { DMA2_CONTROL.set(0); DMA2_SOURCE_ADDR.set(sound_memory.as_ptr() as u32); DMA2_DEST_ADDR.set(FIFOB_DEST_ADDR); diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs index 323f7d6..a88d035 100644 --- a/agb/src/sound/mixer/mixer.rs +++ b/agb/src/sound/mixer/mixer.rs @@ -1,15 +1,18 @@ use super::hw; +use super::hw::LeftOrRight; use super::SoundChannel; pub struct Mixer { - buffer: MixerBuffer, + buffer_l: MixerBuffer, + buffer_r: MixerBuffer, channels: [Option; 16], } impl Mixer { pub(super) fn new() -> Self { Mixer { - buffer: MixerBuffer::new(), + buffer_l: MixerBuffer::new(LeftOrRight::Left), + buffer_r: MixerBuffer::new(LeftOrRight::Right), channels: Default::default(), } } @@ -20,14 +23,17 @@ impl Mixer { } pub fn vblank(&mut self) { - self.buffer.swap(); - self.buffer.clear(); + self.buffer_l.swap(); + self.buffer_r.swap(); + self.buffer_l.clear(); + self.buffer_r.clear(); for channel in self.channels.iter_mut() { let mut has_finished = false; if let Some(some_channel) = channel { - self.buffer.write_channel(some_channel); + self.buffer_l.write_channel(some_channel); + self.buffer_r.write_channel(some_channel); some_channel.pos += SOUND_BUFFER_SIZE; if some_channel.pos >= some_channel.data.len() { @@ -69,15 +75,18 @@ struct MixerBuffer { buffer2: [i8; SOUND_BUFFER_SIZE], buffer_1_active: bool, + + lr: LeftOrRight, } impl MixerBuffer { - fn new() -> Self { + fn new(lr: LeftOrRight) -> Self { MixerBuffer { buffer1: [0; SOUND_BUFFER_SIZE], buffer2: [0; SOUND_BUFFER_SIZE], buffer_1_active: true, + lr, } } @@ -85,9 +94,9 @@ impl MixerBuffer { self.buffer_1_active = !self.buffer_1_active; if self.buffer_1_active { - hw::enable_dma1_for_sound(&self.buffer1); + hw::enable_dma_for_sound(&self.buffer1, self.lr); } else { - hw::enable_dma1_for_sound(&self.buffer2); + hw::enable_dma_for_sound(&self.buffer2, self.lr); } } From 54e949888623a1ff17e4294beaf0f076ecfefa7d Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 22:43:37 +0100 Subject: [PATCH 07/19] Add usize implementation for Number --- agb/src/number.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/agb/src/number.rs b/agb/src/number.rs index a4f0238..bb22a1a 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -86,6 +86,7 @@ fixed_width_unsigned_integer_impl!(i16); fixed_width_unsigned_integer_impl!(u16); fixed_width_unsigned_integer_impl!(i32); fixed_width_unsigned_integer_impl!(u32); +fixed_width_unsigned_integer_impl!(usize); fixed_width_signed_integer_impl!(i16); fixed_width_signed_integer_impl!(i32); From 5b1f85a6195a22595d28999b6128bd19d9d1ebbe Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 22:46:21 +0100 Subject: [PATCH 08/19] Make the current position in the audio sample a fix point --- agb/src/sound/mixer/mixer.rs | 6 +++--- agb/src/sound/mixer/mod.rs | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs index a88d035..9d38671 100644 --- a/agb/src/sound/mixer/mixer.rs +++ b/agb/src/sound/mixer/mixer.rs @@ -36,9 +36,9 @@ impl Mixer { self.buffer_r.write_channel(some_channel); some_channel.pos += SOUND_BUFFER_SIZE; - if some_channel.pos >= some_channel.data.len() { + if some_channel.pos.floor() >= some_channel.data.len() { if some_channel.should_loop { - some_channel.pos = 0; + some_channel.pos = 0.into(); } else { has_finished = true; } @@ -105,7 +105,7 @@ impl MixerBuffer { } fn write_channel(&mut self, channel: &SoundChannel) { - let data_to_copy = &channel.data[channel.pos..]; + let data_to_copy = &channel.data[channel.pos.floor()..]; let place_to_write_to = self.get_write_buffer(); for (i, v) in data_to_copy.iter().take(SOUND_BUFFER_SIZE).enumerate() { diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs index 5e6f801..99ead31 100644 --- a/agb/src/sound/mixer/mod.rs +++ b/agb/src/sound/mixer/mod.rs @@ -3,6 +3,8 @@ mod mixer; pub use mixer::Mixer; +use crate::number::Num; + #[non_exhaustive] pub struct MixerController {} @@ -18,7 +20,7 @@ impl MixerController { pub struct SoundChannel { data: &'static [u8], - pos: usize, + pos: Num, should_loop: bool, } @@ -26,7 +28,7 @@ impl SoundChannel { pub fn new(data: &'static [u8]) -> Self { SoundChannel { data, - pos: 0, + pos: 0.into(), should_loop: false, } } From 9b77ab75875d0a69d3e5d129f72b25d6ee28b645 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 23:00:00 +0100 Subject: [PATCH 09/19] Allow controlling of playback speed --- agb/src/sound/mixer/mixer.rs | 80 ++++++++++++++++-------------------- agb/src/sound/mixer/mod.rs | 8 ++++ 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs index 9d38671..1d4602a 100644 --- a/agb/src/sound/mixer/mixer.rs +++ b/agb/src/sound/mixer/mixer.rs @@ -3,16 +3,14 @@ use super::hw::LeftOrRight; use super::SoundChannel; pub struct Mixer { - buffer_l: MixerBuffer, - buffer_r: MixerBuffer, + buffer: MixerBuffer, channels: [Option; 16], } impl Mixer { pub(super) fn new() -> Self { Mixer { - buffer_l: MixerBuffer::new(LeftOrRight::Left), - buffer_r: MixerBuffer::new(LeftOrRight::Right), + buffer: MixerBuffer::new(), channels: Default::default(), } } @@ -23,31 +21,15 @@ impl Mixer { } pub fn vblank(&mut self) { - self.buffer_l.swap(); - self.buffer_r.swap(); - self.buffer_l.clear(); - self.buffer_r.clear(); + self.buffer.swap(); + self.buffer.clear(); for channel in self.channels.iter_mut() { - let mut has_finished = false; - if let Some(some_channel) = channel { - self.buffer_l.write_channel(some_channel); - self.buffer_r.write_channel(some_channel); - some_channel.pos += SOUND_BUFFER_SIZE; - - if some_channel.pos.floor() >= some_channel.data.len() { - if some_channel.should_loop { - some_channel.pos = 0.into(); - } else { - has_finished = true; - } + if self.buffer.write_channel(some_channel) { + channel.take(); } } - - if has_finished { - channel.take(); - } } } @@ -71,50 +53,60 @@ const SOUND_FREQUENCY: i32 = 10512; const SOUND_BUFFER_SIZE: usize = 176; struct MixerBuffer { - buffer1: [i8; SOUND_BUFFER_SIZE], - buffer2: [i8; SOUND_BUFFER_SIZE], + buffer1: [i8; SOUND_BUFFER_SIZE * 2], // first half is left, second is right + buffer2: [i8; SOUND_BUFFER_SIZE * 2], buffer_1_active: bool, - - lr: LeftOrRight, } impl MixerBuffer { - fn new(lr: LeftOrRight) -> Self { + fn new() -> Self { MixerBuffer { - buffer1: [0; SOUND_BUFFER_SIZE], - buffer2: [0; SOUND_BUFFER_SIZE], + buffer1: [0; SOUND_BUFFER_SIZE * 2], + buffer2: [0; SOUND_BUFFER_SIZE * 2], buffer_1_active: true, - lr, } } fn swap(&mut self) { - self.buffer_1_active = !self.buffer_1_active; + let (left_buffer, right_buffer) = self.get_write_buffer().split_at(SOUND_BUFFER_SIZE); - if self.buffer_1_active { - hw::enable_dma_for_sound(&self.buffer1, self.lr); - } else { - hw::enable_dma_for_sound(&self.buffer2, self.lr); - } + hw::enable_dma_for_sound(left_buffer, LeftOrRight::Left); + hw::enable_dma_for_sound(right_buffer, LeftOrRight::Right); + + self.buffer_1_active = !self.buffer_1_active; } fn clear(&mut self) { self.get_write_buffer().fill(0); } - fn write_channel(&mut self, channel: &SoundChannel) { - let data_to_copy = &channel.data[channel.pos.floor()..]; + fn write_channel(&mut self, channel: &mut SoundChannel) -> bool { let place_to_write_to = self.get_write_buffer(); + let mut current_point = channel.pos; - for (i, v) in data_to_copy.iter().take(SOUND_BUFFER_SIZE).enumerate() { - let v = *v as i8; - place_to_write_to[i] = place_to_write_to[i].saturating_add(v); + for i in 0..SOUND_BUFFER_SIZE { + let v = channel.data[current_point.floor()]; + current_point += channel.playback_speed; + + if current_point.floor() >= channel.data.len() { + if channel.should_loop { + channel.pos -= channel.data.len(); + } else { + return true; + } + } + + place_to_write_to[i] = place_to_write_to[i].saturating_add(v as i8); + place_to_write_to[i + SOUND_BUFFER_SIZE] = + place_to_write_to[i + SOUND_BUFFER_SIZE].saturating_add(v as i8); } + + false } - fn get_write_buffer(&mut self) -> &mut [i8; SOUND_BUFFER_SIZE] { + fn get_write_buffer(&mut self) -> &mut [i8; SOUND_BUFFER_SIZE * 2] { if self.buffer_1_active { &mut self.buffer2 } else { diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs index 99ead31..3acc8bc 100644 --- a/agb/src/sound/mixer/mod.rs +++ b/agb/src/sound/mixer/mod.rs @@ -22,6 +22,8 @@ pub struct SoundChannel { data: &'static [u8], pos: Num, should_loop: bool, + + playback_speed: Num, } impl SoundChannel { @@ -30,6 +32,7 @@ impl SoundChannel { data, pos: 0.into(), should_loop: false, + playback_speed: 1.into(), } } @@ -37,4 +40,9 @@ impl SoundChannel { self.should_loop = true; self } + + pub fn playback(mut self, playback_speed: Num) -> Self { + self.playback_speed = playback_speed; + self + } } From 063af3fc400fe550da9061eba75d9888c9e83cf2 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 23:34:03 +0100 Subject: [PATCH 10/19] Panning working? --- agb/src/number.rs | 9 +++++++ agb/src/sound/mixer/mixer.rs | 51 ++++++++++++++++++++---------------- agb/src/sound/mixer/mod.rs | 11 ++++++++ 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/agb/src/number.rs b/agb/src/number.rs index bb22a1a..d9ac36a 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -103,6 +103,15 @@ impl From for Num { } } +impl Default for Num +where + I: FixedWidthUnsignedInteger, +{ + fn default() -> Self { + Num(I::zero()) + } +} + impl Add for Num where I: FixedWidthUnsignedInteger, diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs index 1d4602a..f79d064 100644 --- a/agb/src/sound/mixer/mixer.rs +++ b/agb/src/sound/mixer/mixer.rs @@ -1,6 +1,7 @@ use super::hw; use super::hw::LeftOrRight; use super::SoundChannel; +use crate::number::Num; pub struct Mixer { buffer: MixerBuffer, @@ -24,13 +25,8 @@ impl Mixer { self.buffer.swap(); self.buffer.clear(); - for channel in self.channels.iter_mut() { - if let Some(some_channel) = channel { - if self.buffer.write_channel(some_channel) { - channel.take(); - } - } - } + self.buffer + .write_channels(self.channels.iter_mut().flatten()); } pub fn play_sound(&mut self, new_channel: SoundChannel) { @@ -82,28 +78,37 @@ impl MixerBuffer { self.get_write_buffer().fill(0); } - fn write_channel(&mut self, channel: &mut SoundChannel) -> bool { - let place_to_write_to = self.get_write_buffer(); - let mut current_point = channel.pos; + fn write_channels<'a>(&mut self, channels: impl Iterator) { + let mut buffer: [Num; SOUND_BUFFER_SIZE * 2] = [Num::new(0); SOUND_BUFFER_SIZE * 2]; - for i in 0..SOUND_BUFFER_SIZE { - let v = channel.data[current_point.floor()]; - current_point += channel.playback_speed; + for channel in channels { + let mut current_point = channel.pos; - if current_point.floor() >= channel.data.len() { - if channel.should_loop { - channel.pos -= channel.data.len(); - } else { - return true; + let right_amount = (channel.panning - 1) / 2; + let left_amount = -right_amount + 1; + + for i in 0..SOUND_BUFFER_SIZE { + let v = (channel.data[current_point.floor()] as i8) as i16; + let v: Num = v.into(); + current_point += channel.playback_speed; + + if current_point.floor() >= channel.data.len() { + if channel.should_loop { + channel.pos -= channel.data.len(); + } else { + continue; + } } - } - place_to_write_to[i] = place_to_write_to[i].saturating_add(v as i8); - place_to_write_to[i + SOUND_BUFFER_SIZE] = - place_to_write_to[i + SOUND_BUFFER_SIZE].saturating_add(v as i8); + buffer[i] += v * left_amount; + buffer[i + SOUND_BUFFER_SIZE] += v * right_amount; + } } - false + let write_buffer = self.get_write_buffer(); + for i in 0..SOUND_BUFFER_SIZE * 2 { + write_buffer[i] = buffer[i].floor().clamp(i8::MIN as i16, i8::MAX as i16) as i8 + } } fn get_write_buffer(&mut self) -> &mut [i8; SOUND_BUFFER_SIZE * 2] { diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs index 3acc8bc..280f111 100644 --- a/agb/src/sound/mixer/mod.rs +++ b/agb/src/sound/mixer/mod.rs @@ -24,6 +24,8 @@ pub struct SoundChannel { should_loop: bool, playback_speed: Num, + + panning: Num, // between -1 and 1 } impl SoundChannel { @@ -33,6 +35,7 @@ impl SoundChannel { pos: 0.into(), should_loop: false, playback_speed: 1.into(), + panning: 0.into(), } } @@ -45,4 +48,12 @@ impl SoundChannel { self.playback_speed = playback_speed; self } + + pub fn panning(mut self, panning: Num) -> Self { + debug_assert!(panning >= Num::new(-1), "panning value must be >= -1"); + debug_assert!(panning <= Num::new(1), "panning value must be <= 1"); + + self.panning = panning; + self + } } From f82ed3d7c189208ca883120bc06c196f94e34060 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 23:35:12 +0100 Subject: [PATCH 11/19] Keep track of whether a channel is done --- agb/src/sound/mixer/mixer.rs | 5 +++++ agb/src/sound/mixer/mod.rs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs index f79d064..f66030d 100644 --- a/agb/src/sound/mixer/mixer.rs +++ b/agb/src/sound/mixer/mixer.rs @@ -82,6 +82,10 @@ impl MixerBuffer { let mut buffer: [Num; SOUND_BUFFER_SIZE * 2] = [Num::new(0); SOUND_BUFFER_SIZE * 2]; for channel in channels { + if channel.is_done { + continue; + } + let mut current_point = channel.pos; let right_amount = (channel.panning - 1) / 2; @@ -96,6 +100,7 @@ impl MixerBuffer { if channel.should_loop { channel.pos -= channel.data.len(); } else { + channel.is_done = true; continue; } } diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs index 280f111..d445c04 100644 --- a/agb/src/sound/mixer/mod.rs +++ b/agb/src/sound/mixer/mod.rs @@ -26,6 +26,7 @@ pub struct SoundChannel { playback_speed: Num, panning: Num, // between -1 and 1 + is_done: bool, } impl SoundChannel { @@ -36,6 +37,7 @@ impl SoundChannel { should_loop: false, playback_speed: 1.into(), panning: 0.into(), + is_done: false, } } From bcee6be7df4a6524f2b4be5b711f473c3b26739b Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 23:45:19 +0100 Subject: [PATCH 12/19] Fix issues discovered while testing --- agb/src/sound/mixer/mixer.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs index f66030d..f78779f 100644 --- a/agb/src/sound/mixer/mixer.rs +++ b/agb/src/sound/mixer/mixer.rs @@ -31,8 +31,10 @@ impl Mixer { pub fn play_sound(&mut self, new_channel: SoundChannel) { for channel in self.channels.iter_mut() { - if channel.is_some() { - continue; + if let Some(some_channel) = channel { + if !some_channel.is_done { + continue; + } } channel.replace(new_channel); @@ -86,17 +88,11 @@ impl MixerBuffer { continue; } - let mut current_point = channel.pos; - let right_amount = (channel.panning - 1) / 2; let left_amount = -right_amount + 1; for i in 0..SOUND_BUFFER_SIZE { - let v = (channel.data[current_point.floor()] as i8) as i16; - let v: Num = v.into(); - current_point += channel.playback_speed; - - if current_point.floor() >= channel.data.len() { + if channel.pos.floor() >= channel.data.len() { if channel.should_loop { channel.pos -= channel.data.len(); } else { @@ -105,8 +101,12 @@ impl MixerBuffer { } } - buffer[i] += v * left_amount; - buffer[i + SOUND_BUFFER_SIZE] += v * right_amount; + let v = (channel.data[channel.pos.floor()] as i8) as i16; + let v: Num = v.into(); + channel.pos += channel.playback_speed; + + buffer[i] += v; + buffer[i + SOUND_BUFFER_SIZE] += v; } } From 898620112b6243071d7d880eac80f2748e64386f Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 23:46:46 +0100 Subject: [PATCH 13/19] Reinstate panning --- agb/src/sound/mixer/mixer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs index f78779f..1106fa4 100644 --- a/agb/src/sound/mixer/mixer.rs +++ b/agb/src/sound/mixer/mixer.rs @@ -105,8 +105,8 @@ impl MixerBuffer { let v: Num = v.into(); channel.pos += channel.playback_speed; - buffer[i] += v; - buffer[i + SOUND_BUFFER_SIZE] += v; + buffer[i] += v * left_amount; + buffer[i + SOUND_BUFFER_SIZE] += v * right_amount; } } From d28b885e29e262376081f3a2f3c77aa77c83aaf6 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 10 Jun 2021 23:56:27 +0100 Subject: [PATCH 14/19] Shouldn't output to the left with channel B --- agb/src/sound/mixer/hw.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agb/src/sound/mixer/hw.rs b/agb/src/sound/mixer/hw.rs index 2c10275..9d3c8fa 100644 --- a/agb/src/sound/mixer/hw.rs +++ b/agb/src/sound/mixer/hw.rs @@ -66,7 +66,7 @@ pub(super) fn set_sound_control_register_for_mixer() { let sound_b_volume_100: u16 = 1 << 3; let sound_b_rout: u16 = 1 << 12; - let sound_b_lout: u16 = 1 << 13; + let sound_b_lout: u16 = 0 << 13; let sound_b_fifo_reset: u16 = 1 << 15; SOUND_CONTROL.set( From e88eb16c622cf7e82e9edff7ffba25f933c579c3 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Fri, 11 Jun 2021 00:10:06 +0100 Subject: [PATCH 15/19] Calculate panning correctly --- agb/src/sound/mixer/mixer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs index 1106fa4..9f76b66 100644 --- a/agb/src/sound/mixer/mixer.rs +++ b/agb/src/sound/mixer/mixer.rs @@ -88,7 +88,7 @@ impl MixerBuffer { continue; } - let right_amount = (channel.panning - 1) / 2; + let right_amount = (channel.panning + 1) / 2; let left_amount = -right_amount + 1; for i in 0..SOUND_BUFFER_SIZE { From 11a74979ebfc9bc6641d04eedb31b449b29b98e7 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Fri, 18 Jun 2021 22:21:55 +0100 Subject: [PATCH 16/19] Fix unaligned write --- agb/src/sound/mixer/hw.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/agb/src/sound/mixer/hw.rs b/agb/src/sound/mixer/hw.rs index 9d3c8fa..c055638 100644 --- a/agb/src/sound/mixer/hw.rs +++ b/agb/src/sound/mixer/hw.rs @@ -1,15 +1,25 @@ use crate::memory_mapped::MemoryMapped; -// Once we have proper DMA support, we should use that rather than hard coding these here too -const DMA1_SOURCE_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00bc) }; -const DMA1_DEST_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c0) }; -const _DMA1_WORD_COUNT: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c4) }; // sound ignores this for some reason -const DMA1_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00c6) }; +const fn dma_source_addr(dma: usize) -> usize { + 0x0400_00b0 + 0x0c * dma +} -const DMA2_SOURCE_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00ca) }; -const DMA2_DEST_ADDR: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00cc) }; -const _DMA2_WORD_COUNT: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00d0) }; -const DMA2_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_00d2) }; +const fn dma_dest_addr(dma: usize) -> usize { + 0x0400_00b4 + 0x0c * dma +} + +const fn dma_control_addr(dma: usize) -> usize { + 0x0400_00ba + 0x0c * dma +} + +// Once we have proper DMA support, we should use that rather than hard coding these here too +const DMA1_SOURCE_ADDR: MemoryMapped = unsafe { MemoryMapped::new(dma_source_addr(1)) }; +const DMA1_DEST_ADDR: MemoryMapped = unsafe { MemoryMapped::new(dma_dest_addr(1)) }; +const DMA1_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(dma_control_addr(1)) }; + +const DMA2_SOURCE_ADDR: MemoryMapped = unsafe { MemoryMapped::new(dma_source_addr(2)) }; +const DMA2_DEST_ADDR: MemoryMapped = unsafe { MemoryMapped::new(dma_dest_addr(2)) }; +const DMA2_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(dma_control_addr(2)) }; const FIFOA_DEST_ADDR: u32 = 0x0400_00a0; const FIFOB_DEST_ADDR: u32 = 0x0400_00a4; From ea9441f40b10426fc1c9640252f2797878182d59 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Fri, 18 Jun 2021 22:28:11 +0100 Subject: [PATCH 17/19] Don't need to go through archive.org --- agb/src/sound/mixer/mixer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs index 9f76b66..45e5f8f 100644 --- a/agb/src/sound/mixer/mixer.rs +++ b/agb/src/sound/mixer/mixer.rs @@ -46,7 +46,7 @@ impl Mixer { } // I've picked one frequency that works nicely. But there are others that work nicely -// which we may want to consider in the future: https://web.archive.org/web/20070608011909/http://deku.gbadev.org/program/sound1.html +// which we may want to consider in the future: http://deku.gbadev.org/program/sound1.html const SOUND_FREQUENCY: i32 = 10512; const SOUND_BUFFER_SIZE: usize = 176; From 057467ecf8a0a5140fc09a3b3ab830df4e201e34 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Fri, 18 Jun 2021 22:56:49 +0100 Subject: [PATCH 18/19] Only do the if statement once per channel rather than once per index --- agb/src/sound/mixer/mixer.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/mixer.rs index 45e5f8f..69484d4 100644 --- a/agb/src/sound/mixer/mixer.rs +++ b/agb/src/sound/mixer/mixer.rs @@ -91,22 +91,23 @@ impl MixerBuffer { let right_amount = (channel.panning + 1) / 2; let left_amount = -right_amount + 1; - for i in 0..SOUND_BUFFER_SIZE { - if channel.pos.floor() >= channel.data.len() { - if channel.should_loop { - channel.pos -= channel.data.len(); - } else { - channel.is_done = true; - continue; - } + if channel.pos + channel.playback_speed * SOUND_BUFFER_SIZE >= channel.data.len().into() + { + // TODO: This should probably play what's left rather than skip the last bit + if channel.should_loop { + channel.pos -= channel.data.len(); + } else { + channel.is_done = true; + continue; } + } + for i in 0..SOUND_BUFFER_SIZE { let v = (channel.data[channel.pos.floor()] as i8) as i16; - let v: Num = v.into(); channel.pos += channel.playback_speed; - buffer[i] += v * left_amount; - buffer[i + SOUND_BUFFER_SIZE] += v * right_amount; + buffer[i] += left_amount * v; + buffer[i + SOUND_BUFFER_SIZE] += right_amount * v; } } From db4233cceee361a46e68d59b845cdd86b51ca64a Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sun, 20 Jun 2021 21:29:44 +0100 Subject: [PATCH 19/19] Rename mixer.rs to sw_mixer.rs --- agb/src/sound/mixer/mod.rs | 4 ++-- agb/src/sound/mixer/{mixer.rs => sw_mixer.rs} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename agb/src/sound/mixer/{mixer.rs => sw_mixer.rs} (100%) diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs index d445c04..06875cd 100644 --- a/agb/src/sound/mixer/mod.rs +++ b/agb/src/sound/mixer/mod.rs @@ -1,7 +1,7 @@ mod hw; -mod mixer; +mod sw_mixer; -pub use mixer::Mixer; +pub use sw_mixer::Mixer; use crate::number::Num; diff --git a/agb/src/sound/mixer/mixer.rs b/agb/src/sound/mixer/sw_mixer.rs similarity index 100% rename from agb/src/sound/mixer/mixer.rs rename to agb/src/sound/mixer/sw_mixer.rs