#![allow(unused)]
use hound::{SampleFormat, WavSpec};
use itertools::Itertools;
use std::f64::consts::PI;
use std::fs;
use std::path::{Path, PathBuf};
use std::vec::Vec;
pub fn read_wav_to_mono<T: AsRef<Path>>(file: T) -> (Vec<i16>, WavSpec) {
let mut reader = hound::WavReader::open(file).unwrap();
let header = reader.spec();
let data = reader
.samples::<i16>()
.map(|s| s.unwrap())
.collect::<Vec<_>>();
if header.channels == 1 {
(data, header)
} else if header.channels == 2 {
let data = data
.into_iter()
.chunks(2)
.into_iter()
.map(|mut lr| {
let l = lr.next().unwrap();
let r = lr
.next()
.expect("should have an even number of LRLR samples");
stereo_to_mono(l, r)
})
.collect::<Vec<_>>();
(data, header)
} else {
panic!("unsupported format!");
}
}
pub fn write_wav_file(path: &Path, samples: &[i16], sample_rate: u32) {
let mut wav_writer = hound::WavWriter::create(
path,
WavSpec {
channels: 1,
sample_rate,
bits_per_sample: 16,
sample_format: SampleFormat::Int,
},
)
.unwrap();
for &sample in samples {
wav_writer.write_sample(sample).unwrap()
}
wav_writer.finalize().unwrap();
}
#[inline]
#[must_use]
pub const fn stereo_to_mono(l: i16, r: i16) -> i16 {
let l = l as i32;
let r = r as i32;
let avg = (l + r) / 2;
avg as i16
}
#[inline]
pub fn i16_sample_to_f32(val: i16) -> f32 {
if val == i16::MIN {
-1.0
} else {
val as f32 / i16::MAX as f32
}
}
#[inline]
pub fn f32_sample_to_i16(val: f32) -> i16 {
if val.is_finite() && val.abs() <= 1.0 {
(val * i16::MAX as f32) as i16
} else {
panic!("invalid f32");
}
}
pub fn target_dir() -> PathBuf {
std::env::var("CARGO_TARGET_DIR").map_or_else(
|_| {
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
manifest_dir.join("target")
},
PathBuf::from,
)
}
pub fn target_dir_test_artifacts() -> PathBuf {
let mut path = target_dir();
path.push("test_generated");
if !fs::exists(&path).unwrap() {
fs::create_dir(&path).unwrap();
}
path
}
pub fn sine_wave(fr: f64) -> impl Fn(f64) -> f64 {
move |time| (2.0 * PI * fr * time).sin()
}
pub fn sine_wave_samples(fr: f64, sampling_rate: f64) -> Vec<f64> {
let sine_wave = sine_wave(fr);
(0..(2 * sampling_rate as usize))
.map(|x| x as f64)
.map(|t| t / sampling_rate)
.map(sine_wave)
.collect::<Vec<_>>()
}
pub fn calculate_power(samples: &[f64]) -> f64 {
samples
.iter()
.copied()
.map(|x| x / i16::MAX as f64)
.map(|x| x * x)
.fold(0.0, |acc, val| acc + val)
}