From 006ce9d1da2af36364d2acce6f4aada71a965766 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Fri, 2 May 2025 23:33:58 -0400 Subject: [PATCH 01/25] delaytime --- packages/superdough/superdough.mjs | 8 ++++---- packages/superdough/util.mjs | 4 ++++ packages/webaudio/webaudio.mjs | 5 +++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index a1dc30b7c..2a205e18d 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th import './feedbackdelay.mjs'; import './reverb.mjs'; import './vowel.mjs'; -import { clamp, nanFallback, _mod } from './util.mjs'; +import { clamp, nanFallback, _mod, cycleToSeconds } from './util.mjs'; import workletsUrl from './worklets.mjs?audioworklet'; import { createFilter, gainNode, getCompressor, getWorklet } from './helpers.mjs'; import { map } from 'nanostores'; @@ -132,7 +132,7 @@ const defaultDefaultValues = { distortvol: 1, delay: 0, delayfeedback: 0.5, - delaytime: 0.25, + delaytime: 3 / 16, orbit: 1, i: 1, velocity: 1, @@ -429,7 +429,7 @@ export function resetGlobalEffects() { let activeSoundSources = new Map(); -export const superdough = async (value, t, hapDuration) => { +export const superdough = async (value, t, hapDuration, cps = 1) => { const ac = getAudioContext(); t = typeof t === 'string' && t.startsWith('=') ? Number(t.slice(1)) : ac.currentTime + t; let { stretch } = value; @@ -699,7 +699,7 @@ export const superdough = async (value, t, hapDuration) => { // delay let delaySend; if (delay > 0 && delaytime > 0 && delayfeedback > 0) { - const delyNode = getDelay(orbit, delaytime, delayfeedback, t); + const delyNode = getDelay(orbit, cycleToSeconds(delaytime, cps), delayfeedback, t); delaySend = effectSend(post, delyNode, delay); audioNodes.push(delaySend); } diff --git a/packages/superdough/util.mjs b/packages/superdough/util.mjs index 4e3c7e41e..ea63a16f0 100644 --- a/packages/superdough/util.mjs +++ b/packages/superdough/util.mjs @@ -68,3 +68,7 @@ export const _mod = (n, m) => ((n % m) + m) % m; export const getSoundIndex = (n, numSounds) => { return _mod(Math.round(nanFallback(n, 0)), numSounds); }; + +export function cycleToSeconds(cycle, cps) { + return cycle / cps; +} diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 44a683480..3ce4f91b3 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -17,8 +17,9 @@ const hap2value = (hap) => { export const webaudioOutputTrigger = (t, hap, ct, cps) => superdough(hap2value(hap), t - ct, hap.duration / cps, cps); // uses more precise, absolute t if available, see https://github.com/tidalcycles/strudel/pull/1004 -export const webaudioOutput = (hap, deadline, hapDuration, cps, t) => - superdough(hap2value(hap), t ? `=${t}` : deadline, hapDuration); +export const webaudioOutput = (hap, deadline, hapDuration, cps, t) => { + return superdough(hap2value(hap), t ? `=${t}` : deadline, hapDuration,cps); +}; Pattern.prototype.webaudio = function () { return this.onTrigger(webaudioOutputTrigger); From 94257e81ee6c43053ffa739eff88c1454ba36604 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Fri, 2 May 2025 23:44:55 -0400 Subject: [PATCH 02/25] lint --- packages/webaudio/webaudio.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 3ce4f91b3..640449db0 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -18,7 +18,7 @@ const hap2value = (hap) => { export const webaudioOutputTrigger = (t, hap, ct, cps) => superdough(hap2value(hap), t - ct, hap.duration / cps, cps); // uses more precise, absolute t if available, see https://github.com/tidalcycles/strudel/pull/1004 export const webaudioOutput = (hap, deadline, hapDuration, cps, t) => { - return superdough(hap2value(hap), t ? `=${t}` : deadline, hapDuration,cps); + return superdough(hap2value(hap), t ? `=${t}` : deadline, hapDuration, cps); }; Pattern.prototype.webaudio = function () { From ae15bb72740000bd1ac563cf4a0f96d2e9c73d1f Mon Sep 17 00:00:00 2001 From: Alice Wyan <121136+wyan@users.noreply.github.com> Date: Mon, 9 Jun 2025 15:03:41 +0200 Subject: [PATCH 03/25] Add browser cache explanation in samples.mdx Several users (including me) have been bitten by this, so it's perhaps worth mentioning in the docs that the strudel.json file gets cached by the browser and doesn't reload properly unless forced. --- website/src/pages/learn/samples.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/website/src/pages/learn/samples.mdx b/website/src/pages/learn/samples.mdx index 890de3aae..88a0a3b29 100644 --- a/website/src/pages/learn/samples.mdx +++ b/website/src/pages/learn/samples.mdx @@ -163,6 +163,12 @@ The last section could be written as: } ``` +Please note that browsers will often cache `strudel.json` on first load, and keep using the cached +version even if the orginal has been updated. If this bites you (for example while developing a new +sample pack), you can force the browser to download a new copy by i.e. changing capitalization of one +character in the URL, or by removing it from cache (deleting cache in browser Privacy settings, or from +the dev console if you're technically minded, or by using a cache deleting extension). + ## Github Shortcut Because loading samples from github is common, there is a shortcut: From 117cf7e18aa3e481ffde92964fc41df3439d83c7 Mon Sep 17 00:00:00 2001 From: Alice Wyan <121136+wyan@users.noreply.github.com> Date: Mon, 9 Jun 2025 19:45:21 +0200 Subject: [PATCH 04/25] Update samples.mdx --- website/src/pages/learn/samples.mdx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/website/src/pages/learn/samples.mdx b/website/src/pages/learn/samples.mdx index 88a0a3b29..bc6627d29 100644 --- a/website/src/pages/learn/samples.mdx +++ b/website/src/pages/learn/samples.mdx @@ -166,8 +166,15 @@ The last section could be written as: Please note that browsers will often cache `strudel.json` on first load, and keep using the cached version even if the orginal has been updated. If this bites you (for example while developing a new sample pack), you can force the browser to download a new copy by i.e. changing capitalization of one -character in the URL, or by removing it from cache (deleting cache in browser Privacy settings, or from -the dev console if you're technically minded, or by using a cache deleting extension). +character in the URL, or adding a URL attribute, such as: +```javascript +samples('https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/strudel.json?version=2') +``` +that gets ignored by GitHub (but changes the URL, forcing the browser to reload every time we increase +the version number). + +It is also possible, of course, to just remove it from cache (deleting cache in browser Privacy settings, +or from the dev console if you're technically minded, or by using a cache deleting extension). ## Github Shortcut From 1b7fbecf50c8385497005cd8c8df36bc004f8f0e Mon Sep 17 00:00:00 2001 From: Alice Wyan <121136+wyan@users.noreply.github.com> Date: Tue, 10 Jun 2025 13:20:21 +0200 Subject: [PATCH 05/25] Fix style issue --- website/src/pages/learn/samples.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/src/pages/learn/samples.mdx b/website/src/pages/learn/samples.mdx index bc6627d29..daaecd06c 100644 --- a/website/src/pages/learn/samples.mdx +++ b/website/src/pages/learn/samples.mdx @@ -167,9 +167,11 @@ Please note that browsers will often cache `strudel.json` on first load, and kee version even if the orginal has been updated. If this bites you (for example while developing a new sample pack), you can force the browser to download a new copy by i.e. changing capitalization of one character in the URL, or adding a URL attribute, such as: + ```javascript -samples('https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/strudel.json?version=2') +samples('https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/strudel.json?version=2'); ``` + that gets ignored by GitHub (but changes the URL, forcing the browser to reload every time we increase the version number). From fe9a91d1e4d9933d21f9aa028851a62f348ebe1e Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 24 Jun 2025 23:22:42 +0100 Subject: [PATCH 06/25] add unjoin, into and chunkinto --- packages/core/pattern.mjs | 41 ++++++++++++++ test/__snapshots__/examples.test.mjs.snap | 69 +++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index beefc5971..0ad1f77c9 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -869,6 +869,47 @@ export class Pattern { console.log(drawLine(this)); return this; } + + ////////////////////////////////////////////////////////////////////// + // methods relating to breaking patterns into subcycles + + // Breaks a pattern into a pattern of patterns, according to the structure of the given binary pattern. + unjoin(pieces, func = id) { + return pieces.withHap((hap) => + hap.withValue((v) => (v ? func(this.ribbon(hap.whole.begin, hap.whole.duration)) : this)), + ); + } + + /** + * Breaks a pattern into pieces according to the structure of a given pattern. + * True values in the given pattern cause the corresponding subcycle of the + * source pattern to be looped, and for an (optional) given function to be + * applied. False values result in the corresponding part of the source pattern + * to be played unchanged. + * @name into + * @memberof Pattern + * @example + * sound("bd sd ht lt").into("1 0", hurry(2)) + */ + into(pieces, func) { + return this.unjoin(pieces, func).innerJoin(); + } + + /** + * Like `chunk`, but the function is applied to a looped subcycle of the source pattern. + * @name chunkInto + * @synonym chunkinto + * @memberof Pattern + * @example + * sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2)) + * .bank("tr909") + */ + chunkInto(n, func) { + return this.into(fastcat(true, ...Array(n - 1).fill(false)).iterback(4), func); + } + chunkinto(n, func) { + return this.chunkInto(n, func); + } } ////////////////////////////////////////////////////////////////////// diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index f3607cb48..d0a622940 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1889,6 +1889,46 @@ exports[`runs examples > example "chunkBack" example index 0 1`] = ` ] `; +exports[`runs examples > example "chunkInto" example index 0 1`] = ` +[ + "[ 0/1 → 1/16 | s:bd speed:2 bank:tr909 ]", + "[ 1/16 → 1/8 | s:sd speed:2 bank:tr909 ]", + "[ 1/8 → 3/16 | s:bd speed:2 bank:tr909 ]", + "[ 3/16 → 1/4 | s:sd speed:2 bank:tr909 ]", + "[ 1/4 → 3/8 | s:ht bank:tr909 ]", + "[ 3/8 → 1/2 | s:lt bank:tr909 ]", + "[ 1/2 → 5/8 | s:bd bank:tr909 ]", + "[ 3/4 → 7/8 | s:cp bank:tr909 ]", + "[ 7/8 → 1/1 | s:lt bank:tr909 ]", + "[ 1/1 → 9/8 | s:bd bank:tr909 ]", + "[ 9/8 → 5/4 | s:sd bank:tr909 ]", + "[ 5/4 → 21/16 | s:ht speed:2 bank:tr909 ]", + "[ 21/16 → 11/8 | s:lt speed:2 bank:tr909 ]", + "[ 11/8 → 23/16 | s:ht speed:2 bank:tr909 ]", + "[ 23/16 → 3/2 | s:lt speed:2 bank:tr909 ]", + "[ 3/2 → 13/8 | s:bd bank:tr909 ]", + "[ 7/4 → 15/8 | s:cp bank:tr909 ]", + "[ 15/8 → 2/1 | s:lt bank:tr909 ]", + "[ 2/1 → 17/8 | s:bd bank:tr909 ]", + "[ 17/8 → 9/4 | s:sd bank:tr909 ]", + "[ 9/4 → 19/8 | s:ht bank:tr909 ]", + "[ 19/8 → 5/2 | s:lt bank:tr909 ]", + "[ 5/2 → 41/16 | s:bd speed:2 bank:tr909 ]", + "[ 21/8 → 43/16 | s:bd speed:2 bank:tr909 ]", + "[ 11/4 → 23/8 | s:cp bank:tr909 ]", + "[ 23/8 → 3/1 | s:lt bank:tr909 ]", + "[ 3/1 → 25/8 | s:bd bank:tr909 ]", + "[ 25/8 → 13/4 | s:sd bank:tr909 ]", + "[ 13/4 → 27/8 | s:ht bank:tr909 ]", + "[ 27/8 → 7/2 | s:lt bank:tr909 ]", + "[ 7/2 → 29/8 | s:bd bank:tr909 ]", + "[ 15/4 → 61/16 | s:cp speed:2 bank:tr909 ]", + "[ 61/16 → 31/8 | s:lt speed:2 bank:tr909 ]", + "[ 31/8 → 63/16 | s:cp speed:2 bank:tr909 ]", + "[ 63/16 → 4/1 | s:lt speed:2 bank:tr909 ]", +] +`; + exports[`runs examples > example "clip" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:c s:piano clip:0.5 ]", @@ -4391,6 +4431,35 @@ exports[`runs examples > example "inside" example index 0 1`] = ` ] `; +exports[`runs examples > example "into" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | s:bd speed:2 ]", + "[ 1/8 → 1/4 | s:sd speed:2 ]", + "[ 1/4 → 3/8 | s:bd speed:2 ]", + "[ 3/8 → 1/2 | s:sd speed:2 ]", + "[ 1/2 → 3/4 | s:ht ]", + "[ 3/4 → 1/1 | s:lt ]", + "[ 1/1 → 9/8 | s:bd speed:2 ]", + "[ 9/8 → 5/4 | s:sd speed:2 ]", + "[ 5/4 → 11/8 | s:bd speed:2 ]", + "[ 11/8 → 3/2 | s:sd speed:2 ]", + "[ 3/2 → 7/4 | s:ht ]", + "[ 7/4 → 2/1 | s:lt ]", + "[ 2/1 → 17/8 | s:bd speed:2 ]", + "[ 17/8 → 9/4 | s:sd speed:2 ]", + "[ 9/4 → 19/8 | s:bd speed:2 ]", + "[ 19/8 → 5/2 | s:sd speed:2 ]", + "[ 5/2 → 11/4 | s:ht ]", + "[ 11/4 → 3/1 | s:lt ]", + "[ 3/1 → 25/8 | s:bd speed:2 ]", + "[ 25/8 → 13/4 | s:sd speed:2 ]", + "[ 13/4 → 27/8 | s:bd speed:2 ]", + "[ 27/8 → 7/2 | s:sd speed:2 ]", + "[ 7/2 → 15/4 | s:ht ]", + "[ 15/4 → 4/1 | s:lt ]", +] +`; + exports[`runs examples > example "invert" example index 0 1`] = ` [ "[ 0/1 → 1/8 | s:bd ]", From e19fd2444704b1767f415d68c897d3da0058eb6a Mon Sep 17 00:00:00 2001 From: Khalid Date: Wed, 25 Jun 2025 08:44:12 -0400 Subject: [PATCH 07/25] Case insensitive search in the reference tab --- website/src/repl/components/panel/Reference.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/src/repl/components/panel/Reference.jsx b/website/src/repl/components/panel/Reference.jsx index ab925eb91..42a03a02e 100644 --- a/website/src/repl/components/panel/Reference.jsx +++ b/website/src/repl/components/panel/Reference.jsx @@ -21,7 +21,8 @@ export function Reference() { return true; } - return entry.name.includes(search) || (entry.synonyms?.some((s) => s.includes(search)) ?? false); + const lowCaseSearch = search.toLowerCase(); + return entry.name.toLowerCase().includes(lowCaseSearch) || (entry.synonyms?.some((s) => s.includes(lowCaseSearch)) ?? false); }); }, [search]); From 09d05abd707fefb77bdceb3f0d7dee35227e87ba Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Fri, 27 Jun 2025 15:54:39 -0400 Subject: [PATCH 08/25] delaysync --- packages/core/controls.mjs | 18 +++++++++++++++++- packages/superdough/superdough.mjs | 2 +- packages/webaudio/webaudio.mjs | 1 - 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 3a7faf081..c37960d41 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -985,15 +985,31 @@ export const { delayfeedback, delayfb, dfb } = registerControl('delayfeedback', * */ export const { delaytime, delayt, dt } = registerControl('delaytime', 'delayt', 'dt'); -/* // TODO: test + +/** + * Sets the time of the delay effect in cycles. + * + * @name delaysync + * @param {number | Pattern} cycles delay length in cycles + * @synonyms delayt, dt + * @example + * s("bd bd").delay(.25).delaysync("<1 2 3 5>".div(8)) + * + */ +export const { delaysync } = registerControl('delaysync'); + +/** * Specifies whether delaytime is calculated relative to cps. * * @name lock * @param {number | Pattern} enable When set to 1, delaytime is a direct multiple of a cycle. + * @superdirtOnly * @example * s("sd").delay().lock(1).osc() * + * */ + export const { lock } = registerControl('lock'); /** * Set detune for stacked voices of supported oscillators diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index fc75276a8..14f46711b 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -548,7 +548,7 @@ export const superdough = async (value, t, hapDuration, cps = 0.5) => { compressorRelease, } = value; - delaytime = delaytime ?? cycleToSeconds(delaysync) + delaytime = delaytime ?? cycleToSeconds(delaysync, cps); const orbitChannels = mapChannelNumbers( multiChannelOrbits && orbit > 0 ? [orbit * 2 - 1, orbit * 2] : getDefaultValue('channels'), diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 67490cd23..91e28defd 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -21,7 +21,6 @@ export const webaudioOutput = (hap, deadline, hapDuration, cps, t) => { return superdough(hap2value(hap), t ? `=${t}` : deadline, hapDuration, cps); }; - Pattern.prototype.webaudio = function () { return this.onTrigger(webaudioOutputTrigger); }; From 7a53f6c021b89d53664a222b0f46b0a17c58a4f4 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Fri, 27 Jun 2025 15:56:37 -0400 Subject: [PATCH 09/25] add test --- test/__snapshots__/examples.test.mjs.snap | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index f3607cb48..ed3b5f793 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2505,6 +2505,19 @@ exports[`runs examples > example "delayfeedback" example index 0 1`] = ` ] `; +exports[`runs examples > example "delaysync" example index 0 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd delay:0.25 delaysync:0.125 ]", + "[ 1/2 → 1/1 | s:bd delay:0.25 delaysync:0.125 ]", + "[ 1/1 → 3/2 | s:bd delay:0.25 delaysync:0.25 ]", + "[ 3/2 → 2/1 | s:bd delay:0.25 delaysync:0.25 ]", + "[ 2/1 → 5/2 | s:bd delay:0.25 delaysync:0.375 ]", + "[ 5/2 → 3/1 | s:bd delay:0.25 delaysync:0.375 ]", + "[ 3/1 → 7/2 | s:bd delay:0.25 delaysync:0.625 ]", + "[ 7/2 → 4/1 | s:bd delay:0.25 delaysync:0.625 ]", +] +`; + exports[`runs examples > example "delaytime" example index 0 1`] = ` [ "[ 0/1 → 1/2 | s:bd delay:0.25 delaytime:0.125 ]", @@ -5016,6 +5029,15 @@ exports[`runs examples > example "linger" example index 0 1`] = ` ] `; +exports[`runs examples > example "lock" example index 0 1`] = ` +[ + "[ 0/1 → 1/1 | delay:{s:sd} lock:1 ]", + "[ 1/1 → 2/1 | delay:{s:sd} lock:1 ]", + "[ 2/1 → 3/1 | delay:{s:sd} lock:1 ]", + "[ 3/1 → 4/1 | delay:{s:sd} lock:1 ]", +] +`; + exports[`runs examples > example "loop" example index 0 1`] = ` [ "[ 0/1 → 1/1 | s:casio loop:1 ]", From ff5b11f5edee691e5cb126f6a88d0fc4471bc4d0 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Jun 2025 22:44:15 +0100 Subject: [PATCH 10/25] test + bugfix for chunkinto --- packages/core/pattern.mjs | 36 ++++++++++++++--------------- packages/core/test/pattern.test.mjs | 23 ++++++++++++++++++ 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 10527a1a8..c8c744628 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -894,22 +894,6 @@ export class Pattern { into(pieces, func) { return this.unjoin(pieces, func).innerJoin(); } - - /** - * Like `chunk`, but the function is applied to a looped subcycle of the source pattern. - * @name chunkInto - * @synonym chunkinto - * @memberof Pattern - * @example - * sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2)) - * .bank("tr909") - */ - chunkInto(n, func) { - return this.into(fastcat(true, ...Array(n - 1).fill(false)).iterback(4), func); - } - chunkinto(n, func) { - return this.chunkInto(n, func); - } } ////////////////////////////////////////////////////////////////////// @@ -1858,9 +1842,9 @@ export const { fastGap, fastgap } = register(['fastGap', 'fastgap'], function (f const newWhole = !hap.whole ? undefined : new TimeSpan( - newPart.begin.sub(begin.sub(hap.whole.begin).div(factor)), - newPart.end.add(hap.whole.end.sub(end).div(factor)), - ); + newPart.begin.sub(begin.sub(hap.whole.begin).div(factor)), + newPart.end.add(hap.whole.end.sub(end).div(factor)), + ); return new Hap(newWhole, newPart, hap.value, hap.context); }; return pat.withQuerySpanMaybe(qf).withHap(ef).splitQueries(); @@ -2535,6 +2519,20 @@ export const { fastchunk, fastChunk } = register( true, ); +/** + * Like `chunk`, but the function is applied to a looped subcycle of the source pattern. + * @name chunkInto + * @synonym chunkinto + * @memberof Pattern + * @example + * sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2)) + * .bank("tr909") + */ +export const { chunkinto, chunkInto } = register(['chunkinto', 'chunkInto'], + function (n, func, pat) { + return pat.into(fastcat(true, ...Array(n - 1).fill(false)).iterback(n), func); + }); + // TODO - redefine elsewhere in terms of mask export const bypass = register( 'bypass', diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index 874d45132..8d26a990c 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -1271,4 +1271,27 @@ describe('Pattern', () => { ); }); }); + describe('unjoin', () => { + it('destructures a pattern into subcycles', () => { + sameFirst( + fastcat('a', 'b', 'c', 'd').unjoin(fastcat(true, fastcat(true, true))).fmap(fast(2)).join(), + fastcat('a', 'b', 'a', 'b', 'c', 'c', 'd', 'd') + ) + }) + }) + describe('into', () => { + it('applies a function to subcycles of a pattern', () => { + sameFirst( + fastcat('a', 'b', 'c', 'd').into(fastcat(fastcat('true', 'true'), 'true'), fast(2)), + fastcat('a', 'a', 'b', 'b', 'c', 'd', 'c', 'd') + ) + }) + }), + describe('chunkinto', () => { + it('chunks into subcycles', () => { + sameFirst(fastcat('a', 'b', 'c').chunkInto(3, fast(2)).fast(3), + fastcat(fastcat('a', 'a'), 'b', 'c', 'a', fastcat('b', 'b'), 'c', 'a', 'b', fastcat('c', 'c')) + ) + }) + }) }); From f44caf90966e34271f155f366721a64b060c1f97 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Jun 2025 22:51:47 +0100 Subject: [PATCH 11/25] tests and tweaks, and add chunkBackInto --- packages/core/pattern.mjs | 16 +++++++++++++++- packages/core/test/pattern.test.mjs | 23 +++++++++++++++-------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index c8c744628..6d42c51fd 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2530,7 +2530,21 @@ export const { fastchunk, fastChunk } = register( */ export const { chunkinto, chunkInto } = register(['chunkinto', 'chunkInto'], function (n, func, pat) { - return pat.into(fastcat(true, ...Array(n - 1).fill(false)).iterback(n), func); + return pat.into(fastcat(true, ...Array(n - 1).fill(false))._iterback(n), func); + }); + +/** + * Like `chunkInto`, but moves backwards through the chunks. + * @name chunkBackInto + * @synonym chunkbackinto + * @memberof Pattern + * @example + * sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2)) + * .bank("tr909") + */ +export const { chunkbackinto, chunkBackInto } = register(['chunkbackinto', 'chunkBackInto'], + function (n, func, pat) { + return pat.into(fastcat(true, ...Array(n - 1).fill(false))._iter(n)._early(1), func); }); // TODO - redefine elsewhere in terms of mask diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index 8d26a990c..4ab519a75 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -1278,7 +1278,7 @@ describe('Pattern', () => { fastcat('a', 'b', 'a', 'b', 'c', 'c', 'd', 'd') ) }) - }) + }); describe('into', () => { it('applies a function to subcycles of a pattern', () => { sameFirst( @@ -1286,12 +1286,19 @@ describe('Pattern', () => { fastcat('a', 'a', 'b', 'b', 'c', 'd', 'c', 'd') ) }) - }), - describe('chunkinto', () => { - it('chunks into subcycles', () => { - sameFirst(fastcat('a', 'b', 'c').chunkInto(3, fast(2)).fast(3), - fastcat(fastcat('a', 'a'), 'b', 'c', 'a', fastcat('b', 'b'), 'c', 'a', 'b', fastcat('c', 'c')) - ) - }) + }); + describe('chunkinto', () => { + it('chunks into subcycles', () => { + sameFirst(fastcat('a', 'b', 'c').chunkInto(3, fast(2)).fast(3), + fastcat(fastcat('a', 'a'), 'b', 'c', 'a', fastcat('b', 'b'), 'c', 'a', 'b', fastcat('c', 'c')) + ) }) + }); + describe('chunkbackinto', () => { + it('chunks into subcycles backwards', () => { + sameFirst(fastcat('a', 'b', 'c').chunkBackInto(3, fast(2)).fast(3), + fastcat('a', 'b', fastcat('c', 'c'), 'a', fastcat('b', 'b'), 'c', fastcat('a', 'a'), 'b', 'c') + ) + }) + }); }); From 27073d6c17264dd3218102bd72bcb96d6a0186d6 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Jun 2025 22:56:19 +0100 Subject: [PATCH 12/25] format --- packages/core/pattern.mjs | 25 ++++++++++++--------- packages/core/test/pattern.test.mjs | 35 ++++++++++++++++------------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 6d42c51fd..cbaf8a8a2 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -1842,9 +1842,9 @@ export const { fastGap, fastgap } = register(['fastGap', 'fastgap'], function (f const newWhole = !hap.whole ? undefined : new TimeSpan( - newPart.begin.sub(begin.sub(hap.whole.begin).div(factor)), - newPart.end.add(hap.whole.end.sub(end).div(factor)), - ); + newPart.begin.sub(begin.sub(hap.whole.begin).div(factor)), + newPart.end.add(hap.whole.end.sub(end).div(factor)), + ); return new Hap(newWhole, newPart, hap.value, hap.context); }; return pat.withQuerySpanMaybe(qf).withHap(ef).splitQueries(); @@ -2528,10 +2528,9 @@ export const { fastchunk, fastChunk } = register( * sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2)) * .bank("tr909") */ -export const { chunkinto, chunkInto } = register(['chunkinto', 'chunkInto'], - function (n, func, pat) { - return pat.into(fastcat(true, ...Array(n - 1).fill(false))._iterback(n), func); - }); +export const { chunkinto, chunkInto } = register(['chunkinto', 'chunkInto'], function (n, func, pat) { + return pat.into(fastcat(true, ...Array(n - 1).fill(false))._iterback(n), func); +}); /** * Like `chunkInto`, but moves backwards through the chunks. @@ -2542,10 +2541,14 @@ export const { chunkinto, chunkInto } = register(['chunkinto', 'chunkInto'], * sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2)) * .bank("tr909") */ -export const { chunkbackinto, chunkBackInto } = register(['chunkbackinto', 'chunkBackInto'], - function (n, func, pat) { - return pat.into(fastcat(true, ...Array(n - 1).fill(false))._iter(n)._early(1), func); - }); +export const { chunkbackinto, chunkBackInto } = register(['chunkbackinto', 'chunkBackInto'], function (n, func, pat) { + return pat.into( + fastcat(true, ...Array(n - 1).fill(false)) + ._iter(n) + ._early(1), + func, + ); +}); // TODO - redefine elsewhere in terms of mask export const bypass = register( diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index 4ab519a75..93c4168c9 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -1274,31 +1274,36 @@ describe('Pattern', () => { describe('unjoin', () => { it('destructures a pattern into subcycles', () => { sameFirst( - fastcat('a', 'b', 'c', 'd').unjoin(fastcat(true, fastcat(true, true))).fmap(fast(2)).join(), - fastcat('a', 'b', 'a', 'b', 'c', 'c', 'd', 'd') - ) - }) + fastcat('a', 'b', 'c', 'd') + .unjoin(fastcat(true, fastcat(true, true))) + .fmap(fast(2)) + .join(), + fastcat('a', 'b', 'a', 'b', 'c', 'c', 'd', 'd'), + ); + }); }); describe('into', () => { it('applies a function to subcycles of a pattern', () => { sameFirst( fastcat('a', 'b', 'c', 'd').into(fastcat(fastcat('true', 'true'), 'true'), fast(2)), - fastcat('a', 'a', 'b', 'b', 'c', 'd', 'c', 'd') - ) - }) + fastcat('a', 'a', 'b', 'b', 'c', 'd', 'c', 'd'), + ); + }); }); describe('chunkinto', () => { it('chunks into subcycles', () => { - sameFirst(fastcat('a', 'b', 'c').chunkInto(3, fast(2)).fast(3), - fastcat(fastcat('a', 'a'), 'b', 'c', 'a', fastcat('b', 'b'), 'c', 'a', 'b', fastcat('c', 'c')) - ) - }) + sameFirst( + fastcat('a', 'b', 'c').chunkInto(3, fast(2)).fast(3), + fastcat(fastcat('a', 'a'), 'b', 'c', 'a', fastcat('b', 'b'), 'c', 'a', 'b', fastcat('c', 'c')), + ); + }); }); describe('chunkbackinto', () => { it('chunks into subcycles backwards', () => { - sameFirst(fastcat('a', 'b', 'c').chunkBackInto(3, fast(2)).fast(3), - fastcat('a', 'b', fastcat('c', 'c'), 'a', fastcat('b', 'b'), 'c', fastcat('a', 'a'), 'b', 'c') - ) - }) + sameFirst( + fastcat('a', 'b', 'c').chunkBackInto(3, fast(2)).fast(3), + fastcat('a', 'b', fastcat('c', 'c'), 'a', fastcat('b', 'b'), 'c', fastcat('a', 'a'), 'b', 'c'), + ); + }); }); }); From df06248c54709e68d39d4f4ae607af4509742842 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Jun 2025 22:59:01 +0100 Subject: [PATCH 13/25] snapshot --- test/__snapshots__/examples.test.mjs.snap | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index d0a622940..2d20cff4c 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1889,6 +1889,46 @@ exports[`runs examples > example "chunkBack" example index 0 1`] = ` ] `; +exports[`runs examples > example "chunkBackInto" example index 0 1`] = ` +[ + "[ 0/1 → 1/16 | s:bd speed:2 bank:tr909 ]", + "[ 1/16 → 1/8 | s:sd speed:2 bank:tr909 ]", + "[ 1/8 → 3/16 | s:bd speed:2 bank:tr909 ]", + "[ 3/16 → 1/4 | s:sd speed:2 bank:tr909 ]", + "[ 1/4 → 3/8 | s:ht bank:tr909 ]", + "[ 3/8 → 1/2 | s:lt bank:tr909 ]", + "[ 1/2 → 5/8 | s:bd bank:tr909 ]", + "[ 3/4 → 7/8 | s:cp bank:tr909 ]", + "[ 7/8 → 1/1 | s:lt bank:tr909 ]", + "[ 1/1 → 9/8 | s:bd bank:tr909 ]", + "[ 9/8 → 5/4 | s:sd bank:tr909 ]", + "[ 5/4 → 21/16 | s:ht speed:2 bank:tr909 ]", + "[ 21/16 → 11/8 | s:lt speed:2 bank:tr909 ]", + "[ 11/8 → 23/16 | s:ht speed:2 bank:tr909 ]", + "[ 23/16 → 3/2 | s:lt speed:2 bank:tr909 ]", + "[ 3/2 → 13/8 | s:bd bank:tr909 ]", + "[ 7/4 → 15/8 | s:cp bank:tr909 ]", + "[ 15/8 → 2/1 | s:lt bank:tr909 ]", + "[ 2/1 → 17/8 | s:bd bank:tr909 ]", + "[ 17/8 → 9/4 | s:sd bank:tr909 ]", + "[ 9/4 → 19/8 | s:ht bank:tr909 ]", + "[ 19/8 → 5/2 | s:lt bank:tr909 ]", + "[ 5/2 → 41/16 | s:bd speed:2 bank:tr909 ]", + "[ 21/8 → 43/16 | s:bd speed:2 bank:tr909 ]", + "[ 11/4 → 23/8 | s:cp bank:tr909 ]", + "[ 23/8 → 3/1 | s:lt bank:tr909 ]", + "[ 3/1 → 25/8 | s:bd bank:tr909 ]", + "[ 25/8 → 13/4 | s:sd bank:tr909 ]", + "[ 13/4 → 27/8 | s:ht bank:tr909 ]", + "[ 27/8 → 7/2 | s:lt bank:tr909 ]", + "[ 7/2 → 29/8 | s:bd bank:tr909 ]", + "[ 15/4 → 61/16 | s:cp speed:2 bank:tr909 ]", + "[ 61/16 → 31/8 | s:lt speed:2 bank:tr909 ]", + "[ 31/8 → 63/16 | s:cp speed:2 bank:tr909 ]", + "[ 63/16 → 4/1 | s:lt speed:2 bank:tr909 ]", +] +`; + exports[`runs examples > example "chunkInto" example index 0 1`] = ` [ "[ 0/1 → 1/16 | s:bd speed:2 bank:tr909 ]", From 77bab433e0c897048e874ad97f0721733a55948e Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sat, 28 Jun 2025 14:06:16 -0400 Subject: [PATCH 14/25] cf --- website/src/repl/components/panel/Reference.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/website/src/repl/components/panel/Reference.jsx b/website/src/repl/components/panel/Reference.jsx index 42a03a02e..1b617341b 100644 --- a/website/src/repl/components/panel/Reference.jsx +++ b/website/src/repl/components/panel/Reference.jsx @@ -21,8 +21,11 @@ export function Reference() { return true; } - const lowCaseSearch = search.toLowerCase(); - return entry.name.toLowerCase().includes(lowCaseSearch) || (entry.synonyms?.some((s) => s.includes(lowCaseSearch)) ?? false); + const lowCaseSearch = search.toLowerCase(); + return ( + entry.name.toLowerCase().includes(lowCaseSearch) || + (entry.synonyms?.some((s) => s.includes(lowCaseSearch)) ?? false) + ); }); }, [search]); From f2330a2307fcdba42b55fe976635dce3e941cfcc Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 29 Jun 2025 20:18:15 +0200 Subject: [PATCH 15/25] add 1.1.0 release notes --- .../blog/release-1.1.0-bananensplit.mdx | 317 ++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 website/src/content/blog/release-1.1.0-bananensplit.mdx diff --git a/website/src/content/blog/release-1.1.0-bananensplit.mdx b/website/src/content/blog/release-1.1.0-bananensplit.mdx new file mode 100644 index 000000000..dcc547682 --- /dev/null +++ b/website/src/content/blog/release-1.1.0-bananensplit.mdx @@ -0,0 +1,317 @@ +--- +title: 'Release Notes v1.1.0' +description: '' +date: '2024-06-02' +tags: ['meta'] +author: froos +--- + +These are the release notes for Strudel 1.1.0 aka "Bananensplit". + +The last release was over 19 weeks ago, so a lot of things have happened! + +First, here's a little demo, teasing some of the new features: + +import { Youtube } from '@src/components/Youtube'; + + + +Let's write up some of the highlights: + +## New DSP Features + +### Stereo Supersaw + +with spread, unison, and detune parameters + +```plaintext +note("d f a a# a d3").fast(2) +.s("supersaw").spread(".8").detune(.3).unison("2 7") +``` + +### Analog "ladder" filter type + +works great for acid basslines and vibey tones + +```plaintext +note("{d d d a a# d3 f4}%16".sub(12)).gain(1).s("sawtooth") +.lpf(200).lpenv(slider(1.36,0,8)).lpq(7).distort("1.5:.7")` +.ftype('ladder') +``` + +### stereo distortion effect + +```plaintext +note("{g g a# g g4}%8".add("{0 7 12 0}%8")).lpf(500) +.s("supersaw").dist("4:.2") +``` + +## Editor Features + +### inline viz + +The editor now supports multiple visuals within the code, using the `_` prefix for viz functions: + +Screenshot 2024-06-01 at 01 23 51 + +- `._pianoroll()`: inline pianoroll +- `._punchcard()`: inline punchcard +- `._scope()`: inline scope +- `._pitchwheel()`: inline pitchwheel + +For more info, check out the new [Visual Feedback Page](https://strudel.cc/learn/visual-feedback/) + +### label notation + +This new notation simplifies writing patterns at the top level: + +```plaintext +d1: s("bd*4") +d2: s("[- hh]*4") +``` + +This is equivalent to: + +```plaintext +stack( + s("bd*4"), + s("[- hh]*4") +) +``` + +The labels you choose are arbitrary, the above `d1` and `d2` are a typical thing you'd write in tidal, for example `d1 $ s "bd*4"`. +If the same label is used multiple times, the last one wins: + +```plaintext +d1: s("bd*4") +d1: s("[- hh]*4") // <-- only this plays +``` + +There is a special label anonymous label `$`, which can appear multiple times without overriding itself: + +```plaintext +// both of these will play: +$: s("bd*4") +$: s("[- hh]*4") +``` + +You can mute a pattern by prefixing `_`: + +```plaintext +_$: s("bd*4") // <-- this one is muted +$: s("[- hh]*4") +``` + +To run a transformation on all patterns, you can use `all`: + +```plaintext +$: s("bd*4") +$: s("[- hh]*4") +all(x=>x.room(.5)) +``` + +This notation is now the recommended way to [play patterns in parallel](https://strudel.cc/workshop/first-notes/#playing-multiple-patterns) + +### Clock sync between multiple instances + +timing has received a major overhaul, and is now much more accurate on all browsers. Additionally, you can now sync timing across multiple windows. +![Screenshot 2024-06-02 at 11 24 40 PM](https://codeberg.org/uzu/strudel/assets/47068718/840be744-a13e-4d7b-ab09-50d3a70b1f85) + +### Better sample upload support + +you can now upload large amounts of samples much faster across all browsers including on IOS devices. supported filetypes now include: ogg flac mp3 wav aac m4a + +### experimental tidal syntax + +The new `tidal` function allows you to write strudel patterns in tidal syntax: + +```plaintext +await initTidal() + +tidal` +d1 $ s "bd*4" + +d2 $ s "[- hh]*4" +` +``` + +As we're looking to improve compatibility with tidal, we're happy to hear feedback. + +## breaking changes + +This release comes with a bunch of breaking changes. If you find your patterns to sound different, check out the PRs below for guidance on how to update them. Most of these changes shouldn't affect a lot of patterns. +In case of doubt, add the line `// @version 1.0` to your old pattern. +If you're having problems, please let us know! + +- remove legacy legato + duration implementations by @felixroos in https://codeberg.org/uzu/strudel/pull/965 +- Velocity in value by @felixroos in https://codeberg.org/uzu/strudel/pull/974 +- use ireal as default voicing dict by @felixroos https://codeberg.org/uzu/strudel/pull/967 +- Color in hap value by @felixroos https://codeberg.org/uzu/strudel/pull/1007 +- rename trig -> reset, trigzero -> restart by @felixroos https://codeberg.org/uzu/strudel/pull/1010 +- remove dangerous arithmetic feature by @felixroos https://codeberg.org/uzu/strudel/pull/1030 +- change fanchor to 0 by @daslyfe https://codeberg.org/uzu/strudel/pull/1107 + +## superdough features + +- replace shape with distort in learn doc by @daslyfe https://codeberg.org/uzu/strudel/pull/982 +- Worklet Improvents / fixes by @daslyfe https://codeberg.org/uzu/strudel/pull/963 +- supersaw oscillator by @daslyfe https://codeberg.org/uzu/strudel/pull/978 +- Add analog-style ladder filter by @daslyfe https://codeberg.org/uzu/strudel/pull/1103 +- Calculate phaser modulation phase based on time by @daslyfe https://codeberg.org/uzu/strudel/pull/1110 +- rollback phaser by @daslyfe https://codeberg.org/uzu/strudel/pull/1113 + +## editor / ui features + +- 'Enable Bracket Matching' option in Codemirror by @eefano https://codeberg.org/uzu/strudel/pull/956 +- REPL sync between windows by @daslyfe https://codeberg.org/uzu/strudel/pull/900 +- inline viz / widgets package by @felixroos https://codeberg.org/uzu/strudel/pull/989 +- Inline punchcard + spiral by @felixroos https://codeberg.org/uzu/strudel/pull/1008 +- More fonts by @felixroos https://codeberg.org/uzu/strudel/pull/1023 +- better theme integration for visuals + various fixes by @felixroos https://codeberg.org/uzu/strudel/pull/1024 +- add setting for sync flag by @felixroos https://codeberg.org/uzu/strudel/pull/1025 +- add closeBrackets setting by @felixroos https://codeberg.org/uzu/strudel/pull/1031 +- add font file types to offline cache by @felixroos https://codeberg.org/uzu/strudel/pull/1032 +- pitchwheel visual by @felixroos https://codeberg.org/uzu/strudel/pull/1041 +- repl: set document.title from @title by @kasparsj https://codeberg.org/uzu/strudel/pull/1090 +- Samples tab improvements by @daslyfe https://codeberg.org/uzu/strudel/pull/1102 + +## language features + +- pickOut(), pickRestart(), pickReset() by @eefano https://codeberg.org/uzu/strudel/pull/950 +- Auto await samples by @felixroos https://codeberg.org/uzu/strudel/pull/955 +- feat: can now invert euclid pulses with negative numbers by @felixroos https://codeberg.org/uzu/strudel/pull/959 +- Nested controls by @felixroos https://codeberg.org/uzu/strudel/pull/973 +- alias - for ~ by @yaxu https://codeberg.org/uzu/strudel/pull/981 +- Beat-oriented functionality by @yaxu https://codeberg.org/uzu/strudel/pull/976 +- Labeled statements by @felixroos https://codeberg.org/uzu/strudel/pull/991 +- accidentals in scale degrees by @eefano https://codeberg.org/uzu/strudel/pull/1000 +- Feature: tactus marking by @yaxu https://codeberg.org/uzu/strudel/pull/1021 +- Tactus tidy by @yaxu https://codeberg.org/uzu/strudel/pull/1027 +- Wax, wane, taper and taperlist by @yaxu https://codeberg.org/uzu/strudel/pull/1042 +- transpose: support all combinations of numbers and strings for notes and intervals by @felixroos https://codeberg.org/uzu/strudel/pull/1048 +- anonymous patterns + muting by @felixroos https://codeberg.org/uzu/strudel/pull/1059 +- add swing + swingBy by @felixroos https://codeberg.org/uzu/strudel/pull/1038 +- Stepwise functions from Tidal by @yaxu https://codeberg.org/uzu/strudel/pull/1060 +- Tactus tweaks - fixes for maintaining tactus and highlight locations by @yaxu https://codeberg.org/uzu/strudel/pull/1065 +- Fix stepjoin by @yaxu https://codeberg.org/uzu/strudel/pull/1067 +- More tactus tidying by @yaxu https://codeberg.org/uzu/strudel/pull/1071 +- Tactus calculation toggle and breaking change to tactus calculation in fast/slow/hurry by @yaxu https://codeberg.org/uzu/strudel/pull/1081 +- hs2js package / tidal parser by @felixroos https://codeberg.org/uzu/strudel/pull/870 +- Add the mousex and mousey signal by @Enelg52 https://codeberg.org/uzu/strudel/pull/1112 +- can now access strudelMirror from repl by @felixroos https://codeberg.org/uzu/strudel/pull/1117 + +## sampler + +If you have nodejs installed on your system, you can now use [@strudel/sampler](https://www.npmjs.com/package/@strudel/sampler) to serve samples from disk to the REPL or flok. + +- local sample server cli by @felixroos https://codeberg.org/uzu/strudel/pull/1033 +- Fix sampler paths by @felixroos https://codeberg.org/uzu/strudel/pull/1034 +- Fix sampler windows by @felixroos https://codeberg.org/uzu/strudel/pull/1108 +- fix sampler on windows by @geikha https://codeberg.org/uzu/strudel/pull/1109 + +## docs + +- V1 release notes by @felixroos https://codeberg.org/uzu/strudel/pull/935 +- Minor documentation error: Update first-sounds.mdx by @mhetrick https://codeberg.org/uzu/strudel/pull/941 +- Update synths.mdx by @andresgottlieb https://codeberg.org/uzu/strudel/pull/984 +- using strudel in your project guide + cleanup examples by @felixroos https://codeberg.org/uzu/strudel/pull/1006 +- Document signals by @ilesinge https://codeberg.org/uzu/strudel/pull/1015 +- improve tutorial + custom samples doc by @felixroos https://codeberg.org/uzu/strudel/pull/1053 +- fix cr typo on first-sounds.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1068 +- fix first sounds typo by @cleary https://codeberg.org/uzu/strudel/pull/1069 +- add `<...>` to first-sounds.mdx recap by @cleary https://codeberg.org/uzu/strudel/pull/1070 +- add nesting to `off` example variation in pattern-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1075 +- fix translation issue in first-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1072 +- add signals to recap in first-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1073 +- fix docs on alignment.mdx by @diegodorado https://codeberg.org/uzu/strudel/pull/1076 +- fix little dub tune example by @lukad https://codeberg.org/uzu/strudel/pull/1104 +- clarify `off` in pattern-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1074 +- Fixes drawPianoroll import in codemirror example by @giohappy https://codeberg.org/uzu/strudel/pull/1116 +- Migrate tutorial fanchor by @felixroos https://codeberg.org/uzu/strudel/pull/1122 + +## internals + +- remove cjs builds by @felixroos https://codeberg.org/uzu/strudel/pull/945 +- controls refactoring: simplify exports by @felixroos https://codeberg.org/uzu/strudel/pull/962 +- move canvas related helpers from core to new draw package by @felixroos https://codeberg.org/uzu/strudel/pull/971 +- remove canvas, externalize samples, delete junk by @felixroos https://codeberg.org/uzu/strudel/pull/1003 +- Improve performance of ! (replicate) by @yaxu https://codeberg.org/uzu/strudel/pull/1084 +- Benchmarks by @yaxu https://codeberg.org/uzu/strudel/pull/1079 + +## fixes + +- fix midi issue on firefox and added quote error by @Enelg52 https://codeberg.org/uzu/strudel/pull/936 +- fix: pianoroll sorting by @felixroos https://codeberg.org/uzu/strudel/pull/938 +- account for cps in midi time duration by @daslyfe https://codeberg.org/uzu/strudel/pull/954 +- fix script importable packages (web + repl) by @felixroos https://codeberg.org/uzu/strudel/pull/957 +- fix: reset global fx on pattern change by @felixroos https://codeberg.org/uzu/strudel/pull/960 +- add debounce to logger by @felixroos https://codeberg.org/uzu/strudel/pull/968 +- fix for transpose(): preserve hap value object structure by @eefano https://codeberg.org/uzu/strudel/pull/966 +- fix: clear hydra on reset by @felixroos https://codeberg.org/uzu/strudel/pull/983 +- little fix for withVal by @eefano https://codeberg.org/uzu/strudel/pull/980 +- fix: share now shares what's visible instead of active by @felixroos https://codeberg.org/uzu/strudel/pull/985 +- Fix pure mini highlight by @yaxu https://codeberg.org/uzu/strudel/pull/994 +- fix: await injectPatternMethods by @felixroos https://codeberg.org/uzu/strudel/pull/1012 +- update undocumented script by @felixroos https://codeberg.org/uzu/strudel/pull/1013 +- eliminate chromium clock jitter by @felixroos https://codeberg.org/uzu/strudel/pull/1004 +- Repl sync fixes by @daslyfe https://codeberg.org/uzu/strudel/pull/1014 +- hotfix for 1017 by @daslyfe https://codeberg.org/uzu/strudel/pull/1020 +- fix cyclist fizzling out by @felixroos https://codeberg.org/uzu/strudel/pull/1046 +- Midi Time hotfix for scheduler updates by @daslyfe https://codeberg.org/uzu/strudel/pull/1047 +- fix: do not reset cc input values on each eval by @felixroos https://codeberg.org/uzu/strudel/pull/1054 +- Fix wchooseCycles not picking the whole pattern by @ilesinge https://codeberg.org/uzu/strudel/pull/1061 +- fix OSC timing for recent scheduler updates by @daslyfe https://codeberg.org/uzu/strudel/pull/1062 +- clarify license by @yaxu https://codeberg.org/uzu/strudel/pull/1064 +- fix failing format test by @daslyfe https://codeberg.org/uzu/strudel/pull/1077 +- fix: url parsing with extra params by @felixroos https://codeberg.org/uzu/strudel/pull/1083 +- fix: csound + dough timing by @felixroos https://codeberg.org/uzu/strudel/pull/1086 +- fix: missing events due to premature worklet cleanup by @felixroos https://codeberg.org/uzu/strudel/pull/1089 +- Use sessionStorage for viewingPatternData and activePattern by @kasparsj https://codeberg.org/uzu/strudel/pull/1091 +- osc: couple of fixes by @kasparsj https://codeberg.org/uzu/strudel/pull/1093 +- web package fixes by @felixroos https://codeberg.org/uzu/strudel/pull/1044 +- Fix audio worklets by @daslyfe https://codeberg.org/uzu/strudel/pull/1114 +- fix: use full repl in web package by @felixroos https://codeberg.org/uzu/strudel/pull/1119 +- [BUG FIX] Audio worklets sometimes dont load by @daslyfe https://codeberg.org/uzu/strudel/pull/1121 + +## New Contributors + +- @mhetrick made their first contribution https://codeberg.org/uzu/strudel/pull/941 +- @eefano made their first contribution https://codeberg.org/uzu/strudel/pull/956 +- @Enelg52 made their first contribution https://codeberg.org/uzu/strudel/pull/936 +- @andresgottlieb made their first contribution https://codeberg.org/uzu/strudel/pull/984 +- @cleary made their first contribution https://codeberg.org/uzu/strudel/pull/1068 +- @diegodorado made their first contribution https://codeberg.org/uzu/strudel/pull/1076 +- @lukad made their first contribution https://codeberg.org/uzu/strudel/pull/1104 +- @giohappy made their first contribution https://codeberg.org/uzu/strudel/pull/1116 + +A huge thanks to all contributors!!! + +## Packages + +- @strudel/codemirror@1.1.0 +- @strudel/core@1.1.0 +- @strudel/csound@1.1.0 +- @strudel/draw@1.1.0 +- @strudel/embed@1.1.0 +- hs2js@0.1.0 +- @strudel/hydra@1.1.0 +- @strudel/midi@1.1.0 +- @strudel/mini@1.1.0 +- @strudel/osc@1.1.0 +- @strudel/repl@1.1.0 +- @strudel/sampler@0.1.0 +- @strudel/serial@1.1.0 +- @strudel/soundfonts@1.1.0 +- superdough@1.1.0 +- @strudel/tidal@0.1.0 +- @strudel/tonal@1.1.0 +- @strudel/transpiler@1.1.0 +- @strudel/web@1.1.0 +- @strudel/webaudio@1.1.0 +- @strudel/xen@1.1.0 + +**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v1.0.0...v1.1.0 From eac6f27ca4e79a0b21c2c48e6cc3bdf3331e1be5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 29 Jun 2025 21:29:11 +0200 Subject: [PATCH 16/25] add 1.2.0 release notes --- .../blog/release-1.2.0-kardinalschnitten.mdx | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 website/src/content/blog/release-1.2.0-kardinalschnitten.mdx diff --git a/website/src/content/blog/release-1.2.0-kardinalschnitten.mdx b/website/src/content/blog/release-1.2.0-kardinalschnitten.mdx new file mode 100644 index 000000000..e58e27aec --- /dev/null +++ b/website/src/content/blog/release-1.2.0-kardinalschnitten.mdx @@ -0,0 +1,187 @@ +--- +title: 'Release Notes v1.2.0' +description: '' +date: '2025-05-01' +tags: ['meta'] +author: froos +--- + +## What's Changed + +## highlights + +- [stepwise functions](https://strudel.cc/learn/stepwise/) ([PR](https://github.com/tidalcycles/strudel/pull/1262)) +- [midimaps](https://strudel.cc/learn/input-output/#midimaps) ([PR](https://github.com/tidalcycles/strudel/pull/1274)) +- [spectrum](https://strudel.cc/learn/visual-feedback/#spectrum) ([PR](https://github.com/tidalcycles/strudel/pull/1213)) +- [mqtt](https://strudel.cc/learn/input-output/#mqtt) ([PR](https://github.com/tidalcycles/strudel/pull/1224)) +- pulse oscillator (todo: https://github.com/tidalcycles/strudel/issues/1336) ([PR](https://github.com/tidalcycles/strudel/pull/1304)) +- theme improvements + +## breaking changes + +- [breaking change] Sample signals from query onset, rather than midpoint by @yaxu in https://github.com/tidalcycles/strudel/pull/1278 +- change behaviour of polymeter, and remove polymeterSteps by @yaxu in https://github.com/tidalcycles/strudel/pull/1302 +- Polish, rename, and document stepwise functions by @yaxu in https://github.com/tidalcycles/strudel/pull/1262 + +### superdough + +- feat: Create Pulse Oscillator with variable PWM by @daslyfe in https://github.com/tidalcycles/strudel/pull/1304 +- add num samples (edited numbers) by @yaxu in https://github.com/tidalcycles/strudel/pull/1309 +- Add num samples from 0 up to 20 by @yaxu in https://github.com/tidalcycles/strudel/pull/1310 +- feat: add max polyphony feature for superdough by @daslyfe in https://github.com/tidalcycles/strudel/pull/1317 + +### docs + +- doc: visual functions + refactor onPaint by @felixroos in https://github.com/tidalcycles/strudel/pull/1125 +- Labeled statements doc by @felixroos in https://github.com/tidalcycles/strudel/pull/1126 +- Correct spelling mistakes by @EdwardBetts in https://github.com/tidalcycles/strudel/pull/1183 +- remove redundant example for cat, update snapshot by @kdiab in https://github.com/tidalcycles/strudel/pull/1189 +- chore: Edit run locally instructions in README.md by @ChinoUkaegbu in https://github.com/tidalcycles/strudel/pull/1206 +- suggested changes to voicings.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/1231 +- Documentation for all/each, and bugfix for each by @yaxu in https://github.com/tidalcycles/strudel/pull/1233 +- Update documentation for param value modification by @gillespi314 in https://github.com/tidalcycles/strudel/pull/1238 +- fix docs for beat function by @daslyfe in https://github.com/tidalcycles/strudel/pull/1248 +- understand voicings page by @felixroos in https://github.com/tidalcycles/strudel/pull/1230 +- add reference package by @felixroos in https://github.com/tidalcycles/strudel/pull/1252 +- Stepwise documentation tweaks, with mridangam samples by @yaxu in https://github.com/tidalcycles/strudel/pull/1275 +- showcase tweaks by @yaxu in https://github.com/tidalcycles/strudel/pull/1291 +- Signpost licenses for source code and samples a bit more, ref #1277 by @yaxu in https://github.com/tidalcycles/strudel/pull/1289 +- Fix misplaced ending sentence by @makmanalp in https://github.com/tidalcycles/strudel/pull/1296 +- Fix typo pattnr by @ReneNyffenegger in https://github.com/tidalcycles/strudel/pull/1316 +- update docs to reflect import sounds tab change by @hpunq in https://github.com/tidalcycles/strudel/pull/1332 + +### ui improvements + +- Udels (MultiFrame Strudel) Revisited by @daslyfe in https://github.com/tidalcycles/strudel/pull/1132 +- Create audio target selector for OSC/Superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1160 +- Add a search bar to the REPL Reference tab by @netux in https://github.com/tidalcycles/strudel/pull/1165 +- Adding search bar (soundtab.jsx) by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/1185 +- add 2 new ui settings by @felixroos in https://github.com/tidalcycles/strudel/pull/1200 +- Theme glowup by @felixroos in https://github.com/tidalcycles/strudel/pull/1268 +- Create Pattern Page Pagination by @daslyfe in https://github.com/tidalcycles/strudel/pull/1287 +- feat: Theme improvements by @daslyfe in https://github.com/tidalcycles/strudel/pull/1295 +- feat: new themes + theme improvements by @daslyfe in https://github.com/tidalcycles/strudel/pull/1326 +- Add new "import-sounds" tab with explanation on folder import by @hpunq in https://github.com/tidalcycles/strudel/pull/1329 +- Add Icon to import sample button by @daslyfe in https://github.com/tidalcycles/strudel/pull/1331 +- better spacing in zen mode by @felixroos in https://github.com/tidalcycles/strudel/pull/1147 +- Screenreader improvements by @yaxu in https://github.com/tidalcycles/strudel/pull/1158 +- colorize console + tweak header by @felixroos in https://github.com/tidalcycles/strudel/pull/1203 +- Menu Panel Improvements! by @daslyfe in https://github.com/tidalcycles/strudel/pull/1193 +- Make panel hover behavior optional by @daslyfe in https://github.com/tidalcycles/strudel/pull/1199 +- REPL: solo and sync configuration by @bthj in https://github.com/tidalcycles/strudel/pull/1214 +- enhancement: make error messages easier to read by @daslyfe in https://github.com/tidalcycles/strudel/pull/1315 + +### mqtt + +- MQTT support by @yaxu in https://github.com/tidalcycles/strudel/pull/1224 +- MQTT - if password isn't provided, prompt for one by @yaxu in https://github.com/tidalcycles/strudel/pull/1249 +- MQTT - support adding hap duration and cps metadata to JSON messages by @yaxu in https://github.com/tidalcycles/strudel/pull/1279 +- make mqtt topic patternable by @yaxu in https://github.com/tidalcycles/strudel/pull/1280 +- Bugfix: update mqtt connections dictionary by @yaxu in https://github.com/tidalcycles/strudel/pull/1281 +- mqtt bugfix - connection check by @yaxu in https://github.com/tidalcycles/strudel/pull/1282 + +### new functions + +- Add scramble and shuffle by @yaxu in https://github.com/tidalcycles/strudel/pull/1167 +- polyJoin by @yaxu in https://github.com/tidalcycles/strudel/pull/1168 +- Add seqPLoop from Tidal by @yaxu in https://github.com/tidalcycles/strudel/pull/1182 +- add filter + filterWhen + within by @felixroos in https://github.com/tidalcycles/strudel/pull/1039 +- Add bite function by @yaxu in https://github.com/tidalcycles/strudel/pull/1187 +- markcss by @felixroos in https://github.com/tidalcycles/strudel/pull/1202 +- "beat" function for "step sequencer" style rhythm notation by @daslyfe in https://github.com/tidalcycles/strudel/pull/1237 +- Add s_zip for 'cat'-ing patterns together step-by-step, bugfix `steps` by @yaxu in https://github.com/tidalcycles/strudel/pull/1208 +- "stretch" function (phase vocoder) by @daslyfe in https://github.com/tidalcycles/strudel/pull/1130 +- add basic spectrum function by @felixroos in https://github.com/tidalcycles/strudel/pull/1213 +- Add onKey function for custom key commands for patterns by @daslyfe in https://github.com/tidalcycles/strudel/pull/1235 +- Add binary and binaryN by @heerman in https://github.com/tidalcycles/strudel/pull/1226 +- midimaps by @felixroos in https://github.com/tidalcycles/strudel/pull/1274 +- small feat: Add alias for segment and ribbon by @daslyfe in https://github.com/tidalcycles/strudel/pull/1314 +- feat: Create scrub function for scrubbing an audio file by @daslyfe in https://github.com/tidalcycles/strudel/pull/1321 +- feat: Improve gain curve by @daslyfe in https://github.com/tidalcycles/strudel/pull/1318 +- Chop chop by @yaxu in https://github.com/tidalcycles/strudel/pull/1078 + +### more + +- Make `all()` post-stack again, and add `each()` for pre-stack by @yaxu in https://github.com/tidalcycles/strudel/pull/1229 +- Add stepBind, and some toplevel aliases for binds and withValue by @yaxu in https://github.com/tidalcycles/strudel/pull/1241 +- Make cps patternable by @eefano in https://github.com/tidalcycles/strudel/pull/1001 +- Allow wchooseCycles probabilities to be patterned by @yaxu in https://github.com/tidalcycles/strudel/pull/1292 +- @strudel/sampler improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/1288 + +### refactor + +- export comment commands by @felixroos in https://github.com/tidalcycles/strudel/pull/113 + 6 +- containerize/seperate out boolean checks for repl types/Repl logic into bespoke components. by @daslyfe in https://github.com/tidalcycles/strudel/pull/1163 +- Improve + simplify neocyclist timing by @daslyfe in https://github.com/tidalcycles/strudel/pull/1164 +- Make phaser control consistent with superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1178 +- Revert "Make phaser control consistent with superdirt" by @daslyfe in https://github.com/tidalcycles/strudel/pull/1179 +- make phaser control match superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1180 +- refactor sampler by @felixroos in https://github.com/tidalcycles/strudel/pull/1101 +- update lockfile + minor versions by @felixroos in https://github.com/tidalcycles/strudel/pull/1198 +- Preserve tactus for 'degrade' and friends, and tidy up 'pick' and friends by @yaxu in https://github.com/tidalcycles/strudel/pull/1205 +- Apply `all` function to individual patterns rather than final stack by @yaxu in https://github.com/tidalcycles/strudel/pull/1209 +- Revert "Fix sometimes" by @yaxu in https://github.com/tidalcycles/strudel/pull/1267 +- patchday by @felixroos in https://github.com/tidalcycles/strudel/pull/1264 +- Rename repeat back to extend by @yaxu in https://github.com/tidalcycles/strudel/pull/1285 +- Send delta in OSC message in seconds, to match tidal/superdirt by @yaxu in https://github.com/tidalcycles/strudel/pull/1323 + +### fixes + +- Fix clock worker dependency path in module builds by @matthewkaney in https://github.com/tidalcycles/strudel/pull/1129 +- Fix bug in Fraction.lcm by @yaxu in https://github.com/tidalcycles/strudel/pull/1133 +- Fix tactus marking in mininotation by @yaxu in https://github.com/tidalcycles/strudel/pull/1144 +- Fix loopAt tactus by @yaxu in https://github.com/tidalcycles/strudel/pull/1145 +- Fix OSC clock jitter by @daslyfe in https://github.com/tidalcycles/strudel/pull/1157 +- [CORS HOTFIX] by @daslyfe in https://github.com/tidalcycles/strudel/pull/1162 +- Fixes fit so it works after a chop or slice by @yaxu in https://github.com/tidalcycles/strudel/pull/1171 +- fix sample speed when using splice and fit with superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1172 +- handle midin device not found error by @felixroos in https://github.com/tidalcycles/strudel/pull/1146 +- Fix serial timing by @yaxu in https://github.com/tidalcycles/strudel/pull/1188 +- Fix regression for d1, p1, p(n) by @yaxu in https://github.com/tidalcycles/strudel/pull/1227 +- Fix sometimes by @yaxu in https://github.com/tidalcycles/strudel/pull/1243 +- Fix sf2 timing by @felixroos in https://github.com/tidalcycles/strudel/pull/1272 +- Fix "squeezejoin" and functions using it, including "bite" by @yaxu in https://github.com/tidalcycles/strudel/pull/1286 +- Fixes inverted triangle wave by renaming it to "itri", making non-inverted "tri" by @yaxu in https://github.com/tidalcycles/strudel/pull/1283 +- Hotfix: prevent undefined pattern code from crashing strudel on load by @daslyfe in https://github.com/tidalcycles/strudel/pull/1297 +- Fix test error #1297 by @nkymut in https://github.com/tidalcycles/strudel/pull/1298 +- bugfix zoom stepcount by @yaxu in https://github.com/tidalcycles/strudel/pull/1301 +- bugfix: Allow single param to be used in the as function by @daslyfe in https://github.com/tidalcycles/strudel/pull/1312 +- fix: replace empty spaces in registered sound keys by @daslyfe in https://github.com/tidalcycles/strudel/pull/1319 +- FIX: Multichannel Audio by @daslyfe in https://github.com/tidalcycles/strudel/pull/1322 +- fix: udels header by @daslyfe in https://github.com/tidalcycles/strudel/pull/1325 +- fix: disable astro toolbar by default by @daslyfe in https://github.com/tidalcycles/strudel/pull/1324 +- FIX: sound import order by @daslyfe in https://github.com/tidalcycles/strudel/pull/1333` + +## New Contributors + +- @EdwardBetts made their first contribution in https://github.com/tidalcycles/strudel/pull/1183 +- @netux made their first contribution in https://github.com/tidalcycles/strudel/pull/1165 +- @kdiab made their first contribution in https://github.com/tidalcycles/strudel/pull/1189 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v1.1.0...v1.1.1 + +## packages + +- @strudel/codemirror@1.2.0 +- @strudel/core@1.2.0 +- @strudel/csound@1.2.0 +- @strudel/draw@1.2.0 +- @strudel/gamepad@1.2.0 +- @strudel/hydra@1.2.0 +- @strudel/midi@1.2.0 +- @strudel/mini@1.2.0 +- @strudel/motion@1.2.0 +- @strudel/mqtt@1.2.0 +- @strudel/osc@1.2.0 +- @strudel/reference@1.2.0 +- @strudel/repl@1.2.0 +- @strudel/sampler@0.2.0 +- @strudel/serial@1.2.0 +- @strudel/soundfonts@1.2.0 +- superdough@1.2.0 +- @strudel/tonal@1.2.0 +- @strudel/transpiler@1.2.0 +- @strudel/web@1.2.0 +- @strudel/webaudio@1.2.0 +- @strudel/xen@1.2.0 From 5a72ea94b15e1905e82dd210ac18f63ebae9b5cc Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 30 Jun 2025 05:15:30 +0200 Subject: [PATCH 17/25] fix: format --- website/src/content/blog/release-1.2.0-kardinalschnitten.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/src/content/blog/release-1.2.0-kardinalschnitten.mdx b/website/src/content/blog/release-1.2.0-kardinalschnitten.mdx index e58e27aec..e215d4532 100644 --- a/website/src/content/blog/release-1.2.0-kardinalschnitten.mdx +++ b/website/src/content/blog/release-1.2.0-kardinalschnitten.mdx @@ -110,8 +110,7 @@ author: froos ### refactor -- export comment commands by @felixroos in https://github.com/tidalcycles/strudel/pull/113 - 6 +- expose comment commands by @felixroos in https://github.com/tidalcycles/strudel/pull/1136 - containerize/seperate out boolean checks for repl types/Repl logic into bespoke components. by @daslyfe in https://github.com/tidalcycles/strudel/pull/1163 - Improve + simplify neocyclist timing by @daslyfe in https://github.com/tidalcycles/strudel/pull/1164 - Make phaser control consistent with superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1178 From 2e3356978610400136a983740d013cb7305809c4 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 30 Jun 2025 05:48:08 +0200 Subject: [PATCH 18/25] add setDefault + resetDefaults to superdough --- packages/superdough/superdough.mjs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 14f46711b..0db5e2b99 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -150,6 +150,17 @@ const defaultDefaultValues = { fft: 8, }; +const defaultDefaultDefaultValues = Object.freeze({ ...defaultDefaultValues }); + +export function setDefault(control, value) { + const main = getControlName(control); + defaultDefaultValues[main] = value; +} + +export function resetDefaults() { + defaultDefaultValues = { ...defaultDefaultDefaultValues }; +} + let defaultControls = new Map(Object.entries(defaultDefaultValues)); export function setDefaultValue(key, value) { From c063fb6b1ca7f2cd32fe626b9545702e8b65ec24 Mon Sep 17 00:00:00 2001 From: tj-mueller Date: Mon, 30 Jun 2025 11:51:39 +0200 Subject: [PATCH 19/25] correct rd to cr --- website/src/pages/de/workshop/first-sounds.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/de/workshop/first-sounds.mdx b/website/src/pages/de/workshop/first-sounds.mdx index 3695843b0..64a58db02 100644 --- a/website/src/pages/de/workshop/first-sounds.mdx +++ b/website/src/pages/de/workshop/first-sounds.mdx @@ -95,7 +95,7 @@ Diese Kombinationen von Buchstaben stehen für verschiedene Teile eines Schlagze - `mt` = **m**iddle tom - `ht` = **h**igh tom - `rd` = **r**i**d**e cymbal -- `rd` = **cr**ash cymbal +- `cr` = **cr**ash cymbal Probier verschiedene Sounds aus! From 168269a839f54ca95dab38097f9ecbb87b90259c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 4 Jul 2025 22:29:18 +0200 Subject: [PATCH 20/25] disable fm for supersaw --- packages/superdough/synth.mjs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 13cfa13a5..88e14e5ab 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -121,7 +121,10 @@ export function registerSynthSounds() { const gainAdjustment = 1 / Math.sqrt(voices); getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend); const vibratoOscillator = getVibratoOscillator(o.parameters.get('detune'), value, begin); - const fm = applyFM(o.parameters.get('frequency'), value, begin); + // const fm = applyFM(o.parameters.get('frequency'), value, begin); + // https://codeberg.org/uzu/strudel/issues/1428 + // if you think about re-enabling this, please test with fm > 1 first + // it's like 10x gain, so it's really dangerous let envGain = gainNode(1); envGain = o.connect(envGain); @@ -133,7 +136,7 @@ export function registerSynthSounds() { destroyAudioWorkletNode(o); envGain.disconnect(); onended(); - fm?.stop(); + // fm?.stop(); vibratoOscillator?.stop(); }, begin, From 05bcd5e32fd706969aa9c9c343ed7bf43cc528e3 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 5 Jul 2025 09:01:48 +0100 Subject: [PATCH 21/25] Fix randrun and deps including shuffle. Fixes #1441 --- packages/core/signal.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index c933e7fe2..6bd6fde67 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -264,7 +264,7 @@ export const randrun = (n) => { const rands = timeToRands(t.floor().add(0.5), n); const nums = rands .map((n, i) => [n, i]) - .sort((a, b) => a[0] > b[0] - a[0] < b[0]) + .sort((a, b) => (a[0] > b[0]) - (a[0] < b[0])) .map((x) => x[1]); const i = t.cyclePos().mul(n).floor() % n; return nums[i]; From 82b14b529201f72b35e9603da43a62de22bb19ad Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 5 Jul 2025 11:13:40 +0200 Subject: [PATCH 22/25] fix: lint --- packages/superdough/superdough.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 0db5e2b99..8ff64ca8c 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -126,7 +126,7 @@ export const getAudioDevices = async () => { return devicesMap; }; -const defaultDefaultValues = { +let defaultDefaultValues = { s: 'triangle', gain: 0.8, postgain: 1, @@ -153,8 +153,8 @@ const defaultDefaultValues = { const defaultDefaultDefaultValues = Object.freeze({ ...defaultDefaultValues }); export function setDefault(control, value) { - const main = getControlName(control); - defaultDefaultValues[main] = value; + // const main = getControlName(control); // we cant do this because superdough is independent of strudel/core + defaultDefaultValues[control] = value; } export function resetDefaults() { From a901e2e3875288626ab2136b85ab969ec60847e6 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 5 Jul 2025 10:28:20 +0100 Subject: [PATCH 23/25] snapshot --- test/__snapshots__/examples.test.mjs.snap | 48 +++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index cc45848bf..36c7ca58b 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -8813,46 +8813,46 @@ exports[`runs examples > example "shrink" example index 3 1`] = ` exports[`runs examples > example "shuffle" example index 0 1`] = ` [ - "[ 0/1 → 1/4 | note:c s:piano ]", + "[ 0/1 → 1/4 | note:e s:piano ]", "[ 1/4 → 1/2 | note:d s:piano ]", - "[ 1/2 → 3/4 | note:e s:piano ]", - "[ 3/4 → 1/1 | note:f s:piano ]", - "[ 1/1 → 5/4 | note:c s:piano ]", - "[ 5/4 → 3/2 | note:d s:piano ]", - "[ 3/2 → 7/4 | note:e s:piano ]", - "[ 7/4 → 2/1 | note:f s:piano ]", - "[ 2/1 → 9/4 | note:c s:piano ]", - "[ 9/4 → 5/2 | note:d s:piano ]", + "[ 1/2 → 3/4 | note:f s:piano ]", + "[ 3/4 → 1/1 | note:c s:piano ]", + "[ 1/1 → 5/4 | note:e s:piano ]", + "[ 5/4 → 3/2 | note:c s:piano ]", + "[ 3/2 → 7/4 | note:f s:piano ]", + "[ 7/4 → 2/1 | note:d s:piano ]", + "[ 2/1 → 9/4 | note:d s:piano ]", + "[ 9/4 → 5/2 | note:c s:piano ]", "[ 5/2 → 11/4 | note:e s:piano ]", "[ 11/4 → 3/1 | note:f s:piano ]", "[ 3/1 → 13/4 | note:c s:piano ]", - "[ 13/4 → 7/2 | note:d s:piano ]", - "[ 7/2 → 15/4 | note:e s:piano ]", - "[ 15/4 → 4/1 | note:f s:piano ]", + "[ 13/4 → 7/2 | note:e s:piano ]", + "[ 7/2 → 15/4 | note:f s:piano ]", + "[ 15/4 → 4/1 | note:d s:piano ]", ] `; exports[`runs examples > example "shuffle" example index 1 1`] = ` [ - "[ 0/1 → 1/8 | note:c s:piano ]", + "[ 0/1 → 1/8 | note:e s:piano ]", "[ 1/8 → 1/4 | note:d s:piano ]", - "[ 1/4 → 3/8 | note:e s:piano ]", - "[ 3/8 → 1/2 | note:f s:piano ]", + "[ 1/4 → 3/8 | note:f s:piano ]", + "[ 3/8 → 1/2 | note:c s:piano ]", "[ 1/2 → 1/1 | note:g s:piano ]", - "[ 1/1 → 9/8 | note:c s:piano ]", - "[ 9/8 → 5/4 | note:d s:piano ]", - "[ 5/4 → 11/8 | note:e s:piano ]", - "[ 11/8 → 3/2 | note:f s:piano ]", + "[ 1/1 → 9/8 | note:e s:piano ]", + "[ 9/8 → 5/4 | note:c s:piano ]", + "[ 5/4 → 11/8 | note:f s:piano ]", + "[ 11/8 → 3/2 | note:d s:piano ]", "[ 3/2 → 2/1 | note:g s:piano ]", - "[ 2/1 → 17/8 | note:c s:piano ]", - "[ 17/8 → 9/4 | note:d s:piano ]", + "[ 2/1 → 17/8 | note:d s:piano ]", + "[ 17/8 → 9/4 | note:c s:piano ]", "[ 9/4 → 19/8 | note:e s:piano ]", "[ 19/8 → 5/2 | note:f s:piano ]", "[ 5/2 → 3/1 | note:g s:piano ]", "[ 3/1 → 25/8 | note:c s:piano ]", - "[ 25/8 → 13/4 | note:d s:piano ]", - "[ 13/4 → 27/8 | note:e s:piano ]", - "[ 27/8 → 7/2 | note:f s:piano ]", + "[ 25/8 → 13/4 | note:e s:piano ]", + "[ 13/4 → 27/8 | note:f s:piano ]", + "[ 27/8 → 7/2 | note:d s:piano ]", "[ 7/2 → 4/1 | note:g s:piano ]", ] `; From 664d76cf1b1756f1cd01155c3120642793297f62 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 5 Jul 2025 11:32:16 +0200 Subject: [PATCH 24/25] resetDefaults when editor is reset --- website/src/repl/useReplContext.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/src/repl/useReplContext.jsx b/website/src/repl/useReplContext.jsx index 12621c50a..ac30fe342 100644 --- a/website/src/repl/useReplContext.jsx +++ b/website/src/repl/useReplContext.jsx @@ -13,6 +13,7 @@ import { resetGlobalEffects, resetLoadedSounds, initAudioOnFirstClick, + resetDefaults, } from '@strudel/webaudio'; import { setVersionDefaultsFrom } from './util.mjs'; import { StrudelMirror, defaultSettings } from '@strudel/codemirror'; @@ -181,6 +182,7 @@ export function useReplContext() { const resetEditor = async () => { (await getModule('@strudel/tonal'))?.resetVoicings(); + resetDefaults(); resetGlobalEffects(); clearCanvas(); clearHydra(); From a7a283a99e1505005e45ccf0e7df0f5be83391e2 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 6 Jul 2025 17:00:33 +0200 Subject: [PATCH 25/25] doc: add version tagging guide to contributing.md --- CONTRIBUTING.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f455741f5..a7f65b5bf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -150,6 +150,7 @@ Important: Always publish with `pnpm`, as `npm` does not support overriding main ## useful commands + ```sh #regenerate the test snapshots (ex: when updating or creating new pattern functions) pnpm snapshot @@ -160,6 +161,81 @@ pnpm run osc #build the standalone version pnpm tauri build ``` + +## version tag patching + +here's a little guide on how to patch patterns in the database to prevent breaking old patterns due to breaking changes in newer versions. + +the general tactic is to use `// @version x.y` to tag a pattern with a specific strudel version. when a pattern is evaluated, this metadata will de-activate any breaking changes that came after the specified version. +for example, in version 1.1, the default value for `fanchor` was changed from `0.5` to `0`. +if play a pattern that was made before that change, sounds that use filter evenlopes can sound very different, so by adding `// @version 1.0` will make it sound like it used to. +before releasing a new version with breaking changes, we can edit all patterns in the database, inserting the version tag they were created under: + +as an example, to release version 1.2, do the following: + +1. get date range + +```sh +# get date of last version: +git log -1 --format=%aI @strudel/core@1.1.0 +# 2024-05-31T23:07:26+02:00 + +# get date of current version: +git log -1 --format=%aI @strudel/core@1.2.0 +# 2025-05-01T12:39:24+02:00 +# might also use todays timestamp if version is not yet released +``` + +now we know, all patterns between these 2 dates have to receive a version tag (unless they already have one). + +2. get patterns in question + +```sql +SELECT * +FROM code_v1 +WHERE code NOT LIKE '%@version%' +AND created_at > '2024-05-31T23:07:26+02:00' +AND created_at < '2025-05-01T12:39:24+02:00' +ORDER BY created_at ASC; +``` + +this gives us all unversioned patterns that were saved between 1.1.0 and 1.2.0. in this case, it's 9373 patterns! + +3. insert version tags + +we are now ready to insert the version tag to these patterns. +before updating thousands of patterns, it's probably a good idea to test if a single one gets udpated: + +```sql +UPDATE code_v1 +SET code = code || E'\n// @version 1.1' +WHERE hash = 'Ns2sMB40yIw4'; +``` + +after [verifying](https://strudel.cc/?Ns2sMB40yIw4) that the version tag has been added, let's insert it everywhere: + +```sql +UPDATE code_v1 +SET code = code || E'\n// @version 1.1' +WHERE code NOT LIKE '%@version%' +AND created_at > '2024-05-31T23:07:26+02:00' +AND created_at < '2025-05-01T12:39:24+02:00' +``` + +4. verify + +we can verify that the edits worked by querying all patterns that contain the new version tag: + +```sql +SELECT * +FROM code_v1 +WHERE code LIKE '%@version 1.1%' +AND created_at > '2024-05-31T23:07:26+02:00' +AND created_at < '2025-05-01T12:39:24+02:00' +ORDER BY created_at ASC; +``` + + ## Have Fun Remember to have fun, and that this project is driven by the passion of volunteers!