Compare commits

..

4 Commits

Author SHA1 Message Date
Felix Roos 95ecd73d49 some notes 2022-06-16 11:48:09 +02:00
Felix Roos a9995d185f dont add location if addLocations is false 2022-06-16 11:48:00 +02:00
Felix Roos 5da2085436 count calls and log every second 2022-06-16 03:52:54 +02:00
Felix Roos ae9820b39f some testing with Fraction mock class 2022-06-16 03:17:35 +02:00
99 changed files with 4292 additions and 10146 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
[![Strudel test status](https://github.com/tidalcycles/strudel/actions/workflows/test.yml/badge.svg)](https://github.com/tidalcycles/strudel/actions)
An experiment in making a [Tidal](https://github.com/tidalcycles/tidal/) using web technologies. This software is slowly stabilising, but please continue to tread carefully.
An experiment in making a [Tidal](https://github.com/tidalcycles/tidal/) using web technologies. This is unstable software, please tread carefully.
- Try it here: <https://strudel.tidalcycles.org/>
- Tutorial: <https://strudel.tidalcycles.org/tutorial/>
+48 -274
View File
@@ -2243,10 +2243,6 @@
"resolved": "packages/serial",
"link": true
},
"node_modules/@strudel.cycles/soundfonts": {
"resolved": "packages/soundfonts",
"link": true
},
"node_modules/@strudel.cycles/tonal": {
"resolved": "packages/tonal",
"link": true
@@ -3951,15 +3947,6 @@
"node": ">=0.10"
}
},
"node_modules/data-uri-to-buffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
"dev": true,
"engines": {
"node": ">= 12"
}
},
"node_modules/dateformat": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
@@ -4968,29 +4955,6 @@
"reusify": "^1.0.4"
}
},
"node_modules/fetch-blob": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.5.tgz",
"integrity": "sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"dependencies": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
}
},
"node_modules/figures": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -5170,18 +5134,6 @@
"node": ">= 0.12"
}
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"dev": true,
"dependencies": {
"fetch-blob": "^3.1.2"
},
"engines": {
"node": ">=12.20.0"
}
},
"node_modules/fraction.js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
@@ -7067,9 +7019,9 @@
}
},
"node_modules/marked": {
"version": "4.0.17",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz",
"integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==",
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.0.14.tgz",
"integrity": "sha512-HL5sSPE/LP6U9qKgngIIPTthuxC0jrfxpYMZ3LdGDD3vTnLs59m2Z7r6+LNDR3ToqEQdkKd6YaaEfJhodJmijQ==",
"bin": {
"marked": "bin/marked.js"
},
@@ -7630,25 +7582,6 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@@ -8504,31 +8437,6 @@
"node": ">=8"
}
},
"node_modules/peggy": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/peggy/-/peggy-2.0.1.tgz",
"integrity": "sha512-mBqfmdUAOVn7RILpXTbcRBhLfTR4Go0SresSnivGDdRylBOyVFJncFiVyCNNpPWq8HmgeRleXHs/Go4o8kQVXA==",
"dev": true,
"dependencies": {
"commander": "^9.3.0",
"source-map-generator": "0.8.0"
},
"bin": {
"peggy": "bin/peggy.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/peggy/node_modules/commander": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz",
"integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==",
"dev": true,
"engines": {
"node": "^12.20.0 || >=14"
}
},
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -9926,15 +9834,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/source-map-generator": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/source-map-generator/-/source-map-generator-0.8.0.tgz",
"integrity": "sha512-psgxdGMwl5MZM9S3FWee4EgsEaIjahYV5AzGnwUvPhWeITz/j6rKpysQHlQ4USdxvINlb8lKfWGIXwfkrgtqkA==",
"dev": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@@ -10920,15 +10819,6 @@
"defaults": "^1.0.3"
}
},
"node_modules/web-streams-polyfill": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/WebDirt": {
"version": "1.0.0",
"resolved": "git+ssh://git@github.com/dktr0/WebDirt.git#425dc8fd023440d9c61ffdb8642e44e2710faea0",
@@ -11373,7 +11263,7 @@
},
"packages/core": {
"name": "@strudel.cycles/core",
"version": "0.1.2",
"version": "0.1.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"bjork": "^0.0.1",
@@ -11385,15 +11275,15 @@
},
"packages/embed": {
"name": "@strudel.cycles/embed",
"version": "0.1.1",
"version": "0.1.0",
"license": "AGPL-3.0-or-later"
},
"packages/eval": {
"name": "@strudel.cycles/eval",
"version": "0.1.3",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"estraverse": "^5.3.0",
"shift-ast": "^6.1.0",
"shift-codegen": "^7.0.3",
@@ -11417,30 +11307,27 @@
},
"packages/midi": {
"name": "@strudel.cycles/midi",
"version": "0.1.3",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/tone": "^0.1.3",
"@strudel.cycles/tone": "^0.1.1",
"tone": "^14.7.77",
"webmidi": "^2.5.2"
}
},
"packages/mini": {
"name": "@strudel.cycles/mini",
"version": "0.1.3",
"version": "0.1.1",
"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"
},
"devDependencies": {
"peggy": "^2.0.1"
"@strudel.cycles/core": "^0.1.0",
"@strudel.cycles/eval": "^0.1.1",
"@strudel.cycles/tone": "^0.1.1"
}
},
"packages/osc": {
"name": "@strudel.cycles/osc",
"version": "0.1.1",
"version": "0.1.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"osc-js": "^2.3.2"
@@ -11448,14 +11335,14 @@
},
"packages/react": {
"name": "@strudel.cycles/react",
"version": "0.1.4",
"version": "0.1.2",
"license": "AGPL-3.0-or-later",
"peer": true,
"dependencies": {
"@codemirror/lang-javascript": "^0.19.0",
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/eval": "^0.1.3",
"@strudel.cycles/tone": "^0.1.3",
"@strudel.cycles/core": "*",
"@strudel.cycles/eval": "^0.1.1",
"@strudel.cycles/tone": "^0.1.1",
"react-codemirror6": "^1.1.0",
"react-hook-inview": "^4.5.0"
},
@@ -11524,45 +11411,15 @@
},
"packages/serial": {
"name": "@strudel.cycles/serial",
"version": "0.1.3",
"version": "0.1.0",
"license": "AGPL-3.0-or-later"
},
"packages/soundfonts": {
"name": "@strudel.cycles/soundfonts",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "*",
"@strudel.cycles/webaudio": "^0.1.4"
},
"devDependencies": {
"node-fetch": "^3.2.6"
}
},
"packages/soundfonts/node_modules/node-fetch": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.6.tgz",
"integrity": "sha512-LAy/HZnLADOVkVPubaxHDft29booGglPFDr2Hw0J1AercRh01UiVFm++KMDnJeH9sHgNB4hsXPii7Sgym/sTbw==",
"dev": true,
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
}
},
"packages/tonal": {
"name": "@strudel.cycles/tonal",
"version": "0.1.3",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"@tonaljs/tonal": "^4.6.5",
"webmidi": "^3.0.15"
}
@@ -11584,10 +11441,10 @@
},
"packages/tone": {
"name": "@strudel.cycles/tone",
"version": "0.1.3",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"@tonejs/piano": "^0.2.1",
"chord-voicings": "^0.0.1",
"tone": "^14.7.77"
@@ -11595,27 +11452,27 @@
},
"packages/webaudio": {
"name": "@strudel.cycles/webaudio",
"version": "0.1.4",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.1.2"
"@strudel.cycles/core": "^0.1.0"
}
},
"packages/webdirt": {
"name": "@strudel.cycles/webdirt",
"version": "0.1.2",
"version": "0.1.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"WebDirt": "github:dktr0/WebDirt"
}
},
"packages/xen": {
"name": "@strudel.cycles/xen",
"version": "0.1.3",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.1.2"
"@strudel.cycles/core": "^0.1.0"
}
}
},
@@ -13430,7 +13287,7 @@
"@strudel.cycles/eval": {
"version": "file:packages/eval",
"requires": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"estraverse": "^5.3.0",
"shift-ast": "^6.1.0",
"shift-codegen": "^7.0.3",
@@ -13442,7 +13299,7 @@
"@strudel.cycles/midi": {
"version": "file:packages/midi",
"requires": {
"@strudel.cycles/tone": "^0.1.3",
"@strudel.cycles/tone": "^0.1.1",
"tone": "^14.7.77",
"webmidi": "^2.5.2"
}
@@ -13450,10 +13307,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",
"peggy": "^2.0.1"
"@strudel.cycles/core": "^0.1.0",
"@strudel.cycles/eval": "^0.1.1",
"@strudel.cycles/tone": "^0.1.1"
}
},
"@strudel.cycles/osc": {
@@ -13466,9 +13322,9 @@
"version": "file:packages/react",
"requires": {
"@codemirror/lang-javascript": "^0.19.0",
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/eval": "^0.1.3",
"@strudel.cycles/tone": "^0.1.3",
"@strudel.cycles/core": "*",
"@strudel.cycles/eval": "^0.1.1",
"@strudel.cycles/tone": "^0.1.1",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2",
"@vitejs/plugin-react": "^1.3.0",
@@ -13528,31 +13384,10 @@
"@strudel.cycles/serial": {
"version": "file:packages/serial"
},
"@strudel.cycles/soundfonts": {
"version": "file:packages/soundfonts",
"requires": {
"@strudel.cycles/core": "*",
"@strudel.cycles/webaudio": "^0.1.4",
"node-fetch": "^3.2.6"
},
"dependencies": {
"node-fetch": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.6.tgz",
"integrity": "sha512-LAy/HZnLADOVkVPubaxHDft29booGglPFDr2Hw0J1AercRh01UiVFm++KMDnJeH9sHgNB4hsXPii7Sgym/sTbw==",
"dev": true,
"requires": {
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
}
}
}
},
"@strudel.cycles/tonal": {
"version": "file:packages/tonal",
"requires": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"@tonaljs/tonal": "^4.6.5",
"webmidi": "^3.0.15"
},
@@ -13572,7 +13407,7 @@
"@strudel.cycles/tone": {
"version": "file:packages/tone",
"requires": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"@tonejs/piano": "^0.2.1",
"chord-voicings": "^0.0.1",
"tone": "^14.7.77"
@@ -13581,20 +13416,20 @@
"@strudel.cycles/webaudio": {
"version": "file:packages/webaudio",
"requires": {
"@strudel.cycles/core": "^0.1.2"
"@strudel.cycles/core": "^0.1.0"
}
},
"@strudel.cycles/webdirt": {
"version": "file:packages/webdirt",
"requires": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"WebDirt": "github:dktr0/WebDirt"
}
},
"@strudel.cycles/xen": {
"version": "file:packages/xen",
"requires": {
"@strudel.cycles/core": "^0.1.2"
"@strudel.cycles/core": "^0.1.0"
}
},
"@tonaljs/abc-notation": {
@@ -14973,12 +14808,6 @@
"assert-plus": "^1.0.0"
}
},
"data-uri-to-buffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
"dev": true
},
"dateformat": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
@@ -15652,16 +15481,6 @@
"reusify": "^1.0.4"
}
},
"fetch-blob": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.5.tgz",
"integrity": "sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==",
"dev": true,
"requires": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
}
},
"figures": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -15790,15 +15609,6 @@
"mime-types": "^2.1.12"
}
},
"formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"dev": true,
"requires": {
"fetch-blob": "^3.1.2"
}
},
"fraction.js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
@@ -17248,9 +17058,9 @@
"requires": {}
},
"marked": {
"version": "4.0.17",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz",
"integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA=="
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.0.14.tgz",
"integrity": "sha512-HL5sSPE/LP6U9qKgngIIPTthuxC0jrfxpYMZ3LdGDD3vTnLs59m2Z7r6+LNDR3ToqEQdkKd6YaaEfJhodJmijQ=="
},
"mdurl": {
"version": "1.0.1",
@@ -17675,12 +17485,6 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"dev": true
},
"node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@@ -18330,24 +18134,6 @@
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
},
"peggy": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/peggy/-/peggy-2.0.1.tgz",
"integrity": "sha512-mBqfmdUAOVn7RILpXTbcRBhLfTR4Go0SresSnivGDdRylBOyVFJncFiVyCNNpPWq8HmgeRleXHs/Go4o8kQVXA==",
"dev": true,
"requires": {
"commander": "^9.3.0",
"source-map-generator": "0.8.0"
},
"dependencies": {
"commander": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz",
"integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==",
"dev": true
}
}
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -18600,9 +18386,9 @@
"version": "file:packages/react",
"requires": {
"@codemirror/lang-javascript": "^0.19.0",
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/eval": "^0.1.3",
"@strudel.cycles/tone": "^0.1.3",
"@strudel.cycles/core": "*",
"@strudel.cycles/eval": "^0.1.1",
"@strudel.cycles/tone": "^0.1.1",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2",
"@vitejs/plugin-react": "^1.3.0",
@@ -19466,12 +19252,6 @@
"is-plain-obj": "^2.0.0"
}
},
"source-map-generator": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/source-map-generator/-/source-map-generator-0.8.0.tgz",
"integrity": "sha512-psgxdGMwl5MZM9S3FWee4EgsEaIjahYV5AzGnwUvPhWeITz/j6rKpysQHlQ4USdxvINlb8lKfWGIXwfkrgtqkA==",
"dev": true
},
"source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@@ -20249,12 +20029,6 @@
"defaults": "^1.0.3"
}
},
"web-streams-polyfill": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
"dev": true
},
"WebDirt": {
"version": "git+ssh://git@github.com/dktr0/WebDirt.git#425dc8fd023440d9c61ffdb8642e44e2710faea0",
"from": "WebDirt@github:dktr0/WebDirt"
+1 -3
View File
@@ -6,11 +6,9 @@
"scripts": {
"test": "npm run test --workspaces --if-present && cd repl && npm run test",
"bootstrap": "lerna bootstrap",
"setup": "npm i && npm run bootstrap && cd repl && npm i && cd ../tutorial && npm i",
"snapshot": "cd repl && npm run snapshot",
"setup": "npm i && npm run bootstrap && cd repl && npm i",
"repl": "cd repl && npm run dev",
"osc": "cd packages/osc && npm run server",
"sampler": "cd ./repl/public/samples && node ../../packages/webaudio/sample-server.js",
"build": "rm -rf out && cd repl && npm run build && cd ../tutorial && npm run build",
"preview": "npx serve ./out",
"deploy": "gh-pages -d out",
+3 -8
View File
@@ -744,30 +744,25 @@ const generic_params = [
['f', 'uid', ''],
['f', 'val', ''],
['f', 'cps', ''],
['f', 'clip', ''],
];
// TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13
const _name = (name, ...pats) => sequence(...pats).withValue((x) => ({ [name]: x }));
const _setter = (func, name) =>
const _setter = (func) =>
function (...pats) {
if (!pats.length) {
return this.fmap((value) => ({ [name]: value }));
}
return this.set(func(...pats));
};
generic_params.forEach(([type, name, description]) => {
controls[name] = (...pats) => _name(name, ...pats);
Pattern.prototype[name] = _setter(controls[name], name);
Pattern.prototype[name] = _setter(controls[name]);
});
// create custom param
controls.createParam = (name) => {
const func = (...pats) => _name(name, ...pats);
Pattern.prototype[name] = _setter(func, name);
Pattern.prototype[name] = _setter(controls[name]);
return (...pats) => _name(name, ...pats);
};
+92 -10
View File
@@ -4,9 +4,87 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Fraction from 'fraction.js';
// import Fraction from 'fraction.js';
import { TimeSpan } from './timespan.mjs';
let instances = 0;
let strings = 0;
let fractions = 0;
let numbers = 0;
setInterval(() => {
console.log(`${instances} calls = ${numbers} numbers + ${fractions} fractions + ${strings} strings`);
instances = 0;
strings = 0;
fractions = 0;
numbers = 0;
}, 1000);
// http://localhost:3000/#c3RhY2soCiAgImUzLGJiMyxkNCIuc3RydWN0KCJ4KDMsOCwtMSkiKS5vZmYoMS84LHg9PngudHJhbnNwb3NlKDEyKS52ZWxvY2l0eSguMikpLAogICJjMiIuc3RydWN0KCJ4KDQsOCwtMikiKSwKICAiYzMiLnN0cnVjdCgieCgzLDgsLTIpIi5mYXN0KDIpKQopLnNsb3coMikKIC5lY2hvKDQsLjEyNSwuOCkKIC52ZWxvY2l0eShzaW5lLnN0cnVjdCgieCo4IikuYWRkKDMvNSkubXVsKDIvNSkuZmFzdCg4KSkKIC8vIC5waWFub3JvbGwoKQovLyBzdHJ1ZGVsIGRpc2FibGUtaGlnaGxpZ2h0aW5n
// ~400k/s
// this is a "mock" for fraction.js, using just floats without any rational arithmetic
// to test if the performance gets better without fraction.js
// result: it seems to get better but not by much
// the main jankyness remains for some complicated patterns
class Fraction {
value; // number
constructor(value) {
instances++;
if (value instanceof Fraction) {
// TODO: return this?
this.value = value.value;
fractions++;
} else if (typeof value === 'string') {
const [n, d] = value.split('/');
this.value = n / (d || 1);
strings++;
} else if (typeof value !== 'number' || isNaN(value)) {
console.warn('Fraction got NaN', value);
} else {
numbers++;
this.value = Number(value);
if (isNaN(this.value)) {
console.warn('Fraction parsed NaN from', value);
}
}
}
add(other) {
return new Fraction(this.value + other);
}
sub(other) {
return new Fraction(this.value - other);
}
mul(other) {
return new Fraction(this.value * other);
}
div(other) {
return new Fraction(this.value / other);
}
toString() {
return this.value + '';
}
valueOf() {
return this.value;
}
floor() {
return new Fraction(Math.floor(this.value));
}
abs() {
return new Fraction(Math.abs(this.value));
}
inverse() {
return new Fraction(1 / this.value);
}
compare(other) {
return this.value - other;
}
equals(other) {
return this.value.valueOf() === other.valueOf();
}
// TODO: toFraction
}
// Returns the start of the cycle.
Fraction.prototype.sam = function () {
return this.floor();
@@ -14,12 +92,16 @@ Fraction.prototype.sam = function () {
// Returns the start of the next cycle.
Fraction.prototype.nextSam = function () {
// return new Fraction(Math.floor(this.value) + 1);
return this.sam().add(1);
};
// Returns a TimeSpan representing the begin and end of the Time value's cycle
Fraction.prototype.wholeCycle = function () {
return new TimeSpan(this.sam(), this.nextSam());
/* const begin = Math.floor(this.value);
const end = begin + 1;
return new TimeSpan(begin, end); */
};
// The position of a time value relative to the start of its cycle.
@@ -63,20 +145,20 @@ Fraction.prototype.or = function (other) {
return this.eq(0) ? other : this;
};
const fraction = (n) => {
/* const fraction = (n) => {
if (typeof n === 'number') {
/*
https://github.com/infusion/Fraction.js/#doubles
„If you pass a double as it is, Fraction.js will perform a number analysis based on Farey Sequences."
„If you want to keep the number as it is, convert it to a string, as the string parser will not perform any further observations“
// https://github.com/infusion/Fraction.js/#doubles
// „If you pass a double as it is, Fraction.js will perform a number analysis based on Farey Sequences."
// „If you want to keep the number as it is, convert it to a string, as the string parser will not perform any further observations“
-> those farey sequences turn out to make pattern querying ~20 times slower! always use strings!
-> still, some optimizations could be done: .mul .div .add .sub calls still use numbers
*/
// -> those farey sequences turn out to make pattern querying ~20 times slower! always use strings!
// -> still, some optimizations could be done: .mul .div .add .sub calls still use numbers
n = String(n);
}
return Fraction(n);
};
}; */
const fraction = (n) => new Fraction(n);
export const gcd = (...fractions) => {
return fractions.reduce((gcd, fraction) => gcd.gcd(fraction), fraction(1));
+2 -2
View File
@@ -6,7 +6,7 @@ This program is free software: you can redistribute it and/or modify it under th
// this is a shortcut to eval code from a gist
// why? to be able to shorten strudel code + e.g. be able to change instruments after links have been generated
export default (route, cache = true) =>
fetch(`https://gist.githubusercontent.com/${route}?cachebust=${cache ? '' : Date.now()}`)
export default (route) =>
fetch(`https://gist.githubusercontent.com/${route}?cachebust=${Date.now()}`)
.then((res) => res.text())
.then((code) => eval(code));
+5 -3
View File
@@ -86,9 +86,11 @@ export class Hap {
}
showWhole() {
return `${this.whole == undefined ? '~' : this.whole.show()}: ${
typeof this.value === 'object' ? JSON.stringify(this.value) : this.value
}`;
return `${this.whole == undefined ? '~' : this.whole.show()}: ${this.value}`;
}
showWhole() {
return `${this.whole == undefined ? '~' : this.whole.show()}: ${this.value}`;
}
combineContext(b) {
+2 -16
View File
@@ -15,19 +15,5 @@ export * from './state.mjs';
export * from './timespan.mjs';
export * from './util.mjs';
export * from './speak.mjs';
export { default as gist } from './gist.js';
// below won't work with runtime.mjs (json import fails)
/* import * as p from './package.json';
export const version = p.version; */
console.log(
'%c // 🌀 @strudel.cycles/core loaded 🌀', // keep "//" for runnable snapshot source..
'background-color: black;color:white;padding:4px;border-radius:15px',
);
if (globalThis._strudelLoaded) {
console.warn(
`@strudel.cycles/core was loaded more than once...
This might happen when you have multiple versions of strudel installed.
Please check with "npm ls @strudel.cycles/core".`,
);
}
globalThis._strudelLoaded = true;
export * as gist from './gist.js';
// export * from './value.mjs';
+3 -3
View File
@@ -1,13 +1,13 @@
{
"name": "@strudel.cycles/core",
"version": "0.1.2",
"version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@strudel.cycles/core",
"version": "0.1.0",
"license": "AGPL-3.0-or-later",
"version": "0.0.3",
"license": "GPL-3.0-or-later",
"dependencies": {
"bjork": "^0.0.1",
"fraction.js": "^4.2.0"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/core",
"version": "0.1.2",
"version": "0.1.0",
"description": "Port of Tidal Cycles to JavaScript",
"main": "index.mjs",
"type": "module",
+1 -14
View File
@@ -15,7 +15,6 @@ import drawLine from './drawLine.mjs';
/** @class Class representing a pattern. */
export class Pattern {
_Pattern = true; // this property is used to detect if a pattern that fails instanceof Pattern is an instance of another Pattern
/**
* Create a pattern. As an end user, you will most likely not create a Pattern directly.
*
@@ -1050,9 +1049,6 @@ export class Pattern {
.unit('c')
.slow(factor);
}
onTrigger(onTrigger) {
return this._withHap((hap) => hap.setContext({ ...hap.context, onTrigger }));
}
}
// TODO - adopt value.mjs fully..
@@ -1213,15 +1209,7 @@ export function pure(value) {
export function isPattern(thing) {
// thing?.constructor?.name !== 'Pattern' // <- this will fail when code is mangled
const is = thing instanceof Pattern || thing._Pattern;
if (!thing instanceof Pattern) {
console.warn(
`Found Pattern that fails "instanceof Pattern" check.
This may happen if you are using multiple versions of @strudel.cycles/core.
Please check by running "npm ls @strudel.cycles/core".`,
);
}
return is;
return thing instanceof Pattern;
}
export function reify(thing) {
@@ -1398,7 +1386,6 @@ export function pr(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));
export const chunkBack = curry((a, pat) => pat.chunkBack(a));
export const div = curry((a, pat) => pat.div(a));
+2 -2
View File
@@ -10,7 +10,7 @@ export const tokenizeNote = (note) => {
if (typeof note !== 'string') {
return [];
}
const [pc, acc = '', oct] = note.match(/^([a-gA-G])([#bs]*)([0-9])?$/)?.slice(1) || [];
const [pc, acc = '', oct] = note.match(/^([a-gA-G])([#b]*)([0-9])?$/)?.slice(1) || [];
if (!pc) {
return [];
}
@@ -24,7 +24,7 @@ export const toMidi = (note) => {
throw new Error('not a note: "' + note + '"');
}
const chroma = { c: 0, d: 2, e: 4, f: 5, g: 7, a: 9, b: 11 }[pc.toLowerCase()];
const offset = acc?.split('').reduce((o, char) => o + { '#': 1, b: -1, s: 1 }[char], 0) || 0;
const offset = acc?.split('').reduce((o, char) => o + { '#': 1, b: -1 }[char], 0) || 0;
return (Number(oct) + 1) * 12 + chroma + offset;
};
export const fromMidi = (n) => {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/embed",
"version": "0.1.1",
"version": "0.1.0",
"description": "Embeddable Web Component to load a Strudel REPL into an iframe",
"main": "embed.js",
"type": "module",
+2 -4
View File
@@ -15,11 +15,9 @@ npm i @strudel.cycles/eval --save
```js
import { evaluate, extend } from '@strudel.cycles/eval';
import * as strudel from '@strudel.cycles/core';
evalScope(
import('@strudel.cycles/core'),
// import other strudel packages here
); // add strudel to eval scope
extend(strudel); // add strudel to eval scope
async function run(code) {
const { pattern } = await evaluate(code);
+3 -3
View File
@@ -1,13 +1,13 @@
{
"name": "@strudel.cycles/eval",
"version": "0.1.3",
"version": "0.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@strudel.cycles/eval",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"version": "0.0.3",
"license": "GPL-3.0-or-later",
"dependencies": {
"estraverse": "^5.3.0",
"shift-ast": "^6.1.0",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/eval",
"version": "0.1.3",
"version": "0.1.1",
"description": "Code evaluator for strudel",
"main": "index.mjs",
"type": "module",
@@ -28,7 +28,7 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"estraverse": "^5.3.0",
"shift-ast": "^6.1.0",
"shift-codegen": "^7.0.3",
+1 -1
View File
@@ -89,7 +89,7 @@ export default (_code) => {
const isMarkable = isPatternArg(parents) || hasModifierCall(parent);
// add to location to pure(x) calls
if (node.type === 'CallExpression' && node.callee.name === 'pure') {
if (addLocations && node.type === 'CallExpression' && node.callee.name === 'pure') {
const literal = node.arguments[0];
// const value = literal[{ LiteralNumericExpression: 'value', LiteralStringExpression: 'name' }[literal.type]];
return reifyWithLocation(literal, node.arguments[0], ast.locations, artificialNodes);
+3 -3
View File
@@ -1,13 +1,13 @@
{
"name": "@strudel.cycles/midi",
"version": "0.1.3",
"version": "0.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@strudel.cycles/midi",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"version": "0.0.4",
"license": "GPL-3.0-or-later",
"dependencies": {
"tone": "^14.7.77",
"webmidi": "^2.5.2"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/midi",
"version": "0.1.3",
"version": "0.1.1",
"description": "Midi API for strudel",
"main": "index.mjs",
"repository": {
@@ -21,7 +21,7 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/tone": "^0.1.3",
"@strudel.cycles/tone": "^0.1.1",
"tone": "^14.7.77",
"webmidi": "^2.5.2"
}
+158 -164
View File
@@ -1,4 +1,10 @@
// Generated by Peggy 2.0.1.
/*
krill-parser.js - <short description TODO>
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/mini/krill-parser.js>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// Generated by Peggy 1.2.0.
//
// https://peggyjs.org/
@@ -10,7 +16,6 @@ function peg$subclass(child, parent) {
function peg$SyntaxError(message, expected, found, location) {
var self = Error.call(this, message);
// istanbul ignore next Check is a necessary evil to support older environments
if (Object.setPrototypeOf) {
Object.setPrototypeOf(self, peg$SyntaxError.prototype);
}
@@ -46,15 +51,14 @@ peg$SyntaxError.prototype.format = function(sources) {
var loc = this.location.source + ":" + s.line + ":" + s.column;
if (src) {
var e = this.location.end;
var filler = peg$padEnd("", s.line.toString().length, ' ');
var filler = peg$padEnd("", s.line.toString().length);
var line = src[s.line - 1];
var last = s.line === e.line ? e.column : line.length + 1;
var hatLen = (last - s.column) || 1;
str += "\n --> " + loc + "\n"
+ filler + " |\n"
+ s.line + " | " + line + "\n"
+ filler + " | " + peg$padEnd("", s.column - 1, ' ')
+ peg$padEnd("", hatLen, "^");
+ filler + " | " + peg$padEnd("", s.column - 1)
+ peg$padEnd("", last - s.column, "^");
} else {
str += "\n at " + loc;
}
@@ -75,7 +79,7 @@ peg$SyntaxError.buildMessage = function(expected, found) {
: classEscape(part);
});
return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]";
return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";
},
any: function() {
@@ -181,32 +185,31 @@ function peg$parse(input, options) {
var peg$c7 = "#";
var peg$c8 = "^";
var peg$c9 = "_";
var peg$c10 = ":";
var peg$c11 = "[";
var peg$c12 = "]";
var peg$c13 = "<";
var peg$c14 = ">";
var peg$c15 = "@";
var peg$c16 = "!";
var peg$c17 = "(";
var peg$c18 = ")";
var peg$c19 = "/";
var peg$c20 = "*";
var peg$c21 = "%";
var peg$c22 = "struct";
var peg$c23 = "target";
var peg$c24 = "euclid";
var peg$c25 = "slow";
var peg$c26 = "rotL";
var peg$c27 = "rotR";
var peg$c28 = "fast";
var peg$c29 = "scale";
var peg$c30 = "//";
var peg$c31 = "cat";
var peg$c32 = "$";
var peg$c33 = "setcps";
var peg$c34 = "setbpm";
var peg$c35 = "hush";
var peg$c10 = "[";
var peg$c11 = "]";
var peg$c12 = "<";
var peg$c13 = ">";
var peg$c14 = "@";
var peg$c15 = "!";
var peg$c16 = "(";
var peg$c17 = ")";
var peg$c18 = "/";
var peg$c19 = "*";
var peg$c20 = "%";
var peg$c21 = "struct";
var peg$c22 = "target";
var peg$c23 = "euclid";
var peg$c24 = "slow";
var peg$c25 = "rotL";
var peg$c26 = "rotR";
var peg$c27 = "fast";
var peg$c28 = "scale";
var peg$c29 = "//";
var peg$c30 = "cat";
var peg$c31 = "$";
var peg$c32 = "setcps";
var peg$c33 = "setbpm";
var peg$c34 = "hush";
var peg$r0 = /^[1-9]/;
var peg$r1 = /^[eE]/;
@@ -232,33 +235,32 @@ function peg$parse(input, options) {
var peg$e14 = peg$literalExpectation("#", false);
var peg$e15 = peg$literalExpectation("^", false);
var peg$e16 = peg$literalExpectation("_", false);
var peg$e17 = peg$literalExpectation(":", false);
var peg$e18 = peg$literalExpectation("[", false);
var peg$e19 = peg$literalExpectation("]", false);
var peg$e20 = peg$literalExpectation("<", false);
var peg$e21 = peg$literalExpectation(">", false);
var peg$e22 = peg$literalExpectation("@", false);
var peg$e23 = peg$literalExpectation("!", false);
var peg$e24 = peg$literalExpectation("(", false);
var peg$e25 = peg$literalExpectation(")", false);
var peg$e26 = peg$literalExpectation("/", false);
var peg$e27 = peg$literalExpectation("*", false);
var peg$e28 = peg$literalExpectation("%", false);
var peg$e29 = peg$literalExpectation("struct", false);
var peg$e30 = peg$literalExpectation("target", false);
var peg$e31 = peg$literalExpectation("euclid", false);
var peg$e32 = peg$literalExpectation("slow", false);
var peg$e33 = peg$literalExpectation("rotL", false);
var peg$e34 = peg$literalExpectation("rotR", false);
var peg$e35 = peg$literalExpectation("fast", false);
var peg$e36 = peg$literalExpectation("scale", false);
var peg$e37 = peg$literalExpectation("//", false);
var peg$e38 = peg$classExpectation(["\n"], true, false);
var peg$e39 = peg$literalExpectation("cat", false);
var peg$e40 = peg$literalExpectation("$", false);
var peg$e41 = peg$literalExpectation("setcps", false);
var peg$e42 = peg$literalExpectation("setbpm", false);
var peg$e43 = peg$literalExpectation("hush", false);
var peg$e17 = peg$literalExpectation("[", false);
var peg$e18 = peg$literalExpectation("]", false);
var peg$e19 = peg$literalExpectation("<", false);
var peg$e20 = peg$literalExpectation(">", false);
var peg$e21 = peg$literalExpectation("@", false);
var peg$e22 = peg$literalExpectation("!", false);
var peg$e23 = peg$literalExpectation("(", false);
var peg$e24 = peg$literalExpectation(")", false);
var peg$e25 = peg$literalExpectation("/", false);
var peg$e26 = peg$literalExpectation("*", false);
var peg$e27 = peg$literalExpectation("%", false);
var peg$e28 = peg$literalExpectation("struct", false);
var peg$e29 = peg$literalExpectation("target", false);
var peg$e30 = peg$literalExpectation("euclid", false);
var peg$e31 = peg$literalExpectation("slow", false);
var peg$e32 = peg$literalExpectation("rotL", false);
var peg$e33 = peg$literalExpectation("rotR", false);
var peg$e34 = peg$literalExpectation("fast", false);
var peg$e35 = peg$literalExpectation("scale", false);
var peg$e36 = peg$literalExpectation("//", false);
var peg$e37 = peg$classExpectation(["\n"], true, false);
var peg$e38 = peg$literalExpectation("cat", false);
var peg$e39 = peg$literalExpectation("$", false);
var peg$e40 = peg$literalExpectation("setcps", false);
var peg$e41 = peg$literalExpectation("setbpm", false);
var peg$e42 = peg$literalExpectation("hush", false);
var peg$f0 = function() { return parseFloat(text()); };
var peg$f1 = function(chars) { return chars.join("") };
@@ -292,6 +294,7 @@ function peg$parse(input, options) {
var peg$f29 = function(v) { return new CommandStub("setcps", { value: v})};
var peg$f30 = function(v) { return new CommandStub("setcps", { value: (v/120/2)})};
var peg$f31 = function() { return new CommandStub("hush")};
var peg$currPos = 0;
var peg$savedPos = 0;
var peg$posDetailsCache = [{ line: 1, column: 1 }];
@@ -807,15 +810,6 @@ function peg$parse(input, options) {
s0 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e16); }
}
if (s0 === peg$FAILED) {
if (input.charCodeAt(peg$currPos) === 58) {
s0 = peg$c10;
peg$currPos++;
} else {
s0 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e17); }
}
}
}
}
}
@@ -858,11 +852,11 @@ function peg$parse(input, options) {
s0 = peg$currPos;
s1 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 91) {
s2 = peg$c11;
s2 = peg$c10;
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e18); }
if (peg$silentFails === 0) { peg$fail(peg$e17); }
}
if (s2 !== peg$FAILED) {
s3 = peg$parsews();
@@ -870,11 +864,11 @@ function peg$parse(input, options) {
if (s4 !== peg$FAILED) {
s5 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 93) {
s6 = peg$c12;
s6 = peg$c11;
peg$currPos++;
} else {
s6 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e19); }
if (peg$silentFails === 0) { peg$fail(peg$e18); }
}
if (s6 !== peg$FAILED) {
s7 = peg$parsews();
@@ -902,11 +896,11 @@ function peg$parse(input, options) {
s0 = peg$currPos;
s1 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 60) {
s2 = peg$c13;
s2 = peg$c12;
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e20); }
if (peg$silentFails === 0) { peg$fail(peg$e19); }
}
if (s2 !== peg$FAILED) {
s3 = peg$parsews();
@@ -914,11 +908,11 @@ function peg$parse(input, options) {
if (s4 !== peg$FAILED) {
s5 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 62) {
s6 = peg$c14;
s6 = peg$c13;
peg$currPos++;
} else {
s6 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e21); }
if (peg$silentFails === 0) { peg$fail(peg$e20); }
}
if (s6 !== peg$FAILED) {
s7 = peg$parsews();
@@ -982,11 +976,11 @@ function peg$parse(input, options) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 64) {
s1 = peg$c15;
s1 = peg$c14;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e22); }
if (peg$silentFails === 0) { peg$fail(peg$e21); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsenumber();
@@ -1010,11 +1004,11 @@ function peg$parse(input, options) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 33) {
s1 = peg$c16;
s1 = peg$c15;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e23); }
if (peg$silentFails === 0) { peg$fail(peg$e22); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsenumber();
@@ -1038,11 +1032,11 @@ function peg$parse(input, options) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 40) {
s1 = peg$c17;
s1 = peg$c16;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e24); }
if (peg$silentFails === 0) { peg$fail(peg$e23); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1066,11 +1060,11 @@ function peg$parse(input, options) {
}
s12 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 41) {
s13 = peg$c18;
s13 = peg$c17;
peg$currPos++;
} else {
s13 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e25); }
if (peg$silentFails === 0) { peg$fail(peg$e24); }
}
if (s13 !== peg$FAILED) {
peg$savedPos = s0;
@@ -1104,11 +1098,11 @@ function peg$parse(input, options) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 47) {
s1 = peg$c19;
s1 = peg$c18;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e26); }
if (peg$silentFails === 0) { peg$fail(peg$e25); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsenumber();
@@ -1132,11 +1126,11 @@ function peg$parse(input, options) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 42) {
s1 = peg$c20;
s1 = peg$c19;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e27); }
if (peg$silentFails === 0) { peg$fail(peg$e26); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsenumber();
@@ -1160,11 +1154,11 @@ function peg$parse(input, options) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 37) {
s1 = peg$c21;
s1 = peg$c20;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e28); }
if (peg$silentFails === 0) { peg$fail(peg$e27); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsenumber();
@@ -1338,12 +1332,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3;
s0 = peg$currPos;
if (input.substr(peg$currPos, 6) === peg$c22) {
s1 = peg$c22;
if (input.substr(peg$currPos, 6) === peg$c21) {
s1 = peg$c21;
peg$currPos += 6;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e29); }
if (peg$silentFails === 0) { peg$fail(peg$e28); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1367,12 +1361,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3, s4, s5;
s0 = peg$currPos;
if (input.substr(peg$currPos, 6) === peg$c23) {
s1 = peg$c23;
if (input.substr(peg$currPos, 6) === peg$c22) {
s1 = peg$c22;
peg$currPos += 6;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e30); }
if (peg$silentFails === 0) { peg$fail(peg$e29); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1408,12 +1402,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3, s4, s5, s6, s7;
s0 = peg$currPos;
if (input.substr(peg$currPos, 6) === peg$c24) {
s1 = peg$c24;
if (input.substr(peg$currPos, 6) === peg$c23) {
s1 = peg$c23;
peg$currPos += 6;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e31); }
if (peg$silentFails === 0) { peg$fail(peg$e30); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1449,12 +1443,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3;
s0 = peg$currPos;
if (input.substr(peg$currPos, 4) === peg$c25) {
s1 = peg$c25;
if (input.substr(peg$currPos, 4) === peg$c24) {
s1 = peg$c24;
peg$currPos += 4;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e32); }
if (peg$silentFails === 0) { peg$fail(peg$e31); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1478,12 +1472,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3;
s0 = peg$currPos;
if (input.substr(peg$currPos, 4) === peg$c26) {
s1 = peg$c26;
if (input.substr(peg$currPos, 4) === peg$c25) {
s1 = peg$c25;
peg$currPos += 4;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e33); }
if (peg$silentFails === 0) { peg$fail(peg$e32); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1507,12 +1501,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3;
s0 = peg$currPos;
if (input.substr(peg$currPos, 4) === peg$c27) {
s1 = peg$c27;
if (input.substr(peg$currPos, 4) === peg$c26) {
s1 = peg$c26;
peg$currPos += 4;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e34); }
if (peg$silentFails === 0) { peg$fail(peg$e33); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1536,12 +1530,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3;
s0 = peg$currPos;
if (input.substr(peg$currPos, 4) === peg$c28) {
s1 = peg$c28;
if (input.substr(peg$currPos, 4) === peg$c27) {
s1 = peg$c27;
peg$currPos += 4;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e35); }
if (peg$silentFails === 0) { peg$fail(peg$e34); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1565,12 +1559,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3, s4, s5;
s0 = peg$currPos;
if (input.substr(peg$currPos, 5) === peg$c29) {
s1 = peg$c29;
if (input.substr(peg$currPos, 5) === peg$c28) {
s1 = peg$c28;
peg$currPos += 5;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e36); }
if (peg$silentFails === 0) { peg$fail(peg$e35); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1615,12 +1609,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3;
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c30) {
s1 = peg$c30;
if (input.substr(peg$currPos, 2) === peg$c29) {
s1 = peg$c29;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e37); }
if (peg$silentFails === 0) { peg$fail(peg$e36); }
}
if (s1 !== peg$FAILED) {
s2 = [];
@@ -1629,7 +1623,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e38); }
if (peg$silentFails === 0) { peg$fail(peg$e37); }
}
while (s3 !== peg$FAILED) {
s2.push(s3);
@@ -1638,7 +1632,7 @@ function peg$parse(input, options) {
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e38); }
if (peg$silentFails === 0) { peg$fail(peg$e37); }
}
}
s1 = [s1, s2];
@@ -1655,21 +1649,21 @@ function peg$parse(input, options) {
var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;
s0 = peg$currPos;
if (input.substr(peg$currPos, 3) === peg$c31) {
s1 = peg$c31;
if (input.substr(peg$currPos, 3) === peg$c30) {
s1 = peg$c30;
peg$currPos += 3;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e39); }
if (peg$silentFails === 0) { peg$fail(peg$e38); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 91) {
s3 = peg$c11;
s3 = peg$c10;
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e18); }
if (peg$silentFails === 0) { peg$fail(peg$e17); }
}
if (s3 !== peg$FAILED) {
s4 = peg$parsews();
@@ -1711,11 +1705,11 @@ function peg$parse(input, options) {
}
s7 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 93) {
s8 = peg$c12;
s8 = peg$c11;
peg$currPos++;
} else {
s8 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e19); }
if (peg$silentFails === 0) { peg$fail(peg$e18); }
}
if (s8 !== peg$FAILED) {
peg$savedPos = s0;
@@ -1776,11 +1770,11 @@ function peg$parse(input, options) {
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 36) {
s3 = peg$c32;
s3 = peg$c31;
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e40); }
if (peg$silentFails === 0) { peg$fail(peg$e39); }
}
if (s3 !== peg$FAILED) {
s4 = peg$parsews();
@@ -1858,12 +1852,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3;
s0 = peg$currPos;
if (input.substr(peg$currPos, 6) === peg$c33) {
s1 = peg$c33;
if (input.substr(peg$currPos, 6) === peg$c32) {
s1 = peg$c32;
peg$currPos += 6;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e41); }
if (peg$silentFails === 0) { peg$fail(peg$e40); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1887,12 +1881,12 @@ function peg$parse(input, options) {
var s0, s1, s2, s3;
s0 = peg$currPos;
if (input.substr(peg$currPos, 6) === peg$c34) {
s1 = peg$c34;
if (input.substr(peg$currPos, 6) === peg$c33) {
s1 = peg$c33;
peg$currPos += 6;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e42); }
if (peg$silentFails === 0) { peg$fail(peg$e41); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
@@ -1916,12 +1910,12 @@ function peg$parse(input, options) {
var s0, s1;
s0 = peg$currPos;
if (input.substr(peg$currPos, 4) === peg$c35) {
s1 = peg$c35;
if (input.substr(peg$currPos, 4) === peg$c34) {
s1 = peg$c34;
peg$currPos += 4;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e43); }
if (peg$silentFails === 0) { peg$fail(peg$e42); }
}
if (s1 !== peg$FAILED) {
peg$savedPos = s0;
@@ -1944,34 +1938,35 @@ function peg$parse(input, options) {
}
var PatternStub = function(source, alignment)
{
this.type_ = "pattern";
this.arguments_ = { alignment : alignment};
this.source_ = source;
}
var PatternStub = function(source, alignment)
{
this.type_ = "pattern";
this.arguments_ = { alignment : alignment};
this.source_ = source;
}
var OperatorStub = function(name, args, source)
{
this.type_ = name;
this.arguments_ = args;
this.source_ = source;
}
var OperatorStub = function(name, args, source)
{
this.type_ = name;
this.arguments_ = args;
this.source_ = source;
}
var ElementStub = function(source, options)
{
this.type_ = "element";
this.source_ = source;
this.options_ = options;
this.location_ = location();
}
var ElementStub = function(source, options)
{
this.type_ = "element";
this.source_ = source;
this.options_ = options;
this.location_ = location();
}
var CommandStub = function(name, options)
{
this.type_ = "command";
this.name_ = name;
this.options_ = options;
}
var CommandStub = function(name, options)
{
this.type_ = "command";
this.name_ = name;
this.options_ = options;
}
peg$result = peg$startRuleFunction();
@@ -1995,6 +1990,5 @@ function peg$parse(input, options) {
export {
peg$SyntaxError as SyntaxError,
peg$parse as parse
};
+1 -1
View File
@@ -87,7 +87,7 @@ quote = '"' / "'"
// ------------------ steps and cycles ---------------------------
// single step definition (e.g bd)
step_char = [0-9a-zA-Z~] / "-" / "#" / "." / "^" / "_" / ":"
step_char = [0-9a-zA-Z~] / "-" / "#" / "." / "^" / "_"
step = ws chars:step_char+ ws { return chars.join("") }
// define a sub cycle e.g. [1 2, 3 [4]]
-1031
View File
File diff suppressed because it is too large Load Diff
+5 -9
View File
@@ -1,12 +1,11 @@
{
"name": "@strudel.cycles/mini",
"version": "0.1.3",
"version": "0.1.1",
"description": "Mini notation for strudel",
"main": "index.mjs",
"type": "module",
"scripts": {
"test": "mocha --colors",
"build:parser": "peggy -o krill-parser.js --format es ./krill.pegjs"
"test": "mocha --colors"
},
"repository": {
"type": "git",
@@ -26,11 +25,8 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/eval": "^0.1.3",
"@strudel.cycles/tone": "^0.1.3"
},
"devDependencies": {
"peggy": "^2.0.1"
"@strudel.cycles/core": "^0.1.0",
"@strudel.cycles/eval": "^0.1.1",
"@strudel.cycles/tone": "^0.1.1"
}
}
+2 -4
View File
@@ -22,15 +22,13 @@ let startedAt = -1;
*/
Pattern.prototype.osc = function () {
return this._withHap((hap) => {
const onTrigger = (time, hap, currentTime, cps) => {
const cycle = hap.wholeOrPart().begin.valueOf();
const delta = hap.duration.valueOf();
const onTrigger = (time, hap, currentTime, cps, cycle, delta) => {
// time should be audio time of onset
// currentTime should be current time of audio context (slightly before time)
if (startedAt < 0) {
startedAt = Date.now() - currentTime * 1000;
}
const controls = Object.assign({}, { cps, cycle, delta }, hap.value);
const controls = Object.assign({}, { cps: cps, cycle: cycle, delta: delta }, hap.value);
const keyvals = Object.entries(controls).flat();
const ts = Math.floor(startedAt + (time + latency) * 1000);
const message = new OSC.Message('/dirt/play', ...keyvals);
+3 -3
View File
@@ -1,13 +1,13 @@
{
"name": "@strudel.cycles/osc",
"version": "0.1.1",
"version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@strudel.cycles/osc",
"version": "0.1.0",
"license": "AGPL-3.0-or-later",
"version": "0.0.1",
"license": "GPL-3.0-or-later",
"dependencies": {
"osc-js": "^2.3.2"
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/osc",
"version": "0.1.1",
"version": "0.1.0",
"description": "OSC messaging for strudel",
"main": "osc.mjs",
"scripts": {
+2 -2
View File
File diff suppressed because one or more lines are too long
+10 -35
View File
@@ -145,37 +145,6 @@ const materialPalenightHighlightStyle = HighlightStyle.define([
// : Extension
const materialPalenight = [materialPalenightTheme, materialPalenightHighlightStyle];
const setFlash = StateEffect.define();
const flashField = StateField.define({
create() {
return Decoration.none;
},
update(flash2, tr) {
try {
for (let e of tr.effects) {
if (e.is(setFlash)) {
if (e.value) {
const mark = Decoration.mark({ attributes: { style: `background-color: #FFCA2880` } });
flash2 = Decoration.set([mark.range(0, tr.newDoc.length)]);
} else {
flash2 = Decoration.set([]);
}
}
}
return flash2;
} catch (err) {
console.warn("flash error", err);
return flash2;
}
},
provide: (f) => EditorView.decorations.from(f)
});
const flash = (view) => {
view.dispatch({ effects: setFlash.of(true) });
setTimeout(() => {
view.dispatch({ effects: setFlash.of(false) });
}, 200);
};
const setHighlights = StateEffect.define();
const highlightField = StateField.define({
create() {
@@ -218,8 +187,7 @@ function CodeMirror({ value, onChange, onViewChanged, onCursor, options, editorD
extensions: [
javascript(),
materialPalenight,
highlightField,
flashField
highlightField
]
}));
}
@@ -372,7 +340,14 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP
/* console.warn('no instrument chosen', event);
throw new Error(`no instrument chosen for ${JSON.stringify(event)}`); */
} else {
onTrigger(time, event, currentTime, 1 /* cps */);
onTrigger(
time,
event,
currentTime,
1 /* cps */,
event.wholeOrPart().begin.valueOf(),
event.duration.valueOf(),
);
}
} catch (err) {
console.warn(err);
@@ -648,4 +623,4 @@ function useWebMidi(props) {
return { loading, outputs, outputByName };
}
export { CodeMirror, MiniRepl, cx, flash, useCycle, useHighlighting, usePostMessage, useRepl, useWebMidi };
export { CodeMirror, MiniRepl, cx, useCycle, useHighlighting, usePostMessage, useRepl, useWebMidi };
-3984
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/react",
"version": "0.1.4",
"version": "0.1.2",
"description": "React components for strudel",
"main": "dist/index.cjs.js",
"module": "dist/index.es.js",
@@ -38,9 +38,9 @@
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@codemirror/lang-javascript": "^0.19.0",
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/eval": "^0.1.3",
"@strudel.cycles/tone": "^0.1.3",
"@strudel.cycles/core": "*",
"@strudel.cycles/eval": "^0.1.1",
"@strudel.cycles/tone": "^0.1.1",
"react-codemirror6": "^1.1.0",
"react-hook-inview": "^4.5.0"
},
@@ -7,39 +7,6 @@ import { javascript } from '@codemirror/lang-javascript';
// import { materialPalenight } from 'codemirror6-themes';
import { materialPalenight } from '../themes/material-palenight';
export const setFlash = StateEffect.define();
const flashField = StateField.define({
create() {
return Decoration.none;
},
update(flash, tr) {
try {
for (let e of tr.effects) {
if (e.is(setFlash)) {
if (e.value) {
const mark = Decoration.mark({ attributes: { style: `background-color: #FFCA2880` } });
flash = Decoration.set([mark.range(0, tr.newDoc.length)]);
} else {
flash = Decoration.set([]);
}
}
}
return flash;
} catch (err) {
console.warn('flash error', err);
return flash;
}
},
provide: (f) => EditorView.decorations.from(f),
});
export const flash = (view) => {
view.dispatch({ effects: setFlash.of(true) });
setTimeout(() => {
view.dispatch({ effects: setFlash.of(false) });
}, 200);
};
export const setHighlights = StateEffect.define();
const highlightField = StateField.define({
create() {
@@ -94,7 +61,6 @@ export default function CodeMirror({ value, onChange, onViewChanged, onCursor, o
javascript(),
materialPalenight,
highlightField,
flashField,
// theme, language, ...
]}
/>
+8 -1
View File
@@ -57,7 +57,14 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP
/* console.warn('no instrument chosen', event);
throw new Error(`no instrument chosen for ${JSON.stringify(event)}`); */
} else {
onTrigger(time, event, currentTime, 1 /* cps */);
onTrigger(
time,
event,
currentTime,
1 /* cps */,
event.wholeOrPart().begin.valueOf(),
event.duration.valueOf(),
);
}
} catch (err) {
console.warn(err);
+1 -1
View File
@@ -1,6 +1,6 @@
// import 'tailwindcss/tailwind.css';
export { default as CodeMirror, flash } from './components/CodeMirror6';
export { default as CodeMirror } from './components/CodeMirror6';
export * from './components/MiniRepl';
export { default as useCycle } from './hooks/useCycle';
export { default as useHighlighting } from './hooks/useHighlighting';
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/serial",
"version": "0.1.3",
"version": "0.1.0",
"description": "Webserial API for strudel",
"main": "serial.mjs",
"repository": {
+5 -23
View File
@@ -9,7 +9,7 @@ import { Pattern, isPattern } from '@strudel.cycles/core';
var serialWriter;
var choosing = false;
export async function getWriter(br=38400) {
export async function getWriter(br=115200) {
if (choosing) {
return;
}
@@ -34,7 +34,8 @@ export async function getWriter(br=38400) {
const latency = 0.1;
Pattern.prototype.serial = function (...args) {
// Pattern.prototype.midi = function (output: string | number, channel = 1) {
Pattern.prototype.serial = async function (...args) {
return this._withHap((hap) => {
if (!serialWriter) {
getWriter(...args);
@@ -42,27 +43,8 @@ Pattern.prototype.serial = function (...args) {
const onTrigger = (time, hap, currentTime) => {
var message = "";
if (typeof hap.value === 'object') {
if ('action' in hap.value) {
message += hap.value['action'] + '(';
var first = true;
for (const [key, val] of Object.entries(hap.value)) {
if (key === 'action') {
continue;
}
if (first) {
first = false;
}
else {
message +=',';
}
message += `${key}:${val}`
}
message += ')';
}
else {
for (const [key, val] of Object.entries(hap.value)) {
message += `${key}:${val};`
}
for (const [key, val] of Object.entries(hap.value).flat()) {
message += `${key}:${val};`
}
}
else {
-13
View File
@@ -1,13 +0,0 @@
// this script converts a soundfont into a json file, it has not been not used yet
import fetch from 'node-fetch';
const name = '0000_JCLive';
const js = await fetch(`https://felixroos.github.io/webaudiofontdata/sound/${name}_sf2_file.js`).then((res) =>
res.text(),
);
// console.log(js);
let [_, data] = js.split('_sf2_file=');
data = eval(data);
console.log(JSON.stringify(data));
-114
View File
@@ -1,114 +0,0 @@
let loadCache = {};
async function loadFont(name) {
if (loadCache[name]) {
return loadCache[name];
}
const load = async () => {
// TODO: make soundfont source configurable
const url = `https://felixroos.github.io/webaudiofontdata/sound/${name}.js`;
console.log('load font', name, url);
const preset = await fetch(url).then((res) => res.text());
let [_, data] = preset.split('={');
return eval('{' + data);
};
loadCache[name] = load();
return loadCache[name];
}
export async function getFontBufferSource(name, pitch, ac) {
if (typeof pitch === 'string') {
pitch = toMidi(pitch);
}
const { buffer, zone } = await getFontPitch(name, pitch, ac);
const src = ac.createBufferSource();
src.buffer = buffer;
const baseDetune = zone.originalPitch - 100.0 * zone.coarseTune - zone.fineTune;
const playbackRate = 1.0 * Math.pow(2, (100.0 * pitch - baseDetune) / 1200.0);
// src detune?
src.playbackRate.value = playbackRate;
const loop = zone.loopStart > 1 && zone.loopStart < zone.loopEnd;
if (!loop) {
/* const waveDuration = duration + this.afterTime;
if (waveDuration > zone.buffer.duration / playbackRate) {
waveDuration = zone.buffer.duration / playbackRate;
// TODO: do sth with waveduration
} */
} else {
src.loop = true;
src.loopStart = zone.loopStart / zone.sampleRate;
src.loopEnd = zone.loopEnd / zone.sampleRate;
//+ (zone.delay ? zone.delay : 0);
}
return src;
}
let bufferCache = {};
export async function getFontPitch(name, pitch, ac) {
const key = `${name}:::${pitch}`;
if (bufferCache[key]) {
return bufferCache[key];
}
// console.log('load buffer', key);
const load = async () => {
const preset = await loadFont(name);
if (!preset) {
throw new Error(`Could not load soundfont ${name}`);
}
const zone = findZone(preset, pitch);
if (!zone) {
throw new Error('no soundfont zone found for preset ', name, 'pitch', pitch);
}
const buffer = await getBuffer(zone, ac);
if (!buffer) {
throw new Error(`no soundfont buffer found for preset ${name}, pitch: ${pitch}`);
}
return { buffer, zone };
};
bufferCache[key] = load(); // dont await here to cache promise immediately!
return bufferCache[key];
}
function findZone(preset, pitch) {
return preset.find((zone) => {
return zone.keyRangeLow <= pitch && zone.keyRangeHigh + 1 >= pitch;
});
}
// promisified version of https://github.com/felixroos/webaudiofont/blob/c6f97249b60dcfafc20fca5bb381294a6b2f8f51/npm/dist/WebAudioFontPlayer.js#L740
async function getBuffer(zone, audioContext) {
if (zone.sample) {
console.warn('zone.sample untested!');
const decoded = atob(zone.sample);
zone.buffer = audioContext.createBuffer(1, decoded.length / 2, zone.sampleRate);
const float32Array = zone.buffer.getChannelData(0);
let b1, b2, n;
for (var i = 0; i < decoded.length / 2; i++) {
b1 = decoded.charCodeAt(i * 2);
b2 = decoded.charCodeAt(i * 2 + 1);
if (b1 < 0) {
b1 = 256 + b1;
}
if (b2 < 0) {
b2 = 256 + b2;
}
n = b2 * 256 + b1;
if (n >= 65536 / 2) {
n = n - 65536;
}
float32Array[i] = n / 65536.0;
}
} else {
if (zone.file) {
const datalen = zone.file.length;
const arraybuffer = new ArrayBuffer(datalen);
const view = new Uint8Array(arraybuffer);
const decoded = atob(zone.file);
let b;
for (let i = 0; i < decoded.length; i++) {
b = decoded.charCodeAt(i);
view[i] = b;
}
return new Promise((resolve) => audioContext.decodeAudioData(arraybuffer, resolve));
}
}
}
-6
View File
@@ -1,6 +0,0 @@
import { getFontBufferSource } from './fontloader.mjs';
import * as soundfontList from './list.mjs';
globalThis.getFontBufferSource = getFontBufferSource;
globalThis.soundfontList = soundfontList;
globalThis.soundfontList = soundfontList;
File diff suppressed because it is too large Load Diff
-301
View File
@@ -1,301 +0,0 @@
{
"name": "@strudel.cycles/soundfonts",
"version": "0.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@strudel.cycles/soundfonts",
"version": "0.1.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"webaudiofont": "^3.0.1"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"node_modules/glob": {
"version": "8.0.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
"integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^5.0.1",
"once": "^1.3.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/jsonc-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
"integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA=="
},
"node_modules/lunr": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="
},
"node_modules/marked": {
"version": "4.0.17",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz",
"integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==",
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/minimatch": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
"integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/shiki": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz",
"integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==",
"dependencies": {
"jsonc-parser": "^3.0.0",
"vscode-oniguruma": "^1.6.1",
"vscode-textmate": "5.2.0"
}
},
"node_modules/typedoc": {
"version": "0.22.17",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.17.tgz",
"integrity": "sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg==",
"dependencies": {
"glob": "^8.0.3",
"lunr": "^2.3.9",
"marked": "^4.0.16",
"minimatch": "^5.1.0",
"shiki": "^0.10.1"
},
"bin": {
"typedoc": "bin/typedoc"
},
"engines": {
"node": ">= 12.10.0"
},
"peerDependencies": {
"typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x || 4.7.x"
}
},
"node_modules/typescript": {
"version": "4.7.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/vscode-oniguruma": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz",
"integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA=="
},
"node_modules/vscode-textmate": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz",
"integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ=="
},
"node_modules/webaudiofont": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webaudiofont/-/webaudiofont-3.0.1.tgz",
"integrity": "sha512-PwqbR4OdvzbW8/TLTitSU/rw4mxMKyAGTKV42mePCgMoUGLJoQj8HDLWVqtNOpUZ0ghPNhNE6cRFEv6HFFEBQA==",
"dependencies": {
"typedoc": "^0.22.14"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
},
"dependencies": {
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"requires": {
"balanced-match": "^1.0.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"glob": {
"version": "8.0.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
"integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^5.0.1",
"once": "^1.3.0"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"jsonc-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
"integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA=="
},
"lunr": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="
},
"marked": {
"version": "4.0.17",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz",
"integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA=="
},
"minimatch": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
"integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
"requires": {
"brace-expansion": "^2.0.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"requires": {
"wrappy": "1"
}
},
"shiki": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz",
"integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==",
"requires": {
"jsonc-parser": "^3.0.0",
"vscode-oniguruma": "^1.6.1",
"vscode-textmate": "5.2.0"
}
},
"typedoc": {
"version": "0.22.17",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.17.tgz",
"integrity": "sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg==",
"requires": {
"glob": "^8.0.3",
"lunr": "^2.3.9",
"marked": "^4.0.16",
"minimatch": "^5.1.0",
"shiki": "^0.10.1"
}
},
"typescript": {
"version": "4.7.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
"peer": true
},
"vscode-oniguruma": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz",
"integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA=="
},
"vscode-textmate": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz",
"integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ=="
},
"webaudiofont": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webaudiofont/-/webaudiofont-3.0.1.tgz",
"integrity": "sha512-PwqbR4OdvzbW8/TLTitSU/rw4mxMKyAGTKV42mePCgMoUGLJoQj8HDLWVqtNOpUZ0ghPNhNE6cRFEv6HFFEBQA==",
"requires": {
"typedoc": "^0.22.14"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
}
}
-31
View File
@@ -1,31 +0,0 @@
{
"name": "@strudel.cycles/soundfonts",
"version": "0.1.1",
"description": "Soundsfont support for strudel",
"main": "index.mjs",
"type": "module",
"repository": {
"type": "git",
"url": "git+https://github.com/tidalcycles/strudel.git"
},
"keywords": [
"tidalcycles",
"strudel",
"pattern",
"livecoding",
"algorave"
],
"author": "Felix Roos <flix91@gmail.com>",
"license": "AGPL-3.0-or-later",
"bugs": {
"url": "https://github.com/tidalcycles/strudel/issues"
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "*",
"@strudel.cycles/webaudio": "^0.1.4"
},
"devDependencies": {
"node-fetch": "^3.2.6"
}
}
+3 -3
View File
@@ -1,13 +1,13 @@
{
"name": "@strudel.cycles/tonal",
"version": "0.1.3",
"version": "0.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@strudel.cycles/tonal",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"version": "0.0.3",
"license": "GPL-3.0-or-later",
"dependencies": {
"@tonaljs/tonal": "^4.6.5",
"webmidi": "^3.0.15"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/tonal",
"version": "0.1.3",
"version": "0.1.1",
"description": "Tonal functions for strudel",
"main": "index.mjs",
"type": "module",
@@ -25,7 +25,7 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"@tonaljs/tonal": "^4.6.5",
"webmidi": "^3.0.15"
}
+2 -1
View File
@@ -36,7 +36,8 @@ Pattern.prototype.draw = function (callback, { from, to, onQuery }) {
const begin = currentCycle + from;
const end = currentCycle + to;
setTimeout(() => {
events = this.query(new State(new TimeSpan(begin, end)))
events = this._asNumber(true) // true = silent error
.query(new State(new TimeSpan(begin, end)))
.filter(Boolean)
.filter((event) => event.part.begin.equals(event.whole.begin));
onQuery?.(events);
+3 -3
View File
@@ -1,13 +1,13 @@
{
"name": "@strudel.cycles/tone",
"version": "0.1.3",
"version": "0.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@strudel.cycles/tone",
"version": "0.1.1",
"license": "AGPL-3.0-or-later",
"version": "0.0.4",
"license": "GPL-3.0-or-later",
"dependencies": {
"@tonejs/piano": "^0.2.1",
"chord-voicings": "^0.0.1",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/tone",
"version": "0.1.3",
"version": "0.1.1",
"description": "Tone.js API for strudel",
"main": "index.mjs",
"type": "module",
@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"@tonejs/piano": "^0.2.1",
"chord-voicings": "^0.0.1",
"tone": "^14.7.77"
+3 -9
View File
@@ -7,13 +7,6 @@ This program is free software: you can redistribute it and/or modify it under th
import { Pattern } from '@strudel.cycles/core';
const scale = (normalized, min, max) => normalized * (max - min) + min;
const getValue = (e) => {
let value = typeof e.value === 'object' ? e.value.note ?? e.value.n : e.value;
if (typeof value === 'string') {
value = toMidi(value);
}
return value;
};
Pattern.prototype.pianoroll = function ({
cycles = 4,
@@ -82,9 +75,9 @@ Pattern.prototype.pianoroll = function ({
ctx.stroke();
const timePx = scale((event.whole.begin - (flipTime ? to : from)) / timeExtent, ...timeRange);
let durationPx = scale(event.duration / timeExtent, 0, timeAxis);
const value = getValue(event);
const valuePx = scale(
fold ? foldValues.indexOf(value) / foldValues.length : (Number(value) - minMidi) / valueExtent,
fold ? foldValues.indexOf(event.value) / foldValues.length : (Number(event.value) - minMidi) / valueExtent,
...valueRange,
);
let margin = 0;
@@ -112,6 +105,7 @@ Pattern.prototype.pianoroll = function ({
from: from - overscan,
to: to + overscan,
onQuery: (events) => {
const getValue = (e) => Number(e.value);
const { min, max, values } = events.reduce(
({ min, max, values }, e) => {
const v = getValue(e);
-2
View File
@@ -7,5 +7,3 @@ This program is free software: you can redistribute it and/or modify it under th
export * from './clockworker.mjs';
export * from './scheduler.mjs';
export * from './webaudio.mjs';
export * from './sampler.mjs';
export * from './prebake.mjs';
+3667 -865
View File
File diff suppressed because it is too large Load Diff
+2 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/webaudio",
"version": "0.1.4",
"version": "0.1.1",
"description": "Web Audio helpers for Strudel",
"main": "index.mjs",
"type": "module",
@@ -28,11 +28,6 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.1.2"
},
"devDependencies": {
"koa": "^2.13.4",
"koa-static": "^5.0.0",
"@koa/cors": "^3.3.0"
"@strudel.cycles/core": "^0.1.0"
}
}
-83
View File
@@ -1,83 +0,0 @@
import { Pattern, toMidi } from '@strudel.cycles/core';
import { samples } from '.';
let baking;
export function prebake(props) {
if (baking) {
return baking;
}
baking = prebaker(props);
return baking;
}
async function prebaker(props = {}) {
const { baseURL = './samples' } = props; // http://localhost:1234
try {
samples(
{
piano: {
A0: 'A0v8.mp3',
C1: 'C1v8.mp3',
Ds1: 'Ds1v8.mp3',
Fs1: 'Fs1v8.mp3',
A1: 'A1v8.mp3',
C2: 'C2v8.mp3',
Ds2: 'Ds2v8.mp3',
Fs2: 'Fs2v8.mp3',
A2: 'A2v8.mp3',
C3: 'C3v8.mp3',
Ds3: 'Ds3v8.mp3',
Fs3: 'Fs3v8.mp3',
A3: 'A3v8.mp3',
C4: 'C4v8.mp3',
Ds4: 'Ds4v8.mp3',
Fs4: 'Fs4v8.mp3',
A4: 'A4v8.mp3',
C5: 'C5v8.mp3',
Ds4: 'Ds4v8.mp3',
Fs5: 'Fs5v8.mp3',
A5: 'A5v8.mp3',
C6: 'C6v8.mp3',
Ds6: 'Ds6v8.mp3',
Fs6: 'Fs6v8.mp3',
A6: 'A6v8.mp3',
C7: 'C7v8.mp3',
Ds7: 'Ds7v8.mp3',
Fs7: 'Fs7v8.mp3',
A7: 'A7v8.mp3',
C8: 'C8v8.mp3',
},
},
// https://archive.org/details/SalamanderGrandPianoV3
// License: CC-by http://creativecommons.org/licenses/by/3.0/ Author: Alexander Holm
baseURL + '/piano/',
);
const maxPan = toMidi('C8');
const panwidth = (pan, width) => pan * width + (1 - width) / 2;
Pattern.prototype.piano = function () {
return this.clip(1)
.s('piano')
.fmap((value) => {
// pan by pitch
const pan = panwidth(Math.min(toMidi(value.note) / maxPan, 1), 0.5);
return { ...value, pan: (value.pan || 1) * pan };
});
};
// ping sample server
/* await fetch(samplerURL)
.then(() => {
console.log(`prebake: Using samples from "${baseURL}"`);
})
.catch(() => {
throw new Error(
`sample server not running at "${samplerURL}"... run "npm run sampler" from the strudel project root.`,
);
}); */
} catch (e) {
console.warn('prebake error', e);
}
}
-34
View File
@@ -1,34 +0,0 @@
// "sampler": "cd ./repl/public/samples && node ../../../packages/webaudio/sample-server.js",
// "sampler": "http-server ./repl/public",
import fs from 'fs';
import path from 'path';
import Koa from 'koa'; // CJS: require('koa');
import cors from '@koa/cors';
import serve from 'koa-static'; // CJS: require('koa-static')
const cwd = process.cwd();
const yellow = '\x1b[33m%s\x1b[0m';
// get array of all folders in cwd:
const banks = fs.readdirSync(cwd).filter((f) => fs.statSync(path.join(cwd, f)).isDirectory());
const app = new Koa();
app.use(cors());
app.use(serve(cwd));
app.use((ctx, next) => {
return next().then(() => {
if (ctx.path === '/') {
ctx.body = 'banks: ' + banks.join(', ');
}
});
});
const port = 1234;
app.listen(port);
console.log(yellow, `strudel sampler running at http://localhost:${port}`);
// node: get current working directory
console.log(yellow, 'cwd: ' + cwd);
console.log('found banks:');
banks.map((c) => console.log(yellow, c));
+4 -6
View File
@@ -10,20 +10,18 @@ import { State, TimeSpan } from '@strudel.cycles/core';
export class Scheduler {
worker;
pattern;
constructor({ audioContext, interval = 0.2, onEvent, latency = 0.2 }) {
constructor({ audioContext, interval = 0.2, onEvent }) {
this.worker = new ClockWorker(
audioContext,
(begin, end) => {
this.pattern.query(new State(new TimeSpan(begin + latency, end + latency))).forEach((e) => {
this.pattern.query(new State(new TimeSpan(begin, end))).forEach((e) => {
if (!e.part.begin.equals(e.whole.begin)) {
return;
}
if (e.context.onTrigger) {
// TODO: kill first param, as it's contained in e
e.context.onTrigger(e.whole.begin, e, audioContext.currentTime, 1 /* cps */);
}
if (onEvent) {
onEvent?.(e);
} else {
console.warn('unplayable event: no audio node nor onEvent callback', e);
}
});
},
+56 -233
View File
@@ -6,11 +6,8 @@ This program is free software: you can redistribute it and/or modify it under th
// import { Pattern, getFrequency, patternify2 } from '@strudel.cycles/core';
import * as strudel from '@strudel.cycles/core';
import { fromMidi, toMidi } from '@strudel.cycles/core';
import { loadBuffer } from './sampler.mjs';
const { Pattern } = strudel;
// export const getAudioContext = () => Tone.getContext().rawContext;
import { Tone } from '@strudel.cycles/tone';
const { Pattern, getFrequency, patternify2 } = strudel;
let audioContext;
export const getAudioContext = () => {
@@ -20,15 +17,9 @@ export const getAudioContext = () => {
return audioContext;
};
const getFilter = (type, frequency, Q) => {
const filter = getAudioContext().createBiquadFilter();
filter.type = type;
filter.frequency.value = frequency;
filter.Q.value = Q;
return filter;
};
const lookahead = 0.2;
const getADSR = (attack, decay, sustain, release, velocity, begin, end) => {
const adsr = (attack, decay, sustain, release, velocity, begin, end) => {
const gainNode = getAudioContext().createGain();
gainNode.gain.setValueAtTime(0, begin);
gainNode.gain.linearRampToValueAtTime(velocity, begin + attack); // attack
@@ -39,233 +30,65 @@ const getADSR = (attack, decay, sustain, release, velocity, begin, end) => {
return gainNode;
};
const getOscillator = ({ s, freq, t, duration, release }) => {
// make oscillator
const o = getAudioContext().createOscillator();
o.type = s || 'triangle';
o.frequency.value = Number(freq);
o.start(t);
o.stop(t + duration + release);
return o;
Pattern.prototype.withAudioNode = function (createAudioNode) {
return this._withHap((hap) => {
return hap.setContext({
...hap.context,
createAudioNode: (t, e) => createAudioNode(t, e, hap.context.createAudioNode?.(t, hap)),
});
});
};
const getSoundfontKey = (s) => {
if (!globalThis.soundfontList) {
// soundfont package not loaded
return false;
}
if (globalThis.soundfontList?.instruments?.includes(s)) {
return s;
}
// check if s is one of the soundfonts, which are loaded into globalThis, to avoid coupling both packages
const nameIndex = globalThis.soundfontList?.instrumentNames?.indexOf(s);
// convert number nameIndex (0-128) to 3 digit string (001-128)
const name = nameIndex < 10 ? `00${nameIndex}` : nameIndex < 100 ? `0${nameIndex}` : nameIndex;
if (nameIndex !== -1) {
// TODO: indices of instrumentNames do not seem to match instruments
return globalThis.soundfontList.instruments.find((instrument) => instrument.startsWith(name));
}
return;
Pattern.prototype._wave = function (type) {
return this.withAudioNode((t, e) => {
const osc = getAudioContext().createOscillator();
osc.type = type;
const f = getFrequency(e);
osc.frequency.value = f; // expects frequency..
const begin = t ?? e.whole.begin.valueOf() + lookahead;
const end = begin + e.duration.valueOf();
osc.start(begin);
osc.stop(end); // release?
return osc;
});
};
Pattern.prototype.adsr = function (a = 0.01, d = 0.05, s = 1, r = 0.01) {
return this.withAudioNode((t, e, node) => {
const velocity = e.context?.velocity || 1;
const begin = t ?? e.whole.begin.valueOf() + lookahead;
const end = begin + e.duration.valueOf() + lookahead;
const envelope = adsr(a, d, s, r, velocity, begin, end);
node?.connect(envelope);
return envelope;
});
};
Pattern.prototype._filter = function (type = 'lowpass', frequency = 1000) {
return this.withAudioNode((t, e, node) => {
const filter = getAudioContext().createBiquadFilter();
filter.type = type;
filter.frequency.value = frequency;
node?.connect(filter);
return filter;
});
};
const getSampleBufferSource = async (s, n, note) => {
let transpose = 0;
if (note) {
transpose = toMidi(note) - 36; // C3 is middle C
}
const ac = getAudioContext();
// is sample from loaded samples(..)
const samples = getLoadedSamples();
if (!samples) {
throw new Error('no samples loaded');
}
const bank = samples?.[s];
if (!bank) {
throw new Error('sample not found:', s, 'try one of ' + Object.keys(samples));
}
if (typeof bank !== 'object') {
throw new Error('wrong format for sample bank:', s);
}
let sampleUrl;
if (Array.isArray(bank)) {
sampleUrl = bank[n % bank.length];
} else {
if (!note) {
throw new Error('no note(...) set for sound', s);
}
const midiDiff = (noteA) => toMidi(noteA) - toMidi(note);
// object format will expect keys as notes
const closest = Object.keys(bank)
.filter((k) => !k.startsWith('_'))
.reduce(
(closest, key, j) => (!closest || Math.abs(midiDiff(key)) < Math.abs(midiDiff(closest)) ? key : closest),
null,
);
transpose = -midiDiff(closest); // semitones to repitch
sampleUrl = bank[closest][n % bank[closest].length];
}
const buffer = await loadBuffer(sampleUrl, ac);
const bufferSource = ac.createBufferSource();
bufferSource.buffer = buffer;
const playbackRate = 1.0 * Math.pow(2, transpose / 12);
// bufferSource.playbackRate.value = Math.pow(2, transpose / 12);
bufferSource.playbackRate.value = playbackRate;
return bufferSource;
};
const splitSN = (s, n) => {
if (!s.includes(':')) {
return [s, n];
}
let [s2, n2] = s.split(':');
if (isNaN(Number(n2))) {
return [s, n];
}
return [s2, n2];
Pattern.prototype.filter = function (type, frequency) {
return patternify2(Pattern.prototype._filter)(reify(type), reify(frequency), this);
};
Pattern.prototype.out = function () {
return this.onTrigger(async (t, hap, ct) => {
const ac = getAudioContext();
// calculate correct time (tone.js workaround)
t = ac.currentTime + t - ct;
// destructure value
let {
freq,
s,
sf,
clip = 0, // if 1, samples will be cut off when the hap ends
n = 0,
note,
gain = 1,
cutoff,
resonance = 1,
hcutoff,
hresonance = 1,
bandf,
bandq = 1,
pan,
attack = 0.001,
decay = 0.05,
sustain = 0.5,
release = 0.001,
speed = 1, // sample playback speed
begin = 0,
end = 1,
} = hap.value;
const { velocity = 1 } = hap.context;
gain *= velocity; // legacy fix for velocity
// the chain will hold all audio nodes that connect to each other
const chain = [];
if (typeof s === 'string') {
[s, n] = splitSN(s, n);
const master = getAudioContext().createGain();
master.gain.value = 0.1;
master.connect(getAudioContext().destination);
return this.withAudioNode((t, e, node) => {
if (!node) {
console.warn('out: no source! call .osc() first');
}
if (typeof note === 'string') {
[note, n] = splitSN(note, n);
}
if (!s || ['sine', 'square', 'triangle', 'sawtooth'].includes(s)) {
// with synths, n and note are the same thing
n = note || n;
if (typeof n === 'string') {
n = toMidi(n); // e.g. c3 => 48
}
// get frequency
if (!freq && typeof n === 'number') {
freq = fromMidi(n); // + 48);
}
// make oscillator
const o = getOscillator({ t, s, freq, duration: hap.duration, release });
chain.push(o);
// level down oscillators as they are really loud compared to samples i've tested
const g = ac.createGain();
g.gain.value = 0.3;
chain.push(g);
// TODO: make adsr work with samples without pops
// envelope
const adsr = getADSR(attack, decay, sustain, release, 1, t, t + hap.duration);
chain.push(adsr);
} else {
// load sample
if (speed === 0) {
// no playback
return;
}
if (!s) {
console.warn('no sample specified');
return;
}
const soundfont = getSoundfontKey(s);
let bufferSource;
try {
if (soundfont) {
// is soundfont
bufferSource = await globalThis.getFontBufferSource(soundfont, note || n, ac);
} else {
// is sample from loaded samples(..)
bufferSource = await getSampleBufferSource(s, n, note);
}
} catch (err) {
console.warn(err);
return;
}
// asny stuff above took too long?
if (ac.currentTime > t) {
console.warn('sample still loading:', s, n);
return;
}
if (!bufferSource) {
console.warn('no buffer source');
return;
}
bufferSource.playbackRate.value = Math.abs(speed) * bufferSource.playbackRate.value;
// TODO: nudge, unit, cut, loop
let duration = soundfont || clip ? hap.duration : bufferSource.buffer.duration;
// let duration = bufferSource.buffer.duration;
const offset = begin * duration;
duration = ((end - begin) * duration) / Math.abs(speed);
if (soundfont || clip) {
bufferSource.start(t, offset); // duration does not work here for some reason
} else {
bufferSource.start(t, offset, duration);
}
chain.push(bufferSource);
if (soundfont || clip) {
const env = ac.createGain();
const releaseLength = 0.1;
env.gain.value = 0.6;
env.gain.setValueAtTime(env.gain.value, t + duration);
env.gain.linearRampToValueAtTime(0, t + duration + releaseLength);
// env.gain.linearRampToValueAtTime(0, t + duration + releaseLength);
chain.push(env);
bufferSource.stop(t + duration + releaseLength);
} else {
bufferSource.stop(t + duration);
}
}
// master out
const master = ac.createGain();
master.gain.value = gain;
chain.push(master);
// filters
cutoff !== undefined && chain.push(getFilter('lowpass', cutoff, resonance));
hcutoff !== undefined && chain.push(getFilter('highpass', hcutoff, hresonance));
bandf !== undefined && chain.push(getFilter('bandpass', bandf, bandq));
// TODO vowel
// TODO delay / delaytime / delayfeedback
// panning
if (pan !== undefined) {
const panner = ac.createStereoPanner();
panner.pan.value = 2 * pan - 1;
chain.push(panner);
}
// master out
/* const master = ac.createGain();
master.gain.value = 0.8 * gain;
chain.push(master); */
chain.push(ac.destination);
// connect chain elements together
chain.slice(1).reduce((last, current) => last.connect(current), chain[0]);
node?.connect(master);
})._withHap((hap) => {
const onTrigger = (time, e) => e.context?.createAudioNode?.(time, e);
return hap.setContext({ ...hap.context, onTrigger });
});
};
Pattern.prototype.define('wave', (type, pat) => pat.wave(type), { patternified: true });
+1
View File
@@ -1 +1,2 @@
export * from './webdirt.mjs';
export * from './sampler.mjs';
-28
View File
@@ -1,28 +0,0 @@
{
"name": "@strudel.cycles/webdirt",
"version": "0.1.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@strudel.cycles/webdirt",
"version": "0.1.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"WebDirt": "github:dktr0/WebDirt"
}
},
"node_modules/WebDirt": {
"name": "webdirt",
"version": "1.0.0",
"resolved": "git+ssh://git@github.com/dktr0/WebDirt.git#425dc8fd023440d9c61ffdb8642e44e2710faea0",
"license": "ISC"
}
},
"dependencies": {
"WebDirt": {
"version": "git+ssh://git@github.com/dktr0/WebDirt.git#425dc8fd023440d9c61ffdb8642e44e2710faea0",
"from": "WebDirt@github:dktr0/WebDirt"
}
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/webdirt",
"version": "0.1.2",
"version": "0.1.0",
"description": "WebDirt integration for Strudel",
"main": "index.mjs",
"type": "module",
@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.1.2",
"@strudel.cycles/core": "^0.1.0",
"WebDirt": "github:dktr0/WebDirt"
}
}
@@ -1,8 +1,6 @@
const bufferCache = {}; // string: Promise<ArrayBuffer>
const loadCache = {}; // string: Promise<ArrayBuffer>
export const getCachedBuffer = (url) => bufferCache[url];
export const loadBuffer = (url, ac) => {
if (!loadCache[url]) {
loadCache[url] = fetch(url)
@@ -93,32 +91,16 @@ export const loadGithubSamples = async (path, nameFn) => {
*
*/
export const samples = (sampleMap, baseUrl = sampleMap._base || '') => {
export const samples = (sampleMap, baseUrl = '') => {
sampleCache.current = {
...sampleCache.current,
...Object.fromEntries(
Object.entries(sampleMap).map(([key, value]) => {
if (typeof value === 'string') {
value = [value];
}
if (typeof value !== 'object') {
throw new Error('wrong sample map format for ' + key);
}
baseUrl = value._base || baseUrl;
const replaceUrl = (v) => (baseUrl + v).replace('github:', 'https://raw.githubusercontent.com/');
if (Array.isArray(value)) {
return [key, value.map(replaceUrl)];
}
// must be object
return [
key,
Object.fromEntries(
Object.entries(value).map(([note, samples]) => {
return [note, (typeof samples === 'string' ? [samples] : samples).map(replaceUrl)];
}),
),
];
}),
Object.entries(sampleMap).map(([key, value]) => [
key,
(typeof value === 'string' ? [value] : value).map((v) =>
(baseUrl + v).replace('github:', 'https://raw.githubusercontent.com/'),
),
]),
),
};
};
+1 -1
View File
@@ -1,7 +1,7 @@
import * as strudel from '@strudel.cycles/core';
const { Pattern } = strudel;
import * as WebDirt from 'WebDirt';
import { getLoadedSamples, loadBuffer, getLoadedBuffer } from '@strudel.cycles/webaudio';
import { getLoadedSamples, loadBuffer, getLoadedBuffer } from './sampler.mjs';
let webDirt;
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/xen",
"version": "0.1.3",
"version": "0.1.1",
"description": "Xenharmonic API for strudel",
"main": "index.mjs",
"scripts": {
@@ -24,6 +24,6 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.1.2"
"@strudel.cycles/core": "^0.1.0"
}
}
-2
View File
@@ -22,5 +22,3 @@ dist-ssr
*.njsproj
*.sln
*.sw?
oldtunes.mjs
+10 -506
View File
@@ -8,8 +8,6 @@
"name": "@strudel.cycles/repl",
"version": "0.0.0",
"dependencies": {
"@supabase/supabase-js": "^1.35.3",
"nanoid": "^4.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
@@ -511,59 +509,6 @@
"node": ">= 8.0.0"
}
},
"node_modules/@supabase/functions-js": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-1.3.3.tgz",
"integrity": "sha512-35vO9niHRtzGe1QSvXKdOfvGPiX2KC44dGpWU6y0/gZCfTIgog/soU9HqABzQC/maVowO3hGLWfez5aN0MKfow==",
"dependencies": {
"cross-fetch": "^3.1.5"
}
},
"node_modules/@supabase/gotrue-js": {
"version": "1.22.16",
"resolved": "https://registry.npmjs.org/@supabase/gotrue-js/-/gotrue-js-1.22.16.tgz",
"integrity": "sha512-t/tR87anihvyc9ePk53NF2CG8yzTDiWOt0ReZpr7sRKV91sHNLbghVMsMDwPONWnVQ9V2/qfKutuAvPGTB/Dew==",
"dependencies": {
"cross-fetch": "^3.0.6"
}
},
"node_modules/@supabase/postgrest-js": {
"version": "0.37.3",
"resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-0.37.3.tgz",
"integrity": "sha512-Iqwv9D80YGkCi60Zl2lsV04WxOmjFqxpFmxoZ5xUqsVZHvIoAbJ9tMM3+0F7VkZZbsjnaYHrpJ58xLxU7cgy2w==",
"dependencies": {
"cross-fetch": "^3.1.5"
}
},
"node_modules/@supabase/realtime-js": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-1.7.2.tgz",
"integrity": "sha512-DMUaFIKj7KszGtWTTQbhMmUzZf7UnwYqySsmY+G8HgYxvY3ZaVa+DZD0I6ofgr4OLNr0po/ODM2a4lf5m5GNBg==",
"dependencies": {
"@types/phoenix": "^1.5.4",
"websocket": "^1.0.34"
}
},
"node_modules/@supabase/storage-js": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-1.7.1.tgz",
"integrity": "sha512-0ZlKlGgB3Qzhu07fts5pr2Y+c4xW58d7sDOB9m6nSfltS6SSfBPmqtdhU0zV9vy3vAjC74XeqUcpMhHP5E+aoA==",
"dependencies": {
"cross-fetch": "^3.1.0"
}
},
"node_modules/@supabase/supabase-js": {
"version": "1.35.3",
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-1.35.3.tgz",
"integrity": "sha512-uwO8OVdMFsGZNZ1xQhFz22+PSW0EWYZ5xVq+jQeGz8nhabEu+Q9Uyep/bcNzOpyPJRzbGfxSPRzgAdAxfJgFhw==",
"dependencies": {
"@supabase/functions-js": "^1.3.3",
"@supabase/gotrue-js": "^1.22.14",
"@supabase/postgrest-js": "^0.37.2",
"@supabase/realtime-js": "^1.7.2",
"@supabase/storage-js": "^1.7.0"
}
},
"node_modules/@tailwindcss/typography": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.2.tgz",
@@ -578,11 +523,6 @@
"tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || insiders"
}
},
"node_modules/@types/phoenix": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.5.4.tgz",
"integrity": "sha512-L5eZmzw89eXBKkiqVBcJfU1QGx9y+wurRIEgt0cuLH0hwNtVUxtx+6cu0R2STwWj468sjXyBYPYDtGclUd1kjQ=="
},
"node_modules/@vitejs/plugin-react": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-1.3.2.tgz",
@@ -748,18 +688,6 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
"node_modules/bufferutil": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz",
"integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==",
"hasInstallScript": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/camelcase-css": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
@@ -862,14 +790,6 @@
"safe-buffer": "~5.1.1"
}
},
"node_modules/cross-fetch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
"integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
"dependencies": {
"node-fetch": "2.6.7"
}
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -882,15 +802,6 @@
"node": ">=4"
}
},
"node_modules/d": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
"integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
"dependencies": {
"es5-ext": "^0.10.50",
"type": "^1.0.1"
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -949,39 +860,6 @@
"integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==",
"dev": true
},
"node_modules/es5-ext": {
"version": "0.10.61",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz",
"integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==",
"hasInstallScript": true,
"dependencies": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
"next-tick": "^1.1.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
"dependencies": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"node_modules/es6-symbol": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
"dependencies": {
"d": "^1.0.1",
"ext": "^1.1.2"
}
},
"node_modules/esbuild": {
"version": "0.14.39",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.39.tgz",
@@ -1361,19 +1239,6 @@
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true
},
"node_modules/ext": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
"integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
"dependencies": {
"type": "^2.5.0"
}
},
"node_modules/ext/node_modules/type": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz",
"integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ=="
},
"node_modules/fast-glob": {
"version": "3.2.11",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
@@ -1561,11 +1426,6 @@
"node": ">=0.12.0"
}
},
"node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -1668,48 +1528,15 @@
"dev": true
},
"node_modules/nanoid": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
"integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==",
"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.js"
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^14 || ^16 || >=18"
}
},
"node_modules/next-tick": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
},
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-gyp-build": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz",
"integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==",
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/node-releases": {
@@ -1887,18 +1714,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/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -2165,36 +1980,6 @@
"node": ">=8.0"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
"integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
},
"node_modules/typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"dependencies": {
"is-typedarray": "^1.0.0"
}
},
"node_modules/utf-8-validate": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz",
"integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==",
"hasInstallScript": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -2238,49 +2023,6 @@
}
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/websocket": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
"integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
"dependencies": {
"bufferutil": "^4.0.1",
"debug": "^2.2.0",
"es5-ext": "^0.10.50",
"typedarray-to-buffer": "^3.1.5",
"utf-8-validate": "^5.0.2",
"yaeti": "^0.0.6"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/websocket/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/websocket/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@@ -2290,14 +2032,6 @@
"node": ">=0.4"
}
},
"node_modules/yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
"integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==",
"engines": {
"node": ">=0.10.32"
}
},
"node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
@@ -2668,59 +2402,6 @@
"picomatch": "^2.2.2"
}
},
"@supabase/functions-js": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-1.3.3.tgz",
"integrity": "sha512-35vO9niHRtzGe1QSvXKdOfvGPiX2KC44dGpWU6y0/gZCfTIgog/soU9HqABzQC/maVowO3hGLWfez5aN0MKfow==",
"requires": {
"cross-fetch": "^3.1.5"
}
},
"@supabase/gotrue-js": {
"version": "1.22.16",
"resolved": "https://registry.npmjs.org/@supabase/gotrue-js/-/gotrue-js-1.22.16.tgz",
"integrity": "sha512-t/tR87anihvyc9ePk53NF2CG8yzTDiWOt0ReZpr7sRKV91sHNLbghVMsMDwPONWnVQ9V2/qfKutuAvPGTB/Dew==",
"requires": {
"cross-fetch": "^3.0.6"
}
},
"@supabase/postgrest-js": {
"version": "0.37.3",
"resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-0.37.3.tgz",
"integrity": "sha512-Iqwv9D80YGkCi60Zl2lsV04WxOmjFqxpFmxoZ5xUqsVZHvIoAbJ9tMM3+0F7VkZZbsjnaYHrpJ58xLxU7cgy2w==",
"requires": {
"cross-fetch": "^3.1.5"
}
},
"@supabase/realtime-js": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-1.7.2.tgz",
"integrity": "sha512-DMUaFIKj7KszGtWTTQbhMmUzZf7UnwYqySsmY+G8HgYxvY3ZaVa+DZD0I6ofgr4OLNr0po/ODM2a4lf5m5GNBg==",
"requires": {
"@types/phoenix": "^1.5.4",
"websocket": "^1.0.34"
}
},
"@supabase/storage-js": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-1.7.1.tgz",
"integrity": "sha512-0ZlKlGgB3Qzhu07fts5pr2Y+c4xW58d7sDOB9m6nSfltS6SSfBPmqtdhU0zV9vy3vAjC74XeqUcpMhHP5E+aoA==",
"requires": {
"cross-fetch": "^3.1.0"
}
},
"@supabase/supabase-js": {
"version": "1.35.3",
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-1.35.3.tgz",
"integrity": "sha512-uwO8OVdMFsGZNZ1xQhFz22+PSW0EWYZ5xVq+jQeGz8nhabEu+Q9Uyep/bcNzOpyPJRzbGfxSPRzgAdAxfJgFhw==",
"requires": {
"@supabase/functions-js": "^1.3.3",
"@supabase/gotrue-js": "^1.22.14",
"@supabase/postgrest-js": "^0.37.2",
"@supabase/realtime-js": "^1.7.2",
"@supabase/storage-js": "^1.7.0"
}
},
"@tailwindcss/typography": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.2.tgz",
@@ -2732,11 +2413,6 @@
"lodash.merge": "^4.6.2"
}
},
"@types/phoenix": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.5.4.tgz",
"integrity": "sha512-L5eZmzw89eXBKkiqVBcJfU1QGx9y+wurRIEgt0cuLH0hwNtVUxtx+6cu0R2STwWj468sjXyBYPYDtGclUd1kjQ=="
},
"@vitejs/plugin-react": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-1.3.2.tgz",
@@ -2843,14 +2519,6 @@
"picocolors": "^1.0.0"
}
},
"bufferutil": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz",
"integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==",
"requires": {
"node-gyp-build": "^4.3.0"
}
},
"camelcase-css": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
@@ -2925,29 +2593,12 @@
"safe-buffer": "~5.1.1"
}
},
"cross-fetch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
"integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
"requires": {
"node-fetch": "2.6.7"
}
},
"cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true
},
"d": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
"integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
"requires": {
"es5-ext": "^0.10.50",
"type": "^1.0.1"
}
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -2992,35 +2643,6 @@
"integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==",
"dev": true
},
"es5-ext": {
"version": "0.10.61",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz",
"integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==",
"requires": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
"next-tick": "^1.1.0"
}
},
"es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
"requires": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"es6-symbol": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
"requires": {
"d": "^1.0.1",
"ext": "^1.1.2"
}
},
"esbuild": {
"version": "0.14.39",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.39.tgz",
@@ -3207,21 +2829,6 @@
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true
},
"ext": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
"integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
"requires": {
"type": "^2.5.0"
},
"dependencies": {
"type": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz",
"integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ=="
}
}
},
"fast-glob": {
"version": "3.2.11",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
@@ -3358,11 +2965,6 @@
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -3441,27 +3043,10 @@
"dev": true
},
"nanoid": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
"integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg=="
},
"next-tick": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
},
"node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
}
},
"node-gyp-build": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz",
"integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ=="
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"dev": true
},
"node-releases": {
"version": "2.0.4",
@@ -3519,14 +3104,6 @@
"nanoid": "^3.3.3",
"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": {
@@ -3748,32 +3325,6 @@
"is-number": "^7.0.0"
}
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
"integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
},
"typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"requires": {
"is-typedarray": "^1.0.0"
}
},
"utf-8-validate": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz",
"integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==",
"requires": {
"node-gyp-build": "^4.3.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -3793,59 +3344,12 @@
"rollup": "^2.59.0"
}
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"websocket": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
"integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
"requires": {
"bufferutil": "^4.0.1",
"debug": "^2.2.0",
"es5-ext": "^0.10.50",
"typedarray-to-buffer": "^3.1.5",
"utf-8-validate": "^5.0.2",
"yaeti": "^0.0.6"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
}
}
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"dev": true
},
"yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
"integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug=="
},
"yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+1 -3
View File
@@ -3,7 +3,7 @@
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite --host",
"dev": "vite",
"start": "vite",
"build": "vite build",
"preview": "vite preview",
@@ -15,8 +15,6 @@
"static": "npx serve ../docs"
},
"dependencies": {
"@supabase/supabase-js": "^1.35.3",
"nanoid": "^4.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+13 -92
View File
@@ -6,24 +6,14 @@ This program is free software: you can redistribute it and/or modify it under th
import controls from '@strudel.cycles/core/controls.mjs';
import { evalScope, evaluate } from '@strudel.cycles/eval';
import { CodeMirror, cx, flash, useHighlighting, useRepl, useWebMidi } from '@strudel.cycles/react';
import { CodeMirror, cx, useHighlighting, useRepl, useWebMidi } from '@strudel.cycles/react';
import { getDefaultSynth, cleanupDraw, cleanupUi, Tone } from '@strudel.cycles/tone';
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
import './App.css';
import logo from './logo.svg';
import * as tunes from './tunes.mjs';
import { prebake } from './prebake.mjs';
import * as WebDirt from 'WebDirt';
import { loadWebDirt } from '@strudel.cycles/webdirt';
import { resetLoadedSamples, getAudioContext } from '@strudel.cycles/webaudio';
import { createClient } from '@supabase/supabase-js';
import { nanoid } from 'nanoid';
// Create a single supabase client for interacting with your database
const supabase = createClient(
'https://pidxdsxphlhzjnzmifth.supabase.co',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM',
);
import { loadWebDirt, resetLoadedSamples } from '@strudel.cycles/webdirt';
evalScope(
Tone,
@@ -39,7 +29,6 @@ evalScope(
import('@strudel.cycles/osc'),
import('@strudel.cycles/webdirt'),
import('@strudel.cycles/serial'),
import('@strudel.cycles/soundfonts'),
);
loadWebDirt({
@@ -47,37 +36,13 @@ loadWebDirt({
sampleFolder: 'EmuSP12',
});
prebake();
async function initCode() {
// load code from url hash (either short hash from database or decode long hash)
try {
const initialUrl = window.location.href;
const hash = initialUrl.split('?')[1]?.split('#')?.[0];
const codeParam = window.location.href.split('#')[1];
// looking like https://strudel.tidalcycles.org/?J01s5i1J0200 (fixed hash length)
if (codeParam) {
console.log('decode hash from url');
// looking like https://strudel.tidalcycles.org/#ImMzIGUzIg%3D%3D (hash length depends on code length)
return atob(decodeURIComponent(codeParam || ''));
} else if (hash) {
return supabase
.from('code')
.select('code')
.eq('hash', hash)
.then(({ data, error }) => {
if (error) {
console.warn('failed to load hash', err);
}
if (data.length) {
console.log('load hash from database', hash);
return data[0].code;
}
});
}
} catch (err) {
console.warn('failed to decode', err);
}
const initialUrl = window.location.href;
const codeParam = window.location.href.split('#')[1];
let decoded;
try {
decoded = atob(decodeURIComponent(codeParam || ''));
} catch (err) {
console.warn('failed to decode', err);
}
function getRandomTune() {
@@ -92,7 +57,6 @@ const isEmbedded = window.location !== window.parent.location;
function App() {
// const [editor, setEditor] = useState();
const [view, setView] = useState();
const [lastShared, setLastShared] = useState();
const {
setCode,
setPattern,
@@ -109,12 +73,9 @@ function App() {
pushLog,
pending,
} = useRepl({
tune: '// LOADING...',
tune: decoded || randomTune,
defaultSynth,
});
useEffect(() => {
initCode().then((decoded) => setCode(decoded || randomTune));
}, []);
const logBox = useRef();
// scroll log box to bottom when log changes
useLayoutEffect(() => {
@@ -130,7 +91,6 @@ function App() {
if (e.ctrlKey || e.altKey) {
if (e.code === 'Enter') {
e.preventDefault();
flash(view);
await activateCode();
} else if (e.code === 'Period') {
cycle.stop();
@@ -140,7 +100,7 @@ function App() {
};
window.addEventListener('keydown', handleKeyPress, true);
return () => window.removeEventListener('keydown', handleKeyPress, true);
}, [pattern, code, activateCode, cycle, view]);
}, [pattern, code, activateCode, cycle]);
useHighlighting({ view, pattern, active: cycle.started && !activeCode?.includes('strudel disable-highlighting') });
@@ -179,13 +139,7 @@ function App() {
<h1 className={isEmbedded ? 'text-l' : 'text-xl'}>Strudel {isEmbedded ? 'Mini ' : ''}REPL</h1>
</div>
<div className="flex">
<button
onClick={() => {
getAudioContext().resume(); // fixes no sound in ios webkit
togglePlay();
}}
className={cx('hover:bg-gray-300', !isEmbedded ? 'p-2' : 'px-2')}
>
<button onClick={() => togglePlay()} className={cx('hover:bg-gray-300', !isEmbedded ? 'p-2' : 'px-2')}>
{!pending ? (
<span className={cx('flex items-center', isEmbedded ? 'w-16' : 'w-16')}>
{cycle.started ? (
@@ -221,7 +175,6 @@ function App() {
cleanupDraw();
cleanupUi();
resetLoadedSamples();
prebake();
const parsed = await evaluate(_code);
setPattern(parsed.pattern);
setActiveCode(_code);
@@ -235,38 +188,6 @@ function App() {
<a href="./tutorial">📚 tutorial</a>
</button>
)}
{!isEmbedded && (
<button
className={cx('cursor-pointer hover:bg-gray-300', !isEmbedded ? 'p-2' : 'px-2')}
onClick={async () => {
const codeToShare = activeCode || code;
if (lastShared === codeToShare) {
// alert('Link already generated!');
pushLog(`Link already generated!`);
return;
}
// generate uuid in the browser
const hash = nanoid(12);
const { data, error } = await supabase.from('code').insert([{ code: codeToShare, hash }]);
if (!error) {
setLastShared(activeCode || code);
const shareUrl = window.location.origin + '?' + hash;
// copy shareUrl to clipboard
navigator.clipboard.writeText(shareUrl);
const message = `Link copied to clipboard: ${shareUrl}`;
// alert(message);
pushLog(message);
} else {
console.log('error', error);
const message = `Error: ${error.message}`;
// alert(message);
pushLog(message);
}
}}
>
📣 share{lastShared && lastShared === (activeCode || code) ? 'd!' : ''}
</button>
)}
{isEmbedded && (
<button className={cx('hover:bg-gray-300 px-2')}>
<a href={window.location.href} target="_blank" rel="noopener noreferrer" title="Open in REPL">
-57
View File
@@ -1,57 +0,0 @@
import { Pattern, toMidi } from '@strudel.cycles/core';
import { samples } from '@strudel.cycles/webaudio';
export function prebake() {
samples(
{
piano: {
A0: 'A0v8.mp3',
C1: 'C1v8.mp3',
Ds1: 'Ds1v8.mp3',
Fs1: 'Fs1v8.mp3',
A1: 'A1v8.mp3',
C2: 'C2v8.mp3',
Ds2: 'Ds2v8.mp3',
Fs2: 'Fs2v8.mp3',
A2: 'A2v8.mp3',
C3: 'C3v8.mp3',
Ds3: 'Ds3v8.mp3',
Fs3: 'Fs3v8.mp3',
A3: 'A3v8.mp3',
C4: 'C4v8.mp3',
Ds4: 'Ds4v8.mp3',
Fs4: 'Fs4v8.mp3',
A4: 'A4v8.mp3',
C5: 'C5v8.mp3',
Ds4: 'Ds4v8.mp3',
Fs5: 'Fs5v8.mp3',
A5: 'A5v8.mp3',
C6: 'C6v8.mp3',
Ds6: 'Ds6v8.mp3',
Fs6: 'Fs6v8.mp3',
A6: 'A6v8.mp3',
C7: 'C7v8.mp3',
Ds7: 'Ds7v8.mp3',
Fs7: 'Fs7v8.mp3',
A7: 'A7v8.mp3',
C8: 'C8v8.mp3',
},
},
// https://archive.org/details/SalamanderGrandPianoV3
// License: CC-by http://creativecommons.org/licenses/by/3.0/ Author: Alexander Holm
'./piano/',
);
}
const maxPan = toMidi('C8');
const panwidth = (pan, width) => pan * width + (1 - width) / 2;
Pattern.prototype.piano = function () {
return this.clip(1)
.s('piano')
.fmap((value) => {
// pan by pitch
const pan = panwidth(Math.min(toMidi(value.note) / maxPan, 1), 0.5);
return { ...value, pan: (value.pan || 1) * pan };
});
};
+1 -12
View File
@@ -6,8 +6,6 @@
import { evaluate } from '@strudel.cycles/eval';
import { extend } from '@strudel.cycles/eval';
import * as strudel from '@strudel.cycles/core';
import * as webaudio from '@strudel.cycles/webaudio';
import controls from '@strudel.cycles/core/controls.mjs';
// import gist from '@strudel.cycles/core/gist.js';
import { mini } from '@strudel.cycles/mini/mini.mjs';
// import { Tone } from '@strudel.cycles/tone';
@@ -31,8 +29,6 @@ import '@strudel.cycles/xen/xen.mjs';
// import '@strudel.cycles/serial/serial.mjs';
// import controls from '@strudel.cycles/core/controls.mjs';
import { prebake } from './prebake.mjs';
class MockedNode {
chain() {
return this;
@@ -87,9 +83,6 @@ const toneHelpersMocked = {
strudel.Pattern.prototype.tone = function () {
return this;
};
strudel.Pattern.prototype.webdirt = function () {
return this;
};
// draw mock
strudel.Pattern.prototype.pianoroll = function () {
@@ -123,8 +116,6 @@ const uiHelpersMocked = {
backgroundImage: id,
};
prebake();
// TODO: refactor to evalScope
extend(
// Tone,
@@ -132,8 +123,6 @@ extend(
strudel.Pattern.prototype.bootstrap(),
toneHelpersMocked,
uiHelpersMocked,
controls,
webaudio,
/* controls,
toneHelpers,
voicingHelpers,
@@ -192,6 +181,6 @@ export const testCycles = {
randomBells: 24,
waa: 16,
waar: 16,
hyperpop: 10,
hyperpop: 60,
festivalOfFingers3: 16,
};
+60 -263
View File
@@ -444,7 +444,7 @@ export const barryHarris = `backgroundImage(
.scale('C bebop major')
.transpose("<0 1 2 1>/8")
.slow(2)
.note().piano().out()
.tone((await piano()).toDestination())
`;
export const blippyRhodes = `const delay = new FeedbackDelay(1/12, .4).chain(vol(0.3), out());
@@ -551,7 +551,7 @@ export const risingEnemy = `stack(
.transpose("<0 1 2 1>/2".early(0.5))
.transpose(5)
.fast(2 / 3)
.note().piano().out()`;
.tone((await piano()).toDestination())`;
export const festivalOfFingers = `const chords = "<Cm7 Fm7 G7 F#7>";
stack(
@@ -563,7 +563,7 @@ stack(
.scaleTranspose("0 4 0 6".early(".125 .5")).layer(scaleTranspose("0,<2 [4,6] [5,7]>/4"))
).slow(2)
.velocity(sine.struct("x*8").add(3/5).mul(2/5).fast(8))
.note().piano().out()`;
.tone((await piano()).chain(out()))`;
export const festivalOfFingers2 = `const chords = "<Cm7 Fm7 G7 F#7 >";
const scales = cat('C minor','F dorian','G dorian','F# mixolydian')
@@ -577,35 +577,36 @@ stack(
).slow(2).transpose(-1)
.legato(cosine.struct("x*8").add(4/5).mul(4/5).fast(8))
.velocity(sine.struct("x*8").add(3/5).mul(2/5).fast(8))
.note().piano().out().fast(3/4)`;
.tone((await piano()).chain(out())).fast(3/4)`;
// iter, echo, echoWith
// iter, stut, stutWith
export const undergroundPlumber = `backgroundImage('https://images.nintendolife.com/news/2016/08/video_exploring_the_funky_inspiration_for_the_super_mario_bros_underground_theme/large.jpg',{ className:'darken' })
samples({ bd: 'bd/BT0A0D0.wav', sn: 'sn/ST0T0S3.wav', hh: 'hh/000_hh3closedhh.wav', cp: 'cp/HANDCLP0.wav',
const drums = await players({
bd: 'bd/BT0A0D0.wav',
sn: 'sn/ST0T0S3.wav',
hh: 'hh/000_hh3closedhh.wav',
cp: 'cp/HANDCLP0.wav',
}, 'https://loophole-letters.vercel.app/samples/tidal/')
const h = x=>x.transpose("<0@2 5 0 7 5 0 -5>/2")
stack(
s("<<bd*2 bd> sn> hh").fast(2).gain(.7),
"[c2 a1 bb1 ~] ~"
.echo(2, 1/16, 1)
.legato(.4)
.slow(2)
.layer(h)
.note().s('square')
.cutoff(400).decay(.12).sustain(0)
,
"[g2,[c3 eb3]]".iter(4)
.echoWith(4, 1/8, (x,n)=>x.transpose(n*12).velocity(Math.pow(.4,n)))
.legato(.1)
.layer(h).note()
).out()
"<<bd*2 bd> sn> hh".fast(4).slow(2).tone(drums.chain(vol(.5),out())),
stack(
"[c2 a1 bb1 ~] ~"
.stut(2, .6, 1/16)
.legato(.4)
.slow(2)
.tone(synth({...osc('sawtooth7'),...adsr(0,.3,0)}).chain(out())),
"[g2,[c3 eb3]]".iter(4)
.stutWith(4, 1/8, (x,n)=>x.transpose(n*12).velocity(Math.pow(.4,n)))
.legato(.1)
)
.transpose("<0@2 5 0 7 5 0 -5>/2")
)
.fast(2/3)
.pianoroll({})`;
.pianoroll({minMidi:21,maxMidi:180, background:'transparent',inactive:'#3F8F90',active:'#DE3123'})`;
export const bridgeIsOver = `samples({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'})
export const bridgeIsOver = `const breaks = (await players({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'})).chain(out())
stack(
stack(
"c3*2 [[c3@1.4 bb2] ab2] gb2*2 <[[gb2@1.4 ab2] bb2] gb2>".legato(".5 1".fast(2)).velocity(.8),
@@ -617,11 +618,9 @@ stack(
.velocity(.7)
.legato(.5)
.stut(3, .5, 1/8)
).transpose(-1).note().piano(),
s("mad").slow(2)
).cpm(78).slow(4)
.out()
.pianoroll()
).transpose(-1).tone((await piano()).chain(out())),
"mad".slow(2).tone(breaks)
).cpm(78).slow(4).pianoroll()
`;
export const goodTimes = `const scale = cat('C3 dorian','Bb2 major').slow(4);
@@ -638,9 +637,10 @@ stack(
.legato("2")
.scale(scale)
.scaleTranspose("<0>".slow(4))
.transpose(5)
.note().piano().out()
.tone((await piano()).chain(out()))
//.midi()
.velocity(.8)
.transpose(5)
.slow(2)
.pianoroll({maxMidi:100,minMidi:20})`;
@@ -651,7 +651,7 @@ export const echoPiano = `"<0 2 [4 6](3,4,1) 3*2>"
.off(1/2, x=>x.scaleTranspose(6).color('steelblue'))
.legato(.5)
.echo(4, 1/8, .5)
.note().piano().out()
.tone((await piano()).chain(out()))
.pianoroll()`;
export const sml1 = `
@@ -687,7 +687,7 @@ stack(
f3!2 e3!2 ab3!2 ~!2
>\`
.legato(.5)
).fast(2) // .note().piano().out()`;
).fast(2) //.tone((await piano()).chain(out()))`;
export const speakerman = `backgroundImage('https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fi.ytimg.com%2Fvi%2FXR0rKqW3VwY%2Fmaxresdefault.jpg&f=1&nofb=1',
{ className:'darken', style:'background-size:cover'})
@@ -728,7 +728,7 @@ bell = bell.chain(vol(0.6).connect(delay),out());
.slow(6)
.pianoroll({minMidi:20,maxMidi:120,background:'transparent'})`;
/* export const waa = `n("a4 [a3 c3] a3 c3")
export const waa = `"a4 [a3 c3] a3 c3"
.sub("<7 12>/2")
.off(1/8, add("12"))
.off(1/4, add("7"))
@@ -736,37 +736,23 @@ bell = bell.chain(vol(0.6).connect(delay),out());
.slow(2)
.wave("sawtooth square")
.filter('lowpass', "<2000 1000 500>")
.out()`; */
.out()`;
export const waa = `n(
"a4 [a3 c3] a3 c3"
.sub("<7 12>/2")
.off(1/8, add("12"))
.off(1/4, add("7"))
)
.legato(.5)
.slow(2)
.s("sawtooth square")
.cutoff("<2000 1000 500>")
.out()
`;
export const waa2 = `n(
"a4 [a3 c3] a3 c3"
.sub("<7 12 5 12>".slow(2))
.off(1/4,x=>x.add(7))
.off(1/8,x=>x.add(12))
)
.slow(2)
.legato(sine.range(0.3, 2).slow(28))
.s("sawtooth square".fast(2))
.cutoff(cosine.range(500,4000).slow(16))
.out()`;
export const waar = `"a4 [a3 c3] a3 c3".color('#F9D649')
.sub("<7 12 5 12>".slow(2))
.off(1/4,x=>x.add(7).color("#FFFFFF #0C3AA1 #C63928"))
.off(1/8,x=>x.add(12).color('#215CB6'))
.slow(2)
.legato(sine.range(0.3, 2).slow(28))
.wave("sawtooth square".fast(2))
.filter('lowpass', cosine.range(500,4000).slow(16))
.out()
.pianoroll({minMidi:20,maxMidi:120,background:'#202124'})`;
export const hyperpop = `const lfo = cosine.slow(15);
const lfo2 = sine.slow(16);
const filter1 = x=>x.cutoff(lfo2.range(300,3000));
const filter2 = x=>x.hcutoff(lfo.range(1000,6000)).cutoff(4000)
const filter1 = x=>x.filter('lowpass', lfo2.range(300,3000));
const filter2 = x=>x.filter('highpass', lfo.range(1000,6000)).filter('lowpass',4000)
const scales = cat('D3 major', 'G3 major').slow(8)
const drums = await players({
@@ -779,30 +765,24 @@ const drums = await players({
stack(
"-7 0 -7 7".struct("x(5,8,2)").fast(2).sub(7)
.scale(scales)
.n()
.s("sawtooth,square")
.gain(.3).attack(0.01).decay(0.1).sustain(.5)
.scale(scales).wave("sawtooth,square").velocity(.3).adsr(0.01,0.1,.5,0)
.apply(filter1),
"~@3 [<2 3>,<4 5>]"
.echo(4,1/16,.7)
.echo(8,1/16,.7)
.scale(scales)
.n()
.s('square').gain(.7)
.attack(0.01).decay(0.1).sustain(0)
.apply(filter1),
"6 4 2".add(14)
.wave('square').velocity(.7).adsr(0.01,0.1,0).apply(filter1),
"6 5 4".add(14)
.superimpose(sub("5"))
.fast(1).euclidLegato(3,8)
.mask("<1 0@7>")
.fast(2)
.echo(32, 1/8, .8)
.echo(32, 1/8, .9)
.scale(scales)
.n()
.s("sawtooth")
.gain(sine.range(.1,.4).slow(8))
.attack(.001).decay(.2).sustain(0)
.wave("sawtooth")
.velocity(.2)
.adsr(.01,.5,0)
.apply(filter2)
//.echo(4,1/16,.5)
).out().stack(
stack(
"bd <~@7 [~ bd]>".fast(2),
@@ -810,7 +790,7 @@ stack(
"[~ hh3]*2"
).tone(drums.chain(vol(.18),out())).fast(2)
).slow(2)
//.pianoroll({minMidi:20, maxMidi:160})
// strudel disable-highlighting`;
@@ -827,7 +807,7 @@ export const festivalOfFingers3 = `"[-7*3],0,2,6,[8 7]"
.scale(cat('D dorian','G mixolydian','C dorian','F mixolydian'))
.legato(1)
.slow(2)
.note().piano().out()
.tone((await piano()).toDestination())
//.pianoroll({maxMidi:160})`;
export const bossa = `
@@ -835,187 +815,4 @@ const scales = sequence('C minor', ['D locrian', 'G phrygian'], 'Bb2 minor', ['C
stack(
"<Cm7 [Dm7b5 G7b9] Bbm7 [Cm7b5 F7b9]>".fast(2).struct("x ~ x@3 x ~ x ~ ~ ~ x ~ x@3".late(1/8)).early(1/8).slow(2).voicings(),
"[~ [0 ~]] 0 [~ [4 ~]] 4".sub(7).restart(scales).scale(scales).early(.25)
).note().piano().out().slow(2)`;
export const customTrigger = `stack(
freq("55 [110,165] 110 [220,275]".mul("<1 <3/4 2/3>>").struct("x(3,8)").layer(x=>x.mul("1.006,.995"))),
freq("440(5,8)".legato(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8))
).s("<sawtooth square>/2")
.onTrigger((t,hap,ct)=>{
const ac = Tone.getContext().rawContext;
t = ac.currentTime + t - ct;
const { freq, s, gain = 1 } = hap.value;
const master = ac.createGain();
master.gain.value = 0.1 * gain;
master.connect(ac.destination);
const o = ac.createOscillator();
o.type = s || 'triangle';
o.frequency.value = Number(freq);
o.connect(master);
o.start(t);
o.stop(t + hap.duration);
}).stack(s("bd(3,8),hh*4,~ sd").webdirt())`;
export const bornagain = `stack(
freq("55 [110,165] 110 [220,275]".mul("<1 <3/4 2/3>>").struct("x(3,8)")
.layer(x=>x.mul("1.006,.995"))), // detune
freq("440(5,8)".legato(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8))
).s("<sawtooth square>/2")
.cutoff(perlin.range(100,4000).slow(4))
.jux(rev)
.out()
.stack(s("bd(3,8),hh*4,~ sd").webdirt())`;
export const meltingsubmarine = `samples({
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
}, 'github:tidalcycles/Dirt-Samples/master/');
stack(
s("bd,[~ <sd!3 sd(3,4,2)>],hh(3,4)") // drums
.speed(perlin.range(.7,.9)) // random sample speed variation
//.hush()
,"<a1 b1*2 a1(3,8) e2>" // 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
//.hush()
,"<Am7!3 <Em7 E7b13 Em7 Ebm7b5>>".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
//.hush()
,"a4 c5 <e6 a6>".struct("x(5,8)")
.superimpose(x=>x.add(.04)) // add second, slightly detuned voice
.add(perlin.range(0,.5)) // random pitch variation
.n() // wrap in "n"
.decay(.1).sustain(0) // make notes short
.s('triangle') // waveform
.degradeBy(perlin.range(0,.5)) // randomly controlled random removal :)
.echoWith(4,.125,(x,n)=>x.gain(.15*1/(n+1))) // echo notes
//.hush()
)
.out()
.slow(3/2)`;
export const swimmingWithSoundfonts = `stack(
n(
"~",
"~",
"~",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [F5@2 C6] A5 G5",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [Bb5 A5 G5] F5@2",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [F5@2 C6] A5 G5",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [Bb5 A5 G5] F5@2",
"A5 [F5@2 C5] A5 F5",
"Ab5 [F5@2 Ab5] G5@2",
"A5 [F5@2 C5] A5 F5",
"Ab5 [F5@2 C5] C6@2",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [Bb5 A5 G5] F5@2"
).s('Sitar: Ethnic'),
n(
"[F4,Bb4,D5] [[D4,G4,Bb4]@2 [Bb3,D4,F4]] [[G3,C4,E4]@2 [[Ab3,F4] [A3,Gb4]]] [Bb3,E4,G4]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, Bb3, Db3] [F3, Bb3, Db3]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [A3, C4, E4] [A3, C4, E4]] [~ [Ab3, C4, Eb4] [Ab3, C4, Eb4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [G3, C4, E4] [G3, C4, E4]]",
"[~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [A3, C4, E4] [A3, C4, E4]] [~ [Ab3, C4, Eb4] [Ab3, C4, Eb4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [G3, C4, E4] [G3, C4, E4]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]",
"[~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [A3, C4, F4] [A3, C4, F4]] [~ [A3, C4, F4] [A3, C4, F4]]",
"[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]",
"[~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [A3, C4, F4] [A3, C4, F4]] [~ [A3, C4, F4] [A3, C4, F4]]",
"[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]"
).s('Kalimba: Ethnic'),
n(
"[G3 G3 C3 E3]",
"[F2 D2 G2 C2]",
"[F2 D2 G2 C2]",
"[F2 A2 Bb2 B2]",
"[A2 Ab2 G2 C2]",
"[F2 A2 Bb2 B2]",
"[G2 C2 F2 F2]",
"[F2 A2 Bb2 B2]",
"[A2 Ab2 G2 C2]",
"[F2 A2 Bb2 B2]",
"[G2 C2 F2 F2]",
"[Bb2 Bb2 A2 A2]",
"[Ab2 Ab2 G2 [C2 D2 E2]]",
"[Bb2 Bb2 A2 A2]",
"[Ab2 Ab2 G2 [C2 D2 E2]]",
"[F2 A2 Bb2 B2]",
"[G2 C2 F2 F2]"
).s('Acoustic Bass: Bass')
).slow(51)
.out()`;
export const outroMusic = `samples({
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
perc: ['perc/002_perc2.wav'],
}, 'github:tidalcycles/Dirt-Samples/master/');
"C^7 Am7 Dm7 G7".slow(2).voicings()
.stack("0@6 [<1 2> <2 0> 1]@2".scale('C5 major'))
.n().slow(4)
.s('0040_FluidR3_GM_sf2_file')
.color('steelblue')
.stack(
"<-7 ~@2 [~@2 -7] -9 ~@2 [~@2 -9] -10!2 ~ [~@2 -10] -5 ~ [-3 -2 -10]@2>*2".scale('C3 major')
.n().s('sawtooth').color('brown')
)
.attack(0.05).decay(.1).sustain(.7)
.cutoff(perlin.range(800,2000))
.gain(.3)
.stack(
s("<bd!3 [bd ~ bd]> sd,hh*3,~@5 <perc perc*3>")
.speed(perlin.range(.9,1.1))
.n(3).color('gray')
).slow(3/2)
//.pianoroll({autorange:1,vertical:1,fold:0})
.out()`;
export const bassFuge = `samples({ flbass: ['00_c2_finger_long_neck.wav','01_c2_finger_short_neck.wav','02_c2_finger_long_bridge.wav','03_c2_finger_short_bridge.wav','04_c2_pick_long.wav','05_c2_pick_short.wav','06_c2_palm_mute.wav'] },
'github:cleary/samples-flbass/main/')
samples({
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
}, 'github:tidalcycles/Dirt-Samples/master/');
note("<8(3,8) <7 7*2> [4 5@3] 8>".sub(1) // sub 1 -> 1-indexed
.layer(
x=>x,
x=>x.add(7).color('steelblue')
.off(1/8,x=>x.add("2,4").off(1/8,x=>x.add(5).echo(4,.125,.5)))
.slow(2),
).scale('A1 minor'))
.s("flbass").n(0)
.gain(.3)
.cutoff(sine.slow(7).range(200,4000))
.resonance(10)
//.hcutoff(400)
.clip(1)
.stack(s("bd:1*2,~ sd:0,[~ hh:0]*2"))
.out()
.pianoroll({vertical:1})`;
).tone((await piano()).toDestination()).slow(2)`;
File diff suppressed because one or more lines are too long
+61
View File
@@ -0,0 +1,61 @@
# study: why are there so many calls?
- `pure('c3')` => 746 calls per second...
- shapeshifted: `(async()=>{return reify("c3").withLocation([1,5,20],[1,9,24])})()`Ï => same # of calls with or without shapeshifting
- without highlighting (// strudel disable-highlighting), there are only 15 calls
## call stack
this is how the ~15 calls are made for the first query:
- keypress -> activateCode -> evaluate -> safeEval -> pure -> new Pattern (pretty simple)
- query 0
- const timespan = new TimeSpan(0,1)
- Fraction(0), Fraction(1)
- onQuery(new State(timespan))
- pattern.query(state)
- pure.query(state)
- state.span.spanCycles
- end.sam() -> this.floor -> new Fraction
- begin.sam -> this.floor -> new Fraction
- begin.nextSam
- begin.sam -> this.floor -> new Fraction
- .add(1) -> new Fraction
- Fraction(0).wholeCycle -> new TimeSpan(0, 1)
- this.sam -> new Fraction(0)
- this.nextSam -> new Fraction(1)
- new Hap(TimeSpan(0,1), TimeSpan(0,1), 'c3')
- Tone.getTransport().cancel(0);
- queryNextTime = 0.5
- t = 0.6
## from simple to complicated
(all without highlighting)
- `pure('c3')`: 15 calls
- `pure('c3').fast(1)`: 74 calls
- `pure('c3').fast(1).fast(1)`: 133 calls
- `pure('c3').fast(1).fast(1).fast(1)`: 192 calls
- `pure('c3').fast(1).fast(1).fast(1).fast(1)`: 251 calls
- `pure('c3').fast(1).fast(1).fast(1).fast(1).fast(1)`: 310 calls
- `pure('c3').fast(2)`: 94 calls
- `pure('c3').fast(2).fast(2)`: 264 calls
- `pure('c3').fast(2).fast(2).fast(2)`: 636 calls
- `pure('c3').fast(4)`: 134 calls
## WIL
- Fraction.wholeCycle: returns a timespan for the whole cycle the given fraction is in. Fraction(n).wholeCycle -> TimeSpan(n.floor, n.floor+1)
- e.g. `Fraction(0.5).wholeCycle` -> `TimeSpan(0, 1)`
- TimeSpan.spanCycles: returns an array of whole cycle timespans that intersect with the given timespan
- e.g. `TimeSpan(0.5, 1.5)` -> `[TimeSpan(0, 1), TimeSpan(1, 2)]`
- pure: returns one Hap for spanCycles of query span. Hap will get wholeCycle as whole and query span as part
- reify: turns non patterns into patterns using pure. makes sure you get a pattern
## notes
- slowcat -> sequence -> fastcat -> slowcat is a somewhat hidden recursion
- slowcat -> pat_n can be negative and will then return an empty array. is that good? shouldn't pat_n be always a positive index?
- slowcat offset: how to think about this?
- slowcat: why add offset and sub it from the query span?