From 38908baccd3ce9a3890f91e284cd1a0846284d5f Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Tue, 6 May 2025 01:06:37 -0400 Subject: [PATCH] working --- packages/core/controls.mjs | 43 ++++++++++++++++++++++++++++++ packages/superdough/superdough.mjs | 20 +++++++------- packages/superdough/synth.mjs | 25 ++++++++++++++--- 3 files changed, 73 insertions(+), 15 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index a6c650e0..2a655eed 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -458,6 +458,49 @@ export const { drive } = registerControl('drive'); */ export const { channels, ch } = registerControl('channels', 'ch'); +/** + * controls the pulsewidth of the pulse oscillator + * + * @name pw + * @param {number | Pattern} pulsewidth + * @example + * note("{f a c e}%16").s("pulse").pw(".8:1:.2") + * @example + * n(run(8)).scale("D:pentatonic").s("pulse").pw("0 .75 .5 1") + */ +export const { pw } = registerControl( + ['pw', 'pwrate', 'pwsweep'], +); + +/** + * controls the lfo rate for the pulsewidth of the pulse oscillator + * + * @name pwrate + * @param {number | Pattern} rate + * @example + * n(run(8)).scale("D:pentatonic").s("pulse").pw("0.5").pwrate("<5 .1 25>").pwsweep("<0.3 .8>") + + * + */ +export const { pwrate } = registerControl( + 'pwrate' +); + + +/** + * controls the lfo sweep for the pulsewidth of the pulse oscillator + * + * @name pwsweep + * @param {number | Pattern} sweep + * @example + * n(run(8)).scale("D:pentatonic").s("pulse").pw("0.5").pwrate("<5 .1 25>").pwsweep("<0.3 .8>") + * + */ +export const { pwsweep } = registerControl( + 'pwsweep' +); + + /** * Phaser audio effect that approximates popular guitar pedals. * diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index a1dc30b7..1bce0d79 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -307,16 +307,9 @@ function getDelay(orbit, delaytime, delayfeedback, t) { return delays[orbit]; } -function getPhaser(time, end, frequency = 1, depth = 0.5, centerFrequency = 1000, sweep = 2000) { - //gain - const ac = getAudioContext(); - const lfoGain = ac.createGain(); - lfoGain.gain.value = sweep * 2; - // centerFrequency = centerFrequency * 2; - // sweep = sweep * 1.5; - - const lfo = getWorklet(ac, 'lfo-processor', { - frequency, +export function getLfo(audioContext, time, end, properties = {}) { + return getWorklet(audioContext, 'lfo-processor', { + frequency: 1, depth: 1, skew: 0, phaseoffset: 0, @@ -324,8 +317,13 @@ function getPhaser(time, end, frequency = 1, depth = 0.5, centerFrequency = 1000 end, shape: 1, dcoffset: -0.5, + ...properties }); - lfo.connect(lfoGain); +} + +function getPhaser(time, end, frequency = 1, depth = 0.5, centerFrequency = 1000, sweep = 2000) { + const ac = getAudioContext(); + const lfoGain = getLfo(ac, time, end, { frequency, depth: sweep * 2 }) //filters const numStages = 2; //num of filters in series diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 8bb47bb7..78712c4e 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -1,5 +1,5 @@ import { clamp, midiToFreq, noteToMidi } from './util.mjs'; -import { registerSound, getAudioContext } from './superdough.mjs'; +import { registerSound, getAudioContext, getLfo } from './superdough.mjs'; import { applyFM, gainNode, @@ -145,7 +145,20 @@ export function registerSynthSounds() { 'pulse', (begin, value, onended) => { const ac = getAudioContext(); - let { duration, n: pulsewidth = 0.5 } = value; + let { pwrate, pwsweep } = value; + if (pwsweep == null) { + if (pwrate != null) { + pwsweep = 0.3 + } else { + pwsweep = 0 + } + } + + if (pwrate == null && pwsweep != null) { + pwrate = 1 + } + + let { duration, pw: pulsewidth = value.n ?? 0.5, } = value; const frequency = getFrequencyFromValue(value); const [attack, decay, sustain, release] = getADSRValues( @@ -153,10 +166,8 @@ export function registerSynthSounds() { 'linear', [0.001, 0.05, 0.6, 0.01], ); - const holdend = begin + duration; const end = holdend + release + 0.01; - let o = getWorklet( ac, 'pulse-oscillator', @@ -179,10 +190,16 @@ export function registerSynthSounds() { getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 1, begin, holdend, 'linear'); + + if (pwsweep != 0) { + let lfo = getLfo(ac, begin, end, { frequency: pwrate, depth: pwsweep, }) + lfo.connect(o.parameters.get('pulsewidth')) + } let timeoutNode = webAudioTimeout( ac, () => { destroyAudioWorkletNode(o); + destroyAudioWorkletNode(lfo); envGain.disconnect(); onended(); fm?.stop();