use std::convert::Infallible;
use super::FilterGenerator;
use crate::{
filter::{
BiquadBank, FilterError, InvalidFilterOrderSnafu, Result, SeriesBiquad,
StandardFilterDescriptor, error::ChannelIndexOutOfBoundsSnafu,
},
*,
};
use serde::{Deserialize, Serialize};
use snafu::prelude::*;
#[cfg_attr(
feature = "python-bindings",
gen_stub_pyclass_enum,
pyclass(from_py_object)
)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[non_exhaustive] pub enum GraphicEqualizerType {
OctaveBank = 0,
ThirdOctaveBank = 1,
}
#[cfg_attr(feature = "python-bindings", gen_stub_pyclass, pyclass(from_py_object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphicEqualizer {
channels: Vec<(bool, String, Flt)>,
filter_order: u32,
graphic_type: GraphicEqualizerType,
}
impl GraphicEqualizer {
pub fn names(&self) -> Vec<String> {
self.channels
.iter()
.map(|(_active, name, _gain)| name.clone())
.collect()
}
pub fn gains_dB(&self) -> Vec<Flt> {
self.channels
.iter()
.map(|(_active, _name, gain)| *gain)
.collect()
}
pub fn len(&self) -> usize {
self.channels.len()
}
pub fn is_empty(&self) -> bool {
self.channels.is_empty()
}
pub fn setGain_dB(&mut self, index: usize, gain: Flt) -> Result<()> {
if index < self.channels.len() {
self.channels[index].2 = gain;
Ok(())
} else {
ChannelIndexOutOfBoundsSnafu.fail()
}
}
pub fn newOctave(filter_order: u32) -> Result<Self> {
let xs = StandardFilterDescriptor::fullOctaveFilterSet();
Self::new(xs, filter_order)
}
pub fn newThirdOctave(filter_order: u32) -> Result<Self> {
let xs = StandardFilterDescriptor::fullThirdOctaveFilterSet();
Self::new(xs, filter_order)
}
pub fn graphicType(&self) -> GraphicEqualizerType {
self.graphic_type
}
fn new(
xs: Vec<StandardFilterDescriptor>,
filter_order: u32,
) -> std::result::Result<Self, FilterError> {
ensure!(filter_order > 0, InvalidFilterOrderSnafu);
let gains_dB = xs
.iter()
.map(|x| {
let name = x.name();
(true, name.into(), 0.)
})
.collect();
Ok(Self {
channels: gains_dB,
filter_order,
graphic_type: GraphicEqualizerType::OctaveBank,
})
}
}
impl Default for GraphicEqualizer {
fn default() -> Self {
Self::newOctave(2).unwrap()
}
}
impl FilterGenerator for GraphicEqualizer {
fn genFilter(&self, fs: StrictlyPositive) -> Result<filter::Filter> {
let desc = match self.graphic_type {
GraphicEqualizerType::OctaveBank => StandardFilterDescriptor::fullOctaveFilterSet(),
GraphicEqualizerType::ThirdOctaveBank => {
StandardFilterDescriptor::fullThirdOctaveFilterSet()
}
};
let mut filters: Vec<SeriesBiquad> = Vec::with_capacity(self.len());
for (desc, cfg) in desc.iter().zip(self.channels.iter()) {
debug_assert!(cfg.1 == desc.name());
let filter_analog = desc.genFilter_custom_order(self.filter_order);
let filter = {
let mut f = filter_analog.bilinear(fs);
f.setGain(cfg.2);
f
};
filters.push(filter);
}
Ok(BiquadBank::new(filters).into())
}
}
#[cfg(feature = "python-bindings")]
#[cfg_attr(feature = "python-bindings", gen_stub_pymethods, pymethods)]
impl GraphicEqualizer {
#[staticmethod]
#[pyo3(name = "newOctave")]
fn newOctave_py(filter_order: u32) -> PyResult<Self> {
Ok(Self::newOctave(filter_order)?)
}
#[staticmethod]
#[pyo3(name = "newThirdOctave")]
fn newThirdOctave_py(filter_order: u32) -> PyResult<Self> {
Ok(Self::newThirdOctave(filter_order)?)
}
#[pyo3(name = "names")]
fn names_py(&self) -> Vec<String> {
self.names()
}
#[pyo3(name = "graphicType")]
fn graphicType_py(&self) -> GraphicEqualizerType {
self.graphic_type
}
#[pyo3(name = "gains_dB")]
fn gains_dB_py(&self) -> Vec<Flt> {
self.gains_dB()
}
#[pyo3(name = "len")]
fn len_py(&self) -> usize {
self.len()
}
#[pyo3(name = "setGain_dB")]
fn setGain_dB_py(&mut self, index: usize, gain: Flt) -> PyResult<()> {
Ok(self.setGain_dB(index, gain)?)
}
}