rosa 0.1.0

Audio feature extraction library matching librosa output
Documentation
//! Zero-crossing rate matching `librosa.feature.zero_crossing_rate`.

use crate::matrix::FrameIter;

/// Compute zero-crossing rate per frame.
///
/// Matches `librosa.feature.zero_crossing_rate(y, frame_length, hop_length, center)`.
/// Returns the fraction of zero crossings in each frame.
///
/// Note: Uses edge-padding (not zero-padding) when `center=true`,
/// matching librosa's `pad_mode="edge"` for ZCR.
pub fn zero_crossing_rate(
    y: &[f64],
    frame_length: usize,
    hop_length: usize,
    center: bool,
) -> Vec<f64> {
    let padded: Vec<f64>;
    let signal = if center {
        // librosa uses pad_mode="edge" for ZCR (not "constant")
        let pad = frame_length / 2;
        let first = y.first().copied().unwrap_or(0.0);
        let last = y.last().copied().unwrap_or(0.0);
        padded = std::iter::repeat_n(first, pad)
            .chain(y.iter().copied())
            .chain(std::iter::repeat_n(last, pad))
            .collect();
        &padded
    } else {
        y
    };

    let frames = FrameIter::new(signal, frame_length, hop_length);
    frames
        .map(|frame| {
            let crossings = crate::audio::zero_crossings(frame, 1e-10, false, true);
            let count = crossings.iter().filter(|&&c| c).count();
            count as f64 / frame.len() as f64
        })
        .collect()
}