From fde0da3b195c0c2863aca24668fc3e2198504376 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 3 Apr 2024 22:43:35 +0200 Subject: [PATCH 01/34] dont ignore hydra.mjs in eslint + fix lint --- .eslintignore | 1 - packages/hydra/hydra.mjs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.eslintignore b/.eslintignore index 7d807b65..9f6d5035 100644 --- a/.eslintignore +++ b/.eslintignore @@ -20,5 +20,4 @@ vite.config.js **/dist /src-tauri/target/**/* reverbGen.mjs -hydra.mjs jsdoc-synonyms.js \ No newline at end of file diff --git a/packages/hydra/hydra.mjs b/packages/hydra/hydra.mjs index 13d08de6..91401034 100644 --- a/packages/hydra/hydra.mjs +++ b/packages/hydra/hydra.mjs @@ -1,5 +1,5 @@ import { getDrawContext } from '@strudel/draw'; -import { controls } from '@strudel/core'; +import { controls, getTime } from '@strudel/core'; let latestOptions; let hydra; @@ -27,6 +27,7 @@ export async function initHydra(options = {}) { hydraConfig.canvas = canvas; await import(/* @vite-ignore */ src); + /* eslint-disable-next-line */ hydra = new Hydra(hydraConfig); if (feedStrudel) { const { canvas } = getDrawContext(); From d06b70c28d3e153a727653c38c3f0b56884e1cba Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 3 Apr 2024 23:02:42 +0200 Subject: [PATCH 02/34] fix: call setTime in initStrudel + return promise with scheduler --- packages/web/web.mjs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/web/web.mjs b/packages/web/web.mjs index 660acf26..2c07d2a6 100644 --- a/packages/web/web.mjs +++ b/packages/web/web.mjs @@ -5,7 +5,7 @@ export * from '@strudel/transpiler'; export * from '@strudel/mini'; export * from '@strudel/tonal'; export * from '@strudel/webaudio'; -import { Pattern, evalScope } from '@strudel/core'; +import { Pattern, evalScope, setTime } from '@strudel/core'; import { initAudioOnFirstClick, registerSynthSounds, webaudioScheduler } from '@strudel/webaudio'; // import { registerSoundfonts } from '@strudel/soundfonts'; import { evaluate as _evaluate } from '@strudel/transpiler'; @@ -33,11 +33,14 @@ export function initStrudel(options = {}) { miniAllStrings(); const { prebake, ...schedulerOptions } = options; + scheduler = webaudioScheduler(schedulerOptions); initDone = (async () => { await defaultPrebake(); await prebake?.(); + return scheduler; })(); - scheduler = webaudioScheduler(schedulerOptions); + setTime(() => scheduler.now()); + return initDone; } window.initStrudel = initStrudel; From 610c848ff4632b1924f5b78b8651d190e21ae906 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 3 Apr 2024 23:06:02 +0200 Subject: [PATCH 03/34] fix: reify hydra pattern --- packages/hydra/hydra.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hydra/hydra.mjs b/packages/hydra/hydra.mjs index 91401034..8f6d9d8e 100644 --- a/packages/hydra/hydra.mjs +++ b/packages/hydra/hydra.mjs @@ -47,4 +47,4 @@ export function clearHydra() { globalThis.shape = controls.shape; } -export const H = (p) => () => p.queryArc(getTime(), getTime())[0].value; +export const H = (p) => () => reify(p).queryArc(getTime(), getTime())[0].value; From 3a4ffb13ad6b7d6f2b394ee3ce72316e57e08e05 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 3 Apr 2024 23:48:08 +0200 Subject: [PATCH 04/34] add more info on using strings for patterns in web package --- packages/web/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/web/README.md b/packages/web/README.md index 8b567729..659c8271 100644 --- a/packages/web/README.md +++ b/packages/web/README.md @@ -72,7 +72,13 @@ document.getElementById('play').addEventListener('stop', There is a tiny difference between the [Strudel REPL](https://strudel.cc/) and `@strudel/web`. In the REPL you can use 'single quotes' for regular JS strings and "double quotes" for mini notation patterns. In `@strudel/web`, it does not matter which types of quotes you're using. -There will probably be an escapte hatch for that in the future. + +This difference means that you cannot call pattern methods on raw strings, for example `"1 2 3".slow(2)`. +To make it work you can either: + +1. Use the `evaluate` function, which behaves exactly like the Strudel REPL, interpreting double quoted strings as mini notation. +2. wrap the string with `m`: `m("1 2 3").slow(2)` +3. wrap the string in a control function: `n("1 2 3").slow(2)` depending on your context. ## More Examples From 915a4d2149ca33943e22ef752088e06cfe6ceb2f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 3 Apr 2024 23:53:25 +0200 Subject: [PATCH 05/34] fix: example encoding for testing builds locally without server --- examples/buildless/headless-simple.html | 25 ++++++++---- examples/buildless/headless-with-samples.html | 38 +++++++++++-------- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/examples/buildless/headless-simple.html b/examples/buildless/headless-simple.html index 15a56161..768765d6 100644 --- a/examples/buildless/headless-simple.html +++ b/examples/buildless/headless-simple.html @@ -1,9 +1,18 @@ - - - - + + + + + + + + + + + + + diff --git a/examples/buildless/headless-with-samples.html b/examples/buildless/headless-with-samples.html index 18b5e379..1915cd54 100644 --- a/examples/buildless/headless-with-samples.html +++ b/examples/buildless/headless-with-samples.html @@ -1,16 +1,24 @@ - - - - - - + + + + + + + + + + + + + + From 6ff7697cfda05188caabf575fbdc68f425cfc59a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 4 Apr 2024 00:03:32 +0200 Subject: [PATCH 06/34] fix: use foreground color for pianoroll playhead --- packages/draw/pianoroll.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/draw/pianoroll.mjs b/packages/draw/pianoroll.mjs index 1bdf81c4..247213b4 100644 --- a/packages/draw/pianoroll.mjs +++ b/packages/draw/pianoroll.mjs @@ -108,7 +108,7 @@ export function pianoroll({ active = getTheme().foreground, background = 'transparent', smear = 0, - playheadColor = 'white', + playheadColor = getTheme().foreground, minMidi = 10, maxMidi = 90, autorange = 0, From 18abcaccbb844438b9948f4700079471255e1a9f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 4 Apr 2024 00:03:43 +0200 Subject: [PATCH 07/34] add fallback theme --- packages/draw/draw.mjs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/draw/draw.mjs b/packages/draw/draw.mjs index cfd2ce75..81123f46 100644 --- a/packages/draw/draw.mjs +++ b/packages/draw/draw.mjs @@ -191,7 +191,16 @@ export function getComputedPropertyValue(name) { return getComputedStyle(document.documentElement).getPropertyValue(name); } -let theme = {}; +let theme = { + background: '#222', + foreground: '#75baff', + caret: '#ffcc00', + selection: 'rgba(128, 203, 196, 0.5)', + selectionMatch: '#036dd626', + lineHighlight: '#00000050', + gutterBackground: 'transparent', + gutterForeground: '#8a919966', +}; export function getTheme() { return theme; } From ca8707f32a626d250a498987937400cd2bfe9420 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 4 Apr 2024 00:13:37 +0200 Subject: [PATCH 08/34] cooler example --- examples/buildless/headless-simple.html | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/examples/buildless/headless-simple.html b/examples/buildless/headless-simple.html index 768765d6..61533447 100644 --- a/examples/buildless/headless-simple.html +++ b/examples/buildless/headless-simple.html @@ -2,16 +2,29 @@ - - - + + From 0ba4be0571834b7d0729ca2715238f76df7bcd0d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 4 Apr 2024 00:13:43 +0200 Subject: [PATCH 09/34] bg --- examples/buildless/headless-with-samples.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/buildless/headless-with-samples.html b/examples/buildless/headless-with-samples.html index 1915cd54..3ac6d42e 100644 --- a/examples/buildless/headless-with-samples.html +++ b/examples/buildless/headless-with-samples.html @@ -2,10 +2,10 @@ - - + + From a4897adb831b9ad0e4ed0c53bead73a497b90e52 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 4 Apr 2024 00:38:08 +0200 Subject: [PATCH 10/34] fix: import --- packages/hydra/hydra.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hydra/hydra.mjs b/packages/hydra/hydra.mjs index 8f6d9d8e..2cb265c2 100644 --- a/packages/hydra/hydra.mjs +++ b/packages/hydra/hydra.mjs @@ -1,5 +1,5 @@ import { getDrawContext } from '@strudel/draw'; -import { controls, getTime } from '@strudel/core'; +import { controls, getTime, reify } from '@strudel/core'; let latestOptions; let hydra; From d49c9dce4fccb5df67e60577352a7bcb997cfc49 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Fri, 17 May 2024 00:27:34 -0400 Subject: [PATCH 11/34] working --- packages/superdough/superdough.mjs | 2 + packages/superdough/worklets.mjs | 64 ++++++++++++++++++++++++++++++ website/src/repl/panel/Forms.jsx | 5 +-- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index c0ba96e0..cd9fcfeb 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -471,6 +471,8 @@ export const superdough = async (value, t, hapDuration) => { shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', { shape, postgain: shapevol })); distort !== undefined && chain.push(getWorklet(ac, 'distort-processor', { distort, postgain: distortvol })); + chain.push(getWorklet(ac, 'ladder-processor', { cutoff: 500, q: 1 })); + compressorThreshold !== undefined && chain.push( getCompressor(ac, compressorThreshold, compressorRatio, compressorKnee, compressorAttack, compressorRelease), diff --git a/packages/superdough/worklets.mjs b/packages/superdough/worklets.mjs index a1f524ca..152e51d6 100644 --- a/packages/superdough/worklets.mjs +++ b/packages/superdough/worklets.mjs @@ -106,6 +106,70 @@ class ShapeProcessor extends AudioWorkletProcessor { } registerProcessor('shape-processor', ShapeProcessor); +function fast_tanh(x) { + const x2 = x * x; + return (x * (27.0 + x2)) / (27.0 + 9.0 * x2); +} +const _PI = 3.14159265359; + +class LadderProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [ + { name: 'cutoff', defaultValue: 500 }, + { name: 'q', defaultValue: 1 }, + ]; + } + + constructor() { + super(); + this.started = false; + this.p0 = 0; + this.p1 = 0; + this.p2 = 0; + this.p3 = 0; + this.p32 = 0; + this.p33 = 0; + this.p34 = 0; + } + + process(inputs, outputs, parameters) { + const input = inputs[0]; + const output = outputs[0]; + + const hasInput = !(input[0] === undefined); + if (this.started && !hasInput) { + return false; + } + this.started = hasInput; + + const resonance = parameters.q[0]; + let cutoff = parameters.cutoff[0]; + cutoff = (cutoff * 2 * _PI) / sampleRate; + cutoff = cutoff > 1 ? 1 : cutoff; + + const k = resonance * 4; + + for (let n = 0; n < blockSize; n++) { + for (let i = 0; i < input.length; i++) { + const out = this.p3 * 0.360891 + this.p32 * 0.41729 + this.p33 * 0.177896 + this.p34 * 0.0439725; + + this.p34 = this.p33; + this.p33 = this.p32; + this.p32 = this.p3; + + this.p0 += (fast_tanh(input[i][n] - k * out) - fast_tanh(this.p0)) * cutoff; + this.p1 += (fast_tanh(this.p0) - fast_tanh(this.p1)) * cutoff; + this.p2 += (fast_tanh(this.p1) - fast_tanh(this.p2)) * cutoff; + this.p3 += (fast_tanh(this.p2) - fast_tanh(this.p3)) * cutoff; + + output[i][n] = out; + } + } + return true; + } +} +registerProcessor('ladder-processor', LadderProcessor); + class DistortProcessor extends AudioWorkletProcessor { static get parameterDescriptors() { return [ diff --git a/website/src/repl/panel/Forms.jsx b/website/src/repl/panel/Forms.jsx index c5b22002..b9172e91 100644 --- a/website/src/repl/panel/Forms.jsx +++ b/website/src/repl/panel/Forms.jsx @@ -2,16 +2,13 @@ import cx from '@src/cx.mjs'; export function ButtonGroup({ value, onChange, items }) { return ( -
+
{Object.entries(items).map(([key, label], i, arr) => (