diff --git a/examples/audio_playback/src/main.rs b/examples/audio_playback/src/main.rs index 65cc190..e858abd 100644 --- a/examples/audio_playback/src/main.rs +++ b/examples/audio_playback/src/main.rs @@ -1,3 +1,4 @@ +use std::f64::consts::PI; use std::path::Path; use anyhow::Result; @@ -27,6 +28,31 @@ fn load_and_convert_wav(path: &Path, target_spec: &AudioSpec) -> Result Self { + SineWaveGenerator { + t: 0 + } + } +} + +impl AudioGenerator for SineWaveGenerator { + fn gen_sample(&mut self, position: usize) -> Option { + const MAX_TIME: usize = AUDIO_FREQUENCY_22KHZ as usize * 3; // 3 seconds + if self.t < MAX_TIME { + let sample = (self.t as f64 * 0.25).sin() * 80.0; + self.t += 1; + Some((sample + 128.0) as u8) + } else { + None + } + } +} + fn main() -> Result<()> { let mut system = SystemBuilder::new().window_title("Audio Playback").vsync(true).build()?; @@ -73,6 +99,10 @@ fn main() -> Result<()> { audio_device.play_buffer(&sound5, false)?; } + if system.keyboard.is_key_pressed(Scancode::Num6) { + audio_device.play_generator(Box::new(SineWaveGenerator::new()), false); + } + for index in 0..NUM_CHANNELS { let channel = &audio_device[index]; let mut status = &mut statuses[index]; diff --git a/libretrogd/src/audio/mod.rs b/libretrogd/src/audio/mod.rs index c73dcff..9578aa8 100644 --- a/libretrogd/src/audio/mod.rs +++ b/libretrogd/src/audio/mod.rs @@ -55,11 +55,17 @@ impl AudioSpec { ////////////////////////////////////////////////////////////////////////////////////////////////// -#[derive(Debug, Clone)] +pub trait AudioGenerator: Send { + fn gen_sample(&mut self, position: usize) -> Option; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + pub struct AudioChannel { pub playing: bool, pub loops: bool, pub data: Vec, + pub generator: Option>, pub volume: f32, pub position: usize, } @@ -71,10 +77,19 @@ impl AudioChannel { loops: false, volume: 1.0, position: 0, + generator: None, data: Vec::new(), } } + fn data_at(&mut self, position: usize) -> Option { + if let Some(generator) = &mut self.generator { + generator.gen_sample(position) + } else { + self.data.get(self.position).copied() + } + } + /// Returns the next sample from this channel's buffer. If this channel's buffer is done /// playing or there is no buffer data at all, `None` is returned. If the next sample was /// successfully loaded from the buffer, the channel's current position is advanced by 1. @@ -84,9 +99,9 @@ impl AudioChannel { /// instead of 0 to 255). #[inline] fn next_sample(&mut self) -> Option { - if let Some(sample) = self.data.get(self.position) { + if let Some(sample) = self.data_at(self.position) { self.position += 1; - Some((*sample as i16) - 128) + Some(sample as i16 - 128) } else { None } @@ -104,25 +119,25 @@ impl AudioChannel { pub fn sample(&mut self) -> Option { if !self.playing { return None; - } else if self.position >= self.data.len() { - if self.loops { - self.position = 0; - } else { - self.stop(); - return None; - } } - if let Some(raw_sample) = self.next_sample() { - Some((raw_sample as f32 * self.volume) as i16) + if let Some(sample) = self.next_sample() { + Some((sample as f32 * self.volume) as i16) } else { - None + if self.loops { + self.position = 0; + None + } else { + self.stop(); + None + } } } #[inline] pub fn reset(&mut self) { self.data.clear(); + self.generator = None; self.position = 0; self.playing = false; } @@ -131,14 +146,27 @@ impl AudioChannel { pub fn play_buffer(&mut self, buffer: &AudioBuffer, loops: bool) { self.data.clear(); self.data.extend(&buffer.data); + self.generator = None; self.position = 0; self.playing = true; self.loops = loops; } + pub fn play_generator(&mut self, generator: Box, loops: bool) { + self.data.clear(); + self.generator = Some(generator); + self.position = 0; + self.playing = true; + self.loops = loops; + } + + pub fn is_playable(&self) -> bool { + !self.data.is_empty() || self.generator.is_some() + } + #[inline] pub fn play(&mut self, loops: bool) { - if !self.data.is_empty() { + if self.is_playable() { self.position = 0; self.playing = true; self.loops = loops; @@ -222,6 +250,15 @@ impl AudioDevice { } } + pub fn play_generator(&mut self, generator: Box, loops: bool) -> Result, AudioDeviceError> { + if let Some(channel) = self.stopped_channels_iter_mut().next() { + channel.play_generator(generator, loops); + Ok(Some(channel)) + } else { + Ok(None) + } + } + #[inline] pub fn playing_channels_iter(&mut self) -> impl Iterator { self.channels.iter().filter(|channel| channel.playing)