mirror of
https://codeberg.org/uzu/strudel
synced 2026-09-13 09:25:11 -04:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1dd895d94 | |||
| f8124fca80 | |||
| 95fee04bea | |||
| f60894f2ce |
@@ -4,6 +4,7 @@
|
||||
"private": true,
|
||||
"description": "Port of tidalcycles to javascript",
|
||||
"scripts": {
|
||||
"strudeljson": "node ./website/src/repl/create_strudel_json.mjs",
|
||||
"setup": "pnpm i",
|
||||
"pretest": "npm run jsdoc-json",
|
||||
"prebuild": "npm run jsdoc-json",
|
||||
|
||||
@@ -985,31 +985,15 @@ export const { delayfeedback, delayfb, dfb } = registerControl('delayfeedback',
|
||||
*
|
||||
*/
|
||||
export const { delaytime, delayt, dt } = registerControl('delaytime', 'delayt', 'dt');
|
||||
|
||||
/**
|
||||
* Sets the time of the delay effect in cycles.
|
||||
*
|
||||
* @name delaysync
|
||||
* @param {number | Pattern} cycles delay length in cycles
|
||||
* @synonyms delayt, dt
|
||||
* @example
|
||||
* s("bd bd").delay(.25).delaysync("<1 2 3 5>".div(8))
|
||||
*
|
||||
*/
|
||||
export const { delaysync } = registerControl('delaysync');
|
||||
|
||||
/**
|
||||
/* // TODO: test
|
||||
* Specifies whether delaytime is calculated relative to cps.
|
||||
*
|
||||
* @name lock
|
||||
* @param {number | Pattern} enable When set to 1, delaytime is a direct multiple of a cycle.
|
||||
* @superdirtOnly
|
||||
* @example
|
||||
* s("sd").delay().lock(1).osc()
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
export const { lock } = registerControl('lock');
|
||||
/**
|
||||
* Set detune for stacked voices of supported oscillators
|
||||
|
||||
@@ -46,11 +46,10 @@ export class Pattern {
|
||||
* @param {function} query - The function that maps a `State` to an array of `Hap`.
|
||||
* @noAutocomplete
|
||||
*/
|
||||
constructor(query, steps = undefined, alignment = undefined) {
|
||||
constructor(query, steps = undefined) {
|
||||
this.query = query;
|
||||
this._Pattern = true; // this property is used to detectinstance of another Pattern
|
||||
this._steps = steps; // in terms of number of steps per cycle
|
||||
this._alignment = alignment;
|
||||
}
|
||||
|
||||
get _steps() {
|
||||
@@ -77,11 +76,6 @@ export class Pattern {
|
||||
return this._steps !== undefined;
|
||||
}
|
||||
|
||||
setAlignment(alignment) {
|
||||
this._alignment = alignment;
|
||||
return this;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Haskell-style functor, applicative and monadic operations
|
||||
|
||||
@@ -875,31 +869,6 @@ export class Pattern {
|
||||
console.log(drawLine(this));
|
||||
return this;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// methods relating to breaking patterns into subcycles
|
||||
|
||||
// Breaks a pattern into a pattern of patterns, according to the structure of the given binary pattern.
|
||||
unjoin(pieces, func = id) {
|
||||
return pieces.withHap((hap) =>
|
||||
hap.withValue((v) => (v ? func(this.ribbon(hap.whole.begin, hap.whole.duration)) : this)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks a pattern into pieces according to the structure of a given pattern.
|
||||
* True values in the given pattern cause the corresponding subcycle of the
|
||||
* source pattern to be looped, and for an (optional) given function to be
|
||||
* applied. False values result in the corresponding part of the source pattern
|
||||
* to be played unchanged.
|
||||
* @name into
|
||||
* @memberof Pattern
|
||||
* @example
|
||||
* sound("bd sd ht lt").into("1 0", hurry(2))
|
||||
*/
|
||||
into(pieces, func) {
|
||||
return this.unjoin(pieces, func).innerJoin();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@@ -1616,13 +1585,8 @@ export function register(name, func, patternify = true, preserveSteps = false, j
|
||||
let mapFn = (...args) => {
|
||||
return func(...args, pat);
|
||||
};
|
||||
// mapFn = curry(mapFn, null, arity - 1);
|
||||
// result = join(right.reduce((acc, p) => acc.appLeft(p), left.fmap(mapFn)));
|
||||
// patternify2 f pata patb patc = pata >>= \a -> patb >>= \b -> f a b patc
|
||||
function bindArgs(argv, pat, ...pats) {
|
||||
return pat.innerBind((x) => (pats.length ? bindArgs([...argv, x], ...pats) : mapFn(...argv, x)));
|
||||
}
|
||||
result = bindArgs([], ...firstArgs);
|
||||
mapFn = curry(mapFn, null, arity - 1);
|
||||
result = join(right.reduce((acc, p) => acc.appLeft(p), left.fmap(mapFn)));
|
||||
}
|
||||
}
|
||||
if (preserveSteps) {
|
||||
@@ -2530,37 +2494,6 @@ export const { fastchunk, fastChunk } = register(
|
||||
true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Like `chunk`, but the function is applied to a looped subcycle of the source pattern.
|
||||
* @name chunkInto
|
||||
* @synonym chunkinto
|
||||
* @memberof Pattern
|
||||
* @example
|
||||
* sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2))
|
||||
* .bank("tr909")
|
||||
*/
|
||||
export const { chunkinto, chunkInto } = register(['chunkinto', 'chunkInto'], function (n, func, pat) {
|
||||
return pat.into(fastcat(true, ...Array(n - 1).fill(false))._iterback(n), func);
|
||||
});
|
||||
|
||||
/**
|
||||
* Like `chunkInto`, but moves backwards through the chunks.
|
||||
* @name chunkBackInto
|
||||
* @synonym chunkbackinto
|
||||
* @memberof Pattern
|
||||
* @example
|
||||
* sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2))
|
||||
* .bank("tr909")
|
||||
*/
|
||||
export const { chunkbackinto, chunkBackInto } = register(['chunkbackinto', 'chunkBackInto'], function (n, func, pat) {
|
||||
return pat.into(
|
||||
fastcat(true, ...Array(n - 1).fill(false))
|
||||
._iter(n)
|
||||
._early(1),
|
||||
func,
|
||||
);
|
||||
});
|
||||
|
||||
// TODO - redefine elsewhere in terms of mask
|
||||
export const bypass = register(
|
||||
'bypass',
|
||||
|
||||
@@ -1271,39 +1271,4 @@ describe('Pattern', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('unjoin', () => {
|
||||
it('destructures a pattern into subcycles', () => {
|
||||
sameFirst(
|
||||
fastcat('a', 'b', 'c', 'd')
|
||||
.unjoin(fastcat(true, fastcat(true, true)))
|
||||
.fmap(fast(2))
|
||||
.join(),
|
||||
fastcat('a', 'b', 'a', 'b', 'c', 'c', 'd', 'd'),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('into', () => {
|
||||
it('applies a function to subcycles of a pattern', () => {
|
||||
sameFirst(
|
||||
fastcat('a', 'b', 'c', 'd').into(fastcat(fastcat('true', 'true'), 'true'), fast(2)),
|
||||
fastcat('a', 'a', 'b', 'b', 'c', 'd', 'c', 'd'),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('chunkinto', () => {
|
||||
it('chunks into subcycles', () => {
|
||||
sameFirst(
|
||||
fastcat('a', 'b', 'c').chunkInto(3, fast(2)).fast(3),
|
||||
fastcat(fastcat('a', 'a'), 'b', 'c', 'a', fastcat('b', 'b'), 'c', 'a', 'b', fastcat('c', 'c')),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('chunkbackinto', () => {
|
||||
it('chunks into subcycles backwards', () => {
|
||||
sameFirst(
|
||||
fastcat('a', 'b', 'c').chunkBackInto(3, fast(2)).fast(3),
|
||||
fastcat('a', 'b', fastcat('c', 'c'), 'a', fastcat('b', 'b'), 'c', fastcat('a', 'a'), 'b', 'c'),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
||||
import './feedbackdelay.mjs';
|
||||
import './reverb.mjs';
|
||||
import './vowel.mjs';
|
||||
import { clamp, nanFallback, _mod, cycleToSeconds } from './util.mjs';
|
||||
import { clamp, nanFallback, _mod } from './util.mjs';
|
||||
import workletsUrl from './worklets.mjs?audioworklet';
|
||||
import { createFilter, gainNode, getCompressor, getWorklet } from './helpers.mjs';
|
||||
import { map } from 'nanostores';
|
||||
@@ -143,7 +143,7 @@ const defaultDefaultValues = {
|
||||
delay: 0,
|
||||
byteBeatExpression: '0',
|
||||
delayfeedback: 0.5,
|
||||
delaysync: 3 / 16,
|
||||
delaytime: 0.25,
|
||||
orbit: 1,
|
||||
i: 1,
|
||||
velocity: 1,
|
||||
@@ -450,7 +450,7 @@ function mapChannelNumbers(channels) {
|
||||
return (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1);
|
||||
}
|
||||
|
||||
export const superdough = async (value, t, hapDuration, cps = 0.5) => {
|
||||
export const superdough = async (value, t, hapDuration, cps) => {
|
||||
const ac = getAudioContext();
|
||||
t = typeof t === 'string' && t.startsWith('=') ? Number(t.slice(1)) : ac.currentTime + t;
|
||||
let { stretch } = value;
|
||||
@@ -528,8 +528,7 @@ export const superdough = async (value, t, hapDuration, cps = 0.5) => {
|
||||
vowel,
|
||||
delay = getDefaultValue('delay'),
|
||||
delayfeedback = getDefaultValue('delayfeedback'),
|
||||
delaysync = getDefaultValue('delaysync'),
|
||||
delaytime,
|
||||
delaytime = getDefaultValue('delaytime'),
|
||||
orbit = getDefaultValue('orbit'),
|
||||
room,
|
||||
roomfade,
|
||||
@@ -548,8 +547,6 @@ export const superdough = async (value, t, hapDuration, cps = 0.5) => {
|
||||
compressorRelease,
|
||||
} = value;
|
||||
|
||||
delaytime = delaytime ?? cycleToSeconds(delaysync, cps);
|
||||
|
||||
const orbitChannels = mapChannelNumbers(
|
||||
multiChannelOrbits && orbit > 0 ? [orbit * 2 - 1, orbit * 2] : getDefaultValue('channels'),
|
||||
);
|
||||
@@ -728,8 +725,8 @@ export const superdough = async (value, t, hapDuration, cps = 0.5) => {
|
||||
// delay
|
||||
let delaySend;
|
||||
if (delay > 0 && delaytime > 0 && delayfeedback > 0) {
|
||||
const delayNode = getDelay(orbit, delaytime, delayfeedback, t, orbitChannels);
|
||||
delaySend = effectSend(post, delayNode, delay);
|
||||
const delyNode = getDelay(orbit, delaytime, delayfeedback, t, orbitChannels);
|
||||
delaySend = effectSend(post, delyNode, delay);
|
||||
audioNodes.push(delaySend);
|
||||
}
|
||||
// reverb
|
||||
|
||||
@@ -68,7 +68,3 @@ export const _mod = (n, m) => ((n % m) + m) % m;
|
||||
export const getSoundIndex = (n, numSounds) => {
|
||||
return _mod(Math.round(nanFallback(n, 0)), numSounds);
|
||||
};
|
||||
|
||||
export function cycleToSeconds(cycle, cps) {
|
||||
return cycle / cps;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@ const hap2value = (hap) => {
|
||||
};
|
||||
|
||||
export const webaudioOutputTrigger = (t, hap, ct, cps) => superdough(hap2value(hap), t - ct, hap.duration / cps, cps);
|
||||
// uses more precise, absolute t if available, see https://github.com/tidalcycles/strudel/pull/1004
|
||||
export const webaudioOutput = (hap, deadline, hapDuration, cps, t) => {
|
||||
return superdough(hap2value(hap), t ? `=${t}` : deadline, hapDuration, cps);
|
||||
};
|
||||
// uses more precise, absolute t if available, see https://codeberg.org/uzu/strudel/pulls/1004
|
||||
export const webaudioOutput = (hap, deadline, hapDuration, cps, t) =>
|
||||
superdough(hap2value(hap), t ? `=${t}` : deadline, hapDuration);
|
||||
|
||||
Pattern.prototype.webaudio = function () {
|
||||
return this.onTrigger(webaudioOutputTrigger);
|
||||
|
||||
@@ -1889,86 +1889,6 @@ exports[`runs examples > example "chunkBack" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "chunkBackInto" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/16 | s:bd speed:2 bank:tr909 ]",
|
||||
"[ 1/16 → 1/8 | s:sd speed:2 bank:tr909 ]",
|
||||
"[ 1/8 → 3/16 | s:bd speed:2 bank:tr909 ]",
|
||||
"[ 3/16 → 1/4 | s:sd speed:2 bank:tr909 ]",
|
||||
"[ 1/4 → 3/8 | s:ht bank:tr909 ]",
|
||||
"[ 3/8 → 1/2 | s:lt bank:tr909 ]",
|
||||
"[ 1/2 → 5/8 | s:bd bank:tr909 ]",
|
||||
"[ 3/4 → 7/8 | s:cp bank:tr909 ]",
|
||||
"[ 7/8 → 1/1 | s:lt bank:tr909 ]",
|
||||
"[ 1/1 → 9/8 | s:bd bank:tr909 ]",
|
||||
"[ 9/8 → 5/4 | s:sd bank:tr909 ]",
|
||||
"[ 5/4 → 21/16 | s:ht speed:2 bank:tr909 ]",
|
||||
"[ 21/16 → 11/8 | s:lt speed:2 bank:tr909 ]",
|
||||
"[ 11/8 → 23/16 | s:ht speed:2 bank:tr909 ]",
|
||||
"[ 23/16 → 3/2 | s:lt speed:2 bank:tr909 ]",
|
||||
"[ 3/2 → 13/8 | s:bd bank:tr909 ]",
|
||||
"[ 7/4 → 15/8 | s:cp bank:tr909 ]",
|
||||
"[ 15/8 → 2/1 | s:lt bank:tr909 ]",
|
||||
"[ 2/1 → 17/8 | s:bd bank:tr909 ]",
|
||||
"[ 17/8 → 9/4 | s:sd bank:tr909 ]",
|
||||
"[ 9/4 → 19/8 | s:ht bank:tr909 ]",
|
||||
"[ 19/8 → 5/2 | s:lt bank:tr909 ]",
|
||||
"[ 5/2 → 41/16 | s:bd speed:2 bank:tr909 ]",
|
||||
"[ 21/8 → 43/16 | s:bd speed:2 bank:tr909 ]",
|
||||
"[ 11/4 → 23/8 | s:cp bank:tr909 ]",
|
||||
"[ 23/8 → 3/1 | s:lt bank:tr909 ]",
|
||||
"[ 3/1 → 25/8 | s:bd bank:tr909 ]",
|
||||
"[ 25/8 → 13/4 | s:sd bank:tr909 ]",
|
||||
"[ 13/4 → 27/8 | s:ht bank:tr909 ]",
|
||||
"[ 27/8 → 7/2 | s:lt bank:tr909 ]",
|
||||
"[ 7/2 → 29/8 | s:bd bank:tr909 ]",
|
||||
"[ 15/4 → 61/16 | s:cp speed:2 bank:tr909 ]",
|
||||
"[ 61/16 → 31/8 | s:lt speed:2 bank:tr909 ]",
|
||||
"[ 31/8 → 63/16 | s:cp speed:2 bank:tr909 ]",
|
||||
"[ 63/16 → 4/1 | s:lt speed:2 bank:tr909 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "chunkInto" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/16 | s:bd speed:2 bank:tr909 ]",
|
||||
"[ 1/16 → 1/8 | s:sd speed:2 bank:tr909 ]",
|
||||
"[ 1/8 → 3/16 | s:bd speed:2 bank:tr909 ]",
|
||||
"[ 3/16 → 1/4 | s:sd speed:2 bank:tr909 ]",
|
||||
"[ 1/4 → 3/8 | s:ht bank:tr909 ]",
|
||||
"[ 3/8 → 1/2 | s:lt bank:tr909 ]",
|
||||
"[ 1/2 → 5/8 | s:bd bank:tr909 ]",
|
||||
"[ 3/4 → 7/8 | s:cp bank:tr909 ]",
|
||||
"[ 7/8 → 1/1 | s:lt bank:tr909 ]",
|
||||
"[ 1/1 → 9/8 | s:bd bank:tr909 ]",
|
||||
"[ 9/8 → 5/4 | s:sd bank:tr909 ]",
|
||||
"[ 5/4 → 21/16 | s:ht speed:2 bank:tr909 ]",
|
||||
"[ 21/16 → 11/8 | s:lt speed:2 bank:tr909 ]",
|
||||
"[ 11/8 → 23/16 | s:ht speed:2 bank:tr909 ]",
|
||||
"[ 23/16 → 3/2 | s:lt speed:2 bank:tr909 ]",
|
||||
"[ 3/2 → 13/8 | s:bd bank:tr909 ]",
|
||||
"[ 7/4 → 15/8 | s:cp bank:tr909 ]",
|
||||
"[ 15/8 → 2/1 | s:lt bank:tr909 ]",
|
||||
"[ 2/1 → 17/8 | s:bd bank:tr909 ]",
|
||||
"[ 17/8 → 9/4 | s:sd bank:tr909 ]",
|
||||
"[ 9/4 → 19/8 | s:ht bank:tr909 ]",
|
||||
"[ 19/8 → 5/2 | s:lt bank:tr909 ]",
|
||||
"[ 5/2 → 41/16 | s:bd speed:2 bank:tr909 ]",
|
||||
"[ 21/8 → 43/16 | s:bd speed:2 bank:tr909 ]",
|
||||
"[ 11/4 → 23/8 | s:cp bank:tr909 ]",
|
||||
"[ 23/8 → 3/1 | s:lt bank:tr909 ]",
|
||||
"[ 3/1 → 25/8 | s:bd bank:tr909 ]",
|
||||
"[ 25/8 → 13/4 | s:sd bank:tr909 ]",
|
||||
"[ 13/4 → 27/8 | s:ht bank:tr909 ]",
|
||||
"[ 27/8 → 7/2 | s:lt bank:tr909 ]",
|
||||
"[ 7/2 → 29/8 | s:bd bank:tr909 ]",
|
||||
"[ 15/4 → 61/16 | s:cp speed:2 bank:tr909 ]",
|
||||
"[ 61/16 → 31/8 | s:lt speed:2 bank:tr909 ]",
|
||||
"[ 31/8 → 63/16 | s:cp speed:2 bank:tr909 ]",
|
||||
"[ 63/16 → 4/1 | s:lt speed:2 bank:tr909 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "clip" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:c s:piano clip:0.5 ]",
|
||||
@@ -2585,19 +2505,6 @@ exports[`runs examples > example "delayfeedback" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "delaysync" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/2 | s:bd delay:0.25 delaysync:0.125 ]",
|
||||
"[ 1/2 → 1/1 | s:bd delay:0.25 delaysync:0.125 ]",
|
||||
"[ 1/1 → 3/2 | s:bd delay:0.25 delaysync:0.25 ]",
|
||||
"[ 3/2 → 2/1 | s:bd delay:0.25 delaysync:0.25 ]",
|
||||
"[ 2/1 → 5/2 | s:bd delay:0.25 delaysync:0.375 ]",
|
||||
"[ 5/2 → 3/1 | s:bd delay:0.25 delaysync:0.375 ]",
|
||||
"[ 3/1 → 7/2 | s:bd delay:0.25 delaysync:0.625 ]",
|
||||
"[ 7/2 → 4/1 | s:bd delay:0.25 delaysync:0.625 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "delaytime" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/2 | s:bd delay:0.25 delaytime:0.125 ]",
|
||||
@@ -4484,35 +4391,6 @@ exports[`runs examples > example "inside" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "into" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | s:bd speed:2 ]",
|
||||
"[ 1/8 → 1/4 | s:sd speed:2 ]",
|
||||
"[ 1/4 → 3/8 | s:bd speed:2 ]",
|
||||
"[ 3/8 → 1/2 | s:sd speed:2 ]",
|
||||
"[ 1/2 → 3/4 | s:ht ]",
|
||||
"[ 3/4 → 1/1 | s:lt ]",
|
||||
"[ 1/1 → 9/8 | s:bd speed:2 ]",
|
||||
"[ 9/8 → 5/4 | s:sd speed:2 ]",
|
||||
"[ 5/4 → 11/8 | s:bd speed:2 ]",
|
||||
"[ 11/8 → 3/2 | s:sd speed:2 ]",
|
||||
"[ 3/2 → 7/4 | s:ht ]",
|
||||
"[ 7/4 → 2/1 | s:lt ]",
|
||||
"[ 2/1 → 17/8 | s:bd speed:2 ]",
|
||||
"[ 17/8 → 9/4 | s:sd speed:2 ]",
|
||||
"[ 9/4 → 19/8 | s:bd speed:2 ]",
|
||||
"[ 19/8 → 5/2 | s:sd speed:2 ]",
|
||||
"[ 5/2 → 11/4 | s:ht ]",
|
||||
"[ 11/4 → 3/1 | s:lt ]",
|
||||
"[ 3/1 → 25/8 | s:bd speed:2 ]",
|
||||
"[ 25/8 → 13/4 | s:sd speed:2 ]",
|
||||
"[ 13/4 → 27/8 | s:bd speed:2 ]",
|
||||
"[ 27/8 → 7/2 | s:sd speed:2 ]",
|
||||
"[ 7/2 → 15/4 | s:ht ]",
|
||||
"[ 15/4 → 4/1 | s:lt ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "invert" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | s:bd ]",
|
||||
@@ -5138,15 +5016,6 @@ exports[`runs examples > example "linger" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "lock" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/1 | delay:{s:sd} lock:1 ]",
|
||||
"[ 1/1 → 2/1 | delay:{s:sd} lock:1 ]",
|
||||
"[ 2/1 → 3/1 | delay:{s:sd} lock:1 ]",
|
||||
"[ 3/1 → 4/1 | delay:{s:sd} lock:1 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "loop" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/1 | s:casio loop:1 ]",
|
||||
|
||||
@@ -21,11 +21,7 @@ export function Reference() {
|
||||
return true;
|
||||
}
|
||||
|
||||
const lowCaseSearch = search.toLowerCase();
|
||||
return (
|
||||
entry.name.toLowerCase().includes(lowCaseSearch) ||
|
||||
(entry.synonyms?.some((s) => s.includes(lowCaseSearch)) ?? false)
|
||||
);
|
||||
return entry.name.includes(search) || (entry.synonyms?.some((s) => s.includes(search)) ?? false);
|
||||
});
|
||||
}, [search]);
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { createInterface } from 'node:readline';
|
||||
import * as fs from 'node:fs';
|
||||
|
||||
const validFileTypes = new Set(['.wav', '.mp3', '.aac', '.m4a']);
|
||||
/** For automatically creating the strudel JSON that for samples hosted in a remote repo */
|
||||
async function writeStrudelJson(subpath, hosturl) {
|
||||
const children = await fs.promises.readdir(subpath, { recursive: true });
|
||||
const name = subpath.split('/').slice(-1)[0];
|
||||
const tree = { name, children };
|
||||
let samples = {
|
||||
_base: hosturl,
|
||||
};
|
||||
|
||||
const files = tree.children
|
||||
.filter((path) => {
|
||||
const extension = path.match(/\.[0-9a-z]+$/i)?.[0];
|
||||
return validFileTypes.has(extension);
|
||||
})
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
|
||||
files.forEach((path) => {
|
||||
const groupName = path.match(/([^/]+)\/[^/]+$/)[1];
|
||||
samples[groupName] = samples[groupName] ?? [];
|
||||
samples[groupName].push(path);
|
||||
});
|
||||
const json = JSON.stringify(samples, null, 2);
|
||||
const filepath = subpath + '/strudel.json';
|
||||
await fs.promises.writeFile(filepath, json);
|
||||
console.log(`wrote strudel.json with ${files.length} samples to ${subpath}`);
|
||||
}
|
||||
|
||||
const rl = createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
rl.question(`enter sample folder path: `, async (path) => {
|
||||
rl.question(`enter hosted URL: `, async (hosturl) => {
|
||||
const githubregex = /github\.com\/([^/]+)\/([^/]+)/;
|
||||
const githubparams = hosturl.match(githubregex);
|
||||
if (githubparams) {
|
||||
const username = githubparams[1];
|
||||
const repo = githubparams[2];
|
||||
|
||||
hosturl = `https://raw.githubusercontent.com/${username}/${repo}/main/`;
|
||||
console.log('reformatting github URL to: ', hosturl);
|
||||
}
|
||||
|
||||
await writeStrudelJson(path, hosturl);
|
||||
rl.close();
|
||||
});
|
||||
});
|
||||
@@ -33,7 +33,7 @@ async function loadStrudelJson(subpath) {
|
||||
});
|
||||
}
|
||||
|
||||
async function writeStrudelJson(subpath) {
|
||||
export async function writeStrudelJson(subpath) {
|
||||
const children = await readDir(subpath, { dir, recursive: true });
|
||||
const name = subpath.split('/').slice(-1)[0];
|
||||
const tree = { name, children };
|
||||
@@ -41,7 +41,7 @@ async function writeStrudelJson(subpath) {
|
||||
let samples = {};
|
||||
let count = 0;
|
||||
walkFileTree(tree, (entry, parent) => {
|
||||
if (['wav', 'mp3'].includes(entry.name.split('.').slice(-1)[0])) {
|
||||
if (['wav', 'mp3', 'aac', 'm4a'].includes(entry.name.split('.').slice(-1)[0])) {
|
||||
samples[parent.name] = samples[parent.name] || [];
|
||||
count += 1;
|
||||
samples[parent.name].push(entry.subpath.slice(1).concat([entry.name]).join('/'));
|
||||
|
||||
Reference in New Issue
Block a user