diff --git a/ctru-rs/examples/audio-filters.rs b/ctru-rs/examples/audio-filters.rs index 8381bfa..a576150 100644 --- a/ctru-rs/examples/audio-filters.rs +++ b/ctru-rs/examples/audio-filters.rs @@ -41,23 +41,6 @@ fn main() { let apt = Apt::init().expect("Couldn't obtain APT controller"); let _console = Console::init(gfx.top_screen.borrow_mut()); - let mut ndsp = Ndsp::init().expect("Couldn't obtain NDSP controller"); - - // This line isn't needed since the default NDSP configuration already sets the output mode to `Stereo` - ndsp.set_output_mode(OutputMode::Stereo); - - let channel_zero = ndsp.channel(0).unwrap(); - channel_zero.set_interpolation(InterpolationType::Linear); - channel_zero.set_sample_rate(SAMPLE_RATE as f32); - channel_zero.set_format(AudioFormat::PCM16Stereo); - - // Output at 100% on the first pair of left and right channels. - - let mut mix: [f32; 12] = [0f32; 12]; - mix[0] = 1.0; - mix[1] = 1.0; - channel_zero.set_mix(&mix); - let mut note: usize = 4; // Filters @@ -77,14 +60,30 @@ fn main() { // effectively streaming an infinitely long sine wave. let mut audio_data1 = Box::new_in([0u8; AUDIO_WAVE_LENGTH], LinearAllocator); - fill_buffer(&mut audio_data1[..], NOTEFREQ[4]); + fill_buffer(audio_data1.as_mut_slice(), NOTEFREQ[4]); - let mut audio_data2 = Box::new_in([0u8; AUDIO_WAVE_LENGTH], LinearAllocator); - fill_buffer(&mut audio_data2[..], NOTEFREQ[4]); + let audio_data2 = audio_data1.clone(); let mut wave_info1 = WaveInfo::new(audio_data1, AudioFormat::PCM16Stereo, false); let mut wave_info2 = WaveInfo::new(audio_data2, AudioFormat::PCM16Stereo, false); + let mut ndsp = Ndsp::init().expect("Couldn't obtain NDSP controller"); + + // This line isn't needed since the default NDSP configuration already sets the output mode to `Stereo` + ndsp.set_output_mode(OutputMode::Stereo); + + let channel_zero = ndsp.channel(0).unwrap(); + channel_zero.set_interpolation(InterpolationType::Linear); + channel_zero.set_sample_rate(SAMPLE_RATE as f32); + channel_zero.set_format(AudioFormat::PCM16Stereo); + + // Output at 100% on the first pair of left and right channels. + + let mut mix: [f32; 12] = [0f32; 12]; + mix[0] = 1.0; + mix[1] = 1.0; + channel_zero.set_mix(&mix); + channel_zero.queue_wave(&mut wave_info1); channel_zero.queue_wave(&mut wave_info2); @@ -106,7 +105,7 @@ fn main() { if keys_down.intersects(KeyPad::KEY_DOWN) { note = note.saturating_sub(1); } else if keys_down.intersects(KeyPad::KEY_UP) { - note += 1; + note = std::cmp::min(note + 1, NOTEFREQ.len() - 1);; } let mut update_params = false; @@ -127,9 +126,6 @@ fn main() { update_params = true; } - // Check for upper limit - note = std::cmp::min(note, NOTEFREQ.len() - 1); - println!("\x1b[4;1Hnote = {} Hz ", NOTEFREQ[note]); println!("\x1b[5;1Hfilter = {} ", filter_names[filter]); @@ -152,7 +148,7 @@ fn main() { let status = current.get_status(); if let WaveStatus::Done = status { - fill_buffer(current.get_mut_buffer(), NOTEFREQ[note]); + fill_buffer(current.get_buffer_mut(), NOTEFREQ[note]); channel_zero.queue_wave(current); diff --git a/ctru-rs/src/services/ndsp/mod.rs b/ctru-rs/src/services/ndsp/mod.rs index 64931f9..e1b10e1 100644 --- a/ctru-rs/src/services/ndsp/mod.rs +++ b/ctru-rs/src/services/ndsp/mod.rs @@ -6,6 +6,8 @@ use crate::services::ServiceReference; use std::sync::Mutex; +const NUMBER_OF_CHANNELS: u8 = 24; + #[derive(Copy, Clone, Debug)] #[repr(u32)] pub enum OutputMode { @@ -64,7 +66,7 @@ impl Ndsp { /// /// An error will be returned if the channel id is not between 0 and 23. pub fn channel(&self, id: u8) -> crate::Result { - if id > 23 { + if id >= NUMBER_OF_CHANNELS as u8 { return Err(crate::Error::InvalidChannel(id.into())); } @@ -216,7 +218,7 @@ impl AudioFormat { impl Drop for Ndsp { fn drop(&mut self) { - for i in 0..24 { + for i in 0..NUMBER_OF_CHANNELS { self.channel(i).unwrap().clear_queue(); } } diff --git a/ctru-rs/src/services/ndsp/wave.rs b/ctru-rs/src/services/ndsp/wave.rs index ebb30dd..e565df4 100644 --- a/ctru-rs/src/services/ndsp/wave.rs +++ b/ctru-rs/src/services/ndsp/wave.rs @@ -26,8 +26,10 @@ impl WaveInfo { audio_format: AudioFormat, looping: bool, ) -> Self { - let nsamples: usize = buffer.len() / (audio_format.sample_size() as usize); + let sample_count: usize = buffer.len() / (audio_format.sample_size() as usize); + // Signal to the DSP processor the buffer's RAM sector. + // This step may seem delicate, but testing reports failure most of the time, while still having no repercussions on the resulting audio. unsafe { let _r = ctru_sys::DSP_FlushDataCache(buffer.as_ptr().cast(), buffer.len() as u32); } @@ -38,7 +40,7 @@ impl WaveInfo { let raw_data = ctru_sys::ndspWaveBuf { __bindgen_anon_1: address, // Buffer data virtual address - nsamples: nsamples as u32, + nsamples: sample_count as u32, adpcm_data: std::ptr::null_mut(), offset: 0, looping, @@ -56,7 +58,11 @@ impl WaveInfo { } } - pub fn get_mut_buffer(&mut self) -> &mut [u8] { + pub fn get_buffer(&self) -> &[u8] { + &self.buffer + } + + pub fn get_buffer_mut(&mut self) -> &mut [u8] { &mut self.buffer } @@ -64,7 +70,7 @@ impl WaveInfo { self.raw_data.status.try_into().unwrap() } - pub fn get_sample_amount(&self) -> u32 { + pub fn get_sample_count(&self) -> u32 { self.raw_data.nsamples } @@ -78,7 +84,7 @@ impl WaveInfo { } impl TryFrom for WaveStatus { - type Error = String; + type Error = &'static str; fn try_from(value: u8) -> Result { match value { @@ -86,7 +92,7 @@ impl TryFrom for WaveStatus { 1 => Ok(Self::Queued), 2 => Ok(Self::Playing), 3 => Ok(Self::Done), - _ => Err(String::from("Invalid WaveInfo Status code")), + _ => Err("Invalid WaveInfo Status code"), } } } @@ -105,7 +111,8 @@ impl Drop for WaveInfo { } unsafe { - // Result can't be used in any way, let's just shrug it off + // Flag the buffer's RAM sector as unused + // This step has no real effect in normal applications and is skipped even by devkitPRO's own examples. let _r = ctru_sys::DSP_InvalidateDataCache( self.buffer.as_ptr().cast(), self.buffer.len().try_into().unwrap(),