simplify modulators
This commit is contained in:
parent
23d4bfa9d9
commit
c689874bb4
2 changed files with 78 additions and 41 deletions
|
|
@ -153,6 +153,41 @@ export const getADSRValues = (params, curve = 'linear', defaultValues) => {
|
||||||
return [Math.max(a ?? 0, envmin), Math.max(d ?? 0, envmin), Math.min(sustain, envmax), Math.max(r ?? 0, releaseMin)];
|
return [Math.max(a ?? 0, envmin), Math.max(d ?? 0, envmin), Math.min(sustain, envmax), Math.max(r ?? 0, releaseMin)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// helper utility for applying standard modulators to a parameter
|
||||||
|
export function applyParameterModulators(audioContext, param, start, end, envelopeValues, lfoValues) {
|
||||||
|
let { amount,offset,defaultAmount = 1, curve = 'linear', values, holdEnd, defaultValues } = envelopeValues;
|
||||||
|
|
||||||
|
if (amount == null) {
|
||||||
|
const hasADSRParams = values.some(p => p != null);
|
||||||
|
amount = hasADSRParams ? defaultAmount : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const min = offset ?? 0;
|
||||||
|
const max = amount + min
|
||||||
|
const diff = Math.abs(max - min)
|
||||||
|
if (diff) {
|
||||||
|
const [attack, decay, sustain, release] = getADSRValues(values, curve, defaultValues);
|
||||||
|
getParamADSR(param, attack, decay, sustain, release, min, max, start, holdEnd, curve);
|
||||||
|
}
|
||||||
|
let lfo
|
||||||
|
let {defaultDepth = 1,depth, dcoffset, ...getLfoInputs} = lfoValues
|
||||||
|
|
||||||
|
if (depth == null) {
|
||||||
|
const hasLFOParams = Object.values(getLfoInputs).some(v => v != null)
|
||||||
|
depth = hasLFOParams ? defaultDepth : 0;
|
||||||
|
}
|
||||||
|
if (depth) {
|
||||||
|
lfo = getLfo(audioContext, start, end, {
|
||||||
|
depth,
|
||||||
|
dcoffset,
|
||||||
|
...getLfoInputs
|
||||||
|
});
|
||||||
|
lfo.connect(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { lfo, disconnect: () => lfo?.disconnect() }
|
||||||
|
}
|
||||||
|
|
||||||
export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fenv, start, end, fanchor, model, drive) {
|
export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fenv, start, end, fanchor, model, drive) {
|
||||||
const curve = 'exponential';
|
const curve = 'exponential';
|
||||||
const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], curve, [0.005, 0.14, 0, 0.1]);
|
const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], curve, [0.005, 0.14, 0, 0.1]);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { getAudioContext, registerSound } from './index.mjs';
|
import { getAudioContext, registerSound } from './index.mjs';
|
||||||
import { getCommonSampleInfo } from './util.mjs';
|
import { getCommonSampleInfo } from './util.mjs';
|
||||||
import {
|
import {
|
||||||
|
applyParameterModulators,
|
||||||
destroyAudioWorkletNode,
|
destroyAudioWorkletNode,
|
||||||
getADSRValues,
|
getADSRValues,
|
||||||
getFrequencyFromValue,
|
getFrequencyFromValue,
|
||||||
|
|
@ -220,8 +221,10 @@ export const tables = async (url, frameLen, json, options = {}) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) {
|
export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) {
|
||||||
const { s, n = 0, duration, wtenv } = value;
|
const { s, n = 0, duration } = value;
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
const [attack, decay, sustain, release] = getADSRValues([value.attack, value.decay, value.sustain, value.release]);
|
const [attack, decay, sustain, release] = getADSRValues([value.attack, value.decay, value.sustain, value.release]);
|
||||||
let { warpmode } = value;
|
let { warpmode } = value;
|
||||||
|
|
@ -245,7 +248,7 @@ export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) {
|
||||||
position: value.wt,
|
position: value.wt,
|
||||||
warp: value.warp,
|
warp: value.warp,
|
||||||
warpMode: warpmode,
|
warpMode: warpmode,
|
||||||
voices: value.unison,
|
voices: Math.max(value.unison ?? 1, 1),
|
||||||
spread: value.spread,
|
spread: value.spread,
|
||||||
phaserand: (value.wtphaserand ?? value.unison > 1) ? 1 : 0,
|
phaserand: (value.wtphaserand ?? value.unison > 1) ? 1 : 0,
|
||||||
},
|
},
|
||||||
|
|
@ -261,55 +264,54 @@ export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) {
|
||||||
const wtParams = source.parameters;
|
const wtParams = source.parameters;
|
||||||
const positionParam = wtParams.get('position');
|
const positionParam = wtParams.get('position');
|
||||||
const warpParam = wtParams.get('warp');
|
const warpParam = wtParams.get('warp');
|
||||||
let posLFO;
|
|
||||||
if ([wtenv, ...posADSRParams].some((p) => p !== undefined)) {
|
|
||||||
const [pAttack, pDecay, pSustain, pRelease] = getADSRValues(posADSRParams, 'linear', [0, 0.5, 0, 0.1]);
|
|
||||||
const min = value.wt ?? 0;
|
|
||||||
const max = (wtenv ?? 0.5) + min;
|
|
||||||
getParamADSR(positionParam, pAttack, pDecay, pSustain, pRelease, min, max, t, holdEnd, 'linear');
|
|
||||||
}
|
|
||||||
let wtrate = value.wtrate;
|
let wtrate = value.wtrate;
|
||||||
if (value.wtsync != null) {
|
if (value.wtsync != null) {
|
||||||
wtrate = wtrate = cps * value.wtsync;
|
wtrate = cps * value.wtsync;
|
||||||
}
|
}
|
||||||
if ([wtrate, value.wtdepth, value.wtshape, value.wtskew, value.wtdc].some((p) => p != null)) {
|
|
||||||
const posLFO = getLfo(ac, t, endWithRelease, {
|
const wtPosModulators = applyParameterModulators(ac, positionParam, t, endWithRelease, {
|
||||||
|
offset: value.wt,
|
||||||
|
amount: value.wtenv,
|
||||||
|
defaultAmount: 0.5,
|
||||||
|
shape: 'linear',
|
||||||
|
values: posADSRParams,
|
||||||
|
holdEnd,
|
||||||
|
defaultValues: [0, 0.5, 0, 0.1],
|
||||||
|
}, {
|
||||||
frequency: wtrate,
|
frequency: wtrate,
|
||||||
depth: value.wtdepth ?? 0.5,
|
depth: value.wtdepth,
|
||||||
|
defaultDepth: 0.5,
|
||||||
shape: value.wtshape,
|
shape: value.wtshape,
|
||||||
skew: value.wtskew,
|
skew: value.wtskew,
|
||||||
dcoffset: value.wtdc ?? 0,
|
dcoffset: value.wtdc ?? 0,
|
||||||
});
|
});
|
||||||
posLFO.connect(positionParam);
|
|
||||||
}
|
|
||||||
let warpLFO;
|
|
||||||
|
|
||||||
if (posADSRParams.some((p) => p !== undefined)) {
|
|
||||||
const [wAttack, wDecay, wSustain, wRelease] = getADSRValues(warpADSRParams);
|
|
||||||
const min = value.warp ?? 0;
|
|
||||||
const max = (value.warpenv ?? 0.5) + min;
|
|
||||||
getParamADSR(warpParam, wAttack, wDecay, wSustain, wRelease, min, max, t, holdEnd, 'linear', [0, 0.5, 0, 0.1]);
|
|
||||||
}
|
|
||||||
let warprate = value.warprate;
|
let warprate = value.warprate;
|
||||||
if (value.warpsync != null) {
|
if (value.warpsync != null) {
|
||||||
console.info(value.warpsync);
|
|
||||||
warprate = warprate = cps * value.warpsync;
|
warprate = warprate = cps * value.warpsync;
|
||||||
}
|
}
|
||||||
if ([warprate, value.warpdepth, value.warpshape, value.warpskew, value.warpdc].some((p) => p != null)) {
|
const wtWarpModulators = applyParameterModulators(ac, warpParam, t, endWithRelease, {
|
||||||
const warpLFO = getLfo(ac, t, endWithRelease, {
|
offset: value.warp,
|
||||||
|
amount: value.warpenv,
|
||||||
|
defaultAmount: 0.5,
|
||||||
|
shape: 'linear',
|
||||||
|
values: warpADSRParams,
|
||||||
|
holdEnd,
|
||||||
|
defaultValues: [0, 0.5, 0, 0.1],
|
||||||
|
}, {
|
||||||
frequency: warprate,
|
frequency: warprate,
|
||||||
depth: value.warpdepth ?? 0.5,
|
depth: value.warpdepth,
|
||||||
|
defaultDepth: 0.5,
|
||||||
shape: value.warpshape,
|
shape: value.warpshape,
|
||||||
skew: value.warpskew,
|
skew: value.warpskew,
|
||||||
dcoffset: value.warpdc ?? 0,
|
dcoffset: value.warpdc ?? 0,
|
||||||
});
|
});
|
||||||
warpLFO.connect(warpParam);
|
|
||||||
}
|
|
||||||
const vibratoOscillator = getVibratoOscillator(source.detune, value, t);
|
const vibratoOscillator = getVibratoOscillator(source.detune, value, t);
|
||||||
const envGain = ac.createGain();
|
const envGain = ac.createGain();
|
||||||
const node = source.connect(envGain);
|
const node = source.connect(envGain);
|
||||||
getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, t, holdEnd, 'linear');
|
getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, t, holdEnd, 'linear');
|
||||||
getPitchEnvelope(source.detune, value, t, holdEnd);
|
getPitchEnvelope(source.parameters.get('detune'), value, t, holdEnd);
|
||||||
const handle = { node, source };
|
const handle = { node, source };
|
||||||
const timeoutNode = webAudioTimeout(
|
const timeoutNode = webAudioTimeout(
|
||||||
ac,
|
ac,
|
||||||
|
|
@ -318,8 +320,8 @@ export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) {
|
||||||
destroyAudioWorkletNode(source);
|
destroyAudioWorkletNode(source);
|
||||||
vibratoOscillator?.stop();
|
vibratoOscillator?.stop();
|
||||||
node.disconnect();
|
node.disconnect();
|
||||||
posLFO?.disconnect();
|
wtPosModulators?.disconnect();
|
||||||
warpLFO?.disconnect();
|
wtWarpModulators?.disconnect();
|
||||||
onended();
|
onended();
|
||||||
},
|
},
|
||||||
t,
|
t,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue