Skip to main content

audio_lab/signal/fs/
npy.rs

1use crate::signal::{FreqSignal, SignalError, TimeSignal};
2
3#[derive(Debug, thiserror::Error)]
4pub enum NpyOrSignalError {
5    #[error(transparent)]
6    Npy(#[from] ndarray_npy::ReadNpyError),
7    #[error(transparent)]
8    Signal(#[from] SignalError),
9}
10
11pub fn read_npy_time(
12    path: impl AsRef<std::path::Path>,
13    sample_rate: f64,
14) -> Result<TimeSignal, NpyOrSignalError> {
15    let y_data = ndarray_npy::read_npy(path).map_err(NpyOrSignalError::Npy)?;
16    TimeSignal::new(y_data, sample_rate).map_err(NpyOrSignalError::Signal)
17}
18
19pub fn write_npy_time(
20    signal: &TimeSignal,
21    path: impl AsRef<std::path::Path>,
22) -> Result<(), ndarray_npy::WriteNpyError> {
23    ndarray_npy::write_npy(path, &signal.time_data().to_owned())
24}
25
26pub fn read_npy_freq(
27    path: impl AsRef<std::path::Path>,
28    sample_rate: f64,
29    num_time_steps: Option<usize>,
30) -> Result<FreqSignal, NpyOrSignalError> {
31    let y_data = ndarray_npy::read_npy(path).map_err(NpyOrSignalError::Npy)?;
32    FreqSignal::new(y_data, sample_rate, num_time_steps).map_err(NpyOrSignalError::Signal)
33}
34
35pub fn write_npy_freq(
36    signal: &FreqSignal,
37    path: impl AsRef<std::path::Path>,
38) -> Result<(), ndarray_npy::WriteNpyError> {
39    ndarray_npy::write_npy(path, &signal.freq_data().to_owned())
40}
41
42#[cfg(test)]
43mod tests {
44    use std::time::{SystemTime, UNIX_EPOCH};
45
46    use ndarray::arr2;
47    use num::complex::Complex64;
48
49    use super::*;
50
51    #[test]
52    fn writes_and_reads_time_signal_npy() {
53        let signal = TimeSignal::new(arr2(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]), 44_100.0).unwrap();
54        let path = std::env::temp_dir().join(format!(
55            "audio-lab-{}-{}.npy",
56            std::process::id(),
57            SystemTime::now()
58                .duration_since(UNIX_EPOCH)
59                .unwrap()
60                .as_nanos()
61        ));
62
63        write_npy_time(&signal, &path).unwrap();
64        let loaded = read_npy_time(&path, 44_100.0).unwrap();
65        std::fs::remove_file(&path).unwrap();
66
67        assert_eq!(loaded, signal);
68    }
69
70    #[test]
71    fn writes_and_reads_freq_signal_npy() {
72        let signal = FreqSignal::new(
73            arr2(&[
74                [Complex64::new(1.0, 2.0), Complex64::new(3.0, 4.0)],
75                [Complex64::new(5.0, 6.0), Complex64::new(7.0, 8.0)],
76            ]),
77            44_100.0,
78            Some(3),
79        )
80        .unwrap();
81        let path = std::env::temp_dir().join(format!(
82            "audio-lab-freq-{}-{}.npy",
83            std::process::id(),
84            SystemTime::now()
85                .duration_since(UNIX_EPOCH)
86                .unwrap()
87                .as_nanos()
88        ));
89
90        write_npy_freq(&signal, &path).unwrap();
91        let loaded = read_npy_freq(&path, 44_100.0, Some(3)).unwrap();
92        std::fs::remove_file(&path).unwrap();
93
94        assert_eq!(loaded, signal);
95    }
96}