migrate to encapsulated out
This commit is contained in:
parent
5c99b72e2f
commit
d092068bd2
1 changed files with 197 additions and 172 deletions
|
|
@ -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));
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue