mirror of
https://codeberg.org/uzu/strudel
synced 2026-09-04 22:52:55 -04:00
Merge commit '5f381cf1536e3c87e16cf164e91666d8b7ec403a' into voicing-rework
This commit is contained in:
+2
-1
@@ -36,4 +36,5 @@ doc.json
|
||||
talk/public/EmuSP12
|
||||
talk/public/samples
|
||||
server/samples/old
|
||||
repl/stats.html
|
||||
repl/stats.html
|
||||
coverage
|
||||
Generated
+410
-45
@@ -13,6 +13,7 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@vitest/ui": "^0.21.1",
|
||||
"c8": "^7.12.0",
|
||||
"events": "^3.3.0",
|
||||
"gh-pages": "^4.0.0",
|
||||
"happy-dom": "^6.0.4",
|
||||
@@ -487,6 +488,12 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bcoe/v8-coverage": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
|
||||
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@codemirror/autocomplete": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.1.0.tgz",
|
||||
@@ -609,6 +616,15 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@istanbuljs/schema": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
|
||||
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
|
||||
@@ -622,9 +638,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
|
||||
"integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
@@ -638,17 +654,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.11",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz",
|
||||
"integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg=="
|
||||
"version": "1.4.14",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz",
|
||||
"integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==",
|
||||
"version": "0.3.17",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
|
||||
"integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
"@jridgewell/resolve-uri": "3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@lerna/add": {
|
||||
@@ -2438,6 +2454,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/istanbul-lib-coverage": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
|
||||
"integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/linkify-it": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
|
||||
@@ -3138,6 +3160,41 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/c8": {
|
||||
"version": "7.12.0",
|
||||
"resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz",
|
||||
"integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@bcoe/v8-coverage": "^0.2.3",
|
||||
"@istanbuljs/schema": "^0.1.3",
|
||||
"find-up": "^5.0.0",
|
||||
"foreground-child": "^2.0.0",
|
||||
"istanbul-lib-coverage": "^3.2.0",
|
||||
"istanbul-lib-report": "^3.0.0",
|
||||
"istanbul-reports": "^3.1.4",
|
||||
"rimraf": "^3.0.2",
|
||||
"test-exclude": "^6.0.0",
|
||||
"v8-to-istanbul": "^9.0.0",
|
||||
"yargs": "^16.2.0",
|
||||
"yargs-parser": "^20.2.9"
|
||||
},
|
||||
"bin": {
|
||||
"c8": "bin/c8.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/c8/node_modules/yargs-parser": {
|
||||
"version": "20.2.9",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/cacache": {
|
||||
"version": "15.3.0",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz",
|
||||
@@ -3322,18 +3379,6 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chardet": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
|
||||
@@ -5365,6 +5410,35 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/find-up": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"locate-path": "^6.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
|
||||
"integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.0",
|
||||
"signal-exit": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
@@ -6070,6 +6144,12 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/html-escaper": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
||||
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
|
||||
@@ -6786,6 +6866,42 @@
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/istanbul-lib-coverage": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
|
||||
"integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/istanbul-lib-report": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
|
||||
"integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"make-dir": "^3.0.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/istanbul-reports": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
|
||||
"integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"html-escaper": "^2.0.0",
|
||||
"istanbul-lib-report": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/jazz-midi": {
|
||||
"version": "1.7.5",
|
||||
"resolved": "https://registry.npmjs.org/jazz-midi/-/jazz-midi-1.7.5.tgz",
|
||||
@@ -7360,6 +7476,21 @@
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"p-locate": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
@@ -8705,6 +8836,36 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yocto-queue": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-locate": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
|
||||
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"p-limit": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-map": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||
@@ -10858,6 +11019,18 @@
|
||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz",
|
||||
"integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw=="
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
@@ -11042,6 +11215,20 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/test-exclude": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
|
||||
"integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@istanbuljs/schema": "^0.1.2",
|
||||
"glob": "^7.1.4",
|
||||
"minimatch": "^3.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/test-value": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/test-value/-/test-value-3.0.0.tgz",
|
||||
@@ -11516,6 +11703,20 @@
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-to-istanbul": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz",
|
||||
"integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.12",
|
||||
"@types/istanbul-lib-coverage": "^2.0.1",
|
||||
"convert-source-map": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/validate-npm-package-license": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
||||
@@ -12219,6 +12420,18 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/yoctodelay": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yoctodelay/-/yoctodelay-1.2.0.tgz",
|
||||
@@ -12828,6 +13041,12 @@
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@bcoe/v8-coverage": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
|
||||
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
|
||||
"dev": true
|
||||
},
|
||||
"@codemirror/autocomplete": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.1.0.tgz",
|
||||
@@ -12932,6 +13151,12 @@
|
||||
"integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@istanbuljs/schema": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
|
||||
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
|
||||
"dev": true
|
||||
},
|
||||
"@jridgewell/gen-mapping": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
|
||||
@@ -12942,9 +13167,9 @@
|
||||
}
|
||||
},
|
||||
"@jridgewell/resolve-uri": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
|
||||
"integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew=="
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w=="
|
||||
},
|
||||
"@jridgewell/set-array": {
|
||||
"version": "1.1.1",
|
||||
@@ -12952,17 +13177,17 @@
|
||||
"integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ=="
|
||||
},
|
||||
"@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.11",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz",
|
||||
"integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg=="
|
||||
"version": "1.4.14",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
|
||||
},
|
||||
"@jridgewell/trace-mapping": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz",
|
||||
"integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==",
|
||||
"version": "0.3.17",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
|
||||
"integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
|
||||
"requires": {
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
"@jridgewell/resolve-uri": "3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"@lerna/add": {
|
||||
@@ -14628,6 +14853,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/istanbul-lib-coverage": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
|
||||
"integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/linkify-it": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
|
||||
@@ -15185,6 +15416,34 @@
|
||||
"integrity": "sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A==",
|
||||
"dev": true
|
||||
},
|
||||
"c8": {
|
||||
"version": "7.12.0",
|
||||
"resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz",
|
||||
"integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@bcoe/v8-coverage": "^0.2.3",
|
||||
"@istanbuljs/schema": "^0.1.3",
|
||||
"find-up": "^5.0.0",
|
||||
"foreground-child": "^2.0.0",
|
||||
"istanbul-lib-coverage": "^3.2.0",
|
||||
"istanbul-lib-report": "^3.0.0",
|
||||
"istanbul-reports": "^3.1.4",
|
||||
"rimraf": "^3.0.2",
|
||||
"test-exclude": "^6.0.0",
|
||||
"v8-to-istanbul": "^9.0.0",
|
||||
"yargs": "^16.2.0",
|
||||
"yargs-parser": "^20.2.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"yargs-parser": {
|
||||
"version": "20.2.9",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"cacache": {
|
||||
"version": "15.3.0",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz",
|
||||
@@ -15319,17 +15578,6 @@
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"chardet": {
|
||||
@@ -16830,6 +17078,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"find-up": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"locate-path": "^6.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"foreground-child": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
|
||||
"integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cross-spawn": "^7.0.0",
|
||||
"signal-exit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
@@ -17361,6 +17629,12 @@
|
||||
"whatwg-encoding": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"html-escaper": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
||||
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
|
||||
"dev": true
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
|
||||
@@ -17909,6 +18183,33 @@
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
||||
"dev": true
|
||||
},
|
||||
"istanbul-lib-coverage": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
|
||||
"integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
|
||||
"dev": true
|
||||
},
|
||||
"istanbul-lib-report": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
|
||||
"integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"make-dir": "^3.0.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"istanbul-reports": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
|
||||
"integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"html-escaper": "^2.0.0",
|
||||
"istanbul-lib-report": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"jazz-midi": {
|
||||
"version": "1.7.5",
|
||||
"resolved": "https://registry.npmjs.org/jazz-midi/-/jazz-midi-1.7.5.tgz",
|
||||
@@ -18364,6 +18665,15 @@
|
||||
"integrity": "sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==",
|
||||
"dev": true
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-locate": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
@@ -19405,6 +19715,24 @@
|
||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
|
||||
"dev": true
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yocto-queue": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
|
||||
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-limit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"p-map": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||
@@ -21104,6 +21432,15 @@
|
||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz",
|
||||
"integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
@@ -21254,6 +21591,17 @@
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"test-exclude": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
|
||||
"integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@istanbuljs/schema": "^0.1.2",
|
||||
"glob": "^7.1.4",
|
||||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"test-value": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/test-value/-/test-value-3.0.0.tgz",
|
||||
@@ -21635,6 +21983,17 @@
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"dev": true
|
||||
},
|
||||
"v8-to-istanbul": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz",
|
||||
"integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/trace-mapping": "^0.3.12",
|
||||
"@types/istanbul-lib-coverage": "^2.0.1",
|
||||
"convert-source-map": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
||||
@@ -22124,6 +22483,12 @@
|
||||
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
|
||||
"dev": true
|
||||
},
|
||||
"yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"yoctodelay": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yoctodelay/-/yoctodelay-1.2.0.tgz",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"scripts": {
|
||||
"test": "vitest run --version",
|
||||
"test-ui": "vitest --ui",
|
||||
"test-coverage": "vitest --coverage",
|
||||
"bootstrap": "lerna bootstrap",
|
||||
"setup": "npm i && npm run bootstrap && cd repl && npm i && cd ../tutorial && npm i",
|
||||
"snapshot": "cd repl && npm run snapshot",
|
||||
@@ -39,6 +40,7 @@
|
||||
"homepage": "https://strudel.tidalcycles.org",
|
||||
"devDependencies": {
|
||||
"@vitest/ui": "^0.21.1",
|
||||
"c8": "^7.12.0",
|
||||
"events": "^3.3.0",
|
||||
"gh-pages": "^4.0.0",
|
||||
"happy-dom": "^6.0.4",
|
||||
|
||||
@@ -62,12 +62,12 @@ const generic_params = [
|
||||
*/
|
||||
['f', 'accelerate', 'a pattern of numbers that speed up (or slow down) samples while they play.'],
|
||||
/**
|
||||
* Like {@link amp}, but exponential.
|
||||
* Controls the gain by an exponential amount.
|
||||
*
|
||||
* @name gain
|
||||
* @param {number | Pattern} amount gain.
|
||||
* @example
|
||||
* s("bd*8").gain(".7*2 1 .7*2 1 .7 1").osc()
|
||||
* s("hh*8").gain(".4!2 1 .4!2 1 .4 1").out()
|
||||
*
|
||||
*/
|
||||
[
|
||||
@@ -147,10 +147,12 @@ const generic_params = [
|
||||
/**
|
||||
* a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample.
|
||||
*
|
||||
* @memberof Pattern
|
||||
* @name begin
|
||||
* @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample
|
||||
* @example
|
||||
* s("rave").begin("<0 .25 .5 .75>").osc()
|
||||
* samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/')
|
||||
* s("rave").begin("<0 .25 .5 .75>").out()
|
||||
*
|
||||
*/
|
||||
[
|
||||
@@ -159,12 +161,13 @@ const generic_params = [
|
||||
'a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample.',
|
||||
],
|
||||
/**
|
||||
* The same as {@link begin}, but cuts off the end off each sample.
|
||||
* The same as .begin, but cuts off the end off each sample.
|
||||
*
|
||||
* @memberof Pattern
|
||||
* @name end
|
||||
* @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc..
|
||||
* @example
|
||||
* s("bd*2,ho*4").end("<.1 .2 .5 1>").osc()
|
||||
* s("bd*2,ho*4").end("<.1 .2 .5 1>").out()
|
||||
*
|
||||
*/
|
||||
[
|
||||
|
||||
@@ -25,14 +25,19 @@ const euclid = (pulses, steps, rotation = 0) => {
|
||||
* describe a large number of rhythms used in the most important music world traditions.
|
||||
*
|
||||
* @memberof Pattern
|
||||
* @name euclid
|
||||
* @param {number} pulses the number of onsets / beats
|
||||
* @param {number} steps the number of steps to fill
|
||||
* @param {number} rotation (optional) offset in steps
|
||||
* @returns Pattern
|
||||
* @example // The Cuban tresillo pattern.
|
||||
* "c3".euclid(3,8)
|
||||
* @example
|
||||
* // The Cuban tresillo pattern.
|
||||
* n("c3").euclid(3,8).out()
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example // A thirteenth century Persian rhythm called Khafif-e-ramal.
|
||||
* "c3".euclid(2,5)
|
||||
* n("c3").euclid(2,5)
|
||||
* @example // The archetypal pattern of the Cumbia from Colombia, as well as a Calypso rhythm from Trinidad.
|
||||
* "c3".euclid(3,4)
|
||||
* @example // Another thirteenth century Persian rhythm by the name of Khafif-e-ramal, as well as a Rumanian folk-dance rhythm.
|
||||
@@ -79,7 +84,11 @@ Pattern.prototype.euclid = function (pulses, steps, rotation = 0) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Similar to {@link Pattern#euclid}, but each pulse is held until the next pulse, so there will be no gaps.
|
||||
* Similar to `.euclid`, but each pulse is held until the next pulse, so there will be no gaps.
|
||||
* @name euclidLegato
|
||||
* @memberof Pattern
|
||||
* @example
|
||||
* n("g2").decay(.1).sustain(.3).euclidLegato(3,8).out()
|
||||
*/
|
||||
Pattern.prototype.euclidLegato = function (pulses, steps, rotation = 0) {
|
||||
const bin_pat = euclid(pulses, steps, rotation);
|
||||
|
||||
+126
-16
@@ -468,7 +468,11 @@ export class Pattern {
|
||||
/**
|
||||
* Assumes a numerical pattern. Returns a new pattern with all values rounded
|
||||
* to the nearest integer.
|
||||
* @name round
|
||||
* @memberof Pattern
|
||||
* @returns Pattern
|
||||
* @example
|
||||
* "0.5 1.5 2.5".round().scale('C major')
|
||||
*/
|
||||
round() {
|
||||
return this._asNumber().fmap((v) => Math.round(v));
|
||||
@@ -522,7 +526,7 @@ export class Pattern {
|
||||
* @example
|
||||
* s("bd sd,hh*4").cutoff(sine.range(500,2000).slow(4)).out()
|
||||
*/
|
||||
range(min, max) {
|
||||
_range(min, max) {
|
||||
return this.mul(max - min).add(min);
|
||||
}
|
||||
|
||||
@@ -534,8 +538,8 @@ export class Pattern {
|
||||
* @param {Number} max
|
||||
* @returns Pattern
|
||||
*/
|
||||
rangex(min, max) {
|
||||
return this.range(Math.log(min), Math.log(max)).fmap(Math.exp);
|
||||
_rangex(min, max) {
|
||||
return this._range(Math.log(min), Math.log(max)).fmap(Math.exp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -545,8 +549,8 @@ export class Pattern {
|
||||
* @param {Number} max
|
||||
* @returns Pattern
|
||||
*/
|
||||
range2(min, max) {
|
||||
return this._fromBipolar().range(min, max);
|
||||
_range2(min, max) {
|
||||
return this._fromBipolar()._range(min, max);
|
||||
}
|
||||
|
||||
_bindWhole(choose_whole, func) {
|
||||
@@ -695,6 +699,13 @@ export class Pattern {
|
||||
return this.fmap(func)._squeezeJoin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like layer, but with a single function:
|
||||
* @name apply
|
||||
* @memberof Pattern
|
||||
* @example
|
||||
* "<c3 eb3 g3>".scale('C minor').apply(scaleTranspose("0,2,4"))
|
||||
*/
|
||||
_apply(func) {
|
||||
return func(this);
|
||||
}
|
||||
@@ -739,13 +750,20 @@ export class Pattern {
|
||||
const end = cycle.add(span.end.sub(cycle).mul(factor).min(1));
|
||||
return new TimeSpan(begin, end);
|
||||
};
|
||||
const ef = function (span) {
|
||||
const cycle = span.begin.sam();
|
||||
const begin = cycle.add(span.begin.sub(cycle).div(factor).min(1));
|
||||
const end = cycle.add(span.end.sub(cycle).div(factor).min(1));
|
||||
return new TimeSpan(begin, end);
|
||||
const ef = function (hap) {
|
||||
const begin = hap.part.begin;
|
||||
const end = hap.part.end;
|
||||
const cycle = begin.sam();
|
||||
const beginPos = begin.sub(cycle).div(factor).min(1);
|
||||
const endPos = end.sub(cycle).div(factor).min(1);
|
||||
const newPart = new TimeSpan(cycle.add(beginPos), cycle.add(endPos))
|
||||
const newWhole = !hap.whole ? undefined : new TimeSpan(
|
||||
newPart.begin.sub(begin.sub(hap.whole.begin).div(factor)),
|
||||
newPart.end.add(hap.whole.end.sub(end).div(factor))
|
||||
);
|
||||
return new Hap(newWhole, newPart, hap.value, hap.context);
|
||||
};
|
||||
return this.withQuerySpan(qf).withHapSpan(ef)._splitQueries();
|
||||
return this.withQuerySpan(qf)._withHap(ef)._splitQueries();
|
||||
}
|
||||
|
||||
// Compress each cycle into the given timespan, leaving a gap
|
||||
@@ -765,7 +783,7 @@ export class Pattern {
|
||||
_focus(b, e) {
|
||||
return this._fast(Fraction(1).div(e.sub(b))).late(b.cyclePos());
|
||||
}
|
||||
|
||||
|
||||
_focusSpan(span) {
|
||||
return this._focus(span.begin, span.end);
|
||||
}
|
||||
@@ -811,6 +829,20 @@ export class Pattern {
|
||||
return this.fmap((x) => pure(x)._fast(factor))._squeezeJoin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cuts each sample into the given number of parts, allowing you to explore a technique known as 'granular synthesis'.
|
||||
* It turns a pattern of samples into a pattern of parts of samples.
|
||||
* @name chop
|
||||
* @memberof Pattern
|
||||
* @returns Pattern
|
||||
* @example
|
||||
* samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
|
||||
* s("rhodes")
|
||||
* .chop(4)
|
||||
* .rev() // reverse order of chops
|
||||
* .loopAt(4,1) // fit sample into 4 cycles
|
||||
* .out()
|
||||
*/
|
||||
_chop(n) {
|
||||
const slices = Array.from({ length: n }, (x, i) => i);
|
||||
const slice_objects = slices.map((i) => ({ begin: i / n, end: (i + 1) / n }));
|
||||
@@ -1182,6 +1214,9 @@ export class Pattern {
|
||||
* @name echo
|
||||
* @memberof Pattern
|
||||
* @returns Pattern
|
||||
* @param {number} times how many times to repeat
|
||||
* @param {number} time cycle offset between iterations
|
||||
* @param {number} feedback velocity multiplicator for each iteration
|
||||
* @example
|
||||
* s("bd sd").echo(3, 1/6, .8).out()
|
||||
*/
|
||||
@@ -1254,16 +1289,40 @@ export class Pattern {
|
||||
return this.withHapSpan((span) => new TimeSpan(span.begin, span.begin.add(value)));
|
||||
}
|
||||
|
||||
// sets hap relative duration of haps
|
||||
/**
|
||||
*
|
||||
* Multiplies the hap duration with the given factor.
|
||||
* @name legato
|
||||
* @memberof Pattern
|
||||
* @example
|
||||
* n("c3 eb3 g3 c4").legato("<.25 .5 1 2>").out()
|
||||
*/
|
||||
_legato(value) {
|
||||
return this.withHapSpan((span) => new TimeSpan(span.begin, span.begin.add(span.end.sub(span.begin).mul(value))));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Sets the velocity from 0 to 1. Is multiplied together with gain.
|
||||
* @name velocity
|
||||
* @example
|
||||
* s("hh*8")
|
||||
* .gain(".4!2 1 .4!2 1 .4 1")
|
||||
* .velocity(".4 1").out()
|
||||
*/
|
||||
_velocity(velocity) {
|
||||
return this._withContext((context) => ({ ...context, velocity: (context.velocity || 1) * velocity }));
|
||||
}
|
||||
|
||||
// move this to controls? (speed and unit are controls)
|
||||
/**
|
||||
* Makes the sample fit the given number of cycles by changing the speed.
|
||||
* @name loopAt
|
||||
* @memberof Pattern
|
||||
* @returns Pattern
|
||||
* @example
|
||||
* samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
|
||||
* s("rhodes").loopAt(4,1).out()
|
||||
*/
|
||||
_loopAt(factor, cps = 1) {
|
||||
return this.speed((1 / factor) * cps)
|
||||
.unit('c')
|
||||
@@ -1319,9 +1378,48 @@ function _composeOp(a, b, func) {
|
||||
keepif: [(a, b) => (b ? a : undefined)],
|
||||
|
||||
// numerical functions
|
||||
/**
|
||||
*
|
||||
* Assumes a pattern of numbers. Adds the given number to each item in the pattern.
|
||||
* @name add
|
||||
* @memberof Pattern
|
||||
* @example
|
||||
* // Here, the triad 0, 2, 4 is shifted by different amounts
|
||||
* "0 2 4".add("<0 3 4 0>").scale('C major')
|
||||
* // Without add, the equivalent would be:
|
||||
* // "<[0 2 4] [3 5 7] [4 6 8] [0 2 4]>".scale('C major')
|
||||
* @example
|
||||
* // You can also use add with notes:
|
||||
* "c3 e3 g3".add("<0 5 7 0>")
|
||||
* // Behind the scenes, the notes are converted to midi numbers:
|
||||
* // "48 52 55".add("<0 5 7 0>")
|
||||
*/
|
||||
add: [(a, b) => a + b, numOrString], // support string concatenation
|
||||
/**
|
||||
*
|
||||
* Like add, but the given numbers are subtracted.
|
||||
* @name sub
|
||||
* @memberof Pattern
|
||||
* @example
|
||||
* "0 2 4".sub("<0 1 2 3>").scale('C4 minor')
|
||||
* // See add for more information.
|
||||
*/
|
||||
sub: [(a, b) => a - b, num],
|
||||
/**
|
||||
*
|
||||
* Multiplies each number by the given factor.
|
||||
* @name mul
|
||||
* @memberof Pattern
|
||||
* @example
|
||||
* "1 1.5 [1.66, <2 2.33>]".mul(150).freq().out()
|
||||
*/
|
||||
mul: [(a, b) => a * b, num],
|
||||
/**
|
||||
*
|
||||
* Divides each number by the given factor.
|
||||
* @name div
|
||||
* @memberof Pattern
|
||||
*/
|
||||
div: [(a, b) => a / b, num],
|
||||
mod: [mod, num],
|
||||
pow: [Math.pow, num],
|
||||
@@ -1363,8 +1461,7 @@ function _composeOp(a, b, func) {
|
||||
// avoid union, as we want to throw away the value of 'b' completely
|
||||
result = pat['_op' + how](other, (a) => (b) => op(a, b));
|
||||
result = result._removeUndefineds();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
result = pat['_op' + how](other, (a) => (b) => _composeOp(a, b, op));
|
||||
}
|
||||
return result;
|
||||
@@ -1657,6 +1754,7 @@ export const mul = curry((a, pat) => pat.mul(a));
|
||||
export const off = curry((t, f, pat) => pat.off(t, f));
|
||||
export const ply = curry((a, pat) => pat.ply(a));
|
||||
export const range = curry((a, b, pat) => pat.range(a, b));
|
||||
export const rangex = curry((a, b, pat) => pat.rangex(a, b));
|
||||
export const range2 = curry((a, b, pat) => pat.range2(a, b));
|
||||
export const rev = (pat) => pat.rev();
|
||||
export const slow = curry((a, pat) => pat.slow(a));
|
||||
@@ -1743,6 +1841,18 @@ Pattern.prototype.inside = function (...args) {
|
||||
args = args.map(reify);
|
||||
return patternify2(Pattern.prototype._inside)(...args, this);
|
||||
};
|
||||
Pattern.prototype.range = function (...args) {
|
||||
args = args.map(reify);
|
||||
return patternify2(Pattern.prototype._range)(...args, this);
|
||||
};
|
||||
Pattern.prototype.rangex = function (...args) {
|
||||
args = args.map(reify);
|
||||
return patternify2(Pattern.prototype._rangex)(...args, this);
|
||||
};
|
||||
Pattern.prototype.range2 = function (...args) {
|
||||
args = args.map(reify);
|
||||
return patternify2(Pattern.prototype._range2)(...args, this);
|
||||
};
|
||||
|
||||
// call this after all Patter.prototype.define calls have been executed! (right before evaluate)
|
||||
Pattern.prototype.bootstrap = function () {
|
||||
|
||||
@@ -372,6 +372,11 @@ describe('Pattern', () => {
|
||||
sequence(['a', 'b', 'c'], silence, ['a', 'b', 'c'], silence).firstCycle(),
|
||||
);
|
||||
});
|
||||
it('copes with breaking up events across cycles', () => {
|
||||
expect(pure('a').slow(2)._fastGap(2)._setContext({}).query(st(0, 2))).toStrictEqual(
|
||||
[hap(ts(0, 1), ts(0, 0.5), 'a'), hap(ts(0.5, 1.5), ts(1, 1.5), 'a')]
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('_compressSpan()', () => {
|
||||
it('Can squash cycles of a pattern into a given timespan', () => {
|
||||
@@ -848,6 +853,13 @@ describe('Pattern', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('range', () => {
|
||||
it('Can be patterned', () => {
|
||||
expect(sequence(0, 0).range(sequence(0, 0.5), 1).firstCycle()).toStrictEqual(
|
||||
sequence(0, 0.5).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('range2', () => {
|
||||
it('Can change the range of a bipolar pattern', () => {
|
||||
expect(sequence(-1, -0.5, 0, 0.5).range2(1000, 1100).firstCycle()).toStrictEqual(
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
util.test.mjs - <short description TODO>
|
||||
util.test.mjs - Tests for the core 'util' module
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/test/util.test.mjs>
|
||||
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 { pure } from '../pattern.mjs';
|
||||
import { isNote, tokenizeNote, toMidi, fromMidi, mod, compose, getFrequency } from '../util.mjs';
|
||||
import { isNote, tokenizeNote, toMidi, fromMidi, mod, compose, getFrequency, getPlayableNoteValue } from '../util.mjs';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('isNote', () => {
|
||||
@@ -70,6 +70,10 @@ describe('toMidi', () => {
|
||||
expect(toMidi('C#3')).toEqual(49);
|
||||
expect(toMidi('C##3')).toEqual(50);
|
||||
});
|
||||
it('should throw an error when given a non-note', () => {
|
||||
expect(() => toMidi('Q')).toThrowError(`not a note: "Q"`);
|
||||
expect(() => toMidi('Z')).toThrowError(`not a note: "Z"`);
|
||||
});
|
||||
});
|
||||
describe('fromMidi', () => {
|
||||
it('should turn midi into frequency', () => {
|
||||
@@ -78,13 +82,27 @@ describe('fromMidi', () => {
|
||||
});
|
||||
});
|
||||
describe('getFrequency', () => {
|
||||
it('should turn midi into frequency', () => {
|
||||
const happify = (val, context = {}) => pure(val).firstCycle()[0].setContext(context);
|
||||
const happify = (val, context = {}) => pure(val).firstCycle()[0].setContext(context);
|
||||
it('should turn note into frequency', () => {
|
||||
expect(getFrequency(happify('a4'))).toEqual(440);
|
||||
expect(getFrequency(happify('a3'))).toEqual(220);
|
||||
expect(getFrequency(happify(440, { type: 'frequency' }))).toEqual(440); // TODO: migrate when values are objects..
|
||||
});
|
||||
it('should turn midi into frequency', () => {
|
||||
expect(getFrequency(happify(69, { type: 'midi' }))).toEqual(440);
|
||||
expect(getFrequency(happify(57, { type: 'midi' }))).toEqual(220);
|
||||
});
|
||||
it('should return frequencies unchanged', () => {
|
||||
expect(getFrequency(happify(440, { type: 'frequency' }))).toEqual(440);
|
||||
expect(getFrequency(happify(432, { type: 'frequency' }))).toEqual(432);
|
||||
});
|
||||
it('should turn object with a "freq" property into frequency', () => {
|
||||
expect(getFrequency(happify({freq: 220}))).toEqual(220)
|
||||
expect(getFrequency(happify({freq: 440}))).toEqual(440)
|
||||
});
|
||||
it('should throw an error when given a non-note', () => {
|
||||
expect(() => getFrequency(happify('Q'))).toThrowError(`not a note or frequency: Q`)
|
||||
expect(() => getFrequency(happify('Z'))).toThrowError(`not a note or frequency: Z`)
|
||||
});
|
||||
});
|
||||
|
||||
describe('mod', () => {
|
||||
@@ -118,3 +136,26 @@ describe('compose', () => {
|
||||
expect(compose(addS('a'), addS('b'))('x')).toEqual('xab');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPlayableNoteValue', () => {
|
||||
const happify = (val, context = {}) => pure(val).firstCycle()[0].setContext(context);
|
||||
it('should return object "note" property', () => {
|
||||
expect(getPlayableNoteValue(happify({note: "a4"}))).toEqual('a4')
|
||||
});
|
||||
it('should return object "n" property', () => {
|
||||
expect(getPlayableNoteValue(happify({n: "a4"}))).toEqual('a4')
|
||||
});
|
||||
it('should return object "value" property', () => {
|
||||
expect(getPlayableNoteValue(happify({value: "a4"}))).toEqual('a4')
|
||||
});
|
||||
it('should turn midi into frequency', () => {
|
||||
expect(getPlayableNoteValue(happify(57, {type: 'midi'}))).toEqual(220)
|
||||
})
|
||||
it('should return frequency value', () => {
|
||||
expect(getPlayableNoteValue(happify(220, {type: 'frequency'}))).toEqual(220)
|
||||
})
|
||||
it('should throw an error if value is not an object, number, or string', () => {
|
||||
expect(() => getPlayableNoteValue(happify(false))).toThrowError(`not a note: false`)
|
||||
expect(() => getPlayableNoteValue(happify(undefined))).toThrowError(`not a note: undefined`)
|
||||
})
|
||||
});
|
||||
@@ -31,6 +31,9 @@ export const fromMidi = (n) => {
|
||||
return Math.pow(2, (n - 69) / 12) * 440;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated does not appear to be referenced or invoked anywhere in the codebase
|
||||
*/
|
||||
export const getFreq = (noteOrMidi) => {
|
||||
if (typeof noteOrMidi === 'number') {
|
||||
return fromMidi(noteOrMidi);
|
||||
@@ -38,6 +41,9 @@ export const getFreq = (noteOrMidi) => {
|
||||
return fromMidi(toMidi(noteOrMidi));
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated does not appear to be referenced or invoked anywhere in the codebase
|
||||
*/
|
||||
export const midi2note = (n) => {
|
||||
const oct = Math.floor(n / 12) - 1;
|
||||
const pc = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'][n % 12];
|
||||
@@ -75,7 +81,7 @@ export const getFrequency = (hap) => {
|
||||
} else if (typeof value === 'string' && isNote(value)) {
|
||||
value = fromMidi(toMidi(hap.value));
|
||||
} else if (typeof value !== 'number') {
|
||||
throw new Error('not a note or frequency:' + value);
|
||||
throw new Error('not a note or frequency: ' + value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
@@ -18,3 +18,6 @@ if (typeof AudioContext !== 'undefined') {
|
||||
return convolver;
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: make the reverb more exciting
|
||||
// check out https://blog.gskinner.com/archives/2019/02/reverb-web-audio-api.html
|
||||
|
||||
+2229
-10787
File diff suppressed because it is too large
Load Diff
+75
-145
@@ -149,20 +149,20 @@ export const zeldasRescue = `stack(
|
||||
[[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2]
|
||||
[[F2 C3] E3@2] [[E2 B2] D3@2] [[D2 A2] C3@2] [[C2 G2] B2@2]
|
||||
[[F2 C3] E3@2] [[E2 B2] D3@2] [[Eb2 Bb2] Db3@2] [[D2 A2] C3 [F3,G2]]\`
|
||||
).transpose(12).slow(48).tone(
|
||||
new PolySynth().chain(
|
||||
new Gain(0.3),
|
||||
new Chorus(2, 2.5, 0.5).start(),
|
||||
new Freeverb(),
|
||||
getDestination())
|
||||
)`;
|
||||
).transpose(12).slow(48)
|
||||
.superimpose(x=>x.add(0.06)) // add slightly detuned voice
|
||||
.note()
|
||||
.gain(.1)
|
||||
.s('triangle')
|
||||
.room(1)
|
||||
.out()`;
|
||||
|
||||
export const caverave = `const keys = x => x.s('sawtooth').cutoff(1200).gain(.5).attack(0).decay(0.5).sustain(.16).release(.8);
|
||||
export const caverave = `const keys = x => x.s('sawtooth').cutoff(1200).gain(.5).attack(0).decay(.16).sustain(.3).release(.1);
|
||||
|
||||
const drums = stack(
|
||||
s("bd*2").mask("<x@7 ~>/8"),
|
||||
s("~ <sd!7 [sd@3 x]>").mask("<x@7 ~>/4"),
|
||||
s("[~ hh]*2").delay(.3).delayfeedback(.5).delaytime(.125)
|
||||
s("bd*2").mask("<x@7 ~>/8").gain(.8),
|
||||
s("~ <sd!7 [sd@3 ~]>").mask("<x@7 ~>/4").gain(.5),
|
||||
s("[~ hh]*2").delay(.3).delayfeedback(.5).delaytime(.125).gain(.4)
|
||||
);
|
||||
|
||||
const thru = (x) => x.transpose("<0 1>/8").transpose(-1);
|
||||
@@ -178,8 +178,9 @@ const synths = stack(
|
||||
note("<C2 Bb1 Ab1 [G1 [G2 G1]]>/2".apply(thru))
|
||||
.struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2".fast(2))
|
||||
.s('sawtooth').attack(0.001).decay(0.2).sustain(1).cutoff(500),
|
||||
"<Cm7 Bb7 Fm7 G7b13>/2".struct("~ [x@0.1 ~]".fast(2)).voicings()
|
||||
.apply(thru).every(2, early(1/8)).note().apply(keys)
|
||||
"<Cm7 Bb7 Fm7 G7b13>/2".struct("~ [x@0.2 ~]".fast(2)).voicings()
|
||||
.apply(thru).every(2, early(1/8)).note().apply(keys).sustain(0)
|
||||
.delay(.4).delaytime(.12)
|
||||
.mask("<x@7 ~>/8".early(1/4))
|
||||
)
|
||||
stack(
|
||||
@@ -187,35 +188,7 @@ stack(
|
||||
synths
|
||||
).slow(2).out()`;
|
||||
|
||||
export const callcenterhero = `const bpm = 90;
|
||||
const lead = polysynth().set({...osc('sine4'),...adsr(.004)}).chain(vol(0.15),out())
|
||||
const bass = fmsynth({...osc('sawtooth6'),...adsr(0.05,.6,0.8,0.1)}).chain(vol(0.6), out());
|
||||
const s = scale(cat('F3 minor', 'Ab3 major', 'Bb3 dorian', 'C4 phrygian dominant').slow(4));
|
||||
stack(
|
||||
"0 2".struct("<x ~> [x ~]").apply(s).scaleTranspose(stack(0,2)).tone(lead),
|
||||
"<6 7 9 7>".struct("[~ [x ~]*2]*2").apply(s).scaleTranspose("[0,2] [2,4]".fast(2).every(4,rev)).tone(lead),
|
||||
"-14".struct("[~ x@0.8]*2".early(0.01)).apply(s).tone(bass),
|
||||
"c2*2".tone(membrane().chain(vol(0.6), out())),
|
||||
"~ c2".tone(noise().chain(vol(0.2), out())),
|
||||
"c4*4".tone(metal(adsr(0,.05,0)).chain(vol(0.03), out()))
|
||||
)
|
||||
.slow(120 / bpm)`;
|
||||
|
||||
export const primalEnemy = `const f = fast("<1 <2 [4 8]>>");
|
||||
stack(
|
||||
"c3,g3,c4".struct("[x ~]*2").apply(f).transpose("<0 <3 [5 [7 [9 [11 13]]]]>>"),
|
||||
"c2 [c2 ~]*2".tone(synth(osc('sawtooth8')).chain(vol(0.8),out())),
|
||||
"c1*2".tone(membrane().chain(vol(0.8),out()))
|
||||
).slow(1)`;
|
||||
|
||||
export const synthDrums = `stack(
|
||||
"c1*2".tone(membrane().chain(vol(0.8),out())),
|
||||
"~ c3".tone(noise().chain(vol(0.8),out())),
|
||||
"c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.015)).chain(vol(0.8),out()))
|
||||
)
|
||||
`;
|
||||
|
||||
export const sampleDrums = `const drums = await players({
|
||||
export const sampleDrums = `samples({
|
||||
bd: 'bd/BT0A0D0.wav',
|
||||
sn: 'sn/ST0T0S3.wav',
|
||||
hh: 'hh/000_hh3closedhh.wav'
|
||||
@@ -225,9 +198,11 @@ stack(
|
||||
"<bd!3 bd(3,4,2)>",
|
||||
"hh*4",
|
||||
"~ <sn!3 sn(3,4,1)>"
|
||||
).tone(drums.chain(out()))
|
||||
).s().out()
|
||||
`;
|
||||
|
||||
// TODO:
|
||||
/*
|
||||
export const xylophoneCalling = `const t = x => x.scaleTranspose("<0 2 4 3>/4").transpose(-2)
|
||||
const s = x => x.scale(cat('C3 minor pentatonic','G3 minor pentatonic').slow(4))
|
||||
const delay = new FeedbackDelay(1/8, .6).chain(vol(0.1), out());
|
||||
@@ -264,7 +239,10 @@ stack(
|
||||
"c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.02)).chain(vol(0.5).connect(delay),out()))
|
||||
).slow(1)
|
||||
// strudel disable-highlighting`;
|
||||
*/
|
||||
|
||||
// TODO:
|
||||
/*
|
||||
export const sowhatelse = `// mixer
|
||||
const mix = (key) => vol({
|
||||
chords: .2,
|
||||
@@ -301,6 +279,7 @@ stack(
|
||||
"[2,4]/4".scale('D dorian').apply(t).tone(instr('pad')).mask("<x x x ~>/8")
|
||||
).fast(6/8)
|
||||
// strudel disable-highlighting`;
|
||||
*/
|
||||
|
||||
export const barryHarris = `backgroundImage(
|
||||
'https://media.npr.org/assets/img/2017/02/03/barryharris_600dpi_wide-7eb49998aa1af377d62bb098041624c0a0d1a454.jpg',
|
||||
@@ -314,15 +293,11 @@ export const barryHarris = `backgroundImage(
|
||||
.note().piano().out()
|
||||
`;
|
||||
|
||||
export const blippyRhodes = `const delay = new FeedbackDelay(1/12, .4).chain(vol(0.3), out());
|
||||
|
||||
const drums = await players({
|
||||
export const blippyRhodes = `samples({
|
||||
bd: 'samples/tidal/bd/BT0A0D0.wav',
|
||||
sn: 'samples/tidal/sn/ST0T0S3.wav',
|
||||
hh: 'samples/tidal/hh/000_hh3closedhh.wav'
|
||||
}, 'https://loophole-letters.vercel.app/')
|
||||
|
||||
const rhodes = await sampler({
|
||||
hh: 'samples/tidal/hh/000_hh3closedhh.wav',
|
||||
rhodes: {
|
||||
E1: 'samples/rhodes/MK2Md2000.mp3',
|
||||
E2: 'samples/rhodes/MK2Md2012.mp3',
|
||||
E3: 'samples/rhodes/MK2Md2024.mp3',
|
||||
@@ -330,33 +305,37 @@ const rhodes = await sampler({
|
||||
E5: 'samples/rhodes/MK2Md2048.mp3',
|
||||
E6: 'samples/rhodes/MK2Md2060.mp3',
|
||||
E7: 'samples/rhodes/MK2Md2072.mp3'
|
||||
}
|
||||
}, 'https://loophole-letters.vercel.app/')
|
||||
|
||||
const bass = synth(osc('sawtooth8')).chain(vol(.5),out())
|
||||
const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', cat('Db major','Db mixolydian')])
|
||||
|
||||
stack(
|
||||
"<bd sn> <hh hh*2 hh*3>"
|
||||
.tone(drums.chain(out())),
|
||||
s("<bd sn> <hh hh*2 hh*3>"),
|
||||
"<g4 c5 a4 [ab4 <eb5 f5>]>"
|
||||
.scale(scales)
|
||||
.struct("x*8")
|
||||
.scaleTranspose("0 [-5,-2] -7 [-9,-2]")
|
||||
.legato(.3)
|
||||
.slow(2)
|
||||
.tone(rhodes.chain(vol(0.5).connect(delay), out())),
|
||||
//"<C^7 C7 F^7 [Fm7 <Db^7 Db7>]>".slow(2).voicings().struct("~ x").legato(.25).tone(rhodes),
|
||||
.note()
|
||||
.s('rhodes')
|
||||
.clip(1)
|
||||
.room(.5)
|
||||
.delay(.3)
|
||||
.delayfeedback(.4)
|
||||
.delaytime(1/12).gain(.5),
|
||||
"<c2 c3 f2 [[F2 C2] db2]>"
|
||||
.legato("<1@3 [.3 1]>")
|
||||
.slow(2)
|
||||
.tone(bass),
|
||||
).fast(3/2)`;
|
||||
.slow(2).superimpose(x=>x.add(.02))
|
||||
.note().gain(.3)
|
||||
.s('sawtooth').cutoff(600),
|
||||
).fast(3/2).out()`;
|
||||
|
||||
export const wavyKalimba = `const delay = new FeedbackDelay(1/3, .5).chain(vol(.2), out())
|
||||
let kalimba = await sampler({
|
||||
C5: 'https://freesound.org/data/previews/536/536549_11935698-lq.mp3'
|
||||
export const wavyKalimba = `samples({
|
||||
'kalimba': { c5:'https://freesound.org/data/previews/536/536549_11935698-lq.mp3' }
|
||||
})
|
||||
kalimba = kalimba.chain(vol(0.6).connect(delay),out());
|
||||
const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', 'Db major'])
|
||||
|
||||
stack(
|
||||
@@ -365,8 +344,7 @@ stack(
|
||||
.scale(scales)
|
||||
.struct("x*8")
|
||||
.velocity("<.8 .3 .6>*8")
|
||||
.slow(2)
|
||||
.tone(kalimba),
|
||||
.slow(2),
|
||||
"<c2 c2 f2 [[F2 C2] db2]>"
|
||||
.scale(scales)
|
||||
.scaleTranspose("[0 <2 4>]*2")
|
||||
@@ -374,11 +352,17 @@ stack(
|
||||
.velocity("<.8 .5>*4")
|
||||
.velocity(0.8)
|
||||
.slow(2)
|
||||
.tone(kalimba)
|
||||
)
|
||||
.legato("<.4 .8 1 1.2 1.4 1.6 1.8 2>/8")
|
||||
.fast(1)`;
|
||||
.fast(1)
|
||||
.note()
|
||||
.clip(1)
|
||||
.s('kalimba')
|
||||
.delay(.2)
|
||||
.out()`;
|
||||
|
||||
// TODO: rework tune to use freq
|
||||
/*
|
||||
export const jemblung = `const delay = new FeedbackDelay(1/8, .6).chain(vol(0.15), out());
|
||||
const snare = noise({type:'white',...adsr(0,0.2,0)}).chain(lowpass(5000),vol(1.8),out());
|
||||
const s = polysynth().set({...osc('sawtooth4'),...adsr(0.01,.2,.6,0.2)}).chain(vol(.23).connect(delay),out());
|
||||
@@ -405,20 +389,7 @@ stack(
|
||||
// hihat
|
||||
"c2*8".tone(noise().chain(highpass(6000),vol(0.5).connect(delay),out())),
|
||||
).slow(3)`;
|
||||
|
||||
export const risingEnemy = `stack(
|
||||
"2,6"
|
||||
.scale('F3 dorian')
|
||||
.transpose(sine2.struct("x*64").slow(4).mul(2).round())
|
||||
.fast(2)
|
||||
.struct("x x*3")
|
||||
.legato(".9 .3"),
|
||||
"0@3 -3*3".legato(".95@3 .4").scale('F2 dorian')
|
||||
)
|
||||
.transpose("<0 1 2 1>/2".early(0.5))
|
||||
.transpose(5)
|
||||
.fast(2 / 3)
|
||||
.note().piano().out()`;
|
||||
*/
|
||||
|
||||
export const festivalOfFingers = `const chords = "<Cm7 Fm7 G7 F#7>";
|
||||
stack(
|
||||
@@ -432,20 +403,6 @@ stack(
|
||||
.velocity(sine.struct("x*8").add(3/5).mul(2/5).fast(8))
|
||||
.note().piano().out()`;
|
||||
|
||||
export const festivalOfFingers2 = `const chords = "<Cm7 Fm7 G7 F#7 >";
|
||||
const scales = cat('C minor','F dorian','G dorian','F# mixolydian')
|
||||
stack(
|
||||
chords.voicings().struct("x(3,8,-1)").velocity(.5).off(1/7,x=>x.transpose(12).velocity(.2)),
|
||||
chords.rootNotes(2).struct("x(4,8)"),
|
||||
chords.rootNotes(4)
|
||||
.scale(scales)
|
||||
.struct("x(3,8,-2)".fast(2))
|
||||
.scaleTranspose("0 4 0 6".early(".125 .5")).layer(scaleTranspose("0,<2 [4,6] [5,7]>/3"))
|
||||
).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)`;
|
||||
|
||||
// iter, echo, echoWith
|
||||
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' })
|
||||
|
||||
@@ -556,6 +513,8 @@ stack(
|
||||
.legato(.5)
|
||||
).fast(2) // .note().piano().out()`;
|
||||
|
||||
/*
|
||||
// TODO: does not work on linux (at least for me..)
|
||||
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'})
|
||||
stack(
|
||||
@@ -575,48 +534,29 @@ stack(
|
||||
'got to keep on running',
|
||||
).speak("en zu en".slow(12), "<0 2 3 4 5 6>".slow(2)),
|
||||
).slow(4)`;
|
||||
*/
|
||||
|
||||
export const randomBells = `const delay = new FeedbackDelay(1/3, .8).chain(vol(.2), out());
|
||||
let bell = await sampler({
|
||||
C6: 'https://freesound.org/data/previews/411/411089_5121236-lq.mp3'
|
||||
export const randomBells = `samples({
|
||||
bell: { c6: 'https://freesound.org/data/previews/411/411089_5121236-lq.mp3' },
|
||||
bass: { d2: 'https://freesound.org/data/previews/608/608286_13074022-lq.mp3' }
|
||||
})
|
||||
const bass = await sampler({
|
||||
d2: 'https://freesound.org/data/previews/608/608286_13074022-lq.mp3'
|
||||
});
|
||||
bell = bell.chain(vol(0.6).connect(delay),out());
|
||||
|
||||
"0".euclidLegato(3,8)
|
||||
stack(
|
||||
// bells
|
||||
"0".euclidLegato(3,8)
|
||||
.echo(3, 1/16, .5)
|
||||
.add(rand.range(0,12))
|
||||
.velocity(rand.range(.5,1))
|
||||
.legato(rand.range(.4,3))
|
||||
.scale(cat('D minor pentatonic')).tone(bell)
|
||||
.stack("<D2 A2 G2 F2>".euclidLegato(6,8,1).tone(bass.toDestination()))
|
||||
.slow(6)
|
||||
.pianoroll({minMidi:20,maxMidi:120,background:'transparent'})`;
|
||||
|
||||
/* 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)
|
||||
.wave("sawtooth square")
|
||||
.filter('lowpass', "<2000 1000 500>")
|
||||
.out()`; */
|
||||
|
||||
export const waa = `n(
|
||||
"a4 [a3 c3] a3 c3"
|
||||
.sub("<7 12>/2")
|
||||
.off(1/8, add("12"))
|
||||
.off(1/4, add("7"))
|
||||
.scale(cat('D minor pentatonic')).note()
|
||||
.s('bell').gain(.6).delay(.2).delaytime(1/3).delayfeedback(.8),
|
||||
// bass
|
||||
"<D2 A2 G2 F2>".euclidLegato(6,8,1).note().s('bass').clip(1).gain(.8)
|
||||
)
|
||||
.legato(.5)
|
||||
.slow(2)
|
||||
.s("sawtooth square")
|
||||
.cutoff("<2000 1000 500>")
|
||||
.slow(6)
|
||||
.out()
|
||||
`;
|
||||
.pianoroll({minMidi:20,maxMidi:120,background:'transparent'})
|
||||
`;
|
||||
|
||||
export const waa2 = `n(
|
||||
"a4 [a3 c3] a3 c3"
|
||||
@@ -628,6 +568,8 @@ export const waa2 = `n(
|
||||
.legato(sine.range(0.3, 2).slow(28))
|
||||
.s("sawtooth square".fast(2))
|
||||
.cutoff(cosine.range(500,4000).slow(16))
|
||||
.gain(.5)
|
||||
.room(.5)
|
||||
.out()`;
|
||||
|
||||
export const hyperpop = `const lfo = cosine.slow(15);
|
||||
@@ -636,7 +578,7 @@ const filter1 = x=>x.cutoff(lfo2.range(300,3000));
|
||||
const filter2 = x=>x.hcutoff(lfo.range(1000,6000)).cutoff(4000)
|
||||
const scales = cat('D3 major', 'G3 major').slow(8)
|
||||
|
||||
const drums = await players({
|
||||
samples({
|
||||
bd: '344/344757_1676145-lq.mp3',
|
||||
sn: '387/387186_7255534-lq.mp3',
|
||||
hh: '561/561241_12517458-lq.mp3',
|
||||
@@ -670,15 +612,13 @@ stack(
|
||||
.gain(sine.range(.1,.4).slow(8))
|
||||
.attack(.001).decay(.2).sustain(0)
|
||||
.apply(filter2)
|
||||
).out().stack(
|
||||
).stack(
|
||||
stack(
|
||||
"bd <~@7 [~ bd]>".fast(2),
|
||||
"~ sn",
|
||||
"[~ hh3]*2"
|
||||
).tone(drums.chain(vol(.18),out())).fast(2)
|
||||
).slow(2)
|
||||
|
||||
//.pianoroll({minMidi:20, maxMidi:160})
|
||||
).s().fast(2).gain(.7)
|
||||
).slow(2).out()
|
||||
// strudel disable-highlighting`;
|
||||
|
||||
export const festivalOfFingers3 = `"[-7*3],0,2,6,[8 7]"
|
||||
@@ -703,7 +643,7 @@ 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))
|
||||
@@ -721,17 +661,7 @@ export const customTrigger = `stack(
|
||||
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())`;
|
||||
}).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'],
|
||||
@@ -896,7 +826,7 @@ stack(
|
||||
x? ~ ~ x@3 ~ x |
|
||||
x? ~ ~ x ~ x@3\`),
|
||||
roots.struct("x [~ x?0.2] x [~ x?] | x!4 | x@2 ~ ~ ~ x x x").transpose("0 7")
|
||||
).slow(2).pianoroll().note().piano().out();`;
|
||||
).slow(2).pianoroll().note().piano().out()`;
|
||||
|
||||
export const chop = `samples({ p: 'https://cdn.freesound.org/previews/648/648433_11943129-lq.mp3' })
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ import '@strudel.cycles/react/dist/style.css';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<div className="min-h-screen">
|
||||
<header className="flex-none flex justify-start sticky top-0 z-[2] w-full h-16 px-2 items-center border-b border-gray-200 bg-white">
|
||||
<div className="p-4 w-full flex justify-between">
|
||||
<div className="min-h-screen bg-slate-900">
|
||||
<header className="flex-none flex justify-start sticky top-0 z-[2] w-full h-16 px-2 items-center border-b border-slate-500 text-white bg-slate-900 z-[100]">
|
||||
<div className="p-4 w-full flex justify-between items-center">
|
||||
<div className="flex items-center space-x-2">
|
||||
<img src={'https://tidalcycles.org/img/logo.svg'} className="Tidal-logo w-10 h-10" alt="logo" />
|
||||
<h1 className="text-xl cursor-pointer" onClick={() => window.scrollTo(0, 0)}>
|
||||
@@ -23,15 +23,14 @@ ReactDOM.render(
|
||||
</h1>
|
||||
</div>
|
||||
{!window.location.href.includes('localhost') && (
|
||||
<div className="flex space-x-4">
|
||||
<div className="flex space-x-4 text-slate-200">
|
||||
<a href="../">go to REPL</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
<main className="p-4 pl-6 max-w-3xl prose">
|
||||
<main className="p-4 pl-6 max-w-3xl prose prose-invert">
|
||||
<Tutorial />
|
||||
{/* <ApiDoc /> */}
|
||||
</main>
|
||||
</div>
|
||||
</React.StrictMode>,
|
||||
|
||||
+27
-55
@@ -365,10 +365,24 @@ note("g2!2 <bb2 c3>!2, <c4@3 [<eb4 bb3> g4 f4]>")
|
||||
|
||||
The sampler will always pick the closest matching sample for the current note!
|
||||
|
||||
## Effects
|
||||
## Sampler Effects
|
||||
|
||||
{{ 'Pattern.begin' | jsdoc }}
|
||||
|
||||
{{ 'Pattern.end' | jsdoc }}
|
||||
|
||||
{{ 'Pattern.loopAt' | jsdoc }}
|
||||
|
||||
{{ 'Pattern.chop' | jsdoc }}
|
||||
|
||||
## Audio Effects
|
||||
|
||||
Wether you're using a synth or a sample, you can apply these effects:
|
||||
|
||||
{{ 'gain' | jsdoc }}
|
||||
|
||||
{{ 'velocity' | jsdoc }}
|
||||
|
||||
{{ 'cutoff' | jsdoc }}
|
||||
|
||||
{{ 'resonance' | jsdoc }}
|
||||
@@ -496,11 +510,15 @@ The following functions modify a pattern temporal structure in some way.
|
||||
|
||||
{{ 'Pattern.late' | jsdoc }}
|
||||
|
||||
{{ 'Pattern.rev' | jsdoc }}
|
||||
{{ 'Pattern.legato' | jsdoc }}
|
||||
|
||||
{{ 'Pattern.struct' | jsdoc }}
|
||||
|
||||
{{ 'Pattern.legato' | jsdoc }}
|
||||
{{ 'Pattern.euclid' | jsdoc }}
|
||||
|
||||
{{ 'Pattern.euclidLegato' | jsdoc }}
|
||||
|
||||
{{ 'Pattern.rev' | jsdoc }}
|
||||
|
||||
{{ 'Pattern.iter' | jsdoc }}
|
||||
|
||||
@@ -536,63 +554,17 @@ The following functions modify a pattern temporal structure in some way.
|
||||
|
||||
## Value Modifiers
|
||||
|
||||
### add(n)
|
||||
{{ 'Pattern.add' | jsdoc }}
|
||||
|
||||
Adds the given number to each item in the pattern:
|
||||
{{ 'Pattern.sub' | jsdoc }}
|
||||
|
||||
<MiniRepl tune={`"0 2 4".add("<0 3 4 0>").scale('C major')`} />
|
||||
{{ 'Pattern.mul' | jsdoc }}
|
||||
|
||||
Here, the triad `0, 2, 4` is shifted by different amounts. Without add, the equivalent would be:
|
||||
{{ 'Pattern.div' | jsdoc }}
|
||||
|
||||
<MiniRepl tune={`"<[0 2 4] [3 5 7] [4 6 8] [0 2 4]>".scale('C major')`} />
|
||||
{{ 'Pattern.round' | jsdoc }}
|
||||
|
||||
You can also use add with notes:
|
||||
|
||||
<MiniRepl tune={`"c3 e3 g3".add("<0 5 7 0>")`} />
|
||||
|
||||
Behind the scenes, the notes are converted to midi numbers as soon before add is applied, which is equivalent to:
|
||||
|
||||
<MiniRepl tune={`"48 52 55".add("<0 5 7 0>")`} />
|
||||
|
||||
### sub(n)
|
||||
|
||||
Like add, but the given numbers are subtracted:
|
||||
|
||||
<MiniRepl tune={`"0 2 4".sub("<0 1 2 3>").scale('C4 minor')`} />
|
||||
|
||||
See add for more information.
|
||||
|
||||
### mul(n)
|
||||
|
||||
Multiplies each number by the given factor:
|
||||
|
||||
<MiniRepl tune={`"0,1,2".mul("<2 3 4 3>").scale('C4 minor')`} />
|
||||
|
||||
... is equivalent to:
|
||||
|
||||
<MiniRepl tune={`"<[0,2,4] [0,3,6] [0,4,8] [0,3,6]>".scale('C4 minor')`} />
|
||||
|
||||
This function is really useful in combination with signals:
|
||||
|
||||
<MiniRepl tune={`sine.struct("x*16").mul(7).round().scale('C major')`} />
|
||||
|
||||
Here, we sample a sine wave 16 times, and multiply each sample by 7. This way, we let values oscillate between 0 and 7.
|
||||
|
||||
### div(n)
|
||||
|
||||
Like mul, but dividing by the given number.
|
||||
|
||||
### round()
|
||||
|
||||
Rounds all values to the nearest integer:
|
||||
|
||||
<MiniRepl tune={`"0.5 1.5 2.5".round().scale('C major')`} />
|
||||
|
||||
### apply(func)
|
||||
|
||||
Like layer, but with a single function:
|
||||
|
||||
<MiniRepl tune={`"<c3 eb3 g3>".scale('C minor').apply(scaleTranspose("0,2,4"))`} />
|
||||
{{ 'Pattern.apply' | jsdoc }}
|
||||
|
||||
{{ 'Pattern.range' | jsdoc }}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user