use std::f64::consts::PI; use std::path::Path; use anyhow::Result; use sdl2::keyboard::Scancode; use libretrogd::audio::*; use libretrogd::graphics::*; use libretrogd::system::*; use libretrogd::utils::rnd_value; #[derive(Debug, Copy, Clone)] struct AudioChannelStatus { size: usize, position: usize, playing: bool } fn load_and_convert_wav(path: &Path, target_spec: &AudioSpec) -> Result { let sound = AudioBuffer::load_wav_file(path)?; let original_spec = *sound.spec(); let sound = sound.convert(target_spec)?; let final_spec = *sound.spec(); if original_spec != final_spec { println!("{:?} was converted from {:?} to {:?}", path, original_spec, final_spec); } else { println!("{:?} did not need to be converted from {:?}", path, original_spec); } Ok(sound) } pub struct SineWaveGenerator { t: usize, } impl SineWaveGenerator { pub fn new() -> 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()?; let mut is_running = true; let sounds = [ load_and_convert_wav(Path::new("./assets/pickup-coin.wav"), system.audio.spec())?, load_and_convert_wav(Path::new("./assets/powerup.wav"), system.audio.spec())?, load_and_convert_wav(Path::new("./assets/explosion.wav"), system.audio.spec())?, load_and_convert_wav(Path::new("./assets/jump.wav"), system.audio.spec())?, load_and_convert_wav(Path::new("./assets/laser-shoot.wav"), system.audio.spec())?, ]; let mut statuses = [AudioChannelStatus { size: 0, position: 0, playing: false }; NUM_CHANNELS]; while is_running { system.do_events_with(|event| { if let sdl2::event::Event::Quit { .. } = event { is_running = false; } }); let mut audio_device = system.audio.lock(); if system.keyboard.is_key_pressed(Scancode::Escape) { is_running = false; } if system.keyboard.is_key_pressed(Scancode::Num1) { audio_device.play_buffer(&sounds[0], false)?; } if system.keyboard.is_key_pressed(Scancode::Num2) { audio_device.play_buffer(&sounds[1], false)?; } if system.keyboard.is_key_pressed(Scancode::Num3) { audio_device.play_buffer(&sounds[2], false)?; } if system.keyboard.is_key_pressed(Scancode::Num4) { audio_device.play_buffer(&sounds[3], false)?; } if system.keyboard.is_key_pressed(Scancode::Num5) { audio_device.play_buffer(&sounds[4], false)?; } if system.keyboard.is_key_pressed(Scancode::Num6) { audio_device.play_generator(SineWaveGenerator::new(), false); } if system.keyboard.is_key_pressed(Scancode::Num7) { let index = rnd_value(0, sounds.len() - 1); audio_device.play_buffer_on_channel(7, &sounds[index], false)?; } for index in 0..NUM_CHANNELS { let channel = &audio_device[index]; let mut status = &mut statuses[index]; status.playing = channel.playing; status.position = channel.position; status.size = channel.data.len(); } drop(audio_device); system.video.clear(0); system.video.print_string("Audio Channels", 16, 16, FontRenderOpts::Color(14), &system.font); let mut y = 32; for index in 0..NUM_CHANNELS { let status = &statuses[index]; system.video.print_string( &format!( "channel {} - {} {}", index, if status.playing { "playing" } else { "not playing" }, if status.playing { String::from(format!("{} / {}", status.position, status.size)) } else { String::new() } ), 16, y, FontRenderOpts::Color(15), &system.font ); y += 16; } system.display()?; } Ok(()) }