use core::ffi::{c_uint, c_ulong};
use libsoxr_sys as sys;
#[derive(Debug, Clone)]
pub struct QualitySpec {
raw: sys::soxr_quality_spec,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum QualityRecipe {
Quick = 0,
Low = 1,
Medium = 2,
Bits16 = 3,
Bits20 = 4,
Bits24 = 5,
Bits28 = 6,
Bits32 = 7,
}
impl QualityRecipe {
pub const fn high() -> Self {
QualityRecipe::Bits20
}
pub const fn very_high() -> Self {
QualityRecipe::Bits28
}
pub const fn to_raw(self) -> c_ulong {
self as u8 as c_ulong
}
}
impl Default for QualityRecipe {
fn default() -> Self {
QualityRecipe::high()
}
}
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum Rolloff {
Small = 0,
Medium = 1,
None = 2,
}
impl Default for Rolloff {
fn default() -> Self {
Rolloff::Small
}
}
bitflags::bitflags! {
#[derive(Debug, Default, Clone, Copy)]
pub struct QualityFlags: u8 {
const HighPrecisionClock = 8;
const DoublePrecision = 16;
const VariableRate = 32;
}
}
impl QualitySpec {
pub fn new(recipe: QualityRecipe) -> Self {
Self::configure(recipe, Rolloff::default(), QualityFlags::default())
}
pub fn variable_rate(recipe: QualityRecipe) -> Self {
Self::configure(recipe, Rolloff::default(), QualityFlags::VariableRate)
}
pub fn configure(recipe: QualityRecipe, rolloff: Rolloff, flags: QualityFlags) -> Self {
let flags = flags.bits();
let flags = flags | rolloff as u8;
let flags = flags as c_ulong;
unsafe { Self::from_raw(sys::soxr_quality_spec(recipe.to_raw(), flags)) }
}
pub fn precision(&self) -> f64 {
self.raw.precision
}
pub fn set_precision(&mut self, precision: f64) {
self.raw.precision = precision;
}
pub fn with_precision(mut self, precision: f64) -> Self {
self.set_precision(precision);
self
}
pub fn phase_response(&self) -> f64 {
self.raw.phase_response
}
pub fn set_phase_response(&mut self, phase_response: f64) {
self.raw.phase_response = phase_response;
}
pub fn with_phase_response(mut self, phase_response: f64) -> Self {
self.set_phase_response(phase_response);
self
}
pub fn passband_end(&self) -> f64 {
self.raw.passband_end
}
pub fn set_passband_end(&mut self, passband_end: f64) {
self.raw.passband_end = passband_end;
}
pub fn with_passband_end(mut self, passband_end: f64) -> Self {
self.set_passband_end(passband_end);
self
}
pub fn stopband_begin(&self) -> f64 {
self.raw.stopband_begin
}
pub fn set_stopband_begin(&mut self, stopband_begin: f64) {
self.raw.stopband_begin = stopband_begin;
}
pub fn with_stopband_begin(mut self, stopband_begin: f64) -> Self {
self.set_stopband_begin(stopband_begin);
self
}
pub const fn as_raw(&self) -> &sys::soxr_quality_spec {
&self.raw
}
pub const unsafe fn from_raw(raw: sys::soxr_quality_spec) -> Self {
QualitySpec { raw }
}
}
impl Default for QualitySpec {
fn default() -> Self {
QualitySpec::new(QualityRecipe::high())
}
}
pub struct RuntimeSpec {
raw: sys::soxr_runtime_spec,
}
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum Interpolation {
Auto = 0,
Low = 2,
High = 3,
}
impl RuntimeSpec {
pub fn new(num_threads: c_uint) -> Self {
unsafe { Self::from_raw(sys::soxr_runtime_spec(num_threads)) }
}
pub fn log2_min_dft_size(&self) -> c_uint {
self.raw.log2_min_dft_size
}
pub fn set_log2_min_dft_size(&mut self, log2_min_dft_size: c_uint) {
self.raw.log2_min_dft_size = log2_min_dft_size;
}
pub fn with_log2_min_dft_size(mut self, log2_min_dft_size: c_uint) -> Self {
self.set_log2_min_dft_size(log2_min_dft_size);
self
}
pub fn log2_large_dft_size(&self) -> c_uint {
self.raw.log2_large_dft_size
}
pub fn set_log2_large_dft_size(&mut self, log2_large_dft_size: c_uint) {
self.raw.log2_large_dft_size = log2_large_dft_size;
}
pub fn with_log2_large_dft_size(mut self, log2_large_dft_size: c_uint) -> Self {
self.set_log2_large_dft_size(log2_large_dft_size);
self
}
pub fn coef_size_kbytes(&self) -> c_uint {
self.raw.log2_large_dft_size
}
pub fn set_coef_size_kbytes(&mut self, coef_size_kbytes: c_uint) {
self.raw.coef_size_kbytes = coef_size_kbytes;
}
pub fn with_coef_size_kbytes(mut self, coef_size_kbytes: c_uint) -> Self {
self.set_coef_size_kbytes(coef_size_kbytes);
self
}
pub fn num_threads(&self) -> c_uint {
self.raw.num_threads
}
pub fn set_num_threads(&mut self, num_threads: c_uint) {
self.raw.num_threads = num_threads;
}
pub fn with_num_threads(mut self, num_threads: c_uint) -> Self {
self.set_num_threads(num_threads);
self
}
pub fn interpolation(&self) -> Interpolation {
let interp = self.raw.flags & 3;
match interp {
0 => Interpolation::Auto,
2 => Interpolation::Low,
3 => Interpolation::High,
_ => {
Interpolation::Auto
}
}
}
pub fn set_interpolation(&mut self, interpolation: Interpolation) {
self.raw.flags &= !3;
self.raw.flags |= interpolation as u8 as c_ulong;
}
pub fn with_interpolation(mut self, interpolation: Interpolation) -> Self {
self.set_interpolation(interpolation);
self
}
pub const fn as_raw(&self) -> &sys::soxr_runtime_spec {
&self.raw
}
pub const unsafe fn from_raw(raw: sys::soxr_runtime_spec) -> Self {
RuntimeSpec { raw }
}
}
impl Default for RuntimeSpec {
fn default() -> Self {
Self::new(1)
}
}