ramp cut audio node

This commit is contained in:
Jade (Rose) Rowland 2025-03-30 16:33:47 -04:00
parent 8962e5a4f0
commit 6f9bcc53dc
5 changed files with 51 additions and 32 deletions

View File

@ -212,6 +212,7 @@ export function webAudioTimeout(audioContext, onComplete, startTime, stopTime) {
constantNode.onended = () => { constantNode.onended = () => {
onComplete(); onComplete();
}; };
return constantNode
} }
const mod = (freq, range = 1, type = 'sine') => { const mod = (freq, range = 1, type = 'sine') => {
const ctx = getAudioContext(); const ctx = getAudioContext();

View File

@ -345,7 +345,9 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
}; };
let envEnd = holdEnd + release + 0.01; let envEnd = holdEnd + release + 0.01;
bufferSource.stop(envEnd); bufferSource.stop(envEnd);
const stop = (endTime, playWholeBuffer) => {}; const stop = (endTime) => {
bufferSource.stop(endTime)
};
const handle = { node: out, bufferSource, stop }; const handle = { node: out, bufferSource, stop };
// cut groups // cut groups

View File

@ -379,7 +379,7 @@ export function resetGlobalEffects() {
analysersData = {}; analysersData = {};
} }
let allAudioNodeChains = new Map(); let activeSoundSources = new Map();
export const superdough = async (value, t, hapDuration) => { export const superdough = async (value, t, hapDuration) => {
const ac = getAudioContext(); const ac = getAudioContext();
@ -480,30 +480,24 @@ export const superdough = async (value, t, hapDuration) => {
gain = nanFallback(gain, 1); gain = nanFallback(gain, 1);
const chainID = Math.round(Math.random() * 10000); const chainID = Math.round(Math.random() * 1000000);
// oldest audio nodes will be removed if maximum polyphony is exceeded // oldest audio nodes will be destroyed if maximum polyphony is exceeded
for (let i = 0; i <= allAudioNodeChains.size - maxPolyphony; i++) { for (let i = 0; i <= activeSoundSources.size - maxPolyphony; i++) {
const ch = allAudioNodeChains.entries().next(); const ch = activeSoundSources.entries().next();
const key = ch.value[0]; const source = ch.value[1];
const chain = ch.value[1]; const chainID = ch.value[0];
if (key == null) { const endTime = t + .25;
continue; source?.node?.gain?.linearRampToValueAtTime(0, endTime);
} source?.stop?.(endTime);
chain?.forEach((node) => node?.disconnect()); activeSoundSources.delete(chainID);
allAudioNodeChains.delete(key);
} }
//music programs/audio gear usually increments inputs/outputs from 1, so imitate that behavior //music programs/audio gear usually increments inputs/outputs from 1, so imitate that behavior
channels = (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1); channels = (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1);
gain *= velocity; // velocity currently only multiplies with gain. it might do other things in the future gain *= velocity; // velocity currently only multiplies with gain. it might do other things in the future
let audioNodes = [];
const onended = () => {
const chain = allAudioNodeChains.get(chainID);
chain?.forEach((n) => n?.disconnect());
allAudioNodeChains.delete(chainID);
};
if (bank && s) { if (bank && s) {
s = `${bank}_${s}`; s = `${bank}_${s}`;
value.s = s; value.s = s;
@ -515,10 +509,15 @@ export const superdough = async (value, t, hapDuration) => {
sourceNode = source(t, value, hapDuration); sourceNode = source(t, value, hapDuration);
} else if (getSound(s)) { } else if (getSound(s)) {
const { onTrigger } = getSound(s); const { onTrigger } = getSound(s);
const soundHandle = await onTrigger(t, value, onended); const onEnded = () => {
audioNodes.forEach((n) => n?.disconnect());
activeSoundSources.delete(chainID);
};
const soundHandle = await onTrigger(t, value, onEnded);
if (soundHandle) { if (soundHandle) {
sourceNode = soundHandle.node; sourceNode = soundHandle.node;
soundHandle.stop(t + hapDuration); activeSoundSources.set(chainID, soundHandle);
} }
} else { } else {
throw new Error(`sound ${s} not found! Is it loaded?`); throw new Error(`sound ${s} not found! Is it loaded?`);
@ -648,6 +647,7 @@ export const superdough = async (value, t, hapDuration) => {
if (delay > 0 && delaytime > 0 && delayfeedback > 0) { if (delay > 0 && delaytime > 0 && delayfeedback > 0) {
const delyNode = getDelay(orbit, delaytime, delayfeedback, t); const delyNode = getDelay(orbit, delaytime, delayfeedback, t);
delaySend = effectSend(post, delyNode, delay); delaySend = effectSend(post, delyNode, delay);
audioNodes.push(delaySend);
} }
// reverb // reverb
let reverbSend; let reverbSend;
@ -665,6 +665,7 @@ export const superdough = async (value, t, hapDuration) => {
} }
const reverbNode = getReverb(orbit, roomsize, roomfade, roomlp, roomdim, roomIR); const reverbNode = getReverb(orbit, roomsize, roomfade, roomlp, roomdim, roomIR);
reverbSend = effectSend(post, reverbNode, room); reverbSend = effectSend(post, reverbNode, room);
audioNodes.push(reverbSend);
} }
// analyser // analyser
@ -672,11 +673,13 @@ export const superdough = async (value, t, hapDuration) => {
if (analyze) { if (analyze) {
const analyserNode = getAnalyserById(analyze, 2 ** (fft + 5)); const analyserNode = getAnalyserById(analyze, 2 ** (fft + 5));
analyserSend = effectSend(post, analyserNode, 1); analyserSend = effectSend(post, analyserNode, 1);
audioNodes.push(analyserSend);
} }
// connect chain elements together // connect chain elements together
chain.slice(1).reduce((last, current) => last.connect(current), chain[0]); chain.slice(1).reduce((last, current) => last.connect(current), chain[0]);
allAudioNodeChains.set(chainID, [...chain, delaySend, reverbSend, analyserSend]); audioNodes = audioNodes.concat(chain);
// activeSoundSources.set(chainID, [...chain, delaySend, reverbSend, analyserSend].filter(Boolean));
}; };
export const superdoughTrigger = (t, hap, ct, cps) => { export const superdoughTrigger = (t, hap, ct, cps) => {

View File

@ -63,7 +63,9 @@ export function registerSynthSounds() {
stop(envEnd); stop(envEnd);
return { return {
node, node,
stop: (releaseTime) => {}, stop: (endTime) => {
stop(endTime);
},
}; };
}, },
{ type: 'synth', prebake: true }, { type: 'synth', prebake: true },
@ -110,7 +112,9 @@ export function registerSynthSounds() {
let envGain = gainNode(1); let envGain = gainNode(1);
envGain = o.connect(envGain); envGain = o.connect(envGain);
webAudioTimeout( getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 0.3 * gainAdjustment, begin, holdend, 'linear');
let timeoutNode = webAudioTimeout(
ac, ac,
() => { () => {
o.disconnect(); o.disconnect();
@ -123,11 +127,11 @@ export function registerSynthSounds() {
end, end,
); );
getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 0.3 * gainAdjustment, begin, holdend, 'linear');
return { return {
node: envGain, node: envGain,
stop: (time) => {}, stop: (time) => {
timeoutNode.stop(time);
},
}; };
}, },
{ prebake: true, type: 'synth' }, { prebake: true, type: 'synth' },
@ -169,7 +173,10 @@ export function registerSynthSounds() {
let envGain = gainNode(1); let envGain = gainNode(1);
envGain = o.connect(envGain); envGain = o.connect(envGain);
webAudioTimeout(
getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 1, begin, holdend, 'linear');
let timeoutNode = webAudioTimeout(
ac, ac,
() => { () => {
o.disconnect(); o.disconnect();
@ -182,11 +189,11 @@ export function registerSynthSounds() {
end, end,
); );
getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 1, begin, holdend, 'linear');
return { return {
node: envGain, node: envGain,
stop: (time) => {}, stop: (time) => {
timeoutNode.stop(time);
},
}; };
}, },
{ prebake: true, type: 'synth' }, { prebake: true, type: 'synth' },
@ -229,7 +236,9 @@ export function registerSynthSounds() {
stop(envEnd); stop(envEnd);
return { return {
node, node,
stop: (releaseTime) => {}, stop: (endTime) => {
stop(endTime)
},
}; };
}, },
{ type: 'synth', prebake: true }, { type: 'synth', prebake: true },
@ -299,6 +308,7 @@ export function getOscillator(s, t, value) {
return { return {
node: noiseMix?.node || o, node: noiseMix?.node || o,
stop: (time) => { stop: (time) => {
// console.info(time)
fmModulator.stop(time); fmModulator.stop(time);
vibratoOscillator?.stop(time); vibratoOscillator?.stop(time);
noiseMix?.stop(time); noiseMix?.stop(time);

View File

@ -663,6 +663,9 @@ registerProcessor('phase-vocoder-processor', PhaseVocoderProcessor);
class PulseOscillatorProcessor extends AudioWorkletProcessor { class PulseOscillatorProcessor extends AudioWorkletProcessor {
constructor() { constructor() {
super(); super();
// this.port.onmessage = (event) => {
// console.info(event)
// };
this.pi = _PI; this.pi = _PI;
this.phi = -this.pi; // phase this.phi = -this.pi; // phase
this.Y0 = 0; // feedback memories this.Y0 = 0; // feedback memories