use std::num::NonZeroU32;
use std::time::Duration;
#[cfg(feature = "editing")]
use crate::AudioSampleResult;
use crate::{AudioSamples, ConvertTo, StandardSample};
#[cfg(feature = "editing")]
use non_empty_slice::NonEmptyVec;
#[cfg(feature = "editing")]
use crate::{AudioEditing, repr::SampleRate};
use ndarray::Array1;
use non_empty_slice::NonEmptySlice;
use num_traits::FloatConst;
#[cfg(feature = "editing")]
#[derive(Debug, Clone)]
pub struct MonoSampleBuilder<'a, T>
where
T: StandardSample,
{
samples: Vec<AudioSamples<'a, T>>,
sample_rate: SampleRate,
}
#[cfg(feature = "editing")]
impl<T> MonoSampleBuilder<'_, T>
where
T: StandardSample,
{
#[inline]
#[must_use]
pub const fn new(sample_rate: SampleRate) -> Self {
Self {
samples: Vec::new(),
sample_rate,
}
}
#[inline]
#[must_use]
pub fn add_sample(mut self, sample: AudioSamples<'_, T>) -> Self {
self.samples.push(sample.into_owned());
self
}
#[inline]
#[must_use]
pub fn sine_wave(self, frequency: f64, duration: Duration, amplitude: f64) -> Self {
let sr = self.sample_rate;
self.add_sample(sine_wave::<T>(frequency, duration, sr, amplitude))
}
#[inline]
#[must_use]
pub fn cosine_wave(self, frequency: f64, duration: Duration, amplitude: f64) -> Self {
let sr = self.sample_rate;
self.add_sample(cosine_wave::<T>(frequency, duration, sr, amplitude))
}
#[cfg(feature = "random-generation")]
#[inline]
#[must_use]
pub fn white_noise(self, duration: Duration, amplitude: f64, seed: Option<u64>) -> Self {
let sr = self.sample_rate;
self.add_sample(white_noise::<T>(duration, sr, amplitude, seed))
}
#[cfg(feature = "random-generation")]
#[inline]
#[must_use]
pub fn pink_noise(self, duration: Duration, amplitude: f64, seed: Option<u64>) -> Self {
let sr = self.sample_rate;
self.add_sample(pink_noise::<T>(duration, sr, amplitude, seed))
}
#[inline]
#[must_use]
pub fn sawtooth_wave(self, frequency: f64, duration: Duration, amplitude: f64) -> Self {
let sr = self.sample_rate;
self.add_sample(sawtooth_wave::<T>(frequency, duration, sr, amplitude))
}
#[inline]
#[must_use]
pub fn square_wave(self, frequency: f64, duration: Duration, amplitude: f64) -> Self {
let sr = self.sample_rate;
self.add_sample(square_wave::<T>(frequency, duration, sr, amplitude))
}
#[inline]
#[must_use]
pub fn triangle_wave(self, frequency: f64, duration: Duration, amplitude: f64) -> Self {
let sr = self.sample_rate;
self.add_sample(triangle_wave::<T>(frequency, duration, sr, amplitude))
}
#[inline]
#[must_use]
pub fn silence(self, duration: Duration) -> Self {
let sr = self.sample_rate;
self.add_sample(silence::<T>(duration, sr))
}
#[inline]
pub fn build(self) -> AudioSampleResult<AudioSamples<'static, T>> {
let samples =
NonEmptyVec::new(self.samples).map_err(|_| crate::AudioSampleError::EmptyData)?;
AudioSamples::concatenate_owned(samples)
}
}
#[inline]
#[must_use]
pub fn sine_wave<T>(
frequency: f64,
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let sample_rate_f = f64::from(sample_rate.get());
let num_samples = (duration.as_secs_f64() * sample_rate_f) as usize;
let mut samples = Vec::with_capacity(num_samples);
let two = 2.0;
let pi = f64::PI();
let two_pi_frrq = two * pi * frequency;
for i in 0..num_samples {
let t = i as f64 / sample_rate_f;
let sample = amplitude * (two_pi_frrq * t).sin();
samples.push(sample.convert_to());
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[inline]
#[must_use]
pub fn cosine_wave<T>(
frequency: f64,
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let sample_rate_f = f64::from(sample_rate.get());
let num_samples = (duration.as_secs_f64() * sample_rate_f) as usize;
let mut samples = Vec::with_capacity(num_samples);
let pi = f64::PI();
let two_pi_freq = 2.0 * pi * frequency;
for i in 0..num_samples {
let t = i as f64 / sample_rate_f;
let sample = amplitude * (two_pi_freq * t).cos();
samples.push(sample.convert_to());
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[cfg(feature = "random-generation")]
#[inline]
#[must_use]
pub fn brown_noise<T>(
duration: Duration,
sample_rate: NonZeroU32,
step: f64,
amplitude: f64,
seed: Option<u64>,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let num_samples = (duration.as_secs_f64() * f64::from(sample_rate.get())) as usize;
let mut samples = Vec::with_capacity(num_samples);
let mut brown_state = 0.0f64;
if let Some(seed) = seed {
use rand::rngs::StdRng;
use rand::{RngExt, SeedableRng};
let mut rng = StdRng::seed_from_u64(seed);
let white: f64 = (rng.random::<f64>() - 0.5) * 2.0;
brown_state += white * step;
brown_state = brown_state.clamp(-1.0, 1.0);
let b_state: f64 = brown_state;
let sample = amplitude * b_state;
samples.push(sample.convert_to());
} else {
for _ in 0..num_samples {
let white: f64 = (rand::random::<f64>() - 0.5) * 2.0;
brown_state += white * step;
brown_state = brown_state.clamp(-1.0, 1.0);
let b_state: f64 = brown_state;
let sample = amplitude * b_state;
samples.push(sample.convert_to());
}
}
let arr = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(arr, sample_rate) }
}
#[cfg(feature = "random-generation")]
#[inline]
#[must_use]
pub fn white_noise<T>(
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
seed: Option<u64>,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
use rand::rngs::StdRng;
use rand::{RngExt, SeedableRng};
let num_samples = ((duration.as_secs_f64()) * f64::from(sample_rate.get())) as usize;
let mut samples = Vec::with_capacity(num_samples);
let two = 2.0;
let half = 0.5;
if let Some(seed) = seed {
let mut rng = StdRng::seed_from_u64(seed);
for _ in 0..num_samples {
let random_value = (rng.random::<f64>() - half) * two;
let random_value: f64 = random_value;
let sample = amplitude * random_value;
samples.push(sample.convert_to());
}
} else {
for _ in 0..num_samples {
let random_value = (rand::random::<f64>() - half) * two;
let random_value: f64 = random_value;
let sample = amplitude * random_value;
samples.push(sample.convert_to());
}
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[cfg(feature = "random-generation")]
#[inline]
#[must_use]
pub fn pink_noise<T>(
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
seed: Option<u64>,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
use rand::rngs::StdRng;
use rand::{RngExt, SeedableRng};
let num_samples = ((duration.as_secs_f64()) * f64::from(sample_rate.get())) as usize;
let mut samples = Vec::with_capacity(num_samples);
let mut b = [0.0; 7];
let two = 2.0;
let half = 0.5;
let a0 = 0.998_86;
let b0 = 0.055_517_9;
let a1 = 0.993_32;
let b1 = 0.075_075_9;
let a2 = 0.969_00;
let b2 = 0.153_852_0;
let a3 = 0.866_50;
let b3 = 0.310_485_6;
let a4 = 0.550_00;
let b4 = 0.532_952_2;
let a5 = -0.761_6;
let b5 = -0.016_898_0;
let b6 = 0.115_926;
let pink_calc_multiplier1 = 0.5362;
let pink_calc_multiplier2 = 0.11;
if let Some(seed) = seed {
let mut rng = StdRng::seed_from_u64(seed);
for _ in 0..num_samples {
let white = (rng.random::<f64>() - half) * two;
b[0] = a0 * b[0] + white * b0;
b[1] = a1 * b[1] + white * b1;
b[2] = a2 * b[2] + white * b2;
b[3] = a3 * b[3] + white * b3;
b[4] = a4 * b[4] + white * b4;
b[5] = a5 * b[5] + white * b5;
let pink =
b[0] + b[1] + b[2] + b[3] + b[4] + b[5] + b[6] + white * pink_calc_multiplier1;
b[6] = white * b6;
let pink: f64 = pink * pink_calc_multiplier2;
let sample = amplitude * pink;
samples.push(sample.convert_to());
}
} else {
for _ in 0..num_samples {
let white = (rand::random::<f64>() - half) * two;
b[0] = a0 * b[0] + white * b0;
b[1] = a1 * b[1] + white * b1;
b[2] = a2 * b[2] + white * b2;
b[3] = a3 * b[3] + white * b3;
b[4] = a4 * b[4] + white * b4;
b[5] = a5 * b[5] + white * b5;
let pink =
b[0] + b[1] + b[2] + b[3] + b[4] + b[5] + b[6] + white * pink_calc_multiplier1;
b[6] = white * b6;
let pink: f64 = pink * pink_calc_multiplier2;
let sample = amplitude * pink;
samples.push(sample.convert_to());
}
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[inline]
#[must_use]
pub fn square_wave<T>(
frequency: f64,
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let num_samples = ((duration.as_secs_f64()) * f64::from(sample_rate.get())) as usize;
let mut samples = Vec::with_capacity(num_samples);
let two_pi = 2.0 * std::f64::consts::PI;
let freq = frequency;
let sample_rate_f = f64::from(sample_rate.get());
for i in 0..num_samples {
let t = i as f64 / sample_rate_f;
let arg = two_pi * freq * t;
let sin_val = arg.sin();
let sample = if sin_val >= 0.0 {
amplitude
} else {
-amplitude
};
samples.push(sample.convert_to());
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[inline]
#[must_use]
pub fn sawtooth_wave<T>(
frequency: f64,
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let sr_f = f64::from(sample_rate.get());
let num_samples = (duration.as_secs_f64() * sr_f) as usize;
let mut samples = Vec::with_capacity(num_samples);
let two_pi = 2.0 * std::f64::consts::PI;
let freq = frequency;
for i in 0..num_samples {
let t = i as f64 / sr_f;
let arg = two_pi * freq * t;
let phase = arg / two_pi;
let frac = (phase - 1.0) % 1.0;
let frac = if frac < 0.0 { frac + 1.0 } else { frac };
let sample = amplitude * (frac * 2.0 - 1.0);
samples.push(sample.convert_to());
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[inline]
#[must_use]
pub fn triangle_wave<T>(
frequency: f64,
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let sr_f = f64::from(sample_rate.get());
let freq_f = frequency;
let num_samples = (duration.as_secs_f64() * sr_f) as usize;
let mut samples = Vec::with_capacity(num_samples);
let mut phase = 0.0;
let phase_inc = freq_f / sr_f;
for _ in 0..num_samples {
let sample = if phase < 0.5 {
amplitude * 4.0f64.mul_add(phase, -1.0)
} else {
amplitude * 4.0f64.mul_add(-phase, 3.0)
};
samples.push(sample.convert_to());
phase += phase_inc;
if phase >= 1.0 {
phase -= 1.0;
}
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[inline]
#[must_use]
pub fn chirp<T>(
start_freq: f64,
end_freq: f64,
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let num_samples = ((duration.as_secs_f64()) * f64::from(sample_rate.get())) as usize;
let mut samples = Vec::with_capacity(num_samples);
let sr_f = f64::from(sample_rate.get());
let f0 = start_freq;
let f1 = end_freq;
let duration_f = duration.as_secs_f64();
let k = (f1 - f0) / duration_f;
let two_pi = 2.0 * f64::PI();
for i in 0..num_samples {
let t = i as f64 / sr_f;
let phase = two_pi * f0.mul_add(t, 0.5 * k * t * t);
let value = amplitude * phase.sin();
samples.push(value.convert_to());
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[inline]
#[must_use]
pub fn impulse<T>(
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
position: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let num_samples = ((duration.as_secs_f64()) * f64::from(sample_rate.get())) as usize;
let mut samples: Vec<T> = vec![0.0.convert_to(); num_samples];
let impulse_sample = (position * f64::from(sample_rate.get())) as usize;
if impulse_sample < num_samples {
samples[impulse_sample] = amplitude.convert_to();
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct ToneComponent {
pub frequency: f64,
pub amplitude: f64,
}
impl ToneComponent {
#[inline]
#[must_use]
pub const fn new(frequency: f64, amplitude: f64) -> Self {
Self {
frequency,
amplitude,
}
}
}
#[inline]
#[must_use]
pub fn compound_tone<T>(
components: &NonEmptySlice<ToneComponent>,
duration: Duration,
sample_rate: NonZeroU32,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let sr_f = f64::from(sample_rate.get());
let num_samples = ((duration.as_secs_f64()) * sr_f) as usize;
let two_pi = 2.0 * f64::PI();
let mut samples = Vec::with_capacity(num_samples);
for i in 0..num_samples {
let t = i as f64 / sr_f;
let mut sum = 0.0;
for comp in components {
sum += comp.amplitude * two_pi * comp.frequency * t.sin();
}
samples.push(sum.convert_to());
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[inline]
#[must_use]
pub fn am_signal<T>(
carrier_freq: f64,
modulator_freq: f64,
modulation_depth: f64,
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let sr_f = f64::from(sample_rate.get());
let num_samples = ((duration.as_secs_f64()) * sr_f) as usize;
let two_pi = 2.0 * f64::PI();
let one = 1.0;
let mut samples = Vec::with_capacity(num_samples);
for i in 0..num_samples {
let t = i as f64 / sr_f;
let envelope =
modulation_depth.mul_add((two_pi * modulator_freq * t).sin(), one - modulation_depth);
let carrier = (two_pi * carrier_freq * t).sin();
let sample = amplitude * envelope * carrier;
samples.push(sample.convert_to());
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[cfg(feature = "random-generation")]
#[inline]
#[must_use]
pub fn exponential_bursts<T>(
burst_rate: f64,
decay_rate: f64,
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let sr_f = f64::from(sample_rate.get());
let num_samples = ((duration.as_secs_f64()) * sr_f) as usize;
let two_pi = 2.0 * f64::PI();
let burst_period_threshold = 0.1; let noise_mix = 0.7;
let tone_mix = 0.3;
let tone_freq = 200.0;
let mut samples = Vec::with_capacity(num_samples);
for i in 0..num_samples {
let t = i as f64 / sr_f;
let burst_phase = (burst_rate * t) % 1.0;
let envelope = if burst_phase < burst_period_threshold {
(-burst_phase * decay_rate).exp()
} else {
0.0
};
let noise = (rand::random::<f64>() - 0.5) * 2.0;
let tone = (two_pi * tone_freq * t).sin();
let sample = amplitude * envelope * (noise_mix * noise + tone_mix * tone);
samples.push(sample.convert_to());
}
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[inline]
#[must_use]
pub fn silence<T>(duration: Duration, sample_rate: NonZeroU32) -> AudioSamples<'static, T>
where
T: StandardSample,
{
let num_samples = ((duration.as_secs_f64()) * f64::from(sample_rate.get())) as usize;
let samples = vec![T::zero(); num_samples];
let array = Array1::from_vec(samples);
unsafe { AudioSamples::new_mono_unchecked(array, sample_rate) }
}
#[cfg(feature = "channels")]
#[inline]
#[must_use]
pub fn stereo_sine_wave<T>(
frequency: f64,
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
use crate::operations::AudioChannelOps;
let mono = sine_wave::<T>(frequency, duration, sample_rate, amplitude);
mono.duplicate_to_channels(2)
.expect("duplicating mono to stereo should not fail")
}
#[cfg(feature = "channels")]
#[inline]
#[must_use]
pub fn stereo_chirp<T>(
start_freq: f64,
end_freq: f64,
duration: Duration,
sample_rate: NonZeroU32,
amplitude: f64,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
use crate::operations::AudioChannelOps;
let mono = chirp::<T>(start_freq, end_freq, duration, sample_rate, amplitude);
mono.duplicate_to_channels(2)
.expect("duplicating mono to stereo should not fail")
}
#[cfg(feature = "channels")]
#[inline]
#[must_use]
pub fn stereo_silence<T>(duration: Duration, sample_rate: NonZeroU32) -> AudioSamples<'static, T>
where
T: StandardSample,
{
use crate::operations::AudioChannelOps;
let mono = silence::<T>(duration, sample_rate);
mono.duplicate_to_channels(2)
.expect("duplicating mono to stereo should not fail")
}
#[cfg(feature = "channels")]
#[inline]
#[must_use]
pub fn multichannel_compound_tone<T>(
components: &NonEmptySlice<ToneComponent>,
duration: Duration,
sample_rate: NonZeroU32,
n_channels: usize,
) -> AudioSamples<'static, T>
where
T: StandardSample,
{
use crate::operations::AudioChannelOps;
let mono = compound_tone::<T>(components, duration, sample_rate);
mono.duplicate_to_channels(n_channels)
.expect("duplicating mono to n_channels should not fail")
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "statistics")]
use crate::operations::traits::AudioStatistics;
use crate::sample_rate;
use approx_eq::assert_approx_eq;
#[test]
fn test_sine_wave_generation() {
let audio = sine_wave::<f32>(
440.0,
Duration::from_secs_f32(1.0),
sample_rate!(44100),
1.0,
);
assert_eq!(audio.sample_rate(), sample_rate!(44100));
assert_eq!(audio.num_channels().get(), 1);
assert_eq!(audio.samples_per_channel().get(), 44100);
#[cfg(feature = "statistics")]
{
let peak = audio.peak();
assert!(peak > 0.9 && peak <= 1.0);
}
}
#[test]
#[cfg(feature = "random-generation")]
fn test_white_noise_generation() {
let audio =
white_noise::<f64>(Duration::from_secs_f32(1.0), sample_rate!(44100), 1.0, None);
assert_eq!(audio.sample_rate(), sample_rate!(44100));
assert_eq!(audio.num_channels().get(), 1);
assert_eq!(audio.samples_per_channel().get(), 44100);
let mono = audio.as_mono().unwrap();
let min_val = mono
.iter()
.min_by(|a, b| a.partial_cmp(b).unwrap())
.unwrap();
let max_val = mono
.iter()
.max_by(|a, b| a.partial_cmp(b).unwrap())
.unwrap();
assert!(max_val > min_val); }
#[test]
fn test_square_wave_generation() {
let audio = square_wave::<f64>(1.0, Duration::from_secs_f32(1.0), sample_rate!(10), 1.0);
assert_eq!(audio.sample_rate(), sample_rate!(10));
assert_eq!(audio.samples_per_channel().get(), 10);
let mono = audio.as_mono().unwrap();
for &sample in mono.iter() {
assert!(sample.abs() > 0.9); }
}
#[test]
fn test_impulse_generation() {
let audio = impulse::<f64>(Duration::from_secs_f32(1.0), sample_rate!(10), 1.0, 0.5);
assert_eq!(audio.sample_rate(), sample_rate!(10));
assert_eq!(audio.samples_per_channel().get(), 10);
let mono = audio.as_mono().unwrap();
let non_zero_count = mono.iter().filter(|&&x| x != 0.0).count();
assert_eq!(non_zero_count, 1);
assert_approx_eq!(mono[5].into(), 1.0, 1e-6);
assert!((mono[5] as f64 - 1.0).abs() < 1e-6);
}
#[test]
fn test_silence_generation() {
let audio = silence::<f64>(Duration::from_secs_f32(1.0), sample_rate!(44100));
assert_eq!(audio.sample_rate(), sample_rate!(44100));
assert_eq!(audio.samples_per_channel().get(), 44100);
let mono = audio.as_mono().unwrap();
for &sample in mono.iter() {
assert_eq!(sample, 0.0);
}
}
#[test]
fn test_chirp_generation() {
let audio = chirp::<f64>(
100.0,
1000.0,
Duration::from_secs_f32(1.0),
sample_rate!(44100),
1.0,
);
assert_eq!(audio.sample_rate(), sample_rate!(44100));
assert_eq!(audio.samples_per_channel().get(), 44100);
#[cfg(feature = "statistics")]
{
let peak = audio.peak();
assert!(peak > 0.9 && peak <= 1.0);
}
}
#[test]
fn test_compound_tone_generation() {
let components = [
ToneComponent::new(440.0, 1.0),
ToneComponent::new(880.0, 0.5),
ToneComponent::new(1320.0, 0.25),
];
let components = NonEmptySlice::from_slice(&components).unwrap();
let audio = compound_tone::<f64>(
&components,
Duration::from_secs_f32(1.0),
sample_rate!(44100),
);
assert_eq!(audio.sample_rate(), sample_rate!(44100));
assert_eq!(audio.samples_per_channel().get(), 44100);
assert_eq!(audio.num_channels().get(), 1);
let mono = audio.as_mono().unwrap();
let min_val = mono.iter().cloned().fold(f64::INFINITY, f64::min);
let max_val = mono.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
assert!(max_val > min_val);
}
#[test]
fn test_am_signal_generation() {
let audio = am_signal::<f64>(
440.0,
2.0,
0.5,
Duration::from_secs_f32(1.0),
sample_rate!(44100),
0.8,
);
assert_eq!(audio.sample_rate(), sample_rate!(44100));
assert_eq!(audio.samples_per_channel().get(), 44100);
assert_eq!(audio.num_channels().get(), 1);
#[cfg(feature = "statistics")]
{
let peak = audio.peak();
assert!(peak > 0.7 && peak <= 0.85, "Peak was {}", peak);
}
}
#[test]
#[cfg(feature = "random-generation")]
fn test_exponential_bursts_generation() {
let audio = exponential_bursts::<f64>(
2.0,
30.0,
Duration::from_secs_f32(1.0),
sample_rate!(44100),
0.8,
);
assert_eq!(audio.sample_rate(), sample_rate!(44100));
assert_eq!(audio.samples_per_channel().get(), 44100);
assert_eq!(audio.num_channels().get(), 1);
let mono = audio.as_mono().unwrap();
let min_val = mono.iter().cloned().fold(f64::INFINITY, f64::min);
let max_val = mono.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
assert!(max_val > min_val);
}
#[cfg(all(feature = "editing", feature = "channels"))]
#[test]
fn test_stereo_sine_wave_generation() {
let audio = stereo_sine_wave::<f64>(
440.0,
Duration::from_secs_f32(1.0),
sample_rate!(44100),
0.8,
);
assert_eq!(audio.sample_rate(), sample_rate!(44100));
assert_eq!(audio.samples_per_channel().get(), 44100);
assert_eq!(audio.num_channels().get(), 2);
let multi = audio.as_multi_channel().unwrap();
for s_idx in 0..audio.samples_per_channel().get() {
assert_eq!(multi[(0, s_idx)], multi[(1, s_idx)]);
}
}
#[cfg(all(feature = "editing", feature = "channels"))]
#[test]
fn test_multichannel_compound_tone_generation() {
let components = [
ToneComponent::new(440.0, 1.0),
ToneComponent::new(880.0, 0.5),
];
let components = NonEmptySlice::from_slice(&components).unwrap();
let audio = multichannel_compound_tone::<f64>(
&components,
Duration::from_secs_f32(0.1),
sample_rate!(44100),
6, );
assert_eq!(audio.sample_rate(), sample_rate!(44100));
assert_eq!(audio.num_channels().get(), 6);
let multi = audio.as_multi_channel().unwrap();
for s_idx in 0..audio.samples_per_channel().get() {
let first_val = multi[(0, s_idx)];
for ch_idx in 1..6 {
assert_eq!(multi[(ch_idx, s_idx)], first_val);
}
}
}
}