Remove unsused variable

Added bytemuck for faster pcm decoding
refactor spectrometer
This commit is contained in:
JorySeverijnse 2026-01-18 19:52:25 +01:00
parent e3ff11d8a8
commit 837be94e1c
4 changed files with 30 additions and 30 deletions

1
Cargo.lock generated
View File

@ -704,6 +704,7 @@ name = "oscilloscope-video-gen"
version = "1.0.0"
dependencies = [
"anyhow",
"bytemuck",
"clap",
"hound",
"image",

View File

@ -31,6 +31,9 @@ anyhow = "1.0"
# FFT processing for spectrometer
rustfft = "6.1"
# Efficient byte casting
bytemuck = "1.24"
[profile.release]
opt-level = 3
lto = true

View File

@ -3,6 +3,7 @@
//! Handles reading and decoding WAV files into normalized sample data.
use anyhow::{anyhow, Context, Result};
use bytemuck;
use std::path::Path;
/// Normalized audio sample data.
@ -49,12 +50,11 @@ impl AudioData {
let mut left_channel = Vec::with_capacity(total_samples);
let mut right_channel = Vec::with_capacity(total_samples);
for i in 0..total_samples {
let offset = i * 2 * num_channels;
let left_val = i16::from_le_bytes([pcm_data[offset], pcm_data[offset + 1]]);
let right_val = i16::from_le_bytes([pcm_data[offset + 2], pcm_data[offset + 3]]);
// Convert PCM data to f32 samples efficiently
let samples: &[i16] = bytemuck::cast_slice(&pcm_data);
for chunk in samples.chunks_exact(num_channels) {
let left_val = chunk[0];
let right_val = chunk[1];
left_channel.push(left_val as f32 / 32768.0);
right_channel.push(right_val as f32 / 32768.0);
}

View File

@ -78,12 +78,7 @@ pub fn draw_line(
fn draw_graticule(
buffer: &mut ImageBuffer<image::Rgb<u8>, Vec<u8>>,
primary_color: image::Rgb<u8>,
show_grid: bool,
) {
if !show_grid {
return;
}
let (width, height) = buffer.dimensions();
for x in 0..width {
@ -108,7 +103,7 @@ pub fn parse_rgb_hex(hex: &str) -> Result<image::Rgb<u8>> {
}
/// Compute frequency spectrum from audio samples using FFT.
fn compute_spectrum(audio_data: &AudioData, start_sample: usize, window_size: usize) -> Vec<f32> {
fn compute_spectrum(audio_data: &AudioData, start_sample: usize) -> Vec<f32> {
// Use a larger FFT size for better frequency resolution, especially in the bass
let fft_size = 2048;
let mut planner = FftPlanner::new();
@ -159,19 +154,23 @@ fn draw_spectrometer(
color: image::Rgb<u8>,
sample_rate: u32,
) {
let spacing = 1;
let bar_width = (width - (num_bars as u32 - 1) * spacing) / num_bars as u32;
// Constants for logarithmic frequency mapping
const MIN_FREQ: f32 = 20.0;
const MAX_FREQ: f32 = 20000.0;
const FREQ_BOOST_FACTOR: f32 = 5.0;
const DYNAMIC_RANGE_SCALE: f32 = 20.0;
const NOISE_FLOOR: f32 = 0.05;
const BAR_SPACING: u32 = 1;
let bar_width = (width - (num_bars as u32 - 1) * BAR_SPACING) / num_bars as u32;
let bar_width = bar_width.max(1);
// Logarithmic mapping parameters
let min_freq = 20.0f32;
let max_freq = 20000.0f32;
let nyquist = sample_rate as f32 / 2.0;
for i in 0..num_bars {
// Calculate frequency range for this bar (logarithmic)
let f_start = min_freq * (max_freq / min_freq).powf(i as f32 / num_bars as f32);
let f_end = min_freq * (max_freq / min_freq).powf((i + 1) as f32 / num_bars as f32);
let f_start = MIN_FREQ * (MAX_FREQ / MIN_FREQ).powf(i as f32 / num_bars as f32);
let f_end = MIN_FREQ * (MAX_FREQ / MIN_FREQ).powf((i + 1) as f32 / num_bars as f32);
// Map frequencies to FFT bin indices
let bin_start = (f_start / nyquist * spectrum.len() as f32) as usize;
@ -185,18 +184,17 @@ fn draw_spectrometer(
}
// Apply frequency-dependent boost (higher frequencies are naturally quieter)
// Boost highs by adding a linear factor based on frequency
let freq_factor = 1.0 + (f_start / max_freq) * 5.0;
let freq_factor = 1.0 + (f_start / MAX_FREQ) * FREQ_BOOST_FACTOR;
let mut val = magnitude * freq_factor;
// Dynamic range compression/scaling
val = (val * 20.0).sqrt().min(1.0);
val = (val * DYNAMIC_RANGE_SCALE).sqrt().min(1.0);
// Noise floor
if val < 0.05 { val = 0.0; }
if val < NOISE_FLOOR { val = 0.0; }
let bar_height = (val * height as f32) as u32;
let x = x_offset + i as u32 * (bar_width + spacing);
let x = x_offset + i as u32 * (bar_width + BAR_SPACING);
for y in 0..bar_height {
let pixel_y = y_offset + height - 1 - y;
@ -226,7 +224,7 @@ pub fn draw_frame(
}
if options.show_grid {
draw_graticule(&mut buffer, options.left_color, true);
draw_graticule(&mut buffer, options.left_color);
}
let end_sample = std::cmp::min(start_sample + samples_per_frame, audio_data.left_channel.len());
@ -362,8 +360,7 @@ pub fn draw_frame(
let spec_x_offset = half_width;
let spec_y_offset = half_height;
let window_size = 1024.min(samples_per_frame);
let spectrum = compute_spectrum(audio_data, start_sample, window_size);
let spectrum = compute_spectrum(audio_data, start_sample);
draw_spectrometer(
&mut buffer,
@ -386,8 +383,7 @@ pub fn draw_frame(
}
}
RenderMode::Spectrometer => {
let window_size = 1024.min(samples_per_frame);
let spectrum = compute_spectrum(audio_data, start_sample, window_size);
let spectrum = compute_spectrum(audio_data, start_sample);
draw_spectrometer(
&mut buffer,