+use cpal::{StreamConfig, InputCallbackInfo, OutputCallbackInfo};
+use cpal::traits::{HostTrait, DeviceTrait, StreamTrait};
+use std::sync::{Arc, Mutex};
+use std::sync::mpsc;
+use std::sync::mpsc::{Sender, Receiver};
+use rustfft::num_complex::Complex;
+use std::thread;
+use std::thread::sleep;
+use std::time::Duration;
+use hound::{ WavWriter, WavSpec, SampleFormat};
+
+use crate::SPECTOGRAM_AREA;
+
+const DUMMY_READ_DELAY: u64 = 1; // seconds
+const DUMMY_SAMPLE_SIZE: usize = 10;
+
+const DEFAULT_SAMPLE_RATE: u32 = 48_000;
+
+struct InputBuffer {
+ buffer: Arc<Mutex<[i16; SPECTOGRAM_AREA]>>
+}
+
+impl InputBuffer {
+ fn new(buffer: Arc<Mutex<[i16; SPECTOGRAM_AREA]>>) -> Self {
+ Self {
+ buffer
+ }
+ }
+
+ fn get_data(&mut self, data: &mut [i16]) {
+ let buffer = self.buffer.lock().unwrap();
+ for (i, point) in data.iter_mut().enumerate() {
+ *point = buffer[i];
+ }
+ }
+
+ fn give_data(&mut self, data: &mut [i16]) {
+ let mut buffer = self.buffer.lock().unwrap();
+ let length = data.len()/2;
+
+ for (i, x) in (length..SPECTOGRAM_AREA).enumerate() {
+ buffer[i] = buffer[x];
+ }
+
+ for (i, x) in (SPECTOGRAM_AREA-length..SPECTOGRAM_AREA).enumerate() {
+ buffer[x] = data[i];
+ }
+ }
+}
+
+struct OutputBuffer {
+ buffer: Arc<Mutex<[i16; 2 * SPECTOGRAM_AREA]>>,
+ index: usize,
+ tx: Sender<bool>,
+ rx: Receiver<bool>,
+}
+
+impl OutputBuffer {
+ fn new(buffer: Arc<Mutex<[i16; 2 * SPECTOGRAM_AREA]>>) -> Self {
+ let (tx, rx) = mpsc::channel();
+ Self {
+ buffer,
+ index: 0,
+ tx,
+ rx
+ }
+ }
+
+ fn get_data(&mut self, data: &mut [i16]) {
+ let mut buffer = self.buffer.lock().unwrap();
+ let length = data.len()/2;
+
+ for i in 0..length {
+ data[i*2] = buffer[i + self.index];
+ }
+
+ self.index += length;
+ if self.index > SPECTOGRAM_AREA {
+ for i in 0..SPECTOGRAM_AREA {
+ buffer[i] = buffer[i + SPECTOGRAM_AREA];
+ }
+ self.index -= SPECTOGRAM_AREA;
+
+ let _ = self.tx.send(true);
+ }
+ }
+
+ fn give_data(&mut self, data: &[Complex<f32>]) {
+ if self.rx.recv().unwrap() {
+ let mut buffer = self.buffer.lock().unwrap();
+ for (i, x) in buffer[SPECTOGRAM_AREA..].iter_mut().enumerate() {
+ *x = data[i].re as i16;
+ }
+ }
+ }
+}
+
+enum Location {
+ Physical(StreamConfig),
+ File(String),
+ None
+}
+
+pub struct SoundObject {
+ callback: fn(&mut [i16]),
+ input_buffer: InputBuffer,
+ output_buffer: OutputBuffer
+}
+
+impl SoundObject {
+ fn new(input: Location, output: Location) -> Self {
+ let input_buffer_space = Arc::new(Mutex::new([0i16; SPECTOGRAM_AREA]));
+ let input_buffer = InputBuffer::new(input_buffer_space.clone());
+ let thread_input_buffer = InputBuffer::new(input_buffer_space);
+
+ let output_buffer_space = Arc::new(Mutex::new([0i16; 2 * SPECTOGRAM_AREA]));
+ let output_buffer = OutputBuffer::new(output_buffer_space.clone());
+ let thread_output_buffer = OutputBuffer::new(output_buffer_space);
+
+ let (sample_rate, callback):(u32, Box<dyn Fn(&mut [i16])>) = match input {
+ Location::Physical(config) => {
+ let host = cpal::default_host();
+ let device = host.default_input_device().expect("No input device available");
+ let stream = device.build_input_stream(
+ &config,
+ move | data: &mut [i16], _: &InputCallbackInfo | {
+ thread_input_buffer.give_data(data);
+ },
+ move | err | {
+ eprintln!("an error occurred on the input audio stream: {}", err);
+ },
+ None
+ ).unwrap();
+ stream.play().expect("Output stream play failed");
+
+ let callback = Box::new(| data: &mut [i16] | {
+ input_buffer.get_data(data);
+ });
+ (DEFAULT_SAMPLE_RATE, callback)
+ },
+ Location::File(string) => {
+ let mut reader = hound::WavReader::open(string).unwrap();
+ let sample_rate = reader.spec().sample_rate;
+ let mut samples = reader.samples();
+ let callback = Box::new(| data: &mut [i16] | {
+ for sample in data.iter_mut() {
+ *sample = match samples.next() {
+ Some(x) => x.unwrap(),
+ None => {
+ samples = reader.samples();
+ 0
+ }
+ } as i16
+ }
+ });
+ (sample_rate, callback)
+ },
+ Location::None => {
+ let callback = Box::new(| data: &mut [i16] | {
+ for point in data.iter_mut() {
+ *point = 0i16;
+ }
+ });
+ (DEFAULT_SAMPLE_RATE, callback)
+
+ }
+ };
+
+ match output {
+ Location::Physical(config) => {
+ let host = cpal::default_host();
+ let device = host.default_output_device().expect("No output device available");
+ let stream = device.build_output_stream(
+ &config,
+ move |data: &mut [i16], _: &OutputCallbackInfo| {
+ thread_output_buffer.get_data(data);
+ },
+ move |err| {
+ eprintln!("an error occurred on the output audio stream: {}", err);
+ },
+ None
+ ).unwrap();
+ stream.play().expect("Output stream play failed");
+ },
+ Location::File(path) => {
+ let mut writer = WavWriter::create(path, WavSpec{
+ channels: 1,
+ sample_rate,
+ bits_per_sample: 16,
+ sample_format: SampleFormat::Int
+ }).unwrap();
+ let write_delay = DUMMY_SAMPLE_SIZE as f32 / sample_rate as f32;
+ let _ = thread::spawn(move || {
+ let mut data = [0i16; DUMMY_SAMPLE_SIZE];
+ loop {
+ thread_output_buffer.get_data(&mut data[..]);
+ for i in 0..DUMMY_SAMPLE_SIZE {
+ writer.write_sample(data[i]).unwrap();
+ }
+ sleep(Duration::from_secs_f32(write_delay));
+ }
+ });
+ },
+ Location::None => {
+ let mut data = [0i16; DUMMY_SAMPLE_SIZE];
+ let write_delay = DUMMY_SAMPLE_SIZE as f32 / sample_rate as f32;
+ let _ = thread::spawn(move || {
+ loop {
+ thread_output_buffer.get_data(&mut data[..]);
+ sleep(Duration::from_secs_f32(write_delay));
+ }
+ });
+ }
+ }
+
+ Self {
+ callback,
+ input_buffer,
+ output_buffer
+ }
+ }
+}
+
+