From 56d992def940eff9497a5c0be7eaef76b84143ac Mon Sep 17 00:00:00 2001 From: Vasilii Milovidov Date: Tue, 3 Oct 2023 14:20:35 +0400 Subject: [PATCH] tests: reverb --- src-tauri/src/main.rs | 1 + src-tauri/src/reverbgen.rs | 22 +++++++++++ src-tauri/src/superdough.rs | 20 ++++++++-- src-tauri/src/webaudiobridge.rs | 67 ++++++++++++++++++++++++++++----- 4 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 src-tauri/src/reverbgen.rs diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 3b44915e7..040db4db3 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -6,6 +6,7 @@ mod oscbridge; mod loggerbridge; mod webaudiobridge; mod superdough; +mod reverbgen; use std::sync::Arc; diff --git a/src-tauri/src/reverbgen.rs b/src-tauri/src/reverbgen.rs new file mode 100644 index 000000000..557463ed8 --- /dev/null +++ b/src-tauri/src/reverbgen.rs @@ -0,0 +1,22 @@ +use web_audio_api::AudioBuffer; +use web_audio_api::context::{AudioContext, BaseAudioContext}; + +pub fn generate_reverb(context: &AudioContext) { + let sample_rate = 44100.0; + let num_channels = 2.0; + let total_time = 2.0 * 1.5; + let decay_samples = (2.0_f64 * sample_rate).round() as usize; + let num_samples = (total_time * sample_rate).round() as usize; + let fade_samples = 0.0; + let decay_base = (1.0_f64 / 1000.0_f64).powf(1.0 / decay_samples as f64) as f32; + let mut reverb_ir = context.create_buffer(2, num_samples, 44100.0); + + for i in 0..num_channels as usize { + let mut chan = reverb_ir.get_channel_data_mut(i); + for j in 0..num_samples { + chan[j] = -0.3 * decay_base.powf(j as f32); + } + } + println!("{:?}", reverb_ir); +} + diff --git a/src-tauri/src/superdough.rs b/src-tauri/src/superdough.rs index 0fbd511f3..2022975e0 100644 --- a/src-tauri/src/superdough.rs +++ b/src-tauri/src/superdough.rs @@ -7,6 +7,7 @@ use web_audio_api::{ node::BiquadFilterType::{Bandpass, Highpass, Lowpass}, }; use web_audio_api::node::{ConvolverNode, DelayNode, DynamicsCompressorNode}; +use crate::reverbgen::generate_reverb; use crate::webaudiobridge::WebAudioMessage; #[derive(Clone, Copy, Debug)] @@ -106,15 +107,26 @@ pub struct Reverb { } impl Reverb { - pub fn new(context: &AudioContext, compressor: &DynamicsCompressorNode, room: f32, size: f32) -> Self { + pub fn new(context: &AudioContext, compressor: &DynamicsCompressorNode, room: f32, size: f32, buffer: AudioBuffer) -> Self { + let new_length = buffer.sample_rate() * size; + let mut new_buffer = context.create_buffer(buffer.number_of_channels(), buffer.length(), buffer.sample_rate()); + + for ch in 0..buffer.number_of_channels() { + let old_data = buffer.get_channel_data(ch); + let new_data = new_buffer.get_channel_data_mut(ch); + + for i in 0..new_length as usize { + new_data[i] = old_data[i]; + } + } + let reverb = context.create_convolver(); reverb.connect(compressor); + Self { reverb, room, size } } - pub fn asign_buffer(&mut self, buffer: AudioBuffer) { - self.reverb.set_buffer(buffer.clone()); - } + } pub struct Synth { diff --git a/src-tauri/src/webaudiobridge.rs b/src-tauri/src/webaudiobridge.rs index fd3ce6721..47432797c 100644 --- a/src-tauri/src/webaudiobridge.rs +++ b/src-tauri/src/webaudiobridge.rs @@ -126,17 +126,18 @@ pub fn init( let compressor = audio_context.create_dynamics_compressor(); compressor.threshold().set_value(-50.0); compressor.connect(&audio_context.destination()); - let mut reverb = ConvolverNode::new(&audio_context, ConvolverOptions::default()); - let impulse_file1 = File::open("/Users/vasiliymilovidov/samples/ir1.wav").unwrap(); - let impulse_buffer1 = audio_context.decode_audio_data_sync(impulse_file1).unwrap(); - reverb.set_buffer(impulse_buffer1); - reverb.connect(&audio_context.destination()); + // let mut reverb = ConvolverNode::new(&audio_context, ConvolverOptions::default()); + // let impulse_file1 = File::open("/Users/vasiliymilovidov/samples/ir1.wav").unwrap(); + // let impulse_buffer1 = audio_context.decode_audio_data_sync(impulse_file1).unwrap(); + // reverb.set_buffer(impulse_buffer1); + // reverb.connect(&audio_context.destination()); let cache: Cache = Cache::builder() .max_capacity(31 * 1024 * 1024) .time_to_idle(Duration::from_secs(40)) .build(); + let ir_cache: Cache = Cache::builder().max_capacity(31 * 1024 * 1024).build(); loop { match receiver.recv() { Ok(message) => { @@ -226,12 +227,60 @@ pub fn init( delay.pre_gain.gain().set_value_at_time(message.delay.wet.unwrap_or(0.25), t + message.delay.delay_time.unwrap_or(0.5) as f64); }; + // REVERB + if message.reverb.ir.is_some() { + let (ir_url, ir_file_path, ir_file_path_clone) = create_ir_filepath(&message); + + tokio::spawn(async move { + if tokio::fs::metadata(&ir_file_path.clone()).await.is_err() { + let response = reqwest::get(ir_url) + .await + .unwrap_or_else(|_| panic!("Failed to send GET request")); + + let bytes = response.bytes().await.unwrap(); + let path = Path::new(&ir_file_path); + let mut file = create_file_and_dirs(path).await; + file.write_all(&bytes) + .await + .unwrap_or_else(|_| panic!("Failed to write to file")); + } + }); + + let requested_size = message.reverb.size.unwrap_or(2.0).clone(); + if let Some(ir_buffer) = ir_cache.get(&ir_file_path_clone) { + let t = audio_context.current_time(); + let ir_buffer_duration = ir_buffer.duration(); + let mut reverb = audio_context.create_convolver(); + reverb.set_buffer(ir_buffer); + reverb.connect(&compressor); + sampler.envelope.connect(&reverb); + } else if let Ok(file) = File::open(&ir_file_path_clone) { + let ir_cache_clone = ir_cache.clone(); + tokio::spawn(async move { + let context = OfflineAudioContext::new(2, 400, 44100.0); + let ir_buffer = context.decode_audio_data_sync(file).expect("IR OOOOPS"); + let new_length = ir_buffer.sample_rate() * requested_size; + let mut new_buffer = context.create_buffer(ir_buffer.number_of_channels(), new_length as usize, ir_buffer.sample_rate()); + for ch in 0..ir_buffer.number_of_channels() { + let old_data = ir_buffer.get_channel_data(ch); + let new_data = new_buffer.get_channel_data_mut(ch); + + for i in 0..new_length as usize { + if i < old_data.len() { + new_data[i] = old_data[i]; + } else { + new_data[i] = 0.0; + } + } + } + ir_cache_clone.insert(ir_file_path_clone.clone(), new_buffer); + }); + } + } - // sampler.envelope.connect(&reverb); - // CONNECT SAMPLER TO OUTPUT AND PLAY sampler.envelope.connect(&compressor); - sampler.play(t, &message, audio_buffer_duration); - sampler.envelope.connect(&reverb); + sampler.play(t, &message, message.adsr.release.unwrap_or(0.001)); + // CONNECT SAMPLER TO OUTPUT AND PLAY // IF FILE EXIST - DECODE IT } else if let Ok(file) = File::open(&file_path_clone) { let cache_clone = cache.clone();