fix view diff

This commit is contained in:
2025-04-10 13:59:42 +02:00
parent bc4c3d1fd3
commit 2ade4ef543
+76 -18
View File
@@ -1,23 +1,46 @@
use clap::Parser;
use ncurses::*;
use ncurses::{LcCategory, setlocale};
use rustfft::{algorithm::Radix4, num_complex::Complex, Fft, FftDirection};
use std::collections::VecDeque;
use std::collections::{VecDeque, HashMap};
use std::io::{stdin, Read};
use std::fs::File;
use std::time::{Duration, Instant};
use byteorder::{LittleEndian, ReadBytesExt};
use std::process::{Command, Stdio};
use std::thread::sleep;
// Create screen buffer struct to track cell states
// Each cell stores a character and its state (whether it's filled or not)
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
struct Cell {
character: String,
filled: bool,
}
// ViewDiff struct for efficient terminal updates
struct ViewDiff {
changes: HashMap<(usize, usize), String>,
}
impl ViewDiff {
fn new() -> Self {
ViewDiff {
changes: HashMap::new(),
}
}
fn add_change(&mut self, y: usize, x: usize, character: String) {
self.changes.insert((y, x), character);
}
fn apply(&self) {
for ((y, x), character) in &self.changes {
let _ = mvprintw(*y as i32, *x as i32, character);
}
}
}
// Function to handle terminal resizing
fn handle_terminal_resize(
rows: &mut i32,
@@ -99,7 +122,7 @@ fn main() {
let cli = Cli::parse();
// Initialize ncurses with proper locale for UTF-8 support
setlocale(LcCategory::all, ""); // Set locale before ncurses init for UTF-8 support
let _ = setlocale(LcCategory::all, ""); // Set locale before ncurses init for UTF-8 support
initscr();
noecho();
curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
@@ -114,14 +137,15 @@ fn main() {
let sample_rate: usize = 48000;
let bit_depth: usize = 16;
let num_channels: usize = 2; // Default to assume stereo for better handling
let samples_per_frame: usize = sample_rate / usize::from(cli.fps);
let fft_size: usize = 1024;
// Set up FFT processor
let fft = Radix4::new(fft_size, FftDirection::Forward);
// Set up audio input source
let mut input_buffer = vec![0; samples_per_frame * (bit_depth / 8)];
// Set up audio input source - account for num_channels in buffer size
let mut input_buffer = vec![0; samples_per_frame * num_channels * (bit_depth / 8)];
let mut complex_buffer = vec![Complex { re: 0.0, im: 0.0 }; fft_size];
// Set up input reader based on command line arguments
@@ -137,8 +161,9 @@ fn main() {
// Set up audio source
let mut audio_source = if cli.pipewire {
// Launch PipeWire capture process with raw output format
// Using stereo (2 channels) for consistent behavior with other input sources
let process = Command::new("pw-record")
.args(["--format=s16", "--rate=48000", "--channels=1", "--raw", "-"])
.args(["--format=s16", "--rate=48000", "--channels=2", "--raw", "-"])
.stdout(Stdio::piped())
.spawn()
.expect("Failed to start pw-record");
@@ -264,17 +289,31 @@ fn main() {
// Resize input buffer to match actual bytes read
let actual_input = &input_buffer[0..n];
// Convert raw bytes to audio samples
// Convert raw bytes to audio samples, handling multichannel input
let mut cursor = std::io::Cursor::new(actual_input);
// Read as many complete samples as possible
while cursor.position() < (n as u64 - 1) {
// Read as many complete sample frames as possible
while cursor.position() < (n as u64 - (num_channels * (bit_depth / 8)) as u64 + 1) {
let mut frame_sum = 0.0;
let mut valid_channels = 0;
// Read all channels and average them
for _ in 0..num_channels {
match cursor.read_i16::<LittleEndian>() {
Ok(sample) => all_samples.push(sample as f32 / 32768.0),
Ok(sample) => {
frame_sum += sample as f32;
valid_channels += 1;
},
Err(_) => break,
}
}
// Average the channels (if any valid channels were read)
if valid_channels > 0 {
all_samples.push((frame_sum / valid_channels as f32) / 32768.0);
}
}
// If we've collected enough samples, we can stop to avoid too much processing
if all_samples.len() >= fft_size * 2 {
break;
@@ -302,15 +341,21 @@ fn main() {
}
}
// Render only the changed cells - using safe dimensions
// Create a view diff for error display
let mut view_diff = ViewDiff::new();
// Record only the changed cells - using safe dimensions
for y in 0..safe_rows as usize {
for x in 0..safe_cols as usize {
if current_buffer[y][x] != next_buffer[y][x] {
let _ = mvprintw(y as i32, x as i32, &next_buffer[y][x].character);
view_diff.add_change(y, x, next_buffer[y][x].character.clone());
}
}
}
// Apply all changes in one batch operation
view_diff.apply();
// Swap buffers
std::mem::swap(&mut current_buffer, &mut next_buffer);
@@ -362,6 +407,7 @@ fn main() {
complex_buffer[i].re *= window;
}
// Process FFT using standard rustfft implementation (already optimized)
fft.process(&mut complex_buffer);
// Calculate frequency bands using our mapping - with safe dimensions
@@ -440,15 +486,21 @@ fn main() {
}
}
// Render only the cells that changed (diff and patch) - using safe dimensions
// Create a view diff for efficient terminal updates
let mut view_diff = ViewDiff::new();
// Record only the changed cells (diff and patch) - using safe dimensions
for y in 0..safe_rows as usize {
for x in 0..safe_cols as usize {
if current_buffer[y][x] != next_buffer[y][x] {
let _ = mvprintw(y as i32, x as i32, &next_buffer[y][x].character);
view_diff.add_change(y, x, next_buffer[y][x].character.clone());
}
}
}
// Apply changes efficiently in one batch
view_diff.apply();
// Swap buffers for next frame
std::mem::swap(&mut current_buffer, &mut next_buffer);
@@ -483,15 +535,21 @@ fn main() {
}
}
// Render only the cells that changed - using safe dimensions
// Create a view diff for efficient terminal updates
let mut view_diff = ViewDiff::new();
// Record only the changed cells - using safe dimensions
for y in 0..safe_rows as usize {
for x in 0..safe_cols as usize {
if current_buffer[y][x] != next_buffer[y][x] {
let _ = mvprintw(y as i32, x as i32, &next_buffer[y][x].character);
view_diff.add_change(y, x, next_buffer[y][x].character.clone());
}
}
}
// Apply all changes in one batch operation
view_diff.apply();
// Swap buffers
std::mem::swap(&mut current_buffer, &mut next_buffer);