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;
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
}
}
+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,
i += 1;
}
-
- // Create a window with default options and display the image.
-
- loop {}
-
Ok(())
}