pywavers 0.1.1

A mixed Rust and Python crate/package for reading and writing WAVE files. Exposes the Rust crate Wavers to Python.
Documentation
use std::path::Path;

use numpy::pyo3::Python;
use numpy::{Ix2, PyArray};
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use wavers::{
    signal_channels, signal_duration, signal_info, signal_sample_rate, write_wav_as, SampleType,
    SignalInfo, WavFile,
};

#[pyfunction]
pub fn _read_i16(py: Python, fp: String) -> PyResult<&PyArray<i16, Ix2>> {
    let wav_fp = Path::new(&fp);

    let wav = match WavFile::from_file(wav_fp) {
        Ok(wav) => wav,
        Err(e) => {
            return Err(PyValueError::new_err(format!(
                "Error opening wav file: {}",
                e
            )))
        }
    };

    let wav_arr = wav
        .read(Some(SampleType::I16(0 as i16)))
        .mapv(|sample| sample.to_i16());
    Ok(PyArray::from_array(py, &wav_arr))
}

#[pyfunction]
pub fn _read_i32(py: Python, fp: String) -> PyResult<&PyArray<i32, Ix2>> {
    let wav_fp = Path::new(&fp);

    let wav = match WavFile::from_file(wav_fp) {
        Ok(wav) => wav,
        Err(e) => {
            return Err(PyValueError::new_err(format!(
                "Error opening wav file: {}",
                e
            )))
        }
    };

    let wav_arr = wav
        .read(Some(SampleType::I32(0 as i32)))
        .mapv(|sample| sample.to_i32());
    Ok(PyArray::from_array(py, &wav_arr))
}

#[pyfunction]
pub fn _read_f32(py: Python, fp: String) -> PyResult<&PyArray<f32, Ix2>> {
    let wav_fp = Path::new(&fp);

    let wav = match WavFile::from_file(wav_fp) {
        Ok(wav) => wav,
        Err(e) => {
            return Err(PyValueError::new_err(format!(
                "Error opening wav file: {}",
                e
            )))
        }
    };

    let wav_arr = wav
        .read(Some(SampleType::F32(0.0 as f32)))
        .mapv(|sample| sample.to_f32());
    Ok(PyArray::from_array(py, &wav_arr))
}

#[pyfunction]
pub fn _read_f64(py: Python, fp: String) -> PyResult<&PyArray<f64, Ix2>> {
    let wav_fp = Path::new(&fp);

    let wav = match WavFile::from_file(wav_fp) {
        Ok(wav) => wav,
        Err(e) => {
            return Err(PyValueError::new_err(format!(
                "Error opening wav file: {}",
                e
            )))
        }
    };

    let wav_arr = wav
        .read(Some(SampleType::F64(0.0 as f64)))
        .mapv(|sample| sample.to_f64());
    Ok(PyArray::from_array(py, &wav_arr))
}

#[pyfunction]
pub fn _write_wav_i16(
    out_fp: String,
    signal: &PyArray<i16, Ix2>,
    sample_rate: i32,
) -> PyResult<()> {
    let signal = unsafe { signal.as_array() };
    let signal = signal.mapv(|sample| SampleType::I16(sample));
    write_wav_as(Path::new(&out_fp), &signal, None, sample_rate)
        .map_err(|e| PyValueError::new_err(format!("Error writing wav file: {}", e)))
}

#[pyfunction]
pub fn _write_wav_i32(
    out_fp: String,
    signal: &PyArray<i32, Ix2>,
    sample_rate: i32,
) -> PyResult<()> {
    let signal = unsafe { signal.as_array() };
    let signal = signal.mapv(|sample| SampleType::I32(sample));
    write_wav_as(Path::new(&out_fp), &signal, None, sample_rate)
        .map_err(|e| PyValueError::new_err(format!("Error writing wav file: {}", e)))
}

#[pyfunction]
pub fn _write_wav_f32(
    out_fp: String,
    signal: &PyArray<f32, Ix2>,
    sample_rate: i32,
) -> PyResult<()> {
    let signal = unsafe { signal.as_array() };
    let signal = signal.mapv(|sample| SampleType::F32(sample));
    write_wav_as(Path::new(&out_fp), &signal, None, sample_rate)
        .map_err(|e| PyValueError::new_err(format!("Error writing wav file: {}", e)))
}

#[pyfunction]
pub fn _write_wav_f64(
    out_fp: String,
    signal: &PyArray<f64, Ix2>,
    sample_rate: i32,
) -> PyResult<()> {
    let signal = unsafe { signal.as_array() };
    let signal = signal.mapv(|sample| SampleType::F64(sample));
    write_wav_as(Path::new(&out_fp), &signal, None, sample_rate)
        .map_err(|e| PyValueError::new_err(format!("Error writing wav file: {}", e)))
}

#[pyfunction]
pub fn _signal_duration(fp: String) -> PyResult<u64> {
    signal_duration(Path::new(&fp)).map_err(|e| {
        PyValueError::new_err(format!(
            "Error reading wav file when getting signal duration: {}",
            e
        ))
    })
}

#[pyfunction]
pub fn _signal_channels(fp: String) -> PyResult<u16> {
    signal_channels(Path::new(&fp)).map_err(|e| {
        PyValueError::new_err(format!(
            "Error reading wav file when getting signal channels: {}",
            e
        ))
    })
}

#[pyfunction]
pub fn _signal_sample_rate(fp: String) -> PyResult<i32> {
    signal_sample_rate(Path::new(&fp)).map_err(|e| {
        PyValueError::new_err(format!(
            "Error reading wav file when getting signal sample rate: {}",
            e
        ))
    })
}

#[pyfunction]
pub fn _signal_info(fp: String) -> PyResult<SignalInfo> {
    signal_info(Path::new(&fp)).map_err(|e| {
        PyValueError::new_err(format!(
            "Error reading wav file when getting signal info: {}",
            e
        ))
    })
}

#[pymodule]
fn pywavers(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<SignalInfo>()?;

    m.add_function(wrap_pyfunction!(_read_i16, m)?)?;
    m.add_function(wrap_pyfunction!(_read_i32, m)?)?;
    m.add_function(wrap_pyfunction!(_read_f32, m)?)?;
    m.add_function(wrap_pyfunction!(_read_f64, m)?)?;

    m.add_function(wrap_pyfunction!(_write_wav_i16, m)?)?;
    m.add_function(wrap_pyfunction!(_write_wav_i32, m)?)?;
    m.add_function(wrap_pyfunction!(_write_wav_f32, m)?)?;
    m.add_function(wrap_pyfunction!(_write_wav_f64, m)?)?;

    m.add_function(wrap_pyfunction!(_signal_duration, m)?)?;
    m.add_function(wrap_pyfunction!(_signal_channels, m)?)?;
    m.add_function(wrap_pyfunction!(_signal_sample_rate, m)?)?;
    m.add_function(wrap_pyfunction!(_signal_info, m)?)?;

    Ok(())
}