]> OzVa Git service - rust_fft/commitdiff
Built dynamic ifft processor
authorwill <greenwoodw50@gmail.com>
Fri, 18 Oct 2024 13:25:19 +0000 (14:25 +0100)
committerwill <greenwoodw50@gmail.com>
Fri, 18 Oct 2024 13:25:19 +0000 (14:25 +0100)
src/main.rs

index 18efd08ea159daaf41caee29a9e45b2564a3c309..d74aa90768c66c9c388271cd2c7c2ad907fdbb0e 100644 (file)
@@ -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<Mutex<Vec<Complex<f32>>>>,
+       read_zone: Arc<Mutex<Vec<Complex<f32>>>>,
+       storage: [i16; WINDOW_SIZE*2],
+       inverse_transform: Radix4::<f32>,
+       scratch: Vec<Complex<f32>>,
+       counter: Arc<Mutex<usize>>,
+       tx: Sender<bool>
+}
+
+impl SwitchSpace {
+       fn new (write_zone: Arc<Mutex<Vec<Complex<f32>>>>, tx: Sender<bool>) -> 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::<f32>::new(WINDOW_SIZE, FftDirection::Inverse),
+
+                       scratch: vec![
+                               Complex{re: 0f32, im: 0f32};
+                               Radix4::<f32>::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<dyn std::error::Error>> {
 
-
        let forward_transform = Radix4::<f32>::new(WINDOW_SIZE, FftDirection::Forward);
-       let inverse_transform = Radix4::<f32>::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::<i16>() {
+               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<dyn std::error::Error>> {
                i += 1;
        }
 
-
-       // Create a window with default options and display the image.
-
-       loop {}
-
        Ok(())
 
 }