use std::borrow::Cow;
use numpy::{Element, PyArray1, PyArray2, PyArrayMethods, PyReadonlyArray1, PyReadonlyArrayDyn, PyUntypedArrayMethods};
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
pub fn borrow_1d<'a, T: Element + Copy>(arr: &'a PyReadonlyArray1<'a, T>) -> Cow<'a, [T]> {
match arr.as_slice() {
Ok(s) => Cow::Borrowed(s),
Err(_) => Cow::Owned(arr.as_array().iter().copied().collect()),
}
}
pub fn vec_to_numpy_1d<T: Element>(py: Python<'_>, v: Vec<T>) -> Bound<'_, PyArray1<T>> {
PyArray1::from_vec(py, v)
}
pub fn borrow_interleaved_f32<'a>(arr: &'a PyReadonlyArrayDyn<'a, f32>, channels: usize) -> PyResult<Cow<'a, [f32]>> {
let shape = arr.shape();
let total = match *shape {
[n] => n,
[frames, ch] => {
if ch != channels {
return Err(PyValueError::new_err(format!(
"array has {ch} columns but the codec is configured for {channels} channels"
)));
}
frames * ch
},
_ => {
return Err(PyValueError::new_err(
"PCM must be a 1-D interleaved array or a 2-D (frames, channels) array",
));
},
};
if channels == 0 || total % channels != 0 {
return Err(PyValueError::new_err(
"PCM length must be a whole number of frames for the channel count",
));
}
Ok(match arr.as_slice() {
Ok(s) => Cow::Borrowed(s),
Err(_) => Cow::Owned(arr.as_array().iter().copied().collect()),
})
}
pub fn interleaved_f32_to_numpy<'py>(
py: Python<'py>,
pcm: Vec<f32>,
channels: usize,
) -> PyResult<Bound<'py, PyArray2<f32>>> {
debug_assert!(channels != 0);
let frames = pcm.len() / channels;
let flat = PyArray1::from_vec(py, pcm);
flat.reshape([frames, channels])
}
pub fn interleaved_i16_to_numpy<'py>(
py: Python<'py>,
pcm: Vec<i16>,
channels: usize,
) -> PyResult<Bound<'py, PyArray2<i16>>> {
debug_assert!(channels != 0);
let frames = pcm.len() / channels;
let flat = PyArray1::from_vec(py, pcm);
flat.reshape([frames, channels])
}