Merge branch 'main' into fix-perf12

This commit is contained in:
jeromew
2025-12-08 18:54:51 +01:00
6 changed files with 447 additions and 34 deletions
+23 -11
View File
@@ -401,12 +401,13 @@ export const { accelerate } = registerControl('accelerate');
* Sets the velocity from 0 to 1. Is multiplied together with gain.
*
* @name velocity
* @synonyms vel
* @example
* s("hh*8")
* .gain(".4!2 1 .4!2 1 .4 1")
* .velocity(".4 1")
*/
export const { velocity } = registerControl('velocity');
export const { velocity, vel } = registerControl('velocity', 'vel');
/**
* Controls the gain by an exponential amount.
*
@@ -1482,14 +1483,13 @@ export const { lpdepth } = registerControl('lpdepth');
* Depth of the LFO for the lowpass filter, in HZ
*
* @name lpdepthfrequency
* @synonyms
* lpdethfreq
* @synonyms lpdepthfreq
* @param {number | Pattern} depth depth of modulation
* @example
* note("<c c c# c c c4>*16").s("sawtooth").lpf(600).lpdepthfrequency("<200 500 100 0>")
*/
export const { lpdepthfrequency } = registerControl('lpdepthfrequency', 'lpdepthfreq');
export const { lpdepthfrequency, lpdepthfreq } = registerControl('lpdepthfrequency', 'lpdepthfreq');
/**
* Shape of the LFO for the lowpass filter
@@ -1543,14 +1543,13 @@ export const { bpdepth } = registerControl('bpdepth');
* Depth of the LFO for the bandpass filter, in HZ
*
* @name bpdepthfrequency
* @synonyms
* bpdethfreq
* @synonyms bpdepthfreq
* @param {number | Pattern} depth depth of modulation
* @example
* note("<c c c# c c c4>*16").s("sawtooth").lpf(600).bpdepthfrequency("<200 500 100 0>")
*/
export const { bpdepthfrequency } = registerControl('bpdepthfrequency', 'bpdepthfreq');
export const { bpdepthfrequency, bpdepthfreq } = registerControl('bpdepthfrequency', 'bpdepthfreq');
/**
* Shape of the LFO for the bandpass filter
@@ -1598,20 +1597,19 @@ export const { hpsync } = registerControl('hpsync');
* @name hpdepth
* @param {number | Pattern} depth depth of modulation
*/
export const { hpdepth, hpdepthfreq } = registerControl('hpdepth');
export const { hpdepth } = registerControl('hpdepth');
/**
* Depth of the LFO for the hipass filter, in hz
*
* @name hpdepthfrequency
* @synonyms
* hpdethfreq
* @synonyms hpdepthfreq
* @param {number | Pattern} depth depth of modulation
* @example
* note("<c c c# c c c4>*16").s("sawtooth").lpf(600).hpdepthfrequency("<200 500 100 0>")
*/
export const { hpdepthfrequency } = registerControl('hpdepthfrequency', 'hpdepthfreq');
export const { hpdepthfrequency, hpdepthfreq } = registerControl('hpdepthfrequency', 'hpdepthfreq');
/**
* Shape of the LFO for the highpass filter
@@ -2788,3 +2786,17 @@ export const scrub = register(
},
false,
);
/**
* Transient shaper. Gives independent control over the emphasis on transients
* and sustains
*
* @name transient
* @param {number | Pattern} attack Emphasis on transients; between -1 (deaccentuate) and 1 (accentuate)
* @param {number | Pattern} sustain Emphasis on the sustains; between -1 (deaccentuate) and 1 (accentuate)
* @example
* s("bd").transient("<-1 -0.5 0 0.5 1>")
* @example
* s("hh*16").bank("tr909").transient("<-1:1 1:-1>")
*/
export const { transient } = registerControl(['transient', 'transsustain']);
+23 -6
View File
@@ -574,7 +574,8 @@ export class Pattern {
* Returns a new Pattern, which only returns haps that meet the given test.
* @param {Function} hap_test - a function which returns false for haps to be removed from the pattern
* @returns Pattern
* @noAutocomplete
* @example
* s("bd*8").velocity(rand).filterHaps((h) => (h.whole.begin % 1) < h.value.velocity)
*/
filterHaps(hap_test) {
return new Pattern((state) => this.query(state).filter(hap_test));
@@ -585,7 +586,11 @@ export class Pattern {
* inside haps.
* @param {Function} value_test
* @returns Pattern
* @noAutocomplete
* @example
* const drums = s("bd sd bd sd")
* kick: drums.filterValues((v) => v.s === 'bd').duck(2)
* snare: drums.filterValues((v) => v.s === 'sd')
* bass: s("saw!4").note("G#1").lpf(80).lpenv(4).orbit(2)
*/
filterValues(value_test) {
return new Pattern((state) => this.query(state).filter((hap) => value_test(hap.value))).setSteps(this._steps);
@@ -1587,7 +1592,13 @@ export const func = curry((a, b) => reify(b).func(a));
*
* @param {string | string[]} name name of the function, or an array of names to be used as synonyms
* @param {function} func function with 1 or more params, where last is the current pattern
* @noAutocomplete
* @param {bool} patternify defaults to true; if set to false, you will have more control over the arguments to `func` as they will be
* in their raw form and it will be up to you to patternify them and/or query them for values
* @example
* const vlpf = register('vlpf', (freq, pat) => {
* return pat.fmap((v) => ({...v, cutoff: freq * (v.velocity ?? 1) }));
* })
* s("saw").seg(8).velocity(rand).vlpf(800)
*
*/
export function register(name, func, patternify = true, preserveSteps = false, join = (x) => x.innerJoin()) {
@@ -2676,8 +2687,13 @@ export const hsl = register('hsl', (h, s, l, pat) => {
/**
* Tags each Hap with an identifier. Good for filtering. The function populates Hap.context.tags (Array).
* @name tag
* @noAutocomplete
* @param {string} tag anything unique
* @example
* s("saw!16").note("F1")
* .lpf(tri.range(40, 80).slow(4)).lpenv(5).lpq(4).lpd(0.15)
* .when(rand.late(0.1).gte(0.5), x => x.transpose("12").tag('altered'))
* .when(rand.late(0.2).gte(0.5), x => x.s("square").tag('altered'))
* .when("<0 1>", x => x.filter((hap) => hap.hasTag('altered')))
*/
Pattern.prototype.tag = function (tag) {
return this.withContext((ctx) => ({ ...ctx, tags: (ctx.tags || []).concat([tag]) }));
@@ -2688,15 +2704,16 @@ Pattern.prototype.tag = function (tag) {
* @name filter
* @param {Function} test function to test Hap
* @example
* s("hh!7 oh").filter(hap => hap.value.s==='hh')
* 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
* @example
* oneCycle: s("bd*4").filterWhen((t) => t < 1)
*/
export const filterWhen = register('filterWhen', (test, pat) => pat.filter((h) => test(h.whole.begin)));
+26 -9
View File
@@ -479,14 +479,24 @@ Pattern.prototype.midi = function (midiport, options = {}) {
let listeners = {};
const refs = {};
const refsByChan = {};
/**
* MIDI input: Opens a MIDI input port to receive MIDI control change messages.
*
* The output is a function that accepts a midi cc value to query as well as (optionally) a midi channel
* @param {string | number} input MIDI device name or index defaulting to 0
* @returns {Function}
* @returns {function(number, number=): Pattern} A function from (cc, channel?) to a pattern.
* When queried, the pattern will produces the most recently received midi value (normalized to 0 to 1)
* that came through that cc number (and channel, if provided)
* @example
* let cc = await midin('IAC Driver Bus 1')
* const cc = await midin('IAC Driver Bus 1')
* note("c a f e").lpf(cc(0).range(0, 1000)).lpq(cc(1).range(0, 10)).sound("sawtooth")
* @example
* const allCC = await midin('IAC Driver Bus 1')
* const cc = (ccNum) => allCC(ccNum, 2) // just channel 2
* note("c a f e").s("saw")
* .when(cc(0).gt(0), x => x.postgain(0))
*/
export async function midin(input) {
if (isPattern(input)) {
@@ -511,17 +521,24 @@ export async function midin(input) {
}`,
);
}
// ensure refs for this input are initialized
if (!refs[input]) {
refs[input] = {};
}
const cc = (cc) => ref(() => refs[input][cc] || 0);
refs[input] ??= {};
refsByChan[input] ??= {};
const cc = (cc, chan) => {
if (chan !== undefined) {
return ref(() => refsByChan[input][cc]?.[chan] || 0);
}
return ref(() => refs[input][cc] || 0);
};
listeners[input] && device.removeListener('midimessage', listeners[input]);
listeners[input] = (e) => {
const cc = e.dataBytes[0];
const ccNum = e.dataBytes[0];
const v = e.dataBytes[1];
refs[input] && (refs[input][cc] = v / 127);
const chan = e.message.channel;
const scaled = v / 127;
refsByChan[input][ccNum] ??= {};
refsByChan[input][ccNum][chan] = scaled;
refs[input][ccNum] = scaled;
};
device.addListener('midimessage', listeners[input]);
return cc;
+24 -8
View File
@@ -299,8 +299,8 @@ function getPhaser(time, end, frequency = 1, depth = 0.5, centerFrequency = 1000
const lfo = getLfo(ac, time, end, { frequency, depth: sweep * 2 });
//filters
const numStages = 2; //num of filters in series
let fOffset = 0;
const numStages = 1; //num of filters in series
let fOffset = 282; //for backward compat in #1800
const filterChain = [];
for (let i = 0; i < numStages; i++) {
const filter = ac.createBiquadFilter();
@@ -311,12 +311,9 @@ function getPhaser(time, end, frequency = 1, depth = 0.5, centerFrequency = 1000
lfo.connect(filter.detune);
fOffset += 282;
if (i > 0) {
filterChain[i - 1].connect(filter);
}
filterChain.push(filter);
}
return { phaser: filterChain[filterChain.length - 1], lfo };
return { filterChain, lfo };
}
function getFilterType(ftype) {
@@ -460,6 +457,8 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
compressorKnee,
compressorAttack,
compressorRelease,
transient,
transsustain,
} = value;
delaytime = delaytime ?? cycleToSeconds(delaysync, cps);
@@ -541,6 +540,23 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
chain.push(sourceNode);
stretch !== undefined && chain.push(getWorklet(ac, 'phase-vocoder-processor', { pitchFactor: stretch }));
transient !== undefined &&
chain.push(
getWorklet(
ac,
'transient-processor',
{},
{
processorOptions: {
attack: transient,
sustain: transsustain,
begin: t,
end: endWithRelease,
},
},
),
);
// gain stage
chain.push(gainNode(gain));
@@ -706,9 +722,9 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
}
// phaser
if (phaserrate !== undefined && phaserdepth > 0) {
const { phaser, lfo } = getPhaser(t, endWithRelease, phaserrate, phaserdepth, phasercenter, phasersweep);
const { filterChain, lfo } = getPhaser(t, endWithRelease, phaserrate, phaserdepth, phasercenter, phasersweep);
audioNodes.push(lfo);
chain.push(phaser);
chain.push(...filterChain);
}
// last gain
+82
View File
@@ -11,6 +11,9 @@ const PI = Math.PI;
const TWO_PI = 2 * PI;
const INVSR = 1 / sampleRate;
const timeToCoeff = (t) => 1 - Math.exp(-INVSR / t);
const dbToLin = (db) => Math.pow(10, db / 20);
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
const mod = (n, m) => ((n % m) + m) % m;
const lerp = (a, b, n) => n * (b - a) + a;
@@ -1384,3 +1387,82 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor {
}
registerProcessor('wavetable-oscillator-processor', WavetableOscillatorProcessor);
class TransientProcessor extends AudioWorkletProcessor {
static get parameterDescriptors() {
return [];
}
constructor(options) {
super();
this.gainCoeff = timeToCoeff(0.2);
this.avgGain = 1;
let {
attackTime = 0.003,
sustainTime = 0.08,
attack = 0,
sustain = 0,
sensitivity = 0.1,
mix = 1,
begin = 0,
end = 0,
} = options.processorOptions;
attackTime = clamp(attackTime, 0.0005, 0.05);
sustainTime = clamp(sustainTime, 0.01, 0.5);
this.attackCoeff = timeToCoeff(attackTime);
this.sustainCoeff = timeToCoeff(sustainTime);
this.attackAmt = clamp(attack, -1, 1);
this.sustainAmt = clamp(sustain, -1, 1);
this.scaling = 0.5 + 5 * clamp(sensitivity, 0, 1);
this.mix = clamp(mix, 0, 1);
this.begin = begin;
this.end = end;
this.attackEnv = new Float32Array(2); // assume stereo
this.sustainEnv = new Float32Array(2);
}
process(inputs, outputs, _params) {
const input = inputs[0];
const output = outputs[0];
if (currentTime >= this.end) {
return false;
}
if (currentTime <= this.begin) {
return true;
}
const channels = input.length;
if (channels > this.attackEnv.length) {
this.attackEnv = new Float32Array(channels);
this.sustainEnv = new Float32Array(channels);
}
let avgGain = this.avgGain;
for (let ch = 0; ch < channels; ch++) {
let attEnv = this.attackEnv[ch];
let susEnv = this.sustainEnv[ch];
for (let n = 0; n < blockSize; n++) {
const sample = input[ch][n];
const x = Math.abs(sample);
attEnv = lerp(attEnv, x, this.attackCoeff);
susEnv = lerp(susEnv, x, this.sustainCoeff);
const peakiness = clamp((this.scaling * (attEnv - susEnv)) / (susEnv + 1e-6), -1.5, 1.5);
const attScale = peakiness > 0 ? peakiness : 0;
const susScale = peakiness < 0 ? -peakiness : 0;
const attackGain = dbToLin(this.attackAmt * attScale * 18);
const sustainGain = dbToLin(this.sustainAmt * susScale * 36);
const gain = clamp(attackGain * sustainGain, 0, 8);
avgGain = lerp(avgGain, gain, this.gainCoeff);
const makeup = avgGain > 1e-3 ? 1 / avgGain : 1;
const wet = sample * gain * makeup;
let y = lerp(sample, wet, this.mix);
y /= 1 + Math.abs(y); // soft clip
output[ch][n] = y;
}
this.attackEnv[ch] = attEnv;
this.sustainEnv[ch] = susEnv;
}
this.avgGain = avgGain;
return true;
}
}
registerProcessor('transient-processor', TransientProcessor);
+269
View File
@@ -4043,6 +4043,70 @@ exports[`runs examples > example "filter" example index 0 1`] = `
]
`;
exports[`runs examples > example "filterHaps" example index 0 1`] = `
[
"[ 1/8 → 1/4 | s:bd velocity:0.6852155700325966 ]",
"[ 1/4 → 3/8 | s:bd velocity:0.36975969187915325 ]",
"[ 3/8 → 1/2 | s:bd velocity:0.40139251574873924 ]",
"[ 1/1 → 9/8 | s:bd velocity:0.5195421651005745 ]",
"[ 9/8 → 5/4 | s:bd velocity:0.6724895145744085 ]",
"[ 5/4 → 11/8 | s:bd velocity:0.7287282031029463 ]",
"[ 3/2 → 13/8 | s:bd velocity:0.6084080748260021 ]",
"[ 2/1 → 17/8 | s:bd velocity:0.9595271199941635 ]",
"[ 17/8 → 9/4 | s:bd velocity:0.9033902939409018 ]",
"[ 9/4 → 19/8 | s:bd velocity:0.34548251144587994 ]",
"[ 19/8 → 5/2 | s:bd velocity:0.8365066405385733 ]",
"[ 3/1 → 25/8 | s:bd velocity:0.21728911064565182 ]",
"[ 25/8 → 13/4 | s:bd velocity:0.34324387833476067 ]",
"[ 13/4 → 27/8 | s:bd velocity:0.9923650715500116 ]",
"[ 27/8 → 7/2 | s:bd velocity:0.40869180113077164 ]",
"[ 29/8 → 15/4 | s:bd velocity:0.9391485787928104 ]",
"[ 15/4 → 31/8 | s:bd velocity:0.8121673222631216 ]",
]
`;
exports[`runs examples > example "filterValues" example index 0 1`] = `
[
"[ 0/1 → 1/4 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 1/4 → 1/2 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 1/2 → 3/4 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 3/4 → 1/1 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 1/1 → 5/4 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 5/4 → 3/2 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 3/2 → 7/4 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 7/4 → 2/1 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 2/1 → 9/4 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 9/4 → 5/2 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 5/2 → 11/4 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 11/4 → 3/1 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 3/1 → 13/4 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 13/4 → 7/2 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 7/2 → 15/4 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
"[ 15/4 → 4/1 | s:saw note:G#1 cutoff:80 lpenv:4 orbit:2 ]",
]
`;
exports[`runs examples > example "filterWhen" example index 0 1`] = `
[
"[ 0/1 → 1/4 | s:bd ]",
"[ 1/4 → 1/2 | s:bd ]",
"[ 1/2 → 3/4 | s:bd ]",
"[ 3/4 → 1/1 | s:bd ]",
"[ 1/1 → 5/4 | s:bd ]",
"[ 5/4 → 3/2 | s:bd ]",
"[ 3/2 → 7/4 | s:bd ]",
"[ 7/4 → 2/1 | s:bd ]",
"[ 2/1 → 9/4 | s:bd ]",
"[ 9/4 → 5/2 | s:bd ]",
"[ 5/2 → 11/4 | s:bd ]",
"[ 11/4 → 3/1 | s:bd ]",
"[ 3/1 → 13/4 | s:bd ]",
"[ 13/4 → 7/2 | s:bd ]",
"[ 7/2 → 15/4 | s:bd ]",
"[ 15/4 → 4/1 | s:bd ]",
]
`;
exports[`runs examples > example "firstOf" example index 0 1`] = `
[
"[ 0/1 → 1/4 | note:g3 ]",
@@ -6984,6 +7048,27 @@ exports[`runs examples > example "midin" example index 0 1`] = `
]
`;
exports[`runs examples > example "midin" example index 1 1`] = `
[
"[ 0/1 → 1/4 | note:c s:saw ]",
"[ 1/4 → 1/2 | note:a s:saw ]",
"[ 1/2 → 3/4 | note:f s:saw ]",
"[ 3/4 → 1/1 | note:e s:saw ]",
"[ 1/1 → 5/4 | note:c s:saw ]",
"[ 5/4 → 3/2 | note:a s:saw ]",
"[ 3/2 → 7/4 | note:f s:saw ]",
"[ 7/4 → 2/1 | note:e s:saw ]",
"[ 2/1 → 9/4 | note:c s:saw ]",
"[ 9/4 → 5/2 | note:a s:saw ]",
"[ 5/2 → 11/4 | note:f s:saw ]",
"[ 11/4 → 3/1 | note:e s:saw ]",
"[ 3/1 → 13/4 | note:c s:saw ]",
"[ 13/4 → 7/2 | note:a s:saw ]",
"[ 7/2 → 15/4 | note:f s:saw ]",
"[ 15/4 → 4/1 | note:e s:saw ]",
]
`;
exports[`runs examples > example "midiport" example index 0 1`] = `
[
"[ 0/1 → 1/4 | note:c midiport:0 ]",
@@ -9101,6 +9186,43 @@ exports[`runs examples > example "ratio" example index 0 1`] = `
]
`;
exports[`runs examples > example "register" example index 0 1`] = `
[
"[ 0/1 → 1/8 | s:saw velocity:0 cutoff:0 ]",
"[ 1/8 → 1/4 | s:saw velocity:0.6852155700325966 cutoff:548.1724560260773 ]",
"[ 1/4 → 3/8 | s:saw velocity:0.36975969187915325 cutoff:295.8077535033226 ]",
"[ 3/8 → 1/2 | s:saw velocity:0.40139251574873924 cutoff:321.1140125989914 ]",
"[ 1/2 → 5/8 | s:saw velocity:0.2604806162416935 cutoff:208.3844929933548 ]",
"[ 5/8 → 3/4 | s:saw velocity:0.1356358677148819 cutoff:108.50869417190552 ]",
"[ 3/4 → 7/8 | s:saw velocity:0.19582648016512394 cutoff:156.66118413209915 ]",
"[ 7/8 → 1/1 | s:saw velocity:0.3976310808211565 cutoff:318.1048646569252 ]",
"[ 1/1 → 9/8 | s:saw velocity:0.5195421651005745 cutoff:415.6337320804596 ]",
"[ 9/8 → 5/4 | s:saw velocity:0.6724895145744085 cutoff:537.9916116595268 ]",
"[ 5/4 → 11/8 | s:saw velocity:0.7287282031029463 cutoff:582.982562482357 ]",
"[ 11/8 → 3/2 | s:saw velocity:0.18280375190079212 cutoff:146.2430015206337 ]",
"[ 3/2 → 13/8 | s:saw velocity:0.6084080748260021 cutoff:486.7264598608017 ]",
"[ 13/8 → 7/4 | s:saw velocity:0.49675471149384975 cutoff:397.4037691950798 ]",
"[ 7/4 → 15/8 | s:saw velocity:0.20473789609968662 cutoff:163.7903168797493 ]",
"[ 15/8 → 2/1 | s:saw velocity:0.5945571791380644 cutoff:475.6457433104515 ]",
"[ 2/1 → 17/8 | s:saw velocity:0.9595271199941635 cutoff:767.6216959953308 ]",
"[ 17/8 → 9/4 | s:saw velocity:0.9033902939409018 cutoff:722.7122351527214 ]",
"[ 9/4 → 19/8 | s:saw velocity:0.34548251144587994 cutoff:276.38600915670395 ]",
"[ 19/8 → 5/2 | s:saw velocity:0.8365066405385733 cutoff:669.2053124308586 ]",
"[ 5/2 → 21/8 | s:saw velocity:0.45861607417464256 cutoff:366.89285933971405 ]",
"[ 21/8 → 11/4 | s:saw velocity:0.16019348427653313 cutoff:128.1547874212265 ]",
"[ 11/4 → 23/8 | s:saw velocity:0.6332327704876661 cutoff:506.5862163901329 ]",
"[ 23/8 → 3/1 | s:saw velocity:0.01625417172908783 cutoff:13.003337383270264 ]",
"[ 3/1 → 25/8 | s:saw velocity:0.21728911064565182 cutoff:173.83128851652145 ]",
"[ 25/8 → 13/4 | s:saw velocity:0.34324387833476067 cutoff:274.59510266780853 ]",
"[ 13/4 → 27/8 | s:saw velocity:0.9923650715500116 cutoff:793.8920572400093 ]",
"[ 27/8 → 7/2 | s:saw velocity:0.40869180113077164 cutoff:326.9534409046173 ]",
"[ 7/2 → 29/8 | s:saw velocity:0.40994881466031075 cutoff:327.9590517282486 ]",
"[ 29/8 → 15/4 | s:saw velocity:0.9391485787928104 cutoff:751.3188630342484 ]",
"[ 15/4 → 31/8 | s:saw velocity:0.8121673222631216 cutoff:649.7338578104973 ]",
"[ 31/8 → 4/1 | s:saw velocity:0.7361665386706591 cutoff:588.9332309365273 ]",
]
`;
exports[`runs examples > example "release" example index 0 1`] = `
[
"[ 0/1 → 1/4 | note:c3 release:0 ]",
@@ -11726,6 +11848,75 @@ exports[`runs examples > example "sysexid" example index 0 1`] = `
]
`;
exports[`runs examples > example "tag" example index 0 1`] = `
[
"[ 0/1 → 1/16 | s:square note:F1 cutoff:40 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 1/16 → 1/8 | s:square note:F1 cutoff:41.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 1/8 → 3/16 | s:square note:F1 cutoff:42.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 3/16 → 1/4 | s:square note:F1 cutoff:43.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 1/4 → 5/16 | s:square note:F1 cutoff:45 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 5/16 → 3/8 | s:square note:F1 cutoff:46.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 3/8 → 7/16 | s:square note:F1 cutoff:47.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 7/16 → 1/2 | s:square note:F1 cutoff:48.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 1/2 → 9/16 | s:square note:F1 cutoff:50 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 9/16 → 5/8 | s:square note:F1 cutoff:51.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 5/8 → 11/16 | s:square note:F1 cutoff:52.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 11/16 → 3/4 | s:square note:F1 cutoff:53.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 3/4 → 13/16 | s:square note:F1 cutoff:55 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 13/16 → 7/8 | s:square note:F1 cutoff:56.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 7/8 → 15/16 | s:square note:F1 cutoff:57.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 15/16 → 1/1 | s:square note:F1 cutoff:58.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 1/1 → 17/16 | s:saw note:F2 cutoff:60 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 17/16 → 9/8 | s:saw note:F2 cutoff:61.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 9/8 → 19/16 | s:saw note:F2 cutoff:62.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 19/16 → 5/4 | s:saw note:F2 cutoff:63.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 5/4 → 21/16 | s:saw note:F2 cutoff:65 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 21/16 → 11/8 | s:saw note:F2 cutoff:66.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 11/8 → 23/16 | s:saw note:F2 cutoff:67.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 23/16 → 3/2 | s:saw note:F2 cutoff:68.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 3/2 → 25/16 | s:saw note:F2 cutoff:70 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 25/16 → 13/8 | s:saw note:F2 cutoff:71.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 13/8 → 27/16 | s:saw note:F2 cutoff:72.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 27/16 → 7/4 | s:saw note:F2 cutoff:73.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 7/4 → 29/16 | s:saw note:F2 cutoff:75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 29/16 → 15/8 | s:saw note:F2 cutoff:76.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 15/8 → 31/16 | s:saw note:F2 cutoff:77.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 31/16 → 2/1 | s:saw note:F2 cutoff:78.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 2/1 → 33/16 | s:saw note:F1 cutoff:80 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 33/16 → 17/8 | s:saw note:F1 cutoff:78.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 17/8 → 35/16 | s:saw note:F1 cutoff:77.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 35/16 → 9/4 | s:saw note:F1 cutoff:76.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 9/4 → 37/16 | s:saw note:F1 cutoff:75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 37/16 → 19/8 | s:saw note:F1 cutoff:73.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 19/8 → 39/16 | s:saw note:F1 cutoff:72.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 39/16 → 5/2 | s:saw note:F1 cutoff:71.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 5/2 → 41/16 | s:saw note:F1 cutoff:70 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 41/16 → 21/8 | s:saw note:F1 cutoff:68.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 21/8 → 43/16 | s:saw note:F1 cutoff:67.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 43/16 → 11/4 | s:saw note:F1 cutoff:66.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 11/4 → 45/16 | s:saw note:F1 cutoff:65 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 45/16 → 23/8 | s:saw note:F1 cutoff:63.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 23/8 → 47/16 | s:saw note:F1 cutoff:62.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 47/16 → 3/1 | s:saw note:F1 cutoff:61.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 3/1 → 49/16 | s:square note:F1 cutoff:60 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 49/16 → 25/8 | s:square note:F1 cutoff:58.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 25/8 → 51/16 | s:square note:F1 cutoff:57.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 51/16 → 13/4 | s:square note:F1 cutoff:56.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 13/4 → 53/16 | s:square note:F1 cutoff:55 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 53/16 → 27/8 | s:square note:F1 cutoff:53.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 27/8 → 55/16 | s:square note:F1 cutoff:52.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 55/16 → 7/2 | s:square note:F1 cutoff:51.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 7/2 → 57/16 | s:square note:F1 cutoff:50 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 57/16 → 29/8 | s:square note:F1 cutoff:48.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 29/8 → 59/16 | s:square note:F1 cutoff:47.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 59/16 → 15/4 | s:square note:F1 cutoff:46.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 15/4 → 61/16 | s:square note:F1 cutoff:45 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 61/16 → 31/8 | s:square note:F1 cutoff:43.75 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 31/8 → 63/16 | s:square note:F1 cutoff:42.5 lpenv:5 resonance:4 lpdecay:0.15 ]",
"[ 63/16 → 4/1 | s:square note:F1 cutoff:41.25 lpenv:5 resonance:4 lpdecay:0.15 ]",
]
`;
exports[`runs examples > example "take" example index 0 1`] = `
[
"[ 0/1 → 1/2 | s:bd ]",
@@ -11838,6 +12029,84 @@ exports[`runs examples > example "tour" example index 0 1`] = `
]
`;
exports[`runs examples > example "transient" example index 0 1`] = `
[
"[ 0/1 → 1/1 | s:bd transient:-1 ]",
"[ 1/1 → 2/1 | s:bd transient:-0.5 ]",
"[ 2/1 → 3/1 | s:bd transient:0 ]",
"[ 3/1 → 4/1 | s:bd transient:0.5 ]",
]
`;
exports[`runs examples > example "transient" example index 1 1`] = `
[
"[ 0/1 → 1/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 1/16 → 1/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 1/8 → 3/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 3/16 → 1/4 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 1/4 → 5/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 5/16 → 3/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 3/8 → 7/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 7/16 → 1/2 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 1/2 → 9/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 9/16 → 5/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 5/8 → 11/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 11/16 → 3/4 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 3/4 → 13/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 13/16 → 7/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 7/8 → 15/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 15/16 → 1/1 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 1/1 → 17/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 17/16 → 9/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 9/8 → 19/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 19/16 → 5/4 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 5/4 → 21/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 21/16 → 11/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 11/8 → 23/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 23/16 → 3/2 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 3/2 → 25/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 25/16 → 13/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 13/8 → 27/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 27/16 → 7/4 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 7/4 → 29/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 29/16 → 15/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 15/8 → 31/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 31/16 → 2/1 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 2/1 → 33/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 33/16 → 17/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 17/8 → 35/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 35/16 → 9/4 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 9/4 → 37/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 37/16 → 19/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 19/8 → 39/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 39/16 → 5/2 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 5/2 → 41/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 41/16 → 21/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 21/8 → 43/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 43/16 → 11/4 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 11/4 → 45/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 45/16 → 23/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 23/8 → 47/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 47/16 → 3/1 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
"[ 3/1 → 49/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 49/16 → 25/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 25/8 → 51/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 51/16 → 13/4 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 13/4 → 53/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 53/16 → 27/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 27/8 → 55/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 55/16 → 7/2 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 7/2 → 57/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 57/16 → 29/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 29/8 → 59/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 59/16 → 15/4 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 15/4 → 61/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 61/16 → 31/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 31/8 → 63/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
"[ 63/16 → 4/1 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
]
`;
exports[`runs examples > example "transpose" example index 0 1`] = `
[
"[ 0/1 → 1/4 | note:C2 ]",