use stft_rs::prelude::*;
fn main() {
println!("Advanced Streaming with Buffer Reuse\n");
let config = StftConfig::<f32>::default_4096();
println!("Configuration:");
println!(
" FFT: {} | Hop: {} | Overlap: {:.1}%\n",
config.fft_size,
config.hop_size,
config.overlap_percent()
);
let mut stft = StreamingStft::new(config.clone());
let mut istft = StreamingIstft::new(config.clone());
let mut spectrum_frames = Vec::new();
let mut output_samples = Vec::new();
let mut final_output = Vec::new();
let sample_rate = 44100;
let duration = 2.0;
let num_samples = (sample_rate as f32 * duration) as usize;
let signal: Vec<f32> = (0..num_samples)
.map(|i| {
let t = i as f32 / sample_rate as f32;
let freq = 440.0 + 200.0 * t; 0.5 * (2.0 * std::f32::consts::PI * freq * t).sin()
})
.collect();
println!("Processing {} samples in chunks...", num_samples);
let pad_amount = config.fft_size / 2;
let padded = apply_padding(&signal, pad_amount, PadMode::Reflect);
let chunk_size = 512;
let mut total_frames = 0;
let mut chunks_processed = 0;
for chunk in padded.chunks(chunk_size) {
spectrum_frames.clear();
output_samples.clear();
let frames_written = stft.push_samples_into(chunk, &mut spectrum_frames);
total_frames += frames_written;
for frame in &spectrum_frames {
istft.push_frame_into(frame, &mut output_samples);
}
final_output.extend_from_slice(&output_samples);
chunks_processed += 1;
}
let remaining_frames = stft.flush();
for frame in remaining_frames {
output_samples.clear();
istft.push_frame_into(&frame, &mut output_samples);
final_output.extend_from_slice(&output_samples);
}
let flush_output = istft.flush();
final_output.extend_from_slice(&flush_output);
println!(" Processed {} chunks", chunks_processed);
println!(" Generated {} STFT frames", total_frames);
println!(" Output: {} samples\n", final_output.len());
let start = pad_amount.min(final_output.len());
let end = (start + signal.len()).min(final_output.len());
let reconstructed = &final_output[start..end];
let min_len = signal.len().min(reconstructed.len());
let signal_power: f32 = signal[..min_len].iter().map(|x| x.powi(2)).sum();
let noise_power: f32 = signal[..min_len]
.iter()
.zip(reconstructed[..min_len].iter())
.map(|(a, b)| (a - b).powi(2))
.sum();
let snr = if noise_power > 0.0 {
10.0 * (signal_power / noise_power).log10()
} else {
f32::INFINITY
};
println!("Reconstruction Quality:");
println!(" Compared {} samples", min_len);
println!(" SNR: {:.2} dB", snr);
println!("\nAdvantages of buffer reuse:");
println!(" - Reduced allocator pressure");
println!(" - Better cache locality");
println!(" - More predictable performance");
println!(" - Lower latency variance (important for real-time)");
}