Allow controlling of playback speed

This commit is contained in:
Gwilym Kuiper 2021-06-10 23:00:00 +01:00
parent 5b1f85a619
commit 9b77ab7587
2 changed files with 44 additions and 44 deletions

View file

@ -3,16 +3,14 @@ use super::hw::LeftOrRight;
use super::SoundChannel; use super::SoundChannel;
pub struct Mixer { pub struct Mixer {
buffer_l: MixerBuffer, buffer: MixerBuffer,
buffer_r: MixerBuffer,
channels: [Option<SoundChannel>; 16], channels: [Option<SoundChannel>; 16],
} }
impl Mixer { impl Mixer {
pub(super) fn new() -> Self { pub(super) fn new() -> Self {
Mixer { Mixer {
buffer_l: MixerBuffer::new(LeftOrRight::Left), buffer: MixerBuffer::new(),
buffer_r: MixerBuffer::new(LeftOrRight::Right),
channels: Default::default(), channels: Default::default(),
} }
} }
@ -23,31 +21,15 @@ impl Mixer {
} }
pub fn vblank(&mut self) { pub fn vblank(&mut self) {
self.buffer_l.swap(); self.buffer.swap();
self.buffer_r.swap(); self.buffer.clear();
self.buffer_l.clear();
self.buffer_r.clear();
for channel in self.channels.iter_mut() { for channel in self.channels.iter_mut() {
let mut has_finished = false;
if let Some(some_channel) = channel { if let Some(some_channel) = channel {
self.buffer_l.write_channel(some_channel); if self.buffer.write_channel(some_channel) {
self.buffer_r.write_channel(some_channel); channel.take();
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 has_finished {
channel.take();
}
} }
} }
@ -71,50 +53,60 @@ const SOUND_FREQUENCY: i32 = 10512;
const SOUND_BUFFER_SIZE: usize = 176; const SOUND_BUFFER_SIZE: usize = 176;
struct MixerBuffer { struct MixerBuffer {
buffer1: [i8; SOUND_BUFFER_SIZE], buffer1: [i8; SOUND_BUFFER_SIZE * 2], // first half is left, second is right
buffer2: [i8; SOUND_BUFFER_SIZE], buffer2: [i8; SOUND_BUFFER_SIZE * 2],
buffer_1_active: bool, buffer_1_active: bool,
lr: LeftOrRight,
} }
impl MixerBuffer { impl MixerBuffer {
fn new(lr: LeftOrRight) -> Self { fn new() -> Self {
MixerBuffer { MixerBuffer {
buffer1: [0; SOUND_BUFFER_SIZE], buffer1: [0; SOUND_BUFFER_SIZE * 2],
buffer2: [0; SOUND_BUFFER_SIZE], buffer2: [0; SOUND_BUFFER_SIZE * 2],
buffer_1_active: true, buffer_1_active: true,
lr,
} }
} }
fn swap(&mut self) { 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(left_buffer, LeftOrRight::Left);
hw::enable_dma_for_sound(&self.buffer1, self.lr); hw::enable_dma_for_sound(right_buffer, LeftOrRight::Right);
} else {
hw::enable_dma_for_sound(&self.buffer2, self.lr); self.buffer_1_active = !self.buffer_1_active;
}
} }
fn clear(&mut self) { fn clear(&mut self) {
self.get_write_buffer().fill(0); self.get_write_buffer().fill(0);
} }
fn write_channel(&mut self, channel: &SoundChannel) { fn write_channel(&mut self, channel: &mut SoundChannel) -> bool {
let data_to_copy = &channel.data[channel.pos.floor()..];
let place_to_write_to = self.get_write_buffer(); 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() { for i in 0..SOUND_BUFFER_SIZE {
let v = *v as i8; let v = channel.data[current_point.floor()];
place_to_write_to[i] = place_to_write_to[i].saturating_add(v); 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 { if self.buffer_1_active {
&mut self.buffer2 &mut self.buffer2
} else { } else {

View file

@ -22,6 +22,8 @@ pub struct SoundChannel {
data: &'static [u8], data: &'static [u8],
pos: Num<usize, 8>, pos: Num<usize, 8>,
should_loop: bool, should_loop: bool,
playback_speed: Num<usize, 8>,
} }
impl SoundChannel { impl SoundChannel {
@ -30,6 +32,7 @@ impl SoundChannel {
data, data,
pos: 0.into(), pos: 0.into(),
should_loop: false, should_loop: false,
playback_speed: 1.into(),
} }
} }
@ -37,4 +40,9 @@ impl SoundChannel {
self.should_loop = true; self.should_loop = true;
self self
} }
pub fn playback(mut self, playback_speed: Num<usize, 8>) -> Self {
self.playback_speed = playback_speed;
self
}
} }