From e0a21a936bad89b1b8cf349fcde5b9a596122250 Mon Sep 17 00:00:00 2001
From: "Jade (Rose) Rowland"
Date: Mon, 2 Jun 2025 12:57:37 +0100
Subject: [PATCH 1/8] berlin
---
packages/core/signal.mjs | 43 ++++++++++++++++++++---
packages/superdough/worklets.mjs | 1 -
test/__snapshots__/examples.test.mjs.snap | 2 ++
3 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs
index b6ba5d5c..8e2d12b7 100644
--- a/packages/core/signal.mjs
+++ b/packages/core/signal.mjs
@@ -486,13 +486,34 @@ export const wchooseCycles = (...pairs) => _wchooseWith(rand.segment(1), ...pair
export const wrandcat = wchooseCycles;
-// this function expects pat to be a pattern of floats...
-export const perlinWith = (pat) => {
- const pata = pat.fmap(Math.floor);
- const patb = pat.fmap((t) => Math.floor(t) + 1);
+function _perlin(t) {
+ let ta = Math.floor(t);
+ let tb = ta + 1;
const smootherStep = (x) => 6.0 * x ** 5 - 15.0 * x ** 4 + 10.0 * x ** 3;
const interp = (x) => (a) => (b) => a + smootherStep(x) * (b - a);
- return pat.sub(pata).fmap(interp).appBoth(pata.fmap(timeToRand)).appBoth(patb.fmap(timeToRand));
+ const v = interp(t - ta)(timeToRand(ta))(timeToRand(tb));
+ return v;
+}
+export const perlinWith = (tpat) => {
+ return tpat.fmap(_perlin);
+};
+
+function _berlin(t) {
+ const prevRidgeStartIndex = Math.floor(t);
+ const nextRidgeStartIndex = prevRidgeStartIndex + 1;
+
+ const prevRidgeBottomPoint = timeToRand(prevRidgeStartIndex);
+ const nextRidgeTopPoint = timeToRand(nextRidgeStartIndex) + prevRidgeBottomPoint;
+
+ const currentPercent = (t - prevRidgeStartIndex) / (nextRidgeStartIndex - prevRidgeStartIndex);
+ const interp = (a, b, t) => {
+ return a + (b - a) * t;
+ };
+ return interp(prevRidgeBottomPoint, nextRidgeTopPoint, currentPercent) / 2;
+}
+
+export const berlinWith = (tpat) => {
+ return tpat.fmap(_berlin);
};
/**
@@ -506,6 +527,18 @@ export const perlinWith = (pat) => {
*/
export const perlin = perlinWith(time.fmap((v) => Number(v)));
+/**
+ * Generates a continuous pattern of [berlin noise](conceived by Jame Coyne and Jade Rowland as a joke but turned out to be surprisingly cool and useful,
+ * like perlin noise but with sawtooth waves), in the range 0..1.
+ *
+ * @name berlin
+ * @example
+ * // ascending arpeggios
+ * $: n("0!16".add(berlin.fast(4).mul(14))).scale("d:minor")._pianoroll()
+ *
+ */
+export const berlin = berlinWith(time.fmap((v) => Number(v)));
+
export const degradeByWith = register(
'degradeByWith',
(withPat, x, pat) => pat.fmap((a) => (_) => a).appLeft(withPat.filterValues((v) => v > x)),
diff --git a/packages/superdough/worklets.mjs b/packages/superdough/worklets.mjs
index 24f7434a..6f526ec8 100644
--- a/packages/superdough/worklets.mjs
+++ b/packages/superdough/worklets.mjs
@@ -882,7 +882,6 @@ class ByteBeatProcessor extends AudioWorkletProcessor {
const funcValue = this.func(local_t);
let signal = (funcValue & 255) / 127.5 - 1;
const out = signal * 0.2;
-
for (let c = 0; c < output.length; c++) {
//prevent speaker blowout via clipping if threshold exceeds
output[c][i] = clamp(out, -0.4, 0.4);
diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap
index 34914664..07480305 100644
--- a/test/__snapshots__/examples.test.mjs.snap
+++ b/test/__snapshots__/examples.test.mjs.snap
@@ -1051,6 +1051,8 @@ exports[`runs examples > example "begin" example index 0 1`] = `
]
`;
+exports[`runs examples > example "berlin" example index 0 1`] = `[]`;
+
exports[`runs examples > example "binary" example index 0 1`] = `
[
"[ 0/1 → 1/3 | s:hh ]",
From cde943d73712d8db15908093a8f1fac46be854f5 Mon Sep 17 00:00:00 2001
From: "Jade (Rose) Rowland"
Date: Mon, 2 Jun 2025 13:02:41 +0100
Subject: [PATCH 2/8] fix test
---
packages/core/signal.mjs | 2 +-
test/__snapshots__/examples.test.mjs.snap | 69 ++++++++++++++++++++++-
2 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs
index 8e2d12b7..5fd83bce 100644
--- a/packages/core/signal.mjs
+++ b/packages/core/signal.mjs
@@ -534,7 +534,7 @@ export const perlin = perlinWith(time.fmap((v) => Number(v)));
* @name berlin
* @example
* // ascending arpeggios
- * $: n("0!16".add(berlin.fast(4).mul(14))).scale("d:minor")._pianoroll()
+ * n("0!16".add(berlin.fast(4).mul(14))).scale("d:minor")
*
*/
export const berlin = berlinWith(time.fmap((v) => Number(v)));
diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap
index 07480305..b57d319a 100644
--- a/test/__snapshots__/examples.test.mjs.snap
+++ b/test/__snapshots__/examples.test.mjs.snap
@@ -1051,7 +1051,74 @@ exports[`runs examples > example "begin" example index 0 1`] = `
]
`;
-exports[`runs examples > example "berlin" example index 0 1`] = `[]`;
+exports[`runs examples > example "berlin" example index 0 1`] = `
+[
+ "[ 0/1 → 1/16 | note:D3 ]",
+ "[ 1/16 → 1/8 | note:E3 ]",
+ "[ 1/8 → 3/16 | note:F3 ]",
+ "[ 3/16 → 1/4 | note:G3 ]",
+ "[ 1/4 → 5/16 | note:A3 ]",
+ "[ 5/16 → 3/8 | note:C4 ]",
+ "[ 3/8 → 7/16 | note:D4 ]",
+ "[ 7/16 → 1/2 | note:F4 ]",
+ "[ 1/2 → 9/16 | note:D4 ]",
+ "[ 9/16 → 5/8 | note:E4 ]",
+ "[ 5/8 → 11/16 | note:E4 ]",
+ "[ 11/16 → 3/4 | note:E4 ]",
+ "[ 3/4 → 13/16 | note:F3 ]",
+ "[ 13/16 → 7/8 | note:F3 ]",
+ "[ 7/8 → 15/16 | note:F3 ]",
+ "[ 15/16 → 1/1 | note:F3 ]",
+ "[ 1/1 → 17/16 | note:E3 ]",
+ "[ 17/16 → 9/8 | note:E3 ]",
+ "[ 9/8 → 19/16 | note:E3 ]",
+ "[ 19/16 → 5/4 | note:F3 ]",
+ "[ 5/4 → 21/16 | note:E3 ]",
+ "[ 21/16 → 11/8 | note:F3 ]",
+ "[ 11/8 → 23/16 | note:G3 ]",
+ "[ 23/16 → 3/2 | note:A3 ]",
+ "[ 3/2 → 25/16 | note:A3 ]",
+ "[ 25/16 → 13/8 | note:Bb3 ]",
+ "[ 13/8 → 27/16 | note:Bb3 ]",
+ "[ 27/16 → 7/4 | note:Bb3 ]",
+ "[ 7/4 → 29/16 | note:F3 ]",
+ "[ 29/16 → 15/8 | note:G3 ]",
+ "[ 15/8 → 31/16 | note:Bb3 ]",
+ "[ 31/16 → 2/1 | note:C4 ]",
+ "[ 2/1 → 33/16 | note:C4 ]",
+ "[ 33/16 → 17/8 | note:D4 ]",
+ "[ 17/8 → 35/16 | note:F4 ]",
+ "[ 35/16 → 9/4 | note:G4 ]",
+ "[ 9/4 → 37/16 | note:Bb3 ]",
+ "[ 37/16 → 19/8 | note:Bb3 ]",
+ "[ 19/8 → 39/16 | note:Bb3 ]",
+ "[ 39/16 → 5/2 | note:C4 ]",
+ "[ 5/2 → 41/16 | note:F3 ]",
+ "[ 41/16 → 21/8 | note:F3 ]",
+ "[ 21/8 → 43/16 | note:G3 ]",
+ "[ 43/16 → 11/4 | note:A3 ]",
+ "[ 11/4 → 45/16 | note:A3 ]",
+ "[ 45/16 → 23/8 | note:A3 ]",
+ "[ 23/8 → 47/16 | note:A3 ]",
+ "[ 47/16 → 3/1 | note:A3 ]",
+ "[ 3/1 → 49/16 | note:E3 ]",
+ "[ 49/16 → 25/8 | note:G3 ]",
+ "[ 25/8 → 51/16 | note:Bb3 ]",
+ "[ 51/16 → 13/4 | note:C4 ]",
+ "[ 13/4 → 53/16 | note:D4 ]",
+ "[ 53/16 → 27/8 | note:E4 ]",
+ "[ 27/8 → 55/16 | note:G4 ]",
+ "[ 55/16 → 7/2 | note:A4 ]",
+ "[ 7/2 → 57/16 | note:Bb3 ]",
+ "[ 57/16 → 29/8 | note:Bb3 ]",
+ "[ 29/8 → 59/16 | note:C4 ]",
+ "[ 59/16 → 15/4 | note:C4 ]",
+ "[ 15/4 → 61/16 | note:F3 ]",
+ "[ 61/16 → 31/8 | note:G3 ]",
+ "[ 31/8 → 63/16 | note:G3 ]",
+ "[ 63/16 → 4/1 | note:A3 ]",
+]
+`;
exports[`runs examples > example "binary" example index 0 1`] = `
[
From df923174ede5ba5df5d54db5a22d90ff05778e1f Mon Sep 17 00:00:00 2001
From: "Jade (Rose) Rowland"
Date: Tue, 3 Jun 2025 01:22:37 +0100
Subject: [PATCH 3/8] working
---
packages/core/pattern.mjs | 19 ++++++++++++
test/__snapshots__/examples.test.mjs.snap | 37 +++++++++++++++++++++++
2 files changed, 56 insertions(+)
diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs
index 56a6b77d..efbae1f3 100644
--- a/packages/core/pattern.mjs
+++ b/packages/core/pattern.mjs
@@ -3192,6 +3192,25 @@ export const slice = register(
false, // turns off auto-patternification
);
+/**
+ *
+ * make something happen on event time
+ * uses browser timeout which is innacurate for audio tasks
+ * @name onTriggerTime
+ * @memberof Pattern
+ * @returns Pattern
+ * @example
+ * s("bd!8").onTriggerTime((hap) => {console.info(hap)})
+ */
+Pattern.prototype.onTriggerTime = function (func) {
+ return this.onTrigger((t_deprecate, hap, currentTime, cps = 1, targetTime) => {
+ const diff = targetTime - currentTime;
+ window.setTimeout(() => {
+ func(hap);
+ }, diff * 1000);
+ }, false);
+};
+
/**
* Works the same as slice, but changes the playback speed of each slice to match the duration of its step.
* @name splice
diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap
index 34914664..2ee135b9 100644
--- a/test/__snapshots__/examples.test.mjs.snap
+++ b/test/__snapshots__/examples.test.mjs.snap
@@ -5950,6 +5950,43 @@ exports[`runs examples > example "often" example index 0 1`] = `
]
`;
+exports[`runs examples > example "onTriggerTime" example index 0 1`] = `
+[
+ "[ 0/1 → 1/8 | s:bd ]",
+ "[ 1/8 → 1/4 | s:bd ]",
+ "[ 1/4 → 3/8 | s:bd ]",
+ "[ 3/8 → 1/2 | s:bd ]",
+ "[ 1/2 → 5/8 | s:bd ]",
+ "[ 5/8 → 3/4 | s:bd ]",
+ "[ 3/4 → 7/8 | s:bd ]",
+ "[ 7/8 → 1/1 | s:bd ]",
+ "[ 1/1 → 9/8 | s:bd ]",
+ "[ 9/8 → 5/4 | s:bd ]",
+ "[ 5/4 → 11/8 | s:bd ]",
+ "[ 11/8 → 3/2 | s:bd ]",
+ "[ 3/2 → 13/8 | s:bd ]",
+ "[ 13/8 → 7/4 | s:bd ]",
+ "[ 7/4 → 15/8 | s:bd ]",
+ "[ 15/8 → 2/1 | s:bd ]",
+ "[ 2/1 → 17/8 | s:bd ]",
+ "[ 17/8 → 9/4 | s:bd ]",
+ "[ 9/4 → 19/8 | s:bd ]",
+ "[ 19/8 → 5/2 | s:bd ]",
+ "[ 5/2 → 21/8 | s:bd ]",
+ "[ 21/8 → 11/4 | s:bd ]",
+ "[ 11/4 → 23/8 | s:bd ]",
+ "[ 23/8 → 3/1 | s:bd ]",
+ "[ 3/1 → 25/8 | s:bd ]",
+ "[ 25/8 → 13/4 | s:bd ]",
+ "[ 13/4 → 27/8 | s:bd ]",
+ "[ 27/8 → 7/2 | s:bd ]",
+ "[ 7/2 → 29/8 | s:bd ]",
+ "[ 29/8 → 15/4 | s:bd ]",
+ "[ 15/4 → 31/8 | s:bd ]",
+ "[ 31/8 → 4/1 | s:bd ]",
+]
+`;
+
exports[`runs examples > example "orbit" example index 0 1`] = `
[
"[ 0/1 → 1/6 | s:hh delay:0.5 delaytime:0.25 orbit:1 ]",
From 2c9f9d785f13e76d5c7304372d0e8c9f4df615d1 Mon Sep 17 00:00:00 2001
From: Felix Roos
Date: Thu, 12 Jun 2025 08:39:27 +0200
Subject: [PATCH 4/8] hotfix: close bakery
---
website/src/config.ts | 2 +-
website/src/repl/components/Header.jsx | 8 ++--
.../src/repl/components/panel/PatternsTab.jsx | 37 +++++++++++--------
3 files changed, 26 insertions(+), 21 deletions(-)
diff --git a/website/src/config.ts b/website/src/config.ts
index 2f499d55..e88b7f3e 100644
--- a/website/src/config.ts
+++ b/website/src/config.ts
@@ -58,7 +58,7 @@ export const SIDEBAR: Sidebar = {
{ text: 'What is Strudel?', link: 'workshop/getting-started' },
{ text: 'Showcase', link: 'intro/showcase' },
{ text: 'Blog', link: 'blog' },
- { text: 'Community Bakery', link: 'bakery' },
+ /* { text: 'Community Bakery', link: 'bakery' }, */
],
Workshop: [
// { text: 'Getting Started', link: 'workshop/getting-started' },
diff --git a/website/src/repl/components/Header.jsx b/website/src/repl/components/Header.jsx
index 2963a5f9..a97e2bed 100644
--- a/website/src/repl/components/Header.jsx
+++ b/website/src/repl/components/Header.jsx
@@ -93,7 +93,7 @@ export function Header({ context, embedded = false }) {
>
{!isEmbedded && update }
- {!isEmbedded && (
+ {/* !isEmbedded && (
shuffle
- )}
- {!isEmbedded && (
+ ) */}
+ {/* !isEmbedded && (
share
- )}
+ ) */}
{!isEmbedded && (
- {patternFilter === patternFilterName.user && (
-
- updateCodeWindow(
- context,
- { ...userPatterns[id], collection: userPattern.collection },
- autoResetPatternOnChange,
- )
- }
- patterns={userPatterns}
- started={context.started}
- activePattern={activePattern}
- viewingPatternID={viewingPatternID}
- />
- )}
+ {/* {patternFilter === patternFilterName.user && ( */}
+
+ updateCodeWindow(
+ context,
+ { ...userPatterns[id], collection: userPattern.collection },
+ autoResetPatternOnChange,
+ )
+ }
+ patterns={userPatterns}
+ started={context.started}
+ activePattern={activePattern}
+ viewingPatternID={viewingPatternID}
+ />
+ {/* )} */}
);
@@ -250,6 +250,11 @@ export function PatternsTab({ context }) {
const { patternFilter } = useSettings();
return (
+
+
+
+ );
+ /* return (
)}
- );
+ ); */
}
From 79f7938b3381b426e85b67ec163abaee5423ed92 Mon Sep 17 00:00:00 2001
From: Felix Roos
Date: Thu, 12 Jun 2025 08:51:03 +0200
Subject: [PATCH 5/8] hotfix: add default code
---
website/src/repl/useReplContext.jsx | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/website/src/repl/useReplContext.jsx b/website/src/repl/useReplContext.jsx
index f88e5a6e..708506cc 100644
--- a/website/src/repl/useReplContext.jsx
+++ b/website/src/repl/useReplContext.jsx
@@ -59,6 +59,8 @@ async function getModule(name) {
return modules.find((m) => m.packageName === name);
}
+const initialCode = `$: s("[bd ]*2").bank("tr909").dec(.4)`;
+
export function useReplContext() {
const { isSyncEnabled, audioEngineTarget } = useSettings();
const shouldUseWebaudio = audioEngineTarget !== audioEngineTargets.osc;
@@ -77,7 +79,7 @@ export function useReplContext() {
transpiler,
autodraw: false,
root: containerRef.current,
- initialCode: '// LOADING',
+ initialCode,
pattern: silence,
drawTime,
drawContext,
From 40ba5d44652d18dc84bcc4d9f9d542f18d573551 Mon Sep 17 00:00:00 2001
From: Felix Roos
Date: Thu, 12 Jun 2025 09:11:19 +0200
Subject: [PATCH 6/8] hotfix: don't load patterns from db
---
website/src/repl/util.mjs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/website/src/repl/util.mjs b/website/src/repl/util.mjs
index f49dd568..9db280da 100644
--- a/website/src/repl/util.mjs
+++ b/website/src/repl/util.mjs
@@ -7,7 +7,7 @@ import './Repl.css';
import { createClient } from '@supabase/supabase-js';
import { nanoid } from 'nanoid';
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
-import { $featuredPatterns, loadDBPatterns } from '@src/user_pattern_utils.mjs';
+import { $featuredPatterns /* , loadDBPatterns */ } from '@src/user_pattern_utils.mjs';
// Create a single supabase client for interacting with your database
export const supabase = createClient(
@@ -16,9 +16,9 @@ export const supabase = createClient(
);
let dbLoaded;
-if (typeof window !== 'undefined') {
+/* if (typeof window !== 'undefined') {
dbLoaded = loadDBPatterns();
-}
+} */
export async function initCode() {
// load code from url hash (either short hash from database or decode long hash)
From ef3b9a68e362218bef0a79f0954fad5fa6a38aae Mon Sep 17 00:00:00 2001
From: Felix Roos
Date: Thu, 12 Jun 2025 09:21:57 +0200
Subject: [PATCH 7/8] hotfix: leave out part about shuffle in welcome tab
---
website/src/repl/components/panel/WelcomeTab.jsx | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/website/src/repl/components/panel/WelcomeTab.jsx b/website/src/repl/components/panel/WelcomeTab.jsx
index 1049a581..a43f02ad 100644
--- a/website/src/repl/components/panel/WelcomeTab.jsx
+++ b/website/src/repl/components/panel/WelcomeTab.jsx
@@ -15,17 +15,18 @@ export function WelcomeTab({ context }) {
1. hit play - 2. change something -{' '}
3. hit update
-
- If you don't like what you hear, try shuffle !
+ {/*
+ If you don't like what you hear, try shuffle ! */}
- To learn more about what this all means, check out the{' '}
+ {/* To learn more about what this all means, check out the{' '} */}
+ To get started, check out the
interactive tutorial
. Also feel free to join the{' '}
- tidalcycles discord channel
+ discord channel
{' '}
to ask any questions, give feedback or just say hello.
From 694a22af85494444c3d07c3c48da48d20afbe390 Mon Sep 17 00:00:00 2001
From: Felix Roos
Date: Thu, 12 Jun 2025 09:51:04 +0200
Subject: [PATCH 8/8] hotfix: bring back loading code + fill in default pattern
later
---
website/src/repl/useReplContext.jsx | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/website/src/repl/useReplContext.jsx b/website/src/repl/useReplContext.jsx
index 708506cc..36e8099c 100644
--- a/website/src/repl/useReplContext.jsx
+++ b/website/src/repl/useReplContext.jsx
@@ -59,7 +59,7 @@ async function getModule(name) {
return modules.find((m) => m.packageName === name);
}
-const initialCode = `$: s("[bd ]*2").bank("tr909").dec(.4)`;
+const initialCode = `// LOADING`;
export function useReplContext() {
const { isSyncEnabled, audioEngineTarget } = useSettings();
@@ -135,9 +135,10 @@ export function useReplContext() {
code = latestCode;
msg = `Your last session has been loaded!`;
} else {
- const { code: randomTune, name } = await getRandomTune();
- code = randomTune;
- msg = `A random code snippet named "${name}" has been loaded!`;
+ /* const { code: randomTune, name } = await getRandomTune();
+ code = randomTune; */
+ code = '$: s("[bd ]*2").bank("tr909").dec(.4)';
+ msg = `Default code has been loaded`;
}
editor.setCode(code);
setDocumentTitle(code);