From 476bda812e93380d633800d0a99ab280e914ed39 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Fri, 17 Nov 2023 12:55:17 +0100 Subject: [PATCH 1/4] Initial work on crackle --- packages/superdough/noise.mjs | 17 +++++++++++++---- packages/superdough/synth.mjs | 4 ++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/superdough/noise.mjs b/packages/superdough/noise.mjs index 2c8c1d4a..6a2d418c 100644 --- a/packages/superdough/noise.mjs +++ b/packages/superdough/noise.mjs @@ -4,7 +4,7 @@ import { getAudioContext } from './superdough.mjs'; let noiseCache = {}; // lazy generates noise buffers and keeps them forever -function getNoiseBuffer(type) { +function getNoiseBuffer(type, density) { const ac = getAudioContext(); if (noiseCache[type]) { return noiseCache[type]; @@ -34,17 +34,26 @@ function getNoiseBuffer(type) { output[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362; output[i] *= 0.11; b6 = white * 0.115926; + } else if (type === 'crackle') { + if (Math.random() < (Math.random() * (density - 0.001) + density).toFixed(4)) { + output[i] = Math.random() * 2 - 1; + } else { + output[i] = 0; + } } } - noiseCache[type] = noiseBuffer; + + // Prevent caching to randomize crackles + if (type !== "crackle") + noiseCache[type] = noiseBuffer; return noiseBuffer; } // expects one of noises as type -export function getNoiseOscillator(type = 'white', t) { +export function getNoiseOscillator(type = 'white', t, density = 0.02) { const ac = getAudioContext(); const o = ac.createBufferSource(); - o.buffer = getNoiseBuffer(type); + o.buffer = getNoiseBuffer(type, density); o.loop = true; o.start(t); return { diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index dafc2e7c..53f462d5 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -22,7 +22,7 @@ const fm = (osc, harmonicityRatio, modulationIndex, wave = 'sine') => { }; const waveforms = ['sine', 'square', 'triangle', 'sawtooth']; -const noises = ['pink', 'white', 'brown']; +const noises = ['pink', 'white', 'brown', 'crackle']; export function registerSynthSounds() { [...waveforms, ...noises].forEach((s) => { @@ -36,7 +36,7 @@ export function registerSynthSounds() { if (waveforms.includes(s)) { sound = getOscillator(s, t, value); } else { - sound = getNoiseOscillator(s, t); + sound = getNoiseOscillator(s, t, 0.002); } let { node: o, stop, triggerRelease } = sound; From fb28083ce616de5b3a14e36a9cc415d6802b5be8 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Fri, 17 Nov 2023 13:18:49 +0100 Subject: [PATCH 2/4] Fixing density and adding documentation --- packages/core/controls.mjs | 15 +++++++++++++-- packages/superdough/noise.mjs | 3 ++- packages/superdough/superdough.mjs | 1 + packages/superdough/synth.mjs | 3 ++- website/src/pages/learn/synths.mdx | 4 ++++ 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index a03658a8..a14f06df 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1214,6 +1214,17 @@ const generic_params = [ * @name waveloss */ ['waveloss'], + /* + * + * Noise crackle density + * + * @name density + * @param {number | Pattern} density between 0 and x + * @example + * s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(4)) + * + */ + ['density'], // TODO: midi effects? ['dur'], // ['modwheel'], @@ -1308,7 +1319,7 @@ const generic_params = [ ]; // TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13 -controls.createParam = function (names) { +controls.createParam = function(names) { const name = Array.isArray(names) ? names[0] : names; var withVal; @@ -1332,7 +1343,7 @@ controls.createParam = function (names) { const func = (...pats) => sequence(...pats).withValue(withVal); - const setter = function (...pats) { + const setter = function(...pats) { if (!pats.length) { return this.fmap(withVal); } diff --git a/packages/superdough/noise.mjs b/packages/superdough/noise.mjs index 6a2d418c..8993f470 100644 --- a/packages/superdough/noise.mjs +++ b/packages/superdough/noise.mjs @@ -35,7 +35,8 @@ function getNoiseBuffer(type, density) { output[i] *= 0.11; b6 = white * 0.115926; } else if (type === 'crackle') { - if (Math.random() < (Math.random() * (density - 0.001) + density).toFixed(4)) { + const probability = density * 0.01 + if (Math.random() < probability) { output[i] = Math.random() * 2 - 1; } else { output[i] = 0; diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 00e2f42c..ed133366 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -241,6 +241,7 @@ export const superdough = async (value, deadline, hapDuration) => { source, gain = 0.8, postgain = 1, + density = 0.03, // filters ftype = '12db', fanchor = 0.5, diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 53f462d5..edc3c01e 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -36,7 +36,8 @@ export function registerSynthSounds() { if (waveforms.includes(s)) { sound = getOscillator(s, t, value); } else { - sound = getNoiseOscillator(s, t, 0.002); + let { density } = value; + sound = getNoiseOscillator(s, t, density); } let { node: o, stop, triggerRelease } = sound; diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index 432276ef..abb74c2f 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -42,6 +42,10 @@ Some amount of pink noise can also be added to any oscillator by using the `nois ").scope()`} /> +You can also use the `crackle` type to play some subtle noise crackles. You can control noise amount by using the `density` parameter: + + + ### Additive Synthesis To tame the harsh sound of the basic waveforms, we can set the `n` control to limit the overtones of the waveform: From 2a18df61cda07a2e4328b53fddd27e091293861a Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Fri, 17 Nov 2023 13:23:54 +0100 Subject: [PATCH 3/4] Fix documentation --- packages/core/controls.mjs | 1 - website/src/pages/learn/synths.mdx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index a14f06df..1cd69e81 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1215,7 +1215,6 @@ const generic_params = [ */ ['waveloss'], /* - * * Noise crackle density * * @name density diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index abb74c2f..d6ac5061 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -44,7 +44,7 @@ Some amount of pink noise can also be added to any oscillator by using the `nois You can also use the `crackle` type to play some subtle noise crackles. You can control noise amount by using the `density` parameter: - +".slow(4)).scope()`} /> ### Additive Synthesis From 6e92c4915aaad88590fbb8d9ff0b3c8e398d28f7 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Fri, 17 Nov 2023 13:37:16 +0100 Subject: [PATCH 4/4] Run prettier --- packages/core/controls.mjs | 4 ++-- packages/superdough/noise.mjs | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 1cd69e81..6449969e 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1318,7 +1318,7 @@ const generic_params = [ ]; // TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13 -controls.createParam = function(names) { +controls.createParam = function (names) { const name = Array.isArray(names) ? names[0] : names; var withVal; @@ -1342,7 +1342,7 @@ controls.createParam = function(names) { const func = (...pats) => sequence(...pats).withValue(withVal); - const setter = function(...pats) { + const setter = function (...pats) { if (!pats.length) { return this.fmap(withVal); } diff --git a/packages/superdough/noise.mjs b/packages/superdough/noise.mjs index 8993f470..24779470 100644 --- a/packages/superdough/noise.mjs +++ b/packages/superdough/noise.mjs @@ -35,7 +35,7 @@ function getNoiseBuffer(type, density) { output[i] *= 0.11; b6 = white * 0.115926; } else if (type === 'crackle') { - const probability = density * 0.01 + const probability = density * 0.01; if (Math.random() < probability) { output[i] = Math.random() * 2 - 1; } else { @@ -45,8 +45,7 @@ function getNoiseBuffer(type, density) { } // Prevent caching to randomize crackles - if (type !== "crackle") - noiseCache[type] = noiseBuffer; + if (type !== 'crackle') noiseCache[type] = noiseBuffer; return noiseBuffer; }