mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-21 10:38:37 +00:00
Merge branch 'main' of github.com:daslyfe/strudel
This commit is contained in:
commit
a91f4576f3
@ -809,15 +809,6 @@ export class Pattern {
|
|||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Multi-pattern functions
|
// Multi-pattern functions
|
||||||
|
|
||||||
/**
|
|
||||||
* Stacks the given pattern(s) to the current pattern.
|
|
||||||
* @name stack
|
|
||||||
* @memberof Pattern
|
|
||||||
* @example
|
|
||||||
* s("hh*4").stack(
|
|
||||||
* note("c4(5,8)")
|
|
||||||
* )
|
|
||||||
*/
|
|
||||||
stack(...pats) {
|
stack(...pats) {
|
||||||
return stack(this, ...pats);
|
return stack(this, ...pats);
|
||||||
}
|
}
|
||||||
@ -826,30 +817,9 @@ export class Pattern {
|
|||||||
return sequence(this, ...pats);
|
return sequence(this, ...pats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends the given pattern(s) to the current pattern.
|
|
||||||
* @name seq
|
|
||||||
* @memberof Pattern
|
|
||||||
* @synonyms sequence, fastcat
|
|
||||||
* @example
|
|
||||||
* s("hh*4").seq(
|
|
||||||
* note("c4(5,8)")
|
|
||||||
* )
|
|
||||||
*/
|
|
||||||
seq(...pats) {
|
seq(...pats) {
|
||||||
return sequence(this, ...pats);
|
return sequence(this, ...pats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends the given pattern(s) to the next cycle.
|
|
||||||
* @name cat
|
|
||||||
* @memberof Pattern
|
|
||||||
* @synonyms slowcat
|
|
||||||
* @example
|
|
||||||
* s("hh*4").cat(
|
|
||||||
* note("c4(5,8)")
|
|
||||||
* )
|
|
||||||
*/
|
|
||||||
cat(...pats) {
|
cat(...pats) {
|
||||||
return cat(this, ...pats);
|
return cat(this, ...pats);
|
||||||
}
|
}
|
||||||
@ -1280,6 +1250,12 @@ export function reify(thing) {
|
|||||||
* @example
|
* @example
|
||||||
* stack("g3", "b3", ["e4", "d4"]).note()
|
* stack("g3", "b3", ["e4", "d4"]).note()
|
||||||
* // "g3,b3,[e4,d4]".note()
|
* // "g3,b3,[e4,d4]".note()
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // As a chained function:
|
||||||
|
* s("hh*4").stack(
|
||||||
|
* note("c4(5,8)")
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
export function stack(...pats) {
|
export function stack(...pats) {
|
||||||
// Array test here is to avoid infinite recursions..
|
// Array test here is to avoid infinite recursions..
|
||||||
@ -1408,6 +1384,11 @@ export function slowcatPrime(...pats) {
|
|||||||
* cat("e5", "b4", ["d5", "c5"]).note()
|
* cat("e5", "b4", ["d5", "c5"]).note()
|
||||||
* // "<e5 b4 [d5 c5]>".note()
|
* // "<e5 b4 [d5 c5]>".note()
|
||||||
*
|
*
|
||||||
|
* @example
|
||||||
|
* // As a chained function:
|
||||||
|
* s("hh*4").cat(
|
||||||
|
* note("c4(5,8)")
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
export function cat(...pats) {
|
export function cat(...pats) {
|
||||||
return slowcat(...pats);
|
return slowcat(...pats);
|
||||||
@ -1430,6 +1411,36 @@ export function arrange(...sections) {
|
|||||||
return s_cat(...sections).slow(total);
|
return s_cat(...sections).slow(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similarly to `arrange`, allows you to arrange multiple patterns together over multiple cycles.
|
||||||
|
* Unlike `arrange`, you specify a start and stop time for each pattern rather than duration, which
|
||||||
|
* means that patterns can overlap.
|
||||||
|
* @return {Pattern}
|
||||||
|
* @example
|
||||||
|
seqPLoop([0, 2, "bd(3,8)"],
|
||||||
|
[1, 3, "cp(3,8)"]
|
||||||
|
)
|
||||||
|
.sound()
|
||||||
|
*/
|
||||||
|
export function seqPLoop(...parts) {
|
||||||
|
let total = Fraction(0);
|
||||||
|
const pats = [];
|
||||||
|
for (let part of parts) {
|
||||||
|
if (part.length == 2) {
|
||||||
|
part.unshift(total);
|
||||||
|
}
|
||||||
|
total = part[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack(
|
||||||
|
...parts.map(([start, stop, pat]) =>
|
||||||
|
pure(reify(pat)).compress(Fraction(start).div(total), Fraction(stop).div(total)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.slow(total)
|
||||||
|
.innerJoin(); // or resetJoin or restartJoin ??
|
||||||
|
}
|
||||||
|
|
||||||
export function fastcat(...pats) {
|
export function fastcat(...pats) {
|
||||||
let result = slowcat(...pats);
|
let result = slowcat(...pats);
|
||||||
if (pats.length > 1) {
|
if (pats.length > 1) {
|
||||||
@ -1448,12 +1459,18 @@ export function sequence(...pats) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Like **cat**, but the items are crammed into one cycle.
|
/** Like **cat**, but the items are crammed into one cycle.
|
||||||
* @synonyms fastcat, sequence
|
* @synonyms sequence, fastcat
|
||||||
* @example
|
* @example
|
||||||
* seq("e5", "b4", ["d5", "c5"]).note()
|
* seq("e5", "b4", ["d5", "c5"]).note()
|
||||||
* // "e5 b4 [d5 c5]".note()
|
* // "e5 b4 [d5 c5]".note()
|
||||||
*
|
*
|
||||||
|
* @example
|
||||||
|
* // As a chained function:
|
||||||
|
* s("hh*4").seq(
|
||||||
|
* note("c4(5,8)")
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function seq(...pats) {
|
export function seq(...pats) {
|
||||||
return fastcat(...pats);
|
return fastcat(...pats);
|
||||||
}
|
}
|
||||||
@ -2016,6 +2033,34 @@ export const { zoomArc, zoomarc } = register(['zoomArc', 'zoomarc'], function (a
|
|||||||
return pat.zoom(a.begin, a.end);
|
return pat.zoom(a.begin, a.end);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits a pattern into the given number of slices, and plays them according to a pattern of slice numbers.
|
||||||
|
* Similar to `slice`, but slices up patterns rather than sound samples.
|
||||||
|
* @param {number} number of slices
|
||||||
|
* @param {number} slices to play
|
||||||
|
* @example
|
||||||
|
* note("0 1 2 3 4 5 6 7".scale('c:mixolydian'))
|
||||||
|
*.bite(4, "3 2 1 0")
|
||||||
|
* @example
|
||||||
|
* sound("bd - bd bd*2, - sd:6 - sd:5 sd:1 - [- sd:2] -, hh [- cp:7]")
|
||||||
|
.bank("RolandTR909").speed(1.2)
|
||||||
|
.bite(4, "0 0 [1 2] <3 2> 0 0 [2 1] 3")
|
||||||
|
*/
|
||||||
|
export const bite = register(
|
||||||
|
'bite',
|
||||||
|
(npat, ipat, pat) => {
|
||||||
|
return ipat
|
||||||
|
.fmap((i) => (n) => {
|
||||||
|
const a = Fraction(i).div(n).mod(1);
|
||||||
|
const b = a.add(Fraction(1).div(n));
|
||||||
|
return pat.zoom(a, b);
|
||||||
|
})
|
||||||
|
.appLeft(npat)
|
||||||
|
.squeezeJoin();
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the given fraction of the pattern and repeats that part to fill the remainder of the cycle.
|
* Selects the given fraction of the pattern and repeats that part to fill the remainder of the cycle.
|
||||||
* @param {number} fraction fraction to select
|
* @param {number} fraction fraction to select
|
||||||
@ -2447,6 +2492,37 @@ Pattern.prototype.tag = function (tag) {
|
|||||||
return this.withContext((ctx) => ({ ...ctx, tags: (ctx.tags || []).concat([tag]) }));
|
return this.withContext((ctx) => ({ ...ctx, tags: (ctx.tags || []).concat([tag]) }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters haps using the given function
|
||||||
|
* @name filter
|
||||||
|
* @param {Function} test function to test Hap
|
||||||
|
* @example
|
||||||
|
* s("hh!7 oh").filter(hap => hap.value.s==='hh')
|
||||||
|
*/
|
||||||
|
export const filter = register('filter', (test, pat) => pat.withHaps((haps) => haps.filter(test)));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters haps by their begin time
|
||||||
|
* @name filterWhen
|
||||||
|
* @noAutocomplete
|
||||||
|
* @param {Function} test function to test Hap.whole.begin
|
||||||
|
*/
|
||||||
|
export const filterWhen = register('filterWhen', (test, pat) => pat.filter((h) => test(h.whole.begin)));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use within to apply a function to only a part of a pattern.
|
||||||
|
* @name within
|
||||||
|
* @param {number} start start within cycle (0 - 1)
|
||||||
|
* @param {number} end end within cycle (0 - 1). Must be > start
|
||||||
|
* @param {Function} func function to be applied to the sub-pattern
|
||||||
|
*/
|
||||||
|
export const within = register('within', (a, b, fn, pat) =>
|
||||||
|
stack(
|
||||||
|
fn(pat.filterWhen((t) => t.cyclePos() >= a && t.cyclePos() <= b)),
|
||||||
|
pat.filterWhen((t) => t.cyclePos() < a || t.cyclePos() > b),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Tactus-related functions, i.e. ones that do stepwise
|
// Tactus-related functions, i.e. ones that do stepwise
|
||||||
// transformations
|
// transformations
|
||||||
|
|||||||
@ -169,13 +169,18 @@ const refs = {};
|
|||||||
export async function midin(input) {
|
export async function midin(input) {
|
||||||
if (isPattern(input)) {
|
if (isPattern(input)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`.midi does not accept Pattern input. Make sure to pass device name with single quotes. Example: .midi('${
|
`midin: does not accept Pattern as input. Make sure to pass device name with single quotes. Example: midin('${
|
||||||
WebMidi.outputs?.[0]?.name || 'IAC Driver Bus 1'
|
WebMidi.outputs?.[0]?.name || 'IAC Driver Bus 1'
|
||||||
}')`,
|
}')`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const initial = await enableWebMidi(); // only returns on first init
|
const initial = await enableWebMidi(); // only returns on first init
|
||||||
const device = getDevice(input, WebMidi.inputs);
|
const device = getDevice(input, WebMidi.inputs);
|
||||||
|
if (!device) {
|
||||||
|
throw new Error(
|
||||||
|
`midiin: device "${input}" not found.. connected devices: ${getMidiDeviceNamesString(WebMidi.inputs)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
if (initial) {
|
if (initial) {
|
||||||
const otherInputs = WebMidi.inputs.filter((o) => o.name !== device.name);
|
const otherInputs = WebMidi.inputs.filter((o) => o.name !== device.name);
|
||||||
logger(
|
logger(
|
||||||
|
|||||||
@ -68,7 +68,7 @@ Pattern.prototype.serial = function (br = 115200, sendcrc = false, singlecharids
|
|||||||
if (!(name in writeMessagers)) {
|
if (!(name in writeMessagers)) {
|
||||||
getWriter(name, br);
|
getWriter(name, br);
|
||||||
}
|
}
|
||||||
const onTrigger = (time, hap, currentTime) => {
|
const onTrigger = (t_deprecate, hap, currentTime, cps, targetTime) => {
|
||||||
var message = '';
|
var message = '';
|
||||||
var chk = 0;
|
var chk = 0;
|
||||||
if (typeof hap.value === 'object') {
|
if (typeof hap.value === 'object') {
|
||||||
@ -105,7 +105,7 @@ Pattern.prototype.serial = function (br = 115200, sendcrc = false, singlecharids
|
|||||||
} else {
|
} else {
|
||||||
message = hap.value;
|
message = hap.value;
|
||||||
}
|
}
|
||||||
const offset = (time - currentTime + latency) * 1000;
|
const offset = (targetTime - currentTime + latency) * 1000;
|
||||||
|
|
||||||
window.setTimeout(function () {
|
window.setTimeout(function () {
|
||||||
writeMessagers[name](message, chk);
|
writeMessagers[name](message, chk);
|
||||||
|
|||||||
@ -22,16 +22,13 @@ function humanFileSize(bytes, si) {
|
|||||||
return bytes.toFixed(1) + ' ' + units[u];
|
return bytes.toFixed(1) + ' ' + units[u];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resolveUrl) => {
|
// deduces relevant info for sample loading from hap.value and sample definition
|
||||||
let transpose = 0;
|
// it encapsulates the core sampler logic into a pure and synchronous function
|
||||||
if (freq !== undefined && note !== undefined) {
|
// hapValue: Hap.value, bank: sample bank definition for sound "s" (values in strudel.json format)
|
||||||
logger('[sampler] hap has note and freq. ignoring note', 'warning');
|
export function getSampleInfo(hapValue, bank) {
|
||||||
}
|
const { s, n = 0, speed = 1.0 } = hapValue;
|
||||||
let midi = valueToMidi({ freq, note }, 36);
|
let midi = valueToMidi(hapValue, 36);
|
||||||
transpose = midi - 36; // C3 is middle C
|
let transpose = midi - 36; // C3 is middle C;
|
||||||
|
|
||||||
const ac = getAudioContext();
|
|
||||||
|
|
||||||
let sampleUrl;
|
let sampleUrl;
|
||||||
let index = 0;
|
let index = 0;
|
||||||
if (Array.isArray(bank)) {
|
if (Array.isArray(bank)) {
|
||||||
@ -50,19 +47,54 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol
|
|||||||
index = getSoundIndex(n, bank[closest].length);
|
index = getSoundIndex(n, bank[closest].length);
|
||||||
sampleUrl = bank[closest][index];
|
sampleUrl = bank[closest][index];
|
||||||
}
|
}
|
||||||
|
const label = `${s}:${index}`;
|
||||||
|
let playbackRate = Math.abs(speed) * Math.pow(2, transpose / 12);
|
||||||
|
return { transpose, sampleUrl, index, midi, label, playbackRate };
|
||||||
|
}
|
||||||
|
|
||||||
|
// takes hapValue and returns buffer + playbackRate.
|
||||||
|
export const getSampleBuffer = async (hapValue, bank, resolveUrl) => {
|
||||||
|
let { sampleUrl, label, playbackRate } = getSampleInfo(hapValue, bank);
|
||||||
if (resolveUrl) {
|
if (resolveUrl) {
|
||||||
sampleUrl = await resolveUrl(sampleUrl);
|
sampleUrl = await resolveUrl(sampleUrl);
|
||||||
}
|
}
|
||||||
let buffer = await loadBuffer(sampleUrl, ac, s, index);
|
const ac = getAudioContext();
|
||||||
if (speed < 0) {
|
const buffer = await loadBuffer(sampleUrl, ac, label);
|
||||||
|
|
||||||
|
if (hapValue.unit === 'c') {
|
||||||
|
playbackRate = playbackRate * buffer.duration;
|
||||||
|
}
|
||||||
|
return { buffer, playbackRate };
|
||||||
|
};
|
||||||
|
|
||||||
|
// creates playback ready AudioBufferSourceNode from hapValue
|
||||||
|
export const getSampleBufferSource = async (hapValue, bank, resolveUrl) => {
|
||||||
|
let { buffer, playbackRate } = await getSampleBuffer(hapValue, bank, resolveUrl);
|
||||||
|
if (hapValue.speed < 0) {
|
||||||
// should this be cached?
|
// should this be cached?
|
||||||
buffer = reverseBuffer(buffer);
|
buffer = reverseBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
const ac = getAudioContext();
|
||||||
const bufferSource = ac.createBufferSource();
|
const bufferSource = ac.createBufferSource();
|
||||||
bufferSource.buffer = buffer;
|
bufferSource.buffer = buffer;
|
||||||
const playbackRate = 1.0 * Math.pow(2, transpose / 12);
|
|
||||||
bufferSource.playbackRate.value = playbackRate;
|
bufferSource.playbackRate.value = playbackRate;
|
||||||
return bufferSource;
|
|
||||||
|
const { s, loopBegin = 0, loopEnd = 1, begin = 0, end = 1 } = hapValue;
|
||||||
|
|
||||||
|
// "The computation of the offset into the sound is performed using the sound buffer's natural sample rate,
|
||||||
|
// rather than the current playback rate, so even if the sound is playing at twice its normal speed,
|
||||||
|
// the midway point through a 10-second audio buffer is still 5."
|
||||||
|
const offset = begin * bufferSource.buffer.duration;
|
||||||
|
|
||||||
|
const loop = s.startsWith('wt_') ? 1 : hapValue.loop;
|
||||||
|
if (loop) {
|
||||||
|
bufferSource.loop = true;
|
||||||
|
bufferSource.loopStart = loopBegin * bufferSource.buffer.duration - offset;
|
||||||
|
bufferSource.loopEnd = loopEnd * bufferSource.buffer.duration - offset;
|
||||||
|
}
|
||||||
|
const bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value;
|
||||||
|
const sliceDuration = (end - begin) * bufferDuration;
|
||||||
|
return { bufferSource, offset, bufferDuration, sliceDuration };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loadBuffer = (url, ac, s, n = 0) => {
|
export const loadBuffer = (url, ac, s, n = 0) => {
|
||||||
@ -232,10 +264,10 @@ export const samples = async (sampleMap, baseUrl = sampleMap._base || '', option
|
|||||||
const { prebake, tag } = options;
|
const { prebake, tag } = options;
|
||||||
processSampleMap(
|
processSampleMap(
|
||||||
sampleMap,
|
sampleMap,
|
||||||
(key, value) =>
|
(key, bank) =>
|
||||||
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, value), {
|
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, bank), {
|
||||||
type: 'sample',
|
type: 'sample',
|
||||||
samples: value,
|
samples: bank,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
prebake,
|
prebake,
|
||||||
tag,
|
tag,
|
||||||
@ -249,38 +281,26 @@ const cutGroups = [];
|
|||||||
export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||||
let {
|
let {
|
||||||
s,
|
s,
|
||||||
freq,
|
|
||||||
unit,
|
|
||||||
nudge = 0, // TODO: is this in seconds?
|
nudge = 0, // TODO: is this in seconds?
|
||||||
cut,
|
cut,
|
||||||
loop,
|
loop,
|
||||||
clip = undefined, // if set, samples will be cut off when the hap ends
|
clip = undefined, // if set, samples will be cut off when the hap ends
|
||||||
n = 0,
|
n = 0,
|
||||||
note,
|
|
||||||
speed = 1, // sample playback speed
|
speed = 1, // sample playback speed
|
||||||
loopBegin = 0,
|
|
||||||
begin = 0,
|
|
||||||
loopEnd = 1,
|
|
||||||
end = 1,
|
|
||||||
duration,
|
duration,
|
||||||
} = value;
|
} = value;
|
||||||
|
|
||||||
// load sample
|
// load sample
|
||||||
if (speed === 0) {
|
if (speed === 0) {
|
||||||
// no playback
|
// no playback
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loop = s.startsWith('wt_') ? 1 : value.loop;
|
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
|
|
||||||
// destructure adsr here, because the default should be different for synths and samples
|
// destructure adsr here, because the default should be different for synths and samples
|
||||||
|
|
||||||
let [attack, decay, sustain, release] = getADSRValues([value.attack, value.decay, value.sustain, value.release]);
|
let [attack, decay, sustain, release] = getADSRValues([value.attack, value.decay, value.sustain, value.release]);
|
||||||
//const soundfont = getSoundfontKey(s);
|
|
||||||
const time = t + nudge;
|
|
||||||
|
|
||||||
const bufferSource = await getSampleBufferSource(s, n, note, speed, freq, bank, resolveUrl);
|
const { bufferSource, sliceDuration, offset } = await getSampleBufferSource(value, bank, resolveUrl);
|
||||||
|
|
||||||
// vibrato
|
|
||||||
let vibratoOscillator = getVibratoOscillator(bufferSource.detune, value, t);
|
|
||||||
|
|
||||||
// asny stuff above took too long?
|
// asny stuff above took too long?
|
||||||
if (ac.currentTime > t) {
|
if (ac.currentTime > t) {
|
||||||
@ -292,26 +312,19 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
|||||||
logger(`[sampler] could not load "${s}:${n}"`, 'error');
|
logger(`[sampler] could not load "${s}:${n}"`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bufferSource.playbackRate.value = Math.abs(speed) * bufferSource.playbackRate.value;
|
|
||||||
if (unit === 'c') {
|
// vibrato
|
||||||
// are there other units?
|
let vibratoOscillator = getVibratoOscillator(bufferSource.detune, value, t);
|
||||||
bufferSource.playbackRate.value = bufferSource.playbackRate.value * bufferSource.buffer.duration * 1; //cps;
|
|
||||||
}
|
const time = t + nudge;
|
||||||
// "The computation of the offset into the sound is performed using the sound buffer's natural sample rate,
|
|
||||||
// rather than the current playback rate, so even if the sound is playing at twice its normal speed,
|
|
||||||
// the midway point through a 10-second audio buffer is still 5."
|
|
||||||
const offset = begin * bufferSource.buffer.duration;
|
|
||||||
if (loop) {
|
|
||||||
bufferSource.loop = true;
|
|
||||||
bufferSource.loopStart = loopBegin * bufferSource.buffer.duration - offset;
|
|
||||||
bufferSource.loopEnd = loopEnd * bufferSource.buffer.duration - offset;
|
|
||||||
}
|
|
||||||
bufferSource.start(time, offset);
|
bufferSource.start(time, offset);
|
||||||
|
|
||||||
const envGain = ac.createGain();
|
const envGain = ac.createGain();
|
||||||
const node = bufferSource.connect(envGain);
|
const node = bufferSource.connect(envGain);
|
||||||
|
|
||||||
|
// if none of these controls is set, the duration of the sound will be set to the duration of the sample slice
|
||||||
if (clip == null && loop == null && value.release == null) {
|
if (clip == null && loop == null && value.release == null) {
|
||||||
const bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value;
|
duration = sliceDuration;
|
||||||
duration = (end - begin) * bufferDuration;
|
|
||||||
}
|
}
|
||||||
let holdEnd = t + duration;
|
let holdEnd = t + duration;
|
||||||
|
|
||||||
|
|||||||
@ -421,6 +421,7 @@ export const superdough = async (value, t, hapDuration) => {
|
|||||||
};
|
};
|
||||||
if (bank && s) {
|
if (bank && s) {
|
||||||
s = `${bank}_${s}`;
|
s = `${bank}_${s}`;
|
||||||
|
value.s = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get source AudioNode
|
// get source AudioNode
|
||||||
|
|||||||
@ -967,6 +967,156 @@ exports[`runs examples > example "begin" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "bite" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/8 | note:Bb3 ]",
|
||||||
|
"[ 1/8 → 1/4 | note:C4 ]",
|
||||||
|
"[ 1/4 → 3/8 | note:G3 ]",
|
||||||
|
"[ 3/8 → 1/2 | note:A3 ]",
|
||||||
|
"[ 1/2 → 5/8 | note:E3 ]",
|
||||||
|
"[ 5/8 → 3/4 | note:F3 ]",
|
||||||
|
"[ 3/4 → 7/8 | note:C3 ]",
|
||||||
|
"[ 7/8 → 1/1 | note:D3 ]",
|
||||||
|
"[ 1/1 → 9/8 | note:Bb3 ]",
|
||||||
|
"[ 9/8 → 5/4 | note:C4 ]",
|
||||||
|
"[ 5/4 → 11/8 | note:G3 ]",
|
||||||
|
"[ 11/8 → 3/2 | note:A3 ]",
|
||||||
|
"[ 3/2 → 13/8 | note:E3 ]",
|
||||||
|
"[ 13/8 → 7/4 | note:F3 ]",
|
||||||
|
"[ 7/4 → 15/8 | note:C3 ]",
|
||||||
|
"[ 15/8 → 2/1 | note:D3 ]",
|
||||||
|
"[ 2/1 → 17/8 | note:Bb3 ]",
|
||||||
|
"[ 17/8 → 9/4 | note:C4 ]",
|
||||||
|
"[ 9/4 → 19/8 | note:G3 ]",
|
||||||
|
"[ 19/8 → 5/2 | note:A3 ]",
|
||||||
|
"[ 5/2 → 21/8 | note:E3 ]",
|
||||||
|
"[ 21/8 → 11/4 | note:F3 ]",
|
||||||
|
"[ 11/4 → 23/8 | note:C3 ]",
|
||||||
|
"[ 23/8 → 3/1 | note:D3 ]",
|
||||||
|
"[ 3/1 → 25/8 | note:Bb3 ]",
|
||||||
|
"[ 25/8 → 13/4 | note:C4 ]",
|
||||||
|
"[ 13/4 → 27/8 | note:G3 ]",
|
||||||
|
"[ 27/8 → 7/2 | note:A3 ]",
|
||||||
|
"[ 7/2 → 29/8 | note:E3 ]",
|
||||||
|
"[ 29/8 → 15/4 | note:F3 ]",
|
||||||
|
"[ 15/4 → 31/8 | note:C3 ]",
|
||||||
|
"[ 31/8 → 4/1 | note:D3 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "bite" example index 1 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 0/1 → 1/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 1/16 → 1/8 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 1/8 → 1/4 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 1/8 → 1/4 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 3/16 → 1/4 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 1/4 → 5/16 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 9/32 → 5/16 | s:sd n:5 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 5/16 → 11/32 | s:sd n:1 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 5/16 → 3/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 3/8 → 7/16 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 3/8 → 1/2 | s:cp n:7 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 13/32 → 7/16 | s:sd n:2 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 7/16 → 1/2 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 1/2 → 5/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 1/2 → 5/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 9/16 → 5/8 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 5/8 → 3/4 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 5/8 → 3/4 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 11/16 → 3/4 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 3/4 → 25/32 | s:sd n:1 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 3/4 → 13/16 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 13/16 → 7/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 27/32 → 7/8 | s:sd n:5 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 7/8 → 15/16 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 7/8 → 1/1 | s:cp n:7 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 29/32 → 15/16 | s:sd n:2 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 15/16 → 1/1 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 1/1 → 9/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 1/1 → 9/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 17/16 → 9/8 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 9/8 → 5/4 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 9/8 → 5/4 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 19/16 → 5/4 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 5/4 → 21/16 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 41/32 → 21/16 | s:sd n:5 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 21/16 → 43/32 | s:sd n:1 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 21/16 → 11/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 11/8 → 23/16 | s:sd n:1 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 11/8 → 3/2 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 3/2 → 13/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 3/2 → 13/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 25/16 → 13/8 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 13/8 → 7/4 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 13/8 → 7/4 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 27/16 → 7/4 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 7/4 → 57/32 | s:sd n:1 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 7/4 → 29/16 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 29/16 → 15/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 59/32 → 15/8 | s:sd n:5 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 15/8 → 31/16 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 15/8 → 2/1 | s:cp n:7 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 61/32 → 31/16 | s:sd n:2 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 31/16 → 2/1 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 2/1 → 17/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 2/1 → 17/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 33/16 → 17/8 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 17/8 → 9/4 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 17/8 → 9/4 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 35/16 → 9/4 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 9/4 → 37/16 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 73/32 → 37/16 | s:sd n:5 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 37/16 → 75/32 | s:sd n:1 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 37/16 → 19/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 19/8 → 39/16 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 19/8 → 5/2 | s:cp n:7 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 77/32 → 39/16 | s:sd n:2 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 39/16 → 5/2 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 5/2 → 21/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 5/2 → 21/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 41/16 → 21/8 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 21/8 → 11/4 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 21/8 → 11/4 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 43/16 → 11/4 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 11/4 → 89/32 | s:sd n:1 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 11/4 → 45/16 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 45/16 → 23/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 91/32 → 23/8 | s:sd n:5 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 23/8 → 47/16 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 23/8 → 3/1 | s:cp n:7 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 93/32 → 47/16 | s:sd n:2 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 47/16 → 3/1 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 3/1 → 25/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 3/1 → 25/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 49/16 → 25/8 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 25/8 → 13/4 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 25/8 → 13/4 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 51/16 → 13/4 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 13/4 → 53/16 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 105/32 → 53/16 | s:sd n:5 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 53/16 → 107/32 | s:sd n:1 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 53/16 → 27/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 27/8 → 55/16 | s:sd n:1 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 27/8 → 7/2 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 7/2 → 29/8 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 7/2 → 29/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 57/16 → 29/8 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 29/8 → 15/4 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 29/8 → 15/4 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 59/16 → 15/4 | s:sd n:6 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 15/4 → 121/32 | s:sd n:1 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 15/4 → 61/16 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 61/16 → 31/8 | s:hh bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 123/32 → 31/8 | s:sd n:5 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 31/8 → 63/16 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 31/8 → 4/1 | s:cp n:7 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 125/32 → 63/16 | s:sd n:2 bank:RolandTR909 speed:1.2 ]",
|
||||||
|
"[ 63/16 → 4/1 | s:bd bank:RolandTR909 speed:1.2 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "bpattack" example index 0 1`] = `
|
exports[`runs examples > example "bpattack" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | note:c2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]",
|
"[ 0/1 → 1/4 | note:c2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]",
|
||||||
@ -1229,6 +1379,16 @@ exports[`runs examples > example "brandBy" example index 0 1`] = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "cat" example index 0 1`] = `
|
exports[`runs examples > example "cat" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/1 | note:e5 ]",
|
||||||
|
"[ 1/1 → 2/1 | note:b4 ]",
|
||||||
|
"[ 2/1 → 5/2 | note:d5 ]",
|
||||||
|
"[ 5/2 → 3/1 | note:c5 ]",
|
||||||
|
"[ 3/1 → 4/1 | note:e5 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "cat" example index 1 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | s:hh ]",
|
"[ 0/1 → 1/4 | s:hh ]",
|
||||||
"[ 1/4 → 1/2 | s:hh ]",
|
"[ 1/4 → 1/2 | s:hh ]",
|
||||||
@ -1251,16 +1411,6 @@ exports[`runs examples > example "cat" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "cat" example index 0 2`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/1 | note:e5 ]",
|
|
||||||
"[ 1/1 → 2/1 | note:b4 ]",
|
|
||||||
"[ 2/1 → 5/2 | note:d5 ]",
|
|
||||||
"[ 5/2 → 3/1 | note:c5 ]",
|
|
||||||
"[ 3/1 → 4/1 | note:e5 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "ceil" example index 0 1`] = `
|
exports[`runs examples > example "ceil" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | note:42 ]",
|
"[ 0/1 → 1/4 | note:42 ]",
|
||||||
@ -2666,6 +2816,43 @@ exports[`runs examples > example "fastGap" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "filter" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/8 | s:hh ]",
|
||||||
|
"[ 1/8 → 1/4 | s:hh ]",
|
||||||
|
"[ 1/4 → 3/8 | s:hh ]",
|
||||||
|
"[ 3/8 → 1/2 | s:hh ]",
|
||||||
|
"[ 1/2 → 5/8 | s:hh ]",
|
||||||
|
"[ 5/8 → 3/4 | s:hh ]",
|
||||||
|
"[ 3/4 → 7/8 | s:hh ]",
|
||||||
|
"[ 7/8 → 1/1 | s:oh ]",
|
||||||
|
"[ 1/1 → 9/8 | s:hh ]",
|
||||||
|
"[ 9/8 → 5/4 | s:hh ]",
|
||||||
|
"[ 5/4 → 11/8 | s:hh ]",
|
||||||
|
"[ 11/8 → 3/2 | s:hh ]",
|
||||||
|
"[ 3/2 → 13/8 | s:hh ]",
|
||||||
|
"[ 13/8 → 7/4 | s:hh ]",
|
||||||
|
"[ 7/4 → 15/8 | s:hh ]",
|
||||||
|
"[ 15/8 → 2/1 | s:oh ]",
|
||||||
|
"[ 2/1 → 17/8 | s:hh ]",
|
||||||
|
"[ 17/8 → 9/4 | s:hh ]",
|
||||||
|
"[ 9/4 → 19/8 | s:hh ]",
|
||||||
|
"[ 19/8 → 5/2 | s:hh ]",
|
||||||
|
"[ 5/2 → 21/8 | s:hh ]",
|
||||||
|
"[ 21/8 → 11/4 | s:hh ]",
|
||||||
|
"[ 11/4 → 23/8 | s:hh ]",
|
||||||
|
"[ 23/8 → 3/1 | s:oh ]",
|
||||||
|
"[ 3/1 → 25/8 | s:hh ]",
|
||||||
|
"[ 25/8 → 13/4 | s:hh ]",
|
||||||
|
"[ 13/4 → 27/8 | s:hh ]",
|
||||||
|
"[ 27/8 → 7/2 | s:hh ]",
|
||||||
|
"[ 7/2 → 29/8 | s:hh ]",
|
||||||
|
"[ 29/8 → 15/4 | s:hh ]",
|
||||||
|
"[ 15/4 → 31/8 | s:hh ]",
|
||||||
|
"[ 31/8 → 4/1 | s:oh ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "firstOf" example index 0 1`] = `
|
exports[`runs examples > example "firstOf" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | note:g3 ]",
|
"[ 0/1 → 1/4 | note:g3 ]",
|
||||||
@ -6789,6 +6976,27 @@ exports[`runs examples > example "segment" example index 0 1`] = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "seq" example index 0 1`] = `
|
exports[`runs examples > example "seq" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/3 | note:e5 ]",
|
||||||
|
"[ 1/3 → 2/3 | note:b4 ]",
|
||||||
|
"[ 2/3 → 5/6 | note:d5 ]",
|
||||||
|
"[ 5/6 → 1/1 | note:c5 ]",
|
||||||
|
"[ 1/1 → 4/3 | note:e5 ]",
|
||||||
|
"[ 4/3 → 5/3 | note:b4 ]",
|
||||||
|
"[ 5/3 → 11/6 | note:d5 ]",
|
||||||
|
"[ 11/6 → 2/1 | note:c5 ]",
|
||||||
|
"[ 2/1 → 7/3 | note:e5 ]",
|
||||||
|
"[ 7/3 → 8/3 | note:b4 ]",
|
||||||
|
"[ 8/3 → 17/6 | note:d5 ]",
|
||||||
|
"[ 17/6 → 3/1 | note:c5 ]",
|
||||||
|
"[ 3/1 → 10/3 | note:e5 ]",
|
||||||
|
"[ 10/3 → 11/3 | note:b4 ]",
|
||||||
|
"[ 11/3 → 23/6 | note:d5 ]",
|
||||||
|
"[ 23/6 → 4/1 | note:c5 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "seq" example index 1 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/8 | s:hh ]",
|
"[ 0/1 → 1/8 | s:hh ]",
|
||||||
"[ 1/8 → 1/4 | s:hh ]",
|
"[ 1/8 → 1/4 | s:hh ]",
|
||||||
@ -6829,24 +7037,23 @@ exports[`runs examples > example "seq" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "seq" example index 0 2`] = `
|
exports[`runs examples > example "seqPLoop" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/3 | note:e5 ]",
|
"[ 0/1 → 1/8 | s:bd ]",
|
||||||
"[ 1/3 → 2/3 | note:b4 ]",
|
"[ 3/8 → 1/2 | s:bd ]",
|
||||||
"[ 2/3 → 5/6 | note:d5 ]",
|
"[ 3/4 → 7/8 | s:bd ]",
|
||||||
"[ 5/6 → 1/1 | note:c5 ]",
|
"[ 1/1 → 9/8 | s:bd ]",
|
||||||
"[ 1/1 → 4/3 | note:e5 ]",
|
"[ 1/1 → 9/8 | s:cp ]",
|
||||||
"[ 4/3 → 5/3 | note:b4 ]",
|
"[ 11/8 → 3/2 | s:bd ]",
|
||||||
"[ 5/3 → 11/6 | note:d5 ]",
|
"[ 11/8 → 3/2 | s:cp ]",
|
||||||
"[ 11/6 → 2/1 | note:c5 ]",
|
"[ 7/4 → 15/8 | s:bd ]",
|
||||||
"[ 2/1 → 7/3 | note:e5 ]",
|
"[ 7/4 → 15/8 | s:cp ]",
|
||||||
"[ 7/3 → 8/3 | note:b4 ]",
|
"[ 2/1 → 17/8 | s:cp ]",
|
||||||
"[ 8/3 → 17/6 | note:d5 ]",
|
"[ 19/8 → 5/2 | s:cp ]",
|
||||||
"[ 17/6 → 3/1 | note:c5 ]",
|
"[ 11/4 → 23/8 | s:cp ]",
|
||||||
"[ 3/1 → 10/3 | note:e5 ]",
|
"[ 3/1 → 25/8 | s:bd ]",
|
||||||
"[ 10/3 → 11/3 | note:b4 ]",
|
"[ 27/8 → 7/2 | s:bd ]",
|
||||||
"[ 11/3 → 23/6 | note:d5 ]",
|
"[ 15/4 → 31/8 | s:bd ]",
|
||||||
"[ 23/6 → 4/1 | note:c5 ]",
|
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -7523,6 +7730,27 @@ exports[`runs examples > example "squiz" example index 0 1`] = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "stack" example index 0 1`] = `
|
exports[`runs examples > example "stack" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/2 | note:e4 ]",
|
||||||
|
"[ 0/1 → 1/1 | note:g3 ]",
|
||||||
|
"[ 0/1 → 1/1 | note:b3 ]",
|
||||||
|
"[ 1/2 → 1/1 | note:d4 ]",
|
||||||
|
"[ 1/1 → 3/2 | note:e4 ]",
|
||||||
|
"[ 1/1 → 2/1 | note:g3 ]",
|
||||||
|
"[ 1/1 → 2/1 | note:b3 ]",
|
||||||
|
"[ 3/2 → 2/1 | note:d4 ]",
|
||||||
|
"[ 2/1 → 5/2 | note:e4 ]",
|
||||||
|
"[ 2/1 → 3/1 | note:g3 ]",
|
||||||
|
"[ 2/1 → 3/1 | note:b3 ]",
|
||||||
|
"[ 5/2 → 3/1 | note:d4 ]",
|
||||||
|
"[ 3/1 → 7/2 | note:e4 ]",
|
||||||
|
"[ 3/1 → 4/1 | note:g3 ]",
|
||||||
|
"[ 3/1 → 4/1 | note:b3 ]",
|
||||||
|
"[ 7/2 → 4/1 | note:d4 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "stack" example index 1 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/8 | note:c4 ]",
|
"[ 0/1 → 1/8 | note:c4 ]",
|
||||||
"[ 0/1 → 1/4 | s:hh ]",
|
"[ 0/1 → 1/4 | s:hh ]",
|
||||||
@ -7563,27 +7791,6 @@ exports[`runs examples > example "stack" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "stack" example index 0 2`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/2 | note:e4 ]",
|
|
||||||
"[ 0/1 → 1/1 | note:g3 ]",
|
|
||||||
"[ 0/1 → 1/1 | note:b3 ]",
|
|
||||||
"[ 1/2 → 1/1 | note:d4 ]",
|
|
||||||
"[ 1/1 → 3/2 | note:e4 ]",
|
|
||||||
"[ 1/1 → 2/1 | note:g3 ]",
|
|
||||||
"[ 1/1 → 2/1 | note:b3 ]",
|
|
||||||
"[ 3/2 → 2/1 | note:d4 ]",
|
|
||||||
"[ 2/1 → 5/2 | note:e4 ]",
|
|
||||||
"[ 2/1 → 3/1 | note:g3 ]",
|
|
||||||
"[ 2/1 → 3/1 | note:b3 ]",
|
|
||||||
"[ 5/2 → 3/1 | note:d4 ]",
|
|
||||||
"[ 3/1 → 7/2 | note:e4 ]",
|
|
||||||
"[ 3/1 → 4/1 | note:g3 ]",
|
|
||||||
"[ 3/1 → 4/1 | note:b3 ]",
|
|
||||||
"[ 7/2 → 4/1 | note:d4 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "steps" example index 0 1`] = `
|
exports[`runs examples > example "steps" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | s:bd ]",
|
"[ 0/1 → 1/4 | s:bd ]",
|
||||||
|
|||||||
@ -26,7 +26,7 @@ author: froos
|
|||||||
- fix: 💄 Enhance visualisation of the Tutorial on mobile by @puria in https://github.com/tidalcycles/strudel/pull/19
|
- fix: 💄 Enhance visualisation of the Tutorial on mobile by @puria in https://github.com/tidalcycles/strudel/pull/19
|
||||||
- Stateful queries and events (WIP) by @yaxu in https://github.com/tidalcycles/strudel/pull/14
|
- Stateful queries and events (WIP) by @yaxu in https://github.com/tidalcycles/strudel/pull/14
|
||||||
- Fix resolveState by @yaxu in https://github.com/tidalcycles/strudel/pull/22
|
- Fix resolveState by @yaxu in https://github.com/tidalcycles/strudel/pull/22
|
||||||
- added \_asNumber + interprete numbers as midi by @felixroos in https://github.com/tidalcycles/strudel/pull/21
|
- added \_asNumber + interpret numbers as midi by @felixroos in https://github.com/tidalcycles/strudel/pull/21
|
||||||
- Update package.json by @ChiakiUehira in https://github.com/tidalcycles/strudel/pull/23
|
- Update package.json by @ChiakiUehira in https://github.com/tidalcycles/strudel/pull/23
|
||||||
- packaging by @felixroos in https://github.com/tidalcycles/strudel/pull/24
|
- packaging by @felixroos in https://github.com/tidalcycles/strudel/pull/24
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ author: froos
|
|||||||
|
|
||||||
- support freq in pianoroll by @felixroos in https://github.com/tidalcycles/strudel/pull/308
|
- support freq in pianoroll by @felixroos in https://github.com/tidalcycles/strudel/pull/308
|
||||||
- ICLC2023 paper WIP by @yaxu in https://github.com/tidalcycles/strudel/pull/306
|
- ICLC2023 paper WIP by @yaxu in https://github.com/tidalcycles/strudel/pull/306
|
||||||
- fix: copy share link to clipboard was broken for some browers by @felixroos in https://github.com/tidalcycles/strudel/pull/311
|
- fix: copy share link to clipboard was broken for some browsers by @felixroos in https://github.com/tidalcycles/strudel/pull/311
|
||||||
- Jsdoc component by @felixroos in https://github.com/tidalcycles/strudel/pull/312
|
- Jsdoc component by @felixroos in https://github.com/tidalcycles/strudel/pull/312
|
||||||
- object support for .scale by @felixroos in https://github.com/tidalcycles/strudel/pull/307
|
- object support for .scale by @felixroos in https://github.com/tidalcycles/strudel/pull/307
|
||||||
- Astro build by @felixroos in https://github.com/tidalcycles/strudel/pull/315
|
- Astro build by @felixroos in https://github.com/tidalcycles/strudel/pull/315
|
||||||
|
|||||||
@ -138,7 +138,7 @@ Plenty of things have been added to the docs, including a [showcase of what peop
|
|||||||
- Export patterns + ui tweaks by @felixroos in https://github.com/tidalcycles/strudel/pull/855
|
- Export patterns + ui tweaks by @felixroos in https://github.com/tidalcycles/strudel/pull/855
|
||||||
- Pattern organization by @felixroos in https://github.com/tidalcycles/strudel/pull/858
|
- Pattern organization by @felixroos in https://github.com/tidalcycles/strudel/pull/858
|
||||||
- Sound Import from local file system by @daslyfe in https://github.com/tidalcycles/strudel/pull/839
|
- Sound Import from local file system by @daslyfe in https://github.com/tidalcycles/strudel/pull/839
|
||||||
- bugfix: suspend and close exisiting audio context when changing interface by @daslyfe in https://github.com/tidalcycles/strudel/pull/882
|
- bugfix: suspend and close existing audio context when changing interface by @daslyfe in https://github.com/tidalcycles/strudel/pull/882
|
||||||
- add root mode for voicings by @felixroos in https://github.com/tidalcycles/strudel/pull/887
|
- add root mode for voicings by @felixroos in https://github.com/tidalcycles/strudel/pull/887
|
||||||
- scales can now be anchored by @felixroos in https://github.com/tidalcycles/strudel/pull/888
|
- scales can now be anchored by @felixroos in https://github.com/tidalcycles/strudel/pull/888
|
||||||
- add dough function for raw dsp by @felixroos in https://github.com/tidalcycles/strudel/pull/707 (experimental)
|
- add dough function for raw dsp by @felixroos in https://github.com/tidalcycles/strudel/pull/707 (experimental)
|
||||||
@ -195,7 +195,7 @@ Plenty of things have been added to the docs, including a [showcase of what peop
|
|||||||
- Update tauri.yml workflow file by @vasilymilovidov in https://github.com/tidalcycles/strudel/pull/705
|
- Update tauri.yml workflow file by @vasilymilovidov in https://github.com/tidalcycles/strudel/pull/705
|
||||||
- vite-vanilla-repl readme fix by @felixroos in https://github.com/tidalcycles/strudel/pull/737
|
- vite-vanilla-repl readme fix by @felixroos in https://github.com/tidalcycles/strudel/pull/737
|
||||||
- completely revert config mess by @felixroos in https://github.com/tidalcycles/strudel/pull/745
|
- completely revert config mess by @felixroos in https://github.com/tidalcycles/strudel/pull/745
|
||||||
- hopefully fix trainling slashes bug by @felixroos in https://github.com/tidalcycles/strudel/pull/753
|
- hopefully fix trailing slashes bug by @felixroos in https://github.com/tidalcycles/strudel/pull/753
|
||||||
- Update vite pwa by @felixroos in https://github.com/tidalcycles/strudel/pull/772
|
- Update vite pwa by @felixroos in https://github.com/tidalcycles/strudel/pull/772
|
||||||
- Update to Astro 3 by @felixroos in https://github.com/tidalcycles/strudel/pull/775
|
- Update to Astro 3 by @felixroos in https://github.com/tidalcycles/strudel/pull/775
|
||||||
- support multiple named serial connections, change default baudrate by @yaxu in https://github.com/tidalcycles/strudel/pull/551
|
- support multiple named serial connections, change default baudrate by @yaxu in https://github.com/tidalcycles/strudel/pull/551
|
||||||
|
|||||||
@ -120,6 +120,7 @@ export function MiniRepl({
|
|||||||
'cursor-pointer w-16 flex items-center justify-center p-1 border-r border-lineHighlight text-foreground bg-lineHighlight hover:bg-background',
|
'cursor-pointer w-16 flex items-center justify-center p-1 border-r border-lineHighlight text-foreground bg-lineHighlight hover:bg-background',
|
||||||
started ? 'animate-pulse' : '',
|
started ? 'animate-pulse' : '',
|
||||||
)}
|
)}
|
||||||
|
aria-label={started ? 'stop' : 'play'}
|
||||||
onClick={() => editorRef.current?.toggle()}
|
onClick={() => editorRef.current?.toggle()}
|
||||||
>
|
>
|
||||||
<Icon type={started ? 'stop' : 'play'} />
|
<Icon type={started ? 'stop' : 'play'} />
|
||||||
@ -129,6 +130,7 @@ export function MiniRepl({
|
|||||||
'w-16 flex items-center justify-center p-1 text-foreground border-lineHighlight bg-lineHighlight',
|
'w-16 flex items-center justify-center p-1 text-foreground border-lineHighlight bg-lineHighlight',
|
||||||
isDirty ? 'text-foreground hover:bg-background cursor-pointer' : 'opacity-50 cursor-not-allowed',
|
isDirty ? 'text-foreground hover:bg-background cursor-pointer' : 'opacity-50 cursor-not-allowed',
|
||||||
)}
|
)}
|
||||||
|
aria-label="update"
|
||||||
onClick={() => editorRef.current?.evaluate()}
|
onClick={() => editorRef.current?.evaluate()}
|
||||||
>
|
>
|
||||||
<Icon type="refresh" />
|
<Icon type="refresh" />
|
||||||
@ -140,6 +142,7 @@ export function MiniRepl({
|
|||||||
className={
|
className={
|
||||||
'cursor-pointer w-16 flex items-center justify-center p-1 border-r border-lineHighlight text-foreground bg-lineHighlight hover:bg-background'
|
'cursor-pointer w-16 flex items-center justify-center p-1 border-r border-lineHighlight text-foreground bg-lineHighlight hover:bg-background'
|
||||||
}
|
}
|
||||||
|
aria-label="previous example"
|
||||||
onClick={() => changeTune(tuneIndex - 1)}
|
onClick={() => changeTune(tuneIndex - 1)}
|
||||||
>
|
>
|
||||||
<div className="rotate-180">
|
<div className="rotate-180">
|
||||||
@ -150,6 +153,7 @@ export function MiniRepl({
|
|||||||
className={
|
className={
|
||||||
'cursor-pointer w-16 flex items-center justify-center p-1 border-r border-lineHighlight text-foreground bg-lineHighlight hover:bg-background'
|
'cursor-pointer w-16 flex items-center justify-center p-1 border-r border-lineHighlight text-foreground bg-lineHighlight hover:bg-background'
|
||||||
}
|
}
|
||||||
|
aria-label="next example"
|
||||||
onClick={() => changeTune(tuneIndex + 1)}
|
onClick={() => changeTune(tuneIndex + 1)}
|
||||||
>
|
>
|
||||||
<Icon type="skip" />
|
<Icon type="skip" />
|
||||||
|
|||||||
@ -25,26 +25,14 @@ These are the equivalents used by the Mini Notation:
|
|||||||
|
|
||||||
<JsDoc client:idle name="cat" h={0} />
|
<JsDoc client:idle name="cat" h={0} />
|
||||||
|
|
||||||
You can also use cat as a chained function like this:
|
|
||||||
|
|
||||||
<JsDoc client:idle name="Pattern.cat" h={0} hideDescription />
|
|
||||||
|
|
||||||
## seq
|
## seq
|
||||||
|
|
||||||
<JsDoc client:idle name="seq" h={0} />
|
<JsDoc client:idle name="seq" h={0} />
|
||||||
|
|
||||||
Or as a chained function:
|
|
||||||
|
|
||||||
<JsDoc client:idle name="Pattern.seq" h={0} hideDescription />
|
|
||||||
|
|
||||||
## stack
|
## stack
|
||||||
|
|
||||||
<JsDoc client:idle name="stack" h={0} />
|
<JsDoc client:idle name="stack" h={0} />
|
||||||
|
|
||||||
As a chained function:
|
|
||||||
|
|
||||||
<JsDoc client:idle name="Pattern.stack" h={0} hideDescription />
|
|
||||||
|
|
||||||
## s_cat
|
## s_cat
|
||||||
|
|
||||||
<JsDoc client:idle name="s_cat" h={0} />
|
<JsDoc client:idle name="s_cat" h={0} />
|
||||||
|
|||||||
@ -43,7 +43,7 @@ export function Header({ context, embedded = false }) {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cx('mt-[1px]', started && 'animate-spin', 'cursor-pointer')}
|
className={cx('mt-[1px]', started && 'animate-spin', 'cursor-pointer', isZen && 'fixed top-2 right-4')}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!isEmbedded) {
|
if (!isEmbedded) {
|
||||||
setIsZen(!isZen);
|
setIsZen(!isZen);
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import cx from '@src/cx.mjs';
|
|||||||
export function ConsoleTab({ log }) {
|
export function ConsoleTab({ log }) {
|
||||||
return (
|
return (
|
||||||
<div id="console-tab" className="break-all px-4 dark:text-white text-stone-900 text-sm">
|
<div id="console-tab" className="break-all px-4 dark:text-white text-stone-900 text-sm">
|
||||||
<pre>{`███████╗████████╗██████╗ ██╗ ██╗██████╗ ███████╗██╗
|
<pre aria-hidden="true">{`███████╗████████╗██████╗ ██╗ ██╗██████╗ ███████╗██╗
|
||||||
██╔════╝╚══██╔══╝██╔══██╗██║ ██║██╔══██╗██╔════╝██║
|
██╔════╝╚══██╔══╝██╔══██╗██║ ██║██╔══██╗██╔════╝██║
|
||||||
███████╗ ██║ ██████╔╝██║ ██║██║ ██║█████╗ ██║
|
███████╗ ██║ ██████╔╝██║ ██║██║ ██║█████╗ ██║
|
||||||
╚════██║ ██║ ██╔══██╗██║ ██║██║ ██║██╔══╝ ██║
|
╚════██║ ██║ ██╔══██╗██║ ██║██║ ██║██╔══╝ ██║
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import jsdocJson from '../../../../../doc.json';
|
import jsdocJson from '../../../../../doc.json';
|
||||||
const visibleFunctions = jsdocJson.docs
|
const availableFunctions = jsdocJson.docs
|
||||||
.filter(({ name, description }) => name && !name.startsWith('_') && !!description)
|
.filter(({ name, description }) => name && !name.startsWith('_') && !!description)
|
||||||
.sort((a, b) => /* a.meta.filename.localeCompare(b.meta.filename) + */ a.name.localeCompare(b.name));
|
.sort((a, b) => /* a.meta.filename.localeCompare(b.meta.filename) + */ a.name.localeCompare(b.name));
|
||||||
|
|
||||||
@ -10,9 +12,29 @@ const getInnerText = (html) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function Reference() {
|
export function Reference() {
|
||||||
|
const [search, setSearch] = useState('');
|
||||||
|
|
||||||
|
const visibleFunctions = useMemo(() => {
|
||||||
|
return availableFunctions.filter((entry) => {
|
||||||
|
if (!search) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry.name.includes(search) || (entry.synonyms?.some((s) => s.includes(search)) ?? false);
|
||||||
|
});
|
||||||
|
}, [search]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full pt-2 text-foreground overflow-hidden">
|
<div className="flex h-full w-full pt-2 text-foreground overflow-hidden">
|
||||||
<div className="w-42 flex-none h-full overflow-y-auto overflow-x-hidden pr-4">
|
<div className="w-42 flex-none h-full overflow-y-auto overflow-x-hidden pr-4">
|
||||||
|
<div class="w-full ml-2 mb-2 top-0 sticky">
|
||||||
|
<input
|
||||||
|
className="w-full p-1 bg-background rounded-md"
|
||||||
|
placeholder="Search"
|
||||||
|
value={search}
|
||||||
|
onInput={(event) => setSearch(event.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
{visibleFunctions.map((entry, i) => (
|
{visibleFunctions.map((entry, i) => (
|
||||||
<a
|
<a
|
||||||
key={i}
|
key={i}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import useEvent from '@src/useEvent.mjs';
|
import useEvent from '@src/useEvent.mjs';
|
||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { getAudioContext, soundMap, connectToDestination } from '@strudel/webaudio';
|
import { getAudioContext, soundMap, connectToDestination } from '@strudel/webaudio';
|
||||||
import React, { useMemo, useRef } from 'react';
|
import React, { useMemo, useRef, useState } from 'react';
|
||||||
import { settingsMap, useSettings } from '../../../settings.mjs';
|
import { settingsMap, useSettings } from '../../../settings.mjs';
|
||||||
import { ButtonGroup } from './Forms.jsx';
|
import { ButtonGroup } from './Forms.jsx';
|
||||||
import ImportSoundsButton from './ImportSoundsButton.jsx';
|
import ImportSoundsButton from './ImportSoundsButton.jsx';
|
||||||
@ -12,15 +12,20 @@ const getSamples = (samples) =>
|
|||||||
export function SoundsTab() {
|
export function SoundsTab() {
|
||||||
const sounds = useStore(soundMap);
|
const sounds = useStore(soundMap);
|
||||||
const { soundsFilter } = useSettings();
|
const { soundsFilter } = useSettings();
|
||||||
|
const [search, setSearch] = useState('');
|
||||||
|
|
||||||
const soundEntries = useMemo(() => {
|
const soundEntries = useMemo(() => {
|
||||||
let filtered = Object.entries(sounds)
|
|
||||||
.filter(([key]) => !key.startsWith('_'))
|
|
||||||
.sort((a, b) => a[0].localeCompare(b[0]));
|
|
||||||
if (!sounds) {
|
if (!sounds) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let filtered = Object.entries(sounds)
|
||||||
|
.filter(([key]) => !key.startsWith('_'))
|
||||||
|
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||||
|
.filter(([name]) => name.toLowerCase().includes(search.toLowerCase()));
|
||||||
|
|
||||||
if (soundsFilter === 'user') {
|
if (soundsFilter === 'user') {
|
||||||
return filtered.filter(([key, { data }]) => !data.prebake);
|
return filtered.filter(([_, { data }]) => !data.prebake);
|
||||||
}
|
}
|
||||||
if (soundsFilter === 'drums') {
|
if (soundsFilter === 'drums') {
|
||||||
return filtered.filter(([_, { data }]) => data.type === 'sample' && data.tag === 'drum-machines');
|
return filtered.filter(([_, { data }]) => data.type === 'sample' && data.tag === 'drum-machines');
|
||||||
@ -32,9 +37,11 @@ export function SoundsTab() {
|
|||||||
return filtered.filter(([_, { data }]) => ['synth', 'soundfont'].includes(data.type));
|
return filtered.filter(([_, { data }]) => ['synth', 'soundfont'].includes(data.type));
|
||||||
}
|
}
|
||||||
return filtered;
|
return filtered;
|
||||||
}, [sounds, soundsFilter]);
|
}, [sounds, soundsFilter, search]);
|
||||||
|
|
||||||
// holds mutable ref to current triggered sound
|
// holds mutable ref to current triggered sound
|
||||||
const trigRef = useRef();
|
const trigRef = useRef();
|
||||||
|
|
||||||
// stop current sound on mouseup
|
// stop current sound on mouseup
|
||||||
useEvent('mouseup', () => {
|
useEvent('mouseup', () => {
|
||||||
const t = trigRef.current;
|
const t = trigRef.current;
|
||||||
@ -43,8 +50,17 @@ 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 dark:text-white text-stone-900">
|
<div id="sounds-tab" className="px-4 flex flex-col w-full h-full dark:text-white text-stone-900">
|
||||||
|
<div className="w-full ml-2 mb-2 top-0 sticky">
|
||||||
|
<input
|
||||||
|
className="w-full p-1 bg-background rounded-md"
|
||||||
|
placeholder="Search"
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="pb-2 flex shrink-0 flex-wrap">
|
<div className="pb-2 flex shrink-0 flex-wrap">
|
||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
value={soundsFilter}
|
value={soundsFilter}
|
||||||
|
|||||||
@ -23,10 +23,10 @@ async function hasStrudelJson(subpath) {
|
|||||||
async function loadStrudelJson(subpath) {
|
async function loadStrudelJson(subpath) {
|
||||||
const contents = await readTextFile(subpath + '/strudel.json', { dir });
|
const contents = await readTextFile(subpath + '/strudel.json', { dir });
|
||||||
const sampleMap = JSON.parse(contents);
|
const sampleMap = JSON.parse(contents);
|
||||||
processSampleMap(sampleMap, (key, value) => {
|
processSampleMap(sampleMap, (key, bank) => {
|
||||||
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, value, fileResolver(subpath)), {
|
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, bank, fileResolver(subpath)), {
|
||||||
type: 'sample',
|
type: 'sample',
|
||||||
samples: value,
|
samples: bank,
|
||||||
fileSystem: true,
|
fileSystem: true,
|
||||||
tag: 'local',
|
tag: 'local',
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user