mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-21 20:55:12 -04:00
adsr tests
This commit is contained in:
+48
-27
@@ -78,38 +78,21 @@ pub fn superdough(message: &WebAudioMessage, context: &mut AudioContext) {
|
||||
}
|
||||
|
||||
if message.delay.wet > 0.0 {
|
||||
let output = context.create_gain();
|
||||
output.connect(&context.destination());
|
||||
|
||||
let delay = delays.get(message.orbit).unwrap();
|
||||
delay.delay_time().set_value(message.delay.delay_time);
|
||||
delay.connect(&output);
|
||||
|
||||
let feedback = context.create_gain();
|
||||
feedback.gain().set_value(message.delay.feedback);
|
||||
feedback.connect(delay);
|
||||
delay.connect(&feedback);
|
||||
|
||||
let pre_gain = context.create_gain();
|
||||
pre_gain.gain().set_value(message.delay.wet);
|
||||
pre_gain.connect(&feedback);
|
||||
|
||||
let input = context.create_gain();
|
||||
input.connect(&pre_gain);
|
||||
input.connect(&context.destination()); // direct sound
|
||||
env.connect(&input);
|
||||
create_delay(message, &context, &env, &mut delays, now);
|
||||
}
|
||||
|
||||
let (sustain, velocity, release) = (message.adsr.sustain, message.velocity, message.adsr.release);
|
||||
// Connect nodes and play synth
|
||||
connect_nodes(chain, context);
|
||||
let osc= play_synth(&message, now, osc, filters, &env);
|
||||
let osc = play_synth(&message, now, osc, filters, &env);
|
||||
|
||||
osc.set_onended(move |_| {
|
||||
for d in &delays {
|
||||
// env.gain().set_value_at_time(velocity * sustain, now);
|
||||
// env.gain().exponential_ramp_to_value_at_time(0.0001, now + release);
|
||||
d.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
_ => {
|
||||
match File::open(format!("samples/{}/{}.wav", message.bank, message.waveform)) {
|
||||
@@ -128,10 +111,23 @@ pub fn superdough(message: &WebAudioMessage, context: &mut AudioContext) {
|
||||
let env = context.create_gain();
|
||||
chain.push(&env);
|
||||
|
||||
let mut delays = Vec::new();
|
||||
for _ in 0..=message.orbit {
|
||||
delays.push(context.create_delay(1.));
|
||||
}
|
||||
|
||||
if message.delay.wet > 0.0 {
|
||||
create_delay(message, &context, &env, &mut delays, now);
|
||||
}
|
||||
// Connect nodes and play sample
|
||||
connect_nodes(chain, context);
|
||||
src.playback_rate().set_value(message.speed);
|
||||
play_sample(message, now, audio_buffer_duration, src, filters, &env);
|
||||
let src = play_sample(message, now, audio_buffer_duration, src, filters, &env);
|
||||
src.set_onended(move |_| {
|
||||
for d in &delays {
|
||||
d.disconnect();
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(e) => eprintln!("Failed to open file: {:?}", e),
|
||||
}
|
||||
@@ -139,6 +135,30 @@ pub fn superdough(message: &WebAudioMessage, context: &mut AudioContext) {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_delay(message: &WebAudioMessage, context: &&mut AudioContext, env: &GainNode, delays: &mut Vec<DelayNode>, now: f64) {
|
||||
|
||||
let output = context.create_gain();
|
||||
output.connect(&context.destination());
|
||||
|
||||
let delay = delays.get(message.orbit).unwrap();
|
||||
delay.delay_time().set_value(message.delay.delay_time);
|
||||
delay.connect(&output);
|
||||
|
||||
let feedback = context.create_gain();
|
||||
feedback.gain().set_value(message.delay.feedback);
|
||||
feedback.connect(delay);
|
||||
delay.connect(&feedback);
|
||||
|
||||
let pre_gain = context.create_gain();
|
||||
// pre_gain.gain().set_value_at_time(0.0, now);
|
||||
pre_gain.gain().set_value_at_time(message.delay.wet, now + message.delay.delay_time as f64);
|
||||
pre_gain.connect(&feedback);
|
||||
|
||||
let input = context.create_gain();
|
||||
input.connect(&pre_gain);
|
||||
env.connect(&input);
|
||||
}
|
||||
|
||||
fn play_synth(message: &&WebAudioMessage, now: f64, osc: OscillatorNode, filters: Vec<BiquadFilterNode>, env: &GainNode) -> OscillatorNode {
|
||||
osc.set_type(create_osc_type(&message));
|
||||
osc.frequency().set_value(message.note);
|
||||
@@ -165,7 +185,7 @@ fn create_osc_type(message: &WebAudioMessage) -> OscillatorType {
|
||||
}
|
||||
}
|
||||
|
||||
fn play_sample(message: &WebAudioMessage, now: f64, audio_buffer_duration: f64, src: AudioBufferSourceNode, filters: Vec<BiquadFilterNode>, env: &GainNode) {
|
||||
fn play_sample(message: &WebAudioMessage, now: f64, audio_buffer_duration: f64, src: AudioBufferSourceNode, filters: Vec<BiquadFilterNode>, env: &GainNode) -> AudioBufferSourceNode {
|
||||
let (start_at, stop_at) = if message.speed < 0.0 {
|
||||
(audio_buffer_duration, now + message.duration + 0.2)
|
||||
} else {
|
||||
@@ -201,6 +221,7 @@ fn play_sample(message: &WebAudioMessage, now: f64, audio_buffer_duration: f64,
|
||||
};
|
||||
src.stop_at(stop_at);
|
||||
}
|
||||
src
|
||||
}
|
||||
|
||||
fn create_filters(context: &mut AudioContext, message: &WebAudioMessage) -> Vec<BiquadFilterNode> {
|
||||
@@ -288,8 +309,8 @@ fn apply_adsr(
|
||||
sustain * message.velocity,
|
||||
now + attack + decay,
|
||||
)
|
||||
.set_value_at_time(sustain * message.velocity, now + attack + decay)
|
||||
.linear_ramp_to_value_at_time(0.0, now + attack + decay + release);
|
||||
.set_value_at_time(sustain * message.velocity, message.duration)
|
||||
.linear_ramp_to_value_at_time(0.001, message.duration + release);
|
||||
}
|
||||
|
||||
fn apply_synth_adsr(envelope: &GainNode, message: &WebAudioMessage, now: f64) {
|
||||
@@ -321,7 +342,7 @@ fn apply_drum_adsr(envelope: &GainNode, message: &WebAudioMessage, now: f64) {
|
||||
}
|
||||
|
||||
fn apply_default_drum_adsr(envelope: &GainNode, message: &WebAudioMessage, now: f64) {
|
||||
apply_adsr(envelope, message, now, 0.001, message.velocity, 0.05, 0.001);
|
||||
apply_adsr(envelope, message, now, 0.001, message.velocity, 0.5, 0.5);
|
||||
}
|
||||
|
||||
fn connect_nodes<'a>(nodes: Vec<&'a (dyn AudioNode + 'a)>, context: &'a mut AudioContext) -> Vec<&'a (dyn AudioNode)> {
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::{
|
||||
time::Duration,
|
||||
thread::sleep
|
||||
};
|
||||
|
||||
use tokio::{
|
||||
sync::{mpsc, Mutex},
|
||||
time::Instant
|
||||
@@ -12,10 +13,9 @@ use web_audio_api::{
|
||||
context::{AudioContext, AudioContextLatencyCategory, AudioContextOptions},
|
||||
node::AudioNode
|
||||
};
|
||||
use web_audio_api::context::BaseAudioContext;
|
||||
use crate::superdough::{ADSR, BPF, Delay, FilterADSR, HPF, Loop, LPF, superdough};
|
||||
|
||||
|
||||
const BLOCK_SIZE: usize = 128;
|
||||
#[derive(Debug)]
|
||||
pub struct WebAudioMessage {
|
||||
pub note: f32,
|
||||
@@ -56,6 +56,8 @@ pub fn init(
|
||||
............................................................*/
|
||||
let message_queue_clone = Arc::clone(&message_queue);
|
||||
tauri::async_runtime::spawn(async move {
|
||||
|
||||
|
||||
loop {
|
||||
if let Some(package) = async_output_receiver.recv().await {
|
||||
let mut message_queue = message_queue_clone.lock().await;
|
||||
@@ -72,6 +74,7 @@ pub fn init(
|
||||
/* ...........................................................
|
||||
Prepare audio context
|
||||
............................................................*/
|
||||
|
||||
let latency_hint = match std::env::var("WEB_AUDIO_LATENCY").as_deref() {
|
||||
Ok("playback") => AudioContextLatencyCategory::Playback,
|
||||
_ => AudioContextLatencyCategory::default(),
|
||||
@@ -98,7 +101,7 @@ pub fn init(
|
||||
|
||||
return false;
|
||||
});
|
||||
sleep(Duration::from_millis(1));
|
||||
tokio::time::sleep(Duration::from_millis(1)).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user