From 42922a0d755edcf5c14f235ff5a7e49a6ee66949 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 9 Sep 2022 21:56:07 +0200 Subject: [PATCH 01/61] fix: support numbers in piano / sampler --- packages/webaudio/webaudio.mjs | 7 +++---- repl/src/prebake.mjs | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index e177d0fd..5b21eec0 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -70,9 +70,8 @@ const getSoundfontKey = (s) => { const getSampleBufferSource = async (s, n, note) => { let transpose = 0; - if (note) { - transpose = toMidi(note) - 36; // C3 is middle C - } + const midi = typeof note === 'string' ? toMidi(note) : note; + transpose = midi - 36; // C3 is middle C const ac = getAudioContext(); // is sample from loaded samples(..) const samples = getLoadedSamples(); @@ -93,7 +92,7 @@ const getSampleBufferSource = async (s, n, note) => { if (!note) { throw new Error('no note(...) set for sound', s); } - const midiDiff = (noteA) => toMidi(noteA) - toMidi(note); + const midiDiff = (noteA) => toMidi(noteA) - midi; // object format will expect keys as notes const closest = Object.keys(bank) .filter((k) => !k.startsWith('_')) diff --git a/repl/src/prebake.mjs b/repl/src/prebake.mjs index 49fc4a64..c30403e3 100644 --- a/repl/src/prebake.mjs +++ b/repl/src/prebake.mjs @@ -55,8 +55,9 @@ Pattern.prototype.piano = function () { return this.clip(1) .s('piano') .fmap((value) => { + const midi = typeof value.note === 'string' ? toMidi(value.note) : value.note; // pan by pitch - const pan = panwidth(Math.min(toMidi(value.note) / maxPan, 1), 0.5); + const pan = panwidth(Math.min(midi / maxPan, 1), 0.5); return { ...value, pan: (value.pan || 1) * pan }; }); }; From 59e16642233a807f13f7eaf90aaa74b69bba35c0 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 9 Sep 2022 22:02:24 +0200 Subject: [PATCH 02/61] pull in midi logic --- packages/webaudio/webaudio.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 5b21eec0..bfb6f9a3 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -70,8 +70,6 @@ const getSoundfontKey = (s) => { const getSampleBufferSource = async (s, n, note) => { let transpose = 0; - const midi = typeof note === 'string' ? toMidi(note) : note; - transpose = midi - 36; // C3 is middle C const ac = getAudioContext(); // is sample from loaded samples(..) const samples = getLoadedSamples(); @@ -92,6 +90,8 @@ const getSampleBufferSource = async (s, n, note) => { if (!note) { throw new Error('no note(...) set for sound', s); } + const midi = typeof note === 'string' ? toMidi(note) : note; + transpose = midi - 36; // C3 is middle C const midiDiff = (noteA) => toMidi(noteA) - midi; // object format will expect keys as notes const closest = Object.keys(bank) From 96f49f117adcfe17d2bc9966c0acfcb79ed81fe1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 10 Sep 2022 23:04:21 +0200 Subject: [PATCH 03/61] add build analyzer --- repl/package-lock.json | 449 +++++ repl/package.json | 1 + repl/stats.html | 4034 ++++++++++++++++++++++++++++++++++++++++ repl/vite.config.js | 5 + 4 files changed, 4489 insertions(+) create mode 100644 repl/stats.html diff --git a/repl/package-lock.json b/repl/package-lock.json index 10375f90..ba6a8611 100644 --- a/repl/package-lock.json +++ b/repl/package-lock.json @@ -18,6 +18,7 @@ "@vitejs/plugin-react": "^1.3.0", "autoprefixer": "^10.4.7", "postcss": "^8.4.13", + "rollup-plugin-visualizer": "^5.8.1", "tailwindcss": "^3.0.24", "vite": "^2.9.9" } @@ -634,6 +635,15 @@ "node": ">=0.4.0" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -838,6 +848,17 @@ "node": ">= 6" } }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -908,6 +929,15 @@ } } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", @@ -949,6 +979,12 @@ "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", "dev": true }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/es5-ext": { "version": "0.10.61", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", @@ -1465,6 +1501,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1531,6 +1576,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1540,6 +1600,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1566,6 +1635,18 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -1753,6 +1834,23 @@ "node": ">= 6" } }, + "node_modules/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -1977,6 +2075,15 @@ "node": ">=8.10.0" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -2019,6 +2126,44 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup-plugin-visualizer": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.8.1.tgz", + "integrity": "sha512-NBT/xN/LWCwDM2/j5vYmjzpEAKHyclo/8Cv8AfTCwgADAG+tLJDy1vzxMw6NO0dSDjmTeRELD9UU3FwknLv0GQ==", + "dev": true, + "dependencies": { + "nanoid": "^3.3.4", + "open": "^8.4.0", + "source-map": "^0.7.3", + "yargs": "^17.5.1" + }, + "bin": { + "rollup-plugin-visualizer": "dist/bin/cli.js" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "rollup": "^2.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/rollup-plugin-visualizer/node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2066,6 +2211,15 @@ "semver": "bin/semver.js" } }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -2075,6 +2229,32 @@ "node": ">=0.10.0" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -2281,6 +2461,56 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -2290,6 +2520,15 @@ "node": ">=0.4" } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yaeti": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", @@ -2306,6 +2545,33 @@ "engines": { "node": ">= 6" } + }, + "node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } } }, "dependencies": { @@ -2776,6 +3042,12 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -2901,6 +3173,17 @@ } } }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -2957,6 +3240,12 @@ "ms": "2.1.2" } }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, "defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", @@ -2992,6 +3281,12 @@ "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", "dev": true }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "es5-ext": { "version": "0.10.61", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", @@ -3289,6 +3584,12 @@ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3337,12 +3638,24 @@ "has": "^1.0.3" } }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3363,6 +3676,15 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3492,6 +3814,17 @@ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "dev": true }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -3619,6 +3952,12 @@ "picomatch": "^2.2.1" } }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, "resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -3645,6 +3984,26 @@ "fsevents": "~2.3.2" } }, + "rollup-plugin-visualizer": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.8.1.tgz", + "integrity": "sha512-NBT/xN/LWCwDM2/j5vYmjzpEAKHyclo/8Cv8AfTCwgADAG+tLJDy1vzxMw6NO0dSDjmTeRELD9UU3FwknLv0GQ==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "open": "^8.4.0", + "source-map": "^0.7.3", + "yargs": "^17.5.1" + }, + "dependencies": { + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + } + } + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3675,12 +4034,38 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + }, "source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -3835,12 +4220,55 @@ "webidl-conversions": "^3.0.0" } }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, "yaeti": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", @@ -3851,6 +4279,27 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true } } } diff --git a/repl/package.json b/repl/package.json index a15f8339..1ee3983e 100644 --- a/repl/package.json +++ b/repl/package.json @@ -25,6 +25,7 @@ "@vitejs/plugin-react": "^1.3.0", "autoprefixer": "^10.4.7", "postcss": "^8.4.13", + "rollup-plugin-visualizer": "^5.8.1", "tailwindcss": "^3.0.24", "vite": "^2.9.9" } diff --git a/repl/stats.html b/repl/stats.html new file mode 100644 index 00000000..920505b6 --- /dev/null +++ b/repl/stats.html @@ -0,0 +1,4034 @@ + + + + + + + + RollUp Visualizer + + + +
+ + + + + diff --git a/repl/vite.config.js b/repl/vite.config.js index 8d83055e..1d3f3e86 100644 --- a/repl/vite.config.js +++ b/repl/vite.config.js @@ -1,10 +1,15 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; +import { visualizer } from 'rollup-plugin-visualizer'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], build: { outDir: '../out', + sourcemap: true, + rollupOptions: { + plugins: [visualizer({ template: 'treemap' })], + }, }, }); From a5f05b471588940f0ce5c205759960a080ab7db9 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 10 Sep 2022 23:19:23 +0200 Subject: [PATCH 04/61] hotfix: regression of #196 - samples loaded as arrays would not be repitched --- packages/webaudio/webaudio.mjs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index bfb6f9a3..2a6d39d0 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -70,6 +70,13 @@ const getSoundfontKey = (s) => { const getSampleBufferSource = async (s, n, note) => { let transpose = 0; + let midi; + + if (note !== undefined) { + midi = typeof note === 'string' ? toMidi(note) : note; + transpose = midi - 36; // C3 is middle C + } + const ac = getAudioContext(); // is sample from loaded samples(..) const samples = getLoadedSamples(); @@ -90,8 +97,6 @@ const getSampleBufferSource = async (s, n, note) => { if (!note) { throw new Error('no note(...) set for sound', s); } - const midi = typeof note === 'string' ? toMidi(note) : note; - transpose = midi - 36; // C3 is middle C const midiDiff = (noteA) => toMidi(noteA) - midi; // object format will expect keys as notes const closest = Object.keys(bank) From 5b721f645395ff4c1b10d3580dfdc5eafff5eedc Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 10 Sep 2022 23:32:33 +0200 Subject: [PATCH 05/61] package-lock --- package-lock.json | 94 +++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index b702d82b..04b7cca7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@strudel.cycles/monorepo", - "version": "0.0.1", + "version": "0.0.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@strudel.cycles/monorepo", - "version": "0.0.1", + "version": "0.0.4", "license": "AGPL-3.0-or-later", "workspaces": [ "packages/*" @@ -12090,7 +12090,7 @@ }, "packages/core": { "name": "@strudel.cycles/core", - "version": "0.1.2", + "version": "0.2.0", "license": "AGPL-3.0-or-later", "dependencies": { "bjork": "^0.0.1", @@ -12104,10 +12104,10 @@ }, "packages/eval": { "name": "@strudel.cycles/eval", - "version": "0.1.3", + "version": "0.2.0", "license": "AGPL-3.0-or-later", "dependencies": { - "@strudel.cycles/core": "^0.1.2", + "@strudel.cycles/core": "^0.2.0", "estraverse": "^5.3.0", "shift-ast": "^6.1.0", "shift-codegen": "^7.0.3", @@ -12131,22 +12131,22 @@ }, "packages/midi": { "name": "@strudel.cycles/midi", - "version": "0.1.3", + "version": "0.2.0", "license": "AGPL-3.0-or-later", "dependencies": { - "@strudel.cycles/tone": "^0.1.3", + "@strudel.cycles/tone": "^0.2.0", "tone": "^14.7.77", "webmidi": "^2.5.2" } }, "packages/mini": { "name": "@strudel.cycles/mini", - "version": "0.1.3", + "version": "0.2.0", "license": "AGPL-3.0-or-later", "dependencies": { - "@strudel.cycles/core": "^0.1.2", - "@strudel.cycles/eval": "^0.1.3", - "@strudel.cycles/tone": "^0.1.3" + "@strudel.cycles/core": "^0.2.0", + "@strudel.cycles/eval": "^0.2.0", + "@strudel.cycles/tone": "^0.2.0" }, "devDependencies": { "peggy": "^2.0.1" @@ -12162,13 +12162,13 @@ }, "packages/react": { "name": "@strudel.cycles/react", - "version": "0.1.4", + "version": "0.2.0", "license": "AGPL-3.0-or-later", "dependencies": { "@codemirror/lang-javascript": "^6.0.2", - "@strudel.cycles/core": "^0.1.2", - "@strudel.cycles/eval": "^0.1.3", - "@strudel.cycles/tone": "^0.1.3", + "@strudel.cycles/core": "^0.2.0", + "@strudel.cycles/eval": "^0.2.0", + "@strudel.cycles/tone": "^0.2.0", "@uiw/codemirror-themes": "^4.11.4", "@uiw/react-codemirror": "^4.11.4", "react-hook-inview": "^4.5.0" @@ -12260,11 +12260,11 @@ }, "packages/soundfonts": { "name": "@strudel.cycles/soundfonts", - "version": "0.1.1", + "version": "0.2.1", "license": "AGPL-3.0-or-later", "dependencies": { - "@strudel.cycles/core": "*", - "@strudel.cycles/webaudio": "^0.1.4", + "@strudel.cycles/core": "^0.2.0", + "@strudel.cycles/webaudio": "^0.2.0", "sfumato": "^0.1.2", "soundfont2": "^0.4.0" }, @@ -12292,10 +12292,10 @@ }, "packages/tonal": { "name": "@strudel.cycles/tonal", - "version": "0.1.3", + "version": "0.2.0", "license": "AGPL-3.0-or-later", "dependencies": { - "@strudel.cycles/core": "^0.1.2", + "@strudel.cycles/core": "^0.2.0", "@tonaljs/tonal": "^4.6.5", "webmidi": "^3.0.15" } @@ -12317,10 +12317,10 @@ }, "packages/tone": { "name": "@strudel.cycles/tone", - "version": "0.1.3", + "version": "0.2.0", "license": "AGPL-3.0-or-later", "dependencies": { - "@strudel.cycles/core": "^0.1.2", + "@strudel.cycles/core": "^0.2.0", "@tonejs/piano": "^0.2.1", "chord-voicings": "^0.0.1", "tone": "^14.7.77" @@ -12328,27 +12328,27 @@ }, "packages/webaudio": { "name": "@strudel.cycles/webaudio", - "version": "0.1.4", + "version": "0.2.0", "license": "AGPL-3.0-or-later", "dependencies": { - "@strudel.cycles/core": "^0.1.2" + "@strudel.cycles/core": "^0.2.0" } }, "packages/webdirt": { "name": "@strudel.cycles/webdirt", - "version": "0.1.2", + "version": "0.2.0", "license": "AGPL-3.0-or-later", "dependencies": { - "@strudel.cycles/core": "^0.1.2", + "@strudel.cycles/core": "^0.2.0", "WebDirt": "github:dktr0/WebDirt" } }, "packages/xen": { "name": "@strudel.cycles/xen", - "version": "0.1.3", + "version": "0.2.0", "license": "AGPL-3.0-or-later", "dependencies": { - "@strudel.cycles/core": "^0.1.2" + "@strudel.cycles/core": "^0.2.0" } } }, @@ -14052,7 +14052,7 @@ "@strudel.cycles/eval": { "version": "file:packages/eval", "requires": { - "@strudel.cycles/core": "^0.1.2", + "@strudel.cycles/core": "^0.2.0", "estraverse": "^5.3.0", "shift-ast": "^6.1.0", "shift-codegen": "^7.0.3", @@ -14064,7 +14064,7 @@ "@strudel.cycles/midi": { "version": "file:packages/midi", "requires": { - "@strudel.cycles/tone": "^0.1.3", + "@strudel.cycles/tone": "^0.2.0", "tone": "^14.7.77", "webmidi": "^2.5.2" } @@ -14072,9 +14072,9 @@ "@strudel.cycles/mini": { "version": "file:packages/mini", "requires": { - "@strudel.cycles/core": "^0.1.2", - "@strudel.cycles/eval": "^0.1.3", - "@strudel.cycles/tone": "^0.1.3", + "@strudel.cycles/core": "^0.2.0", + "@strudel.cycles/eval": "^0.2.0", + "@strudel.cycles/tone": "^0.2.0", "peggy": "^2.0.1" } }, @@ -14088,9 +14088,9 @@ "version": "file:packages/react", "requires": { "@codemirror/lang-javascript": "^6.0.2", - "@strudel.cycles/core": "^0.1.2", - "@strudel.cycles/eval": "^0.1.3", - "@strudel.cycles/tone": "^0.1.3", + "@strudel.cycles/core": "^0.2.0", + "@strudel.cycles/eval": "^0.2.0", + "@strudel.cycles/tone": "^0.2.0", "@types/react": "^17.0.2", "@types/react-dom": "^17.0.2", "@uiw/codemirror-themes": "^4.11.4", @@ -14163,11 +14163,11 @@ "@strudel.cycles/soundfonts": { "version": "file:packages/soundfonts", "requires": { - "@strudel.cycles/core": "*", - "@strudel.cycles/webaudio": "^0.1.4", + "@strudel.cycles/core": "^0.2.0", + "@strudel.cycles/webaudio": "^0.2.0", "node-fetch": "^3.2.6", "sfumato": "^0.1.2", - "soundfont2": "*" + "soundfont2": "^0.4.0" }, "dependencies": { "node-fetch": { @@ -14186,7 +14186,7 @@ "@strudel.cycles/tonal": { "version": "file:packages/tonal", "requires": { - "@strudel.cycles/core": "^0.1.2", + "@strudel.cycles/core": "^0.2.0", "@tonaljs/tonal": "^4.6.5", "webmidi": "^3.0.15" }, @@ -14206,7 +14206,7 @@ "@strudel.cycles/tone": { "version": "file:packages/tone", "requires": { - "@strudel.cycles/core": "^0.1.2", + "@strudel.cycles/core": "^0.2.0", "@tonejs/piano": "^0.2.1", "chord-voicings": "^0.0.1", "tone": "^14.7.77" @@ -14215,20 +14215,20 @@ "@strudel.cycles/webaudio": { "version": "file:packages/webaudio", "requires": { - "@strudel.cycles/core": "^0.1.2" + "@strudel.cycles/core": "^0.2.0" } }, "@strudel.cycles/webdirt": { "version": "file:packages/webdirt", "requires": { - "@strudel.cycles/core": "^0.1.2", + "@strudel.cycles/core": "^0.2.0", "WebDirt": "github:dktr0/WebDirt" } }, "@strudel.cycles/xen": { "version": "file:packages/xen", "requires": { - "@strudel.cycles/core": "^0.1.2" + "@strudel.cycles/core": "^0.2.0" } }, "@tonaljs/abc-notation": { @@ -19717,9 +19717,9 @@ "version": "file:packages/react", "requires": { "@codemirror/lang-javascript": "^6.0.2", - "@strudel.cycles/core": "^0.1.2", - "@strudel.cycles/eval": "^0.1.3", - "@strudel.cycles/tone": "^0.1.3", + "@strudel.cycles/core": "^0.2.0", + "@strudel.cycles/eval": "^0.2.0", + "@strudel.cycles/tone": "^0.2.0", "@types/react": "^17.0.2", "@types/react-dom": "^17.0.2", "@uiw/codemirror-themes": "^4.11.4", From d1cedaa3e8ec6f64928d0ae7df1b0f2a9e81f1cc Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 13 Sep 2022 22:40:52 +0200 Subject: [PATCH 06/61] add dependencies graphic npx depcruise --include-only "^packages" -X "node_modules" --output-type dot packages | dot -T svg > dependencies.svg --- dependencies.svg | 1806 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1806 insertions(+) create mode 100644 dependencies.svg diff --git a/dependencies.svg b/dependencies.svg new file mode 100644 index 00000000..2d2fc61d --- /dev/null +++ b/dependencies.svg @@ -0,0 +1,1806 @@ + + + + + + +dependency-cruiser output + + +cluster_packages + +packages + + +cluster_packages/core + +core + + +cluster_packages/core/test + +test + + +cluster_packages/embed + +embed + + +cluster_packages/eval + +eval + + +cluster_packages/eval/shift-traverser + +shift-traverser + + +cluster_packages/eval/test + +test + + +cluster_packages/midi + +midi + + +cluster_packages/mini + +mini + + +cluster_packages/mini/test + +test + + +cluster_packages/osc + +osc + + +cluster_packages/react + +react + + +cluster_packages/react/dist + +dist + + +cluster_packages/react/src + +src + + +cluster_packages/react/src/components + +components + + +cluster_packages/react/src/hooks + +hooks + + +cluster_packages/react/src/themes + +themes + + +cluster_packages/serial + +serial + + +cluster_packages/soundfonts + +soundfonts + + +cluster_packages/tonal + +tonal + + +cluster_packages/tonal/test + +test + + +cluster_packages/tone + +tone + + +cluster_packages/tone/test + +test + + +cluster_packages/webaudio + +webaudio + + +cluster_packages/webdirt + +webdirt + + +cluster_packages/xen + +xen + + +cluster_packages/xen/test + +test + + + +packages/core/controls.mjs + + +controls.mjs + + + + + +packages/core/pattern.mjs + + +pattern.mjs + + + + + +packages/core/controls.mjs->packages/core/pattern.mjs + + + + + +packages/core/drawLine.mjs + + +drawLine.mjs + + + + + +packages/core/pattern.mjs->packages/core/drawLine.mjs + + + + + +packages/core/fraction.mjs + + +fraction.mjs + + + + + +packages/core/pattern.mjs->packages/core/fraction.mjs + + + + + +packages/core/util.mjs + + +util.mjs + + + + + +packages/core/pattern.mjs->packages/core/util.mjs + + + + + +packages/core/timespan.mjs + + +timespan.mjs + + + + + +packages/core/pattern.mjs->packages/core/timespan.mjs + + + + + +packages/core/hap.mjs + + +hap.mjs + + + + + +packages/core/pattern.mjs->packages/core/hap.mjs + + + + + +packages/core/state.mjs + + +state.mjs + + + + + +packages/core/pattern.mjs->packages/core/state.mjs + + + + + +packages/core/value.mjs + + +value.mjs + + + + + +packages/core/pattern.mjs->packages/core/value.mjs + + + + + +packages/core/drawLine.mjs->packages/core/fraction.mjs + + + + + +packages/core/fraction.mjs->packages/core/timespan.mjs + + + + + + + +packages/core/euclid.mjs + + +euclid.mjs + + + + + +packages/core/euclid.mjs->packages/core/pattern.mjs + + + + + +packages/core/euclid.mjs->packages/core/fraction.mjs + + + + + +packages/core/euclid.mjs->packages/core/util.mjs + + + + + +packages/core/timespan.mjs->packages/core/fraction.mjs + + + + + + + +packages/core/gist.js + + +gist.js + + + + + +packages/core/index.mjs + + +index.mjs + + + + + +packages/core/index.mjs->packages/core/controls.mjs + + + + + +packages/core/index.mjs->packages/core/pattern.mjs + + + + + +packages/core/index.mjs->packages/core/fraction.mjs + + + + + +packages/core/index.mjs->packages/core/euclid.mjs + + + + + +packages/core/index.mjs->packages/core/util.mjs + + + + + +packages/core/index.mjs->packages/core/timespan.mjs + + + + + +packages/core/index.mjs->packages/core/gist.js + + + + + +packages/core/index.mjs->packages/core/hap.mjs + + + + + +packages/core/signal.mjs + + +signal.mjs + + + + + +packages/core/index.mjs->packages/core/signal.mjs + + + + + +packages/core/speak.mjs + + +speak.mjs + + + + + +packages/core/index.mjs->packages/core/speak.mjs + + + + + + + +packages/core/index.mjs->packages/core/state.mjs + + + + + +packages/core/signal.mjs->packages/core/pattern.mjs + + + + + +packages/core/signal.mjs->packages/core/fraction.mjs + + + + + +packages/core/signal.mjs->packages/core/util.mjs + + + + + +packages/core/signal.mjs->packages/core/hap.mjs + + + + + +packages/core/speak.mjs->packages/core/index.mjs + + + + + + + +packages/core/value.mjs->packages/core/util.mjs + + + + + +packages/core/test/drawLine.test.mjs + + +drawLine.test.mjs + + + + + +packages/core/test/drawLine.test.mjs->packages/core/pattern.mjs + + + + + +packages/core/test/drawLine.test.mjs->packages/core/drawLine.mjs + + + + + +packages/core/test/fraction.test.mjs + + +fraction.test.mjs + + + + + +packages/core/test/fraction.test.mjs->packages/core/fraction.mjs + + + + + +packages/core/test/pattern.test.mjs + + +pattern.test.mjs + + + + + +packages/core/test/pattern.test.mjs->packages/core/index.mjs + + + + + +packages/core/test/pattern.test.mjs->packages/core/signal.mjs + + + + + +packages/core/test/util.test.mjs + + +util.test.mjs + + + + + +packages/core/test/util.test.mjs->packages/core/pattern.mjs + + + + + +packages/core/test/util.test.mjs->packages/core/util.mjs + + + + + +packages/core/test/value.test.mjs + + +value.test.mjs + + + + + +packages/core/test/value.test.mjs->packages/core/value.mjs + + + + + +packages/embed/embed.js + + +embed.js + + + + + +packages/eval/evaluate.mjs + + +evaluate.mjs + + + + + +packages/eval/evaluate.mjs->packages/core/index.mjs + + + + + +packages/eval/shapeshifter.mjs + + +shapeshifter.mjs + + + + + +packages/eval/evaluate.mjs->packages/eval/shapeshifter.mjs + + + + + +packages/eval/shapeshifter.mjs->packages/core/index.mjs + + + + + +packages/eval/shift-traverser/index.js + + +index.js + + + + + +packages/eval/shapeshifter.mjs->packages/eval/shift-traverser/index.js + + + + + +packages/eval/index.mjs + + +index.mjs + + + + + +packages/eval/index.mjs->packages/eval/evaluate.mjs + + + + + +packages/eval/test/evaluate.test.mjs + + +evaluate.test.mjs + + + + + +packages/eval/test/evaluate.test.mjs->packages/core/index.mjs + + + + + +packages/eval/test/evaluate.test.mjs->packages/eval/evaluate.mjs + + + + + +packages/mini/index.mjs + + +index.mjs + + + + + +packages/eval/test/evaluate.test.mjs->packages/mini/index.mjs + + + + + +packages/mini/krill-parser.js + + +krill-parser.js + + + + + +packages/mini/index.mjs->packages/mini/krill-parser.js + + + + + +packages/mini/mini.mjs + + +mini.mjs + + + + + +packages/mini/index.mjs->packages/mini/mini.mjs + + + + + +packages/eval/test/shapeshifter.test.mjs + + +shapeshifter.test.mjs + + + + + +packages/eval/test/shapeshifter.test.mjs->packages/eval/shapeshifter.mjs + + + + + +packages/midi/index.mjs + + +index.mjs + + + + + +packages/midi/midi.mjs + + +midi.mjs + + + + + +packages/midi/index.mjs->packages/midi/midi.mjs + + + + + +packages/midi/midi.mjs->packages/core/index.mjs + + + + + +packages/tone/index.mjs + + +index.mjs + + + + + +packages/midi/midi.mjs->packages/tone/index.mjs + + + + + +packages/tone/draw.mjs + + +draw.mjs + + + + + +packages/tone/index.mjs->packages/tone/draw.mjs + + + + + +packages/tone/tone.mjs + + +tone.mjs + + + + + +packages/tone/index.mjs->packages/tone/tone.mjs + + + + + +packages/tone/pianoroll.mjs + + +pianoroll.mjs + + + + + +packages/tone/index.mjs->packages/tone/pianoroll.mjs + + + + + +packages/tone/ui.mjs + + +ui.mjs + + + + + +packages/tone/index.mjs->packages/tone/ui.mjs + + + + + +packages/mini/mini.mjs->packages/core/index.mjs + + + + + +packages/mini/mini.mjs->packages/eval/shapeshifter.mjs + + + + + +packages/mini/mini.mjs->packages/mini/krill-parser.js + + + + + +packages/mini/test/mini.test.mjs + + +mini.test.mjs + + + + + +packages/mini/test/mini.test.mjs->packages/core/euclid.mjs + + + + + +packages/mini/test/mini.test.mjs->packages/mini/mini.mjs + + + + + +packages/osc/osc.mjs + + +osc.mjs + + + + + +packages/osc/osc.mjs->packages/core/index.mjs + + + + + +packages/osc/server.js + + +server.js + + + + + +packages/osc/tidal-sniffer.js + + +tidal-sniffer.js + + + + + +packages/react/dist/index.cjs.js + + +index.cjs.js + + + + + +packages/react/dist/index.cjs.js->packages/core/util.mjs + + + + + +packages/react/dist/index.cjs.js->packages/core/index.mjs + + + + + +packages/react/dist/index.cjs.js->packages/eval/index.mjs + + + + + +packages/react/dist/index.cjs.js->packages/midi/index.mjs + + + + + +packages/react/dist/index.cjs.js->packages/tone/index.mjs + + + + + +packages/react/dist/index.es.js + + +index.es.js + + + + + +packages/react/dist/index.es.js->packages/core/util.mjs + + + + + +packages/react/dist/index.es.js->packages/core/index.mjs + + + + + +packages/react/dist/index.es.js->packages/eval/index.mjs + + + + + +packages/react/dist/index.es.js->packages/midi/index.mjs + + + + + +packages/react/dist/index.es.js->packages/tone/index.mjs + + + + + +packages/react/dist/index.es.js->packages/react/dist/index.cjs.js + + + + + +packages/react/package.json + + +package.json + + + + + +packages/react/postcss.config.js + + +postcss.config.js + + + + + +packages/react/src/App.jsx + + +App.jsx + + + + + +packages/react/src/App.jsx->packages/core/index.mjs + + + + + +packages/react/src/App.jsx->packages/eval/index.mjs + + + + + +packages/react/src/App.jsx->packages/mini/index.mjs + + + + + +packages/react/src/App.jsx->packages/midi/index.mjs + + + + + +packages/react/src/App.jsx->packages/tone/index.mjs + + + + + +packages/react/src/App.jsx->packages/react/dist/index.cjs.js + + + + + +packages/react/src/components/MiniRepl.jsx + + +MiniRepl.jsx + + + + + +packages/react/src/App.jsx->packages/react/src/components/MiniRepl.jsx + + + + + +packages/tonal/index.mjs + + +index.mjs + + + + + +packages/react/src/App.jsx->packages/tonal/index.mjs + + + + + +packages/webaudio/index.mjs + + +index.mjs + + + + + +packages/react/src/App.jsx->packages/webaudio/index.mjs + + + + + +packages/xen/index.mjs + + +index.mjs + + + + + +packages/react/src/App.jsx->packages/xen/index.mjs + + + + + +packages/react/src/components/MiniRepl.jsx->packages/react/dist/index.cjs.js + + + + + +packages/react/src/components/CodeMirror6.jsx + + +CodeMirror6.jsx + + + + + +packages/react/src/components/MiniRepl.jsx->packages/react/src/components/CodeMirror6.jsx + + + + + +packages/react/src/cx.js + + +cx.js + + + + + +packages/react/src/components/MiniRepl.jsx->packages/react/src/cx.js + + + + + +packages/react/src/hooks/useHighlighting.mjs + + +useHighlighting.mjs + + + + + +packages/react/src/components/MiniRepl.jsx->packages/react/src/hooks/useHighlighting.mjs + + + + + +packages/react/src/hooks/useRepl.mjs + + +useRepl.mjs + + + + + +packages/react/src/components/MiniRepl.jsx->packages/react/src/hooks/useRepl.mjs + + + + + +packages/react/src/components/MiniRepl.module.css + + +MiniRepl.module.css + + + + + +packages/react/src/components/MiniRepl.jsx->packages/react/src/components/MiniRepl.module.css + + + + + +packages/react/src/components/style.css + + +style.css + + + + + +packages/react/src/components/MiniRepl.jsx->packages/react/src/components/style.css + + + + + +packages/tonal/tonal.mjs + + +tonal.mjs + + + + + +packages/tonal/index.mjs->packages/tonal/tonal.mjs + + + + + +packages/tonal/voicings.mjs + + +voicings.mjs + + + + + +packages/tonal/index.mjs->packages/tonal/voicings.mjs + + + + + +packages/webaudio/clockworker.mjs + + +clockworker.mjs + + + + + +packages/webaudio/index.mjs->packages/webaudio/clockworker.mjs + + + + + +packages/webaudio/sampler.mjs + + +sampler.mjs + + + + + +packages/webaudio/index.mjs->packages/webaudio/sampler.mjs + + + + + +packages/webaudio/scheduler.mjs + + +scheduler.mjs + + + + + +packages/webaudio/index.mjs->packages/webaudio/scheduler.mjs + + + + + +packages/webaudio/webaudio.mjs + + +webaudio.mjs + + + + + +packages/webaudio/index.mjs->packages/webaudio/webaudio.mjs + + + + + +packages/xen/tune.mjs + + +tune.mjs + + + + + +packages/xen/index.mjs->packages/xen/tune.mjs + + + + + +packages/xen/xen.mjs + + +xen.mjs + + + + + +packages/xen/index.mjs->packages/xen/xen.mjs + + + + + +packages/react/src/components/CodeMirror6.jsx->packages/react/dist/index.cjs.js + + + + + +packages/react/src/themes/material-palenight.js + + +material-palenight.js + + + + + +packages/react/src/components/CodeMirror6.jsx->packages/react/src/themes/material-palenight.js + + + + + +packages/react/src/hooks/useHighlighting.mjs->packages/tone/index.mjs + + + + + +packages/react/src/hooks/useHighlighting.mjs->packages/react/dist/index.cjs.js + + + + + +packages/react/src/hooks/useHighlighting.mjs->packages/react/src/components/CodeMirror6.jsx + + + + + +packages/react/src/hooks/useRepl.mjs->packages/core/util.mjs + + + + + +packages/react/src/hooks/useRepl.mjs->packages/eval/index.mjs + + + + + +packages/react/src/hooks/useRepl.mjs->packages/react/dist/index.cjs.js + + + + + +packages/react/src/hooks/useCycle.mjs + + +useCycle.mjs + + + + + +packages/react/src/hooks/useRepl.mjs->packages/react/src/hooks/useCycle.mjs + + + + + +packages/react/src/hooks/usePostMessage.mjs + + +usePostMessage.mjs + + + + + +packages/react/src/hooks/useRepl.mjs->packages/react/src/hooks/usePostMessage.mjs + + + + + +packages/react/src/hooks/useCycle.mjs->packages/core/index.mjs + + + + + +packages/react/src/hooks/useCycle.mjs->packages/tone/index.mjs + + + + + +packages/react/src/hooks/useCycle.mjs->packages/react/dist/index.cjs.js + + + + + +packages/react/src/hooks/usePostMessage.mjs->packages/react/dist/index.cjs.js + + + + + +packages/react/src/hooks/useWebMidi.mjs + + +useWebMidi.mjs + + + + + +packages/react/src/hooks/useWebMidi.mjs->packages/midi/index.mjs + + + + + +packages/react/src/hooks/useWebMidi.mjs->packages/react/dist/index.cjs.js + + + + + +packages/react/src/index.js + + +index.js + + + + + +packages/react/src/index.js->packages/react/src/components/MiniRepl.jsx + + + + + +packages/react/src/index.js->packages/react/src/components/CodeMirror6.jsx + + + + + +packages/react/src/index.js->packages/react/src/cx.js + + + + + +packages/react/src/index.js->packages/react/src/hooks/useHighlighting.mjs + + + + + +packages/react/src/index.js->packages/react/src/hooks/useRepl.mjs + + + + + +packages/react/src/index.js->packages/react/src/hooks/useCycle.mjs + + + + + +packages/react/src/index.js->packages/react/src/hooks/usePostMessage.mjs + + + + + +packages/react/src/index.js->packages/react/src/hooks/useWebMidi.mjs + + + + + +packages/react/src/main.jsx + + +main.jsx + + + + + +packages/react/src/main.jsx->packages/react/dist/index.cjs.js + + + + + +packages/react/src/main.jsx->packages/react/src/App.jsx + + + + + +packages/react/tailwind.config.js + + +tailwind.config.js + + + + + +packages/react/vite.config.js + + +vite.config.js + + + + + +packages/react/vite.config.js->packages/react/package.json + + + + + +packages/serial/serial.mjs + + +serial.mjs + + + + + +packages/serial/serial.mjs->packages/core/index.mjs + + + + + +packages/soundfonts/convert.js + + +convert.js + + + + + +packages/soundfonts/fontloader.mjs + + +fontloader.mjs + + + + + +packages/soundfonts/index.mjs + + +index.mjs + + + + + +packages/soundfonts/index.mjs->packages/soundfonts/fontloader.mjs + + + + + +packages/soundfonts/list.mjs + + +list.mjs + + + + + +packages/soundfonts/index.mjs->packages/soundfonts/list.mjs + + + + + +packages/tonal/tonal.mjs->packages/core/index.mjs + + + + + +packages/tonal/voicings.mjs->packages/core/index.mjs + + + + + +packages/tonal/test/tonal.test.mjs + + +tonal.test.mjs + + + + + +packages/tonal/test/tonal.test.mjs->packages/core/index.mjs + + + + + +packages/tonal/test/tonal.test.mjs->packages/tonal/tonal.mjs + + + + + +packages/tone/draw.mjs->packages/core/index.mjs + + + + + +packages/tone/draw.mjs->packages/tone/tone.mjs + + + + + +packages/tone/tone.mjs->packages/core/util.mjs + + + + + +packages/tone/tone.mjs->packages/core/index.mjs + + + + + +packages/tone/pianoroll.mjs->packages/core/index.mjs + + + + + +packages/tone/ui.mjs->packages/tone/tone.mjs + + + + + +packages/tone/test/tone.test.mjs + + +tone.test.mjs + + + + + +packages/tone/test/tone.test.mjs->packages/core/index.mjs + + + + + +packages/tone/test/tone.test.mjs->packages/tone/tone.mjs + + + + + +packages/webaudio/scheduler.mjs->packages/core/index.mjs + + + + + +packages/webaudio/scheduler.mjs->packages/webaudio/clockworker.mjs + + + + + +packages/webaudio/webaudio.mjs->packages/core/index.mjs + + + + + +packages/webaudio/webaudio.mjs->packages/webaudio/sampler.mjs + + + + + +packages/webdirt/index.mjs + + +index.mjs + + + + + +packages/webdirt/webdirt.mjs + + +webdirt.mjs + + + + + +packages/webdirt/index.mjs->packages/webdirt/webdirt.mjs + + + + + +packages/webdirt/webdirt.mjs->packages/core/index.mjs + + + + + +packages/webdirt/webdirt.mjs->packages/webaudio/index.mjs + + + + + +packages/xen/tune.mjs->packages/core/index.mjs + + + + + +packages/xen/tunejs.js + + +tunejs.js + + + + + +packages/xen/tune.mjs->packages/xen/tunejs.js + + + + + +packages/xen/xen.mjs->packages/core/index.mjs + + + + + +packages/xen/test/xen.test.mjs + + +xen.test.mjs + + + + + +packages/xen/test/xen.test.mjs->packages/xen/xen.mjs + + + + + From 1441374f6e33655a6738f9eb821b796810b97902 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 13 Sep 2022 22:45:03 +0200 Subject: [PATCH 07/61] Create README.md --- packages/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 packages/README.md diff --git a/packages/README.md b/packages/README.md new file mode 100644 index 00000000..5eaa07c6 --- /dev/null +++ b/packages/README.md @@ -0,0 +1,15 @@ +# Packages + +Each folder represents one of the @strudel.cycles/* packages [published to npm](https://www.npmjs.com/org/strudel.cycles). + +To understand how those pieces connect, refer to the [Technical Manual](https://github.com/tidalcycles/strudel/wiki/Technical-Manual) or the individual READMEs. + +This is a graphical view of all the packages: [full screen](https://raw.githubusercontent.com/tidalcycles/strudel/main/dependencies.svg) + +![dependencies](https://raw.githubusercontent.com/tidalcycles/strudel/main/dependencies.svg) + +Generated with + +```sh +npx depcruise --include-only "^packages" -X "node_modules" --output-type dot packages | dot -T svg > dependencygraph.svg +``` From 88e39d22f1013b6145f498d4ac98a4d1d71f0dbf Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 21:53:41 +0200 Subject: [PATCH 08/61] add drums to mini repl --- tutorial/MiniRepl.jsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tutorial/MiniRepl.jsx b/tutorial/MiniRepl.jsx index af21f362..405cd94d 100644 --- a/tutorial/MiniRepl.jsx +++ b/tutorial/MiniRepl.jsx @@ -2,8 +2,8 @@ import { Tone } from '@strudel.cycles/tone'; import { evalScope } from '@strudel.cycles/eval'; import { MiniRepl as _MiniRepl } from '@strudel.cycles/react'; import controls from '@strudel.cycles/core/controls.mjs'; -import * as WebDirt from 'WebDirt'; import { loadWebDirt } from '@strudel.cycles/webdirt'; +import { samples } from '@strudel.cycles/webaudio'; export const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone.Destination).set({ oscillator: { type: 'triangle' }, @@ -12,6 +12,15 @@ export const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone. }, }); +samples( + { + bd: '808bd/BD0000.WAV', + sd: ['808sd/SD0000.WAV', '808sd/SD0010.WAV', '808sd/SD0050.WAV'], + hh: ['hh27/000_hh27closedhh.wav', 'hh/000_hh3closedhh.wav'], + }, + 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/', +); + evalScope( Tone, controls, From 8e61673bd68c9a84eff459541bbe83030998eefb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 21:54:42 +0200 Subject: [PATCH 09/61] doc: degradeBy --- packages/core/signal.mjs | 12 ++++++++++++ tutorial/tutorial.mdx | 10 ++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index a13674f1..28fc491e 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -223,6 +223,18 @@ Pattern.prototype._degradeByWith = function (withPat, x) { return this.fmap((a) => (_) => a).appLeft(withPat._filterValues((v) => v > x)); }; +/** + * Randomly removes events from the pattern by a given amount. + * 0 = 0% chance of removal + * 1 = 100% chance of removal + * + * @name degradeBy + * @memberof Pattern + * @param {number} amount - a number between 0 and 1 + * @returns Pattern + * @example + * s("hh*8").degradeBy(0.5).out() + */ Pattern.prototype._degradeBy = function (x) { return this._degradeByWith(rand, x); }; diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index f8995a33..e95ea5fe 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -177,11 +177,11 @@ In essence, the `x!n` is like a shortcut for `[x*n]@n`. ## Euclidian -Using round brackets, we can create rhythmical sub-divisions based on three parameters: beats, segments and offset. -The first parameter controls how may beats will be played. -The second parameter controls the total amount of segments the beats will be distributed over. +Using round brackets, we can create rhythmical sub-divisions based on three parameters: beats, segments and offset. +The first parameter controls how may beats will be played. +The second parameter controls the total amount of segments the beats will be distributed over. The third (optional) parameter controls the starting position for distributing the beats. -One popular Euclidian rhythm (going by various names, such as "Pop Clave") is "(3,8,1)" or simply "(3,8)", +One popular Euclidian rhythm (going by various names, such as "Pop Clave") is "(3,8,1)" or simply "(3,8)", resulting in a rhythmical structure of "x ~ ~ x ~ ~ x ~" (3 beats over 8 segments, starting on position 1). @@ -450,6 +450,8 @@ Stacks the given pattern to the current pattern: +{{ 'Pattern.degradeBy' | jsdoc }} + ## Tone API To make the sounds more interesting, we can use Tone.js instruments ands effects. From a022e5bb9315c8446b66355d635b2a2ddfbfc79a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 21:55:09 +0200 Subject: [PATCH 10/61] add missing external deps to react pkg --- packages/react/vite.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react/vite.config.js b/packages/react/vite.config.js index d51ef97a..6786d022 100644 --- a/packages/react/vite.config.js +++ b/packages/react/vite.config.js @@ -38,7 +38,9 @@ export default defineConfig({ '@codemirror/commands', '@lezer/highlight', '@codemirror/language', - '@uiw/codemirror-themes' + '@uiw/codemirror-themes', + '@uiw/react-codemirror', + '@lezer/highlight', ], }, target: 'esnext', From ce91d36b7a0059f01cfb67aff56ea61dbbfa57ab Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 23:16:24 +0200 Subject: [PATCH 11/61] doc: random functions --- packages/core/signal.mjs | 146 ++++++++++++++++++++++++++++++++++++++- tutorial/tutorial.mdx | 28 ++++++++ 2 files changed, 172 insertions(+), 2 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 28fc491e..b43ecadf 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th */ import { Hap } from './hap.mjs'; -import { Pattern, fastcat, reify, silence, stack } from './pattern.mjs'; +import { Pattern, fastcat, reify, silence, stack, isPattern } from './pattern.mjs'; import Fraction from './fraction.mjs'; import { id } from './util.mjs'; @@ -233,16 +233,44 @@ Pattern.prototype._degradeByWith = function (withPat, x) { * @param {number} amount - a number between 0 and 1 * @returns Pattern * @example - * s("hh*8").degradeBy(0.5).out() + * s("hh*8").degradeBy(0.2).out() */ Pattern.prototype._degradeBy = function (x) { return this._degradeByWith(rand, x); }; +/** + * + * Randomly removes 50% of events from the pattern. Shorthand for `.degradeBy(0.5)` + * + * @name degrade + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").degrade().out() + */ Pattern.prototype.degrade = function () { return this._degradeBy(0.5); }; +/** + * Inverse of {@link Pattern#degradeBy}: Randomly removes events from the pattern by a given amount. + * 0 = 100% chance of removal + * 1 = 0% chance of removal + * Events that would be removed by degradeBy are let through by undegradeBy and vice versa (see second example). + * + * @name undegradeBy + * @memberof Pattern + * @param {number} amount - a number between 0 and 1 + * @returns Pattern + * @example + * s("hh*8").undegradeBy(0.2).out() + * @example + * stack( + * s("hh*8").undegradeBy(0.2), + * s("bd*8").degradeBy(0.8) + * ).out() + */ Pattern.prototype._undegradeBy = function (x) { return this._degradeByWith( rand.fmap((r) => 1 - r), @@ -258,6 +286,25 @@ Pattern.prototype._sometimesBy = function (x, func) { return stack(this._degradeBy(x), func(this._undegradeBy(1 - x))); }; +// https://github.com/tidalcycles/strudel/discussions/198 +/* Pattern.prototype._sometimesBy = function (x, other) { + other = typeof other === 'function' ? other(this._undegradeBy(1 - x)) : reify(other)._undegradeBy(1 - x); + return stack(this._degradeBy(x), other); +}; */ + +/** + * + * Randomly applies the given function by the given probability. + * Similar to {@link Pattern#someCyclesBy} + * + * @name sometimesBy + * @memberof Pattern + * @param {number | Pattern} probability - a number between 0 and 1 + * @param {function} function - the transformation to apply + * @returns Pattern + * @example + * s("hh(3,8)").sometimesBy(.4, x=>x.speed("0.5")).out() + */ Pattern.prototype.sometimesBy = function (patx, func) { const pat = this; return reify(patx) @@ -265,6 +312,7 @@ Pattern.prototype.sometimesBy = function (patx, func) { .innerJoin(); }; +// why does this exist? it is identical to sometimesBy Pattern.prototype._sometimesByPre = function (x, func) { return stack(this._degradeBy(x), func(this).undegradeBy(1 - x)); }; @@ -276,6 +324,17 @@ Pattern.prototype.sometimesByPre = function (patx, func) { .innerJoin(); }; +/** + * + * Applies the given function with a 50% chance + * + * @name sometimes + * @memberof Pattern + * @param {function} function - the transformation to apply + * @returns Pattern + * @example + * s("hh*4").sometimes(x=>x.speed("0.5")).out() + */ Pattern.prototype.sometimes = function (func) { return this._sometimesBy(0.5, func); }; @@ -291,6 +350,19 @@ Pattern.prototype._someCyclesBy = function (x, func) { ); }; +/** + * + * Randomly applies the given function by the given probability on a cycle by cycle basis. + * Similar to {@link Pattern#sometimesBy} + * + * @name someCyclesBy + * @memberof Pattern + * @param {number | Pattern} probability - a number between 0 and 1 + * @param {function} function - the transformation to apply + * @returns Pattern + * @example + * s("hh(3,8)").someCyclesBy(.3, x=>x.speed("0.5")).out() + */ Pattern.prototype.someCyclesBy = function (patx, func) { const pat = this; return reify(patx) @@ -298,30 +370,100 @@ Pattern.prototype.someCyclesBy = function (patx, func) { .innerJoin(); }; +/** + * + * Shorthand for `.someCyclesBy(0.5, fn)` + * + * @name someCycles + * @memberof Pattern + * @returns Pattern + * @example + * s("hh(3,8)").someCycles(x=>x.speed("0.5")).out() + */ Pattern.prototype.someCycles = function (func) { return this._someCyclesBy(0.5, func); }; +/** + * + * Shorthand for `.sometimesBy(0.75, fn)` + * + * @name often + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").often(x=>x.speed("0.5")).out() + */ Pattern.prototype.often = function (func) { return this.sometimesBy(0.75, func); }; +/** + * + * Shorthand for `.sometimesBy(0.25, fn)` + * + * @name rarely + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").rarely(x=>x.speed("0.5")).out() + */ Pattern.prototype.rarely = function (func) { return this.sometimesBy(0.25, func); }; +/** + * + * Shorthand for `.sometimesBy(0.1, fn)` + * + * @name almostNever + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").almostNever(x=>x.speed("0.5")).out() + */ Pattern.prototype.almostNever = function (func) { return this.sometimesBy(0.1, func); }; +/** + * + * Shorthand for `.sometimesBy(0.9, fn)` + * + * @name almostAlways + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").almostAlways(x=>x.speed("0.5")).out() + */ Pattern.prototype.almostAlways = function (func) { return this.sometimesBy(0.9, func); }; +/** + * + * Shorthand for `.sometimesBy(0, fn)` (never calls fn) + * + * @name never + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").never(x=>x.speed("0.5")).out() + */ Pattern.prototype.never = function (func) { return this; }; +/** + * + * Shorthand for `.sometimesBy(1, fn)` (always calls fn) + * + * @name always + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").always(x=>x.speed("0.5")).out() + */ Pattern.prototype.always = function (func) { return func(this); }; diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index e95ea5fe..4ff4a20a 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -450,8 +450,36 @@ Stacks the given pattern to the current pattern: +## Randomness + +These methods add random behavior to your Patterns. + {{ 'Pattern.degradeBy' | jsdoc }} +{{ 'Pattern.degrade' | jsdoc }} + +{{ 'Pattern.undegradeBy' | jsdoc }} + +{{ 'Pattern.sometimesBy' | jsdoc }} + +{{ 'Pattern.sometimes' | jsdoc }} + +{{ 'Pattern.someCyclesBy' | jsdoc }} + +{{ 'Pattern.someCycles' | jsdoc }} + +{{ 'Pattern.often' | jsdoc }} + +{{ 'Pattern.rarely' | jsdoc }} + +{{ 'Pattern.almostNever' | jsdoc }} + +{{ 'Pattern.almostAlways' | jsdoc }} + +{{ 'Pattern.never' | jsdoc }} + +{{ 'Pattern.always' | jsdoc }} + ## Tone API To make the sounds more interesting, we can use Tone.js instruments ands effects. From f0e412a44344d1b6b96bd9280f44ad1784c30c94 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 23:40:48 +0200 Subject: [PATCH 12/61] doc: chooseCycles + mini shorthands --- packages/core/signal.mjs | 21 ++++++++++++++------- tutorial/MiniRepl.jsx | 2 +- tutorial/tutorial.mdx | 4 +++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index b43ecadf..9a4b5fe5 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -156,8 +156,8 @@ export const chooseInWith = (pat, xs) => { }; /** - * Chooses randomly from the given list of values. - * @param {...any} xs + * Chooses randomly from the given list of elements. + * @param {...any} xs values / patterns to choose from. * @returns {Pattern} - a continuous pattern. */ export const choose = (...xs) => chooseWith(rand, xs); @@ -183,6 +183,14 @@ Pattern.prototype.choose2 = function (...xs) { return chooseWith(this._fromBipolar(), xs); }; +/** + * Picks one of the elements at random each cycle. + * @returns {Pattern} + * @example + * chooseCycles("bd", "hh", "sd").s().fast(4).out() + * @example + * "bd | hh | sd".s().fast(4).out() + */ export const chooseCycles = (...xs) => chooseInWith(rand.segment(1), xs); export const randcat = chooseCycles; @@ -234,6 +242,8 @@ Pattern.prototype._degradeByWith = function (withPat, x) { * @returns Pattern * @example * s("hh*8").degradeBy(0.2).out() + * @example + * s("[hh?0.2]*8").out() */ Pattern.prototype._degradeBy = function (x) { return this._degradeByWith(rand, x); @@ -248,6 +258,8 @@ Pattern.prototype._degradeBy = function (x) { * @returns Pattern * @example * s("hh*8").degrade().out() + * @example + * s("[hh?]*8").out() */ Pattern.prototype.degrade = function () { return this._degradeBy(0.5); @@ -265,11 +277,6 @@ Pattern.prototype.degrade = function () { * @returns Pattern * @example * s("hh*8").undegradeBy(0.2).out() - * @example - * stack( - * s("hh*8").undegradeBy(0.2), - * s("bd*8").degradeBy(0.8) - * ).out() */ Pattern.prototype._undegradeBy = function (x) { return this._degradeByWith( diff --git a/tutorial/MiniRepl.jsx b/tutorial/MiniRepl.jsx index 405cd94d..0f18c2b6 100644 --- a/tutorial/MiniRepl.jsx +++ b/tutorial/MiniRepl.jsx @@ -15,7 +15,7 @@ export const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone. samples( { bd: '808bd/BD0000.WAV', - sd: ['808sd/SD0000.WAV', '808sd/SD0010.WAV', '808sd/SD0050.WAV'], + sd: ['808sd/SD0010.WAV', '808sd/SD0050.WAV', '808sd/SD0000.WAV'], hh: ['hh27/000_hh27closedhh.wav', 'hh/000_hh3closedhh.wav'], }, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/', diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 4ff4a20a..8e1fc75e 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -452,7 +452,9 @@ Stacks the given pattern to the current pattern: ## Randomness -These methods add random behavior to your Patterns. +These methods add random behavior to your Patterns. + +{{ 'chooseCycles' | jsdoc }} {{ 'Pattern.degradeBy' | jsdoc }} From 0ffbb5cb2cceed3fcff771e75eef69da0b3283c5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 15 Sep 2022 16:54:27 +0200 Subject: [PATCH 13/61] ignore stats --- .gitignore | 3 +- repl/stats.html | 4034 ----------------------------------------------- 2 files changed, 2 insertions(+), 4035 deletions(-) delete mode 100644 repl/stats.html diff --git a/.gitignore b/.gitignore index 43684564..c390b0e5 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,5 @@ tutorial.rendered.mdx doc.json talk/public/EmuSP12 talk/public/samples -server/samples/old \ No newline at end of file +server/samples/old +repl/stats.html \ No newline at end of file diff --git a/repl/stats.html b/repl/stats.html deleted file mode 100644 index 920505b6..00000000 --- a/repl/stats.html +++ /dev/null @@ -1,4034 +0,0 @@ - - - - - - - - RollUp Visualizer - - - -
- - - - - From 4406dd88d1f3f4313149216f3e4cd3d55d2381cb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 15 Sep 2022 20:09:07 +0200 Subject: [PATCH 14/61] add vowel --- packages/webaudio/vowel.mjs | 37 ++++++++++++++++++++++++++++++++++ packages/webaudio/webaudio.mjs | 3 +++ 2 files changed, 40 insertions(+) create mode 100644 packages/webaudio/vowel.mjs diff --git a/packages/webaudio/vowel.mjs b/packages/webaudio/vowel.mjs new file mode 100644 index 00000000..c35b1ebd --- /dev/null +++ b/packages/webaudio/vowel.mjs @@ -0,0 +1,37 @@ +// credits to webdirt: https://github.com/dktr0/WebDirt/blob/41342e81d6ad694a2310d491fef7b7e8b0929efe/js-src/Graph.js#L597 +export var vowelFormant = { + a: { freqs: [660, 1120, 2750, 3000, 3350], gains: [1, 0.5012, 0.0708, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, + e: { freqs: [440, 1800, 2700, 3000, 3300], gains: [1, 0.1995, 0.1259, 0.1, 0.1], qs: [70, 80, 100, 120, 120] }, + i: { freqs: [270, 1850, 2900, 3350, 3590], gains: [1, 0.0631, 0.0631, 0.0158, 0.0158], qs: [40, 90, 100, 120, 120] }, + o: { freqs: [430, 820, 2700, 3000, 3300], gains: [1, 0.3162, 0.0501, 0.0794, 0.01995], qs: [40, 80, 100, 120, 120] }, + u: { freqs: [370, 630, 2750, 3000, 3400], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, +}; + +class VowelNode extends GainNode { + constructor(ac, letter) { + super(ac); + if (!vowelFormant[letter]) { + throw new Error('vowel: unknown vowel ' + letter); + } + const { gains, qs, freqs } = vowelFormant[letter]; + const makeupGain = ac.createGain(); + for (let i = 0; i < 5; i++) { + const gain = ac.createGain(); + gain.gain.value = gains[i]; + const filter = ac.createBiquadFilter(); + filter.type = 'bandpass'; + filter.Q.value = qs[i]; + filter.frequency.value = freqs[i]; + this.connect(filter); + filter.connect(gain); + gain.connect(makeupGain); + } + makeupGain.gain.value = 8; // how much makeup gain to add? + this.connect = (target) => makeupGain.connect(target); + return this; + } +} + +AudioContext.prototype.createVowelFilter = function (letter) { + return new VowelNode(this, letter); +}; diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 2a6d39d0..18186118 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -9,6 +9,7 @@ import * as strudel from '@strudel.cycles/core'; import { fromMidi, toMidi } from '@strudel.cycles/core'; import { loadBuffer } from './sampler.mjs'; const { Pattern } = strudel; +import './vowel.mjs'; // export const getAudioContext = () => Tone.getContext().rawContext; @@ -158,6 +159,7 @@ Pattern.prototype.out = function () { speed = 1, // sample playback speed begin = 0, end = 1, + vowel, } = hap.value; const { velocity = 1 } = hap.context; gain *= velocity; // legacy fix for velocity @@ -258,6 +260,7 @@ Pattern.prototype.out = function () { cutoff !== undefined && chain.push(getFilter('lowpass', cutoff, resonance)); hcutoff !== undefined && chain.push(getFilter('highpass', hcutoff, hresonance)); bandf !== undefined && chain.push(getFilter('bandpass', bandf, bandq)); + vowel !== undefined && chain.push(ac.createVowelFilter(vowel)); // TODO vowel // TODO delay / delaytime / delayfeedback // panning From 149b2ab9f9420549db48b6d7b7140f1019a12538 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 15 Sep 2022 20:11:10 +0200 Subject: [PATCH 15/61] make vowel work with node --- packages/webaudio/vowel.mjs | 53 +++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/packages/webaudio/vowel.mjs b/packages/webaudio/vowel.mjs index c35b1ebd..25357642 100644 --- a/packages/webaudio/vowel.mjs +++ b/packages/webaudio/vowel.mjs @@ -6,32 +6,33 @@ export var vowelFormant = { o: { freqs: [430, 820, 2700, 3000, 3300], gains: [1, 0.3162, 0.0501, 0.0794, 0.01995], qs: [40, 80, 100, 120, 120] }, u: { freqs: [370, 630, 2750, 3000, 3400], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, }; - -class VowelNode extends GainNode { - constructor(ac, letter) { - super(ac); - if (!vowelFormant[letter]) { - throw new Error('vowel: unknown vowel ' + letter); +if (typeof GainNode !== 'undefined') { + class VowelNode extends GainNode { + constructor(ac, letter) { + super(ac); + if (!vowelFormant[letter]) { + throw new Error('vowel: unknown vowel ' + letter); + } + const { gains, qs, freqs } = vowelFormant[letter]; + const makeupGain = ac.createGain(); + for (let i = 0; i < 5; i++) { + const gain = ac.createGain(); + gain.gain.value = gains[i]; + const filter = ac.createBiquadFilter(); + filter.type = 'bandpass'; + filter.Q.value = qs[i]; + filter.frequency.value = freqs[i]; + this.connect(filter); + filter.connect(gain); + gain.connect(makeupGain); + } + makeupGain.gain.value = 8; // how much makeup gain to add? + this.connect = (target) => makeupGain.connect(target); + return this; } - const { gains, qs, freqs } = vowelFormant[letter]; - const makeupGain = ac.createGain(); - for (let i = 0; i < 5; i++) { - const gain = ac.createGain(); - gain.gain.value = gains[i]; - const filter = ac.createBiquadFilter(); - filter.type = 'bandpass'; - filter.Q.value = qs[i]; - filter.frequency.value = freqs[i]; - this.connect(filter); - filter.connect(gain); - gain.connect(makeupGain); - } - makeupGain.gain.value = 8; // how much makeup gain to add? - this.connect = (target) => makeupGain.connect(target); - return this; } -} -AudioContext.prototype.createVowelFilter = function (letter) { - return new VowelNode(this, letter); -}; + AudioContext.prototype.createVowelFilter = function (letter) { + return new VowelNode(this, letter); + }; +} From b9173ebe50a3c8259a11783db731fe5973e27d39 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 16 Sep 2022 00:14:28 +0200 Subject: [PATCH 16/61] add coarse, crush and shape --- packages/webaudio/webaudio.mjs | 32 +++++++++++- packages/webaudio/worklets.mjs | 94 ++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 packages/webaudio/worklets.mjs diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 18186118..2111c10e 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -10,6 +10,7 @@ import { fromMidi, toMidi } from '@strudel.cycles/core'; import { loadBuffer } from './sampler.mjs'; const { Pattern } = strudel; import './vowel.mjs'; +import workletsUrl from './worklets.mjs?url'; // export const getAudioContext = () => Tone.getContext().rawContext; @@ -129,7 +130,29 @@ const splitSN = (s, n) => { return [s2, n2]; }; -Pattern.prototype.out = function () { +let workletsLoading; +function loadWorklets() { + if (workletsLoading) { + return workletsLoading; + } + workletsLoading = getAudioContext().audioWorklet.addModule(workletsUrl); + return workletsLoading; +} + +function getWorklet(ac, processor, params) { + const node = new AudioWorkletNode(ac, processor); + Object.entries(params).forEach(([key, value]) => { + node.parameters.get(key).value = value; + }); + return node; +} + +Pattern.prototype.out = async function () { + try { + await loadWorklets(); + } catch (err) { + console.warn('could not load AudioWorklet effects coarse, crush and shape', err); + } return this.onTrigger(async (t, hap, ct, cps) => { const hapDuration = hap.duration / cps; try { @@ -151,6 +174,9 @@ Pattern.prototype.out = function () { hresonance = 1, bandf, bandq = 1, + coarse, + crush, + shape, pan, attack = 0.001, decay = 0.05, @@ -261,7 +287,9 @@ Pattern.prototype.out = function () { hcutoff !== undefined && chain.push(getFilter('highpass', hcutoff, hresonance)); bandf !== undefined && chain.push(getFilter('bandpass', bandf, bandq)); vowel !== undefined && chain.push(ac.createVowelFilter(vowel)); - // TODO vowel + coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse })); + crush !== undefined && chain.push(getWorklet(ac, 'crush-processor', { crush })); + shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', { shape })); // TODO delay / delaytime / delayfeedback // panning if (pan !== undefined) { diff --git a/packages/webaudio/worklets.mjs b/packages/webaudio/worklets.mjs new file mode 100644 index 00000000..2c4ab540 --- /dev/null +++ b/packages/webaudio/worklets.mjs @@ -0,0 +1,94 @@ +// all the credit goes to webdirt: https://github.com/dktr0/WebDirt/blob/5ce3d698362c54d6e1b68acc47eb2955ac62c793/dist/AudioWorklets.js + +class CoarseProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [{ name: 'coarse', defaultValue: 1 }]; + } + + constructor() { + super(); + this.notStarted = true; + } + + process(inputs, outputs, parameters) { + const input = inputs[0]; + const output = outputs[0]; + const coarse = parameters.coarse; + const blockSize = 128; + const hasInput = !(input[0] === undefined); + if (hasInput) { + this.notStarted = false; + output[0][0] = input[0][0]; + for (let n = 1; n < blockSize; n++) { + if (n % coarse == 0) output[0][n] = input[0][n]; + else output[0][n] = output[0][n - 1]; + } + } + return this.notStarted || hasInput; + } +} + +registerProcessor('coarse-processor', CoarseProcessor); + +class CrushProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [{ name: 'crush', defaultValue: 0 }]; + } + + constructor() { + super(); + this.notStarted = true; + } + + process(inputs, outputs, parameters) { + const input = inputs[0]; + const output = outputs[0]; + const crush = parameters.crush; + const blockSize = 128; + const hasInput = !(input[0] === undefined); + if (hasInput) { + this.notStarted = false; + if (crush.length === 1) { + const x = Math.pow(2, crush[0] - 1); + for (let n = 0; n < blockSize; n++) output[0][n] = Math.round(input[0][n] * x) / x; + } else { + for (let n = 0; n < blockSize; n++) { + let x = Math.pow(2, crush[n] - 1); + output[0][n] = Math.round(input[0][n] * x) / x; + } + } + } + return this.notStarted || hasInput; + } +} +registerProcessor('crush-processor', CrushProcessor); + +class ShapeProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [{ name: 'shape', defaultValue: 0 }]; + } + + constructor() { + super(); + this.notStarted = true; + } + + process(inputs, outputs, parameters) { + const input = inputs[0]; + const output = outputs[0]; + const shape0 = parameters.shape[0]; + const shape1 = shape0 < 1 ? shape0 : 1.0 - 4e-10; + const shape = (2.0 * shape1) / (1.0 - shape1); + const blockSize = 128; + const hasInput = !(input[0] === undefined); + if (hasInput) { + this.notStarted = false; + for (let n = 0; n < blockSize; n++) { + output[0][n] = ((1 + shape) * input[0][n]) / (1 + shape * Math.abs(input[0][n])); + } + } + return this.notStarted || hasInput; + } +} + +registerProcessor('shape-processor', ShapeProcessor); From 5d28c5c825d64fa92392c6ef9b22c190d2d95f92 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 16 Sep 2022 00:17:42 +0200 Subject: [PATCH 17/61] add license info --- packages/webaudio/worklets.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/webaudio/worklets.mjs b/packages/webaudio/worklets.mjs index 2c4ab540..c5306c45 100644 --- a/packages/webaudio/worklets.mjs +++ b/packages/webaudio/worklets.mjs @@ -1,4 +1,6 @@ -// all the credit goes to webdirt: https://github.com/dktr0/WebDirt/blob/5ce3d698362c54d6e1b68acc47eb2955ac62c793/dist/AudioWorklets.js +// LICENSE GNU General Public License v3.0 see https://github.com/dktr0/WebDirt/blob/main/LICENSE +// all the credit goes to dktr0's webdirt: https://github.com/dktr0/WebDirt/blob/5ce3d698362c54d6e1b68acc47eb2955ac62c793/dist/AudioWorklets.js +// <3 class CoarseProcessor extends AudioWorkletProcessor { static get parameterDescriptors() { From a11d23ba62cefbd4426cae73357ea27cf80686f6 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 16 Sep 2022 00:30:37 +0200 Subject: [PATCH 18/61] hotfix: out should not be async --- packages/webaudio/webaudio.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 2111c10e..0a9057e8 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -147,9 +147,9 @@ function getWorklet(ac, processor, params) { return node; } -Pattern.prototype.out = async function () { +Pattern.prototype.out = function () { try { - await loadWorklets(); + loadWorklets(); } catch (err) { console.warn('could not load AudioWorklet effects coarse, crush and shape', err); } From 3fdfd12448d65a65db354b954e68c6c533eab500 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 16 Sep 2022 00:53:43 +0200 Subject: [PATCH 19/61] hotfix: disconnect chain after use --- packages/webaudio/webaudio.mjs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 0a9057e8..e2936f77 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -304,6 +304,10 @@ Pattern.prototype.out = function () { chain.push(ac.destination); // connect chain elements together chain.slice(1).reduce((last, current) => last.connect(current), chain[0]); + // disconnect all nodes when hap is over to make sure they are garbage collected + setTimeout(() => { + chain.forEach((n) => n.disconnect()); + }, (hapDuration + release + 0.1) * 1000); } catch (e) { console.warn('.out error:', e); } From dd4464cb0884bda32746e31b4e7e0ef169e39eaa Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 16 Sep 2022 11:05:38 +0200 Subject: [PATCH 20/61] fix build: dont add sourcemaps --- package.json | 2 +- repl/vite.config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index bf045288..dc23a45c 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "osc": "cd packages/osc && npm run server", "build": "rm -rf out && cd repl && npm run build && cd ../tutorial && npm run build", "preview": "npx serve ./out", - "deploy": "gh-pages -d out", + "deploy": "NODE_DEBUG=gh-pages gh-pages -d out", "jsdoc": "jsdoc packages/ -c jsdoc.config.json", "jsdoc-json": "jsdoc packages/ --template ./node_modules/jsdoc-json --destination doc.json -c jsdoc.config.json" }, diff --git a/repl/vite.config.js b/repl/vite.config.js index 1d3f3e86..728a6e22 100644 --- a/repl/vite.config.js +++ b/repl/vite.config.js @@ -7,7 +7,7 @@ export default defineConfig({ plugins: [react()], build: { outDir: '../out', - sourcemap: true, + sourcemap: false, rollupOptions: { plugins: [visualizer({ template: 'treemap' })], }, From 782e8522c57611be3dd84a45c7e6ff901a557180 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 16 Sep 2022 23:24:47 +0200 Subject: [PATCH 21/61] add all default samples to mini repl --- tutorial/MiniRepl.jsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tutorial/MiniRepl.jsx b/tutorial/MiniRepl.jsx index 0f18c2b6..56387190 100644 --- a/tutorial/MiniRepl.jsx +++ b/tutorial/MiniRepl.jsx @@ -12,14 +12,10 @@ export const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone. }, }); -samples( - { - bd: '808bd/BD0000.WAV', - sd: ['808sd/SD0010.WAV', '808sd/SD0050.WAV', '808sd/SD0000.WAV'], - hh: ['hh27/000_hh27closedhh.wav', 'hh/000_hh3closedhh.wav'], - }, - 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/', -); +await fetch('https://strudel.tidalcycles.org/EmuSP12.json') + .then((res) => res.json()) + .then((json) => samples(json, 'https://strudel.tidalcycles.org/EmuSP12/')); + evalScope( Tone, From 3c8acf9e0e9dbc08d9d5b91035b5c9c60fc4b854 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 16 Sep 2022 23:25:33 +0200 Subject: [PATCH 22/61] comment out timeout: it will cut of samples that are longer than hap.. --- packages/webaudio/webaudio.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index e2936f77..40d0f73f 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -199,7 +199,7 @@ Pattern.prototype.out = function () { } if (!s || ['sine', 'square', 'triangle', 'sawtooth'].includes(s)) { // with synths, n and note are the same thing - n = note || n; + n = note || n || 36; if (typeof n === 'string') { n = toMidi(n); // e.g. c3 => 48 } @@ -305,9 +305,9 @@ Pattern.prototype.out = function () { // connect chain elements together chain.slice(1).reduce((last, current) => last.connect(current), chain[0]); // disconnect all nodes when hap is over to make sure they are garbage collected - setTimeout(() => { +/* setTimeout(() => { chain.forEach((n) => n.disconnect()); - }, (hapDuration + release + 0.1) * 1000); + }, (hapDuration + release + 0.1) * 1000); */ } catch (e) { console.warn('.out error:', e); } From e58aff41f92b2b9deedffd1b57480f83b5d25c50 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 16 Sep 2022 23:25:42 +0200 Subject: [PATCH 23/61] begin webaudio tutorial --- packages/core/controls.mjs | 4 +- packages/webaudio/sampler.mjs | 10 +-- tutorial/tutorial.mdx | 151 ++++++++++++++++++++++++++++++++-- 3 files changed, 152 insertions(+), 13 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index b9d8a257..40ed4427 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -11,7 +11,7 @@ const generic_params = [ /** * Select a sound / sample by name. * - *
+ *
* show all sounds * * 808 (6) 808bd (25) 808cy (25) 808hc (5) 808ht (5) 808lc (5) 808lt (5) 808mc (5) 808mt (5) 808oh (5) 808sd (25) 909 (1) ab (12) ade (10) ades2 (9) ades3 (7) ades4 (6) alex (2) alphabet (26) amencutup (32) armora (7) arp (2) arpy (11) auto (11) baa (7) baa2 (7) bass (4) bass0 (3) bass1 (30) bass2 (5) bass3 (11) bassdm (24) bassfoo (3) battles (2) bd (24) bend (4) bev (2) bin (2) birds (10) birds3 (19) bleep (13) blip (2) blue (2) bottle (13) breaks125 (2) breaks152 (1) breaks157 (1) breaks165 (1) breath (1) bubble (8) can (14) casio (3) cb (1) cc (6) chin (4) circus (3) clak (2) click (4) clubkick (5) co (4) coins (1) control (2) cosmicg (15) cp (2) cr (6) crow (4) d (4) db (13) diphone (38) diphone2 (12) dist (16) dork2 (4) dorkbot (2) dr (42) dr2 (6) dr55 (4) dr_few (8) drum (6) drumtraks (13) e (8) east (9) electro1 (13) em2 (6) erk (1) f (1) feel (7) feelfx (8) fest (1) fire (1) flick (17) fm (17) foo (27) future (17) gab (10) gabba (4) gabbaloud (4) gabbalouder (4) glasstap (3) glitch (8) glitch2 (8) gretsch (24) gtr (3) h (7) hand (17) hardcore (12) hardkick (6) haw (6) hc (6) hh (13) hh27 (13) hit (6) hmm (1) ho (6) hoover (6) house (8) ht (16) if (5) ifdrums (3) incoming (8) industrial (32) insect (3) invaders (18) jazz (8) jungbass (20) jungle (13) juno (12) jvbass (13) kicklinn (1) koy (2) kurt (7) latibro (8) led (1) less (4) lighter (33) linnhats (6) lt (16) made (7) made2 (1) mash (2) mash2 (4) metal (10) miniyeah (4) monsterb (6) moog (7) mouth (15) mp3 (4) msg (9) mt (16) mute (28) newnotes (15) noise (1) noise2 (8) notes (15) numbers (9) oc (4) odx (15) off (1) outdoor (6) pad (3) padlong (1) pebbles (1) perc (6) peri (15) pluck (17) popkick (10) print (11) proc (2) procshort (8) psr (30) rave (8) rave2 (4) ravemono (2) realclaps (4) reverbkick (1) rm (2) rs (1) sax (22) sd (2) seawolf (3) sequential (8) sf (18) sheffield (1) short (5) sid (12) sine (6) sitar (8) sn (52) space (18) speakspell (12) speech (7) speechless (10) speedupdown (9) stab (23) stomp (10) subroc3d (11) sugar (2) sundance (6) tabla (26) tabla2 (46) tablex (3) tacscan (22) tech (13) techno (7) tink (5) tok (4) toys (13) trump (11) ul (10) ulgab (5) uxay (3) v (6) voodoo (5) wind (10) wobble (1) world (3) xmas (1) yeah (31) @@ -23,7 +23,7 @@ const generic_params = [ * @name s * @param {string | Pattern} sound The sound / pattern of sounds to pick * @example - * s("bd hh").osc() + * s("bd hh").out() * */ ['s', 's', 'sound'], diff --git a/packages/webaudio/sampler.mjs b/packages/webaudio/sampler.mjs index 10c6d6be..a86d26ce 100644 --- a/packages/webaudio/sampler.mjs +++ b/packages/webaudio/sampler.mjs @@ -82,14 +82,14 @@ export const loadGithubSamples = async (path, nameFn) => { }; /** - * load the given sample map for webdirt + * Loads a collection of samples to use with `s` * * @example - * loadSamples({ - * bd: '808bd/BD0000.WAV', - * sd: ['808sd/SD0000.WAV','808sd/SD0010.WAV','808sd/SD0050.WAV'] + * samples({ + * bd: '808bd/BD0000.WAV', + * sd: '808sd/SD0010.WAV' * }, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/'); - * s("bd ").n(2).webdirt() + * s("[bd ~]*2, [~ hh]*2, ~ sd").out() * */ diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 8e1fc75e..f8ca1571 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -186,14 +186,153 @@ resulting in a rhythmical structure of "x ~ ~ x ~ ~ x ~" (3 beats over 8 segment -## Mini Notation TODO +
-Compared to [tidal mini notation](https://tidalcycles.org/docs/patternlib/tutorials/mini_notation/), the following mini notation features are missing from Strudel: +# Web Audio Output + +The default way to output sound is by using the Web Audio Output. +Here is a little beat to show some of the possibilities: + +],hh(3,4)") // drums +.speed(perlin.range(.7,.9)) // random sample speed variation +,"" // bassline +.off(1/8,x=>x.add(12).degradeBy(.5)) // random octave jumps +.add(perlin.range(0,.5)) // random pitch variation +.superimpose(add(.05)) // add second, slightly detuned voice +.n() // wrap in "n" +.decay(.15).sustain(0) // make each note of equal length +.s('sawtooth') // waveform +.gain(.4) // turn down +.cutoff(sine.slow(7).range(300,5000)) // automate cutoff +,">".voicings() // chords +.superimpose(x=>x.add(.04)) // add second, slightly detuned voice +.add(perlin.range(0,.5)) // random pitch variation +.n() // wrap in "n" +.s('sawtooth') // waveform +.gain(.16) // turn down +.cutoff(500) // fixed cutoff +.attack(1) // slowly fade in +) +.slow(3/2) +.out()`} +/> + +## Synths + +So far, all the mini notation examples all used the same sound, which is kind of boring. +We can change the sound, using the `s` function: + +>").s('sawtooth').out()`} /> + +Here, we are wrapping our notes inside `note` and set the sound using `s`, connected by a dot. + +Those functions are only 2 of many ways to alter the properties, or _params_ of a sound. +The power of patterns allows us to sequence any _param_ independently: + +>").s("").out()`} /> + +Now we not only pattern the notes, but the sound as well! +`sawtooth` `square` and `triangle` are the basic waveforms available in `s`. + +## Samples + +Besides Synths, `s` can also play back samples: + + + +To know which sounds are available, open the [default sample map](https://strudel.tidalcycles.org/EmuSP12.json) + +### Custom Samples + +You can load your own sample map like this: + + + +The `samples` function takes an object where the properties are the sound names and the values are urls to audio files. +As most sample packs will be loaded from the same location, you can set the base url using the second argument: + + + +Because github is a popular choice to dump samples, there is a shortcut for that: + + + +The format is `github:user/repo/branch/`. + +It is also possible, to declare multiple files for one sound, using the array notation: + +,~ ,[hh:0 hh:1]*2").out()`} +/> + +The `:0` `:1` etc. are the indices of the array. + +For pitched samples, you can use `note`, just like with synths: + +@2").s('gtr').gain(.5).out()`} +/> + +Here, the guitar samples will overlap, because they always play till the end. +If we want them to behave more like a synth, we can add `clip(1)`: + +@2").s('gtr').clip(1) + .gain(.5).out()`} +/> + +If we have 2 samples with different base pitches, we can make them in tune by specifying the pitch like this: + +@2").s("gtr,moog").clip(1) + .gain(.5).out()`} +/> + +If a sample has no pitch set, `c3` is the default. -- [ ] Tie symbols "\_" -- [ ] feet marking "." -- [ ] Polymetric sequences "{ ... }" -- [ ] Fixed steps using "%"
From de4726ec8d437282c3689384f61d3d379ad07818 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 16 Sep 2022 23:59:46 +0200 Subject: [PATCH 24/61] improve sampler section --- tutorial/tutorial.mdx | 52 ++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index f8ca1571..3ef79a0b 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -249,22 +249,10 @@ Besides Synths, `s` can also play back samples: To know which sounds are available, open the [default sample map](https://strudel.tidalcycles.org/EmuSP12.json) -### Custom Samples +### Custom Sample Maps You can load your own sample map like this: - - -The `samples` function takes an object where the properties are the sound names and the values are urls to audio files. -As most sample packs will be loaded from the same location, you can set the base url using the second argument: - +The `samples` function takes an object that maps sound names to audio file paths. +The second argument is the base URL that comes before each path. Make sure your base URL ends with a slash, while your sample paths do **not** begin with one. + Because github is a popular choice to dump samples, there is a shortcut for that: ,~ ,[hh:0 hh:1]*2").out()`} +s(",~ ,[hh:0 hh:1]*2").out()`} /> The `:0` `:1` etc. are the indices of the array. +The sample number can also be set using `n`: -For pitched samples, you can use `note`, just like with synths: +").out()`} +/> + +### Pitched Sounds + +For pitched sounds, you can use `note`, just like with synths: @2").s('gtr').clip(1) .gain(.5).out()`} /> +### Base Pitch + If we have 2 samples with different base pitches, we can make them in tune by specifying the pitch like this: @2").s("gtr,moog").clip(1) If a sample has no pitch set, `c3` is the default. +We can also declare different samples for different regions of the keyboard: + +!2, g4 f4]>") + .s('moog').clip(1) + .gain(.5).out()`} +/> + +The sampler will always pick the closest matching sample for the current note!
From acf339ad1364e206d43c81c7643bd42e1ba0c732 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 15:18:16 +0200 Subject: [PATCH 25/61] load worklets on startup --- packages/webaudio/webaudio.mjs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 40d0f73f..bcba7ef0 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -147,12 +147,13 @@ function getWorklet(ac, processor, params) { return node; } +try { + loadWorklets(); +} catch (err) { + console.warn('could not load AudioWorklet effects coarse, crush and shape', err); +} + Pattern.prototype.out = function () { - try { - loadWorklets(); - } catch (err) { - console.warn('could not load AudioWorklet effects coarse, crush and shape', err); - } return this.onTrigger(async (t, hap, ct, cps) => { const hapDuration = hap.duration / cps; try { @@ -305,7 +306,7 @@ Pattern.prototype.out = function () { // connect chain elements together chain.slice(1).reduce((last, current) => last.connect(current), chain[0]); // disconnect all nodes when hap is over to make sure they are garbage collected -/* setTimeout(() => { + /* setTimeout(() => { chain.forEach((n) => n.disconnect()); }, (hapDuration + release + 0.1) * 1000); */ } catch (e) { From 71ca46b21bd2eaf42bbb7a4d0e620fa36686222a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 15:18:38 +0200 Subject: [PATCH 26/61] remove headings for generated doc --- tutorial/render.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tutorial/render.js b/tutorial/render.js index 58c6c51a..30dbab3f 100644 --- a/tutorial/render.js +++ b/tutorial/render.js @@ -23,8 +23,6 @@ ${item.description.replaceAll(/\{\@link ([a-zA-Z]+)?\#?([a-zA-Z]*)\}/g, (_, a, b return `${a}${b ? `#${b}` : ''}`; })} -${!!item.params?.length ? '**Parameters**' : ''} - ${ item.params ?.map( @@ -36,8 +34,7 @@ ${ ${ item.examples?.length - ? `**Examples** - + ? `
${item.examples?.map((example, k) => ``).join('\n\n')}
` From cafcead62ef153edbb156238b9a882961ef2b9f8 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 15:18:57 +0200 Subject: [PATCH 27/61] doc: web audio effects --- packages/core/controls.mjs | 32 ++++++++++++++++---------------- tutorial/tutorial.mdx | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 40ed4427..c5c19644 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -129,7 +129,7 @@ const generic_params = [ * @name bandf * @param {number | Pattern} frequency center frequency * @example - * s("bd sd").bandf("<1000 2000 4000 8000>").osc() + * s("bd sd,hh*3").bandf("<1000 2000 4000 8000>").out() * */ ['f', 'bandf', 'A pattern of numbers from 0 to 1. Sets the center frequency of the band-pass filter.'], @@ -140,7 +140,7 @@ const generic_params = [ * @name bandq * @param {number | Pattern} q q factor * @example - * s("bd sd").bandf(2000).bandq("<.2 .9>").osc() + * s("bd sd").bandf(500).bandq("<0 1 2 3>").out() * */ ['f', 'bandq', 'a pattern of anumbers from 0 to 1. Sets the q-factor of the band-pass filter.'], @@ -202,7 +202,7 @@ const generic_params = [ * @name crush * @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction). * @example - * s(",hh*3,jvbass*2").fast(2).crush("<16 8 7 6 5 4 3 2>").osc() + * s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>").out() * */ [ @@ -216,7 +216,7 @@ const generic_params = [ * @name coarse * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on. * @example - * s("xmas").coarse("<1 4 8 16 32>").osc() + * s("bd sd,hh*4").coarse("<1 4 8 16 32>").out() * */ [ @@ -253,7 +253,7 @@ const generic_params = [ * @name cutoff * @param {number | Pattern} frequency audible between 0 and 20000 * @example - * s("bd,hh*2,<~ sd>").fast(2).cutoff("<4000 2000 1000 500 200 100>").osc() + * s("bd sd,hh*3").cutoff("<4000 2000 1000 500 200 100>").out() * */ // TODO: add lpf synonym @@ -264,7 +264,7 @@ const generic_params = [ * @name hcutoff * @param {number | Pattern} frequency audible between 0 and 20000 * @example - * s("bd,hh*2,<~ sd>").fast(2).hcutoff("<4000 2000 1000 500 200 100>").osc() + * s("bd sd,hh*4").hcutoff("<4000 2000 1000 500 200 100>").out() * */ // TODO: add hpf synonym @@ -274,12 +274,12 @@ const generic_params = [ 'a pattern of numbers from 0 to 1. Applies the cutoff frequency of the high-pass filter. Also has alias @hpf@', ], /** - * Applies the cutoff frequency of the high-pass filter. + * Applies the resonance of the high-pass filter. * * @name hresonance * @param {number | Pattern} q resonance factor between 0 and 1 * @example - * s("bd,hh*2,<~ sd>").fast(2).hcutoff(2000).hresonance("<0 .2 .4 .6>").osc() + * s("bd sd,hh*4").hcutoff(2000).hresonance("<0 10 20 30>").out() * */ [ @@ -294,13 +294,13 @@ const generic_params = [ * @name resonance * @param {number | Pattern} q resonance factor between 0 and 1 * @example - * s("bd,hh*2,<~ sd>").fast(2).cutoff(2000).resonance("<0 .2 .4 .6>").osc() + * s("bd sd,hh*4").cutoff(2000).resonance("<0 10 20 30>").out() * */ ['f', 'resonance', 'a pattern of numbers from 0 to 1. Specifies the resonance of the low-pass filter.'], // TODO: add lpq synonym? /** - * Set detune of oscillators. Works only with some synths, see tidal doc + * DJ filter, below 0.5 is low pass filter, above is high pass filter. * * @name djf * @param {number | Pattern} cutoff below 0.5 is low pass filter, above is high pass filter @@ -493,7 +493,7 @@ const generic_params = [ * @name pan * @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel) * @example - * s("[bd hh]*2").pan("<.5 1 .5 0>").osc() + * s("[bd hh]*2").pan("<.5 1 .5 0>").out() * */ [ @@ -591,7 +591,7 @@ const generic_params = [ * @name shape * @param {number | Pattern} distortion between 0 and 1 * @example - * s("bd sd").shape("<0 .2 .4 .6 .8 1>").osc() + * s("bd sd,hh*4").shape("<0 .2 .4 .6 .8>").out() * */ [ @@ -648,16 +648,16 @@ const generic_params = [ // ['f', 'tomdecay', ''], // ['f', 'vcfegint', ''], // ['f', 'vcoegint', ''], + // TODO: Use a rest (~) to override the effect <- vowel /** * * Formant filter to make things sound like vowels. * * @name vowel - * @param {string | Pattern} vowel You can use a e i o u. Use a rest (~) to override the effect + * @param {string | Pattern} vowel You can use a e i o u. * @example - * vowel("a e i [o u]").slow(2) - * .n("<[0,7]!4 [2,7]!4>") - * .s('supersquare').osc() + * note("c2 >").s('sawtooth') + * .vowel(">").out() * */ [ diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 3ef79a0b..23fbbc2d 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -241,6 +241,15 @@ The power of patterns allows us to sequence any _param_ independently: Now we not only pattern the notes, but the sound as well! `sawtooth` `square` and `triangle` are the basic waveforms available in `s`. +### Envelope + +You can control the envelope of a synth using the `attack`, `decay`, `sustain` and `release` functions: + +>").s('sawtooth') + .attack(.1).decay(.1).sustain(.2).release(.1).out()`} +/> + ## Samples Besides Synths, `s` can also play back samples: @@ -356,6 +365,32 @@ note("g2!2 !2, g4 f4]>") The sampler will always pick the closest matching sample for the current note! +## Effects + +Wether you're using a synth or a sample, you can apply these effects: + +{{ 'cutoff' | jsdoc }} + +{{ 'resonance' | jsdoc }} + +{{ 'hcutoff' | jsdoc }} + +{{ 'hresonance' | jsdoc }} + +{{ 'bandf' | jsdoc }} + +{{ 'bandq' | jsdoc }} + +{{ 'vowel' | jsdoc }} + +{{ 'pan' | jsdoc }} + +{{ 'coarse' | jsdoc }} + +{{ 'shape' | jsdoc }} + +{{ 'crush' | jsdoc }} +
# Core API From 1ccc391c8e4e6ed2d8e82118be8e5bde94832489 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 15:32:36 +0200 Subject: [PATCH 28/61] proper disconnect onend --- packages/webaudio/webaudio.mjs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index bcba7ef0..b1568ea7 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -305,10 +305,8 @@ Pattern.prototype.out = function () { chain.push(ac.destination); // connect chain elements together chain.slice(1).reduce((last, current) => last.connect(current), chain[0]); - // disconnect all nodes when hap is over to make sure they are garbage collected - /* setTimeout(() => { - chain.forEach((n) => n.disconnect()); - }, (hapDuration + release + 0.1) * 1000); */ + // disconnect all nodes when source node has ended: + chain[0].onended = () => chain.forEach((n) => n.disconnect()); } catch (e) { console.warn('.out error:', e); } From 762a17d949c3f30365a3d8e4b0bd80a7b8daec0f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 15:42:34 +0200 Subject: [PATCH 29/61] fix: remove TLA --- tutorial/MiniRepl.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial/MiniRepl.jsx b/tutorial/MiniRepl.jsx index 56387190..e46e35bc 100644 --- a/tutorial/MiniRepl.jsx +++ b/tutorial/MiniRepl.jsx @@ -12,7 +12,7 @@ export const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone. }, }); -await fetch('https://strudel.tidalcycles.org/EmuSP12.json') +fetch('https://strudel.tidalcycles.org/EmuSP12.json') .then((res) => res.json()) .then((json) => samples(json, 'https://strudel.tidalcycles.org/EmuSP12/')); From dd69e4caff4dc4a8d4a3fbce06ed9fb40a9d3588 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 21:03:58 +0200 Subject: [PATCH 30/61] doc: rand irand perlin --- packages/core/signal.mjs | 32 +++++++++++++++++++++++++++++++- tutorial/tutorial.mdx | 6 ++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 9a4b5fe5..f7c33152 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -111,7 +111,17 @@ const timeToRandsPrime = (seed, n) => { const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n); /** - * A continuous pattern of random numbers, between 0 and 1 + * + */ + +/** + * A continuous pattern of random numbers, between 0 and 1. + * + * @name rand + * @example + * // randomly change the cutoff + * s("bd sd,hh*4").cutoff(rand.range(500,2000)).out() + * */ export const rand = signal(timeToRand); /** @@ -124,6 +134,17 @@ export const brandBy = (pPat) => reify(pPat).fmap(_brandBy).innerJoin(); export const brand = _brandBy(0.5); export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i)); + +/** + * A continuous pattern of random integers, between 0 and n-1. + * + * @name irand + * @param {number} n max value (exclusive) + * @example + * // randomly select scale notes from 0 - 7 (= C to C) + * irand(8).struct("x(3,8)").scale('C minor').note().out() + * + */ export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin(); export const __chooseWith = (pat, xs) => { @@ -225,6 +246,15 @@ export const perlinWith = (pat) => { return pat.sub(pata).fmap(interp).appBoth(pata.fmap(timeToRand)).appBoth(patb.fmap(timeToRand)); }; +/** + * Generates a continuous pattern of [perlin noise](https://en.wikipedia.org/wiki/Perlin_noise), in the range 0..1. + * + * @name perlin + * @example + * // randomly change the cutoff + * s("bd sd,hh*4").cutoff(perlin.range(500,2000)).out() + * + */ export const perlin = perlinWith(time); Pattern.prototype._degradeByWith = function (withPat, x) { diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 23fbbc2d..4b4eecd8 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -678,6 +678,12 @@ These methods add random behavior to your Patterns. {{ 'Pattern.always' | jsdoc }} +{{ 'rand' | jsdoc }} + +{{ 'perlin' | jsdoc }} + +{{ 'irand' | jsdoc }} + ## Tone API To make the sounds more interesting, we can use Tone.js instruments ands effects. From b38b16f70eb0ad0e2e9d8b5b8aab19f6ad7e2644 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 21:45:39 +0200 Subject: [PATCH 31/61] doc: early, late, each, every, rev + doc structure --- packages/core/pattern.mjs | 83 +++++++++++++++++++++++++--- tutorial/tutorial.mdx | 110 ++++++++++++++------------------------ 2 files changed, 117 insertions(+), 76 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 48e52643..d9b63d14 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -734,14 +734,14 @@ export class Pattern { } /** - * Speed up a pattern by the given factor. + * Speed up a pattern by the given factor. Used by "*" in mini notation. * * @name fast * @memberof Pattern * @param {number | Pattern} factor speed up factor * @returns Pattern * @example - * seq(e5, b4, d5, c5).fast(2) + * seq(e5, b4, d5, c5).fast(2) // "[e5 b4 d5 c5]*2" */ _fast(factor) { const fastQuery = this.withQueryTime((t) => t.mul(factor)); @@ -749,14 +749,14 @@ export class Pattern { } /** - * Slow down a pattern over the given number of cycles. + * Slow down a pattern over the given number of cycles. Like the "/" operator in mini notation. * * @name slow * @memberof Pattern * @param {number | Pattern} factor slow down factor * @returns Pattern * @example - * seq(e5, b4, d5, c5).slow(2) + * seq(e5, b4, d5, c5).slow(2) // "[e5 b4 d5 c5]/2" */ _slow(factor) { return this._fast(Fraction(1).div(factor)); @@ -795,14 +795,32 @@ export class Pattern { return this._fast(cpm / 60); } + /** + * Nudge a pattern to start earlier in time. Equivalent of Tidal's <~ operator + * + * @name early + * @memberof Pattern + * @param {number | Pattern} cycles number of cycles to nudge left + * @returns Pattern + * @example + * "bd ~".stack("hh ~".early(.1)).s().out() + */ _early(offset) { - // Equivalent of Tidal's <~ operator offset = Fraction(offset); return this.withQueryTime((t) => t.add(offset)).withHapTime((t) => t.sub(offset)); } + /** + * Nudge a pattern to start later in time. Equivalent of Tidal's ~> operator + * + * @name late + * @memberof Pattern + * @param {number | Pattern} cycles number of cycles to nudge right + * @returns Pattern + * @example + * "bd ~".stack("hh ~".late(.1)).s().out() + */ _late(offset) { - // Equivalent of Tidal's ~> operator offset = Fraction(offset); return this._early(Fraction(0).sub(offset)); } @@ -889,12 +907,56 @@ export class Pattern { return stack(this, func(this.late(time_pat))); } + /** + * Applies the given function every n cycles. + * @name every + * @memberof Pattern + * @param {number} n how many cycles + * @param {function} func function to apply + * @returns Pattern + * @example + * note("c3 d3 e3 g3").every(4, x=>x.rev()).out() + */ + every(n, func) { + const pat = this; + const pats = Array(n - 1).fill(pat); + // pats.unshift(func(pat)); + pats.push(func(pat)); + return slowcatPrime(...pats); + } + /** + * Applies the given function every n cycles, starting from the first cycle. + * @name every + * @memberof Pattern + * @param {number} n how many cycles + * @param {function} func function to apply + * @returns Pattern + * @example + * note("c3 d3 e3 g3").every(4, x=>x.rev()).out() + */ every(n, func) { const pat = this; const pats = Array(n - 1).fill(pat); pats.unshift(func(pat)); return slowcatPrime(...pats); } + + /** + * Applies the given function every n cycles, starting from the last cycle. + * @name each + * @memberof Pattern + * @param {number} n how many cycles + * @param {function} func function to apply + * @returns Pattern + * @example + * note("c3 d3 e3 g3").every(4, x=>x.rev()).out() + */ + each(n, func) { + const pat = this; + const pats = Array(n - 1).fill(pat); + pats.push(func(pat)); + return slowcatPrime(...pats); + } /** * Returns a new pattern where every other cycle is played once, twice as @@ -906,6 +968,15 @@ export class Pattern { return this.when(slowcat(false, true), (x) => fastcat(x, silence)._late(0.25)); } + /** + * Reverse all haps in a pattern + * + * @name rev + * @memberof Pattern + * @returns Pattern + * @example + * "c3 d3 e3 g3".rev() + */ rev() { const pat = this; const query = function (state) { diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 4b4eecd8..dc963734 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -491,59 +491,72 @@ We can write the same with **stack** and **cat**: You can also use the shorthand **pr** instead of **polyrhythm**. -## Pattern modifier functions +## Time Modifiers -The following functions modify a pattern. +The following functions modify a pattern temporal structure in some way. -### slow(factor) +{{ 'Pattern.slow' | jsdoc }} -Like "/" in mini notation, **slow** will slow down a pattern over the given number of cycles: +{{ 'Pattern.fast' | jsdoc }} - +{{ 'Pattern.early' | jsdoc }} -The same in mini notation: +{{ 'Pattern.late' | jsdoc }} - +{{ 'Pattern.rev' | jsdoc }} -### fast(factor) +### struct(binary_pat) -Like "\*" in mini notation, **fast** will play a pattern times the given number in one cycle: +Applies the given structure to the pattern: - + -### early(cycles) +This is also useful to sample signals: -With early, you can nudge a pattern to start earlier in time: + - +## Conditional Modifiers -### late(cycles) +{{ 'Pattern.every' | jsdoc }} -Like early, but in the other direction: +{{ 'Pattern.each' | jsdoc }} - +### when(binary_pat, func) - +Applies the given function whenever the given pattern is in a true state. -### rev() +/2", sub(5))`} /> -Will reverse the pattern: +## Accumulation Modifiers - +### stack(pat) -### every(n, func) +Stacks the given pattern to the current pattern: -Will apply the given function every n cycles: + - +### superimpose(...func) - +Superimposes the result of the given function(s) on top of the original pattern: -Note that late is called directly. This is a shortcut for: +".scale('C minor').superimpose(scaleTranspose("2,4"))`} /> - x.late(0.5)))`} /> +### layer(...func) - +Layers the result of the given function(s) on top of each other. Like superimpose, but the original pattern is not part of the result. + +".scale('C minor').layer(scaleTranspose("0,2,4"))`} /> + +### off(time, func) + +Applies the given function by the given time offset: + + + +## Value Modifiers ### add(n) @@ -597,55 +610,12 @@ Rounds all values to the nearest integer: -### struct(binary_pat) - -Applies the given structure to the pattern: - - - -This is also useful to sample signals: - - - -### when(binary_pat, func) - -Applies the given function whenever the given pattern is in a true state. - -/2", sub(5))`} /> - -### superimpose(...func) - -Superimposes the result of the given function(s) on top of the original pattern: - -".scale('C minor').superimpose(scaleTranspose("2,4"))`} /> - -### layer(...func) - -Layers the result of the given function(s) on top of each other. Like superimpose, but the original pattern is not part of the result. - -".scale('C minor').layer(scaleTranspose("0,2,4"))`} /> - ### apply(func) Like layer, but with a single function: ".scale('C minor').apply(scaleTranspose("0,2,4"))`} /> -### off(time, func) - -Applies the given function by the given time offset: - - - -### stack(pat) - -Stacks the given pattern to the current pattern: - - - ## Randomness These methods add random behavior to your Patterns. From 19b8f073b11202c912ce00892c74f2cefb0600eb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 22:46:30 +0200 Subject: [PATCH 32/61] dedupe most of core api doc --- packages/core/pattern.mjs | 71 +++++++++---- packages/core/signal.mjs | 2 +- tutorial/tutorial.mdx | 206 ++++++++++++++------------------------ 3 files changed, 127 insertions(+), 152 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index d9b63d14..7f5ad154 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -513,11 +513,14 @@ export class Pattern { } /** - * Assumes a numerical pattern, containing unipolar values in the range 0 .. - * 1. Returns a new pattern with values scaled to the given min/max range. - * @param {Number} min - * @param {Number} max + * Assumes a numerical pattern, containing unipolar values in the range 0 .. 1. + * Returns a new pattern with values scaled to the given min/max range. + * Most useful in combination with continuous patterns. + * @name range + * @memberof Pattern * @returns Pattern + * @example + * s("bd sd,hh*4").cutoff(sine.range(500,2000).slow(4)).out() */ range(min, max) { return this.mul(max - min).add(min); @@ -741,7 +744,7 @@ export class Pattern { * @param {number | Pattern} factor speed up factor * @returns Pattern * @example - * seq(e5, b4, d5, c5).fast(2) // "[e5 b4 d5 c5]*2" + * s(" hh").fast(2).out() // s("[ hh]*2").out() */ _fast(factor) { const fastQuery = this.withQueryTime((t) => t.mul(factor)); @@ -756,7 +759,7 @@ export class Pattern { * @param {number | Pattern} factor slow down factor * @returns Pattern * @example - * seq(e5, b4, d5, c5).slow(2) // "[e5 b4 d5 c5]/2" + * s(" hh").slow(2).out() // s("[ hh]/2").out() */ _slow(factor) { return this._fast(Fraction(1).div(factor)); @@ -847,6 +850,17 @@ export class Pattern { return this._zoom(0, t)._slow(t); } + /** + * Applies the given structure to the pattern: + * + * @name struct + * @memberof Pattern + * @returns Pattern + * @example + * "c3,eb3,g3" + * .struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~") + * .slow(4).note().out() + */ // struct(...binary_pats) { // // Re structure the pattern according to a binary pattern (false values are dropped) // const binary_pat = sequence(binary_pats); @@ -917,7 +931,7 @@ export class Pattern { * @example * note("c3 d3 e3 g3").every(4, x=>x.rev()).out() */ - every(n, func) { + every(n, func) { const pat = this; const pats = Array(n - 1).fill(pat); // pats.unshift(func(pat)); @@ -940,7 +954,7 @@ export class Pattern { pats.unshift(func(pat)); return slowcatPrime(...pats); } - + /** * Applies the given function every n cycles, starting from the last cycle. * @name each @@ -951,7 +965,7 @@ export class Pattern { * @example * note("c3 d3 e3 g3").every(4, x=>x.rev()).out() */ - each(n, func) { + each(n, func) { const pat = this; const pats = Array(n - 1).fill(pat); pats.push(func(pat)); @@ -1277,12 +1291,11 @@ Pattern.prototype.factories = { // Nothing export const silence = new Pattern((_) => []); -/** A discrete value that repeats once per cycle: +/** A discrete value that repeats once per cycle. * - * @param {any} value - The value to repeat * @returns {Pattern} * @example - * pure('e4') + * pure('e4') // "e4" */ export function pure(value) { function query(state) { @@ -1312,12 +1325,11 @@ export function reify(thing) { return pure(thing); } -/** The given items are played at the same time at the same length: +/** The given items are played at the same time at the same length. * - * @param {...any} items - The items to stack * @return {Pattern} * @example - * stack(g3, b3, [e4, d4]) + * stack(g3, b3, [e4, d4]) // "g3,b3,[e4,d4]" */ export function stack(...pats) { // Array test here is to avoid infinite recursions.. @@ -1330,7 +1342,6 @@ export function stack(...pats) { * * synonyms: {@link cat} * - * @param {...any} items - The items to concatenate * @return {Pattern} * @example * slowcat(e5, b4, [d5, c5]) @@ -1386,16 +1397,22 @@ export function fastcat(...pats) { return slowcat(...pats)._fast(pats.length); } -/** See {@link slowcat} */ +/** The given items are con**cat**enated, where each one takes one cycle. Synonym: slowcat + * + * @param {...any} items - The items to concatenate + * @return {Pattern} + * @example + * cat(e5, b4, [d5, c5]) // "" + * + */ export function cat(...pats) { return slowcat(...pats); } -/** Like {@link fastcat}, but where each step has a temporal weight: - * @param {...Array} items - The items to concatenate +/** Like {@link seq}, but each step has a length, relative to the whole. * @return {Pattern} * @example - * timeCat([3,e3],[1, g3]) + * timeCat([3,e3],[1, g3]) // "e3@3 g3" */ export function timeCat(...timepats) { const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0)); @@ -1414,7 +1431,11 @@ export function sequence(...pats) { return fastcat(...pats); } -/** See {@link fastcat} */ +/** Like **cat**, but the items are crammed into one cycle. Synonyms: fastcat, sequence + * @example + * seq(e5, b4, [d5, c5]) // "e5 b4 [d5 c5]" + * + */ export function seq(...pats) { return fastcat(...pats); } @@ -1463,6 +1484,14 @@ export function pm(...args) { polymeter(...args); } +/* + * Plays the given items at the same time, within the same length: + * @param {...any} items - The items to play + * @return {Pattern} + * @example + * + * + */ export function polyrhythm(...xs) { const seqs = xs.map((a) => sequence(a)); diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index f7c33152..8637c30e 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -74,7 +74,7 @@ export const square2 = square._toBipolar(); * * @return {Pattern} * @example - * triangle.segment(2).range(0,7).scale('C minor') + * tri.segment(8).range(0,7).scale('C minor') * */ export const tri = fastcat(isaw, saw); diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index dc963734..46da410f 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -413,65 +413,21 @@ The above is the same as: Using strings, you can also use "#". -## Functions that create Patterns +## Pattern Factories -The following functions will return a pattern. We will see later what that means. +The following functions will return a pattern. -## pure(value) - -To create a pattern from a value, you can wrap the value in pure: - - +{{ 'pure' | jsdoc }} Most of the time, you won't need that function as input values of pattern creating functions are purified by default. -### cat(...values) +{{ 'cat' | jsdoc }} -The given items are con**cat**enated, where each one takes one cycle: +{{ 'seq' | jsdoc }} - +{{ 'stack' | jsdoc }} -- Square brackets will create a subsequence -- The function **slowcat** does the same as **cat**. - -### seq(...values) - -Like **cat**, but the items are crammed into one cycle: - - - -- Synonyms: **fastcat**, **sequence** - -### stack(...values) - -The given items are played at the same time at the same length: - - - -- Square Brackets will create a subsequence - -### Nesting functions - -You can nest functions inside one another: - - - -The above is equivalent to - -"`} /> - -### timeCat(...[weight,value]) - -Like with "@" in mini notation, we can specify weights to the items in a sequence: - - +{{ 'timeCat' | jsdoc }} + + +## Combining Patterns + +You can freely mix JS patterns, mini patterns and values! For example, this pattern: + + + +...is equivalent to: + + + +... as well as: + +"`} /> + +While mini notation is almost always shorter, it only has a handful of modifiers: \* / ! @. +When using JS patterns, there is a lot more you can do. + ## Time Modifiers The following functions modify a pattern temporal structure in some way. @@ -505,18 +498,9 @@ The following functions modify a pattern temporal structure in some way. {{ 'Pattern.rev' | jsdoc }} -### struct(binary_pat) +{{ 'Pattern.struct' | jsdoc }} -Applies the given structure to the pattern: - - - -This is also useful to sample signals: - - +{{ 'Pattern.legato' | jsdoc }} ## Conditional Modifiers @@ -616,7 +600,36 @@ Like layer, but with a single function: ".scale('C minor').apply(scaleTranspose("0,2,4"))`} /> -## Randomness +{{ 'Pattern.range' | jsdoc }} + +## Continuous Signals + +Signals are patterns with continuous values, meaning they have theoretically infinite steps. +They can provide streams of numbers that can be sampled at discrete points in time. + +## + +{{ 'saw' | jsdoc }} + +{{ 'sine' | jsdoc }} + +{{ 'cosine' | jsdoc }} + +{{ 'tri' | jsdoc }} + +{{ 'square' | jsdoc }} + +### Ranges from -1 to 1 + +There is also `saw2`, `sine2`, `cosine2`, `tri2` and `square2` which have a range from -1 to 1! + +{{ 'rand' | jsdoc }} + +{{ 'perlin' | jsdoc }} + +{{ 'irand' | jsdoc }} + +## Random Modifiers These methods add random behavior to your Patterns. @@ -648,12 +661,6 @@ These methods add random behavior to your Patterns. {{ 'Pattern.always' | jsdoc }} -{{ 'rand' | jsdoc }} - -{{ 'perlin' | jsdoc }} - -{{ 'irand' | jsdoc }} - ## Tone API To make the sounds more interesting, we can use Tone.js instruments ands effects. @@ -903,67 +910,6 @@ If you want to contribute in another way, either

-# API Docs - -The following is generated from the source documentation. - -## Pattern Factories - -The following functions will return a pattern. We will see later what that means. - -{{ 'pure' | jsdoc }} - -{{ 'slowcat' | jsdoc }} - -{{ 'fastcat' | jsdoc }} - -{{ 'stack' | jsdoc }} - -{{ 'timeCat' | jsdoc }} - -{{ 'polyrhythm' | jsdoc }} - -## Pattern Modifiers - -{{ 'Pattern.slow' | jsdoc }} - -{{ 'Pattern.fast' | jsdoc }} - -{{ 'Pattern.early' | jsdoc }} - -{{ 'Pattern.late' | jsdoc }} - -{{ 'Pattern.rev' | jsdoc }} - -{{ 'Pattern.legato' | jsdoc }} - -## Continuous Signals - -Signals are patterns with continuous values, meaning they have theoretically infinite steps. -They can provide streams of numbers that can be sampled at discrete points in time. - -{{ 'Pattern.range' | jsdoc }} - -{{ 'saw' | jsdoc }} - -{{ 'saw2' | jsdoc }} - -{{ 'sine' | jsdoc }} - -{{ 'sine2' | jsdoc }} - -{{ 'cosine' | jsdoc }} - -{{ 'cosine2' | jsdoc }} - -{{ 'tri' | jsdoc }} - -{{ 'tri2' | jsdoc }} - -{{ 'square' | jsdoc }} - -{{ 'square2' | jsdoc }} - ## Using Samples with Webdirt You can use the powerful sampling engine [Webdirt](https://github.com/dktr0/WebDirt) with Strudel. From dfd33bab8e2191858b333644158359769f222ff4 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 23:16:13 +0200 Subject: [PATCH 33/61] dedupe accumulation modifiers --- packages/core/pattern.mjs | 68 ++++++++++++++++++++++++++++++++++++++- tutorial/tutorial.mdx | 30 +++++------------ 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 7f5ad154..d4d928ba 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -686,6 +686,16 @@ export class Pattern { return func(this); } + /** + * Layers the result of the given function(s). Like {@link superimpose}, but without the original pattern: + * @name layer + * @memberof Pattern + * @returns Pattern + * @example + * "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*4" + * .layer(x=>x.add("0,2")) + * .scale('C minor').note().out() + */ layer(...funcs) { return stack(...funcs.map((func) => func(this))); } @@ -908,6 +918,16 @@ export class Pattern { return this.invert(); } + /** + * Applies the given function whenever the given pattern is in a true state. + * @name when + * @memberof Pattern + * @param {Pattern} binary_pat + * @param {function} func + * @returns Pattern + * @example + * "c3 eb3 g3".when("<0 1>/2", x=>x.sub(5)) + */ when(binary_pat, func) { //binary_pat = sequence(binary_pat) const true_pat = binary_pat._filterValues(id); @@ -917,6 +937,16 @@ export class Pattern { return stack(with_pat, without_pat); } + /** + * Superimposes the function result on top of the original pattern, delayed by the given time. + * @name off + * @memberof Pattern + * @param {Pattern | number} time offset time + * @param {function} func function to apply + * @returns Pattern + * @example + * "c3 eb3 g3".off(1/8, x=>x.add(7)) + */ off(time_pat, func) { return stack(this, func(this.late(time_pat))); } @@ -1033,6 +1063,15 @@ export class Pattern { return this.juxBy(1, func); } + /** + * Stacks the given pattern(s) to the current pattern. + * @name stack + * @memberof Pattern + * @example + * s("hh*2").stack( + * n("c2(3,8)") + * ).out() + */ stack(...pats) { return stack(this, ...pats); } @@ -1041,11 +1080,28 @@ export class Pattern { return sequence(this, ...pats); } - // shorthand for sequence + /** + * Appends the given pattern(s) to the current pattern. Synonyms: .sequence .fastcat + * @name seq + * @memberof Pattern + * @example + * s("hh*2").seq( + * n("c2(3,8)") + * ).out() + */ seq(...pats) { return sequence(this, ...pats); } + /** + * Appends the given pattern(s) to the next cycle. Synonym: .slowcat + * @name cat + * @memberof Pattern + * @example + * s("hh*2").cat( + * n("c2(3,8)") + * ).out() + */ cat(...pats) { return cat(this, ...pats); } @@ -1058,6 +1114,16 @@ export class Pattern { return slowcat(this, ...pats); } + /** + * Superimposes the result of the given function(s) on top of the original pattern: + * @name superimpose + * @memberof Pattern + * @returns Pattern + * @example + * "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*4" + * .superimpose(x=>x.add(2)) + * .scale('C minor').note().out() + */ superimpose(...funcs) { return this.stack(...funcs.map((func) => func(this))); } diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 46da410f..134ea978 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -508,37 +508,23 @@ The following functions modify a pattern temporal structure in some way. {{ 'Pattern.each' | jsdoc }} -### when(binary_pat, func) - -Applies the given function whenever the given pattern is in a true state. - -/2", sub(5))`} /> +{{ 'Pattern.when' | jsdoc }} ## Accumulation Modifiers -### stack(pat) +{{ 'Pattern.stack' | jsdoc }} -Stacks the given pattern to the current pattern: +{{ 'Pattern.superimpose' | jsdoc }} - +{{ 'Pattern.layer' | jsdoc }} -### superimpose(...func) +{{ 'Pattern.off' | jsdoc }} -Superimposes the result of the given function(s) on top of the original pattern: +## Concat Modifiers -".scale('C minor').superimpose(scaleTranspose("2,4"))`} /> +{{ 'Pattern.seq' | jsdoc }} -### layer(...func) - -Layers the result of the given function(s) on top of each other. Like superimpose, but the original pattern is not part of the result. - -".scale('C minor').layer(scaleTranspose("0,2,4"))`} /> - -### off(time, func) - -Applies the given function by the given time offset: - - +{{ 'Pattern.cat' | jsdoc }} ## Value Modifiers From e4913dfb737b604803e43f07e027f726b37b6e3f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 23:35:35 +0200 Subject: [PATCH 34/61] mark tone + webdirt deprecated + add superdirt param list --- tutorial/tutorial.mdx | 426 ++++++++++++++++++------------------------ 1 file changed, 178 insertions(+), 248 deletions(-) diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 134ea978..09990cc2 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -647,11 +647,186 @@ These methods add random behavior to your Patterns. {{ 'Pattern.always' | jsdoc }} -## Tone API +# Tonal API -To make the sounds more interesting, we can use Tone.js instruments ands effects. +The Tonal API, uses [tonaljs](https://github.com/tonaljs/tonal) to provide helpers for musical operations. -[Show Source on Github](https://github.com/tidalcycles/strudel/blob/main/repl/src/tone.ts) +### transpose(semitones) + +Transposes all notes to the given number of semitones: + +".slow(2)).transpose(0)`} /> + +This method gets really exciting when we use it with a pattern as above. + +Instead of numbers, scientific interval notation can be used as well: + +".slow(2)).transpose(1)`} /> + +### scale(name) + +Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like scaleTranpose. + + + +Note that the scale root is octaved here. You can also omit the octave, then index zero will default to octave 3. + +All the available scale names can be found [here](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts). + +### scaleTranspose(steps) + +Transposes notes inside the scale by the number of steps: + +")`} +/> + +### voicings(range?) + +Turns chord symbols into voicings, using the smoothest voice leading possible: + +".voicings(), "")`} /> + + + +### rootNotes(octave = 2) + +Turns chord symbols into root notes of chords in given octave. + +".rootNotes(3)`} /> + +Together with layer, struct and voicings, this can be used to create a basic backing track: + +".layer( + x => x.voicings(['d3','g4']).struct("~ x"), + x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out())) +)`} +/> + + + + +## Microtonal API + +TODO + +## MIDI API + +Strudel also supports midi via [webmidi](https://npmjs.com/package/webmidi). + +### midi(outputName?) + +Make sure to have a midi device connected or to use an IAC Driver. +If no outputName is given, it uses the first midi output it finds. + +Midi is currently not supported by the mini repl used here, but you can [open the midi example in the repl](https://strudel.tidalcycles.org/#c3RhY2soIjxDXjcgQTcgRG03IEc3PiIubS52b2ljaW5ncygpLCAnPEMzIEEyIEQzIEcyPicubSkKICAubWlkaSgp). + +In the REPL, you will se a log of the available MIDI devices. + + + +# Superdirt API + +In mainline tidal, the actual sound is generated via Superdirt, which runs inside Supercollider. +Strudel also supports using Superdirt as a backend, although it requires some developer tooling to run. + +## Prequisites + +Getting Superdirt to work with Strudel, you need to + +1. install SuperCollider + sc3 plugins, see [Tidal Docs](https://tidalcycles.org/docs/) (Install Tidal) for more info. +2. install [node.js](https://nodejs.org/en/) +3. download [Strudel Repo](https://github.com/tidalcycles/strudel/) (or git clone, if you have git installed) +4. run `npm i` in the strudel directory +5. run `npm run osc` to start the osc server, which forwards OSC messages from Strudel REPL to SuperCollider + +Now you're all set! + +## Usage + +1. Start SuperCollider, either using SuperCollider IDE or by running `sclang` in a terminal +2. Open the [Strudel REPL](https://strudel.tidalcycles.org/#cygiYmQgc2QiKS5vc2MoKQ%3D%3D) + +...or test it here: + + + +If you now hear sound, congratulations! If not, you can get help on the [#strudel channel in the TidalCycles discord](https://discord.com/invite/HGEdXmRkzT). + +{{ 'Pattern.osc' | jsdoc }} + +## Superdirt Params + +The following functions can be used with superdirt: + +- s +- n +- freq +- channel +- orbit +- cutoff +- resonance +- hcutoff +- hresonance +- bandf +- bandq +- djf +- vowelSa +- cut +- begin +- end +- loop +- fadeTime +- speed +- unitA +- gain +- amp +- accelerate +- crush +- coarse +- delay +- lock +- leslie +- lrate +- lsize +- pan +- panspan +- pansplay +- room +- size +- dry +- shape +- squiz +- waveloss +- attack +- decayS +- octave +- detune +- tremolodepth + +Please refer to [Tidal Docs](https://tidalcycles.org/) for more info. + +# Webdirt API (deprecated) + +You can use the powerful sampling engine [Webdirt](https://github.com/dktr0/WebDirt) with Strudel. + +{{ 'Pattern.webdirt' | jsdoc }} + +
+
+ +# Tone API (deprecated) + +The Tone API uses Tone.js instruments ands effects to create sounds. - -## Tonal API - -The Tonal API, uses [tonaljs](https://github.com/tonaljs/tonal) to provide helpers for musical operations. - -### transpose(semitones) - -Transposes all notes to the given number of semitones: - -".slow(2)).transpose(0)`} /> - -This method gets really exciting when we use it with a pattern as above. - -Instead of numbers, scientific interval notation can be used as well: - -".slow(2)).transpose(1)`} /> - -### scale(name) - -Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like scaleTranpose. - - - -Note that the scale root is octaved here. You can also omit the octave, then index zero will default to octave 3. - -All the available scale names can be found [here](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts). - -### scaleTranspose(steps) - -Transposes notes inside the scale by the number of steps: - -")`} -/> - -### voicings(range?) - -Turns chord symbols into voicings, using the smoothest voice leading possible: - -".voicings(), "")`} /> - - - -### rootNotes(octave = 2) - -Turns chord symbols into root notes of chords in given octave. - -".rootNotes(3)`} /> - -Together with layer, struct and voicings, this can be used to create a basic backing track: - -".layer( - x => x.voicings(['d3','g4']).struct("~ x"), - x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out())) -)`} -/> - - - - -## Microtonal API - -TODO - -## MIDI API - -Strudel also supports midi via [webmidi](https://npmjs.com/package/webmidi). - -### midi(outputName?) - -Make sure to have a midi device connected or to use an IAC Driver. -If no outputName is given, it uses the first midi output it finds. - -Midi is currently not supported by the mini repl used here, but you can [open the midi example in the repl](https://strudel.tidalcycles.org/#c3RhY2soIjxDXjcgQTcgRG03IEc3PiIubS52b2ljaW5ncygpLCAnPEMzIEEyIEQzIEcyPicubSkKICAubWlkaSgp). - -In the REPL, you will se a log of the available MIDI devices. - - - -# Contributing - -Contributions of any sort are very welcome! You can contribute by editing [this file](https://github.com/tidalcycles/strudel/blob/main/repl/src/tutorial/tutorial.mdx). -All you need is a github account. - -If you want to run the tutorial locally, you can clone the and run: - -```sh -cd repl && npm i && npm run tutorial -``` - -If you want to contribute in another way, either - -- [fork strudel repo on GitHub](https://github.com/tidalcycles/strudel) -- [Join the Discord Channel](https://discord.gg/remJ6gQA) -- [play with the Strudel REPL](https://strudel.tidalcycles.org/) - -
-
- -## Using Samples with Webdirt - -You can use the powerful sampling engine [Webdirt](https://github.com/dktr0/WebDirt) with Strudel. - -{{ 'Pattern.webdirt' | jsdoc }} - -## Using Superdirt via OSC - -In mainline tidal, the actual sound is generated via Superdirt, which runs inside Supercollider. -Strudel also supports using Superdirt as a backend, although it requires some developer tooling to run. - -### Getting Started - -Getting Superdirt to work with Strudel, you need to - -1. install SuperCollider + sc3 plugins, see [Tidal Docs](https://tidalcycles.org/docs/) (Install Tidal) for more info. -2. install [node.js](https://nodejs.org/en/) -3. download [Strudel Repo](https://github.com/tidalcycles/strudel/) (or git clone, if you have git installed) -4. run `npm i` in the strudel directory -5. run `npm run osc` to start the osc server, which forwards OSC messages from Strudel REPL to SuperCollider - -Now you're all set! - -### Usage - -1. Start SuperCollider, either using SuperCollider IDE or by running `sclang` in a terminal -2. Open the [Strudel REPL](https://strudel.tidalcycles.org/#cygiYmQgc2QiKS5vc2MoKQ%3D%3D) - -...or test it here: - - - -If you now hear sound, congratulations! If not, you can get help on the [#strudel channel in the TidalCycles discord](https://discord.com/invite/HGEdXmRkzT). - -{{ 'Pattern.osc' | jsdoc }} - -# Superdirt Params - -The following functions are specific to SuperDirt and won't work with other Strudel outputs. - -## Basic Types - -{{ 's' | jsdoc }} - -{{ 'n' | jsdoc }} - -{{ 'freq' | jsdoc }} - -{{ 'channel' | jsdoc }} - -{{ 'orbit' | jsdoc }} - -## Filters - -{{ 'cutoff' | jsdoc }} - -{{ 'resonance' | jsdoc }} - -{{ 'hcutoff' | jsdoc }} - -{{ 'hresonance' | jsdoc }} - -{{ 'bandf' | jsdoc }} - -{{ 'bandq' | jsdoc }} - -{{ 'djf' | jsdoc }} - -{{ 'vowel' | jsdoc }} - -## Sample Editing - -{{ 'cut' | jsdoc }} - -{{ 'begin' | jsdoc }} - -{{ 'end' | jsdoc }} - -{{ 'loop' | jsdoc }} - -{{ 'fadeTime' | jsdoc }} - -{{ 'speed' | jsdoc }} - -{{ 'unit' | jsdoc }} - -## Audio Effects - -{{ 'gain' | jsdoc }} - -{{ 'amp' | jsdoc }} - -{{ 'accelerate' | jsdoc }} - -{{ 'crush' | jsdoc }} - -{{ 'coarse' | jsdoc }} - -{{ 'delay' | jsdoc }} - -{{ 'lock' | jsdoc }} - -{{ 'leslie' | jsdoc }} - -{{ 'lrate' | jsdoc }} - -{{ 'lsize' | jsdoc }} - -{{ 'pan' | jsdoc }} - -{{ 'panspan' | jsdoc }} - -{{ 'pansplay' | jsdoc }} - -{{ 'room' | jsdoc }} - -{{ 'size' | jsdoc }} - -{{ 'dry' | jsdoc }} - -{{ 'shape' | jsdoc }} - -{{ 'squiz' | jsdoc }} - -{{ 'waveloss' | jsdoc }} - -{{ 'attack' | jsdoc }} - -{{ 'decay' | jsdoc }} - -## Synth Effects - -{{ 'octave' | jsdoc }} - -{{ 'detune' | jsdoc }} - -{{ 'tremolodepth' | jsdoc }} From c786d77b07aaea0d09c97ee79e37e40597324ae3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 23:38:42 +0200 Subject: [PATCH 35/61] make polyrhythm alias of stack #211 --- packages/core/pattern.mjs | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index d4d928ba..29ec0695 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -1404,6 +1404,10 @@ export function stack(...pats) { return new Pattern(query); } +// aliases +const polyrhythm = stack; +const pr = stack; + /** Concatenation: combines a list of patterns, switching between them successively, one per cycle: * * synonyms: {@link cat} @@ -1550,28 +1554,6 @@ export function pm(...args) { polymeter(...args); } -/* - * Plays the given items at the same time, within the same length: - * @param {...any} items - The items to play - * @return {Pattern} - * @example - * - * - */ -export function polyrhythm(...xs) { - const seqs = xs.map((a) => sequence(a)); - - if (seqs.length == 0) { - return silence; - } - return stack(...seqs); -} - -// alias -export function pr(args) { - polyrhythm(args); -} - export const add = curry((a, pat) => pat.add(a)); export const chop = curry((a, pat) => pat.chop(a)); export const chunk = curry((a, pat) => pat.chunk(a)); From a14c7233d45e7287017bc628e72cbfa2c143980c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 23:40:56 +0200 Subject: [PATCH 36/61] fix: tests --- packages/core/pattern.mjs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 29ec0695..9ff616cf 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -1335,6 +1335,11 @@ Pattern.prototype.patternified = [ 'slow', 'velocity', ]; + +// aliases +export const polyrhythm = stack; +export const pr = stack; + // methods that create patterns, which are added to patternified Pattern methods Pattern.prototype.factories = { pure, @@ -1404,10 +1409,6 @@ export function stack(...pats) { return new Pattern(query); } -// aliases -const polyrhythm = stack; -const pr = stack; - /** Concatenation: combines a list of patterns, switching between them successively, one per cycle: * * synonyms: {@link cat} From fdc4bb455fa59165e3b295322caa637a596efa9e Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 23:54:28 +0200 Subject: [PATCH 37/61] fix: formatting --- tutorial/tutorial.mdx | 55 ++++++------------------------------------- 1 file changed, 7 insertions(+), 48 deletions(-) diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 09990cc2..48db137a 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -647,6 +647,9 @@ These methods add random behavior to your Patterns. {{ 'Pattern.always' | jsdoc }} +
+
+ # Tonal API The Tonal API, uses [tonaljs](https://github.com/tonaljs/tonal) to provide helpers for musical operations. @@ -712,11 +715,10 @@ Together with layer, struct and voicings, this can be used to create a basic bac -## Microtonal API +
+
-TODO - -## MIDI API +# MIDI API Strudel also supports midi via [webmidi](https://npmjs.com/package/webmidi). @@ -768,50 +770,7 @@ If you now hear sound, congratulations! If not, you can get help on the [#strude The following functions can be used with superdirt: -- s -- n -- freq -- channel -- orbit -- cutoff -- resonance -- hcutoff -- hresonance -- bandf -- bandq -- djf -- vowelSa -- cut -- begin -- end -- loop -- fadeTime -- speed -- unitA -- gain -- amp -- accelerate -- crush -- coarse -- delay -- lock -- leslie -- lrate -- lsize -- pan -- panspan -- pansplay -- room -- size -- dry -- shape -- squiz -- waveloss -- attack -- decayS -- octave -- detune -- tremolodepth +`s n note freq channel orbit cutoff resonance hcutoff hresonance bandf bandq djf vowel cut begin end loop fadeTime speed unitA gain amp accelerate crush coarse delay lock leslie lrate lsize pan panspan pansplay room size dry shape squiz waveloss attack decay octave detune tremolodepth` Please refer to [Tidal Docs](https://tidalcycles.org/) for more info. From 505cc01a18a48d295656c8e13575143a11256ea5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 17 Sep 2022 23:59:16 +0200 Subject: [PATCH 38/61] remove empty heading --- tutorial/tutorial.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 48db137a..6eaf1d58 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -593,8 +593,6 @@ Like layer, but with a single function: Signals are patterns with continuous values, meaning they have theoretically infinite steps. They can provide streams of numbers that can be sampled at discrete points in time. -## - {{ 'saw' | jsdoc }} {{ 'sine' | jsdoc }} From 6d3d9659e2f19d8f26a9de4e66f9270aa9651978 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 19 Sep 2022 21:48:47 +0200 Subject: [PATCH 39/61] try build workflow --- .github/workflows/build.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..1eb9ed15 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,15 @@ +name: Strudel Build + +on: [workflow_dispatch] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v3 + with: + node-version: 16 + cache: "npm" + - run: npm install + - run: npm run build From 6c363d9c4b0dfe1b96352dcd2b57029a47d65fed Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 19 Sep 2022 21:50:38 +0200 Subject: [PATCH 40/61] add rollup-plugin-visualizer in root pkg --- package-lock.json | 267 ++++++++++++++++++++++++++++++++++++++++++---- package.json | 1 + 2 files changed, 248 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 04b7cca7..494751aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "jsdoc-json": "^2.0.2", "jsdoc-to-markdown": "^7.1.1", "lerna": "^4.0.0", + "rollup-plugin-visualizer": "^5.8.1", "vitest": "^0.21.1" } }, @@ -4256,6 +4257,15 @@ "clone": "^1.0.2" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -6506,6 +6516,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -6722,6 +6747,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -7998,6 +8035,18 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -8575,6 +8624,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -9178,18 +9244,6 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -9941,6 +9995,91 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup-plugin-visualizer": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.8.1.tgz", + "integrity": "sha512-NBT/xN/LWCwDM2/j5vYmjzpEAKHyclo/8Cv8AfTCwgADAG+tLJDy1vzxMw6NO0dSDjmTeRELD9UU3FwknLv0GQ==", + "dev": true, + "dependencies": { + "nanoid": "^3.3.4", + "open": "^8.4.0", + "source-map": "^0.7.3", + "yargs": "^17.5.1" + }, + "bin": { + "rollup-plugin-visualizer": "dist/bin/cli.js" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "rollup": "^2.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/rollup-plugin-visualizer/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup-plugin-visualizer/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/rollup-plugin-visualizer/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup-plugin-visualizer/node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/rollup-plugin-visualizer/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -15950,6 +16089,12 @@ "clone": "^1.0.2" } }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -17575,6 +17720,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -17725,6 +17876,15 @@ "call-bind": "^1.0.2" } }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -18733,6 +18893,12 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -19176,6 +19342,17 @@ "mimic-fn": "^2.1.0" } }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -19551,14 +19728,6 @@ "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" - }, - "dependencies": { - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true - } } }, "postcss-js": { @@ -20263,6 +20432,64 @@ "fsevents": "~2.3.2" } }, + "rollup-plugin-visualizer": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.8.1.tgz", + "integrity": "sha512-NBT/xN/LWCwDM2/j5vYmjzpEAKHyclo/8Cv8AfTCwgADAG+tLJDy1vzxMw6NO0dSDjmTeRELD9UU3FwknLv0GQ==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "open": "^8.4.0", + "source-map": "^0.7.3", + "yargs": "^17.5.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", diff --git a/package.json b/package.json index dc23a45c..97f26247 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "jsdoc-json": "^2.0.2", "jsdoc-to-markdown": "^7.1.1", "lerna": "^4.0.0", + "rollup-plugin-visualizer": "^5.8.1", "vitest": "^0.21.1" } } From 88d12223a52f3b7c3d1451dc72b96c5ba687150d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 19 Sep 2022 21:52:31 +0200 Subject: [PATCH 41/61] build: add npm i in repl folder --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1eb9ed15..7c8f8b8b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,5 +11,5 @@ jobs: with: node-version: 16 cache: "npm" - - run: npm install + - run: npm install && cd repl && npm install - run: npm run build From 8ab912429bbf4d2c82846f8286b71ec82d1d7527 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 19 Sep 2022 21:54:34 +0200 Subject: [PATCH 42/61] build: npm i inside tutorial --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c8f8b8b..7df3b881 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,5 +11,5 @@ jobs: with: node-version: 16 cache: "npm" - - run: npm install && cd repl && npm install + - run: npm ci && cd repl && npm ci && cd ../tutorial && npm ci - run: npm run build From 1da005e811a1079dd17fba55982d58b6a088873e Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 19 Sep 2022 21:58:12 +0200 Subject: [PATCH 43/61] deploy after build --- .github/workflows/{build.yml => delpoy.yml} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename .github/workflows/{build.yml => delpoy.yml} (86%) diff --git a/.github/workflows/build.yml b/.github/workflows/delpoy.yml similarity index 86% rename from .github/workflows/build.yml rename to .github/workflows/delpoy.yml index 7df3b881..d13d0d77 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/delpoy.yml @@ -1,4 +1,4 @@ -name: Strudel Build +name: Build & Deploy on: [workflow_dispatch] @@ -13,3 +13,4 @@ jobs: cache: "npm" - run: npm ci && cd repl && npm ci && cd ../tutorial && npm ci - run: npm run build + - run: npm run deploy From 0134a50ffafe50164d8dccf77ca4e5f4cfef13a5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 19 Sep 2022 22:09:23 +0200 Subject: [PATCH 44/61] add update button --- repl/src/App.jsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/repl/src/App.jsx b/repl/src/App.jsx index fd464d2b..ae55fc78 100644 --- a/repl/src/App.jsx +++ b/repl/src/App.jsx @@ -214,6 +214,19 @@ function App() { <>loading... )} + {!isEmbedded && (