From: will Date: Fri, 18 Oct 2024 13:25:19 +0000 (+0100) Subject: Built dynamic ifft processor X-Git-Url: https://git.ozva.co.uk/?a=commitdiff_plain;ds=sidebyside;p=rust_fft Built dynamic ifft processor --- diff --git a/src/main.rs b/src/main.rs index 18efd08..d74aa90 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,8 +3,11 @@ use rustfft::{Fft, FftDirection}; use rustfft::num_complex::Complex; use show_image::{ImageView, ImageInfo, create_window}; use hound; -use cpal::{Sample, StreamConfig, BufferSize, SampleRate}; +use cpal::{StreamConfig, BufferSize, SampleRate}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; +use std::sync::{Arc, Mutex}; +use std::sync::mpsc; +use std::sync::mpsc::Sender; const WINDOW_SIZE: usize = 128; const CHUNK_SIZE: usize = 72; @@ -22,6 +25,12 @@ const VOLUME_MAX: f32 = 100.0; // 60 - 65 const VOLUME_MIN: f32 = -40.0; const VOLUME_REL: f32 = VOLUME_MAX - VOLUME_MIN; +// have 2 image arrays that are read from and process line by line when neccicary +// increece the buffer size of the audio output to make it work +// mutex counter for the row that is currently to process +// when it reaches the last row it locks both images and switches them over +// then sends a message to the main thread to process -> show -> capture a new image + struct ImageArray { data: [u8; SPECTOGRAM_AREA * 3], chunks: usize @@ -91,55 +100,126 @@ impl ImageArray { } } +struct SwitchSpace { + write_zone: Arc>>>, + read_zone: Arc>>>, + storage: [i16; WINDOW_SIZE*2], + inverse_transform: Radix4::, + scratch: Vec>, + counter: Arc>, + tx: Sender +} + +impl SwitchSpace { + fn new (write_zone: Arc>>>, tx: Sender) -> Self { + Self { + write_zone, + read_zone: Arc::new(Mutex::new(vec![Complex{re: 0f32, im: 0f32}; SPECTOGRAM_AREA])), + storage: [0i16; WINDOW_SIZE*2], + + inverse_transform: Radix4::::new(WINDOW_SIZE, FftDirection::Inverse), + + scratch: vec![ + Complex{re: 0f32, im: 0f32}; + Radix4::::new( + WINDOW_SIZE, + FftDirection::Inverse + ).get_inplace_scratch_len() + ], + + counter: Arc::new(Mutex::new(0usize)), + tx + } + } + + fn get_data(&mut self, data: &mut [i16], _: &cpal::OutputCallbackInfo) { + let mut counter = self.counter.lock().unwrap(); + + { + let mut read_chunk = self.read_zone.lock().unwrap(); + + self.inverse_transform.process_with_scratch(&mut read_chunk[*counter..*counter+WINDOW_SIZE], &mut self.scratch); + + println!("Writing {} data points...", data.len()); + for (i, x) in data.chunks_mut(2).enumerate() { + let value = read_chunk[*counter + i].re as i16; + for sample in x.iter_mut() { + *sample = value; + } + } + } + + if *counter == CHUNK_SIZE { + println!("Read space empty... Running switch..."); + let origional_write = self.write_zone.clone(); + self.write_zone = self.read_zone.clone(); + self.read_zone = origional_write.clone(); + + *counter = 0; + let _ = self.tx.send(true); + } else { + *counter += 1; + } + } +} + #[show_image::main] fn main () -> Result<(), Box> { - let forward_transform = Radix4::::new(WINDOW_SIZE, FftDirection::Forward); - let inverse_transform = Radix4::::new(WINDOW_SIZE, FftDirection::Inverse); let scratch_size = forward_transform.get_inplace_scratch_len(); - let mut image_array = ImageArray::new(); - let mut buffer = vec![Complex{re: 0f32, im: 0f32}; SPECTOGRAM_AREA]; + let write_space = Arc::new(Mutex::new(vec![Complex{re: 0f32, im: 0f32}; SPECTOGRAM_AREA])); let mut scratch = vec![Complex{re: 0f32, im: 0f32}; scratch_size]; + let (tx, rx) = mpsc::channel(); + let mut switch = SwitchSpace::new(write_space.clone(), tx); + + let mut image_array = ImageArray::new(); let window = create_window("image", Default::default())?; let host = cpal::default_host(); - let device = host.default_output_device().expect("no output device available"); - let error_function = |err| eprintln!("an error occurred on the output audio stream: {}", err); + let device = host.default_output_device().expect("No output device available"); let stream = device.build_output_stream( &StreamConfig{ - channels: 1, + channels: 2, sample_rate: SampleRate{0: 22_050}, - buffer_size: BufferSize::Default + buffer_size: BufferSize::Fixed(WINDOW_SIZE as u32) + }, + move |data: &mut [i16], info: &cpal::OutputCallbackInfo| { + switch.get_data(data, info); }, - get_samples, error_function, None + move |err| { + eprintln!("an error occurred on the output audio stream: {}", err); + }, + None ).unwrap(); - let mut get_samples = (data: &mut [T], _: &cpal::OutputCallbackInfo)|| { - - return; - } + stream.play().expect("Stream pay failed"); let mut reader = hound::WavReader::open("/home/will/Downloads/Adducci - Around the Horn.wav").unwrap(); let mut i = 0; for sample in reader.samples::() { + let mut buffer = write_space.lock().unwrap(); if i == SPECTOGRAM_AREA { - forward_transform.process_with_scratch(&mut buffer, &mut scratch); + + forward_transform.process_with_scratch(&mut *buffer, &mut scratch); for x in buffer.iter_mut() { *x *= 1f32 / WINDOW_SIZE as f32; } - image_array.from_buffer(&buffer); - - image_array.to_buffer(&mut buffer); - inverse_transform.process_with_scratch(&mut buffer, &mut scratch); + image_array.from_buffer(&*buffer); let image = ImageView::new(ImageInfo::rgb8(WINDOW_SIZE as u32, CHUNK_SIZE as u32), &image_array.data); window.set_image ("image", image)?; + image_array.to_buffer(&mut *buffer); + i = 0; + + println!("Waiting for signal..."); + if rx.recv().unwrap() {()} + println!("Signal recevied!"); } let value = match sample { Ok(t) => t, @@ -149,11 +229,6 @@ fn main () -> Result<(), Box> { i += 1; } - - // Create a window with default options and display the image. - - loop {} - Ok(()) }