tests: reverb

This commit is contained in:
Vasilii Milovidov
2023-10-02 21:53:08 +04:00
parent 870e7e4f32
commit 18a198df9b
4 changed files with 132 additions and 23 deletions
+10
View File
@@ -970,6 +970,16 @@ const generic_params = [
*
*/
[['room', 'size']],
/**
* Sets the sample to use as an impulse response for the reverb.
*
* @name iresponse
* @param {string | Pattern} sample sample to set as the impulse response
* @example
* s("bd sd").room(.8).ir("<shaker_large:0 shaker_large:2>")
*
*/
[['ir', 'i'], 'iresponse'],
/**
* Sets the room size of the reverb, see {@link room}.
*
+47 -13
View File
@@ -39,7 +39,9 @@ export const desktopAudio = async (value, deadline, hapDuration) => {
delaytime,
orbit = 1,
room,
size = 2,
size,
ir,
i = 0,
velocity = 1,
analyze, // analyser wet
fft = 8, // fftSize 0 - 10
@@ -133,19 +135,37 @@ export const desktopAudio = async (value, deadline, hapDuration) => {
delaytime = Math.abs(delaytime);
}
const packages = {
loop: [loop, loopBegin, loopEnd],
delay: [delay, delaytime, delayfeedback],
lpf: [cutoff, resonance],
hpf: [hcutoff, hresonance],
bpf: [bandf, bandq],
adsr: [attack, decay, sustain, release],
lpenv: [lpattack, lpdecay, lpsustain, lprelease, lpenv],
hpenv: [hpattack, hpdecay, hpsustain, hprelease, hpenv],
bpenv: [bpattack, bpdecay, bpsustain, bprelease, bpenv],
};
let ir_path;
if (getSound(ir).data.baseUrl !== undefined) {
baseUrl = getSound(ir).data.baseUrl;
if (baseUrl === './piano/') {
ir_path = 'https://strudel.tidalcycles.org/';
} else if (baseUrl === './EmuSP12/') {
ir_path = 'https://strudel.tidalcycles.org/';
} else {
ir_path = '';
}
}
let url;
if (ir !== undefined) {
let ir_samples = getSound(ir);
if (Array.isArray(ir_samples)) {
url =
ir_path !== undefined
? ir_path + ir_samples[n % ir_samples.length].replace('./', '')
: ir_samples[n % ir_samples.length].replace('./', '');
// url = ir_samples.data.samples[i % ir_samples.data.samples.length];
} else if (typeof ir_samples === 'object') {
url =
ir_path !== undefined
? ir_path +
Object.values(ir_samples.data.samples)[i & Object.values(ir_samples.data.samples).length].replace('./', '')
: Object.values(ir_samples.data.samples)[i & Object.values(ir_samples.data.samples).length].replace('./', '');
}
}
console.log('url', url);
console.log('unit', unit);
let folder;
if (baseUrl !== undefined) {
folder = baseUrl.replace('./', '') + '/' + s + '/';
@@ -156,6 +176,19 @@ export const desktopAudio = async (value, deadline, hapDuration) => {
const offset = (t - getAudioContext().currentTime) * 1000;
const roundedOffset = Math.round(offset);
const messagesfromjs = [];
const packages = {
loop: [loop, loopBegin, loopEnd],
delay: [delay, delaytime, delayfeedback],
reverb: [room, size, ir, url],
lpf: [cutoff, resonance],
hpf: [hcutoff, hresonance],
bpf: [bandf, bandq],
adsr: [attack, decay, sustain, release],
lpenv: [lpattack, lpdecay, lpsustain, lprelease, lpenv],
hpenv: [hpattack, hpdecay, hpsustain, hprelease, hpenv],
bpenv: [bpattack, bpdecay, bpsustain, bprelease, bpenv],
};
messagesfromjs.push({
note: midiToFreq(note),
offset: roundedOffset,
@@ -166,6 +199,7 @@ export const desktopAudio = async (value, deadline, hapDuration) => {
duration: hapDuration,
velocity: velocity,
delay: packages.delay,
reverb: packages.reverb,
orbit: orbit,
speed: speed,
begin: begin,
+8
View File
@@ -16,6 +16,14 @@ pub struct DelayMessage {
pub feedback: Option<f32>,
}
#[derive(Clone, Debug)]
pub struct ReverbMessage {
pub room: Option<f32>,
pub size: Option<f32>,
pub ir: Option<String>,
pub url: Option<String>,
}
#[derive(Clone, Copy, Debug)]
pub struct LoopMessage {
pub is_loop: u8,
+67 -10
View File
@@ -20,8 +20,8 @@ use web_audio_api::{
context::{AudioContext, AudioContextLatencyCategory, AudioContextOptions},
node::AudioNode,
};
use web_audio_api::node::DelayNode;
use crate::superdough::{ADSRMessage, apply_filter_adsr, BPFMessage, DelayMessage, Delay, EffectsBus, FilterADSRMessage, HPFMessage, LoopMessage, LPFMessage, make_delay, Sampler, Synth, WebAudioInstrument};
use web_audio_api::node::{ConvolverNode, DelayNode};
use crate::superdough::{ADSRMessage, apply_filter_adsr, BPFMessage, DelayMessage, Delay, FilterADSRMessage, HPFMessage, LoopMessage, LPFMessage, Sampler, Synth, WebAudioInstrument, ReverbMessage};
#[derive(Debug, Clone)]
@@ -36,6 +36,7 @@ pub struct WebAudioMessage {
pub duration: f64,
pub velocity: f32,
pub delay: DelayMessage,
pub reverb: ReverbMessage,
pub orbit: usize,
pub speed: f32,
pub begin: f64,
@@ -119,7 +120,8 @@ pub fn init(
..AudioContextOptions::default()
});
let _ = audio_context.create_buffer_source();
let mut delays:HashMap<usize, Delay> = HashMap::new();
let mut delays: HashMap<usize, Delay> = HashMap::new();
let mut reverbs: HashMap<usize, ConvolverNode> = HashMap::new();
let compressor = audio_context.create_dynamics_compressor();
compressor.threshold().set_value(-50.0);
compressor.connect(&audio_context.destination());
@@ -158,13 +160,7 @@ pub fn init(
}
}
_ => {
let url = Url::parse(&*message.sampleurl).expect("failed to parse url");
let filename = url.path_segments()
.and_then(Iterator::last)
.and_then(|name| if name.is_empty() { None } else { Some(name) })
.unwrap_or("tmp.ben");
let file_path = format!("samples/{}{}", message.dirname, filename);
let file_path_clone = file_path.clone();
let (url, file_path, file_path_clone) = create_filepath(&message);
tokio::spawn(async move {
if tokio::fs::metadata(&file_path.clone()).await.is_err() {
@@ -210,6 +206,38 @@ pub fn init(
delay.feedback.gain().set_value(message.delay.feedback.unwrap_or(0.5));
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);
};
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"));
}
});
if let Some(ir_buffer) = cache.get(&ir_file_path_clone) {
reverbs.entry(message.orbit).or_insert({
let mut reverb = audio_context.create_convolver();
reverb.set_buffer(ir_buffer.clone());
reverb
});
let reverb = reverbs.get(&message.orbit).unwrap();
sampler.envelope.connect(reverb);
} else if let Ok(file) = File::open(&ir_file_path_clone) {
let ir_buffer = audio_context.decode_audio_data_sync(file).unwrap_or_else(|_| panic!("Failed to decode audio data"));
cache.insert(ir_file_path_clone.clone(), ir_buffer);
}
}
sampler.envelope.connect(&compressor);
sampler.play(t, &message, audio_buffer_duration);
} else if let Ok(file) = File::open(&file_path_clone) {
@@ -226,6 +254,28 @@ pub fn init(
});
}
fn create_filepath(message: &WebAudioMessage) -> (Url, String, String) {
let url = Url::parse(&*message.sampleurl).expect("failed to parse url");
let filename = url.path_segments()
.and_then(Iterator::last)
.and_then(|name| if name.is_empty() { None } else { Some(name) })
.unwrap_or("tmp.ben");
let file_path = format!("/Users/vasiliymilovidov/samples/{}{}", message.dirname, filename);
let file_path_clone = file_path.clone();
(url, file_path, file_path_clone)
}
fn create_ir_filepath(message: &WebAudioMessage) -> (Url, String, String) {
let url = Url::parse(&message.reverb.url.clone().unwrap()).expect("failed to parse url");
let filename = url.path_segments()
.and_then(Iterator::last)
.and_then(|name| if name.is_empty() { None } else { Some(name) })
.unwrap_or("tmp.ben");
let file_path = format!("/Users/vasiliymilovidov/samples/{}", filename);
let file_path_clone = file_path.clone();
(url, file_path, file_path_clone)
}
pub async fn async_process_model(
mut input_receiver: mpsc::Receiver<Vec<WebAudioMessage>>,
output_transmitter: mpsc::Sender<Vec<WebAudioMessage>>,
@@ -248,6 +298,7 @@ pub struct MessageFromJS {
duration: f64,
velocity: f32,
delay: (Option<f32>, Option<f32>, Option<f32>),
reverb: (Option<f32>, Option<f32>, Option<String>, Option<String>),
orbit: usize,
speed: f32,
begin: f64,
@@ -298,6 +349,12 @@ pub async fn sendwebaudio(
delay_time: m.delay.1,
feedback: m.delay.2,
},
reverb: ReverbMessage {
room: m.reverb.0,
size: m.reverb.1,
ir: m.reverb.2,
url: m.reverb.3,
},
orbit: m.orbit,
speed: m.speed,
begin: m.begin,