lasprs 0.14.1

Library for Acoustic Signal Processing (Rust edition, with optional Python bindings via pyo3)
use super::*;
use crate::{Flt, FreqWeighting, TimeWeighting, config::*, filter::StandardFilterDescriptor};
use anyhow::Result;
use derive_builder::Builder;

/// Settings used to create a Sound Level Meter.
#[derive(Builder, Clone)]
#[builder(setter(into))]
#[cfg_attr(feature = "python-bindings", gen_stub_pyclass, pyclass(from_py_object))]
pub struct SLMSettings {
    /// Sampling frequency in \[Hz\]
    pub fs: StrictlyPositive,

    /// Reference level for computing dB values.
    #[builder(default = "self.Lref_default()")]
    pub Lref: StrictlyPositive,

    /// Frequency weighting A/C/Z applied to data. Defaults to [FreqWeighting::default()].
    #[builder(default = "FreqWeighting::default()")]
    pub freqWeighting: FreqWeighting,

    /// For time-dependent output, the time weighthing applied (Fast / Slow)
    pub timeWeighting: TimeWeighting,
    /// Descriptors for the filters, maximum of 64, which is a reasonable amount
    /// and - if all used - might already choke a computer.
    pub filterDescriptors: Vec<StandardFilterDescriptor>,
    /// Whether the levels-vs-time output is decimated to one sample per
    /// `SLM_LT_DECIMATION_FRACTION` times the time constant. When `false`,
    /// the output contains level data for every sample.
    #[builder(default = "true")]
    pub decimate: bool,
}
impl SLMSettingsBuilder {
    /// Provide the default value for the reference level `Lref`.
    pub fn Lref_default(&self) -> StrictlyPositive {
        StrictlyPositive::new(Lref_default).unwrap()
    }
}

#[cfg(feature = "python-bindings")]
#[cfg_attr(feature = "python-bindings", gen_stub_pymethods, pymethods)]
impl SLMSettings {
    #[new]
    // Signatures bug with pyo3-stubgen. The line below is what I want, but it doesn't work.
    // #[pyo3(signature = (fs, freqWeighting, timeWeighting, filterDescriptors, Lref, decimate = true))]
    fn new_py(
        fs: StrictlyPositive,
        freqWeighting: FreqWeighting,
        timeWeighting: TimeWeighting,
        filterDescriptors: Vec<StandardFilterDescriptor>,
        Lref: StrictlyPositive,
        decimate: bool,
    ) -> PyResult<SLMSettings> {
        Ok(SLMSettings {
            fs,
            Lref,
            freqWeighting,
            timeWeighting,
            filterDescriptors,
            decimate,
        })
    }

    /// Create a new SLMSettings instance with default values for air.
    #[staticmethod]
    // Signatures bug with pyo3-stubgen. The line below is what I want, but it doesn't work.
    // #[pyo3(signature = (fs, freqWeighting, timeWeighting, filterDescriptors, decimate = true))]
    fn newAir(
        fs: Flt,
        freqWeighting: FreqWeighting,
        timeWeighting: TimeWeighting,
        filterDescriptors: Vec<StandardFilterDescriptor>,
        decimate: bool,
    ) -> PyResult<SLMSettings> {
        let fs: StrictlyPositive = fs.try_into()?;
        Ok(SLMSettings {
            fs,
            Lref: Lref_default.try_into().unwrap(),
            freqWeighting,
            timeWeighting,
            filterDescriptors,
            decimate,
        })
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use anyhow::Result;

    #[test]
    fn test_slmsettings1() -> Result<()> {
        let desc = StandardFilterDescriptor::genFilterSetForRange(1, 100., 5e3, true).unwrap();
        let fs: StrictlyPositive = (1e3).try_into()?;

        let _ = SLMSettingsBuilder::default()
            .fs(fs)
            .freqWeighting(FreqWeighting::A)
            .timeWeighting(TimeWeighting::Slow {})
            .Lref(StrictlyPositive::try_from(1.).unwrap())
            .filterDescriptors(desc)
            .build()
            .unwrap();

        Ok(())
    }
}