From 32456d69663acce0b6932f06c8c64e6e2c4e7b73 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 15 Jan 2024 23:55:49 +0100 Subject: [PATCH] pitch envelope for sampler and soundfonts + added getPitchEnvelope helper --- packages/soundfonts/fontloader.mjs | 13 ++++++++++++- packages/superdough/helpers.mjs | 13 +++++++++++++ packages/superdough/sampler.mjs | 7 ++++++- packages/superdough/synth.mjs | 21 ++++++--------------- 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/packages/soundfonts/fontloader.mjs b/packages/soundfonts/fontloader.mjs index dc3f4b61..fced1c28 100644 --- a/packages/soundfonts/fontloader.mjs +++ b/packages/soundfonts/fontloader.mjs @@ -1,5 +1,11 @@ import { noteToMidi, freqToMidi, getSoundIndex } from '@strudel.cycles/core'; -import { getAudioContext, registerSound, getParamADSR, getADSRValues } from '@strudel.cycles/webaudio'; +import { + getAudioContext, + registerSound, + getParamADSR, + getADSRValues, + getPitchEnvelope, +} from '@strudel.cycles/webaudio'; import gm from './gm.mjs'; let loadCache = {}; @@ -149,6 +155,11 @@ export function registerSoundfonts() { getParamADSR(node.gain, attack, decay, sustain, release, 0, 0.3, time, holdEnd, 'linear'); let envEnd = holdEnd + release + 0.01; + // pitch envelope + if (value.penv) { + getPitchEnvelope(bufferSource.detune, value, time, holdEnd); + } + bufferSource.stop(envEnd); const stop = (releaseTime) => {}; bufferSource.onended = () => { diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index bee26f38..d69afd36 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -144,3 +144,16 @@ export function drywet(dry, wet, wetAmount = 0) { wet_gain.connect(mix); return mix; } + +export function getPitchEnvelope(param, value, t, holdEnd) { + if (value.penv) { + let [pattack, pdecay, psustain, prelease] = getADSRValues([ + value.pattack, + value.pdecay, + value.psustain, + value.prelease, + ]); + const cents = value.penv * 100; + getParamADSR(param, pattack, pdecay, psustain, prelease, 0, cents, t, holdEnd, 'linear'); + } +} diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 932be995..5e842da5 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -1,6 +1,6 @@ import { noteToMidi, valueToMidi, getSoundIndex } from './util.mjs'; import { getAudioContext, registerSound } from './index.mjs'; -import { getADSRValues, getParamADSR } from './helpers.mjs'; +import { getADSRValues, getParamADSR, getPitchEnvelope } from './helpers.mjs'; import { logger } from './logger.mjs'; const bufferCache = {}; // string: Promise @@ -310,6 +310,11 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, t, holdEnd, 'linear'); + // pitch envelope + if (value.penv) { + getPitchEnvelope(bufferSource.detune, value, t, holdEnd); + } + const out = ac.createGain(); // we need a separate gain for the cutgroups because firefox... node.connect(out); bufferSource.onended = function () { diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index d484284b..9d70e037 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -1,6 +1,6 @@ import { midiToFreq, noteToMidi } from './util.mjs'; import { registerSound, getAudioContext } from './superdough.mjs'; -import { gainNode, getADSRValues, getParamADSR } from './helpers.mjs'; +import { gainNode, getADSRValues, getParamADSR, getPitchEnvelope } from './helpers.mjs'; import { getNoiseMix, getNoiseOscillator } from './noise.mjs'; const mod = (freq, range = 1, type = 'sine') => { @@ -105,10 +105,8 @@ export function waveformN(partials, type) { } // expects one of waveforms as s -export function getOscillator( - s, - t, - { +export function getOscillator(s, t, value) { + let { n: partials, note, freq, @@ -126,14 +124,7 @@ export function getOscillator( fmvelocity: fmVelocity, fmwave: fmWaveform = 'sine', duration, - penv, - // panchor = 0, // TODO - pattack, - pdecay, - psustain, - prelease, - }, -) { + } = value; let ac = getAudioContext(); let o; // If no partials are given, use stock waveforms @@ -203,9 +194,9 @@ export function getOscillator( } // pitch envelope - if (penv) { + if (value.penv) { const holdEnd = t + duration; - getParamADSR(o.detune, pattack, pdecay, psustain, prelease, 0, penv * 100, t, holdEnd, 'linear'); + getPitchEnvelope(o.detune, value, t, holdEnd); } let noiseMix;