mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-24 05:57:17 -04:00
Switch back to explicit exports and use new release mechanism
This commit is contained in:
@@ -468,7 +468,7 @@ export const { attack, att } = registerControl('attack', 'att');
|
||||
* ._scope()
|
||||
*
|
||||
*/
|
||||
Object.assign(globalThis, registerMultiControl(['fmh', 'fmi'], 8, 'fmh'));
|
||||
export const { fmh, fmh1, fmh2, fmh3, fmh4, fmh5, fmh6, fmh7, fmh8 } = registerMultiControl(['fmh', 'fmi'], 8, 'fmh');
|
||||
|
||||
/**
|
||||
* Sets the Frequency Modulation of the synth.
|
||||
@@ -492,7 +492,8 @@ Object.assign(globalThis, registerMultiControl(['fmh', 'fmi'], 8, 'fmh'));
|
||||
* .fmh(1.06).fmh2(10).fmh3(0.1)
|
||||
*
|
||||
*/
|
||||
Object.assign(globalThis, registerMultiControl(['fmi', 'fmh'], 8, 'fm'));
|
||||
export const { fmi, fmi1, fmi2, fmi3, fmi4, fmi5, fmi6, fmi7, fmi8, fm, fm1, fm2, fm3, fm4, fm5, fm6, fm7, fm8 } =
|
||||
registerMultiControl(['fmi', 'fmh'], 8, 'fm');
|
||||
|
||||
// fm envelope
|
||||
/**
|
||||
@@ -512,7 +513,10 @@ Object.assign(globalThis, registerMultiControl(['fmi', 'fmh'], 8, 'fm'));
|
||||
* ._scope()
|
||||
*
|
||||
*/
|
||||
Object.assign(globalThis, registerMultiControl('fmenv', 8));
|
||||
export const { fmenv, fmenv1, fmenv2, fmenv3, fmenv4, fmenv5, fmenv6, fmenv7, fmenv8 } = registerMultiControl(
|
||||
'fmenv',
|
||||
8,
|
||||
);
|
||||
|
||||
/**
|
||||
* Attack time for the FM envelope: time it takes to reach maximum modulation
|
||||
@@ -530,7 +534,26 @@ Object.assign(globalThis, registerMultiControl('fmenv', 8));
|
||||
* ._scope()
|
||||
*
|
||||
*/
|
||||
Object.assign(globalThis, registerMultiControl('fmattack', 8, 'fmatt'));
|
||||
export const {
|
||||
fmattack,
|
||||
fmattack1,
|
||||
fmattack2,
|
||||
fmattack3,
|
||||
fmattack4,
|
||||
fmattack5,
|
||||
fmattack6,
|
||||
fmattack7,
|
||||
fmattack8,
|
||||
fmatt,
|
||||
fmatt1,
|
||||
fmatt2,
|
||||
fmatt3,
|
||||
fmatt4,
|
||||
fmatt5,
|
||||
fmatt6,
|
||||
fmatt7,
|
||||
fmatt8,
|
||||
} = registerMultiControl('fmattack', 8, 'fmatt');
|
||||
|
||||
/**
|
||||
* Waveform of the fm modulator
|
||||
@@ -546,7 +569,10 @@ Object.assign(globalThis, registerMultiControl('fmattack', 8, 'fmatt'));
|
||||
* n("0 1 2 3".fast(4)).chord("<Dm Am F G>").voicing().s("sawtooth").fmwave("brown").fm(.6)
|
||||
*
|
||||
*/
|
||||
Object.assign(globalThis, registerMultiControl('fmwave', 8));
|
||||
export const { fmwave, fmwave1, fmwave2, fmwave3, fmwave4, fmwave5, fmwave6, fmwave7, fmwave8 } = registerMultiControl(
|
||||
'fmwave',
|
||||
8,
|
||||
);
|
||||
|
||||
/**
|
||||
* Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase.
|
||||
@@ -565,7 +591,26 @@ Object.assign(globalThis, registerMultiControl('fmwave', 8));
|
||||
* ._scope()
|
||||
*
|
||||
*/
|
||||
Object.assign(globalThis, registerMultiControl('fmdecay', 8, 'fmdec'));
|
||||
export const {
|
||||
fmdecay,
|
||||
fmdecay1,
|
||||
fmdecay2,
|
||||
fmdecay3,
|
||||
fmdecay4,
|
||||
fmdecay5,
|
||||
fmdecay6,
|
||||
fmdecay7,
|
||||
fmdecay8,
|
||||
fmdec,
|
||||
fmdec1,
|
||||
fmdec2,
|
||||
fmdec3,
|
||||
fmdec4,
|
||||
fmdec5,
|
||||
fmdec6,
|
||||
fmdec7,
|
||||
fmdec8,
|
||||
} = registerMultiControl('fmdecay', 8, 'fmdec');
|
||||
|
||||
/**
|
||||
* Sustain level for the FM envelope: how much modulation is applied after the decay phase
|
||||
@@ -584,7 +629,26 @@ Object.assign(globalThis, registerMultiControl('fmdecay', 8, 'fmdec'));
|
||||
* ._scope()
|
||||
*
|
||||
*/
|
||||
Object.assign(globalThis, registerMultiControl('fmsustain', 8, 'fmsus'));
|
||||
export const {
|
||||
fmsustain,
|
||||
fmsustain1,
|
||||
fmsustain2,
|
||||
fmsustain3,
|
||||
fmsustain4,
|
||||
fmsustain5,
|
||||
fmsustain6,
|
||||
fmsustain7,
|
||||
fmsustain8,
|
||||
fmsus,
|
||||
fmsus1,
|
||||
fmsus2,
|
||||
fmsus3,
|
||||
fmsus4,
|
||||
fmsus5,
|
||||
fmsus6,
|
||||
fmsus7,
|
||||
fmsus8,
|
||||
} = registerMultiControl('fmsustain', 8, 'fmsus');
|
||||
|
||||
/**
|
||||
* Release time for the FM envelope: how much modulation is applied after the note is released
|
||||
@@ -597,12 +661,35 @@ Object.assign(globalThis, registerMultiControl('fmsustain', 8, 'fmsus'));
|
||||
* @param {number | Pattern} time release time
|
||||
*
|
||||
*/
|
||||
Object.assign(globalThis, registerMultiControl('fmrelease', 8, 'fmrel'));
|
||||
export const {
|
||||
fmrelease,
|
||||
fmrelease1,
|
||||
fmrelease2,
|
||||
fmrelease3,
|
||||
fmrelease4,
|
||||
fmrelease5,
|
||||
fmrelease6,
|
||||
fmrelease7,
|
||||
fmrelease8,
|
||||
fmrel,
|
||||
fmrel1,
|
||||
fmrel2,
|
||||
fmrel3,
|
||||
fmrel4,
|
||||
fmrel5,
|
||||
fmrel6,
|
||||
fmrel7,
|
||||
fmrel8,
|
||||
} = registerMultiControl('fmrelease', 8, 'fmrel');
|
||||
|
||||
// FM Matrix
|
||||
// Note: we do not declare top-level exports here since it would add
|
||||
// ~162 more explicit exports. This is likely fine as the most common use-case would be to at least
|
||||
// declare one other FM prior to utilizing the matrix functionality, but if we ever decide we need it,
|
||||
// TODO to add it explicitly / go with the globalThis approach
|
||||
for (let i = 0; i <= 8; i++) {
|
||||
for (let j = 0; j <= 8; j++) {
|
||||
Object.assign(globalThis, registerControl(`fmi${i}${j}`, `fm${i}${j}`));
|
||||
registerControl(`fmi${i}${j}`, `fm${i}${j}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -372,13 +372,13 @@ const mod = (freq, type = 'sine') => {
|
||||
osc.frequency.value = freq;
|
||||
}
|
||||
osc.start();
|
||||
return { osc, freq };
|
||||
return osc;
|
||||
};
|
||||
|
||||
const fm = (frequencyparam, harmonicityRatio, wave = 'sine') => {
|
||||
const carrfreq = frequencyparam.value;
|
||||
const modfreq = carrfreq * harmonicityRatio;
|
||||
return mod(modfreq, wave);
|
||||
return { osc: mod(modfreq, wave), freq: modfreq };
|
||||
};
|
||||
|
||||
export function applyFM(param, value, begin) {
|
||||
@@ -434,13 +434,12 @@ export function applyFM(param, value, begin) {
|
||||
toCleanup.push(envGain);
|
||||
output = osc.connect(envGain);
|
||||
}
|
||||
fms[idx] = { input: osc.frequency, output, freq, toCleanup };
|
||||
osc.onended = () => cleanupNodes(fms[idx].toCleanup);
|
||||
fms[idx] = { input: osc.frequency, output, freq, osc, toCleanup };
|
||||
}
|
||||
const { input, output, freq, toCleanup } = fms[idx];
|
||||
const { input, output, freq, osc, toCleanup } = fms[idx];
|
||||
const g = gainNode(amt * freq);
|
||||
io.push(isMod ? output.connect(g) : input);
|
||||
toCleanup.push(g);
|
||||
cleanupOnEnd(osc, [...toCleanup, g]);
|
||||
}
|
||||
if (!io[1]) {
|
||||
logger(
|
||||
@@ -451,11 +450,6 @@ export function applyFM(param, value, begin) {
|
||||
}
|
||||
io[0].connect(io[1]);
|
||||
}
|
||||
fmmod.osc.onended = () => {
|
||||
envGain.disconnect();
|
||||
modulator.disconnect();
|
||||
fmmod.osc.disconnect();
|
||||
};
|
||||
}
|
||||
return {
|
||||
stop: (t) => toStop.forEach((m) => m?.stop(t)),
|
||||
@@ -575,10 +569,9 @@ export const getFrequencyFromValue = (value, defaultNote = 36) => {
|
||||
// This helper should be used instead of the `node.onended = callback` pattern
|
||||
// It adds a mechanism to help minimize gc retention
|
||||
export const onceEnded = (node, callback) => {
|
||||
let onended = callback;
|
||||
const onended = callback;
|
||||
node.onended = function cleanup() {
|
||||
onended && onended();
|
||||
onended = null;
|
||||
this.onended = null;
|
||||
};
|
||||
};
|
||||
@@ -624,13 +617,10 @@ export const releaseAudioNode = (node) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const cleanupNode = (node, time) => {
|
||||
if (node == null) return;
|
||||
node.disconnect?.();
|
||||
node.parameters?.get('end')?.setValueAtTime(0, 0);
|
||||
node.stop?.(time);
|
||||
};
|
||||
|
||||
export const cleanupNodes = (nodes, time) => {
|
||||
nodes.forEach((n) => cleanupNode(n, time));
|
||||
// Once the `anchor` node has ended, release all nodes in `toCleanup`
|
||||
export const cleanupOnEnd = (anchor, toCleanup) => {
|
||||
onceEnded(
|
||||
anchor,
|
||||
() => toCleanup.forEach((n) => releaseAudioNode(n)),
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user