stft-rs 0.6.0

Simple, streaming-friendly, no_std compliant STFT implementation with mel spectrogram support
Documentation
use stft_rs::prelude::*;

fn main() {
    let config = StftConfig::<f32>::default_4096();

    println!("STFT Configuration:");
    println!("  FFT size: {}", config.fft_size);
    println!("  Hop size: {}", config.hop_size);
    println!("  Overlap: {:.1}%", config.overlap_percent());
    println!("  Frequency bins: {}", config.freq_bins());
    println!("  Reconstruction: {:?}", config.reconstruction_mode);
    println!();

    let stft = BatchStft::new(config.clone());
    let istft = BatchIstft::new(config);

    let sample_rate = 44100;
    let duration_secs = 1.0;
    let num_samples = (sample_rate as f32 * duration_secs) as usize;

    let audio: Vec<f32> = (0..num_samples)
        .map(|i| {
            let t = i as f32 / sample_rate as f32;
            0.3 * (2.0 * std::f32::consts::PI * 440.0 * t).sin()
                + 0.2 * (2.0 * std::f32::consts::PI * 880.0 * t).sin()
                + 0.1 * (2.0 * std::f32::consts::PI * 1320.0 * t).sin()
        })
        .collect();

    println!(
        "Processing {} samples ({:.2} seconds)",
        num_samples, duration_secs
    );

    let spectrum = stft.process(&audio);
    println!(
        "STFT result: {} frames x {} frequency bins",
        spectrum.num_frames, spectrum.freq_bins
    );
    let mut magnitudes: Vec<(usize, f32)> = (0..spectrum.freq_bins)
        .map(|bin| {
            let c = spectrum.get_complex(0, bin);
            let mag = (c.re * c.re + c.im * c.im).sqrt();
            (bin, mag)
        })
        .collect();

    magnitudes.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());

    println!("\nTop 5 frequency components:");
    let freq_resolution = sample_rate as f32 / 4096.0;
    for i in 0..5 {
        let (bin, mag) = magnitudes[i];
        let freq = bin as f32 * freq_resolution;
        println!("  Bin {}: {:.1} Hz (magnitude: {:.2})", bin, freq, mag);
    }

    let reconstructed = istft.process(&spectrum);
    println!("\nReconstructed {} samples", reconstructed.len());
    let min_len = audio.len().min(reconstructed.len());
    let mse: f32 = audio[..min_len]
        .iter()
        .zip(reconstructed[..min_len].iter())
        .map(|(a, b)| (a - b).powi(2))
        .sum::<f32>()
        / min_len as f32;

    let signal_power: f32 =
        audio[..min_len].iter().map(|x| x.powi(2)).sum::<f32>() / min_len as f32;
    let snr = 10.0 * (signal_power / mse).log10();

    println!("MSE: {:.2e}", mse);
    println!("SNR: {:.2} dB", snr);
}