migrate to encapsulated out

This commit is contained in:
Felix Roos 2022-09-22 20:24:59 +02:00
parent 5c99b72e2f
commit d092068bd2

View file

@ -23,6 +23,21 @@ export const getAudioContext = () => {
return audioContext; return audioContext;
}; };
let destination;
export const getDestination = () => {
const ctx = getAudioContext();
if (!destination) {
destination = ctx.createGain();
destination.connect(ctx.destination);
}
return destination;
};
export const panic = () => {
getDestination().gain.linearRampToValueAtTime(0, getAudioContext().currentTime + 0.01);
destination = null;
};
const getFilter = (type, frequency, Q) => { const getFilter = (type, frequency, Q) => {
const filter = getAudioContext().createBiquadFilter(); const filter = getAudioContext().createBiquadFilter();
filter.type = type; filter.type = type;
@ -99,7 +114,7 @@ const getSampleBufferSource = async (s, n, note) => {
} }
const bank = samples?.[s]; const bank = samples?.[s];
if (!bank) { if (!bank) {
throw new Error('sample not found:', s, 'try one of ' + Object.keys(samples)); throw new Error(`sample not found: "${s}", try one of ${Object.keys(samples).join(', ')}`);
} }
if (typeof bank !== 'object') { if (typeof bank !== 'object') {
throw new Error('wrong format for sample bank:', s); throw new Error('wrong format for sample bank:', s);
@ -172,13 +187,17 @@ function gainNode(value) {
} }
const cutGroups = []; const cutGroups = [];
Pattern.prototype.out = function () { // export const webaudioOutput = async (t, hap, ct, cps) => {
return this.onTrigger(async (t, hap, ct, cps) => { export const webaudioOutput = async (hap, deadline, hapDuration) => {
const hapDuration = hap.duration / cps;
try { try {
const ac = getAudioContext(); const ac = getAudioContext();
if (typeof hap.value !== 'object') {
throw new Error(
`hap.value ${hap.value} is not supported by webaudio output. Hint: append .note() or .s() to the end`,
);
}
// calculate correct time (tone.js workaround) // calculate correct time (tone.js workaround)
t = ac.currentTime + t - ct; let t = ac.currentTime + deadline;
// destructure value // destructure value
let { let {
freq, freq,
@ -306,8 +325,10 @@ Pattern.prototype.out = function () {
const adsr = getADSR(attack, decay, sustain, release, 1, t, t + duration); const adsr = getADSR(attack, decay, sustain, release, 1, t, t + duration);
chain.push(adsr); chain.push(adsr);
} }
// level down before effects // master out
chain.push(gainNode(gain)); const master = ac.createGain();
master.gain.value = gain;
chain.push(master);
// filters // filters
cutoff !== undefined && chain.push(getFilter('lowpass', cutoff, resonance)); cutoff !== undefined && chain.push(getFilter('lowpass', cutoff, resonance));
@ -324,18 +345,18 @@ Pattern.prototype.out = function () {
panner.pan.value = 2 * pan - 1; panner.pan.value = 2 * pan - 1;
chain.push(panner); chain.push(panner);
} }
// last gain // last gain
const post = gainNode(1); const post = gainNode(1);
chain.push(post); chain.push(post);
post.connect(ac.destination);
post.connect(getDestination());
if (delay > 0 && delaytime > 0 && delayfeedback > 0) { if (delay > 0 && delaytime > 0 && delayfeedback > 0) {
const dly = ac.createFeedbackDelay(delay, delaytime, delayfeedback); const dly = ac.createFeedbackDelay(delay, delaytime, delayfeedback);
dly.start(t); dly.start(t);
post.connect(dly); post.connect(dly);
dly.connect(ac.destination); dly.connect(getDestination());
} }
// 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]);
// disconnect all nodes when source node has ended: // disconnect all nodes when source node has ended:
@ -343,5 +364,9 @@ Pattern.prototype.out = function () {
} catch (e) { } catch (e) {
console.warn('.out error:', e); console.warn('.out error:', e);
} }
}); };
Pattern.prototype.out = function () {
// TODO: refactor (t, hap, ct, cps) to (hap, deadline, duration) ?
return this.onTrigger((t, hap, ct, cps) => webaudioOutput(hap, t - ct, hap.duration / cps));
}; };