use crate::base::{from_bool32, Channel, ChannelMixMode, Error, Format, MAX_CHANNELS};
use crate::frames::{Frames, FramesMut};
use miniaudio_sys as sys;
#[repr(transparent)]
pub struct ChannelConverterConfig(sys::ma_channel_converter_config);
impl ChannelConverterConfig {
pub fn new(
format: Format,
channel_map_in: &[Channel],
channel_map_out: &[Channel],
mixing_mode: ChannelMixMode,
) -> ChannelConverterConfig {
ChannelConverterConfig(unsafe {
sys::ma_channel_converter_config_init(
format as _,
channel_map_in.len() as u32,
channel_map_in.as_ptr().cast(),
channel_map_out.len() as u32,
channel_map_out.as_ptr().cast(),
mixing_mode as _,
)
})
}
#[inline]
pub fn format(&self) -> Format {
Format::from_c(self.0.format)
}
#[inline]
pub fn channels_in(&self) -> u32 {
self.0.channelsIn
}
#[inline]
pub fn channels_out(&self) -> u32 {
self.0.channelsOut
}
#[inline]
pub fn channel_map_in(&self) -> &[Channel] {
unsafe {
std::slice::from_raw_parts(
self.0.channelMapIn.as_ptr().cast(),
self.0.channelsIn as usize,
)
}
}
#[inline]
pub fn channel_map_out(&self) -> &[Channel] {
unsafe {
std::slice::from_raw_parts(
self.0.channelMapOut.as_ptr().cast(),
self.0.channelsOut as usize,
)
}
}
#[inline]
pub fn mixing_mode(&self) -> ChannelMixMode {
ChannelMixMode::from_c(self.0.mixingMode)
}
#[inline]
pub fn weight(&self, channel_in_index: usize, channel_out_index: usize) -> f32 {
assert!(
channel_in_index < self.0.channelsIn as usize
&& channel_out_index < self.0.channelsOut as usize,
"channel in/out index out of bounds"
);
self.0.weights[channel_in_index][channel_out_index]
}
#[inline]
pub fn set_weight(&mut self, channel_in_index: usize, channel_out_index: usize, weight: f32) {
assert!(
channel_in_index < self.0.channelsIn as usize
&& channel_out_index < self.0.channelsOut as usize,
"channel in/out index out of bounds"
);
self.0.weights[channel_in_index][channel_out_index] = weight;
}
}
#[repr(transparent)]
#[derive(Clone)]
pub struct ChannelConverter(sys::ma_channel_converter);
impl ChannelConverter {
pub fn new(config: &ChannelConverterConfig) -> Result<ChannelConverter, Error> {
let mut converter = std::mem::MaybeUninit::<ChannelConverter>::uninit();
unsafe {
Error::from_c_result(sys::ma_channel_converter_init(
&config.0 as *const _,
converter.as_mut_ptr().cast(),
))?;
Ok(converter.assume_init())
}
}
#[inline]
pub fn format(&self) -> Format {
Format::from_c(self.0.format)
}
#[inline]
pub fn channels_in(&self) -> u32 {
self.0.channelsIn
}
#[inline]
pub fn channels_out(&self) -> u32 {
self.0.channelsOut
}
#[inline]
pub fn channel_map_in(&self) -> &[Channel] {
unsafe {
std::slice::from_raw_parts(
self.0.channelMapIn.as_ptr().cast(),
self.0.channelsIn as usize,
)
}
}
#[inline]
pub fn channel_map_out(&self) -> &[Channel] {
unsafe {
std::slice::from_raw_parts(
self.0.channelMapOut.as_ptr().cast(),
self.0.channelsOut as usize,
)
}
}
#[inline]
pub fn mixing_mode(&self) -> ChannelMixMode {
ChannelMixMode::from_c(self.0.mixingMode)
}
#[inline]
pub fn is_passthrough(&self) -> bool {
from_bool32(self.0.isPassthrough())
}
#[inline]
pub fn is_simple_shuffle(&self) -> bool {
from_bool32(self.0.isSimpleShuffle())
}
#[inline]
pub fn is_simple_mono_expansion(&self) -> bool {
from_bool32(self.0.isSimpleMonoExpansion())
}
#[inline]
pub fn is_stereo_to_mono(&self) -> bool {
from_bool32(self.0.isStereoToMono())
}
#[inline]
pub fn shuffle_table(&self) -> &[u8; MAX_CHANNELS] {
unsafe { std::mem::transmute(&self.0.shuffleTable) }
}
#[inline]
pub fn process_pcm_frames(
&mut self,
output: &mut FramesMut,
input: &Frames,
) -> Result<(), Error> {
if output.format() != input.format() {
ma_debug_panic!(
"output and input format did not match (output: {:?}, input: {:?}",
output.format(),
input.format()
);
return Err(Error::InvalidArgs);
}
if output.frame_count() != input.frame_count() {
ma_debug_panic!("output and input buffers did not have the same frame count (output: {}, input: {})", output.frame_count(), input.frame_count());
return Err(Error::InvalidArgs);
}
Error::from_c_result(unsafe {
sys::ma_channel_converter_process_pcm_frames(
&mut self.0,
output.as_mut_ptr() as *mut _,
input.as_ptr() as *const _,
output.frame_count() as u64,
)
})
}
}
impl Drop for ChannelConverter {
fn drop(&mut self) {
unsafe {
sys::ma_channel_converter_uninit(&mut self.0);
}
}
}