From 9cbf3079f3bca2bc7cb2ee2192d86c883514a369 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Mon, 6 Nov 2023 19:02:09 -0500 Subject: [PATCH] change to bus effect experiment --- packages/core/controls.mjs | 16 ++++-- packages/superdough/phaser.mjs | 21 ++++---- packages/superdough/superdough.mjs | 82 ++++++++++++++++++++++++++++-- 3 files changed, 102 insertions(+), 17 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index a616ce06..e3fa8be1 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -382,15 +382,25 @@ const generic_params = [ ['coarse'], /** - * fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers + * Phaser audio effect that approximates popular guitar pedals. * * @name phaser - * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on. + * @param {number | Pattern} speed speed of modulation * @example - * s("bd sd,hh*4").coarse("<1 4 8 16 32>") + * run(8).scale("D:pentatonic").note().sound("sawtooth").phaser("2 8").release(0.5) * */ ['phaser'], + /** + * + * + * @name phaserDepth + * @param {number | Pattern} depth number between 0 and 1 + * @example + * run(8).scale("D:pentatonic").note().sound("sawtooth").phaser("2 8").phaserDepth(0.5).release(0.5) + * + */ + ['phaserDepth'], /** * choose the channel the pattern is sent to in superdirt * diff --git a/packages/superdough/phaser.mjs b/packages/superdough/phaser.mjs index bdb64c40..9aadc532 100644 --- a/packages/superdough/phaser.mjs +++ b/packages/superdough/phaser.mjs @@ -1,10 +1,10 @@ const createFilter = (ctx, cutoff, Q) => { - const lowpassFilter = ctx.createBiquadFilter(); - lowpassFilter.type = 'notch'; - lowpassFilter.gain.value = 1; - lowpassFilter.frequency.value = cutoff; - lowpassFilter.Q.value = Q; - return lowpassFilter; + const filter = ctx.createBiquadFilter(); + filter.type = 'notch'; + filter.gain.value = 1; + filter.frequency.value = cutoff; + filter.Q.value = Q; + return filter; }; const createOscillator = (ctx, freq) => { @@ -26,12 +26,15 @@ const createLFO = (ctx, freq, gain) => { osc.connect(gainNode); return gainNode; }; + if (typeof GainNode !== 'undefined') { class PhaserNode extends GainNode { - constructor(ac, speed, cps) { + constructor(ac, input) { super(ac); this.lfo; - console.log(cps); + + const { speed, depth = 0.5 } = input; + console.log(depth); const makeupGain = ac.createGain(); @@ -43,7 +46,7 @@ if (typeof GainNode !== 'undefined') { for (let i = 0; i < numStages; i++) { const gain = ac.createGain(); gain.gain.value = 1 / numStages; - const filter = createFilter(ac, 1000 + fOffset, 0.5); + const filter = createFilter(ac, 1000 + fOffset, 2 - Math.min(Math.max(depth * 2, 0), 1.9)); this.connect(filter); this.lfo.connect(filter.detune); filter.connect(gain); diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 5473cc12..8ea28340 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -113,6 +113,71 @@ function getDelay(orbit, delaytime, delayfeedback, t) { return delays[orbit]; } +const createFilter2 = (ctx, cutoff, Q) => { + const filter = ctx.createBiquadFilter(); + filter.type = 'notch'; + filter.gain.value = 1; + filter.frequency.value = cutoff; + filter.Q.value = Q; + return filter; +}; + +const createOscillator = (ctx, freq) => { + const osc = ctx.createOscillator(); + osc.frequency.value = freq; + osc.type = 'sine'; + return osc; +}; +const createGain = (ctx, gain) => { + const gainNode = ctx.createGain(); + gainNode.gain.value = gain; + return gainNode; +}; + +const createLFO = (ctx, freq, gain) => { + const osc = createOscillator(ctx, freq); + const gainNode = createGain(ctx, gain); + osc.start(); + osc.connect(gainNode); + return gainNode; +}; + +let phasers = {}; + +function getPhaser(orbit, speed = 1, depth = 0.5) { + if (!delays[orbit]) { + const ac = getAudioContext(); + + let lfo; + + const makeupGain = ac.createGain(); + + if (lfo == null) { + lfo = createLFO(ac, speed, 2000); + } + const numStages = 2; + let fOffset = 0; + for (let i = 0; i < numStages; i++) { + const gain = ac.createGain(); + gain.gain.value = 1 / numStages; + const filter = createFilter2(ac, 1000 + fOffset, 2 - Math.min(Math.max(depth * 2, 0), 1.9)); + makeupGain.connect(filter); + lfo.connect(filter.detune); + filter.connect(gain); + gain.connect(makeupGain); + fOffset += 200 + Math.pow(i, 2); + } + makeupGain.gain.value = 1; // how much makeup gain to add? + + makeupGain.connect(getDestination()); + phasers[orbit] = makeupGain; + } + console.log(phasers); + // delays[orbit].delayTime.value !== delaytime && delays[orbit].delayTime.setValueAtTime(delaytime, t); + // delays[orbit].feedback.value !== delayfeedback && delays[orbit].feedback.setValueAtTime(delayfeedback, t); + return phasers[orbit]; +} + let reverbs = {}; let hasChanged = (now, before) => now !== undefined && now !== before; @@ -230,6 +295,7 @@ export const superdough = async (value, deadline, hapDuration) => { //phaser phaser, + phaserDepth, // coarse, crush, @@ -365,10 +431,10 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(vowelFilter); } - if (phaser !== undefined) { - const phaserFX = ac.createPhaser(phaser, hapDuration); - chain.push(phaserFX); - } + // if (phaser !== undefined) { + // const phaserFX = ac.createPhaser({ speed: phaser, depth: phaserDepth }); + // chain.push(phaserFX); + // } // effects coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse })); @@ -393,6 +459,12 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(post); post.connect(getDestination()); + let phaserSend; + if (phaser != null) { + const phaserFX = getPhaser(orbit, phaser, phaserDepth); + + phaserSend = effectSend(post, phaserFX, 0.99); + } // delay let delaySend; if (delay > 0 && delaytime > 0 && delayfeedback > 0) { @@ -429,7 +501,7 @@ export const superdough = async (value, deadline, hapDuration) => { // toDisconnect = all the node that should be disconnected in onended callback // this is crucial for performance - toDisconnect = chain.concat([delaySend, reverbSend, analyserSend]); + toDisconnect = chain.concat([phaserSend, delaySend, reverbSend, analyserSend]); }; export const superdoughTrigger = (t, hap, ct, cps) => superdough(hap, t - ct, hap.duration / cps, cps);