From 1221c6144ca314fb3e80766f89b8bb93cb1a6b0d Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 28 Feb 2024 14:31:07 -0500 Subject: [PATCH] added distortion effect --- packages/core/controls.mjs | 22 +++++++++++++++++----- packages/superdough/superdough.mjs | 11 +++++++++-- packages/superdough/worklets.mjs | 28 +++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index c034f1b5..42f4648a 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1214,19 +1214,31 @@ const generic_params = [ // ['sclaves'], // ['scrash'], /** - * Wave shaping distortion. CAUTION: it might get loud + * (Deprecated) Wave shaping distortion. WARNING: can suddenly get unpredictably loud. + * Please use distort instead, which has a more predictable response curve * second option in optional array syntax (ex: ".9:.5") applies a postgain to the output - * most useful shape values are usually between 0 and 10 (depending on source gain) * * @name shape * @param {number | Pattern} distortion between 0 and 1 * @example - * s("bd sd [~ bd] sd,hh*8").shape("<0 2 3 10:.5>") - * @example - * note("d1!8").s("sine").penv(36).pdecay(.12).decay(.23).shape("8:.4") + * s("bd sd [~ bd] sd,hh*8").shape("<0 .2 .3 .95:.5>") * */ ['shape'], + + /** + * Wave shaping distortion. CAUTION: it can get loud. + * Second option in optional array syntax (ex: ".9:.5") applies a postgain to the output. + * Most useful values are usually between 0 and 10 (depending on source gain). If you are feeling adventurous, you can turn it up to 11 and beyond ;) + * @name distort + * @param {number | Pattern} distortion + * @example + * s("bd sd [~ bd] sd,hh*8").distort("<0 2 3 10:.5>") + * @example + * note("d1!8").s("sine").penv(36).pdecay(.12).decay(.23).distort("8:.4") + * + */ + ['distort', 'dist'], /** * Dynamics Compressor. The params are `compressor("threshold:ratio:knee:attack:release")` * More info [here](https://developer.mozilla.org/en-US/docs/Web/API/DynamicsCompressorNode?retiredLocale=de#instance_properties) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 2eb42720..795354ad 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -311,6 +311,7 @@ export const superdough = async (value, deadline, hapDuration) => { coarse, crush, shape, + distort, pan, vowel, delay = 0, @@ -452,8 +453,14 @@ export const superdough = async (value, deadline, hapDuration) => { // effects coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse })); crush !== undefined && chain.push(getWorklet(ac, 'crush-processor', { crush })); - const shapeInput = Array.isArray(shape) ? { shape: shape[0], postgain: shape[1] } : { shape }; - shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', shapeInput)); + if (shape !== undefined) { + const input = Array.isArray(shape) ? { shape: shape[0], postgain: shape[1] } : { shape }; + chain.push(getWorklet(ac, 'shape-processor', input)); + } + if (distort !== undefined) { + const input = Array.isArray(distort) ? { distort: distort[0], postgain: distort[1] } : { distort }; + chain.push(getWorklet(ac, 'distort-processor', input)); + } compressorThreshold !== undefined && chain.push( diff --git a/packages/superdough/worklets.mjs b/packages/superdough/worklets.mjs index 25885ce6..3f6d7ac9 100644 --- a/packages/superdough/worklets.mjs +++ b/packages/superdough/worklets.mjs @@ -75,7 +75,8 @@ class ShapeProcessor extends AudioWorkletProcessor { process(inputs, outputs, parameters) { let shape = parameters.shape[0]; const postgain = Math.max(0.001, Math.min(1, parameters.postgain[0])); - shape = Math.expm1(shape * 5); + shape = shape < 1 ? shape : 1.0 - 4e-10; + shape = (2.0 * shape) / (1.0 - shape); return processSample(inputs, outputs, (block) => { const val = ((1 + shape) * block) / (1 + shape * Math.abs(block)); return val * postgain; @@ -84,3 +85,28 @@ class ShapeProcessor extends AudioWorkletProcessor { } registerProcessor('shape-processor', ShapeProcessor); + +class DistortProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [ + { name: 'distort', defaultValue: 0 }, + { name: 'postgain', defaultValue: 1 }, + ]; + } + + constructor() { + super(); + } + + process(inputs, outputs, parameters) { + let shape = parameters.distort[0]; + const postgain = Math.max(0.001, Math.min(1, parameters.postgain[0])); + shape = Math.expm1(shape); + return processSample(inputs, outputs, (block) => { + const val = ((1 + shape) * block) / (1 + shape * Math.abs(block)); + return val * postgain; + }); + } +} + +registerProcessor('distort-processor', DistortProcessor);