Browse Source

NdspError enum and better Channel

pull/83/head
Andrea Ciliberti 2 years ago
parent
commit
84df959603
  1. 8
      ctru-rs/examples/audio-filters.rs
  2. 3
      ctru-rs/src/error.rs
  3. 95
      ctru-rs/src/services/ndsp/mod.rs
  4. 4
      ctru-rs/src/services/ndsp/wave.rs

8
ctru-rs/examples/audio-filters.rs

@ -84,8 +84,8 @@ fn main() { @@ -84,8 +84,8 @@ fn main() {
mix[1] = 1.0;
channel_zero.set_mix(&mix);
channel_zero.queue_wave(&mut wave_info1);
channel_zero.queue_wave(&mut wave_info2);
channel_zero.queue_wave(&mut wave_info1).unwrap();
channel_zero.queue_wave(&mut wave_info2).unwrap();
println!("\x1b[1;1HPress up/down to change tone frequency");
println!("\x1b[2;1HPress left/right to change filter");
@ -105,7 +105,7 @@ fn main() { @@ -105,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 = std::cmp::min(note + 1, NOTEFREQ.len() - 1);;
note = std::cmp::min(note + 1, NOTEFREQ.len() - 1);
}
let mut update_params = false;
@ -150,7 +150,7 @@ fn main() { @@ -150,7 +150,7 @@ fn main() {
if let WaveStatus::Done = status {
fill_buffer(current.get_buffer_mut(), NOTEFREQ[note]);
channel_zero.queue_wave(current);
channel_zero.queue_wave(current).unwrap();
altern = !altern;
}

3
ctru-rs/src/error.rs

@ -51,7 +51,6 @@ pub enum Error { @@ -51,7 +51,6 @@ pub enum Error {
Libc(String),
ServiceAlreadyActive,
OutputAlreadyRedirected,
InvalidChannel(i32),
}
impl Error {
@ -98,7 +97,6 @@ impl fmt::Debug for Error { @@ -98,7 +97,6 @@ impl fmt::Debug for Error {
Self::Libc(err) => f.debug_tuple("Libc").field(err).finish(),
Self::ServiceAlreadyActive => f.debug_tuple("ServiceAlreadyActive").finish(),
Self::OutputAlreadyRedirected => f.debug_tuple("OutputAlreadyRedirected").finish(),
Self::InvalidChannel(id) => f.debug_tuple("InvalidChannel").field(id).finish(),
}
}
}
@ -115,7 +113,6 @@ impl fmt::Display for Error { @@ -115,7 +113,6 @@ impl fmt::Display for Error {
Self::OutputAlreadyRedirected => {
write!(f, "output streams are already redirected to 3dslink")
}
Self::InvalidChannel(id) => write!(f, "Audio Channel with id {id} doesn't exist"),
}
}
}

95
ctru-rs/src/services/ndsp/mod.rs

@ -4,6 +4,8 @@ use wave::{WaveInfo, WaveStatus}; @@ -4,6 +4,8 @@ use wave::{WaveInfo, WaveStatus};
use crate::error::ResultCode;
use crate::services::ServiceReference;
use std::error;
use std::fmt;
use std::sync::Mutex;
const NUMBER_OF_CHANNELS: u8 = 24;
@ -34,7 +36,13 @@ pub enum InterpolationType { @@ -34,7 +36,13 @@ pub enum InterpolationType {
None = ctru_sys::NDSP_INTERP_NONE,
}
pub struct Channel(i32);
#[derive(Copy, Clone, Debug)]
pub enum NdspError {
InvalidChannel(u8), // channel id
WaveAlreadyQueued(u8), // channel id
}
pub struct Channel(u8);
static NDSP_ACTIVE: Mutex<usize> = Mutex::new(0);
@ -65,12 +73,12 @@ impl Ndsp { @@ -65,12 +73,12 @@ impl Ndsp {
/// # Errors
///
/// An error will be returned if the channel id is not between 0 and 23.
pub fn channel(&self, id: u8) -> crate::Result<Channel> {
if id >= NUMBER_OF_CHANNELS as u8 {
return Err(crate::Error::InvalidChannel(id.into()));
pub fn channel(&self, id: u8) -> std::result::Result<Channel, NdspError> {
if id >= NUMBER_OF_CHANNELS {
Err(NdspError::InvalidChannel(id))
} else {
Ok(Channel(id))
}
Ok(Channel(id.into()))
}
/// Set the audio output mode. Defaults to `OutputMode::Stereo`.
@ -85,66 +93,66 @@ impl Ndsp { @@ -85,66 +93,66 @@ impl Ndsp {
impl Channel {
/// Reset the channel
pub fn reset(&self) {
unsafe { ctru_sys::ndspChnReset(self.0) };
unsafe { ctru_sys::ndspChnReset(self.0.into()) };
}
/// Initialize the channel's parameters
pub fn init_parameters(&self) {
unsafe { ctru_sys::ndspChnInitParams(self.0) };
unsafe { ctru_sys::ndspChnInitParams(self.0.into()) };
}
/// Returns whether the channel is playing any audio.
pub fn is_playing(&self) -> bool {
unsafe { ctru_sys::ndspChnIsPlaying(self.0) }
unsafe { ctru_sys::ndspChnIsPlaying(self.0.into()) }
}
/// Returns whether the channel's playback is currently paused.
pub fn is_paused(&self) -> bool {
unsafe { ctru_sys::ndspChnIsPaused(self.0) }
unsafe { ctru_sys::ndspChnIsPaused(self.0.into()) }
}
/// Returns the channel's current sample's position.
pub fn get_sample_position(&self) -> u32 {
unsafe { ctru_sys::ndspChnGetSamplePos(self.0) }
unsafe { ctru_sys::ndspChnGetSamplePos(self.0.into()) }
}
/// Returns the channel's current wave sequence's id.
pub fn get_wave_sequence_id(&self) -> u16 {
unsafe { ctru_sys::ndspChnGetWaveBufSeq(self.0) }
unsafe { ctru_sys::ndspChnGetWaveBufSeq(self.0.into()) }
}
/// Pause or un-pause the channel's playback.
pub fn set_paused(&self, state: bool) {
unsafe { ctru_sys::ndspChnSetPaused(self.0, state) };
unsafe { ctru_sys::ndspChnSetPaused(self.0.into(), state) };
}
/// Set the channel's output format.
/// Change this setting based on the used sample's format.
pub fn set_format(&self, format: AudioFormat) {
unsafe { ctru_sys::ndspChnSetFormat(self.0, format as u16) };
unsafe { ctru_sys::ndspChnSetFormat(self.0.into(), format as u16) };
}
/// Set the channel's interpolation mode.
pub fn set_interpolation(&self, interp_type: InterpolationType) {
unsafe { ctru_sys::ndspChnSetInterp(self.0, interp_type as u32) };
unsafe { ctru_sys::ndspChnSetInterp(self.0.into(), interp_type as u32) };
}
/// Set the channel's volume mix.
/// Docs about the buffer usage: https://libctru.devkitpro.org/channel_8h.html#a30eb26f1972cc3ec28370263796c0444
pub fn set_mix(&self, mix: &[f32; 12]) {
unsafe { ctru_sys::ndspChnSetMix(self.0, mix.as_ptr().cast_mut()) }
unsafe { ctru_sys::ndspChnSetMix(self.0.into(), mix.as_ptr().cast_mut()) }
}
/// Set the channel's rate of sampling.
pub fn set_sample_rate(&self, rate: f32) {
unsafe { ctru_sys::ndspChnSetRate(self.0, rate) };
unsafe { ctru_sys::ndspChnSetRate(self.0.into(), rate) };
}
// TODO: find a way to wrap `ndspChnSetAdpcmCoefs`
/// Clear the wave buffer queue and stop playback.
pub fn clear_queue(&self) {
unsafe { ctru_sys::ndspChnWaveBufClear(self.0) };
unsafe { ctru_sys::ndspChnWaveBufClear(self.0.into()) };
}
/// Add a wave buffer to the channel's queue.
@ -154,16 +162,19 @@ impl Channel { @@ -154,16 +162,19 @@ impl Channel {
///
/// `libctru` expects the user to manually keep the info data (in this case [WaveInfo]) alive during playback.
/// To ensure safety, checks within [WaveInfo] will clear the whole channel queue if any queued [WaveInfo] is dropped prematurely.
pub fn queue_wave(&self, wave: &mut WaveInfo) {
// TODO: Return an error for already queued/used WaveInfos.
pub fn queue_wave(&self, wave: &mut WaveInfo) -> std::result::Result<(), NdspError> {
match wave.get_status() {
WaveStatus::Playing | WaveStatus::Queued => return,
WaveStatus::Playing | WaveStatus::Queued => {
return Err(NdspError::WaveAlreadyQueued(self.0))
}
_ => (),
}
wave.set_channel(self.0);
unsafe { ctru_sys::ndspChnWaveBufAdd(self.0, &mut wave.raw_data) };
unsafe { ctru_sys::ndspChnWaveBufAdd(self.0.into(), &mut wave.raw_data) };
Ok(())
}
// FILTERS
@ -171,23 +182,31 @@ impl Channel { @@ -171,23 +182,31 @@ impl Channel {
// TODO: Add Mono filters (and maybe setup the filter functions in a better way)
pub fn iir_biquad_set_enabled(&self, enable: bool) {
unsafe { ctru_sys::ndspChnIirBiquadSetEnable(self.0, enable) };
unsafe { ctru_sys::ndspChnIirBiquadSetEnable(self.0.into(), enable) };
}
pub fn iir_biquad_set_params_high_pass_filter(&self, cut_off_freq: f32, quality: f32) {
unsafe { ctru_sys::ndspChnIirBiquadSetParamsHighPassFilter(self.0, cut_off_freq, quality) };
unsafe {
ctru_sys::ndspChnIirBiquadSetParamsHighPassFilter(self.0.into(), cut_off_freq, quality)
};
}
pub fn iir_biquad_set_params_low_pass_filter(&self, cut_off_freq: f32, quality: f32) {
unsafe { ctru_sys::ndspChnIirBiquadSetParamsLowPassFilter(self.0, cut_off_freq, quality) };
unsafe {
ctru_sys::ndspChnIirBiquadSetParamsLowPassFilter(self.0.into(), cut_off_freq, quality)
};
}
pub fn iir_biquad_set_params_notch_filter(&self, notch_freq: f32, quality: f32) {
unsafe { ctru_sys::ndspChnIirBiquadSetParamsNotchFilter(self.0, notch_freq, quality) };
unsafe {
ctru_sys::ndspChnIirBiquadSetParamsNotchFilter(self.0.into(), notch_freq, quality)
};
}
pub fn iir_biquad_set_params_band_pass_filter(&self, mid_freq: f32, quality: f32) {
unsafe { ctru_sys::ndspChnIirBiquadSetParamsBandPassFilter(self.0, mid_freq, quality) };
unsafe {
ctru_sys::ndspChnIirBiquadSetParamsBandPassFilter(self.0.into(), mid_freq, quality)
};
}
pub fn iir_biquad_set_params_peaking_equalizer(
@ -197,7 +216,12 @@ impl Channel { @@ -197,7 +216,12 @@ impl Channel {
gain: f32,
) {
unsafe {
ctru_sys::ndspChnIirBiquadSetParamsPeakingEqualizer(self.0, central_freq, quality, gain)
ctru_sys::ndspChnIirBiquadSetParamsPeakingEqualizer(
self.0.into(),
central_freq,
quality,
gain,
)
};
}
}
@ -216,6 +240,21 @@ impl AudioFormat { @@ -216,6 +240,21 @@ impl AudioFormat {
}
}
impl fmt::Display for NdspError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::InvalidChannel(id) => write!(f, "Audio Channel with id {id} doesn't exist. Valid channels have an id between 0 and 23."),
Self::WaveAlreadyQueued(id) => write!(f, "The selected WaveInfo is already playing on channel {id}.")
}
}
}
impl error::Error for NdspError {
fn description(&self) -> &str {
"Error caused within the NDSP service wrapper"
}
}
impl Drop for Ndsp {
fn drop(&mut self) {
for i in 0..NUMBER_OF_CHANNELS {

4
ctru-rs/src/services/ndsp/wave.rs

@ -78,8 +78,8 @@ impl WaveInfo { @@ -78,8 +78,8 @@ impl WaveInfo {
self.audio_format
}
pub(crate) fn set_channel(&mut self, id: i32) {
self.played_on_channel = Some(id as u8)
pub(crate) fn set_channel(&mut self, id: u8) {
self.played_on_channel = Some(id)
}
}

Loading…
Cancel
Save