mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-27 23:38:49 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e477268417 |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/codemirror",
|
"name": "@strudel/codemirror",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Codemirror Extensions for Strudel",
|
"description": "Codemirror Extensions for Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/core",
|
"name": "@strudel/core",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Port of Tidal Cycles to JavaScript",
|
"description": "Port of Tidal Cycles to JavaScript",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/csound",
|
"name": "@strudel/csound",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "csound bindings for strudel",
|
"description": "csound bindings for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/draw",
|
"name": "@strudel/draw",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Helpers for drawing with Strudel",
|
"description": "Helpers for drawing with Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/gamepad",
|
"name": "@strudel/gamepad",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Gamepad Inputs for strudel",
|
"description": "Gamepad Inputs for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -35,3 +35,4 @@
|
|||||||
"vite": "^6.0.11"
|
"vite": "^6.0.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hs2js",
|
"name": "hs2js",
|
||||||
"version": "0.2.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
|
||||||
"description": "Experimental Haskell in JavaScript interpreter",
|
"description": "Experimental Haskell in JavaScript interpreter",
|
||||||
"main": "src/index.mjs",
|
"main": "src/index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/hydra",
|
"name": "@strudel/hydra",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Hydra integration for strudel",
|
"description": "Hydra integration for strudel",
|
||||||
"main": "hydra.mjs",
|
"main": "hydra.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/midi",
|
"name": "@strudel/midi",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Midi API for strudel",
|
"description": "Midi API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/mini",
|
"name": "@strudel/mini",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Mini notation for strudel",
|
"description": "Mini notation for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/motion",
|
"name": "@strudel/motion",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "DeviceMotion API for strudel",
|
"description": "DeviceMotion API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -35,3 +35,4 @@
|
|||||||
"vite": "^6.0.11"
|
"vite": "^6.0.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/mqtt",
|
"name": "@strudel/mqtt",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "MQTT API for strudel",
|
"description": "MQTT API for strudel",
|
||||||
"main": "mqtt.mjs",
|
"main": "mqtt.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/osc",
|
"name": "@strudel/osc",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "OSC messaging for strudel",
|
"description": "OSC messaging for strudel",
|
||||||
"main": "osc.mjs",
|
"main": "osc.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/reference",
|
"name": "@strudel/reference",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Headless reference of all strudel functions",
|
"description": "Headless reference of all strudel functions",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -31,6 +31,8 @@
|
|||||||
"url": "https://github.com/tidalcycles/strudel/issues"
|
"url": "https://github.com/tidalcycles/strudel/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/tidalcycles/strudel#readme",
|
"homepage": "https://github.com/tidalcycles/strudel#readme",
|
||||||
|
"dependencies": {
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"vite": "^6.0.11"
|
"vite": "^6.0.11"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
import { dependencies } from './package.json';
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
@@ -10,6 +11,9 @@ export default defineConfig({
|
|||||||
formats: ['es'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
external: [...Object.keys(dependencies)],
|
||||||
|
},
|
||||||
target: 'esnext',
|
target: 'esnext',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/repl",
|
"name": "@strudel/repl",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Strudel REPL as a Web Component",
|
"description": "Strudel REPL as a Web Component",
|
||||||
"module": "index.mjs",
|
"module": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/sampler",
|
"name": "@strudel/sampler",
|
||||||
"version": "0.2.0",
|
"version": "0.1.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"tidalcycles",
|
"tidalcycles",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/serial",
|
"name": "@strudel/serial",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Webserial API for strudel",
|
"description": "Webserial API for strudel",
|
||||||
"main": "serial.mjs",
|
"main": "serial.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/soundfonts",
|
"name": "@strudel/soundfonts",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Soundsfont support for strudel",
|
"description": "Soundsfont support for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "superdough",
|
"name": "superdough",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.",
|
"description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ export const DEFAULT_MAX_POLYPHONY = 128;
|
|||||||
const DEFAULT_AUDIO_DEVICE_NAME = 'System Standard';
|
const DEFAULT_AUDIO_DEVICE_NAME = 'System Standard';
|
||||||
|
|
||||||
let maxPolyphony = DEFAULT_MAX_POLYPHONY;
|
let maxPolyphony = DEFAULT_MAX_POLYPHONY;
|
||||||
|
|
||||||
export function setMaxPolyphony(polyphony) {
|
export function setMaxPolyphony(polyphony) {
|
||||||
maxPolyphony = parseInt(polyphony) ?? DEFAULT_MAX_POLYPHONY;
|
maxPolyphony = parseInt(polyphony) ?? DEFAULT_MAX_POLYPHONY;
|
||||||
}
|
}
|
||||||
@@ -29,16 +28,6 @@ export function registerSound(key, onTrigger, data = {}) {
|
|||||||
soundMap.setKey(key, { onTrigger, data });
|
soundMap.setKey(key, { onTrigger, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
let gainCurveFunc = (val) => val;
|
|
||||||
|
|
||||||
export function applyGainCurve(val) {
|
|
||||||
return gainCurveFunc(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setGainCurve(newGainCurveFunc) {
|
|
||||||
gainCurveFunc = newGainCurveFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
function aliasBankMap(aliasMap) {
|
function aliasBankMap(aliasMap) {
|
||||||
// Make all bank keys lower case for case insensitivity
|
// Make all bank keys lower case for case insensitivity
|
||||||
for (const key in aliasMap) {
|
for (const key in aliasMap) {
|
||||||
@@ -526,13 +515,7 @@ export const superdough = async (value, t, hapDuration) => {
|
|||||||
compressorRelease,
|
compressorRelease,
|
||||||
} = value;
|
} = value;
|
||||||
|
|
||||||
gain = applyGainCurve(nanFallback(gain, 1));
|
gain = nanFallback(gain, 1);
|
||||||
postgain = applyGainCurve(postgain);
|
|
||||||
shapevol = applyGainCurve(shapevol);
|
|
||||||
distortvol = applyGainCurve(distortvol);
|
|
||||||
delay = applyGainCurve(delay);
|
|
||||||
velocity = applyGainCurve(velocity);
|
|
||||||
gain *= velocity; // velocity currently only multiplies with gain. it might do other things in the future
|
|
||||||
|
|
||||||
const chainID = Math.round(Math.random() * 1000000);
|
const chainID = Math.round(Math.random() * 1000000);
|
||||||
|
|
||||||
@@ -549,7 +532,7 @@ export const superdough = async (value, t, hapDuration) => {
|
|||||||
|
|
||||||
//music programs/audio gear usually increments inputs/outputs from 1, so imitate that behavior
|
//music programs/audio gear usually increments inputs/outputs from 1, so imitate that behavior
|
||||||
channels = (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1);
|
channels = (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1);
|
||||||
|
gain *= velocity; // velocity currently only multiplies with gain. it might do other things in the future
|
||||||
let audioNodes = [];
|
let audioNodes = [];
|
||||||
|
|
||||||
if (bank && s) {
|
if (bank && s) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/tidal",
|
"name": "@strudel/tidal",
|
||||||
"version": "0.2.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
|
||||||
"description": "Experimental Tidal Code interpreter",
|
"description": "Experimental Tidal Code interpreter",
|
||||||
"module": "tidal.mjs",
|
"module": "tidal.mjs",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/tonal",
|
"name": "@strudel/tonal",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Tonal functions for strudel",
|
"description": "Tonal functions for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/transpiler",
|
"name": "@strudel/transpiler",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
|
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/web",
|
"name": "@strudel/web",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Easy to setup, opiniated bundle of Strudel for the browser.",
|
"description": "Easy to setup, opiniated bundle of Strudel for the browser.",
|
||||||
"module": "web.mjs",
|
"module": "web.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/webaudio",
|
"name": "@strudel/webaudio",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Web Audio helpers for Strudel",
|
"description": "Web Audio helpers for Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/xen",
|
"name": "@strudel/xen",
|
||||||
"version": "1.2.0",
|
"version": "1.1.0",
|
||||||
"description": "Xenharmonic API for strudel",
|
"description": "Xenharmonic API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ While it saves resources, it can also lead to sounds not being audible the first
|
|||||||
|
|
||||||
# Sound Banks
|
# Sound Banks
|
||||||
|
|
||||||
If we open the `sounds` tab and then `drum-machines`, we can see that the drum samples are all prefixed with drum machine names: `RolandTR808_bd`, `RolandTR808_sd`, `RolandTR808_hh` etc..
|
If we open the `sounds` tab and then `drum machines`, we can see that the drum samples are all prefixed with drum machine names: `RolandTR808_bd`, `RolandTR808_sd`, `RolandTR808_hh` etc..
|
||||||
|
|
||||||
We _could_ use them like this:
|
We _could_ use them like this:
|
||||||
|
|
||||||
@@ -180,12 +180,11 @@ It assumes a `strudel.json` file to be present at the root of the repository:
|
|||||||
https://raw.githubusercontent.com/<user>/<repo>/<branch>/strudel.json
|
https://raw.githubusercontent.com/<user>/<repo>/<branch>/strudel.json
|
||||||
```
|
```
|
||||||
|
|
||||||
## From Disk via "Import Sounds Folder"
|
## From Disk via "Import Sounds"
|
||||||
|
|
||||||
If you don't want to upload your samples to the internet, you can also load them from your local disk.
|
If you don't want to upload your samples to the internet, you can also load them from your local disk.
|
||||||
Go to the `sounds` tab in the REPL and open the `import-sounds` tab below the search bar.
|
Go to the `sounds` tab in the REPL and press "import sounds".
|
||||||
Press the "import sounds folder" button and select a folder that contains audio files.
|
Then you can select a folder that contains audio files. The folder you select can also contain subfolders with audio files.
|
||||||
The folder you select can also contain subfolders with audio files.
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -201,13 +200,12 @@ Example:
|
|||||||
```
|
```
|
||||||
|
|
||||||
In the above example the folder `samples` contains 2 subfolders `swoop` and `smash`, which contain audio files.
|
In the above example the folder `samples` contains 2 subfolders `swoop` and `smash`, which contain audio files.
|
||||||
If you select that `samples` folder, the `user` tab (next to the `import-sounds` tab) will then contain 2 new sounds: `swoop(3) smash(3)`
|
If you select that `samples` folder, the `user` tab (next to the import sounds button) will then contain 2 new sounds: `swoop(3) smash(3)`
|
||||||
The individual samples can the be played normally like `s("swoop:0 swoop:1 smash:2")`.
|
The individual samples can the be played normally like `s("swoop:0 swoop:1 smash:2")`.
|
||||||
The samples within each sound use zero-based indexing in alphabetical order.
|
|
||||||
|
|
||||||
## From Disk via @strudel/sampler
|
## From Disk via @strudel/sampler
|
||||||
|
|
||||||
Instead of loading your samples into your browser with the "import sounds folder" button, you can also serve the samples from a local file server.
|
Instead of loading your samples into your browser with the "import sounds" button, you can also serve the samples from a local file server.
|
||||||
The easiest way to do this is using [@strudel/sampler](https://www.npmjs.com/package/@strudel/sampler):
|
The easiest way to do this is using [@strudel/sampler](https://www.npmjs.com/package/@strudel/sampler):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
@@ -296,16 +296,23 @@ The whole modulation will now take 8 cycles to repeat.
|
|||||||
|
|
||||||
## Recap
|
## Recap
|
||||||
|
|
||||||
| name | example |
|
| Name | Description | Example |
|
||||||
| ------- | ---------------------------------------------------------------------------------------------------------------- |
|
| ------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
|
||||||
| lpf | <MiniRepl client:visible tune={`note("c2 c3 c2 c3").s("sawtooth").lpf("<400 2000>")`} /> |
|
| lpf | Low-pass filter, cuts high frequencies | <MiniRepl client:visible tune={`note("c2 c3 c2 c3").s("sawtooth").lpf("<400 2000>")`} /> |
|
||||||
| vowel | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
|
| vowel | Vowel-like filter | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
|
||||||
| gain | <MiniRepl client:visible tune={`s("hh*16").gain("[.25 1]*2")`} /> |
|
| gain | Adjusts volume/amplitude | <MiniRepl client:visible tune={`s("hh*16").gain("[.25 1]*2")`} /> |
|
||||||
| delay | <MiniRepl client:visible tune={`s("bd rim bd cp").delay(.5)`} /> |
|
| attack | ADSR: Time to reach full volume | <MiniRepl client:visible tune={`note("c3").s("sawtooth").attack(.5)`} /> |
|
||||||
| room | <MiniRepl client:visible tune={`s("bd rim bd cp").room(.5)`} /> |
|
| decay | ADSR: Time to reach sustain level | <MiniRepl client:visible tune={`note("c3").s("sawtooth").decay(.5)`} /> |
|
||||||
| pan | <MiniRepl client:visible tune={`s("bd rim bd cp").pan("0 1")`} /> |
|
| sustain | ADSR: Volume level while note is held | <MiniRepl client:visible tune={`note("c3").s("sawtooth").sustain(.5)`} /> |
|
||||||
| speed | <MiniRepl client:visible tune={`s("bd rim bd cp").speed("<1 2 -1 -2>")`} /> |
|
| release | ADSR: Time to fade out after note ends | <MiniRepl client:visible tune={`note("c3").s("sawtooth").release(.5)`} /> |
|
||||||
| signals | `sine`, `saw`, `square`, `tri`, `rand`, `perlin`<br/><MiniRepl client:visible tune={`s("hh*16").gain (saw)`} /> |
|
| adsr | ADSR: Short notation (attack:decay:sustain:release) | <MiniRepl client:visible tune={`note("c3").s("sawtooth").adsr(".1:.2:.5:.3")`} /> |
|
||||||
| range | <MiniRepl client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> |
|
| delay | Creates echoes | <MiniRepl client:visible tune={`s("bd rim bd cp").delay(.5)`} /> |
|
||||||
|
| room | Simulates room reverb | <MiniRepl client:visible tune={`s("bd rim bd cp").room(.5)`} /> |
|
||||||
|
| pan | Pans sound left (0) to right (1) | <MiniRepl client:visible tune={`s("bd rim bd cp").pan("0 1")`} /> |
|
||||||
|
| speed | Changes playback speed (and pitch) | <MiniRepl client:visible tune={`s("bd rim bd cp").speed("<1 2 -1 -2>")`} /> |
|
||||||
|
| fast | Speeds up pattern playback (outside mini-notation) | <MiniRepl client:visible tune={`s("bd sd").fast(2)`} /> |
|
||||||
|
| slow | Slows down pattern playback (outside mini-notation)| <MiniRepl client:visible tune={`s("bd sd").slow(2)`} /> |
|
||||||
|
| signals | Modulate parameters with waveforms (`sine`, etc.) | `sine`, `saw`, `square`, `tri`, `rand`, `perlin`<br/><MiniRepl client:visible tune={`s("hh*16").gain(saw)`} /> |
|
||||||
|
| range | Set min/max values for signal modulation | <MiniRepl client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> |
|
||||||
|
|
||||||
Let us now take a look at some of Tidal's typical [pattern effects](/workshop/pattern-effects).
|
Let us now take a look at some of Tidal's typical [pattern effects](/workshop/pattern-effects).
|
||||||
|
|||||||
@@ -305,12 +305,14 @@ What's the difference?
|
|||||||
|
|
||||||
Let's recap what we've learned in this chapter:
|
Let's recap what we've learned in this chapter:
|
||||||
|
|
||||||
| Concept | Syntax | Example |
|
| Concept | Syntax | Description | Example |
|
||||||
| --------- | ------ | -------------------------------------------------------- |
|
| --------------- | ------ | ---------------------------------------------- | -------------------------------------------------------------------------- |
|
||||||
| Slow down | \/ | <MiniRepl client:visible tune={`note("[c a f e]/2")`} /> |
|
| Slow down | / | Divide a sequence over multiple cycles | <MiniRepl client:visible tune={`note("[c a f e]/2")`} /> |
|
||||||
| Alternate | \<\> | <MiniRepl client:visible tune={`note("c a f <e g>")`} /> |
|
| Alternate | \<\> | Play one element per cycle from a sequence | <MiniRepl client:visible tune={`note("c a f <e g>")`} /> |
|
||||||
| Elongate | @ | <MiniRepl client:visible tune={`note("c@3 e")`} /> |
|
| Elongate | @ | Extend the duration of an element | <MiniRepl client:visible tune={`note("c@3 e")`} /> |
|
||||||
| Replicate | ! | <MiniRepl client:visible tune={`note("c!3 e")`} /> |
|
| Replicate | ! | Repeat an element multiple times | <MiniRepl client:visible tune={`note("c!3 e")`} /> |
|
||||||
|
| Switch sounds | space | Cycle through sounds within the `sound` func | <MiniRepl client:visible tune={`note("c e").sound("piano sawtooth")`} /> |
|
||||||
|
| Stack sounds | , | Play multiple sounds together in `sound` func | <MiniRepl client:visible tune={`note("c e").sound("piano, sawtooth")`} /> |
|
||||||
|
|
||||||
New functions:
|
New functions:
|
||||||
|
|
||||||
|
|||||||
@@ -270,16 +270,17 @@ This is shorter and more readable than:
|
|||||||
Now we've learned the basics of the so called Mini-Notation, the rhythm language of Tidal.
|
Now we've learned the basics of the so called Mini-Notation, the rhythm language of Tidal.
|
||||||
This is what we've learned so far:
|
This is what we've learned so far:
|
||||||
|
|
||||||
| Concept | Syntax | Example |
|
| Concept | Syntax | Description | Example |
|
||||||
| ----------------- | -------- | ----------------------------------------------------------------------- |
|
| ----------------- | -------- | ----------------------------------------- | ----------------------------------------------------------------------- |
|
||||||
| Sequence | space | <MiniRepl client:visible tune={`sound("bd bd sd hh")`} /> |
|
| Sequence | space | Play sounds one after another | <MiniRepl client:visible tune={`sound("bd bd sd hh bd cp sd hh")`} /> |
|
||||||
| Sample Number | :x | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
|
| Sample Number | :x | Select a specific sample from a sound | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
|
||||||
| Rests | - or ~ | <MiniRepl client:visible tune={`sound("metal - jazz jazz:1")`} /> |
|
| Rests | - or ~ | Add silence into the sequence | <MiniRepl client:visible tune={`sound("metal ~ jazz jazz:1")`} /> |
|
||||||
| Alternate | \<\> | <MiniRepl client:visible tune={`sound("<bd hh rim oh bd rim>")`} /> |
|
| Alternate | \<\> | <MiniRepl client:visible tune={`sound("<bd hh rim oh bd rim>")`} /> |
|
||||||
| Sub-Sequences | \[\] | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
|
| Sub-Sequences | \[\] | Group elements, squished into their space | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
|
||||||
| Sub-Sub-Sequences | \[\[\]\] | <MiniRepl client:visible tune={`sound("bd [metal [jazz [sd cp]]]")`} /> |
|
| Sub-Sub-Sequences | \[\[\]\] | Nest groups within groups | <MiniRepl client:visible tune={`sound("bd [metal [jazz sd]]")`} /> |
|
||||||
| Speed up | \* | <MiniRepl client:visible tune={`sound("bd sd*2 cp*3")`} /> |
|
| Speed up | \* | Make elements play faster | <MiniRepl client:visible tune={`sound("bd sd*2 cp*3")`} /> |
|
||||||
| Parallel | , | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
|
| Parallel | , | Play multiple sequences at the same time | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
|
||||||
|
| Multiple-Lines | \`\` | Write sequences across multiple lines | <MiniRepl client:visible tune={'sound(`bd*2, \n hh*4`)'} /> |
|
||||||
|
|
||||||
The Mini-Notation is usually used inside some function. These are the functions we've seen so far:
|
The Mini-Notation is usually used inside some function. These are the functions we've seen so far:
|
||||||
|
|
||||||
|
|||||||
@@ -11,19 +11,20 @@ This page is just a listing of all functions covered in the workshop!
|
|||||||
|
|
||||||
## Mini Notation
|
## Mini Notation
|
||||||
|
|
||||||
| Concept | Syntax | Example |
|
| Concept | Syntax | Description | Example |
|
||||||
| ----------------- | -------- | --------------------------------------------------------------------- |
|
| ----------------- | -------- | ----------------------------------------- | ----------------------------------------------------------------------- |
|
||||||
| Sequence | space | <MiniRepl client:visible tune={`sound("bd bd sd hh bd cp sd hh")`} /> |
|
| Sequence | space | Play sounds one after another | <MiniRepl client:visible tune={`sound("bd bd sd hh bd cp sd hh")`} /> |
|
||||||
| Sample Number | :x | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
|
| Sample Number | :x | Select a specific sample from a sound | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
|
||||||
| Rests | ~ | <MiniRepl client:visible tune={`sound("metal ~ jazz jazz:1")`} /> |
|
| Rests | ~ | Add silence into the sequence | <MiniRepl client:visible tune={`sound("metal ~ jazz jazz:1")`} /> |
|
||||||
| Sub-Sequences | \[\] | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
|
| Sub-Sequences | \[\] | Group elements, squished into their space | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
|
||||||
| Sub-Sub-Sequences | \[\[\]\] | <MiniRepl client:visible tune={`sound("bd [metal [jazz sd]]")`} /> |
|
| Sub-Sub-Sequences | \[\[\]\] | Nest groups within groups | <MiniRepl client:visible tune={`sound("bd [metal [jazz sd]]")`} /> |
|
||||||
| Speed up | \* | <MiniRepl client:visible tune={`sound("bd sd*2 cp*3")`} /> |
|
| Speed up | \* | Make elements play faster | <MiniRepl client:visible tune={`sound("bd sd*2 cp*3")`} /> |
|
||||||
| Parallel | , | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
|
| Parallel | , | Play multiple sequences at the same time | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
|
||||||
| Slow down | \/ | <MiniRepl client:visible tune={`note("[c a f e]/2")`} /> |
|
| Slow down | \/ | Divide a sequence over multiple cycles | <MiniRepl client:visible tune={`note("[c a f e]/2")`} /> |
|
||||||
| Alternate | \<\> | <MiniRepl client:visible tune={`note("c <e g>")`} /> |
|
| Alternate | \<\> | Play one element per cycle from a sequence| <MiniRepl client:visible tune={`note("c <e g>")`} /> |
|
||||||
| Elongate | @ | <MiniRepl client:visible tune={`note("c@3 e")`} /> |
|
| Elongate | @ | Extend the duration of an element | <MiniRepl client:visible tune={`note("c@3 e")`} /> |
|
||||||
| Replicate | ! | <MiniRepl client:visible tune={`note("c!3 e")`} /> |
|
| Replicate | ! | Repeat an element multiple times | <MiniRepl client:visible tune={`note("c!3 e")`} /> |
|
||||||
|
| Multiple-Lines | \`\` | Write sequences across multiple lines | <MiniRepl client:visible tune={'sound(`bd*2, \n hh*4`)'} /> |
|
||||||
|
|
||||||
## Sounds
|
## Sounds
|
||||||
|
|
||||||
@@ -43,20 +44,26 @@ This page is just a listing of all functions covered in the workshop!
|
|||||||
|
|
||||||
## Audio Effects
|
## Audio Effects
|
||||||
|
|
||||||
| name | example |
|
| Name | Description | Example |
|
||||||
| ----- | --------------------------------------------------------------------------------------- |
|
| ------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
|
||||||
| lpf | <MiniRepl client:visible tune={`note("c2 c3 c2 c3").s("sawtooth").lpf("400 2000")`} /> |
|
| lpf | Low-pass filter, cuts high frequencies | <MiniRepl client:visible tune={`note("c2 c3 c2 c3").s("sawtooth").lpf("400 2000")`} /> |
|
||||||
| vowel | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
|
| vowel | Vowel-like filter | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
|
||||||
| gain | <MiniRepl client:visible tune={`s("hh*16").gain("[.25 1]*4")`} /> |
|
| gain | Adjusts volume/amplitude | <MiniRepl client:visible tune={`s("hh*16").gain("[.25 1]*2")`} /> |
|
||||||
| delay | <MiniRepl client:visible tune={`s("bd rim bd cp").delay(.5)`} /> |
|
| attack | ADSR: Time to reach full volume | <MiniRepl client:visible tune={`note("c3").s("sawtooth").attack(.5)`} /> |
|
||||||
| room | <MiniRepl client:visible tune={`s("bd rim bd cp").room(.5)`} /> |
|
| decay | ADSR: Time to reach sustain level | <MiniRepl client:visible tune={`note("c3").s("sawtooth").decay(.5)`} /> |
|
||||||
| pan | <MiniRepl client:visible tune={`s("bd rim bd cp").pan("0 1")`} /> |
|
| sustain | ADSR: Volume level while note is held | <MiniRepl client:visible tune={`note("c3").s("sawtooth").sustain(.5)`} /> |
|
||||||
| speed | <MiniRepl client:visible tune={`s("bd rim bd cp").speed("<1 2 -1 -2>")`} /> |
|
| release | ADSR: Time to fade out after note ends | <MiniRepl client:visible tune={`note("c3").s("sawtooth").release(.5)`} /> |
|
||||||
| range | <MiniRepl client:visible tune={`s("hh*32").lpf(saw.range(200,4000))`} /> |
|
| adsr | ADSR: Short notation (attack:decay:sustain:release) | <MiniRepl client:visible tune={`note("c3").s("sawtooth").adsr(".1:.2:.5:.3")`} /> |
|
||||||
|
| delay | Creates echoes | <MiniRepl client:visible tune={`s("bd rim bd cp").delay(.5)`} /> |
|
||||||
|
| room | Simulates room reverb | <MiniRepl client:visible tune={`s("bd rim bd cp").room(.5)`} /> |
|
||||||
|
| pan | Pans sound left (0) to right (1) | <MiniRepl client:visible tune={`s("bd rim bd cp").pan("0 1")`} /> |
|
||||||
|
| speed | Changes playback speed (and pitch) | <MiniRepl client:visible tune={`s("bd rim bd cp").speed("<1 2 -1 -2>")`} /> |
|
||||||
|
| signals | Modulate parameters with waveforms (`sine`, etc.) | `sine`, `saw`, `square`, `tri`, `rand`, `perlin`<br/><MiniRepl client:visible tune={`s("hh*16").gain(saw)`} /> |
|
||||||
|
| range | Set min/max values for signal modulation | <MiniRepl client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> |
|
||||||
|
|
||||||
## Pattern Effects
|
## Pattern Effects
|
||||||
|
|
||||||
| name | description | example |
|
| Name | Description | Example |
|
||||||
| ---- | ----------------------------------- | ----------------------------------------------------------------------------------- |
|
| ---- | ----------------------------------- | ----------------------------------------------------------------------------------- |
|
||||||
| cpm | sets the tempo in cycles per minute | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").cpm(45)`} /> |
|
| cpm | sets the tempo in cycles per minute | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").cpm(45)`} /> |
|
||||||
| fast | speed up | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").fast(2)`} /> |
|
| fast | speed up | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").fast(2)`} /> |
|
||||||
|
|||||||
@@ -20,26 +20,10 @@ export default function ImportSoundsButton({ onComplete }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
|
||||||
<label
|
<label
|
||||||
style={{ alignItems: 'center', borderColor: 'red', border: 1 }}
|
style={{ alignItems: 'center' }}
|
||||||
className="flex bg-background p-4 w-fit rounded-xl hover:opacity-50 whitespace-nowrap cursor-pointer"
|
className="flex bg-background ml-2 pl-2 pr-2 max-w-[300px] rounded-md hover:opacity-50 whitespace-nowrap cursor-pointer"
|
||||||
>
|
>
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth={1.5}
|
|
||||||
stroke="currentColor"
|
|
||||||
className="size-6 mr-2"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M7.5 7.5h-.75A2.25 2.25 0 0 0 4.5 9.75v7.5a2.25 2.25 0 0 0 2.25 2.25h7.5a2.25 2.25 0 0 0 2.25-2.25v-7.5a2.25 2.25 0 0 0-2.25-2.25h-.75m0-3-3-3m0 0-3 3m3-3v11.25m6-2.25h.75a2.25 2.25 0 0 1 2.25 2.25v7.5a2.25 2.25 0 0 1-2.25 2.25h-7.5a2.25 2.25 0 0 1-2.25-2.25v-.75"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<input
|
<input
|
||||||
disabled={isUploading}
|
disabled={isUploading}
|
||||||
ref={fileUploadRef}
|
ref={fileUploadRef}
|
||||||
@@ -54,8 +38,7 @@ export default function ImportSoundsButton({ onComplete }) {
|
|||||||
onChange();
|
onChange();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{isUploading ? 'importing...' : 'import sounds folder'}
|
{isUploading ? 'importing...' : 'import sounds'}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ export function SoundsTab() {
|
|||||||
const sounds = useStore(soundMap);
|
const sounds = useStore(soundMap);
|
||||||
const { soundsFilter } = useSettings();
|
const { soundsFilter } = useSettings();
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const { BASE_URL } = import.meta.env;
|
|
||||||
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;
|
|
||||||
|
|
||||||
const soundEntries = useMemo(() => {
|
const soundEntries = useMemo(() => {
|
||||||
if (!sounds) {
|
if (!sounds) {
|
||||||
@@ -39,9 +37,6 @@ export function SoundsTab() {
|
|||||||
if (soundsFilter === 'synths') {
|
if (soundsFilter === 'synths') {
|
||||||
return filtered.filter(([_, { data }]) => ['synth', 'soundfont'].includes(data.type));
|
return filtered.filter(([_, { data }]) => ['synth', 'soundfont'].includes(data.type));
|
||||||
}
|
}
|
||||||
if (soundsFilter === 'importSounds') {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return filtered;
|
return filtered;
|
||||||
}, [sounds, soundsFilter, search]);
|
}, [sounds, soundsFilter, search]);
|
||||||
|
|
||||||
@@ -56,6 +51,7 @@ export function SoundsTab() {
|
|||||||
ref?.stop(getAudioContext().currentTime + 0.01);
|
ref?.stop(getAudioContext().currentTime + 0.01);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="sounds-tab" className="px-4 flex flex-col w-full h-full text-foreground">
|
<div id="sounds-tab" className="px-4 flex flex-col w-full h-full text-foreground">
|
||||||
<Textbox placeholder="Search" value={search} onChange={(v) => setSearch(v)} />
|
<Textbox placeholder="Search" value={search} onChange={(v) => setSearch(v)} />
|
||||||
@@ -69,9 +65,9 @@ export function SoundsTab() {
|
|||||||
drums: 'drum-machines',
|
drums: 'drum-machines',
|
||||||
synths: 'Synths',
|
synths: 'Synths',
|
||||||
user: 'User',
|
user: 'User',
|
||||||
importSounds: 'import-sounds',
|
|
||||||
}}
|
}}
|
||||||
></ButtonGroup>
|
></ButtonGroup>
|
||||||
|
<ImportSoundsButton onComplete={() => settingsMap.setKey('soundsFilter', 'user')} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="min-h-0 max-h-full grow overflow-auto text-sm break-normal pb-2">
|
<div className="min-h-0 max-h-full grow overflow-auto text-sm break-normal pb-2">
|
||||||
@@ -105,55 +101,7 @@ export function SoundsTab() {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{!soundEntries.length && soundsFilter === 'importSounds' ? (
|
{!soundEntries.length ? 'No custom sounds loaded in this pattern (yet).' : ''}
|
||||||
<div className="prose dark:prose-invert min-w-full pt-2 pb-8 px-4">
|
|
||||||
<ImportSoundsButton onComplete={() => settingsMap.setKey('soundsFilter', 'user')} />
|
|
||||||
<p>
|
|
||||||
To import sounds into strudel, they must be contained{' '}
|
|
||||||
<a href={`${baseNoTrailing}/learn/samples/#from-disk-via-import-sounds-folder`} target="_blank">
|
|
||||||
within a folder or subfolder
|
|
||||||
</a>
|
|
||||||
. The best way to do this is to upload a “samples” folder containing subfolders of individual sounds or
|
|
||||||
soundbanks (see diagram below).{' '}
|
|
||||||
</p>
|
|
||||||
<pre className="bg-background" key={'sample-diagram'}>
|
|
||||||
{`└─ samples <-- import this folder
|
|
||||||
├─ swoop
|
|
||||||
│ ├─ swoopshort.wav
|
|
||||||
│ ├─ swooplong.wav
|
|
||||||
│ └─ swooptight.wav
|
|
||||||
└─ smash
|
|
||||||
├─ smashhigh.wav
|
|
||||||
├─ smashlow.wav
|
|
||||||
└─ smashmiddle.wav`}
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
The name of a subfolder corresponds to the sound name under the “user” tab. Multiple samples within a
|
|
||||||
subfolder are all labelled with the same name, but can be accessed using “.n( )” - remember sounds are
|
|
||||||
zero-indexed and in alphabetical order!
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
For more information, and other ways to use your own sounds in strudel,{' '}
|
|
||||||
<a href={`${baseNoTrailing}/learn/samples/#from-disk-via-import-sounds-folder`} target="_blank">
|
|
||||||
check out the docs
|
|
||||||
</a>
|
|
||||||
!
|
|
||||||
</p>
|
|
||||||
<h3>Preview Sounds</h3>
|
|
||||||
<pre className="bg-background" key={'sample-preview'}>
|
|
||||||
n("0 1 2 3 4 5").s("sample-name")
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
Paste the line above into the main editor to hear the uploaded folder. Remember to use the name of your
|
|
||||||
sample as it appears under the "user" tab.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
{!soundEntries.length && soundsFilter !== 'importSounds'
|
|
||||||
? 'No custom sounds loaded in this pattern (yet).'
|
|
||||||
: ''}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -54,23 +54,25 @@ export function registerSamplesFromDB(config = userSamplesDBConfig, onComplete =
|
|||||||
splitRelativePath[splitRelativePath.length - 2] ?? soundFile.id.split(/\W+/)[0] ?? 'user';
|
splitRelativePath[splitRelativePath.length - 2] ?? soundFile.id.split(/\W+/)[0] ?? 'user';
|
||||||
const blob = soundFile.blob;
|
const blob = soundFile.blob;
|
||||||
|
|
||||||
|
// Files used to be uploaded as base64 strings, After Jan 1 2025 this check can be safely deleted
|
||||||
|
if (typeof blob === 'string') {
|
||||||
|
const soundPaths = sounds.get(parentDirectory) ?? new Set();
|
||||||
|
soundPaths.add(blob);
|
||||||
|
sounds.set(parentDirectory, soundPaths);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return blobToDataUrl(blob).then((soundPath) => {
|
return blobToDataUrl(blob).then((soundPath) => {
|
||||||
const titlePathMap = sounds.get(parentDirectory) ?? new Map();
|
const soundPaths = sounds.get(parentDirectory) ?? new Set();
|
||||||
|
soundPaths.add(soundPath);
|
||||||
titlePathMap.set(title, soundPath);
|
sounds.set(parentDirectory, soundPaths);
|
||||||
|
|
||||||
sounds.set(parentDirectory, titlePathMap);
|
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
sounds.forEach((titlePathMap, key) => {
|
sounds.forEach((soundPaths, key) => {
|
||||||
const value = Array.from(titlePathMap.keys())
|
const value = Array.from(soundPaths);
|
||||||
.sort((a, b) => {
|
|
||||||
return a.localeCompare(b);
|
|
||||||
})
|
|
||||||
.map((title) => titlePathMap.get(title));
|
|
||||||
|
|
||||||
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, value), {
|
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, value), {
|
||||||
type: 'sample',
|
type: 'sample',
|
||||||
|
|||||||
Reference in New Issue
Block a user