rosa 0.1.0

Audio feature extraction library matching librosa output
Documentation
use crate::convert::frequency_weighting;
use crate::dsp::db::power_to_db;
use crate::matrix::Matrix;

/// Perceptual weighting of a power spectrogram.
///
/// Matches `librosa.perceptual_weighting`.
///
/// Computes: `result[f, t] = weight[f] + power_to_db(s[f, t])`
///
/// # Parameters
/// - `s`: Power spectrogram (rows = frequency bins, columns = time frames)
/// - `frequencies`: Center frequency for each row of `s`
/// - `kind`: Weighting curve (`"A"`, `"B"`, `"C"`, `"D"`, `"Z"`)
/// - `ref_val`: Reference power for `power_to_db`
/// - `amin`: Minimum amplitude threshold for `power_to_db`
/// - `top_db`: Threshold below peak for `power_to_db`
pub fn perceptual_weighting(
    s: &Matrix,
    frequencies: &[f64],
    kind: &str,
    ref_val: f64,
    amin: f64,
    top_db: Option<f64>,
) -> Matrix {
    let (rows, cols) = s.shape();
    assert_eq!(
        frequencies.len(),
        rows,
        "perceptual_weighting: frequencies length ({}) must match spectrogram rows ({})",
        frequencies.len(),
        rows
    );

    let weights = frequency_weighting(frequencies, kind, None)
        .expect("perceptual_weighting: invalid weighting kind");

    // Convert each row to dB, then add weight offset
    let mut result = Matrix::zeros(rows, cols);
    for r in 0..rows {
        // Extract row data
        let row_data: Vec<f64> = (0..cols).map(|c| s.get(r, c)).collect();
        let row_db = power_to_db(&row_data, ref_val, amin, top_db);
        for c in 0..cols {
            *result.get_mut(r, c) = weights[r] + row_db[c];
        }
    }

    result
}