#[cfg(feature = "envelopes")]
use crate::{NdResult, operations::dynamic_range::EnvelopeFollower};
#[cfg(feature = "envelopes")]
use crate::operations::types::DynamicRangeMethod;
#[cfg(feature = "editing")]
use crate::operations::types::{FadeCurve, PadSide};
#[cfg(feature = "iir-filtering")]
use crate::AudioSample;
#[cfg(all(
feature = "editing",
feature = "random-generation",
feature = "iir-filtering"
))]
use crate::operations::types::PerturbationConfig;
#[cfg(feature = "channels")]
use crate::operations::types::{MonoConversionMethod, StereoConversionMethod};
#[cfg(feature = "processing")]
use crate::operations::types::NormalizationConfig;
#[cfg(all(feature = "processing", feature = "resampling"))]
use crate::{operations::types::ResamplingQuality, repr::SampleRate};
#[cfg(feature = "decomposition")]
use crate::operations::hpss::HpssConfig;
#[cfg(feature = "onset-detection")]
use crate::operations::onset::{
ComplexOnsetConfig, OnsetDetectionConfig, SpectralFluxConfig, SpectralFluxMethod,
};
#[cfg(feature = "parametric-eq")]
use crate::operations::types::{EqBand, ParametricEq, ThreeBandEqConfig};
#[cfg(feature = "beat-tracking")]
use crate::operations::beat::{BeatTrackingConfig, BeatTrackingData};
#[cfg(feature = "vad")]
use crate::operations::types::VadConfig;
#[cfg(feature = "dynamic-range")]
use crate::operations::types::{CompressorConfig, ExpanderConfig, GateConfig, LimiterConfig};
#[cfg(feature = "pitch-analysis")]
use crate::operations::types::PitchDetectionMethod;
#[cfg(feature = "iir-filtering")]
use crate::operations::types::{FilterResponse, IirFilterDesign};
#[cfg(feature = "transforms")]
use spectrograms::{
AmpScaleSpec, ChromaParams, Chromagram, CqtDbSpectrogram, CqtMagnitudeSpectrogram, CqtParams,
CqtPowerSpectrogram, CqtResult, CqtSpectrogram, Decibels, Gammatone, GammatoneDbSpectrogram,
GammatoneMagnitudeSpectrogram, GammatoneParams, GammatonePowerSpectrogram, LinearDbSpectrogram,
LinearHz, LinearMagnitudeSpectrogram, LinearPowerSpectrogram, LogHz, LogHzDbSpectrogram,
LogHzMagnitudeSpectrogram, LogHzParams, LogHzPowerSpectrogram, LogMelSpectrogram, LogParams,
Magnitude, MelMagnitudeSpectrogram, MelParams, MelPowerSpectrogram, MelSpectrogram, Mfcc,
MfccParams, Power, Spectrogram, SpectrogramParams, StftParams, StftResult,
};
#[cfg(any(feature = "transforms", feature = "onset-detection"))]
use ndarray::{Array2, Zip};
#[cfg(feature = "pitch-analysis")]
use spectrograms::WindowType;
#[cfg(feature = "plotting")]
use crate::operations::{
WaveformPlot, WaveformPlotParams,
plotting::lissajous::{LissajousParams, LissajousPlot},
plotting::phase_spectrum::{PhaseSpectrumParams, PhaseSpectrumPlot},
plotting::spectrograms::{SpectrogramPlot, SpectrogramPlotParams},
plotting::spectrum::{MagnitudeSpectrumParams, MagnitudeSpectrumPlot},
};
#[cfg(any(feature = "transforms", feature = "onset-detection"))]
use num_complex::Complex;
#[allow(unused_imports)]
use crate::{AudioSampleResult, AudioSamples, AudioTypeConversion, StandardSample};
#[allow(unused_imports)]
use non_empty_slice::{NonEmptySlice, NonEmptyVec};
#[allow(unused_imports)]
use std::num::NonZeroUsize;
#[cfg(feature = "statistics")]
pub trait AudioStatistics: AudioTypeConversion
where
Self::Sample: StandardSample,
{
fn peak(&self) -> Self::Sample;
#[inline]
fn amplitude(&self) -> Self::Sample {
self.peak()
}
fn min_sample(&self) -> Self::Sample;
fn max_sample(&self) -> Self::Sample;
fn mean(&self) -> f64;
fn midpoint_sample(&self) -> Option<f64>;
fn rms(&self) -> f64;
fn rms_and_peak(&self) -> (f64, Self::Sample) {
(self.rms(), self.peak())
}
fn variance(&self) -> f64;
fn std_dev(&self) -> f64;
fn zero_crossings(&self) -> usize;
fn zero_crossing_rate(&self) -> f64;
fn cross_correlation(
&self,
other: &Self,
max_lag: NonZeroUsize,
) -> AudioSampleResult<NonEmptyVec<f64>>;
#[cfg(feature = "transforms")]
fn spectral_centroid(
&self,
reduction: crate::operations::types::ChannelReduction,
) -> AudioSampleResult<f64>;
#[cfg(feature = "transforms")]
fn autocorrelation(&self, max_lag: NonZeroUsize) -> Option<NonEmptyVec<f64>>;
#[cfg(feature = "transforms")]
fn spectral_rolloff(
&self,
rolloff_percent: f64,
reduction: crate::operations::types::ChannelReduction,
) -> AudioSampleResult<f64>;
#[cfg(feature = "transforms")]
fn spectral_bandwidth(
&self,
reduction: crate::operations::types::ChannelReduction,
) -> AudioSampleResult<f64>;
#[cfg(feature = "transforms")]
fn spectral_flatness(
&self,
reduction: crate::operations::types::ChannelReduction,
) -> AudioSampleResult<f64>;
#[cfg(feature = "transforms")]
fn spectral_crest(
&self,
reduction: crate::operations::types::ChannelReduction,
) -> AudioSampleResult<f64>;
#[cfg(feature = "transforms")]
fn spectral_slope(
&self,
reduction: crate::operations::types::ChannelReduction,
) -> AudioSampleResult<f64>;
#[cfg(feature = "transforms")]
fn spectral_contrast(
&self,
n_bands: core::num::NonZeroUsize,
reduction: crate::operations::types::ChannelReduction,
) -> AudioSampleResult<Vec<f64>>;
}
#[cfg(feature = "vad")]
pub trait AudioVoiceActivityDetection: AudioTypeConversion
where
Self::Sample: StandardSample,
{
fn voice_activity_mask(&self, config: &VadConfig) -> AudioSampleResult<NonEmptyVec<bool>>;
fn speech_regions(&self, config: &VadConfig) -> AudioSampleResult<Vec<(usize, usize)>>;
}
#[cfg(feature = "processing")]
#[cfg_attr(feature = "educational", explainable::explainable)]
pub trait AudioProcessing: AudioTypeConversion
where
Self::Sample: StandardSample,
{
fn normalize_in_place(
&mut self,
config: NormalizationConfig<Self::Sample>,
) -> AudioSampleResult<()>;
#[inline]
fn normalize(&self, config: NormalizationConfig<Self::Sample>) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.normalize_in_place(config)?;
Ok(out)
}
fn scale_in_place(&mut self, factor: f64);
#[must_use]
#[inline]
fn scale(&self, factor: f64) -> Self
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.scale_in_place(factor);
out
}
fn apply_window_in_place(
&mut self,
window: &NonEmptySlice<Self::Sample>,
) -> AudioSampleResult<()>;
#[inline]
fn apply_window(&self, window: &NonEmptySlice<Self::Sample>) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_window_in_place(window)?;
Ok(out)
}
fn apply_filter_in_place(
&mut self,
filter_coeffs: &NonEmptySlice<Self::Sample>,
) -> AudioSampleResult<()>;
#[inline]
fn apply_filter(&self, filter_coeffs: &NonEmptySlice<Self::Sample>) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_filter_in_place(filter_coeffs)?;
Ok(out)
}
fn mu_compress_in_place(&mut self, mu: Self::Sample) -> AudioSampleResult<()>;
#[inline]
fn mu_compress(&self, mu: Self::Sample) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.mu_compress_in_place(mu)?;
Ok(out)
}
fn mu_expand_in_place(&mut self, mu: Self::Sample) -> AudioSampleResult<()>;
#[inline]
fn mu_expand(&self, mu: Self::Sample) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.mu_expand_in_place(mu)?;
Ok(out)
}
fn low_pass_filter_in_place(&mut self, cutoff_hz: f64) -> AudioSampleResult<()>;
#[inline]
fn low_pass_filter(&self, cutoff_hz: f64) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.low_pass_filter_in_place(cutoff_hz)?;
Ok(out)
}
fn high_pass_filter_in_place(&mut self, cutoff_hz: f64) -> AudioSampleResult<()>;
#[inline]
fn high_pass_filter(&self, cutoff_hz: f64) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.high_pass_filter_in_place(cutoff_hz)?;
Ok(out)
}
fn band_pass_filter_in_place(
&mut self,
low_cutoff_hz: f64,
high_cutoff_hz: f64,
) -> AudioSampleResult<()>;
#[inline]
fn band_pass_filter(&self, low_cutoff_hz: f64, high_cutoff_hz: f64) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.band_pass_filter_in_place(low_cutoff_hz, high_cutoff_hz)?;
Ok(out)
}
fn remove_dc_offset_in_place(&mut self) -> AudioSampleResult<()>;
#[inline]
fn remove_dc_offset(&self) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.remove_dc_offset_in_place()?;
Ok(out)
}
fn clip_in_place(
&mut self,
min_val: Self::Sample,
max_val: Self::Sample,
) -> AudioSampleResult<()>;
#[inline]
fn clip(&self, min_val: Self::Sample, max_val: Self::Sample) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.clip_in_place(min_val, max_val)?;
Ok(out)
}
#[cfg(feature = "resampling")]
fn resample(
&self,
target_sample_rate: SampleRate,
quality: ResamplingQuality,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
#[cfg(feature = "resampling")]
fn resample_in_place(
&mut self,
target_sample_rate: SampleRate,
quality: ResamplingQuality,
) -> AudioSampleResult<()>;
#[cfg(feature = "resampling")]
fn resample_by_ratio(
&self,
ratio: f64,
quality: ResamplingQuality,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
#[cfg(feature = "resampling")]
fn resample_by_ratio_in_place(
&mut self,
ratio: f64,
quality: ResamplingQuality,
) -> AudioSampleResult<()>;
}
#[cfg(feature = "transforms")]
pub trait AudioTransforms: AudioTypeConversion
where
Self::Sample: StandardSample,
{
fn fft(&self, n_fft: NonZeroUsize) -> AudioSampleResult<Array2<Complex<f64>>>;
fn convolve(&self, other: &Self) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn deconvolve(
&self,
denominator: &Self,
regularization: f64,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
#[inline]
fn rfft(&self, n_fft: NonZeroUsize) -> AudioSampleResult<Array2<f64>> {
let fft_complex = self.fft(n_fft)?;
Ok(fft_complex.mapv(Complex::norm))
}
fn stft(&self, params: &StftParams) -> AudioSampleResult<StftResult>;
fn istft(stft: StftResult) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn linear_spectrogram<AmpScale>(
&self,
params: &SpectrogramParams,
db: Option<&LogParams>,
) -> AudioSampleResult<Spectrogram<LinearHz, AmpScale>>
where
AmpScale: AmpScaleSpec;
#[inline]
fn linear_magnitude_spectrogram(
&self,
params: &SpectrogramParams,
) -> AudioSampleResult<LinearMagnitudeSpectrogram> {
self.linear_spectrogram::<Magnitude>(params, None)
}
#[inline]
fn linear_power_spectrogram(
&self,
params: &SpectrogramParams,
) -> AudioSampleResult<LinearPowerSpectrogram> {
self.linear_spectrogram::<Power>(params, None)
}
#[inline]
fn linear_db_spectrogram(
&self,
params: &SpectrogramParams,
db: &LogParams,
) -> AudioSampleResult<LinearDbSpectrogram> {
self.linear_spectrogram::<Decibels>(params, Some(db))
}
fn log_frequency_spectrogram<AmpScale>(
&self,
params: &SpectrogramParams,
loghz: &LogHzParams,
db: Option<&LogParams>,
) -> AudioSampleResult<Spectrogram<LogHz, AmpScale>>
where
AmpScale: AmpScaleSpec;
#[inline]
fn loghz_power_spectrogram(
&self,
params: &SpectrogramParams,
loghz: &LogHzParams,
) -> AudioSampleResult<LogHzPowerSpectrogram> {
self.log_frequency_spectrogram::<Power>(params, loghz, None)
}
#[inline]
fn loghz_magnitude_spectrogram(
&self,
params: &SpectrogramParams,
loghz: &LogHzParams,
) -> AudioSampleResult<LogHzMagnitudeSpectrogram> {
self.log_frequency_spectrogram::<Magnitude>(params, loghz, None)
}
#[inline]
fn loghz_db_spectrogram(
&self,
params: &SpectrogramParams,
loghz: &LogHzParams,
db: &LogParams,
) -> AudioSampleResult<LogHzDbSpectrogram> {
self.log_frequency_spectrogram::<Decibels>(params, loghz, Some(db))
}
fn mel_spectrogram<AmpScale>(
&self,
params: &SpectrogramParams,
mel: &MelParams,
db: Option<&LogParams>, ) -> AudioSampleResult<MelSpectrogram<AmpScale>>
where
AmpScale: AmpScaleSpec;
#[inline]
fn mel_mag_spectrogram(
&self,
params: &SpectrogramParams,
mel: &MelParams,
) -> AudioSampleResult<MelMagnitudeSpectrogram> {
self.mel_spectrogram(params, mel, None)
}
#[inline]
fn mel_db_spectrogram(
&self,
params: &SpectrogramParams,
mel: &MelParams,
db: &LogParams,
) -> AudioSampleResult<LogMelSpectrogram> {
self.mel_spectrogram(params, mel, Some(db))
}
#[inline]
fn mel_power_spectrogram(
&self,
params: &SpectrogramParams,
mel: &MelParams,
) -> AudioSampleResult<MelPowerSpectrogram> {
self.mel_spectrogram(params, mel, None)
}
fn mfcc(
&self,
stft_params: &StftParams,
n_mels: NonZeroUsize,
mfcc_params: &MfccParams,
) -> AudioSampleResult<Mfcc>;
fn chromagram(
&self,
stft_params: &StftParams,
cfg: &ChromaParams,
) -> AudioSampleResult<Chromagram>;
fn power_spectral_density(
&self,
window_size: NonZeroUsize,
overlap: f64,
) -> AudioSampleResult<crate::Psd>;
fn gammatone_spectrogram<AmpScale>(
&self,
params: &SpectrogramParams,
gammatone_params: &GammatoneParams,
db: Option<&LogParams>,
) -> AudioSampleResult<Spectrogram<Gammatone, AmpScale>>
where
AmpScale: AmpScaleSpec;
#[inline]
fn gammatone_magnitude_spectrogram(
&self,
params: &SpectrogramParams,
gammatone_params: &GammatoneParams,
) -> AudioSampleResult<GammatoneMagnitudeSpectrogram> {
self.gammatone_spectrogram::<Magnitude>(params, gammatone_params, None)
}
#[inline]
fn gammatone_power_spectrogram(
&self,
params: &SpectrogramParams,
gammatone_params: &GammatoneParams,
) -> AudioSampleResult<GammatonePowerSpectrogram> {
self.gammatone_spectrogram::<Power>(params, gammatone_params, None)
}
#[inline]
fn gammatone_db_spectrogram(
&self,
params: &SpectrogramParams,
gammatone_params: &GammatoneParams,
db: &LogParams,
) -> AudioSampleResult<GammatoneDbSpectrogram> {
self.gammatone_spectrogram::<Decibels>(params, gammatone_params, Some(db))
}
fn constant_q_transform(
&self,
params: &CqtParams,
hop_size: NonZeroUsize,
) -> AudioSampleResult<CqtResult>;
fn cqt_spectrogram<AmpScale>(
&self,
params: &SpectrogramParams,
cqt: &CqtParams,
db: Option<&LogParams>,
) -> AudioSampleResult<CqtSpectrogram<AmpScale>>
where
AmpScale: AmpScaleSpec;
#[inline]
fn cqt_magnitude_spectrogram(
&self,
params: &SpectrogramParams,
cqt: &CqtParams,
) -> AudioSampleResult<CqtMagnitudeSpectrogram> {
self.cqt_spectrogram::<Magnitude>(params, cqt, None)
}
#[inline]
fn cqt_power_spectrogram(
&self,
params: &SpectrogramParams,
cqt: &CqtParams,
) -> AudioSampleResult<CqtPowerSpectrogram> {
self.cqt_spectrogram::<Power>(params, cqt, None)
}
#[inline]
fn cqt_db_spectrogram(
&self,
params: &SpectrogramParams,
cqt: &CqtParams,
db: &LogParams,
) -> AudioSampleResult<CqtDbSpectrogram> {
self.cqt_spectrogram::<Decibels>(params, cqt, Some(db))
}
#[inline]
#[must_use]
fn magphase(
complex_spect: &Array2<Complex<f64>>,
power: Option<NonZeroUsize>,
) -> (Array2<f64>, Array2<Complex<f64>>) {
let mut mag = complex_spect.mapv(num_complex::Complex::norm);
let zeros_to_ones = mag.mapv(|x| if x == 0.0 { 1.0 } else { 0.0 });
let mag_nonzero = &mag + &zeros_to_ones;
let mut phase = complex_spect.clone();
let power = power.map_or(1.0, |p| p.get() as f64);
Zip::from(&mut phase)
.and(&mag_nonzero)
.and(&zeros_to_ones)
.for_each(|p, &m_nz, &z| {
let div = Complex {
re: p.re / m_nz + z, im: p.im / m_nz,
};
*p = div;
});
mag.mapv_inplace(|x| x.powf(power));
(mag, phase)
}
}
#[cfg(feature = "pitch-analysis")]
pub trait AudioPitchAnalysis: AudioTypeConversion
where
Self::Sample: StandardSample,
{
fn detect_pitch_yin(
&self,
threshold: f64,
min_frequency: f64,
max_frequency: f64,
) -> AudioSampleResult<Option<f64>>;
fn detect_pitch_autocorr(
&self,
min_frequency: f64,
max_frequency: f64,
) -> AudioSampleResult<Option<f64>>;
fn track_pitch(
&self,
window_size: NonZeroUsize,
hop_size: NonZeroUsize,
method: PitchDetectionMethod,
threshold: f64,
min_frequency: f64,
max_frequency: f64,
) -> AudioSampleResult<crate::PitchContour>;
fn harmonic_to_noise_ratio(
&self,
fundamental_freq: f64,
num_harmonics: NonZeroUsize,
n_fft: Option<NonZeroUsize>,
window_type: Option<WindowType>,
) -> AudioSampleResult<f64>;
fn harmonic_analysis(
&self,
fundamental_freq: f64,
num_harmonics: NonZeroUsize,
tolerance: f64,
n_fft: Option<NonZeroUsize>,
window_type: Option<WindowType>,
) -> AudioSampleResult<Vec<f64>>;
fn estimate_key(&self, stft_params: &StftParams) -> AudioSampleResult<crate::Key>;
}
#[cfg(feature = "iir-filtering")]
pub trait AudioIirFiltering: AudioTypeConversion
where
Self::Sample: AudioSample,
{
fn apply_iir_filter_in_place(&mut self, design: &IirFilterDesign) -> AudioSampleResult<()>;
fn apply_iir_filter(&self, design: &IirFilterDesign) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_iir_filter_in_place(design)?;
Ok(out)
}
fn filtfilt_in_place(&mut self, design: &IirFilterDesign) -> AudioSampleResult<()>;
fn filtfilt(&self, design: &IirFilterDesign) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.filtfilt_in_place(design)?;
Ok(out)
}
fn butterworth_lowpass_in_place(
&mut self,
order: NonZeroUsize,
cutoff_frequency: f64,
) -> AudioSampleResult<()>;
fn butterworth_lowpass(
&self,
order: NonZeroUsize,
cutoff_frequency: f64,
) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.butterworth_lowpass_in_place(order, cutoff_frequency)?;
Ok(out)
}
fn butterworth_highpass_in_place(
&mut self,
order: NonZeroUsize,
cutoff_frequency: f64,
) -> AudioSampleResult<()>;
fn butterworth_highpass(
&self,
order: NonZeroUsize,
cutoff_frequency: f64,
) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.butterworth_highpass_in_place(order, cutoff_frequency)?;
Ok(out)
}
fn butterworth_bandpass_in_place(
&mut self,
order: NonZeroUsize,
low_frequency: f64,
high_frequency: f64,
) -> AudioSampleResult<()>;
fn butterworth_bandpass(
&self,
order: NonZeroUsize,
low_frequency: f64,
high_frequency: f64,
) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.butterworth_bandpass_in_place(order, low_frequency, high_frequency)?;
Ok(out)
}
fn chebyshev_i_in_place(
&mut self,
order: NonZeroUsize,
cutoff_frequency: f64,
passband_ripple: f64,
response: FilterResponse,
) -> AudioSampleResult<()>;
fn chebyshev_i(
&self,
order: NonZeroUsize,
cutoff_frequency: f64,
passband_ripple: f64,
response: FilterResponse,
) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.chebyshev_i_in_place(order, cutoff_frequency, passband_ripple, response)?;
Ok(out)
}
fn frequency_response(&self, frequencies: &[f64]) -> AudioSampleResult<(Vec<f64>, Vec<f64>)>;
}
#[cfg(feature = "parametric-eq")]
pub trait AudioParametricEq: AudioChannelOps
where
Self::Sample: StandardSample,
{
fn apply_parametric_eq_in_place(&mut self, eq: &ParametricEq) -> AudioSampleResult<()>;
fn apply_parametric_eq(&self, eq: &ParametricEq) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_parametric_eq_in_place(eq)?;
Ok(out)
}
fn apply_eq_band_in_place(&mut self, band: &EqBand) -> AudioSampleResult<()>;
fn apply_eq_band(&self, band: &EqBand) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_eq_band_in_place(band)?;
Ok(out)
}
fn apply_peak_filter_in_place(
&mut self,
frequency: f64,
gain_db: f64,
q_factor: f64,
) -> AudioSampleResult<()>;
fn apply_peak_filter(
&self,
frequency: f64,
gain_db: f64,
q_factor: f64,
) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_peak_filter_in_place(frequency, gain_db, q_factor)?;
Ok(out)
}
fn apply_low_shelf_in_place(
&mut self,
frequency: f64,
gain_db: f64,
q_factor: f64,
) -> AudioSampleResult<()>;
fn apply_low_shelf(
&self,
frequency: f64,
gain_db: f64,
q_factor: f64,
) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_low_shelf_in_place(frequency, gain_db, q_factor)?;
Ok(out)
}
fn apply_high_shelf_in_place(
&mut self,
frequency: f64,
gain_db: f64,
q_factor: f64,
) -> AudioSampleResult<()>;
fn apply_high_shelf(
&self,
frequency: f64,
gain_db: f64,
q_factor: f64,
) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_high_shelf_in_place(frequency, gain_db, q_factor)?;
Ok(out)
}
fn apply_three_band_eq_in_place(&mut self, config: &ThreeBandEqConfig)
-> AudioSampleResult<()>;
fn apply_three_band_eq(&self, config: &ThreeBandEqConfig) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_three_band_eq_in_place(config)?;
Ok(out)
}
fn eq_frequency_response(
&self,
eq: &ParametricEq,
frequencies: &[f64],
) -> AudioSampleResult<(Vec<f64>, Vec<f64>)>;
}
#[cfg(feature = "dynamic-range")]
pub trait AudioDynamicRange: AudioTypeConversion
where
Self::Sample: StandardSample,
{
fn apply_compressor_in_place(&mut self, config: &CompressorConfig) -> AudioSampleResult<()>;
fn apply_compressor(&self, config: &CompressorConfig) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_compressor_in_place(config)?;
Ok(out)
}
fn apply_limiter_in_place(&mut self, config: &LimiterConfig) -> AudioSampleResult<()>;
fn apply_limiter(&self, config: &LimiterConfig) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_limiter_in_place(config)?;
Ok(out)
}
fn apply_compressor_sidechain_in_place(
&mut self,
config: &CompressorConfig,
sidechain_signal: &Self,
) -> AudioSampleResult<()>;
fn apply_compressor_sidechain(
&self,
config: &CompressorConfig,
sidechain_signal: &Self,
) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_compressor_sidechain_in_place(config, sidechain_signal)?;
Ok(out)
}
fn apply_limiter_sidechain_in_place(
&mut self,
config: &LimiterConfig,
sidechain_signal: &Self,
) -> AudioSampleResult<()>;
fn apply_limiter_sidechain(
&self,
config: &LimiterConfig,
sidechain_signal: &Self,
) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_limiter_sidechain_in_place(config, sidechain_signal)?;
Ok(out)
}
fn get_compression_curve(
&self,
config: &CompressorConfig,
input_levels_db: &NonEmptySlice<f64>,
) -> AudioSampleResult<Vec<f64>>;
fn get_gain_reduction(&self, config: &CompressorConfig) -> AudioSampleResult<Vec<f64>>;
fn apply_gate_in_place(&mut self, config: &GateConfig) -> AudioSampleResult<()>;
fn apply_gate(&self, config: &GateConfig) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_gate_in_place(config)?;
Ok(out)
}
fn apply_expander_in_place(&mut self, config: &ExpanderConfig) -> AudioSampleResult<()>;
fn apply_expander(&self, config: &ExpanderConfig) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.apply_expander_in_place(config)?;
Ok(out)
}
}
#[cfg(feature = "editing")]
pub trait AudioEditing: AudioTypeConversion
where
Self::Sample: StandardSample,
{
fn reverse<'b>(&self) -> AudioSamples<'b, Self::Sample>
where
Self: Sized;
fn reverse_in_place(&mut self) -> AudioSampleResult<()>
where
Self: Sized;
fn trim<'b>(
&self,
start_seconds: f64,
end_seconds: f64,
) -> AudioSampleResult<AudioSamples<'b, Self::Sample>>;
fn trim_in_place(&mut self, start_seconds: f64, end_seconds: f64) -> AudioSampleResult<()>;
fn pad<'b>(
&self,
pad_start_seconds: f64,
pad_end_seconds: f64,
pad_value: Self::Sample,
) -> AudioSampleResult<AudioSamples<'b, Self::Sample>>;
fn pad_in_place(
&mut self,
pad_start_seconds: f64,
pad_end_seconds: f64,
pad_value: Self::Sample,
) -> AudioSampleResult<()>;
fn pad_samples_right<'b>(
&self,
target_num_samples: usize,
pad_value: Self::Sample,
) -> AudioSampleResult<AudioSamples<'b, Self::Sample>>;
fn pad_samples_right_in_place(
&mut self,
target_num_samples: usize,
pad_value: Self::Sample,
) -> AudioSampleResult<()>;
fn pad_to_duration<'b>(
&self,
target_duration_seconds: f64,
pad_value: Self::Sample,
pad_side: PadSide,
) -> AudioSampleResult<AudioSamples<'b, Self::Sample>>;
fn pad_to_duration_in_place(
&mut self,
target_duration_seconds: f64,
pad_value: Self::Sample,
pad_side: PadSide,
) -> AudioSampleResult<()>;
fn split(
&self,
segment_duration_seconds: f64,
) -> AudioSampleResult<Vec<AudioSamples<'static, Self::Sample>>>;
fn concatenate<'b>(
segments: &'b NonEmptySlice<AudioSamples<'b, Self::Sample>>,
) -> AudioSampleResult<AudioSamples<'b, Self::Sample>>;
fn concatenate_owned<'b>(
segments: NonEmptyVec<AudioSamples<'_, Self::Sample>>,
) -> AudioSampleResult<AudioSamples<'b, Self::Sample>>;
fn mix(
sources: &NonEmptySlice<Self>,
weights: Option<&NonEmptySlice<f64>>,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn fade_in_in_place(
&mut self,
duration_seconds: f64,
curve: FadeCurve,
) -> AudioSampleResult<()>;
#[inline]
fn fade_in(&self, duration_seconds: f64, curve: FadeCurve) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.fade_in_in_place(duration_seconds, curve)?;
Ok(out)
}
fn fade_out_in_place(
&mut self,
duration_seconds: f64,
curve: FadeCurve,
) -> AudioSampleResult<()>;
#[inline]
fn fade_out(&self, duration_seconds: f64, curve: FadeCurve) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.fade_out_in_place(duration_seconds, curve)?;
Ok(out)
}
fn repeat(&self, count: usize) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn repeat_in_place(&mut self, count: usize) -> AudioSampleResult<()>;
fn trim_silence(
&self,
threshold_db: f64,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn trim_silence_in_place(&mut self, threshold_db: f64) -> AudioSampleResult<()>;
#[cfg(all(feature = "random-generation", feature = "iir-filtering"))]
fn perturb<'b>(
&self,
config: &PerturbationConfig,
) -> AudioSampleResult<AudioSamples<'b, Self::Sample>>;
#[cfg(all(feature = "random-generation", feature = "iir-filtering"))]
fn perturb_in_place(&mut self, config: &PerturbationConfig) -> AudioSampleResult<()>;
fn stack(
sources: &NonEmptySlice<Self>,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn trim_all_silence(
&self,
threshold_db: f64,
min_silence_duration_seconds: f64,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn trim_all_silence_in_place(
&mut self,
threshold_db: f64,
min_silence_duration_seconds: f64,
) -> AudioSampleResult<()>;
}
#[cfg(feature = "channels")]
pub trait AudioChannelOps: AudioTypeConversion
where
Self::Sample: StandardSample,
{
fn to_mono(
&self,
method: MonoConversionMethod,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn to_mono_in_place(&mut self, method: MonoConversionMethod) -> AudioSampleResult<()>;
fn to_stereo(
&self,
method: StereoConversionMethod,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn to_stereo_in_place(&mut self, method: StereoConversionMethod) -> AudioSampleResult<()>;
fn duplicate_to_channels(
&self,
n_channels: usize,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn duplicate_to_channels_in_place(&mut self, n_channels: usize) -> AudioSampleResult<()>;
fn extract_channel(
&self,
channel_index: usize,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn borrow_channel(
&self,
channel_index: usize,
) -> AudioSampleResult<AudioSamples<'_, Self::Sample>>;
fn swap_channels_in_place(&mut self, channel1: usize, channel2: usize)
-> AudioSampleResult<()>;
#[inline]
fn swap_channels(&self, channel1: usize, channel2: usize) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.swap_channels_in_place(channel1, channel2)?;
Ok(out)
}
fn pan_in_place(&mut self, pan_value: f64) -> AudioSampleResult<()>;
#[inline]
fn pan(&self, pan_value: f64) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.pan_in_place(pan_value)?;
Ok(out)
}
fn balance_in_place(&mut self, balance: f64) -> AudioSampleResult<()>;
#[inline]
fn balance(&self, balance: f64) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
{
let mut out = self.clone();
out.balance_in_place(balance)?;
Ok(out)
}
fn apply_to_channel_in_place<F>(
&mut self,
channel_index: usize,
func: F,
) -> AudioSampleResult<()>
where
F: FnMut(Self::Sample) -> Self::Sample;
#[inline]
fn apply_to_channel<F>(&self, channel_index: usize, func: F) -> AudioSampleResult<Self>
where
Self: Sized + Clone,
F: FnMut(Self::Sample) -> Self::Sample,
{
let mut out = self.clone();
out.apply_to_channel_in_place(channel_index, func)?;
Ok(out)
}
fn interleave_channels(
channels: &NonEmptySlice<AudioSamples<'_, Self::Sample>>,
) -> AudioSampleResult<AudioSamples<'static, Self::Sample>>;
fn deinterleave_channels(&self) -> AudioSampleResult<Vec<AudioSamples<'static, Self::Sample>>>;
}
#[cfg(feature = "decomposition")]
pub trait AudioDecomposition: AudioTransforms
where
Self::Sample: StandardSample,
{
#[allow(clippy::type_complexity)]
fn hpss(
&self,
config: &HpssConfig,
) -> AudioSampleResult<(
AudioSamples<'static, Self::Sample>,
AudioSamples<'static, Self::Sample>,
)>;
}
#[cfg(feature = "onset-detection")]
pub trait AudioOnsetDetection: AudioTransforms
where
Self::Sample: StandardSample,
{
fn detect_onsets(&self, config: &OnsetDetectionConfig) -> AudioSampleResult<Vec<f64>>;
fn onset_detection_function(
&self,
config: &OnsetDetectionConfig,
) -> AudioSampleResult<(NonEmptyVec<f64>, NonEmptyVec<f64>)>;
fn detect_onsets_spectral_flux(
&self,
config: &SpectralFluxConfig,
) -> AudioSampleResult<Vec<f64>>;
fn spectral_flux(
&self,
config: &CqtParams,
window_size: NonZeroUsize,
hop_size: NonZeroUsize,
method: SpectralFluxMethod,
) -> AudioSampleResult<(NonEmptyVec<f64>, NonEmptyVec<f64>)>;
fn complex_onset_detection(
&self,
onset_config: &ComplexOnsetConfig,
) -> AudioSampleResult<Vec<f64>>;
fn onset_detection_function_complex(
&self,
onset_config: &ComplexOnsetConfig,
) -> AudioSampleResult<NonEmptyVec<f64>>;
fn magnitude_difference_matrix(
&self,
config: &ComplexOnsetConfig,
) -> AudioSampleResult<Array2<f64>>;
fn phase_deviation_matrix(&self, config: &ComplexOnsetConfig)
-> AudioSampleResult<Array2<f64>>;
}
#[cfg(feature = "beat-tracking")]
pub trait AudioBeatTracking: AudioTransforms
where
Self::Sample: StandardSample,
{
fn detect_beats(&self, config: &BeatTrackingConfig) -> AudioSampleResult<BeatTrackingData>;
fn estimate_tempo(&self, config: &BeatTrackingConfig) -> AudioSampleResult<f64>;
}
#[cfg(feature = "plotting")]
pub trait AudioPlotting: AudioTransforms
where
Self::Sample: StandardSample,
{
fn plot_waveform(&self, params: &WaveformPlotParams) -> AudioSampleResult<WaveformPlot>;
fn plot_spectrogram(
&self,
params: &SpectrogramPlotParams,
) -> AudioSampleResult<SpectrogramPlot>;
fn plot_magnitude_spectrum(
&self,
params: &MagnitudeSpectrumParams,
) -> AudioSampleResult<MagnitudeSpectrumPlot>;
fn plot_phase_spectrum(
&self,
params: &PhaseSpectrumParams,
) -> AudioSampleResult<PhaseSpectrumPlot>;
fn plot_lissajous(&self, params: &LissajousParams) -> AudioSampleResult<LissajousPlot>;
}
#[cfg(feature = "envelopes")]
pub trait AudioEnvelopes: AudioStatistics
where
Self::Sample: StandardSample,
{
fn amplitude_envelope(&self) -> NdResult<Self::Sample>;
fn rms_envelope(
&self,
window_size: NonZeroUsize,
hop_size: NonZeroUsize,
) -> NdResult<Self::Sample>;
#[allow(clippy::type_complexity)]
fn attack_decay_envelope(
&self,
follower: &EnvelopeFollower,
method: DynamicRangeMethod,
) -> (NdResult<Self::Sample>, NdResult<Self::Sample>);
fn analytic_envelope(&self) -> NdResult<Self::Sample>;
fn moving_average_envelope(
&self,
window_size: NonZeroUsize,
hop_size: NonZeroUsize,
) -> NdResult<Self::Sample>;
}