Extend to FM, vibrato, etc
This commit is contained in:
parent
99bec835f8
commit
48f6a41683
9 changed files with 112 additions and 64 deletions
|
|
@ -2870,36 +2870,33 @@ registerSubControls('bmod', [
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Pattern.prototype.modulate = function (type, config, idx) {
|
Pattern.prototype.modulate = function (type, config, idx) {
|
||||||
if (config == null || typeof config !== 'object') {
|
config ??= { control: undefined };
|
||||||
return this;
|
|
||||||
}
|
|
||||||
const modulatorKeys = ['lfo', 'env', 'bmod'];
|
const modulatorKeys = ['lfo', 'env', 'bmod'];
|
||||||
if (!modulatorKeys.includes(type)) {
|
if (!modulatorKeys.includes(type)) {
|
||||||
logger(`[core] Modulation type ${type} not found. Please use one of 'lfo', 'env', 'bmod'`);
|
logger(`[core] Modulation type ${type} not found. Please use one of 'lfo', 'env', 'bmod'`);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
let output = this;
|
let output = this;
|
||||||
let defaultValue = {};
|
let defaultValue = undefined;
|
||||||
let defaultSet = 'control' in config;
|
|
||||||
for (const [rawKey, value] of Object.entries(config)) {
|
for (const [rawKey, value] of Object.entries(config)) {
|
||||||
const key = getMainSubcontrolName(type, rawKey);
|
const key = getMainSubcontrolName(type, rawKey);
|
||||||
const valuePat = reify(value);
|
const valuePat = reify(value);
|
||||||
output = output
|
output = output
|
||||||
.fmap((v) => (c) => {
|
.fmap((v) => (c) => {
|
||||||
if (!defaultSet) {
|
if (defaultValue === undefined) {
|
||||||
// default control to the control set just before this in the chain
|
// default control to the control set just before this in the chain
|
||||||
// e.g. pat.gain(0.5).lfo({..}) will be a gain-LFO
|
// e.g. pat.gain(0.5).lfo({..}) will be a gain-LFO
|
||||||
let control = getControlName(Object.keys(v).at(-1));
|
let control = getControlName(Object.keys(v).at(-1));
|
||||||
if (modulatorKeys.includes(control)) {
|
if (modulatorKeys.includes(control)) {
|
||||||
control = `${control}${v[control].length - 1}`;
|
control = `${control}${v[control].length - 1}`;
|
||||||
}
|
}
|
||||||
defaultValue = { control };
|
defaultValue = control;
|
||||||
defaultSet = true;
|
|
||||||
}
|
}
|
||||||
v[type] ??= [];
|
v[type] ??= [];
|
||||||
const t = v[type];
|
const t = v[type];
|
||||||
idx ??= t.length;
|
idx ??= t.length;
|
||||||
t[idx] ??= defaultValue;
|
t[idx] ??= { control: defaultValue };
|
||||||
|
if (c === undefined) return v;
|
||||||
if (key === 'control' || key === 'subControl') {
|
if (key === 'control' || key === 'subControl') {
|
||||||
t[idx][key] = getControlName(c);
|
t[idx][key] = getControlName(c);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ export function registerSoundfonts() {
|
||||||
let envEnd = holdEnd + release + 0.01;
|
let envEnd = holdEnd + release + 0.01;
|
||||||
|
|
||||||
// vibrato
|
// vibrato
|
||||||
let vibratoOscillator = getVibratoOscillator(bufferSource.detune, value, time);
|
const vibratoHandle = getVibratoOscillator(bufferSource.detune, value, time);
|
||||||
// pitch envelope
|
// pitch envelope
|
||||||
getPitchEnvelope(bufferSource.detune, value, time, holdEnd);
|
getPitchEnvelope(bufferSource.detune, value, time, holdEnd);
|
||||||
|
|
||||||
|
|
@ -174,10 +174,10 @@ export function registerSoundfonts() {
|
||||||
const stop = (releaseTime) => {};
|
const stop = (releaseTime) => {};
|
||||||
onceEnded(bufferSource, () => {
|
onceEnded(bufferSource, () => {
|
||||||
releaseAudioNode(bufferSource);
|
releaseAudioNode(bufferSource);
|
||||||
releaseAudioNode(vibratoOscillator);
|
vibratoHandle?.stop();
|
||||||
onended();
|
onended();
|
||||||
});
|
});
|
||||||
return { node, stop, source: bufferSource };
|
return { node, stop, nodes: { source: [bufferSource], ...vibratoHandle?.nodes } };
|
||||||
},
|
},
|
||||||
{ type: 'soundfont', prebake: true, fonts },
|
{ type: 'soundfont', prebake: true, fonts },
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -351,7 +351,7 @@ export function getVibratoOscillator(param, value, t) {
|
||||||
releaseAudioNode(vibratoOscillator);
|
releaseAudioNode(vibratoOscillator);
|
||||||
});
|
});
|
||||||
vibratoOscillator.start(t);
|
vibratoOscillator.start(t);
|
||||||
return vibratoOscillator;
|
return { stop: (t) => vibratoOscillator.stop(t), nodes: { vib: [vibratoOscillator], vib_gain: [gain] } };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -407,6 +407,7 @@ export function applyFM(param, value, begin) {
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
const toStop = []; // fm oscillators we will expose `stop` for
|
const toStop = []; // fm oscillators we will expose `stop` for
|
||||||
const fms = {};
|
const fms = {};
|
||||||
|
const nodes = {};
|
||||||
// Matrix
|
// Matrix
|
||||||
for (let i = 1; i <= 8; i++) {
|
for (let i = 1; i <= 8; i++) {
|
||||||
for (let j = 0; j <= 8; j++) {
|
for (let j = 0; j <= 8; j++) {
|
||||||
|
|
@ -457,11 +458,13 @@ export function applyFM(param, value, begin) {
|
||||||
output = osc.connect(envGain);
|
output = osc.connect(envGain);
|
||||||
}
|
}
|
||||||
fms[idx] = { input: osc.frequency, output, freq, osc, toCleanup };
|
fms[idx] = { input: osc.frequency, output, freq, osc, toCleanup };
|
||||||
|
nodes[`fm_${idx}`] = [osc];
|
||||||
}
|
}
|
||||||
const { input, output, freq, osc, toCleanup } = fms[idx];
|
const { input, output, freq, osc, toCleanup } = fms[idx];
|
||||||
const g = gainNode(amt * freq);
|
const g = gainNode(amt * freq);
|
||||||
io.push(isMod ? output.connect(g) : input);
|
io.push(isMod ? output.connect(g) : input);
|
||||||
cleanupOnEnd(osc, [...toCleanup, g]);
|
cleanupOnEnd(osc, [...toCleanup, g]);
|
||||||
|
nodes[`fm_${idx}_gain`] = [g];
|
||||||
}
|
}
|
||||||
if (!io[1]) {
|
if (!io[1]) {
|
||||||
logger(
|
logger(
|
||||||
|
|
@ -474,6 +477,7 @@ export function applyFM(param, value, begin) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
nodes,
|
||||||
stop: (t) => toStop.forEach((m) => m?.stop(t)),
|
stop: (t) => toStop.forEach((m) => m?.stop(t)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// vibrato
|
// vibrato
|
||||||
let vibratoOscillator = getVibratoOscillator(bufferSource.detune, value, t);
|
const vibratoHandle = getVibratoOscillator(bufferSource.detune, value, t);
|
||||||
|
|
||||||
const time = t + nudge;
|
const time = t + nudge;
|
||||||
bufferSource.start(time, offset);
|
bufferSource.start(time, offset);
|
||||||
|
|
@ -324,7 +324,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||||
node.connect(out);
|
node.connect(out);
|
||||||
onceEnded(bufferSource, function () {
|
onceEnded(bufferSource, function () {
|
||||||
releaseAudioNode(bufferSource);
|
releaseAudioNode(bufferSource);
|
||||||
releaseAudioNode(vibratoOscillator);
|
vibratoHandle?.stop();
|
||||||
releaseAudioNode(node);
|
releaseAudioNode(node);
|
||||||
releaseAudioNode(out);
|
releaseAudioNode(out);
|
||||||
onended();
|
onended();
|
||||||
|
|
@ -334,7 +334,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||||
const stop = (endTime) => {
|
const stop = (endTime) => {
|
||||||
bufferSource.stop(endTime);
|
bufferSource.stop(endTime);
|
||||||
};
|
};
|
||||||
const handle = { node: out, source: bufferSource, stop };
|
const handle = { node: out, nodes: { source: [bufferSource], ...vibratoHandle?.nodes }, stop };
|
||||||
|
|
||||||
// cut groups
|
// cut groups
|
||||||
if (cut !== undefined) {
|
if (cut !== undefined) {
|
||||||
|
|
|
||||||
|
|
@ -532,7 +532,7 @@ function mapChannelNumbers(channels) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5) => {
|
export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5) => {
|
||||||
const nodes = {};
|
let nodes = {};
|
||||||
// new: t is always expected to be the absolute target onset time
|
// new: t is always expected to be the absolute target onset time
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
const audioController = getSuperdoughAudioController();
|
const audioController = getSuperdoughAudioController();
|
||||||
|
|
@ -690,7 +690,7 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
||||||
if (soundHandle) {
|
if (soundHandle) {
|
||||||
sourceNode = soundHandle.node;
|
sourceNode = soundHandle.node;
|
||||||
activeSoundSources.set(chainID, new WeakRef(soundHandle)); // allow GC
|
activeSoundSources.set(chainID, new WeakRef(soundHandle)); // allow GC
|
||||||
nodes['source'] = [soundHandle.source];
|
nodes = { ...nodes, ...soundHandle.nodes };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`sound ${s} not found! Is it loaded?`);
|
throw new Error(`sound ${s} not found! Is it loaded?`);
|
||||||
|
|
@ -709,9 +709,8 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
||||||
chain.push(sourceNode);
|
chain.push(sourceNode);
|
||||||
stretch !== undefined && chain.push(getWorklet(ac, 'phase-vocoder-processor', { pitchFactor: stretch }));
|
stretch !== undefined && chain.push(getWorklet(ac, 'phase-vocoder-processor', { pitchFactor: stretch }));
|
||||||
|
|
||||||
transient !== undefined &&
|
if (transient !== undefined) {
|
||||||
chain.push(
|
const transProcessor = getWorklet(
|
||||||
getWorklet(
|
|
||||||
ac,
|
ac,
|
||||||
'transient-processor',
|
'transient-processor',
|
||||||
{},
|
{},
|
||||||
|
|
@ -723,8 +722,10 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
||||||
end: endWithRelease,
|
end: endWithRelease,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
chain.push(transProcessor);
|
||||||
|
nodes['transient'] = transProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
// gain stage
|
// gain stage
|
||||||
const initialGain = gainNode(gain);
|
const initialGain = gainNode(gain);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@ const CONTROL_TARGETS = {
|
||||||
lfo_sync: { node: 'lfo', param: 'frequency' },
|
lfo_sync: { node: 'lfo', param: 'frequency' },
|
||||||
lfo_depth: { node: 'lfo', param: 'depth' },
|
lfo_depth: { node: 'lfo', param: 'depth' },
|
||||||
lfo_depthabs: { node: 'lfo', param: 'depth' },
|
lfo_depthabs: { node: 'lfo', param: 'depth' },
|
||||||
|
lfo_skew: { node: 'lfo', param: 'skew' },
|
||||||
|
lfo_curve: { node: 'lfo', param: 'curve' },
|
||||||
|
lfo_dcoffset: { node: 'lfo', param: 'dcoffset' },
|
||||||
env: { node: 'env', param: 'depth' },
|
env: { node: 'env', param: 'depth' },
|
||||||
env_attack: { node: 'env', param: 'attack' },
|
env_attack: { node: 'env', param: 'attack' },
|
||||||
env_decay: { node: 'env', param: 'decay' },
|
env_decay: { node: 'env', param: 'decay' },
|
||||||
|
|
@ -107,6 +110,40 @@ const CONTROL_TARGETS = {
|
||||||
warp: { node: 'source', param: 'warp' },
|
warp: { node: 'source', param: 'warp' },
|
||||||
freq: { node: 'source', param: 'frequency' },
|
freq: { node: 'source', param: 'frequency' },
|
||||||
note: { node: 'source', param: 'frequency' },
|
note: { node: 'source', param: 'frequency' },
|
||||||
|
wtdc: { node: 'wt_lfo', param: 'dc' },
|
||||||
|
wtskew: { node: 'wt_lfo', param: 'skew' },
|
||||||
|
wtrate: { node: 'wt_lfo', param: 'frequency' },
|
||||||
|
wtsync: { node: 'wt_lfo', param: 'frequency' },
|
||||||
|
wtdepth: { node: 'wt_lfo', param: 'depth' },
|
||||||
|
warpdc: { node: 'warp_lfo', param: 'dc' },
|
||||||
|
warpskew: { node: 'warp_lfo', param: 'skew' },
|
||||||
|
warprate: { node: 'warp_lfo', param: 'frequency' },
|
||||||
|
warpsync: { node: 'warp_lfo', param: 'frequency' },
|
||||||
|
warpdepth: { node: 'warp_lfo', param: 'depth' },
|
||||||
|
fmi: { node: 'fm_1_gain', param: 'gain' },
|
||||||
|
fmi2: { node: 'fm_2_gain', param: 'gain' },
|
||||||
|
fmi3: { node: 'fm_3_gain', param: 'gain' },
|
||||||
|
fmi4: { node: 'fm_4_gain', param: 'gain' },
|
||||||
|
fmi5: { node: 'fm_5_gain', param: 'gain' },
|
||||||
|
fmi6: { node: 'fm_6_gain', param: 'gain' },
|
||||||
|
fmi7: { node: 'fm_7_gain', param: 'gain' },
|
||||||
|
fmi8: { node: 'fm_8_gain', param: 'gain' },
|
||||||
|
fmh: { node: 'fm_1', param: 'frequency' },
|
||||||
|
fmh2: { node: 'fm_2', param: 'frequency' },
|
||||||
|
fmh3: { node: 'fm_3', param: 'frequency' },
|
||||||
|
fmh4: { node: 'fm_4', param: 'frequency' },
|
||||||
|
fmh5: { node: 'fm_5', param: 'frequency' },
|
||||||
|
fmh6: { node: 'fm_6', param: 'frequency' },
|
||||||
|
fmh7: { node: 'fm_7', param: 'frequency' },
|
||||||
|
fmh8: { node: 'fm_8', param: 'frequency' },
|
||||||
|
pw: { node: 'source', param: 'pulsewidth' },
|
||||||
|
pwrate: { node: 'pw_lfo', param: 'frequency' },
|
||||||
|
pwsweep: { node: 'pw_lfo', param: 'depth' },
|
||||||
|
vib: { node: 'vib_gain', param: 'gain' },
|
||||||
|
vibmod: { node: 'vib', param: 'frequency' },
|
||||||
|
byteBeatStartTime: { node: 'source', param: 'byteBeatStartTime' },
|
||||||
|
spread: { node: 'source', param: 'panspread' },
|
||||||
|
transient: { node: 'transient', param: 'attack' },
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getSuperdoughControlTargets() {
|
export function getSuperdoughControlTargets() {
|
||||||
|
|
|
||||||
|
|
@ -52,17 +52,17 @@ export function registerSynthSounds() {
|
||||||
// turn down
|
// turn down
|
||||||
const g = gainNode(0.3);
|
const g = gainNode(0.3);
|
||||||
|
|
||||||
let sound = getOscillator(s, t, value, () => {
|
const sound = getOscillator(s, t, value, () => {
|
||||||
releaseAudioNode(g);
|
releaseAudioNode(g);
|
||||||
onended();
|
onended();
|
||||||
});
|
});
|
||||||
|
|
||||||
let { node: o, stop, triggerRelease } = sound;
|
const { node: o, nodes, stop, triggerRelease } = sound;
|
||||||
|
|
||||||
const { duration } = value;
|
const { duration } = value;
|
||||||
|
|
||||||
const envGain = gainNode(1);
|
const envGain = gainNode(1);
|
||||||
let node = o.connect(g).connect(envGain);
|
const node = o.connect(g).connect(envGain);
|
||||||
const holdEnd = t + duration;
|
const holdEnd = t + duration;
|
||||||
getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, t, holdEnd, 'linear');
|
getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, t, holdEnd, 'linear');
|
||||||
const envEnd = holdEnd + release + 0.01;
|
const envEnd = holdEnd + release + 0.01;
|
||||||
|
|
@ -70,7 +70,7 @@ export function registerSynthSounds() {
|
||||||
stop(envEnd);
|
stop(envEnd);
|
||||||
return {
|
return {
|
||||||
node,
|
node,
|
||||||
source: o,
|
nodes,
|
||||||
stop: (endTime) => {
|
stop: (endTime) => {
|
||||||
stop(endTime);
|
stop(endTime);
|
||||||
},
|
},
|
||||||
|
|
@ -140,7 +140,7 @@ export function registerSynthSounds() {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
node,
|
node,
|
||||||
source: o,
|
nodes: { source: [o] },
|
||||||
stop: (endTime) => {
|
stop: (endTime) => {
|
||||||
o.stop(endTime);
|
o.stop(endTime);
|
||||||
},
|
},
|
||||||
|
|
@ -185,8 +185,8 @@ export function registerSynthSounds() {
|
||||||
|
|
||||||
const gainAdjustment = 1 / Math.sqrt(voices);
|
const gainAdjustment = 1 / Math.sqrt(voices);
|
||||||
getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend);
|
getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend);
|
||||||
const vibratoOscillator = getVibratoOscillator(o.parameters.get('detune'), value, begin);
|
const vibratoHandle = getVibratoOscillator(o.parameters.get('detune'), value, begin);
|
||||||
const fm = applyFM(o.parameters.get('frequency'), value, begin);
|
const fmHandle = applyFM(o.parameters.get('frequency'), value, begin);
|
||||||
let envGain = gainNode(1);
|
let envGain = gainNode(1);
|
||||||
envGain = o.connect(envGain);
|
envGain = o.connect(envGain);
|
||||||
|
|
||||||
|
|
@ -197,8 +197,8 @@ export function registerSynthSounds() {
|
||||||
() => {
|
() => {
|
||||||
releaseAudioNode(o);
|
releaseAudioNode(o);
|
||||||
onended();
|
onended();
|
||||||
fm?.stop();
|
fmHandle?.stop();
|
||||||
vibratoOscillator?.stop();
|
vibratoHandle?.stop();
|
||||||
},
|
},
|
||||||
begin,
|
begin,
|
||||||
end,
|
end,
|
||||||
|
|
@ -206,7 +206,7 @@ export function registerSynthSounds() {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
node: envGain,
|
node: envGain,
|
||||||
source: o,
|
nodes: { source: [o], ...fmHandle?.nodes, ...vibratoHandle?.nodes },
|
||||||
stop: (time) => {
|
stop: (time) => {
|
||||||
timeoutNode.stop(time);
|
timeoutNode.stop(time);
|
||||||
},
|
},
|
||||||
|
|
@ -333,25 +333,25 @@ export function registerSynthSounds() {
|
||||||
);
|
);
|
||||||
|
|
||||||
getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend);
|
getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend);
|
||||||
const vibratoOscillator = getVibratoOscillator(o.parameters.get('detune'), value, begin);
|
const vibratoHandle = getVibratoOscillator(o.parameters.get('detune'), value, begin);
|
||||||
const fm = applyFM(o.parameters.get('frequency'), value, begin);
|
const fmHandle = applyFM(o.parameters.get('frequency'), value, begin);
|
||||||
let envGain = gainNode(1);
|
let envGain = gainNode(1);
|
||||||
envGain = o.connect(envGain);
|
envGain = o.connect(envGain);
|
||||||
|
|
||||||
getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 1, begin, holdend, 'linear');
|
getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 1, begin, holdend, 'linear');
|
||||||
let lfo;
|
let pw_lfo;
|
||||||
if (pwsweep != 0) {
|
if (pwsweep != 0) {
|
||||||
lfo = getLfo(ac, { frequency: pwrate, depth: pwsweep, begin, end });
|
pw_lfo = getLfo(ac, { frequency: pwrate, depth: pwsweep, begin, end });
|
||||||
lfo.connect(o.parameters.get('pulsewidth'));
|
pw_lfo.connect(o.parameters.get('pulsewidth'));
|
||||||
}
|
}
|
||||||
let timeoutNode = webAudioTimeout(
|
let timeoutNode = webAudioTimeout(
|
||||||
ac,
|
ac,
|
||||||
() => {
|
() => {
|
||||||
releaseAudioNode(o);
|
releaseAudioNode(o);
|
||||||
releaseAudioNode(lfo);
|
releaseAudioNode(pw_lfo);
|
||||||
onended();
|
onended();
|
||||||
fm?.stop();
|
fmHandle?.stop();
|
||||||
vibratoOscillator?.stop();
|
vibratoHandle?.stop();
|
||||||
},
|
},
|
||||||
begin,
|
begin,
|
||||||
end,
|
end,
|
||||||
|
|
@ -359,7 +359,7 @@ export function registerSynthSounds() {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
node: envGain,
|
node: envGain,
|
||||||
source: o,
|
nodes: { source: [o], pw_lfo: [pw_lfo], ...fmHandle?.nodes, ...vibratoHandle?.nodes },
|
||||||
stop: (time) => {
|
stop: (time) => {
|
||||||
timeoutNode.stop(time);
|
timeoutNode.stop(time);
|
||||||
},
|
},
|
||||||
|
|
@ -394,7 +394,7 @@ export function registerSynthSounds() {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
node: envGain,
|
node: envGain,
|
||||||
source: bus,
|
nodes: { source: [bus] },
|
||||||
stop: (time) => {
|
stop: (time) => {
|
||||||
timeoutNode.stop(time);
|
timeoutNode.stop(time);
|
||||||
},
|
},
|
||||||
|
|
@ -440,7 +440,7 @@ export function registerSynthSounds() {
|
||||||
stop(envEnd);
|
stop(envEnd);
|
||||||
return {
|
return {
|
||||||
node,
|
node,
|
||||||
source: o,
|
nodes: { source: [o] },
|
||||||
stop: (endTime) => {
|
stop: (endTime) => {
|
||||||
stop(endTime);
|
stop(endTime);
|
||||||
},
|
},
|
||||||
|
|
@ -520,11 +520,11 @@ export function getOscillator(s, t, value, onended) {
|
||||||
// set frequency
|
// set frequency
|
||||||
o.frequency.value = getFrequencyFromValue(value);
|
o.frequency.value = getFrequencyFromValue(value);
|
||||||
|
|
||||||
let vibratoOscillator = getVibratoOscillator(o.detune, value, t);
|
const vibratoHandle = getVibratoOscillator(o.detune, value, t);
|
||||||
|
|
||||||
// pitch envelope
|
// pitch envelope
|
||||||
getPitchEnvelope(o.detune, value, t, t + duration);
|
getPitchEnvelope(o.detune, value, t, t + duration);
|
||||||
const fmModulator = applyFM(o.frequency, value, t);
|
const fmHandle = applyFM(o.frequency, value, t);
|
||||||
|
|
||||||
let noiseMix;
|
let noiseMix;
|
||||||
if (noise) {
|
if (noise) {
|
||||||
|
|
@ -541,10 +541,10 @@ export function getOscillator(s, t, value, onended) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
node: noiseMix?.node || o,
|
node: noiseMix?.node || o,
|
||||||
source: o,
|
nodes: { source: [o], ...vibratoHandle?.nodes, ...fmHandle?.nodes },
|
||||||
stop: (time) => {
|
stop: (time) => {
|
||||||
fmModulator.stop(time);
|
fmHandle.stop(time);
|
||||||
vibratoOscillator?.stop(time);
|
vibratoHandle?.stop(time);
|
||||||
noiseMix?.stop(time);
|
noiseMix?.stop(time);
|
||||||
o.stop(time);
|
o.stop(time);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -314,19 +314,28 @@ export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) {
|
||||||
dcoffset: value.warpdc ?? 0,
|
dcoffset: value.warpdc ?? 0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const vibratoOscillator = getVibratoOscillator(source.parameters.get('detune'), value, t);
|
const vibratoHandle = getVibratoOscillator(source.parameters.get('detune'), value, t);
|
||||||
const fm = applyFM(source.parameters.get('frequency'), value, t);
|
const fmHandle = applyFM(source.parameters.get('frequency'), 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, 0.3, t, holdEnd, 'linear');
|
getParamADSR(node.gain, attack, decay, sustain, release, 0, 0.3, t, holdEnd, 'linear');
|
||||||
getPitchEnvelope(source.parameters.get('detune'), value, t, holdEnd);
|
getPitchEnvelope(source.parameters.get('detune'), value, t, holdEnd);
|
||||||
const handle = { node, source };
|
const handle = {
|
||||||
|
node,
|
||||||
|
nodes: {
|
||||||
|
source: [source],
|
||||||
|
wt_lfo: [wtPosModulators],
|
||||||
|
warp_lfo: [wtWarpModulators],
|
||||||
|
...fmHandle?.nodes,
|
||||||
|
...vibratoHandle?.nodes,
|
||||||
|
},
|
||||||
|
};
|
||||||
const timeoutNode = webAudioTimeout(
|
const timeoutNode = webAudioTimeout(
|
||||||
ac,
|
ac,
|
||||||
() => {
|
() => {
|
||||||
releaseAudioNode(source);
|
releaseAudioNode(source);
|
||||||
releaseAudioNode(vibratoOscillator);
|
vibratoHandle?.stop();
|
||||||
fm?.stop();
|
fmHandle?.stop();
|
||||||
releaseAudioNode(wtPosModulators);
|
releaseAudioNode(wtPosModulators);
|
||||||
releaseAudioNode(wtWarpModulators);
|
releaseAudioNode(wtWarpModulators);
|
||||||
onended();
|
onended();
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ export const getZZFX = (value, t) => {
|
||||||
source.start(t);
|
source.start(t);
|
||||||
return {
|
return {
|
||||||
node: source,
|
node: source,
|
||||||
source,
|
nodes: { source: [source] },
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue