From c0bfc66ca50506251fa0e2e6cd98132281d35f81 Mon Sep 17 00:00:00 2001 From: Otto Date: Wed, 18 Jan 2023 21:04:49 +0100 Subject: [PATCH] Change AnalyserNode API, take mutable reference for time/freq data It requires some unsafe magic but it does make the API a lot nicer. --- examples/mic_playback.rs | 10 ++----- src/node/analyser.rs | 60 ++++++++++++++++++++++++++++------------ 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/examples/mic_playback.rs b/examples/mic_playback.rs index c53deca6..f5c2efde 100644 --- a/examples/mic_playback.rs +++ b/examples/mic_playback.rs @@ -229,7 +229,7 @@ fn poll_frequency_graph( height: u16, ) -> ! { let bin_count = analyser.frequency_bin_count(); - let mut freq_buffer = Some(vec![0.; bin_count]); + let mut freq_buffer = vec![0.; bin_count]; loop { // 5 frames per second @@ -237,10 +237,9 @@ fn poll_frequency_graph( // todo, check BaseAudioContext.state if it is still running - let tmp_buf = freq_buffer.take().unwrap(); - let tmp_buf = analyser.get_float_frequency_data(tmp_buf); + analyser.get_float_frequency_data(&mut freq_buffer); - let points: Vec<_> = tmp_buf + let points: Vec<_> = freq_buffer .iter() .enumerate() .map(|(i, &f)| (i as f32, f)) @@ -259,9 +258,6 @@ fn poll_frequency_graph( let event = UiEvent::GraphUpdate(plot); let _ = plot_send.send(event); // allowed to fail if the main thread is shutting down - - // restore Vec - freq_buffer = Some(tmp_buf); } } diff --git a/src/node/analyser.rs b/src/node/analyser.rs index 93448b60..ca6a825a 100644 --- a/src/node/analyser.rs +++ b/src/node/analyser.rs @@ -41,12 +41,12 @@ impl Default for AnalyserOptions { enum AnalyserRequest { FloatTime { - sender: Sender>, - buffer: Vec, + send_done_signal: Sender<()>, + buffer: &'static mut [f32], }, FloatFrequency { - sender: Sender>, - buffer: Vec, + send_done_signal: Sender<()>, + buffer: &'static mut [f32], }, } @@ -137,21 +137,39 @@ impl AnalyserNode { /// Copies the current time domain data (waveform data) into the provided buffer // we can fix this panic cf issue #101 #[allow(clippy::missing_panics_doc)] - pub fn get_float_time_domain_data(&self, buffer: Vec) -> Vec { - let (sender, receiver) = crossbeam_channel::bounded(0); - let request = AnalyserRequest::FloatTime { sender, buffer }; + pub fn get_float_time_domain_data(&self, buffer: &mut [f32]) { + // SAFETY: + // We transmute to a static reference so we can ship it to the render thread. + // The render thread will only write to the reference, and will send back a signal when it + // is done writing. This function will block until the signal is received. + let buffer: &'static mut [f32] = unsafe { std::mem::transmute(buffer) }; + + let (send_done_signal, recv_done_signal) = crossbeam_channel::bounded(0); + let request = AnalyserRequest::FloatTime { + send_done_signal, + buffer, + }; self.sender.send(request).unwrap(); - receiver.recv().unwrap() + recv_done_signal.recv().unwrap() } /// Copies the current frequency data into the provided buffer // we can fix this panic cf issue #101 #[allow(clippy::missing_panics_doc)] - pub fn get_float_frequency_data(&self, buffer: Vec) -> Vec { - let (sender, receiver) = crossbeam_channel::bounded(0); - let request = AnalyserRequest::FloatFrequency { sender, buffer }; + pub fn get_float_frequency_data(&self, buffer: &mut [f32]) { + // SAFETY: + // We transmute to a static reference so we can ship it to the render thread. + // The render thread will only write to the reference, and will send back a signal when it + // is done writing. This function will block until the signal is received. + let buffer: &'static mut [f32] = unsafe { std::mem::transmute(buffer) }; + + let (send_done_signal, recv_done_signal) = crossbeam_channel::bounded(0); + let request = AnalyserRequest::FloatFrequency { + send_done_signal, + buffer, + }; self.sender.send(request).unwrap(); - receiver.recv().unwrap() + recv_done_signal.recv().unwrap() } } @@ -202,17 +220,23 @@ impl AudioProcessor for AnalyserRenderer { // check if any information was requested from the control thread if let Ok(request) = self.receiver.try_recv() { match request { - AnalyserRequest::FloatTime { sender, mut buffer } => { - self.analyser.get_float_time(&mut buffer[..], fft_size); + AnalyserRequest::FloatTime { + send_done_signal: sender, + buffer, + } => { + self.analyser.get_float_time(buffer, fft_size); // allow to fail when receiver is disconnected - let _ = sender.send(buffer); + let _ = sender.send(()); } - AnalyserRequest::FloatFrequency { sender, mut buffer } => { - self.analyser.get_float_frequency(&mut buffer[..]); + AnalyserRequest::FloatFrequency { + send_done_signal: sender, + buffer, + } => { + self.analyser.get_float_frequency(buffer); // allow to fail when receiver is disconnected - let _ = sender.send(buffer); + let _ = sender.send(()); } } }