#[cfg(not(all(feature = "plotting", feature = "statistics")))]
fn main() {
eprintln!("error: This example requires the `plotting` and `statistics` features.");
std::process::exit(1);
}
#[cfg(all(feature = "plotting", feature = "statistics"))]
fn assert_plot_html<P: audio_samples::operations::PlotUtils>(
plot: &P,
name: &str,
) -> audio_samples::AudioSampleResult<()> {
let html = plot.html()?;
assert!(
!html.is_empty() && html.contains("plotly"),
"{name} spectral-overlay HTML should be a non-empty Plotly document"
);
println!("Rendered {name} spectral overlay ({} bytes)", html.len());
Ok(())
}
#[cfg(all(feature = "plotting", feature = "statistics"))]
fn main() -> audio_samples::AudioSampleResult<()> {
use audio_samples::operations::AudioPlotting;
use audio_samples::operations::plotting::dsp_overlays;
use audio_samples::operations::plotting::spectrograms::SpectrogramPlotParams;
use audio_samples::{AudioSamples, chirp, sample_rate};
use std::time::Duration;
println!("=== Spectral Overlays Example ===\n");
let audio: AudioSamples<'_, f32> = chirp::<f32>(
200.0, 2000.0, Duration::from_secs_f32(4.0), sample_rate!(44100),
0.5, );
println!("Generated chirp signal: 200 Hz → 2000 Hz sweep over 4 seconds");
let window_size = audio_samples::nzu!(2048); let hop_size = audio_samples::nzu!(512);
println!("\nSpectral analysis parameters:");
println!(
" Window size: {} samples (~{:.1}ms)",
window_size,
window_size.get() as f64 / 44100.0 * 1000.0
);
println!(
" Hop size: {} samples (~{:.1}ms)",
hop_size,
hop_size.get() as f64 / 44100.0 * 1000.0
);
println!("\n--- Spectral Centroid Overlay ---");
let (centroid_times, centroid_values) =
dsp_overlays::compute_windowed_spectral_centroid(&audio.borrow(), window_size, hop_size);
println!(
"Computed spectral centroid for {} windows",
centroid_times.len()
);
println!(
"Centroid range: {:.0} Hz to {:.0} Hz",
centroid_values
.iter()
.cloned()
.fold(f64::INFINITY, f64::min),
centroid_values
.iter()
.cloned()
.fold(f64::NEG_INFINITY, f64::max)
);
let spectrogram_plot = audio
.plot_spectrogram(&SpectrogramPlotParams::mel_db())?
.add_spectral_centroid(centroid_times.clone(), centroid_values.clone(), None);
assert_plot_html(&spectrogram_plot, "centroid")?;
println!(" White line with cyan markers = Spectral Centroid");
println!("\n--- Spectral Rolloff Overlay ---");
let rolloff_percent = 0.85; let (rolloff_times, rolloff_values) = dsp_overlays::compute_windowed_spectral_rolloff(
&audio.borrow(),
window_size,
hop_size,
rolloff_percent,
);
println!(
"Computed spectral rolloff ({}%) for {} windows",
(rolloff_percent * 100.0) as u32,
rolloff_times.len()
);
println!(
"Rolloff range: {:.0} Hz to {:.0} Hz",
rolloff_values.iter().cloned().fold(f64::INFINITY, f64::min),
rolloff_values
.iter()
.cloned()
.fold(f64::NEG_INFINITY, f64::max)
);
let rolloff_plot = audio
.plot_spectrogram(&SpectrogramPlotParams::mel_db())?
.add_spectral_rolloff(rolloff_times.clone(), rolloff_values.clone(), None);
assert_plot_html(&rolloff_plot, "rolloff")?;
println!(" White line with cyan markers = Spectral Rolloff (85%)");
println!("\n--- Combined Spectral Features ---");
let combined_plot = audio
.plot_spectrogram(&SpectrogramPlotParams::mel_db())?
.add_spectral_centroid(centroid_times, centroid_values.clone(), Some("Centroid"))
.add_spectral_rolloff(rolloff_times, rolloff_values, Some("Rolloff 85%"));
assert_plot_html(&combined_plot, "combined")?;
println!(" Shows both Centroid and Rolloff tracks with legend");
println!("\n--- Multiple Rolloff Percentages ---");
let (rolloff_50_times, rolloff_50_values) = dsp_overlays::compute_windowed_spectral_rolloff(
&audio.borrow(),
window_size,
hop_size,
0.50,
);
let (rolloff_85_times, rolloff_85_values) = dsp_overlays::compute_windowed_spectral_rolloff(
&audio.borrow(),
window_size,
hop_size,
0.85,
);
let (rolloff_95_times, rolloff_95_values) = dsp_overlays::compute_windowed_spectral_rolloff(
&audio.borrow(),
window_size,
hop_size,
0.95,
);
let comparison_plot = audio
.plot_spectrogram(&SpectrogramPlotParams::mel_db())?
.add_spectral_rolloff(rolloff_50_times, rolloff_50_values, Some("Rolloff 50%"))
.add_spectral_rolloff(rolloff_85_times, rolloff_85_values, Some("Rolloff 85%"))
.add_spectral_rolloff(rolloff_95_times, rolloff_95_values, Some("Rolloff 95%"));
assert_plot_html(&comparison_plot, "rolloff_comparison")?;
assert!(
centroid_values.len() >= 2,
"expected multiple centroid windows for a 4 s chirp"
);
assert!(
centroid_values.last().unwrap() > centroid_values.first().unwrap(),
"spectral centroid should rise across an ascending chirp: {} !> {}",
centroid_values.last().unwrap(),
centroid_values.first().unwrap()
);
Ok(())
}