Browse Source

Merged WaveBuffer and Waveinfo

pull/83/head
Andrea Ciliberti 2 years ago
parent
commit
ef1bba99b6
  1. 13
      ctru-rs/examples/audio-filters.rs
  2. 93
      ctru-rs/src/services/ndsp/wave.rs

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

@ -5,7 +5,7 @@ use std::f32::consts::PI;
use ctru::linear::LinearAllocator; use ctru::linear::LinearAllocator;
use ctru::prelude::*; use ctru::prelude::*;
use ctru::services::ndsp::{ use ctru::services::ndsp::{
wave::{WaveBuffer, WaveInfo, WaveStatus}, wave::{WaveInfo, WaveStatus},
AudioFormat, InterpolationType, Ndsp, OutputMode, AudioFormat, InterpolationType, Ndsp, OutputMode,
}; };
@ -82,13 +82,8 @@ fn main() {
let mut audio_data2 = Box::new_in([0u8; AUDIO_WAVE_LENGTH], LinearAllocator); let mut audio_data2 = Box::new_in([0u8; AUDIO_WAVE_LENGTH], LinearAllocator);
fill_buffer(&mut audio_data2[..], NOTEFREQ[4]); fill_buffer(&mut audio_data2[..], NOTEFREQ[4]);
let mut audio_buffer1 = let mut wave_info1 = WaveInfo::new(audio_data1, AudioFormat::PCM16Stereo, false);
WaveBuffer::new(audio_data1, AudioFormat::PCM16Stereo).expect("Couldn't sync DSP cache"); let mut wave_info2 = WaveInfo::new(audio_data2, AudioFormat::PCM16Stereo, false);
let mut audio_buffer2 =
WaveBuffer::new(audio_data2, AudioFormat::PCM16Stereo).expect("Couldn't sync DSP cache");
let mut wave_info1 = WaveInfo::new(&mut audio_buffer1, false);
let mut wave_info2 = WaveInfo::new(&mut audio_buffer2, false);
channel_zero.queue_wave(&mut wave_info1); channel_zero.queue_wave(&mut wave_info1);
channel_zero.queue_wave(&mut wave_info2); channel_zero.queue_wave(&mut wave_info2);
@ -157,7 +152,7 @@ fn main() {
let status = current.get_status(); let status = current.get_status();
if let WaveStatus::Done = status { if let WaveStatus::Done = status {
fill_buffer(current.get_mut_wavebuffer().get_mut_data(), NOTEFREQ[note]); fill_buffer(current.get_mut_buffer(), NOTEFREQ[note]);
channel_zero.queue_wave(current); channel_zero.queue_wave(current);

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

@ -1,21 +1,11 @@
use ctru_sys::ndspChnWaveBufClear;
use super::AudioFormat; use super::AudioFormat;
use crate::linear::LinearAllocator; use crate::linear::LinearAllocator;
/// Base struct to represent audio wave data. This requires audio format information. /// Informational struct holding the raw audio data and playback info. This corresponds to [ctru_sys::ndspWaveBuf]
pub struct WaveBuffer { pub struct WaveInfo {
/// Buffer data. This data must be allocated on the LINEAR memory. /// Data block of the audio wave (and its format information).
data: Box<[u8], LinearAllocator>, buffer: Box<[u8], LinearAllocator>,
audio_format: AudioFormat, audio_format: AudioFormat,
nsamples: usize, // We don't use the slice's length here because depending on the format it may vary
// adpcm_data: AdpcmData, TODO: Requires research on how this format is handled.
}
/// Informational struct holding the raw audio data and playaback info. This corresponds to [ctru_sys::ndspWaveBuf]
pub struct WaveInfo<'b> {
/// Data block of the audio wave (plus its format information).
buffer: &'b mut WaveBuffer,
// Holding the data with the raw format is necessary since `libctru` will access it. // Holding the data with the raw format is necessary since `libctru` will access it.
pub(crate) raw_data: ctru_sys::ndspWaveBuf, pub(crate) raw_data: ctru_sys::ndspWaveBuf,
played_on_channel: Option<u8>, played_on_channel: Option<u8>,
@ -30,43 +20,25 @@ pub enum WaveStatus {
Done = ctru_sys::NDSP_WBUF_DONE as u8, Done = ctru_sys::NDSP_WBUF_DONE as u8,
} }
impl WaveBuffer { impl WaveInfo {
pub fn new(data: Box<[u8], LinearAllocator>, audio_format: AudioFormat) -> crate::Result<Self> { pub fn new(
let nsamples: usize = data.len() / (audio_format.sample_size() as usize); buffer: Box<[u8], LinearAllocator>,
audio_format: AudioFormat,
looping: bool,
) -> Self {
let nsamples: usize = buffer.len() / (audio_format.sample_size() as usize);
unsafe { unsafe {
let _r = ctru_sys::DSP_FlushDataCache(data.as_ptr().cast(), data.len() as u32); let _r = ctru_sys::DSP_FlushDataCache(buffer.as_ptr().cast(), buffer.len() as u32);
} }
Ok(Self {
data,
audio_format,
nsamples,
})
}
pub fn get_mut_data(&mut self) -> &mut [u8] {
&mut self.data
}
pub fn get_format(&self) -> AudioFormat {
self.audio_format
}
pub fn get_sample_amount(&self) -> usize {
self.nsamples
}
}
impl<'b> WaveInfo<'b> {
pub fn new(buffer: &'b mut WaveBuffer, looping: bool) -> Self {
let address = ctru_sys::tag_ndspWaveBuf__bindgen_ty_1 { let address = ctru_sys::tag_ndspWaveBuf__bindgen_ty_1 {
data_vaddr: buffer.data.as_ptr().cast(), data_vaddr: buffer.as_ptr().cast(),
}; };
let raw_data = ctru_sys::ndspWaveBuf { let raw_data = ctru_sys::ndspWaveBuf {
__bindgen_anon_1: address, // Buffer data virtual address __bindgen_anon_1: address, // Buffer data virtual address
nsamples: buffer.get_sample_amount() as u32, nsamples: nsamples as u32,
adpcm_data: std::ptr::null_mut(), adpcm_data: std::ptr::null_mut(),
offset: 0, offset: 0,
looping, looping,
@ -78,19 +50,28 @@ impl<'b> WaveInfo<'b> {
Self { Self {
buffer, buffer,
audio_format,
raw_data, raw_data,
played_on_channel: None, played_on_channel: None,
} }
} }
pub fn get_mut_wavebuffer(&mut self) -> &mut WaveBuffer { pub fn get_mut_buffer(&mut self) -> &mut [u8] {
self.buffer &mut self.buffer
} }
pub fn get_status(&self) -> WaveStatus { pub fn get_status(&self) -> WaveStatus {
self.raw_data.status.try_into().unwrap() self.raw_data.status.try_into().unwrap()
} }
pub fn get_sample_amount(&self) -> u32 {
self.raw_data.nsamples
}
pub fn get_format(&self) -> AudioFormat {
self.audio_format
}
pub(crate) fn set_channel(&mut self, id: i32) { pub(crate) fn set_channel(&mut self, id: i32) {
self.played_on_channel = Some(id as u8) self.played_on_channel = Some(id as u8)
} }
@ -110,19 +91,7 @@ impl TryFrom<u8> for WaveStatus {
} }
} }
impl Drop for WaveBuffer { impl Drop for WaveInfo {
fn drop(&mut self) {
unsafe {
// Result can't be used in any way, let's just shrug it off
let _r = ctru_sys::DSP_InvalidateDataCache(
self.data.as_ptr().cast(),
self.data.len().try_into().unwrap(),
);
}
}
}
impl<'b> Drop for WaveInfo<'b> {
fn drop(&mut self) { fn drop(&mut self) {
// This was the only way I found I could check for improper drops of `WaveInfos`. // This was the only way I found I could check for improper drops of `WaveInfos`.
// A panic was considered, but it would cause issues with drop order against `Ndsp`. // A panic was considered, but it would cause issues with drop order against `Ndsp`.
@ -131,8 +100,16 @@ impl<'b> Drop for WaveInfo<'b> {
// If the status flag is "unfinished" // If the status flag is "unfinished"
_ => { _ => {
// The unwrap is safe, since it must have a value in the case the status is "unfinished". // The unwrap is safe, since it must have a value in the case the status is "unfinished".
unsafe { ndspChnWaveBufClear(self.played_on_channel.unwrap().into()) }; unsafe { ctru_sys::ndspChnWaveBufClear(self.played_on_channel.unwrap().into()) };
} }
} }
unsafe {
// Result can't be used in any way, let's just shrug it off
let _r = ctru_sys::DSP_InvalidateDataCache(
self.buffer.as_ptr().cast(),
self.buffer.len().try_into().unwrap(),
);
}
} }
} }

Loading…
Cancel
Save