Compare commits
2 Commits
7662ff176c
...
eb94785a89
Author | SHA1 | Date | |
---|---|---|---|
eb94785a89 | |||
476479b693 |
40
Cargo.toml
40
Cargo.toml
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lasprs"
|
name = "lasprs"
|
||||||
version = "0.6.0"
|
version = "0.6.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["J.A. de Jong <j.a.dejong@ascee.nl>"]
|
authors = ["J.A. de Jong <j.a.dejong@ascee.nl>"]
|
||||||
description = "Library for Acoustic Signal Processing (Rust edition, with optional Python bindings via pyo3)"
|
description = "Library for Acoustic Signal Processing (Rust edition, with optional Python bindings via pyo3)"
|
||||||
@ -12,7 +12,7 @@ categories = ["multimedia::audio", "science", "mathematics"]
|
|||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "lasprs"
|
name = "lasprs"
|
||||||
crate-type = ["cdylib", "rlib",]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Error handling
|
# Error handling
|
||||||
@ -29,8 +29,12 @@ num = "0.4.3"
|
|||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
|
|
||||||
# Python bindings
|
# Python bindings
|
||||||
pyo3 = { version = "0.22.2", optional = true, features = ["extension-module", "anyhow"]}
|
pyo3 = { version = "0.21.2", optional = true, features = [
|
||||||
numpy = { git = "https://github.com/JRRudy1/rust-numpy", branch = "pyo3-0.22.0" , optional = true}
|
"extension-module",
|
||||||
|
"anyhow",
|
||||||
|
] }
|
||||||
|
# Python bindings for Numpy arrays
|
||||||
|
numpy = { version = "0.21.0", optional = true }
|
||||||
|
|
||||||
# White noise etc
|
# White noise etc
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
@ -74,12 +78,17 @@ itertools = "0.13.0"
|
|||||||
approx = "0.5.1"
|
approx = "0.5.1"
|
||||||
|
|
||||||
# For getting timestamps. Only useful when recording.
|
# For getting timestamps. Only useful when recording.
|
||||||
chrono = {version = "0.4.38", optional = true}
|
chrono = { version = "0.4.38", optional = true }
|
||||||
# For getting UUIDs in recording
|
# For getting UUIDs in recording
|
||||||
uuid = { version = "1.10.0", features = ["v4"] , optional = true}
|
uuid = { version = "1.10.0", features = ["v4"], optional = true }
|
||||||
|
|
||||||
# Command line argument parser, for CLI apps
|
# Command line argument parser, for CLI apps
|
||||||
clap = { version = "4.5.13", features = ["derive", "color", "help", "suggestions"] }
|
clap = { version = "4.5.13", features = [
|
||||||
|
"derive",
|
||||||
|
"color",
|
||||||
|
"help",
|
||||||
|
"suggestions",
|
||||||
|
] }
|
||||||
|
|
||||||
# FFT's
|
# FFT's
|
||||||
realfft = "3.3.0"
|
realfft = "3.3.0"
|
||||||
@ -104,8 +113,21 @@ default = ["f64", "cpal-api", "record"]
|
|||||||
# Use this to test if everything works well in f32
|
# Use this to test if everything works well in f32
|
||||||
# default = ["f32", "cpal-api", "record"]
|
# default = ["f32", "cpal-api", "record"]
|
||||||
|
|
||||||
# Use this for debugging extensions
|
# When building Python bindings of Lasprs, you should enable the feature flag
|
||||||
# default = ["f64", "python-bindings", "record", "cpal-api"]
|
# "python-bindings". When debugging these, to safe the flag specification you
|
||||||
|
# could just uncomment the line below here and comment the one above. If only
|
||||||
|
# testing the implementations, or building the extension module, you should
|
||||||
|
# call:
|
||||||
|
|
||||||
|
# $ maturin develop -F python-bindings
|
||||||
|
|
||||||
|
# Or:
|
||||||
|
|
||||||
|
# $ maturin develop --release -F python-bindings
|
||||||
|
|
||||||
|
# For faster code
|
||||||
|
|
||||||
|
#default = ["f64", "python-bindings", "record", "cpal-api"]
|
||||||
|
|
||||||
pulse-api = []
|
pulse-api = []
|
||||||
cpal-api = ["dep:cpal"]
|
cpal-api = ["dep:cpal"]
|
||||||
|
@ -12,11 +12,12 @@ and processing of (multi) sensor data in real time on a PC and output results.
|
|||||||
|
|
||||||
Documentation is provided at [doc.rs](https://docs.rs/lasprs/latest/lasprs).
|
Documentation is provided at [doc.rs](https://docs.rs/lasprs/latest/lasprs).
|
||||||
|
|
||||||
## Python bindings
|
|
||||||
|
## Python bindings and examples
|
||||||
|
|
||||||
The library has Python bindings (via [pyo3](https://pyo3.rs), which can be installed via:
|
The library has Python bindings (via [pyo3](https://pyo3.rs), which can be installed via:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ pip install git+https://code.ascee.nl/ascee/lasprs --install-option "--all-features"
|
$ pip install git+https://code.ascee.nl/ascee/lasprs --install-option "python-bindings"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -32,7 +32,10 @@ pub trait Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Stream API descriptor: type and corresponding text
|
/// Stream API descriptor: type and corresponding text
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
// Do the following when Pyo3 0.22 can finally be used combined with rust-numpy:
|
||||||
|
//#[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
||||||
|
// For now:
|
||||||
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
#[derive(strum_macros::EnumMessage, Debug, Clone, PartialEq, Serialize, Deserialize, strum_macros::Display)]
|
#[derive(strum_macros::EnumMessage, Debug, Clone, PartialEq, Serialize, Deserialize, strum_macros::Display)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum StreamApiDescr {
|
pub enum StreamApiDescr {
|
||||||
|
@ -7,8 +7,11 @@ use crate::config::*;
|
|||||||
|
|
||||||
/// Data type description for samples coming from a stream
|
/// Data type description for samples coming from a stream
|
||||||
#[derive(strum_macros::EnumMessage, PartialEq, Copy, Debug, Clone, Serialize, Deserialize)]
|
#[derive(strum_macros::EnumMessage, PartialEq, Copy, Debug, Clone, Serialize, Deserialize)]
|
||||||
|
// Do the following when Pyo3 0.22 can finally be used combined with rust-numpy:
|
||||||
|
//#[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
||||||
|
// For now:
|
||||||
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
|
||||||
pub enum DataType {
|
pub enum DataType {
|
||||||
/// 32-bit floats
|
/// 32-bit floats
|
||||||
#[strum(message = "F32", detailed_message = "32-bits floating points")]
|
#[strum(message = "F32", detailed_message = "32-bits floating points")]
|
||||||
|
@ -50,7 +50,10 @@ use api::*;
|
|||||||
use crate::config::*;
|
use crate::config::*;
|
||||||
/// Stream types that can be started
|
/// Stream types that can be started
|
||||||
///
|
///
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
// Do the following when Pyo3 0.22 can finally be used combined with rust-numpy:
|
||||||
|
// #[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
||||||
|
// For now:
|
||||||
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
#[derive(PartialEq, Clone, Copy)]
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
pub enum StreamType {
|
pub enum StreamType {
|
||||||
/// Input-only stream
|
/// Input-only stream
|
||||||
|
@ -7,8 +7,10 @@ use strum_macros;
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
/// Physical quantities that are I/O of a Daq device.
|
/// Physical quantities that are I/O of a Daq device.
|
||||||
|
// Do the following when Pyo3 0.22 can finally be used combined with rust-numpy:
|
||||||
|
// #[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
||||||
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
#[derive(PartialEq, Serialize, Deserialize, strum_macros::EnumMessage, Debug, Clone, Copy)]
|
#[derive(PartialEq, Serialize, Deserialize, strum_macros::EnumMessage, Debug, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum Qty {
|
pub enum Qty {
|
||||||
/// Number
|
/// Number
|
||||||
|
@ -3,7 +3,12 @@ use crate::config::*;
|
|||||||
|
|
||||||
/// Errors that happen in a stream
|
/// Errors that happen in a stream
|
||||||
#[derive(strum_macros::EnumMessage, PartialEq, Debug, Clone, Display, Copy)]
|
#[derive(strum_macros::EnumMessage, PartialEq, Debug, Clone, Display, Copy)]
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
|
||||||
|
// Do the following when Pyo3 0.22 can finally be used combined with rust-numpy:
|
||||||
|
//#[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
||||||
|
// For now:
|
||||||
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
|
|
||||||
pub enum StreamError {
|
pub enum StreamError {
|
||||||
/// Input overrun
|
/// Input overrun
|
||||||
#[strum(
|
#[strum(
|
||||||
|
@ -478,6 +478,7 @@ impl BandDescriptor for ThirdOctaveBandDescriptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python-bindings")]
|
||||||
#[cfg_attr(feature = "python-bindings", pymethods)]
|
#[cfg_attr(feature = "python-bindings", pymethods)]
|
||||||
impl StandardFilterDescriptor {
|
impl StandardFilterDescriptor {
|
||||||
#[pyo3(name = "genFilter")]
|
#[pyo3(name = "genFilter")]
|
||||||
@ -511,7 +512,7 @@ impl StandardFilterDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn __repr__(&self) -> String {
|
fn __repr__(&self) -> String {
|
||||||
format!{"{:#?}", self}
|
format! {"{:#?}", self}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __str__(&self) -> String {
|
fn __str__(&self) -> String {
|
||||||
|
@ -34,12 +34,14 @@ impl FFT {
|
|||||||
nfftF: nfft as Flt,
|
nfftF: nfft as Flt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn process<'a, T>(&mut self, time: &[Flt], freq: T)
|
pub fn process<'a, T, U>(&mut self, time: T, freq: U)
|
||||||
where
|
where
|
||||||
T: Into<ArrayViewMut<'a, Cflt, Ix1>>,
|
T: Into<ArrayView<'a, Flt, Ix1>>,
|
||||||
|
U: Into<ArrayViewMut<'a, Cflt, Ix1>>,
|
||||||
{
|
{
|
||||||
let mut freq = freq.into();
|
let mut freq = freq.into();
|
||||||
self.timescratch.copy_from_slice(time);
|
let time = time.into();
|
||||||
|
self.timescratch.copy_from_slice(time.as_slice().unwrap());
|
||||||
let _ = self
|
let _ = self
|
||||||
.fft
|
.fft
|
||||||
.process(&mut self.timescratch, freq.as_slice_mut().unwrap());
|
.process(&mut self.timescratch, freq.as_slice_mut().unwrap());
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
use crate::config::*;
|
use crate::config::*;
|
||||||
use strum_macros::{Display, EnumMessage};
|
use strum_macros::{Display, EnumMessage};
|
||||||
/// Sound level frequency weighting type (A, C, Z)
|
/// Sound level frequency weighting type (A, C, Z)
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
|
||||||
|
// Do the following when Pyo3 0.22 can finally be used combined with rust-numpy:
|
||||||
|
// #[cfg_attr(feature = "python-bindings", pyclass(eq, eq_int))]
|
||||||
|
// For now:
|
||||||
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
#[derive(Display, Debug, EnumMessage, Default, Clone, PartialEq)]
|
#[derive(Display, Debug, EnumMessage, Default, Clone, PartialEq)]
|
||||||
pub enum FreqWeighting {
|
pub enum FreqWeighting {
|
||||||
/// A-weighting
|
/// A-weighting
|
||||||
|
41
src/ps/ps.rs
41
src/ps/ps.rs
@ -7,8 +7,8 @@ use std::usize;
|
|||||||
|
|
||||||
use crate::Dcol;
|
use crate::Dcol;
|
||||||
|
|
||||||
use super::window::*;
|
|
||||||
use super::fft::FFT;
|
use super::fft::FFT;
|
||||||
|
use super::window::*;
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
use realfft::{RealFftPlanner, RealToComplex};
|
use realfft::{RealFftPlanner, RealToComplex};
|
||||||
@ -46,7 +46,6 @@ pub trait CrossPowerSpecra {
|
|||||||
fn tf(&self, chi: usize, chj: usize, chRef: Option<usize>) -> Array1<Cflt>;
|
fn tf(&self, chi: usize, chj: usize, chRef: Option<usize>) -> Array1<Cflt>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl CrossPowerSpecra for CPSResult {
|
impl CrossPowerSpecra for CPSResult {
|
||||||
fn ap(&self, ch: usize) -> Array1<Flt> {
|
fn ap(&self, ch: usize) -> Array1<Flt> {
|
||||||
// Slice out one value for all frequencies, map to only real part, and
|
// Slice out one value for all frequencies, map to only real part, and
|
||||||
@ -87,10 +86,10 @@ impl CrossPowerSpecra for CPSResult {
|
|||||||
/// estimation.
|
/// estimation.
|
||||||
///
|
///
|
||||||
pub struct PowerSpectra {
|
pub struct PowerSpectra {
|
||||||
/// Window used in estimator
|
/// Window used in estimator. The actual Window in here is normalized with
|
||||||
pub window: Window,
|
/// the square root of the Window power. This safes one division when
|
||||||
/// The window power, is corrected for in power spectra estimants
|
/// processing time data.
|
||||||
pub sqrt_win_pwr: Flt,
|
pub window_normalized: Window,
|
||||||
|
|
||||||
ffts: Vec<FFT>,
|
ffts: Vec<FFT>,
|
||||||
|
|
||||||
@ -103,7 +102,7 @@ pub struct PowerSpectra {
|
|||||||
impl PowerSpectra {
|
impl PowerSpectra {
|
||||||
/// Returns the FFT length used in power spectra computations
|
/// Returns the FFT length used in power spectra computations
|
||||||
pub fn nfft(&self) -> usize {
|
pub fn nfft(&self) -> usize {
|
||||||
self.window.win.len()
|
self.window_normalized.win.len()
|
||||||
}
|
}
|
||||||
/// Create new power spectra estimator. Uses FFT size from window length
|
/// Create new power spectra estimator. Uses FFT size from window length
|
||||||
///
|
///
|
||||||
@ -116,9 +115,12 @@ impl PowerSpectra {
|
|||||||
///
|
///
|
||||||
/// - `window` - A `Window` struct, from which NFFT is also used.
|
/// - `window` - A `Window` struct, from which NFFT is also used.
|
||||||
///
|
///
|
||||||
pub fn newFromWindow(window: Window) -> PowerSpectra {
|
pub fn newFromWindow(mut window: Window) -> PowerSpectra {
|
||||||
let nfft = window.win.len();
|
let nfft = window.win.len();
|
||||||
let win_pwr = window.win.mapv(|w| w.powi(2)).sum() / (nfft as Flt);
|
let win_pwr = window.win.mapv(|w| w.powi(2)).sum() / (nfft as Flt);
|
||||||
|
let sqrt_win_pwr = Flt::sqrt(win_pwr);
|
||||||
|
window.win.mapv_inplace(|v| v / sqrt_win_pwr);
|
||||||
|
|
||||||
assert!(nfft > 0);
|
assert!(nfft > 0);
|
||||||
assert!(nfft % 2 == 0);
|
assert!(nfft % 2 == 0);
|
||||||
|
|
||||||
@ -128,8 +130,7 @@ impl PowerSpectra {
|
|||||||
let Fft = FFT::new(fft);
|
let Fft = FFT::new(fft);
|
||||||
|
|
||||||
PowerSpectra {
|
PowerSpectra {
|
||||||
window,
|
window_normalized: window,
|
||||||
sqrt_win_pwr: Flt::sqrt(win_pwr),
|
|
||||||
ffts: vec![Fft],
|
ffts: vec![Fft],
|
||||||
timedata: Array2::zeros((nfft, 1)),
|
timedata: Array2::zeros((nfft, 1)),
|
||||||
freqdata: Array2::zeros((nfft / 2 + 1, 1)),
|
freqdata: Array2::zeros((nfft / 2 + 1, 1)),
|
||||||
@ -138,7 +139,7 @@ impl PowerSpectra {
|
|||||||
|
|
||||||
/// Compute FFTs of input channel data. Stores the scaled FFT data in
|
/// Compute FFTs of input channel data. Stores the scaled FFT data in
|
||||||
/// self.freqdata.
|
/// self.freqdata.
|
||||||
fn compute_ffts(&mut self, timedata: ArrayView2<Flt>) -> &Array2<Cflt> {
|
fn compute_ffts(&mut self, timedata: ArrayView2<Flt>) -> ArrayView2<Cflt> {
|
||||||
let (n, nch) = timedata.dim();
|
let (n, nch) = timedata.dim();
|
||||||
let nfft = self.nfft();
|
let nfft = self.nfft();
|
||||||
assert!(n == nfft);
|
assert!(n == nfft);
|
||||||
@ -153,25 +154,27 @@ impl PowerSpectra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert!(n == self.nfft());
|
assert!(n == self.nfft());
|
||||||
assert!(n == self.window.win.len());
|
assert!(n == self.window_normalized.win.len());
|
||||||
let sqrt_win_pwr = self.sqrt_win_pwr;
|
|
||||||
|
|
||||||
// Multiply signals with window function, and compute fft's for each channel
|
// Multiply signals with window function, and compute fft's for each channel
|
||||||
Zip::from(timedata.axis_iter(Axis(1)))
|
Zip::from(timedata.axis_iter(Axis(1)))
|
||||||
.and(self.timedata.axis_iter_mut(Axis(1)))
|
.and(self.timedata.axis_iter_mut(Axis(1)))
|
||||||
.and(&mut self.ffts)
|
.and(&mut self.ffts)
|
||||||
.and(self.freqdata.axis_iter_mut(Axis(1)))
|
.and(self.freqdata.axis_iter_mut(Axis(1)))
|
||||||
.par_for_each(|time_in,mut time, fft, mut freq| {
|
.par_for_each(|time_in, mut time_tmp_storage, fft, mut freq| {
|
||||||
|
let DC = time_in.mean().unwrap();
|
||||||
|
|
||||||
|
azip!((t in &mut time_tmp_storage, &tin in time_in, &win in &self.window_normalized.win) {
|
||||||
|
// Substract DC value from time data, as this leaks into
|
||||||
|
// positive frequencies due to windowing.
|
||||||
// Multiply with window and copy over to local time data buffer
|
// Multiply with window and copy over to local time data buffer
|
||||||
azip!((t in &mut time, &tin in time_in, &win in &self.window.win) *t=tin*win/sqrt_win_pwr);
|
*t=(tin-DC)*win});
|
||||||
|
|
||||||
let tslice = time.as_slice().unwrap();
|
fft.process(&time_tmp_storage, &mut freq);
|
||||||
let fslice = freq.as_slice_mut().unwrap();
|
freq[0] = DC + 0. * I;
|
||||||
fft.process(tslice, fslice);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
&self.freqdata
|
self.freqdata.view()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute cross power spectra from input time data. First axis is
|
/// Compute cross power spectra from input time data. First axis is
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
//! let settings = SLMSettingsBuilder::default()
|
//! let settings = SLMSettingsBuilder::default()
|
||||||
//! .fs(48e3)
|
//! .fs(48e3)
|
||||||
//! .freqWeighting(FreqWeighting::A)
|
//! .freqWeighting(FreqWeighting::A)
|
||||||
//! .timeWeighting(TimeWeighting::Fast)
|
//! .timeWeighting(TimeWeighting::Fast{})
|
||||||
//! .filterDescriptors(&[desc]).build().unwrap();
|
//! .filterDescriptors(&[desc]).build().unwrap();
|
||||||
//!
|
//!
|
||||||
//! let mut slm = SLM::new(settings);
|
//! let mut slm = SLM::new(settings);
|
||||||
@ -33,7 +33,7 @@
|
|||||||
//! data[0] = 1.;
|
//! data[0] = 1.;
|
||||||
//!
|
//!
|
||||||
//! // Now apply some data. This is a kind of the SLM-s impulse response
|
//! // Now apply some data. This is a kind of the SLM-s impulse response
|
||||||
//! let res = slm.run(&data.as_slice().unwrap()).unwrap();
|
//! let res = slm.run(data.as_slice().unwrap(), true).unwrap();
|
||||||
//!
|
//!
|
||||||
//! // Only one channel of result data
|
//! // Only one channel of result data
|
||||||
//! assert_eq!(res.len(), 1);
|
//! assert_eq!(res.len(), 1);
|
||||||
|
@ -28,6 +28,7 @@ pub struct SLMSettings {
|
|||||||
pub filterDescriptors: Vec<StandardFilterDescriptor>,
|
pub filterDescriptors: Vec<StandardFilterDescriptor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature="python-bindings")]
|
||||||
#[cfg_attr(feature = "python-bindings", pymethods)]
|
#[cfg_attr(feature = "python-bindings", pymethods)]
|
||||||
impl SLMSettings {
|
impl SLMSettings {
|
||||||
#[new]
|
#[new]
|
||||||
|
@ -205,6 +205,7 @@ impl SLM {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature="python-bindings")]
|
||||||
#[cfg_attr(feature = "python-bindings", pymethods)]
|
#[cfg_attr(feature = "python-bindings", pymethods)]
|
||||||
impl SLM {
|
impl SLM {
|
||||||
#[new]
|
#[new]
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use crate::config::*;
|
use crate::config::*;
|
||||||
/// Time weighting to use in level detection of Sound Level Meter.
|
/// Time weighting to use in level detection of Sound Level Meter.
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass(eq))]
|
///
|
||||||
|
// Do the following when Pyo3 0.22 can finally be used combined with rust-numpy:
|
||||||
|
// #[cfg_attr(feature = "python-bindings", pyclass(eq))]
|
||||||
|
// For now:
|
||||||
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub enum TimeWeighting {
|
pub enum TimeWeighting {
|
||||||
// I know that the curly braces here are not required and add some
|
// I know that the curly braces here are not required and add some
|
||||||
|
Loading…
Reference in New Issue
Block a user