Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Worklet Improvents / fixes #963

Merged
merged 15 commits into from
Mar 4, 2024
23 changes: 20 additions & 3 deletions packages/core/controls.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1276,15 +1276,33 @@ export const { roomsize, size, sz, rsize } = registerControl('roomsize', 'size',
// ['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
*
*
* @name shape
* @param {number | Pattern} distortion between 0 and 1
* @example
* s("bd sd [~ bd] sd,hh*8").shape("<0 .2 .4 .6 .8>")
*
*/
export const { shape } = registerControl('shape');
export const { shape } = registerControl(['shape', 'shapevol']);
/**
* 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
* @synonyms dist
* @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")
*
*/
export const { distort, dist } = registerControl(['distort', 'distortvol'], '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)
Expand Down Expand Up @@ -1420,7 +1438,6 @@ export const { octersubsub } = registerControl('octersubsub');
export const { ring } = registerControl('ring');
export const { ringf } = registerControl('ringf');
export const { ringdf } = registerControl('ringdf');
export const { distort } = registerControl('distort');
export const { freeze } = registerControl('freeze');
export const { xsdelay } = registerControl('xsdelay');
export const { tsdelay } = registerControl('tsdelay');
Expand Down
6 changes: 5 additions & 1 deletion packages/superdough/superdough.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,9 @@ export const superdough = async (value, deadline, hapDuration) => {
coarse,
crush,
shape,
shapevol = 1,
distort,
distortvol = 1,
pan,
vowel,
delay = 0,
Expand Down Expand Up @@ -457,7 +460,8 @@ 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 }));
shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', { shape }));
shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', { shape, postgain: shapevol }));
distort !== undefined && chain.push(getWorklet(ac, 'distort-processor', { distort, postgain: distortvol }));

compressorThreshold !== undefined &&
chain.push(
Expand Down
125 changes: 74 additions & 51 deletions packages/superdough/worklets.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// coarse, crush, and shape processors adapted from dktr0's webdirt: https://github.com/dktr0/WebDirt/blob/5ce3d698362c54d6e1b68acc47eb2955ac62c793/dist/AudioWorklets.js
// LICENSE GNU General Public License v3.0 see https://github.com/dktr0/WebDirt/blob/main/LICENSE
// all the credit goes to dktr0's webdirt: https://github.com/dktr0/WebDirt/blob/5ce3d698362c54d6e1b68acc47eb2955ac62c793/dist/AudioWorklets.js
// <3

class CoarseProcessor extends AudioWorkletProcessor {
static get parameterDescriptors() {
Expand All @@ -9,28 +8,27 @@ class CoarseProcessor extends AudioWorkletProcessor {

constructor() {
super();
this.notStarted = true;
}

process(inputs, outputs, parameters) {
const input = inputs[0];
const output = outputs[0];
const coarse = parameters.coarse;
const blockSize = 128;
const hasInput = !(input[0] === undefined);
if (hasInput) {
this.notStarted = false;
output[0][0] = input[0][0];
for (let n = 1; n < blockSize; n++) {
for (let o = 0; o < output.length; o++) {
output[o][n] = n % coarse == 0 ? input[0][n] : output[o][n - 1];
}

let coarse = parameters.coarse[0] ?? 0;
coarse = Math.max(1, coarse);

if (input[0] == null || output[0] == null) {
return false;
}
for (let n = 0; n < blockSize; n++) {
for (let i = 0; i < input.length; i++) {
output[i][n] = n % coarse === 0 ? input[i][n] : output[i][n - 1];
}
}
return this.notStarted || hasInput;
return true;
}
}

registerProcessor('coarse-processor', CoarseProcessor);

class CrushProcessor extends AudioWorkletProcessor {
Expand All @@ -40,69 +38,94 @@ class CrushProcessor extends AudioWorkletProcessor {

constructor() {
super();
this.notStarted = true;
}

process(inputs, outputs, parameters) {
const input = inputs[0];
const output = outputs[0];
const crush = parameters.crush;
const blockSize = 128;
const hasInput = !(input[0] === undefined);
if (hasInput) {
this.notStarted = false;
if (crush.length === 1) {
const x = Math.pow(2, crush[0] - 1);
for (let n = 0; n < blockSize; n++) {
const value = Math.round(input[0][n] * x) / x;
for (let o = 0; o < output.length; o++) {
output[o][n] = value;
}
}
} else {
for (let n = 0; n < blockSize; n++) {
let x = Math.pow(2, crush[n] - 1);
const value = Math.round(input[0][n] * x) / x;
for (let o = 0; o < output.length; o++) {
output[o][n] = value;
}
}

let crush = parameters.crush[0] ?? 8;
crush = Math.max(1, crush);

if (input[0] == null || output[0] == null) {
return false;
}
for (let n = 0; n < blockSize; n++) {
for (let i = 0; i < input.length; i++) {
const x = Math.pow(2, crush - 1);
output[i][n] = Math.round(input[i][n] * x) / x;
}
}
return this.notStarted || hasInput;
return true;
}
}
registerProcessor('crush-processor', CrushProcessor);

class ShapeProcessor extends AudioWorkletProcessor {
static get parameterDescriptors() {
return [{ name: 'shape', defaultValue: 0 }];
return [
{ name: 'shape', defaultValue: 0 },
{ name: 'postgain', defaultValue: 1 },
];
}

constructor() {
super();
this.notStarted = true;
}

process(inputs, outputs, parameters) {
const input = inputs[0];
const output = outputs[0];
const shape0 = parameters.shape[0];
const shape1 = shape0 < 1 ? shape0 : 1.0 - 4e-10;
const shape = (2.0 * shape1) / (1.0 - shape1);
const blockSize = 128;
const hasInput = !(input[0] === undefined);
if (hasInput) {
this.notStarted = false;
for (let n = 0; n < blockSize; n++) {
const value = ((1 + shape) * input[0][n]) / (1 + shape * Math.abs(input[0][n]));
for (let o = 0; o < output.length; o++) {
output[o][n] = value;
}

let shape = parameters.shape[0];
shape = shape < 1 ? shape : 1.0 - 4e-10;
shape = (2.0 * shape) / (1.0 - shape);
const postgain = Math.max(0.001, Math.min(1, parameters.postgain[0]));

if (input[0] == null || output[0] == null) {
return false;
}
for (let n = 0; n < blockSize; n++) {
for (let i = 0; i < input.length; i++) {
output[i][n] = (((1 + shape) * input[i][n]) / (1 + shape * Math.abs(input[i][n]))) * postgain;
}
}
return this.notStarted || hasInput;
return true;
}
}

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) {
const input = inputs[0];
const output = outputs[0];
const blockSize = 128;

const shape = Math.expm1(parameters.distort[0]);
const postgain = Math.max(0.001, Math.min(1, parameters.postgain[0]));

if (input[0] == null || output[0] == null) {
return false;
}
for (let n = 0; n < blockSize; n++) {
for (let i = 0; i < input.length; i++) {
output[i][n] = (((1 + shape) * input[i][n]) / (1 + shape * Math.abs(input[i][n]))) * postgain;
}
}
return true;
}
}
registerProcessor('distort-processor', DistortProcessor);
90 changes: 90 additions & 0 deletions test/__snapshots__/examples.test.mjs.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,96 @@ exports[`runs examples > example "detune" example index 0 1`] = `
]
`;

exports[`runs examples > example "distort" example index 0 1`] = `
[
"[ 0/1 → 1/8 | s:hh distort:0 ]",
"[ 0/1 → 1/4 | s:bd distort:0 ]",
"[ 1/8 → 1/4 | s:hh distort:0 ]",
"[ 1/4 → 3/8 | s:hh distort:0 ]",
"[ 1/4 → 1/2 | s:sd distort:0 ]",
"[ 3/8 → 1/2 | s:hh distort:0 ]",
"[ 1/2 → 5/8 | s:hh distort:0 ]",
"[ 5/8 → 3/4 | s:bd distort:0 ]",
"[ 5/8 → 3/4 | s:hh distort:0 ]",
"[ 3/4 → 7/8 | s:hh distort:0 ]",
"[ 3/4 → 1/1 | s:sd distort:0 ]",
"[ 7/8 → 1/1 | s:hh distort:0 ]",
"[ 1/1 → 9/8 | s:hh distort:2 ]",
"[ 1/1 → 5/4 | s:bd distort:2 ]",
"[ 9/8 → 5/4 | s:hh distort:2 ]",
"[ 5/4 → 11/8 | s:hh distort:2 ]",
"[ 5/4 → 3/2 | s:sd distort:2 ]",
"[ 11/8 → 3/2 | s:hh distort:2 ]",
"[ 3/2 → 13/8 | s:hh distort:2 ]",
"[ 13/8 → 7/4 | s:bd distort:2 ]",
"[ 13/8 → 7/4 | s:hh distort:2 ]",
"[ 7/4 → 15/8 | s:hh distort:2 ]",
"[ 7/4 → 2/1 | s:sd distort:2 ]",
"[ 15/8 → 2/1 | s:hh distort:2 ]",
"[ 2/1 → 17/8 | s:hh distort:3 ]",
"[ 2/1 → 9/4 | s:bd distort:3 ]",
"[ 17/8 → 9/4 | s:hh distort:3 ]",
"[ 9/4 → 19/8 | s:hh distort:3 ]",
"[ 9/4 → 5/2 | s:sd distort:3 ]",
"[ 19/8 → 5/2 | s:hh distort:3 ]",
"[ 5/2 → 21/8 | s:hh distort:3 ]",
"[ 21/8 → 11/4 | s:bd distort:3 ]",
"[ 21/8 → 11/4 | s:hh distort:3 ]",
"[ 11/4 → 23/8 | s:hh distort:3 ]",
"[ 11/4 → 3/1 | s:sd distort:3 ]",
"[ 23/8 → 3/1 | s:hh distort:3 ]",
"[ 3/1 → 25/8 | s:hh distort:10 distortvol:0.5 ]",
"[ 3/1 → 13/4 | s:bd distort:10 distortvol:0.5 ]",
"[ 25/8 → 13/4 | s:hh distort:10 distortvol:0.5 ]",
"[ 13/4 → 27/8 | s:hh distort:10 distortvol:0.5 ]",
"[ 13/4 → 7/2 | s:sd distort:10 distortvol:0.5 ]",
"[ 27/8 → 7/2 | s:hh distort:10 distortvol:0.5 ]",
"[ 7/2 → 29/8 | s:hh distort:10 distortvol:0.5 ]",
"[ 29/8 → 15/4 | s:bd distort:10 distortvol:0.5 ]",
"[ 29/8 → 15/4 | s:hh distort:10 distortvol:0.5 ]",
"[ 15/4 → 31/8 | s:hh distort:10 distortvol:0.5 ]",
"[ 15/4 → 4/1 | s:sd distort:10 distortvol:0.5 ]",
"[ 31/8 → 4/1 | s:hh distort:10 distortvol:0.5 ]",
]
`;

exports[`runs examples > example "distort" example index 1 1`] = `
[
"[ 0/1 → 1/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 1/8 → 1/4 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 1/4 → 3/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 3/8 → 1/2 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 1/2 → 5/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 5/8 → 3/4 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 3/4 → 7/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 7/8 → 1/1 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 1/1 → 9/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 9/8 → 5/4 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 5/4 → 11/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 11/8 → 3/2 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 3/2 → 13/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 13/8 → 7/4 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 7/4 → 15/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 15/8 → 2/1 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 2/1 → 17/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 17/8 → 9/4 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 9/4 → 19/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 19/8 → 5/2 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 5/2 → 21/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 21/8 → 11/4 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 11/4 → 23/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 23/8 → 3/1 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 3/1 → 25/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 25/8 → 13/4 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 13/4 → 27/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 27/8 → 7/2 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 7/2 → 29/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 29/8 → 15/4 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 15/4 → 31/8 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
"[ 31/8 → 4/1 | note:d1 s:sine penv:36 pdecay:0.12 decay:0.23 distort:8 distortvol:0.4 ]",
]
`;

exports[`runs examples > example "djf" example index 0 1`] = `
[
"[ 0/1 → 1/4 | n:0 s:superzow octave:3 djf:0.5 ]",
Expand Down
Loading