From cb8b65f6f3970ffc60e526f6e31fb3620644a7a8 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 28 Dec 2022 15:39:42 +0100 Subject: [PATCH 1/9] add my-patterns --- my-patterns/README.md | 8 +++++ website/src/pages/my-patterns/[name].png.js | 29 ++++++++++++++++ website/src/pages/my-patterns/index.astro | 29 ++++++++++++++++ website/src/pages/my-patterns/list.json.js | 38 +++++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 my-patterns/README.md create mode 100644 website/src/pages/my-patterns/[name].png.js create mode 100644 website/src/pages/my-patterns/index.astro create mode 100644 website/src/pages/my-patterns/list.json.js diff --git a/my-patterns/README.md b/my-patterns/README.md new file mode 100644 index 00000000..153d198c --- /dev/null +++ b/my-patterns/README.md @@ -0,0 +1,8 @@ +# my-patterns + +This directory can be used to save your own patterns. + +0. fork the strudel repo +1. Save one or more .txt files here. +2. and run `npm run repl` +3. open `http://localhost:3000/my-patterns` ! diff --git a/website/src/pages/my-patterns/[name].png.js b/website/src/pages/my-patterns/[name].png.js new file mode 100644 index 00000000..aa8aabf3 --- /dev/null +++ b/website/src/pages/my-patterns/[name].png.js @@ -0,0 +1,29 @@ +import { createCanvas } from 'canvas'; +import { pianoroll } from '@strudel.cycles/core'; +import { evaluate } from '@strudel.cycles/transpiler'; +import '../../../../test/runtime.mjs'; +import { getMyPatterns } from './list.json'; + +export async function get({ params, request }) { + const patterns = await getMyPatterns(); + const { name } = params; + const tune = patterns[name]; + const { pattern } = await evaluate(tune); + const haps = pattern.queryArc(0, 4); + const canvas = createCanvas(800, 800); + const ctx = canvas.getContext('2d'); + pianoroll({ time: 4, haps, ctx, playhead: 1, fold: 1, background: 'transparent', playheadColor: 'transparent' }); + const buffer = canvas.toBuffer('image/png'); + return { + body: buffer, + encoding: 'binary', + }; +} +export async function getStaticPaths() { + const patterns = await getMyPatterns(); + return Object.keys(patterns).map((name) => ({ + params: { + name, + }, + })); +} diff --git a/website/src/pages/my-patterns/index.astro b/website/src/pages/my-patterns/index.astro new file mode 100644 index 00000000..15ea7da4 --- /dev/null +++ b/website/src/pages/my-patterns/index.astro @@ -0,0 +1,29 @@ +--- +import { getMyPatterns } from './list.json'; + +import { Content } from '../../../../my-patterns/README.md'; + +const myPatterns = await getMyPatterns(); +--- + + + { + Object.keys(myPatterns).length === 0 && ( +
+ +
+ ) + } +
+ { + Object.entries(myPatterns).map(([name, tune]) => ( + +
+ {name} +
+ +
+ )) + } +
+ diff --git a/website/src/pages/my-patterns/list.json.js b/website/src/pages/my-patterns/list.json.js new file mode 100644 index 00000000..e310eacf --- /dev/null +++ b/website/src/pages/my-patterns/list.json.js @@ -0,0 +1,38 @@ +import fs from 'fs'; +import path from 'path'; +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +async function readTextFiles(folder) { + const absolutePath = path.resolve(__dirname, folder); + + // Use `fs.promises.readdir()` to get a list of all the files in the folder + const files = await fs.promises.readdir(absolutePath); + + // Filter the list of files to only include those with a `.txt` extension + const textFiles = files.filter((file) => file.endsWith('.txt')); + // Initialize an empty object to store the file contents + const fileContents = {}; + + // Use `fs.promises.readFile()` to read the contents of each text file + for (const file of textFiles) { + const filePath = `${absolutePath}/${file}`; + const data = await fs.promises.readFile(filePath, 'utf8'); + fileContents[file] = data; + } + // Return the object with the filenames as keys and the file contents as values + return fileContents; +} + +export function getMyPatterns() { + return readTextFiles('../../../../my-patterns'); +} + +export async function get({ params, request }) { + const all = await getMyPatterns(); + return { + body: JSON.stringify(all), + }; +} From 16b4058a8b7d0e960107e6ac0cb58fcb38431aea Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 28 Dec 2022 17:09:18 +0100 Subject: [PATCH 2/9] fix build + simplify logic + add deploy note --- my-patterns/README.md | 7 ++++ website/src/pages/my-patterns/index.astro | 5 ++- website/src/pages/my-patterns/list.json.js | 37 ++++------------------ 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/my-patterns/README.md b/my-patterns/README.md index 153d198c..63d2b3f4 100644 --- a/my-patterns/README.md +++ b/my-patterns/README.md @@ -6,3 +6,10 @@ This directory can be used to save your own patterns. 1. Save one or more .txt files here. 2. and run `npm run repl` 3. open `http://localhost:3000/my-patterns` ! + +## deploy + +1. in your fork, go to settings -> pages and select "Github Actions" as source +2. edit `website/public/CNAME` to contain `.github.io/strudel` +3. go to Actions -> "Build and Deploy" and click "Run workflow" +4. view your patterns at `.github.io/strudel/my-patterns` diff --git a/website/src/pages/my-patterns/index.astro b/website/src/pages/my-patterns/index.astro index 15ea7da4..c73e2572 100644 --- a/website/src/pages/my-patterns/index.astro +++ b/website/src/pages/my-patterns/index.astro @@ -17,7 +17,10 @@ const myPatterns = await getMyPatterns();
{ Object.entries(myPatterns).map(([name, tune]) => ( - +
{name}
diff --git a/website/src/pages/my-patterns/list.json.js b/website/src/pages/my-patterns/list.json.js index e310eacf..6d86e384 100644 --- a/website/src/pages/my-patterns/list.json.js +++ b/website/src/pages/my-patterns/list.json.js @@ -1,36 +1,13 @@ -import fs from 'fs'; -import path from 'path'; -import { dirname } from 'path'; -import { fileURLToPath } from 'url'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -async function readTextFiles(folder) { - const absolutePath = path.resolve(__dirname, folder); - - // Use `fs.promises.readdir()` to get a list of all the files in the folder - const files = await fs.promises.readdir(absolutePath); - - // Filter the list of files to only include those with a `.txt` extension - const textFiles = files.filter((file) => file.endsWith('.txt')); - // Initialize an empty object to store the file contents - const fileContents = {}; - - // Use `fs.promises.readFile()` to read the contents of each text file - for (const file of textFiles) { - const filePath = `${absolutePath}/${file}`; - const data = await fs.promises.readFile(filePath, 'utf8'); - fileContents[file] = data; - } - // Return the object with the filenames as keys and the file contents as values - return fileContents; -} - export function getMyPatterns() { - return readTextFiles('../../../../my-patterns'); + const my = import.meta.glob('../../../../my-patterns/**', { as: 'raw', eager: true }); + return Object.fromEntries( + Object.entries(my) // + .filter(([name]) => name.endsWith('.txt')) // + .map(([name, raw]) => [name.split('/').slice(-1), raw]), // + ); } -export async function get({ params, request }) { +export async function get() { const all = await getMyPatterns(); return { body: JSON.stringify(all), From 6420a72ceb7ba5f57705942fa9b0b106caa893be Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 28 Dec 2022 17:33:14 +0100 Subject: [PATCH 3/9] fix paths + update readme --- my-patterns/README.md | 5 +++-- website/astro.config.mjs | 1 + website/src/pages/my-patterns/index.astro | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/my-patterns/README.md b/my-patterns/README.md index 63d2b3f4..f504d328 100644 --- a/my-patterns/README.md +++ b/my-patterns/README.md @@ -11,5 +11,6 @@ This directory can be used to save your own patterns. 1. in your fork, go to settings -> pages and select "Github Actions" as source 2. edit `website/public/CNAME` to contain `.github.io/strudel` -3. go to Actions -> "Build and Deploy" and click "Run workflow" -4. view your patterns at `.github.io/strudel/my-patterns` +3. edit `website/astro.config.mjs` to use site: `.github.io/strudel` and base `/strudel` +4. go to Actions -> "Build and Deploy" and click "Run workflow" +5. view your patterns at `.github.io/strudel/my-patterns` diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 83038fbc..6714f548 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -31,6 +31,7 @@ export default defineConfig({ tailwind(), ], site: `https://strudel.tidalcycles.org`, + base: '', }); /* diff --git a/website/src/pages/my-patterns/index.astro b/website/src/pages/my-patterns/index.astro index c73e2572..5c7d65ad 100644 --- a/website/src/pages/my-patterns/index.astro +++ b/website/src/pages/my-patterns/index.astro @@ -19,12 +19,12 @@ const myPatterns = await getMyPatterns(); Object.entries(myPatterns).map(([name, tune]) => (
{name}
- +
)) } From dd736130a0fb1755fbd45e3497edc83540b2a068 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 29 Dec 2022 13:03:28 +0100 Subject: [PATCH 4/9] improve pianoroll value mapping --- packages/core/pianoroll.mjs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/core/pianoroll.mjs b/packages/core/pianoroll.mjs index 122bb449..34ce1d4b 100644 --- a/packages/core/pianoroll.mjs +++ b/packages/core/pianoroll.mjs @@ -4,7 +4,7 @@ Copyright (C) 2022 Strudel contributors - see . */ -import { Pattern, toMidi, getDrawContext, freqToMidi } from './index.mjs'; +import { Pattern, toMidi, getDrawContext, freqToMidi, isNote } from './index.mjs'; const scale = (normalized, min, max) => normalized * (max - min) + min; const getValue = (e) => { @@ -12,13 +12,19 @@ const getValue = (e) => { if (typeof e.value !== 'object') { value = { value }; } - let { note, n, freq } = value; + let { note, n, freq, s } = value; if (freq) { - note = freqToMidi(freq); + return freqToMidi(freq); } - value = note ?? n ?? e.value; - if (typeof value === 'string') { - value = toMidi(value); + note = note ?? n; + if (typeof note === 'string') { + return toMidi(note); + } + if (typeof note === 'number') { + return note; + } + if (s) { + return '_' + s; } return value; }; @@ -143,7 +149,7 @@ Pattern.prototype.pianoroll = function ({ maxMidi = max; valueExtent = maxMidi - minMidi + 1; } - foldValues = values.sort((a, b) => a - b); + foldValues = values.sort((a, b) => String(a).localeCompare(String(b))); barThickness = fold ? valueAxis / foldValues.length : valueAxis / valueExtent; }, }, @@ -215,7 +221,8 @@ export function pianoroll({ maxMidi = max; valueExtent = maxMidi - minMidi + 1; } - foldValues = values.sort((a, b) => a - b); + // foldValues = values.sort((a, b) => a - b); + foldValues = values.sort((a, b) => String(a).localeCompare(String(b))); barThickness = fold ? valueAxis / foldValues.length : valueAxis / valueExtent; ctx.fillStyle = background; From af49c4117c79f616ae859f1d17010352e67713e1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 29 Dec 2022 13:25:20 +0100 Subject: [PATCH 5/9] add color to some tunes --- test/__snapshots__/tunes.test.mjs.snap | 2 +- website/src/repl/tunes.mjs | 61 ++++++++++++++++---------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/test/__snapshots__/tunes.test.mjs.snap b/test/__snapshots__/tunes.test.mjs.snap index 3717937e..5b3b5fb5 100644 --- a/test/__snapshots__/tunes.test.mjs.snap +++ b/test/__snapshots__/tunes.test.mjs.snap @@ -339,8 +339,8 @@ exports[`renders tunes > tune: blippyRhodes 1`] = ` "[ 2/3 → 43/60 | note:G3 s:rhodes clip:1 room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]", "[ 5/6 → 53/60 | note:G3 s:rhodes clip:1 room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]", "[ (0/1 → 2/3) ⇝ 4/3 | note:c2 gain:0.3 s:sawtooth cutoff:600 ]", - "[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:c2 gain:0.3 s:sawtooth cutoff:600 ]", "[ (0/1 → 2/3) ⇝ 4/3 | note:36.02 gain:0.3 s:sawtooth cutoff:600 ]", + "[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:c2 gain:0.3 s:sawtooth cutoff:600 ]", "[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:36.02 gain:0.3 s:sawtooth cutoff:600 ]", ] `; diff --git a/website/src/repl/tunes.mjs b/website/src/repl/tunes.mjs index dddfb6e4..89b2acb9 100644 --- a/website/src/repl/tunes.mjs +++ b/website/src/repl/tunes.mjs @@ -24,7 +24,7 @@ stack( "Ab5 [F5@2 C5] C6@2", "A5 [F5@2 C5] [D5@2 F5] F5", "[C5@2 F5] [Bb5 A5 G5] F5@2" - ), + ).color('#FFEBB5'), seq( "[F4,Bb4,D5] [[D4,G4,Bb4]@2 [Bb3,D4,F4]] [[G3,C4,E4]@2 [[Ab3,F4] [A3,Gb4]]] [Bb3,E4,G4]", "[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, Bb3, Db3] [F3, Bb3, Db3]]", @@ -43,7 +43,7 @@ stack( "[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]", "[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]", "[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]" - ), + ).color('#54C571'), seq( "[G3 G3 C3 E3]", "[F2 D2 G2 C2]", @@ -62,8 +62,9 @@ stack( "[Ab2 Ab2 G2 [C2 D2 E2]]", "[F2 A2 Bb2 B2]", "[G2 C2 F2 F2]" - ) -).note().slow(51); + ).color('#0077C9') +).note().slow(51) +//.pianoroll({fold:1}) `; export const giantSteps = `// John Coltrane - Giant Steps @@ -76,22 +77,23 @@ stack( "[D5 Bb4] [G4 Eb4] F#4 [G4 F4]", "Bb4 [B4 A4] D5 [D#5 C#5]", "F#5 [G5 F5] Bb5 [F#5 F#5]", - ), + ).color('#F8E71C'), // chords seq( "[B^7 D7] [G^7 Bb7] Eb^7 [Am7 D7]", "[G^7 Bb7] [Eb^7 F#7] B^7 [Fm7 Bb7]", "Eb^7 [Am7 D7] G^7 [C#m7 F#7]", "B^7 [Fm7 Bb7] Eb^7 [C#m7 F#7]" - ).voicings('lefthand'), + ).voicings('lefthand').color('#7ED321'), // bass seq( "[B2 D2] [G2 Bb2] [Eb2 Bb3] [A2 D2]", "[G2 Bb2] [Eb2 F#2] [B2 F#2] [F2 Bb2]", "[Eb2 Bb2] [A2 D2] [G2 D2] [C#2 F#2]", "[B2 F#2] [F2 Bb2] [Eb2 Bb3] [C#2 F#2]" - ) -).slow(20).note()`; + ).color('#00B8D4') +).slow(20).note() +//.pianoroll({fold:1})`; export const zeldasRescue = `// Koji Kondo - Princess Zelda's Rescue stack( @@ -101,7 +103,8 @@ stack( [B3@2 D4] [A3@2 [G3 A3]] [B3@2 D4] [A3] [B3@2 D4] [A4@2 G4] D5@2 [D5@2 [C5 B4]] [[C5 B4] G4@2] [C5@2 [B4 A4]] [[B4 A4] E4@2] - [D5@2 [C5 B4]] [[C5 B4] G4 C5] [G5] [~ ~ B3]\`, + [D5@2 [C5 B4]] [[C5 B4] G4 C5] [G5] [~ ~ B3]\` + .color('#9C7C38'), // bass \`[[C2 G2] E3@2] [[C2 G2] F#3@2] [[C2 G2] E3@2] [[C2 G2] F#3@2] [[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2] @@ -109,17 +112,19 @@ stack( [[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2] [[F2 C3] E3@2] [[E2 B2] D3@2] [[D2 A2] C3@2] [[C2 G2] B2@2] [[F2 C3] E3@2] [[E2 B2] D3@2] [[Eb2 Bb2] Db3@2] [[D2 A2] C3 [F3,G2]]\` + .color('#4C4646') ).transpose(12).slow(48) .superimpose(x=>x.add(0.06)) // add slightly detuned voice .note() .gain(.1) .s('triangle') .room(1) - `; + //.pianoroll({fold:1})`; export const caverave = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // by Felix Roos -const keys = x => x.s('sawtooth').cutoff(1200).gain(.5).attack(0).decay(.16).sustain(.3).release(.1); +const keys = x => x.s('sawtooth').cutoff(1200).gain(.5) + .attack(0).decay(.16).sustain(.3).release(.1); const drums = stack( s("bd*2").mask("/8").gain(.8), @@ -129,26 +134,31 @@ const drums = stack( const thru = (x) => x.transpose("<0 1>/8").transpose(-1); const synths = stack( - "/2".scale(timeCat([3,'C minor'],[1,'C melodic minor']) + "/2" + .scale(timeCat([3,'C minor'],[1,'C melodic minor']) .slow(8)).struct("[~ x]*2") .layer( x=>x.scaleTranspose(0).early(0), x=>x.scaleTranspose(2).early(1/8), x=>x.scaleTranspose(7).early(1/4), x=>x.scaleTranspose(8).early(3/8) - ).apply(thru).note().apply(keys).mask("<~ x>/16"), + ).apply(thru).note().apply(keys).mask("<~ x>/16") + .color('darkseagreen'), note("/2".apply(thru)) .struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2".fast(2)) - .s('sawtooth').attack(0.001).decay(0.2).sustain(1).cutoff(500), - "/2".struct("~ [x@0.2 ~]".fast(2)).voicings('lefthand') + .s('sawtooth').attack(0.001).decay(0.2).sustain(1).cutoff(500) + .color('brown'), + "/2".struct("~ [x@0.2 ~]".fast(2)) + .voicings('lefthand') .apply(thru).every(2, early(1/8)).note().apply(keys).sustain(0) .delay(.4).delaytime(.12) .mask("/8".early(1/4)) ) stack( - drums.fast(2), + drums.fast(2).color('tomato'), synths -).slow(2)`; +).slow(2) + //.pianoroll({fold:1})`; export const sampleDrums = `samples({ bd: 'bd/BT0A0D0.wav', @@ -157,10 +167,11 @@ export const sampleDrums = `samples({ }, 'https://loophole-letters.vercel.app/samples/tidal/') stack( - "", - "hh*4", - "~ " + "".color('#F5A623'), + "hh*4".color('#673AB7'), + "~ ".color('#4CAF50') ).s() +.pianoroll({fold:1}) `; export const barryHarris = `// adapted from a Barry Harris excercise @@ -170,6 +181,7 @@ export const barryHarris = `// adapted from a Barry Harris excercise .transpose("<0 1 2 1>/8") .slow(2) .note().piano() + .color('#00B8D4') `; export const blippyRhodes = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ @@ -192,7 +204,7 @@ samples({ const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', cat('Db major','Db mixolydian')]) stack( - s(" "), + s(" ").color('#00B8D4'), "]>" .scale(scales) .struct("x*8") @@ -205,13 +217,14 @@ stack( .room(.5) .delay(.3) .delayfeedback(.4) - .delaytime(1/12).gain(.5), + .delaytime(1/12).gain(.5).color('#7ED321'), "" .legato("<1@3 [.3 1]>") .slow(2).superimpose(x=>x.add(.02)) .note().gain(.3) - .s('sawtooth').cutoff(600), -).fast(3/2)`; + .s('sawtooth').cutoff(600).color('#F8E71C'), +).fast(3/2) +//.pianoroll({fold:1})`; export const wavyKalimba = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // by Felix Roos From fb148657857a2050375dbc261f61d49d926c182c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 29 Dec 2022 14:02:50 +0100 Subject: [PATCH 6/9] fix: can now multiply floats in mini notation - fixes #314 --- packages/mini/krill-parser.js | 6 ++-- packages/mini/krill.pegjs | 4 +-- packages/mini/mini.mjs | 56 +++++++++++++++++++---------------- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/mini/krill-parser.js b/packages/mini/krill-parser.js index c4a5d09f..2bc565f7 100644 --- a/packages/mini/krill-parser.js +++ b/packages/mini/krill-parser.js @@ -32,7 +32,7 @@ function peg$padEnd(str, targetLength, padString) { } peg$SyntaxError.prototype.format = function(sources) { - var str = "peg error: " + this.message; + var str = "Error: " + this.message; if (this.location) { var src = null; var k; @@ -271,8 +271,8 @@ function peg$parse(input, options) { var peg$f4 = function(a) { return { weight: a} }; var peg$f5 = function(a) { return { replicate: a } }; var peg$f6 = function(p, s, r) { return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r || 0 } } } }; - var peg$f7 = function(a) { return { operator : { type_: "stretch", arguments_ :{ amount:a } } } }; - var peg$f8 = function(a) { return { operator : { type_: "stretch", arguments_ :{ amount:"1/"+a } } } }; + var peg$f7 = function(a) { return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'slow' } } } }; + var peg$f8 = function(a) { return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'fast' } } } }; var peg$f9 = function(a) { return { operator : { type_: "fixed-step", arguments_ :{ amount:a } } } }; var peg$f10 = function(a) { return { operator : { type_: "degradeBy", arguments_ :{ amount:(a? a : 0.5) } } } }; var peg$f11 = function(s, o) { return new ElementStub(s, o);}; diff --git a/packages/mini/krill.pegjs b/packages/mini/krill.pegjs index 6302614d..87e9df3f 100644 --- a/packages/mini/krill.pegjs +++ b/packages/mini/krill.pegjs @@ -116,10 +116,10 @@ slice_bjorklund = "(" ws p:number ws comma ws s:number ws comma? ws r:number? ws { return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r || 0 } } } } slice_slow = "/"a:number - { return { operator : { type_: "stretch", arguments_ :{ amount:a } } } } + { return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'slow' } } } } slice_fast = "*"a:number - { return { operator : { type_: "stretch", arguments_ :{ amount:"1/"+a } } } } + { return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'fast' } } } } slice_fixed_step = "%"a:number { return { operator : { type_: "fixed-step", arguments_ :{ amount:a } } } } diff --git a/packages/mini/mini.mjs b/packages/mini/mini.mjs index 00ecb24a..745f0f85 100644 --- a/packages/mini/mini.mjs +++ b/packages/mini/mini.mjs @@ -23,8 +23,12 @@ const applyOptions = (parent) => (pat, i) => { if (operator) { switch (operator.type_) { case 'stretch': { - const speed = Fraction(operator.arguments_.amount).inverse(); - return reify(pat).fast(speed); + const legalTypes = ['fast', 'slow']; + const { type, amount } = operator.arguments_; + if (!legalTypes.includes(type)) { + throw new Error(`mini: stretch: type must be one of ${legalTypes.join('|')} but got ${type}`); + } + return reify(pat)[type](amount); } case 'bjorklund': return pat.euclid(operator.arguments_.pulse, operator.arguments_.step, operator.arguments_.rotation); @@ -74,32 +78,32 @@ function resolveReplications(ast) { // could this be made easier?! ast.source_ = ast.source_.map((child) => { const { replicate, ...options } = child.options_ || {}; - if (replicate) { - return { - ...child, - options_: { ...options, weight: replicate }, - source_: { - type_: 'pattern', - arguments_: { - alignment: 'h', - }, - source_: [ - { - type_: 'element', - source_: child.source_, - location_: child.location_, - options_: { - operator: { - type_: 'stretch', - arguments_: { amount: Fraction(replicate).inverse().toString() }, - }, + if (!replicate) { + return child; + } + return { + ...child, + options_: { ...options, weight: replicate }, + source_: { + type_: 'pattern', + arguments_: { + alignment: 'h', + }, + source_: [ + { + type_: 'element', + source_: child.source_, + location_: child.location_, + options_: { + operator: { + type_: 'stretch', + arguments_: { amount: replicate, type: 'fast' }, }, }, - ], - }, - }; - } - return child; + }, + ], + }, + }; }); } From cf21c4085b61aab043c8770189ca454cdb8c4c62 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 29 Dec 2022 21:01:28 +0100 Subject: [PATCH 7/9] simplify embedded mode --- website/src/pages/embed.astro | 14 +++++++++ website/src/repl/Header.jsx | 55 ++++++++++++++++++++++------------- website/src/repl/Repl.jsx | 16 ++++++++-- 3 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 website/src/pages/embed.astro diff --git a/website/src/pages/embed.astro b/website/src/pages/embed.astro new file mode 100644 index 00000000..de8d2c2d --- /dev/null +++ b/website/src/pages/embed.astro @@ -0,0 +1,14 @@ +--- +import HeadCommon from '../components/HeadCommon.astro'; +import { Repl } from '../repl/Repl.jsx'; +--- + + + + + Strudel REPL + + + + + diff --git a/website/src/repl/Header.jsx b/website/src/repl/Header.jsx index c9de3b75..1ea539fc 100644 --- a/website/src/repl/Header.jsx +++ b/website/src/repl/Header.jsx @@ -1,5 +1,5 @@ import AcademicCapIcon from '@heroicons/react/20/solid/AcademicCapIcon'; -import CommandLineIcon from '@heroicons/react/20/solid/CommandLineIcon'; +import ArrowPathIcon from '@heroicons/react/20/solid/ArrowPathIcon'; import LinkIcon from '@heroicons/react/20/solid/LinkIcon'; import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon'; import SparklesIcon from '@heroicons/react/20/solid/SparklesIcon'; @@ -9,10 +9,9 @@ import React, { useContext } from 'react'; // import { ReplContext } from './Repl'; import './Repl.css'; -const isEmbedded = window.location !== window.parent.location; - export function Header({ context }) { const { + embedded, started, pending, isDirty, @@ -25,32 +24,37 @@ export function Header({ context }) { isZen, setIsZen, } = context; + const isEmbedded = embedded || window.location !== window.parent.location; // useContext(ReplContext) return ( diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index ff6be87b..53c744d8 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -22,6 +22,7 @@ import { Footer } from './Footer'; import { Header } from './Header'; import { prebake } from './prebake.mjs'; import * as tunes from './tunes.mjs'; +import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon'; initAudioOnFirstClick(); @@ -101,7 +102,8 @@ const { code: randomTune, name } = getRandomTune(); export const ReplContext = createContext(null); -export function Repl() { +export function Repl({ embedded = false }) { + const isEmbedded = embedded || window.location !== window.parent.location; const [view, setView] = useState(); // codemirror view const [lastShared, setLastShared] = useState(); const [activeFooter, setActiveFooter] = useState(''); @@ -232,6 +234,7 @@ export function Repl() { } }; const context = { + embedded, started, pending, isDirty, @@ -269,7 +272,16 @@ export function Repl() { {error && (
{error.message || 'Unknown Error :-/'}
)} -
+ {isEmbedded && !started && ( + + )} + {!isEmbedded &&
}
); From a57652397680590621dfe3a722cf6d3505a1856d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 29 Dec 2022 21:02:04 +0100 Subject: [PATCH 8/9] simplify meltingsubmarine tune --- test/__snapshots__/tunes.test.mjs.snap | 12 ++++++++---- website/src/repl/tunes.mjs | 8 ++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/__snapshots__/tunes.test.mjs.snap b/test/__snapshots__/tunes.test.mjs.snap index 5b3b5fb5..3d6a085a 100644 --- a/test/__snapshots__/tunes.test.mjs.snap +++ b/test/__snapshots__/tunes.test.mjs.snap @@ -8127,10 +8127,14 @@ exports[`renders tunes > tune: loungeSponge 1`] = ` exports[`renders tunes > tune: meltingsubmarine 1`] = ` [ - "[ (0/1 → 1/1) ⇝ 3/2 | s:bd speed:0.7519542165100574 ]", - "[ (3/4 → 1/1) ⇝ 3/2 | s:sd speed:0.7931522866332671 ]", - "[ 3/8 → 3/4 | s:hh speed:0.7285963821098448 ]", - "[ (3/4 → 1/1) ⇝ 9/8 | s:hh speed:0.77531205091027 ]", + "[ (0/1 → 1/1) ⇝ 3/2 | s:bd:5 speed:0.7519542165100574 ]", + "[ (3/4 → 1/1) ⇝ 3/2 | s:sd:1 speed:0.7931522866332671 ]", + "[ 0/1 → 3/16 | s:hh27 speed:0.7002304945137069 ]", + "[ 3/16 → 3/8 | s:hh27 speed:0.7050675100782229 ]", + "[ 3/8 → 9/16 | s:hh27 speed:0.7187041442227808 ]", + "[ 9/16 → 3/4 | s:hh27 speed:0.7399036937955912 ]", + "[ 3/4 → 15/16 | s:hh27 speed:0.7640047392245236 ]", + "[ (15/16 → 1/1) ⇝ 9/8 | s:hh27 speed:0.7852042887973341 ]", "[ (0/1 → 1/1) ⇝ 3/2 | n:33.129885541275144 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]", "[ (0/1 → 1/1) ⇝ 3/2 | n:33.17988554127514 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]", "[ (0/1 → 1/1) ⇝ 3/2 | n:55.129885541275144 s:sawtooth gain:0.16 cutoff:500 attack:1 ]", diff --git a/website/src/repl/tunes.mjs b/website/src/repl/tunes.mjs index 89b2acb9..4608b616 100644 --- a/website/src/repl/tunes.mjs +++ b/website/src/repl/tunes.mjs @@ -518,13 +518,9 @@ export const festivalOfFingers3 = `// licensed with CC BY-NC-SA 4.0 https://crea export const meltingsubmarine = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // by Felix Roos -samples({ - bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'], - sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'], - hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'], -}, 'github:tidalcycles/Dirt-Samples/master/'); +await samples('github:tidalcycles/Dirt-Samples/master/') stack( - s("bd,[~ ],hh(3,4)") // drums + s("bd:5,[~ ],hh27*8") // drums .speed(perlin.range(.7,.9)) // random sample speed variation //.hush() ,"" // bassline From 26b8f93ceabd34ba0e79f249678f674d6680a1e2 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 29 Dec 2022 21:08:11 +0100 Subject: [PATCH 9/9] roll back hh rhythm --- test/__snapshots__/tunes.test.mjs.snap | 8 ++------ website/src/repl/tunes.mjs | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/test/__snapshots__/tunes.test.mjs.snap b/test/__snapshots__/tunes.test.mjs.snap index 3d6a085a..b5adfeb0 100644 --- a/test/__snapshots__/tunes.test.mjs.snap +++ b/test/__snapshots__/tunes.test.mjs.snap @@ -8129,12 +8129,8 @@ exports[`renders tunes > tune: meltingsubmarine 1`] = ` [ "[ (0/1 → 1/1) ⇝ 3/2 | s:bd:5 speed:0.7519542165100574 ]", "[ (3/4 → 1/1) ⇝ 3/2 | s:sd:1 speed:0.7931522866332671 ]", - "[ 0/1 → 3/16 | s:hh27 speed:0.7002304945137069 ]", - "[ 3/16 → 3/8 | s:hh27 speed:0.7050675100782229 ]", - "[ 3/8 → 9/16 | s:hh27 speed:0.7187041442227808 ]", - "[ 9/16 → 3/4 | s:hh27 speed:0.7399036937955912 ]", - "[ 3/4 → 15/16 | s:hh27 speed:0.7640047392245236 ]", - "[ (15/16 → 1/1) ⇝ 9/8 | s:hh27 speed:0.7852042887973341 ]", + "[ 3/8 → 3/4 | s:hh27 speed:0.7285963821098448 ]", + "[ (3/4 → 1/1) ⇝ 9/8 | s:hh27 speed:0.77531205091027 ]", "[ (0/1 → 1/1) ⇝ 3/2 | n:33.129885541275144 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]", "[ (0/1 → 1/1) ⇝ 3/2 | n:33.17988554127514 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]", "[ (0/1 → 1/1) ⇝ 3/2 | n:55.129885541275144 s:sawtooth gain:0.16 cutoff:500 attack:1 ]", diff --git a/website/src/repl/tunes.mjs b/website/src/repl/tunes.mjs index 4608b616..88fb60d2 100644 --- a/website/src/repl/tunes.mjs +++ b/website/src/repl/tunes.mjs @@ -520,7 +520,7 @@ export const meltingsubmarine = `// licensed with CC BY-NC-SA 4.0 https://creati // by Felix Roos await samples('github:tidalcycles/Dirt-Samples/master/') stack( - s("bd:5,[~ ],hh27*8") // drums + s("bd:5,[~ ],hh27(3,4)") // drums .speed(perlin.range(.7,.9)) // random sample speed variation //.hush() ,"" // bassline