Added siggencommand. Exported sweep types. Added debug derives on some more classes. StreamMgr now returns result on stream commands, by polling back on a channel for result values.
This commit is contained in:
parent
45da6370ec
commit
0567e7fb92
@ -3,6 +3,7 @@ use super::streammgr::SharedInQueue;
|
|||||||
|
|
||||||
|
|
||||||
/// Commands that can be sent to a running stream
|
/// Commands that can be sent to a running stream
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum StreamCommand {
|
pub enum StreamCommand {
|
||||||
/// Add a new queue to a running INPUT stream
|
/// Add a new queue to a running INPUT stream
|
||||||
AddInQueue(SharedInQueue),
|
AddInQueue(SharedInQueue),
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
config::*,
|
config::*,
|
||||||
siggen::{self, Siggen},
|
siggen::{self, Siggen, SiggenCommand},
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, bail, Error, Result};
|
use anyhow::{anyhow, bail, Error, Result};
|
||||||
use api::StreamApiDescr;
|
use api::StreamApiDescr;
|
||||||
@ -122,7 +122,13 @@ impl StreamMgr {
|
|||||||
// value (not the Arc) has to be cloned.
|
// value (not the Arc) has to be cloned.
|
||||||
self.getStreamMetaData(st).map(|b| (*b).clone())
|
self.getStreamMetaData(st).map(|b| (*b).clone())
|
||||||
}
|
}
|
||||||
|
#[pyo3(name = "siggenCommand")]
|
||||||
|
fn siggenCommand_py(&mut self, cmd: SiggenCommand) -> PyResult<()> {
|
||||||
|
self.siggenCommand(cmd)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for StreamMgr {
|
impl Default for StreamMgr {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
@ -148,7 +154,7 @@ impl StreamMgr {
|
|||||||
devs: vec![],
|
devs: vec![],
|
||||||
input_stream: None,
|
input_stream: None,
|
||||||
output_stream: None,
|
output_stream: None,
|
||||||
siggen: None,
|
siggen: Some(Siggen::newSilence(1., 1)),
|
||||||
|
|
||||||
#[cfg(feature = "cpal-api")]
|
#[cfg(feature = "cpal-api")]
|
||||||
cpal_api: CpalApi::new(),
|
cpal_api: CpalApi::new(),
|
||||||
@ -354,6 +360,7 @@ impl StreamMgr {
|
|||||||
.take()
|
.take()
|
||||||
.unwrap_or_else(|| Siggen::newSilence(meta.samplerate, nchannels));
|
.unwrap_or_else(|| Siggen::newSilence(meta.samplerate, nchannels));
|
||||||
|
|
||||||
|
siggen.setAllMute(true);
|
||||||
if siggen.nchannels() != nchannels {
|
if siggen.nchannels() != nchannels {
|
||||||
// Updating number of channels
|
// Updating number of channels
|
||||||
siggen.setNChannels(nchannels);
|
siggen.setNChannels(nchannels);
|
||||||
@ -398,7 +405,7 @@ impl StreamMgr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while tx.len() < 2 {
|
if tx.len() < 1 {
|
||||||
// Obtain signal from signal generator
|
// Obtain signal from signal generator
|
||||||
siggen.genSignal(&mut floatbuf);
|
siggen.genSignal(&mut floatbuf);
|
||||||
|
|
||||||
@ -663,6 +670,40 @@ impl StreamMgr {
|
|||||||
StreamType::Output => self.stopOutputStream(),
|
StreamType::Output => self.stopOutputStream(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Apply a signal generator command to control the output stream's signal
|
||||||
|
/// generator. see [SiggenCommand] for types of commands. Muting, setting
|
||||||
|
/// gain etc. A result code is given back and should be checked for errors.
|
||||||
|
pub fn siggenCommand(&mut self, cmd: SiggenCommand) -> Result<()> {
|
||||||
|
if let Some(stream) = self.output_stream.as_ref() {
|
||||||
|
stream
|
||||||
|
.commtx
|
||||||
|
.send(StreamCommand::SiggenCommand(cmd))
|
||||||
|
.unwrap();
|
||||||
|
return stream.commrx.recv().unwrap();
|
||||||
|
} else if let Some(stream) = self.input_stream.as_ref() {
|
||||||
|
// When its duplex, it should have a signal generator
|
||||||
|
if matches!(stream.streamtype, StreamType::Duplex) {
|
||||||
|
stream
|
||||||
|
.commtx
|
||||||
|
.send(StreamCommand::SiggenCommand(cmd))
|
||||||
|
.unwrap();
|
||||||
|
stream.commrx.recv().unwrap()
|
||||||
|
} else {
|
||||||
|
return self
|
||||||
|
.siggen
|
||||||
|
.as_mut()
|
||||||
|
.expect("siggen should be in rest pos")
|
||||||
|
.applyCommand(cmd);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return self
|
||||||
|
.siggen
|
||||||
|
.as_mut()
|
||||||
|
.expect("siggen should be in rest pos")
|
||||||
|
.applyCommand(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
} // impl StreamMgr
|
} // impl StreamMgr
|
||||||
impl Drop for StreamMgr {
|
impl Drop for StreamMgr {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
@ -2,7 +2,7 @@ use super::*;
|
|||||||
use super::seriesbiquad::*;
|
use super::seriesbiquad::*;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass)]
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
/// Multiple biquad filter that operate in parallel on a signal, and can apply a gain value to each
|
/// Multiple biquad filter that operate in parallel on a signal, and can apply a gain value to each
|
||||||
/// of the returned values. The BiquadBank can be used to decompose a signal by running it through
|
/// of the returned values. The BiquadBank can be used to decompose a signal by running it through
|
||||||
/// parallel filters, or it can directly be used to eq a signal. For the latter process, also a
|
/// parallel filters, or it can directly be used to eq a signal. For the latter process, also a
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
//! Contains [Biquad], [SeriesBiquad], and [BiquadBank]. These are all constructs that work on
|
//! Contains [Biquad], [SeriesBiquad], and [BiquadBank]. These are all constructs that work on
|
||||||
//! blocks of input data, and apply filters on it. TODO: implement FIR filter.
|
//! blocks of input data, and apply filters on it. TODO: implement FIR filter.
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::config::*;
|
use super::config::*;
|
||||||
|
|
||||||
mod biquad;
|
mod biquad;
|
||||||
@ -23,7 +25,7 @@ pub use seriesbiquad::SeriesBiquad;
|
|||||||
pub use zpkmodel::{PoleOrZero, ZPKModel, FilterSpec};
|
pub use zpkmodel::{PoleOrZero, ZPKModel, FilterSpec};
|
||||||
|
|
||||||
/// Implementations of this trait are able to DSP-filter input data.
|
/// Implementations of this trait are able to DSP-filter input data.
|
||||||
pub trait Filter: Send {
|
pub trait Filter: Send + Debug {
|
||||||
//! The filter trait is implemented by, for example, [Biquad], [SeriesBiquad], and [BiquadBank].
|
//! The filter trait is implemented by, for example, [Biquad], [SeriesBiquad], and [BiquadBank].
|
||||||
|
|
||||||
/// Filter input to generate output. A vector of output floats is generated with the same
|
/// Filter input to generate output. A vector of output floats is generated with the same
|
||||||
@ -39,7 +41,6 @@ pub trait Filter: Send {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Implementations are able to generate transfer functions of itself
|
/// Implementations are able to generate transfer functions of itself
|
||||||
|
|
||||||
pub trait TransferFunction<'a, T>: Send
|
pub trait TransferFunction<'a, T>: Send
|
||||||
where
|
where
|
||||||
T: AsArray<'a, Flt>,
|
T: AsArray<'a, Flt>,
|
||||||
|
@ -63,6 +63,8 @@ fn lasprs(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|||||||
m.add_class::<siggen::Siggen>()?;
|
m.add_class::<siggen::Siggen>()?;
|
||||||
m.add_class::<siggen::SiggenCommand>()?;
|
m.add_class::<siggen::SiggenCommand>()?;
|
||||||
m.add_class::<siggen::SweepType>()?;
|
m.add_class::<siggen::SweepType>()?;
|
||||||
|
m.add_class::<siggen::SiggenCommand>()?;
|
||||||
|
m.add_class::<siggen::Source>()?;
|
||||||
|
|
||||||
// SLM
|
// SLM
|
||||||
m.add_class::<slm::TimeWeighting>()?;
|
m.add_class::<slm::TimeWeighting>()?;
|
||||||
|
@ -18,7 +18,7 @@ use std::slice::IterMut;
|
|||||||
/// * [Siggen::newSine]
|
/// * [Siggen::newSine]
|
||||||
/// * [Siggen::newSilence]
|
/// * [Siggen::newSilence]
|
||||||
///
|
///
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass)]
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
pub struct Siggen {
|
pub struct Siggen {
|
||||||
// The source dynamic signal. Noise, a sine wave, sweep, etc
|
// The source dynamic signal. Noise, a sine wave, sweep, etc
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::config::*;
|
use crate::config::*;
|
||||||
use crate::filter::Filter;
|
use crate::filter::Filter;
|
||||||
/// Signal generator config for a certain channel
|
/// Signal generator config for a certain channel
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SiggenChannelConfig {
|
pub struct SiggenChannelConfig {
|
||||||
muted: bool,
|
muted: bool,
|
||||||
prefilter: Option<Box<dyn Filter>>,
|
prefilter: Option<Box<dyn Filter>>,
|
||||||
|
@ -4,6 +4,7 @@ use crate::config::*;
|
|||||||
/// Messages that can be send to a given signal generator [Siggen], to change its behaviour
|
/// Messages that can be send to a given signal generator [Siggen], to change its behaviour
|
||||||
|
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass)]
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub enum SiggenCommand {
|
pub enum SiggenCommand {
|
||||||
/// Change the source to a sine wave with given frequency.
|
/// Change the source to a sine wave with given frequency.
|
||||||
ChangeSource{
|
ChangeSource{
|
||||||
@ -13,13 +14,13 @@ pub enum SiggenCommand {
|
|||||||
|
|
||||||
/// Reset the signal generator state
|
/// Reset the signal generator state
|
||||||
ResetSiggen {
|
ResetSiggen {
|
||||||
/// New sampling frequency \[Hz\]
|
/// Sampling frequency \[Hz\]
|
||||||
fs: Flt,
|
fs: Flt,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Set all gains to value g
|
/// Set all gains to value g
|
||||||
SetAllGains {
|
SetAllGains {
|
||||||
/// Linear gain level to apply
|
/// Linear gain level to apply to all channels
|
||||||
g: Flt,
|
g: Flt,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! All sources for a signal generator. Sine waves, sweeps, noise, etc.
|
//! All sources for a signal generator. Sine waves, sweeps, noise, etc.
|
||||||
use super::sweep::{SweepParams, SweepType};
|
use super::sweep::{SweepParams, SweepType};
|
||||||
use crate::config::*;
|
use crate::config::*;
|
||||||
|
use std::fmt::Debug;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
/// Ratio between circumference and radius of a circle
|
/// Ratio between circumference and radius of a circle
|
||||||
@ -14,7 +15,7 @@ use rand_distr::StandardNormal;
|
|||||||
/// Signal source for a signal generator. A signal source is capable of creating
|
/// Signal source for a signal generator. A signal source is capable of creating
|
||||||
/// new signal data.
|
/// new signal data.
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass)]
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Source {
|
pub struct Source {
|
||||||
src: Box<dyn SourceImpl>,
|
src: Box<dyn SourceImpl>,
|
||||||
}
|
}
|
||||||
@ -69,7 +70,41 @@ impl Source {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[cfg(feature = "python-bindings")]
|
||||||
|
#[cfg_attr(feature = "python-bindings", pymethods)]
|
||||||
|
impl Source {
|
||||||
|
#[staticmethod]
|
||||||
|
#[pyo3(name = "newSine")]
|
||||||
|
fn newSine_py(fs: Flt, freq: Flt) -> PyResult<Source> {
|
||||||
|
Ok(Self::newSine(fs, freq)?)
|
||||||
|
}
|
||||||
|
#[pyo3(name = "newSilence")]
|
||||||
|
#[staticmethod]
|
||||||
|
fn newSilence_py() -> Source {
|
||||||
|
Self::newSilence()
|
||||||
|
}
|
||||||
|
#[staticmethod]
|
||||||
|
#[pyo3(name = "newWhiteNoise")]
|
||||||
|
fn newWhiteNoise_py() -> Source {
|
||||||
|
Self::newWhiteNoise()
|
||||||
|
}
|
||||||
|
#[staticmethod]
|
||||||
|
#[pyo3(name = "newSweep")]
|
||||||
|
fn newSweep_py(
|
||||||
|
fs: Flt,
|
||||||
|
fl: Flt,
|
||||||
|
fu: Flt,
|
||||||
|
sweep_time: Flt,
|
||||||
|
quiet_time: Flt,
|
||||||
|
sweep_type: SweepType,
|
||||||
|
) -> PyResult<Source> {
|
||||||
|
Ok(Self::newSweep(
|
||||||
|
fs, fl, fu, sweep_time, quiet_time, sweep_type,
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
/// Silence source. Most simple one does only send out a 0.
|
/// Silence source. Most simple one does only send out a 0.
|
||||||
struct Silence {}
|
struct Silence {}
|
||||||
|
|
||||||
@ -85,7 +120,7 @@ impl SourceImpl for Silence {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// White noise source. Can be colored by applying a color filter to the source
|
/// White noise source. Can be colored by applying a color filter to the source
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
struct WhiteNoise {}
|
struct WhiteNoise {}
|
||||||
impl SourceImpl for WhiteNoise {
|
impl SourceImpl for WhiteNoise {
|
||||||
fn genSignal_unscaled(&mut self, sig: &mut dyn ExactSizeIterator<Item = &mut Flt>) {
|
fn genSignal_unscaled(&mut self, sig: &mut dyn ExactSizeIterator<Item = &mut Flt>) {
|
||||||
@ -100,7 +135,7 @@ impl SourceImpl for WhiteNoise {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sine wave, with configurable frequency
|
/// Sine wave, with configurable frequency
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
struct Sine {
|
struct Sine {
|
||||||
// Sampling freq \[Hz\]
|
// Sampling freq \[Hz\]
|
||||||
fs: Flt,
|
fs: Flt,
|
||||||
@ -212,7 +247,7 @@ impl DerefMut for Source {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Source for the signal generator. Implementations are sine waves, sweeps, noise.
|
/// Source for the signal generator. Implementations are sine waves, sweeps, noise.
|
||||||
pub trait SourceImpl: Send {
|
pub trait SourceImpl: Send + Debug {
|
||||||
/// Generate the 'pure' source signal. Output is placed inside the `sig` argument.
|
/// Generate the 'pure' source signal. Output is placed inside the `sig` argument.
|
||||||
fn genSignal_unscaled(&mut self, sig: &mut dyn ExactSizeIterator<Item = &mut Flt>);
|
fn genSignal_unscaled(&mut self, sig: &mut dyn ExactSizeIterator<Item = &mut Flt>);
|
||||||
/// Reset the source state, i.e. set phase to 0, etc
|
/// Reset the source state, i.e. set phase to 0, etc
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
//! Sweep signal generation code
|
//! Sweep signal generation code
|
||||||
|
use strum_macros::{Display, EnumMessage};
|
||||||
|
use strum::EnumMessage;
|
||||||
use {
|
use {
|
||||||
crate::config::*,
|
crate::config::*,
|
||||||
anyhow::{bail, Result},
|
anyhow::{bail, Result},
|
||||||
@ -9,23 +11,49 @@ const twopi: Flt = 2. * pi;
|
|||||||
/// Enumerator representing the type of sweep source to create. Used as
|
/// Enumerator representing the type of sweep source to create. Used as
|
||||||
/// parameter in [Siggen::newSweep].
|
/// parameter in [Siggen::newSweep].
|
||||||
#[cfg_attr(feature = "python-bindings", pyclass)]
|
#[cfg_attr(feature = "python-bindings", pyclass)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Display, EnumMessage)]
|
||||||
pub enum SweepType {
|
pub enum SweepType {
|
||||||
/// Forward only logarithmic sweep, repeats itself
|
/// Forward only logarithmic sweep, repeats itself
|
||||||
|
#[strum(message = "Forward logarithmic")]
|
||||||
ForwardLog,
|
ForwardLog,
|
||||||
/// Reverse only logarithmic sweep, repeats itself
|
/// Reverse only logarithmic sweep, repeats itself
|
||||||
|
#[strum(message = "Backward logarithmic")]
|
||||||
BackwardLog,
|
BackwardLog,
|
||||||
/// Continuous logarithmic sweep, repeats itself
|
/// Continuous logarithmic sweep, repeats itself
|
||||||
|
#[strum(message = "Continuous logarithmic")]
|
||||||
ContinuousLog,
|
ContinuousLog,
|
||||||
|
|
||||||
/// Forward only linear sweep, repeats itself
|
/// Forward only linear sweep, repeats itself
|
||||||
|
#[strum(message = "Forward linear")]
|
||||||
ForwardLin,
|
ForwardLin,
|
||||||
/// Reverse only linear sweep, repeats itself
|
/// Reverse only linear sweep, repeats itself
|
||||||
|
#[strum(message = "Backward linear")]
|
||||||
BackwardLin,
|
BackwardLin,
|
||||||
/// Continuous linear sweep, repeats itself
|
/// Continuous linear sweep, repeats itself
|
||||||
|
#[strum(message = "Continuous linear")]
|
||||||
ContinuousLin,
|
ContinuousLin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python-bindings")]
|
||||||
|
#[cfg_attr(feature = "python-bindings", pymethods)]
|
||||||
|
impl SweepType {
|
||||||
|
#[staticmethod]
|
||||||
|
fn all() -> Vec<SweepType> {
|
||||||
|
use SweepType::*;
|
||||||
|
vec![
|
||||||
|
ForwardLin,
|
||||||
|
ForwardLog,
|
||||||
|
BackwardLin,
|
||||||
|
BackwardLog,
|
||||||
|
ContinuousLin,
|
||||||
|
ContinuousLog,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
fn __str__(&self) -> String {
|
||||||
|
self.get_message().unwrap().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SweepParams {
|
pub struct SweepParams {
|
||||||
// These parameters are described at [Source::newSweep]
|
// These parameters are described at [Source::newSweep]
|
||||||
|
Loading…
Reference in New Issue
Block a user