From 184cb746f331c16800ac97664dfbfd0e997efc03 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 18 Jun 2025 19:55:30 +0200 Subject: [PATCH 01/12] arch --- packages/codemirror/themes.mjs | 8 ++++ packages/codemirror/themes/archBtw.mjs | 39 ++++++++++++++++++ .../codemirror/themes/bluescreenlight.mjs | 40 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 packages/codemirror/themes/archBtw.mjs create mode 100644 packages/codemirror/themes/bluescreenlight.mjs diff --git a/packages/codemirror/themes.mjs b/packages/codemirror/themes.mjs index 6aa70471d..c3763a643 100644 --- a/packages/codemirror/themes.mjs +++ b/packages/codemirror/themes.mjs @@ -8,6 +8,9 @@ import CutiePi, { settings as CutiePiSettings } from './themes/CutiePi.mjs'; import sonicPink, { settings as sonicPinkSettings } from './themes/sonic-pink.mjs'; import redText, { settings as redTextSettings } from './themes/red-text.mjs'; import greenText, { settings as greenTextSettings } from './themes/green-text.mjs'; +import archBtw, { settings as archBtwSettings } from './themes/archBtw.mjs'; +import bluescreenlight, { settings as bluescreenlightsettings } from './themes/bluescreenlight.mjs'; + import androidstudio, { settings as androidstudioSettings } from './themes/androidstudio.mjs'; import atomone, { settings as atomOneSettings } from './themes/atomone.mjs'; import aura, { settings as auraSettings } from './themes/aura.mjs'; @@ -39,12 +42,14 @@ import { setTheme } from '@strudel/draw'; export const themes = { strudelTheme, algoboy, + archBtw, androidstudio, atomone, aura, bbedit, blackscreen, bluescreen, + bluescreenlight, CutiePi, darcula, dracula, @@ -78,10 +83,12 @@ export const themes = { export const settings = { strudelTheme: strudelThemeSettings, bluescreen: bluescreenSettings, + bluescreenlight: bluescreenlightsettings, blackscreen: blackscreenSettings, whitescreen: whitescreenSettings, teletext: teletextSettings, algoboy: algoboySettings, + archBtw: archBtwSettings, androidstudio: androidstudioSettings, atomone: atomOneSettings, aura: auraSettings, @@ -95,6 +102,7 @@ export const settings = { githubLight: githubLightSettings, githubDark: githubDarkSettings, greenText: greenTextSettings, + gruvboxDark: gruvboxDarkSettings, gruvboxLight: gruvboxLightSettings, materialDark: materialDarkSettings, diff --git a/packages/codemirror/themes/archBtw.mjs b/packages/codemirror/themes/archBtw.mjs new file mode 100644 index 000000000..7f4c1b5e3 --- /dev/null +++ b/packages/codemirror/themes/archBtw.mjs @@ -0,0 +1,39 @@ +/* + * Atom One + * Atom One dark syntax theme + * + * https://github.com/atom/one-dark-syntax + */ +import { tags as t } from '@lezer/highlight'; +import { createTheme } from './theme-helper.mjs'; + +const hex = ['rgb(0, 0, 0)', 'rgb(113, 208, 250)', 'rgba(113, 208, 250, .4)', 'rgba(113, 208, 250, .15)']; + +export const settings = { + background: hex[0], + lineBackground: 'transparent', + foreground: hex[1], + selection: hex[2], + selectionMatch: hex[0], + gutterBackground: hex[0], + gutterForeground: hex[2], + gutterBorder: 'transparent', + lineHighlight: hex[0], +}; + +export default createTheme({ + theme: 'dark', + settings, + styles: [ + { + tag: [t.function(t.variableName), t.function(t.propertyName), t.url, t.processingInstruction], + color: hex[1], + }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: hex[1] }, + { tag:[ t.comment, t.brace, t.bracket, ], color: hex[2] }, + { tag: [t.variableName, t.propertyName, t.labelName], color: hex[1] }, + { tag: [t.attributeName, t.number], color: hex[1] }, + { tag: t.keyword, color: hex[1] }, + { tag: [t.string, t.regexp, t.special(t.propertyName)], color: hex[1] }, + ], +}); diff --git a/packages/codemirror/themes/bluescreenlight.mjs b/packages/codemirror/themes/bluescreenlight.mjs new file mode 100644 index 000000000..e78bf707c --- /dev/null +++ b/packages/codemirror/themes/bluescreenlight.mjs @@ -0,0 +1,40 @@ +/* + * Atom One + * Atom One dark syntax theme + * + * https://github.com/atom/one-dark-syntax + */ +import { tags as t } from '@lezer/highlight'; +import { createTheme } from './theme-helper.mjs'; + +const hex = ['rgb(75, 130, 247)', 'rgb(47, 108, 246)', 'rgb(255, 255, 255)', 'rgba(255, 255, 255,.3)']; + +export const settings = { + background: hex[0], + lineBackground: 'transparent', + foreground: hex[2], + selection: hex[3], + selectionMatch: hex[0], + gutterBackground: hex[0], + gutterForeground: hex[2], + gutterBorder: 'transparent', + lineHighlight: hex[1], +}; + +export default createTheme({ + theme: 'dark', + settings, + styles: [ + { + tag: [t.function(t.variableName), t.function(t.propertyName), t.url, t.processingInstruction], + color: hex[2], + + }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: hex[2] }, + { tag: [t.comment, t.bracket, t.brace, t.compareOperator], color: hex[3] }, + { tag: [t.variableName, t.propertyName, t.labelName], color: hex[2] }, + { tag: [t.attributeName, t.number], color: hex[2] }, + { tag: t.keyword, color: hex[2] }, + { tag: [t.string, t.regexp, t.special(t.propertyName)], color: hex[2] }, + ], +}); From 011139eff8049abf81af37d169a19cfdbff8e4ed Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 18 Jun 2025 20:12:36 +0200 Subject: [PATCH 02/12] arch2 --- packages/codemirror/themes/archBtw.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/codemirror/themes/archBtw.mjs b/packages/codemirror/themes/archBtw.mjs index 7f4c1b5e3..1ed6a0c6a 100644 --- a/packages/codemirror/themes/archBtw.mjs +++ b/packages/codemirror/themes/archBtw.mjs @@ -7,7 +7,7 @@ import { tags as t } from '@lezer/highlight'; import { createTheme } from './theme-helper.mjs'; -const hex = ['rgb(0, 0, 0)', 'rgb(113, 208, 250)', 'rgba(113, 208, 250, .4)', 'rgba(113, 208, 250, .15)']; +const hex = ['rgb(0, 0, 0)', 'rgb(82, 208, 250)', 'rgba(113, 208, 250, .4)', 'rgba(113, 208, 250, .15)']; export const settings = { background: hex[0], From 7e6876c2824071b2603b63e80675d9be9a2e4bc9 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 18 Jun 2025 20:44:09 -0400 Subject: [PATCH 03/12] comment --- packages/codemirror/themes.mjs | 4 ++ packages/codemirror/themes/archBtw.mjs | 9 ++-- .../codemirror/themes/bluescreenlight.mjs | 11 ++-- packages/codemirror/themes/fruitDaw.mjs | 50 +++++++++++++++++++ 4 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 packages/codemirror/themes/fruitDaw.mjs diff --git a/packages/codemirror/themes.mjs b/packages/codemirror/themes.mjs index c3763a643..1a523b391 100644 --- a/packages/codemirror/themes.mjs +++ b/packages/codemirror/themes.mjs @@ -9,6 +9,8 @@ import sonicPink, { settings as sonicPinkSettings } from './themes/sonic-pink.mj import redText, { settings as redTextSettings } from './themes/red-text.mjs'; import greenText, { settings as greenTextSettings } from './themes/green-text.mjs'; import archBtw, { settings as archBtwSettings } from './themes/archBtw.mjs'; +import fruitDaw, { settings as fruitDawSettings } from './themes/fruitDaw.mjs'; + import bluescreenlight, { settings as bluescreenlightsettings } from './themes/bluescreenlight.mjs'; import androidstudio, { settings as androidstudioSettings } from './themes/androidstudio.mjs'; @@ -55,6 +57,7 @@ export const themes = { dracula, duotoneDark, eclipse, + fruitDaw, githubDark, githubLight, greenText, @@ -99,6 +102,7 @@ export const settings = { eclipse: eclipseSettings, CutiePi: CutiePiSettings, sonicPink: sonicPinkSettings, + fruitDaw: fruitDawSettings, githubLight: githubLightSettings, githubDark: githubDarkSettings, greenText: greenTextSettings, diff --git a/packages/codemirror/themes/archBtw.mjs b/packages/codemirror/themes/archBtw.mjs index 1ed6a0c6a..87546569c 100644 --- a/packages/codemirror/themes/archBtw.mjs +++ b/packages/codemirror/themes/archBtw.mjs @@ -1,8 +1,7 @@ /* - * Atom One - * Atom One dark syntax theme - * - * https://github.com/atom/one-dark-syntax + * Arch Btw + * Modern terminal inspired theme + * made by Jade */ import { tags as t } from '@lezer/highlight'; import { createTheme } from './theme-helper.mjs'; @@ -30,7 +29,7 @@ export default createTheme({ color: hex[1], }, { tag: [t.atom, t.bool, t.special(t.variableName)], color: hex[1] }, - { tag:[ t.comment, t.brace, t.bracket, ], color: hex[2] }, + { tag: [t.comment, t.brace, t.bracket], color: hex[2] }, { tag: [t.variableName, t.propertyName, t.labelName], color: hex[1] }, { tag: [t.attributeName, t.number], color: hex[1] }, { tag: t.keyword, color: hex[1] }, diff --git a/packages/codemirror/themes/bluescreenlight.mjs b/packages/codemirror/themes/bluescreenlight.mjs index e78bf707c..031a3da33 100644 --- a/packages/codemirror/themes/bluescreenlight.mjs +++ b/packages/codemirror/themes/bluescreenlight.mjs @@ -1,13 +1,11 @@ /* - * Atom One - * Atom One dark syntax theme - * - * https://github.com/atom/one-dark-syntax + * A lighter blue screen theme + * made by Jade */ import { tags as t } from '@lezer/highlight'; import { createTheme } from './theme-helper.mjs'; -const hex = ['rgb(75, 130, 247)', 'rgb(47, 108, 246)', 'rgb(255, 255, 255)', 'rgba(255, 255, 255,.3)']; +const hex = ['rgb(75, 130, 247)', 'rgb(47, 108, 246)', 'rgb(255, 255, 255)', 'rgba(255, 255, 255,.3)']; export const settings = { background: hex[0], @@ -28,9 +26,8 @@ export default createTheme({ { tag: [t.function(t.variableName), t.function(t.propertyName), t.url, t.processingInstruction], color: hex[2], - }, - { tag: [t.atom, t.bool, t.special(t.variableName)], color: hex[2] }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: hex[2] }, { tag: [t.comment, t.bracket, t.brace, t.compareOperator], color: hex[3] }, { tag: [t.variableName, t.propertyName, t.labelName], color: hex[2] }, { tag: [t.attributeName, t.number], color: hex[2] }, diff --git a/packages/codemirror/themes/fruitDaw.mjs b/packages/codemirror/themes/fruitDaw.mjs new file mode 100644 index 000000000..c9e557796 --- /dev/null +++ b/packages/codemirror/themes/fruitDaw.mjs @@ -0,0 +1,50 @@ +/* + * Fruit Daw + * made by Jade + */ +import { tags as t } from '@lezer/highlight'; +import { createTheme } from './theme-helper.mjs'; + +const hex = [ + 'rgb(84, 93, 98)', + 'rgb(255, 255, 255)', + 'rgba(255, 255, 255, .25)', + 'rgb(67, 76, 81)', + 'rgb(186, 230, 115)', + 'rgb(252, 184, 67)', + 'rgb(124, 206, 254)', + 'rgb(83, 101, 102)', + 'rgba(46, 62, 72,.5)', + 'rgb(94, 100, 108)', + 'rgb(167, 216, 177)', +]; + +export const settings = { + background: hex[0], + lineBackground: 'transparent', + foreground: hex[10], + selection: hex[8], + selectionMatch: hex[0], + gutterBackground: hex[3], + gutterForeground: hex[2], + gutterBorder: 'transparent', + lineHighlight: hex[3], +}; + +export default createTheme({ + theme: 'dark', + settings, + styles: [ + { + tag: [t.function(t.variableName), t.function(t.propertyName), t.url, t.processingInstruction], + color: hex[1], + }, + { tag: [t.bool, t.special(t.variableName)], color: hex[1] }, + { tag: [t.comment, t.brace, t.bracket], color: hex[2] }, + { tag: [t.variableName], color: hex[1] }, + { tag: [t.labelName, t.propertyName, t.self, t.atom], color: hex[5] }, + { tag: [t.attributeName, t.number], color: hex[6] }, + { tag: t.keyword, color: hex[5] }, + { tag: [t.string, t.regexp, t.special(t.propertyName)], color: hex[4] }, + ], +}); From 6c4aa12c6045fc7a6e0fa086e124124ce194bf0c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 19 Jun 2025 09:09:45 +0200 Subject: [PATCH 04/12] refactor: replace .cpm with setcpm calls + doc setcpm --- packages/core/pattern.mjs | 1 + packages/core/repl.mjs | 11 ++++ packages/gamepad/docs/gamepad.mdx | 15 ++--- .../src/pages/de/workshop/first-sounds.mdx | 56 ++++++++++++------- website/src/pages/de/workshop/recap.mdx | 20 +++---- website/src/pages/learn/samples.mdx | 10 ++-- website/src/pages/understand/cycles.mdx | 49 +++++++++++----- website/src/pages/workshop/first-notes.mdx | 22 +++++--- website/src/pages/workshop/first-sounds.mdx | 44 ++++++++++----- .../src/pages/workshop/pattern-effects.mdx | 10 ++-- website/src/pages/workshop/recap.mdx | 20 +++---- website/src/repl/tunes.mjs | 20 ------- 12 files changed, 169 insertions(+), 109 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 76b02c21e..41b09ea20 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -1981,6 +1981,7 @@ export const apply = register('apply', function (func, pat) { /** * Plays the pattern at the given cycles per minute. + * @deprecated * @example * s(",hh*2").cpm(90) // = 90 bpm */ diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 7a8cbbab2..8acd2bbea 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -85,6 +85,17 @@ export function repl({ const pause = () => scheduler.pause(); const toggle = () => scheduler.toggle(); const setCps = (cps) => scheduler.setCps(cps); + + /** + * Changes the global tempo to the given cycles per minute + * + * @name setcpm + * @alias setCpm + * @param {number} cpm cycles per minute + * @example + * setcpm(140/4) // =140 bpm in 4/4 + * $: s("bd*4,[- sd]*2").bank('tr707') + */ const setCpm = (cpm) => scheduler.setCps(cpm / 60); // TODO - not documented as jsdoc examples as the test framework doesn't simulate enough context for `each` and `all`.. diff --git a/packages/gamepad/docs/gamepad.mdx b/packages/gamepad/docs/gamepad.mdx index 219d8ae0b..e2da594ea 100644 --- a/packages/gamepad/docs/gamepad.mdx +++ b/packages/gamepad/docs/gamepad.mdx @@ -56,14 +56,15 @@ You can use button inputs to control different aspects of your music, such as ga @@ -74,14 +75,13 @@ Analog sticks can be used for continuous control, such as pitch shifting or pann ### Button Sequences @@ -89,6 +89,7 @@ $: note("c4 d3 a3 e3").sound("sawtooth") You can define button sequences to trigger specific actions, like playing a sound when a sequence is detected. -**Tempo ändern mit `cpm`** +**Tempo ändern mit `setcpm`** -*8").cpm(90/4)`} punchcard /> +*8")`} + punchcard +/> @@ -233,8 +238,9 @@ Bolero: @@ -313,18 +319,23 @@ Das haben wir bisher gelernt: Die mit Apostrophen umgebene Mini-Notation benutzt man normalerweise in einer sogenannten Funktion. Die folgenden Funktionen haben wir bereits gesehen: -| Name | Description | Example | -| ----- | -------------------------------------- | ----------------------------------------------------------------------- | -| sound | Spielt den Sound mit dem Namen | | -| bank | Wählt die Soundbank / Drum Machine | | -| cpm | Tempo in **C**ycles **p**ro **M**inute | | -| n | Sample Nummer | | +| Name | Description | Example | +| ------ | -------------------------------------- | ----------------------------------------------------------------------- | +| sound | Spielt den Sound mit dem Namen | | +| bank | Wählt die Soundbank / Drum Machine | | +| setcpm | Tempo in **C**ycles **p**ro **M**inute | | +| n | Sample Nummer | | ## Beispiele **Einfacher Rock Beat** - + **Klassischer House** @@ -339,7 +350,12 @@ Bestimmte Drum Patterns werden oft genreübergreifend wiederverwendet. We Will Rock you - + **Yellow Magic Orchestra - Firecracker** @@ -354,12 +370,13 @@ We Will Rock you @@ -367,12 +384,13 @@ We Will Rock you @@ -380,11 +398,11 @@ We Will Rock you diff --git a/website/src/pages/de/workshop/recap.mdx b/website/src/pages/de/workshop/recap.mdx index 14ef6b252..ec279c084 100644 --- a/website/src/pages/de/workshop/recap.mdx +++ b/website/src/pages/de/workshop/recap.mdx @@ -56,13 +56,13 @@ Diese Seite ist eine Auflistung aller im Workshop vorgestellten Funktionen. ## Pattern-Effekte -| Name | Beschreibung | Beispiel | -| ---- | --------------------------------- | ----------------------------------------------------------------------------------- | -| cpm | Tempo in Cycles pro Minute | | -| fast | schneller | | -| slow | langsamer | | -| rev | rückwärts | | -| jux | einen Stereo-Kanal modifizieren | | -| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | -| ply | jedes Element schneller machen | ")`} /> | -| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | +| Name | Beschreibung | Beispiel | +| ------ | --------------------------------- | ----------------------------------------------------------------------------------- | +| setcpm | Tempo in Cycles pro Minute | | +| fast | schneller | | +| slow | langsamer | | +| rev | rückwärts | | +| jux | einen Stereo-Kanal modifizieren | | +| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | +| ply | jedes Element schneller machen | ")`} /> | +| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | diff --git a/website/src/pages/learn/samples.mdx b/website/src/pages/learn/samples.mdx index cd7944caa..ef97ec0ce 100644 --- a/website/src/pages/learn/samples.mdx +++ b/website/src/pages/learn/samples.mdx @@ -247,15 +247,17 @@ We can also declare different samples for different regions of the keyboard: !2, g4 f4]>") - .s('moog').clip(1) - .gain(.5).cpm(60)`} +.s('moog').clip(1) +.gain(.5)`} /> The sampler will always pick the closest matching sample for the current note! diff --git a/website/src/pages/understand/cycles.mdx b/website/src/pages/understand/cycles.mdx index 4694850c3..1c0a778a6 100644 --- a/website/src/pages/understand/cycles.mdx +++ b/website/src/pages/understand/cycles.mdx @@ -43,21 +43,33 @@ This is why the same CPS can produce different perceived tempos. ## Setting CPM -If you're familiar with BPM, you can use the `cpm` method to set the tempo in cycles per minute: +If you're familiar with BPM, you can use the `setcpm` method to set the global tempo in cycles per minute: - + If you want to add more beats per cycle, you might want to divide the cpm: - + Or using 2 beats per cycle: - + -To set a specific bpm, use `.cpm(bpm/bpc)` +To set a specific bpm, use `setcpm(bpm/bpc)` - bpm: the target beats per minute - bpc: the number of perceived beats per cycle @@ -74,22 +86,31 @@ Many music programs use it as a default. Strudel does not a have concept of bars or measures, there are only cycles. How you use them is up to you. Above, we've had this example: - + This could be interpreted as 4/4 time with a tempo of 110bpm. We could write out multiple bars like this: \`).cpm(110/4)`} +>\`)`} /> Instead of writing out each bar separately, we could express this much shorter: ->,hh*4").cpm(110/2)`} /> +>,hh*4")`} +/> Here we can see that thinking in cycles rather than bars simplifies things a lot! These types of simplifications work because of the repetitive nature of rhythm. @@ -109,10 +130,11 @@ We could also write multiple bars with different time signatures: \`).cpm(110*2)`} +>\`)`} /> Here we switch between 3/4 and 4/4, keeping the same tempo. @@ -121,10 +143,11 @@ If we don't specify the length, we get what's called a metric modulation: \`).cpm(110/2)`} +>\`)`} /> Now the 3 elements get the same time as the 4 elements, which is why the tempo changes. diff --git a/website/src/pages/workshop/first-notes.mdx b/website/src/pages/workshop/first-notes.mdx index f3d74ddce..56312a355 100644 --- a/website/src/pages/workshop/first-notes.mdx +++ b/website/src/pages/workshop/first-notes.mdx @@ -216,8 +216,9 @@ Finding the right notes can be difficult.. Scales are here to help: ") -.scale("C:minor").sound("piano").cpm(60)`} + tune={`setcpm(60) +n("0 2 4 <[6,8] [7,9]>") +.scale("C:minor").sound("piano")`} punchcard /> @@ -242,9 +243,10 @@ Just like anything, we can automate the scale with a pattern: , 2 4 <[6,8] [7,9]>") + tune={`setcpm(60) +n("<0 -3>, 2 4 <[6,8] [7,9]>") .scale("/4") -.sound("piano").cpm(60)`} +.sound("piano")`} punchcard /> @@ -275,9 +277,10 @@ Try changing that number! *2") + tune={`setcpm(60) +n("<[4@2 4] [5@2 5] [6@2 6] [5@2 5]>*2") .scale("/4") -.sound("gm_acoustic_bass").cpm(60)`} +.sound("gm_acoustic_bass")`} punchcard /> @@ -291,7 +294,12 @@ This is also sometimes called triplet swing. You'll often find it in blues and j **Replicate** -]").sound("piano").cpm(60)`} punchcard /> +]").sound("piano")`} + punchcard +/> diff --git a/website/src/pages/workshop/first-sounds.mdx b/website/src/pages/workshop/first-sounds.mdx index 9c33cdc3c..083a55390 100644 --- a/website/src/pages/workshop/first-sounds.mdx +++ b/website/src/pages/workshop/first-sounds.mdx @@ -166,9 +166,14 @@ Try also changing the number at the end to change the tempo! -**changing the tempo with cpm** +**changing the tempo with setcpm** -*8").cpm(90/4)`} punchcard /> +*8")`} + punchcard +/> @@ -287,7 +292,7 @@ The Mini-Notation is usually used inside some function. These are the functions | ----- | ----------------------------------- | --------------------------------------------------------------------------------- | | sound | plays the sound of the given name | | | bank | selects the sound bank | | -| cpm | sets the tempo in cycles per minute | | +| cpm | sets the tempo in cycles per minute | | | n | select sample number | | ## Examples @@ -296,8 +301,8 @@ The Mini-Notation is usually used inside some function. These are the functions @@ -314,14 +319,20 @@ Certain drum patterns are reused across genres. We Will Rock you - + **Yellow Magic Orchestra - Firecracker** @@ -329,12 +340,14 @@ We Will Rock you @@ -342,12 +355,13 @@ We Will Rock you @@ -355,11 +369,11 @@ We Will Rock you diff --git a/website/src/pages/workshop/pattern-effects.mdx b/website/src/pages/workshop/pattern-effects.mdx index c9cb7b462..ad84a9ab3 100644 --- a/website/src/pages/workshop/pattern-effects.mdx +++ b/website/src/pages/workshop/pattern-effects.mdx @@ -68,9 +68,10 @@ Try commenting out one or more by adding `//` before a line >")) + tune={`setcpm(60) +note("c2 [eb3,g3] ".add("<0 <1 -1>>")) .color(">").adsr("[.1 0]:.2:[1 0]") -.sound("gm_acoustic_bass").room(.5).cpm(60)`} +.sound("gm_acoustic_bass").room(.5)`} punchcard /> @@ -84,9 +85,10 @@ We can add as often as we like: >").add("0,7")) + tune={`setcpm(60) +note("c2 [eb3,g3]".add("<0 <1 -1>>").add("0,7")) .color(">").adsr("[.1 0]:.2:[1 0]") -.sound("gm_acoustic_bass").room(.5).cpm(60)`} +.sound("gm_acoustic_bass").room(.5)`} punchcard /> diff --git a/website/src/pages/workshop/recap.mdx b/website/src/pages/workshop/recap.mdx index e2b661f56..08e243cef 100644 --- a/website/src/pages/workshop/recap.mdx +++ b/website/src/pages/workshop/recap.mdx @@ -56,13 +56,13 @@ This page is just a listing of all functions covered in the workshop! ## Pattern Effects -| name | description | example | -| ---- | ----------------------------------- | ----------------------------------------------------------------------------------- | -| cpm | sets the tempo in cycles per minute | | -| fast | speed up | | -| slow | slow down | | -| rev | reverse | | -| jux | split left/right, modify right | | -| add | add numbers / notes | ")).scale("C:minor")`} /> | -| ply | speed up each event n times | ")`} /> | -| off | copy, shift time & modify | x.speed(2))`} /> | +| name | description | example | +| ------ | ----------------------------------- | ----------------------------------------------------------------------------------- | +| setcpm | sets the tempo in cycles per minute | | +| fast | speed up | | +| slow | slow down | | +| rev | reverse | | +| jux | split left/right, modify right | | +| add | add numbers / notes | ")).scale("C:minor")`} /> | +| ply | speed up each event n times | ")`} /> | +| off | copy, shift time & modify | x.speed(2))`} /> | diff --git a/website/src/repl/tunes.mjs b/website/src/repl/tunes.mjs index 774e04e49..afaf937df 100644 --- a/website/src/repl/tunes.mjs +++ b/website/src/repl/tunes.mjs @@ -313,26 +313,6 @@ stack( ) .fast(2/3) .pianoroll()`; -/* -export const bridgeIsOver = `// "Bridge is over" -// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ -// @by Felix Roos, bassline by BDP - The Bridge Is Over - -samples({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'}) -stack( - stack( - note("c3*2 [[c3@1.4 bb2] ab2] gb2*2 <[[gb2@1.4 ab2] bb2] gb2>") - .gain(.8).clip("[.5 1]*2"), - n("<0 1 2 3 4 3 2 1>") - .clip(.5) - .echoWith(8, 1/32, (x,i)=>x.add(n(i)).velocity(Math.pow(.7,i))) - .scale('c4 whole tone') - .echo(3, 1/8, .5) - ).piano(), - s("mad").slow(2) -).cpm(78).slow(4) - .pianoroll() -`; */ export const goodTimes = `// "Good times" // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ From 64ab3c9ba73fddfe3d554b376a72a8ac6dfb23f5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 19 Jun 2025 09:12:05 +0200 Subject: [PATCH 05/12] fix: tests --- test/__snapshots__/examples.test.mjs.snap | 29 +++++++++++++++++++++++ test/runtime.mjs | 2 ++ 2 files changed, 31 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 85948f0c0..f3607cb48 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -8450,6 +8450,35 @@ exports[`runs examples > example "seqPLoop" example index 0 1`] = ` ] `; +exports[`runs examples > example "setcpm" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | s:bd bank:tr707 ]", + "[ 1/4 → 1/2 | s:bd bank:tr707 ]", + "[ 1/4 → 1/2 | s:sd bank:tr707 ]", + "[ 1/2 → 3/4 | s:bd bank:tr707 ]", + "[ 3/4 → 1/1 | s:bd bank:tr707 ]", + "[ 3/4 → 1/1 | s:sd bank:tr707 ]", + "[ 1/1 → 5/4 | s:bd bank:tr707 ]", + "[ 5/4 → 3/2 | s:bd bank:tr707 ]", + "[ 5/4 → 3/2 | s:sd bank:tr707 ]", + "[ 3/2 → 7/4 | s:bd bank:tr707 ]", + "[ 7/4 → 2/1 | s:bd bank:tr707 ]", + "[ 7/4 → 2/1 | s:sd bank:tr707 ]", + "[ 2/1 → 9/4 | s:bd bank:tr707 ]", + "[ 9/4 → 5/2 | s:bd bank:tr707 ]", + "[ 9/4 → 5/2 | s:sd bank:tr707 ]", + "[ 5/2 → 11/4 | s:bd bank:tr707 ]", + "[ 11/4 → 3/1 | s:bd bank:tr707 ]", + "[ 11/4 → 3/1 | s:sd bank:tr707 ]", + "[ 3/1 → 13/4 | s:bd bank:tr707 ]", + "[ 13/4 → 7/2 | s:bd bank:tr707 ]", + "[ 13/4 → 7/2 | s:sd bank:tr707 ]", + "[ 7/2 → 15/4 | s:bd bank:tr707 ]", + "[ 15/4 → 4/1 | s:bd bank:tr707 ]", + "[ 15/4 → 4/1 | s:sd bank:tr707 ]", +] +`; + exports[`runs examples > example "shape" example index 0 1`] = ` [ "[ 0/1 → 1/8 | s:hh shape:0 ]", diff --git a/test/runtime.mjs b/test/runtime.mjs index 6b75fb3be..2a29de3f5 100644 --- a/test/runtime.mjs +++ b/test/runtime.mjs @@ -97,6 +97,7 @@ const toneHelpersMocked = { '_pianoroll', '_spectrum', 'markcss', + 'p', ].forEach((mock) => { strudel.Pattern.prototype[mock] = function () { return this; @@ -163,6 +164,7 @@ evalScope( loadCsound, loadcsound, setcps: id, + setcpm: id, Clock: {}, // whatever }, ); From 66673d211ea60716d83d483b80fdb353c0ba9538 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 19 Jun 2025 09:13:48 +0200 Subject: [PATCH 06/12] fix: cpm -> setcpm --- website/src/pages/workshop/first-sounds.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/website/src/pages/workshop/first-sounds.mdx b/website/src/pages/workshop/first-sounds.mdx index 083a55390..74daf4bab 100644 --- a/website/src/pages/workshop/first-sounds.mdx +++ b/website/src/pages/workshop/first-sounds.mdx @@ -288,12 +288,12 @@ This is what we've learned so far: The Mini-Notation is usually used inside some function. These are the functions we've seen so far: -| Name | Description | Example | -| ----- | ----------------------------------- | --------------------------------------------------------------------------------- | -| sound | plays the sound of the given name | | -| bank | selects the sound bank | | -| cpm | sets the tempo in cycles per minute | | -| n | select sample number | | +| Name | Description | Example | +| ------ | ----------------------------------- | --------------------------------------------------------------------------------- | +| sound | plays the sound of the given name | | +| bank | selects the sound bank | | +| setcpm | sets the tempo in cycles per minute | | +| n | select sample number | | ## Examples From 95193b0bfd4b4e2c2e0c6ef216b4331e2f037cf4 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 19 Jun 2025 08:18:20 +0100 Subject: [PATCH 07/12] a test for #1396 --- packages/core/test/pattern.test.mjs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index 45a1e2a98..b93d80f25 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -52,6 +52,7 @@ import { stackCentre, stepcat, sometimes, + expand } from '../index.mjs'; import { steady } from '../signal.mjs'; @@ -1179,6 +1180,9 @@ describe('Pattern', () => { it('calculates undefined steps as the average', () => { expect(sameFirst(stepcat(pure(1), pure(2), pure(3).setSteps(undefined)), fastcat(1, 2, 3))); }); + it('works with auto-reified values', () => { + expect(sameFirst(stepcat(expand(3, 'bd'), 'rim'), stepcat(expand(3, 'bd'), pure('rim')))) + }); }); describe('shrink', () => { it('can shrink', () => { From 440f1cb081c0947ba3ba8b00b33f4dcc74bafe98 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 19 Jun 2025 08:27:23 +0100 Subject: [PATCH 08/12] reify arguments of stepcat --- packages/core/pattern.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 76b02c21e..59833aea7 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2720,6 +2720,7 @@ export function stepcat(...timepats) { return nothing; } const findsteps = (x) => (Array.isArray(x) ? x : [x._steps, x]); + timepats = timepats.map(reify); timepats = timepats.map(findsteps); if (timepats.find((x) => x[0] === undefined)) { const times = timepats.map((a) => a[0]).filter((x) => x !== undefined); From a1d181d6097057542ca7dd943a2a8105330f52d5 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 19 Jun 2025 08:27:41 +0100 Subject: [PATCH 09/12] format --- packages/core/test/pattern.test.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index b93d80f25..07bdcdda7 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -52,7 +52,7 @@ import { stackCentre, stepcat, sometimes, - expand + expand, } from '../index.mjs'; import { steady } from '../signal.mjs'; @@ -1181,7 +1181,7 @@ describe('Pattern', () => { expect(sameFirst(stepcat(pure(1), pure(2), pure(3).setSteps(undefined)), fastcat(1, 2, 3))); }); it('works with auto-reified values', () => { - expect(sameFirst(stepcat(expand(3, 'bd'), 'rim'), stepcat(expand(3, 'bd'), pure('rim')))) + expect(sameFirst(stepcat(expand(3, 'bd'), 'rim'), stepcat(expand(3, 'bd'), pure('rim')))); }); }); describe('shrink', () => { From a8757fecc8554b10274ca27e378fe9bdb2e216fc Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 19 Jun 2025 08:39:05 +0100 Subject: [PATCH 10/12] avoid double action for PRs, try turning on pnpm cache --- .forgejo/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index 765f5958d..1266d2ddf 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -1,6 +1,6 @@ name: Strudel tests -on: [push, pull_request] +on: [push] jobs: build: @@ -17,7 +17,7 @@ jobs: - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - # cache: 'pnpm' + cache: 'pnpm' - run: pnpm install - run: pnpm run format-check - run: pnpm run lint From f3c4afaa54d0c7fa2428ec883052e6643ec725ea Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 19 Jun 2025 08:42:33 +0100 Subject: [PATCH 11/12] apt install zstd for caching --- .forgejo/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index 1266d2ddf..90cb7e258 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -11,6 +11,8 @@ jobs: steps: - uses: actions/checkout@v4 + - name: apt install ztd + run: apt update && apt install -y zstd - uses: pnpm/action-setup@v4 with: version: 9.12.2 From c01b4c651c54603fd295fc4750e77d9858123b1e Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 19 Jun 2025 09:06:53 +0100 Subject: [PATCH 12/12] don't trash lists passed to timecat --- packages/core/pattern.mjs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 59833aea7..6441b7568 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2719,8 +2719,7 @@ export function stepcat(...timepats) { if (timepats.length === 0) { return nothing; } - const findsteps = (x) => (Array.isArray(x) ? x : [x._steps, x]); - timepats = timepats.map(reify); + const findsteps = (x) => (Array.isArray(x) ? x : [x._steps ?? 1, x]); timepats = timepats.map(findsteps); if (timepats.find((x) => x[0] === undefined)) { const times = timepats.map((a) => a[0]).filter((x) => x !== undefined);