From ec8616a51513229f06f77216d2c4bd771091980d Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 4 Sep 2023 04:56:45 +0200 Subject: [PATCH 001/175] Envelope filter and filter order --- packages/superdough/helpers.mjs | 14 ++++++++-- packages/superdough/superdough.mjs | 44 ++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 07e2b121..9ce197e1 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -66,10 +66,18 @@ export const getADSR = (attack, decay, sustain, release, velocity, begin, end) = return gainNode; }; -export const getFilter = (type, frequency, Q) => { - const filter = getAudioContext().createBiquadFilter(); +export function createFilter(context, type, frequency, Q, curve, to, over, t) { + const filter = context.createBiquadFilter(); filter.type = type; filter.frequency.value = frequency; filter.Q.value = Q; + + if (to !== null && over !== null) { + if (curve === 'lin') { + filter.frequency.linearRampToValueAtTime(to, t + over); + } else { + filter.frequency.exponentialRampToValueAtTime(to, t + over); + } + } return filter; -}; +} diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index af22355f..cf3c231e 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -9,7 +9,7 @@ import './reverb.mjs'; import './vowel.mjs'; import { clamp } from './util.mjs'; import workletsUrl from './worklets.mjs?url'; -import { getFilter, gainNode } from './helpers.mjs'; +import { createFilter, gainNode } from './helpers.mjs'; import { map } from 'nanostores'; import { logger } from './logger.mjs'; @@ -177,6 +177,11 @@ export const superdough = async (value, deadline, hapDuration) => { bank, source, gain = 0.8, + // filters + order = 12, + to, + filtenv = 'lin', + over, // low pass cutoff, resonance = 1, @@ -239,11 +244,37 @@ export const superdough = async (value, deadline, hapDuration) => { // gain stage chain.push(gainNode(gain)); - // filters - cutoff !== undefined && chain.push(getFilter('lowpass', cutoff, resonance)); - hcutoff !== undefined && chain.push(getFilter('highpass', hcutoff, hresonance)); - bandf !== undefined && chain.push(getFilter('bandpass', bandf, bandq)); - vowel !== undefined && chain.push(ac.createVowelFilter(vowel)); + if (cutoff !== undefined) { + const filter1 = createFilter(ac, 'lowpass', cutoff, resonance, filtenv, to || cutoff, over || hapDuration, t); + chain.push(filter1); + if (order === 24) { + const filter2 = createFilter(ac, 'lowpass', cutoff, resonance, filtenv, to || cutoff, over || hapDuration, t); + chain.push(filter2); + } + } + + if (hcutoff !== undefined) { + const filter1 = createFilter(ac, 'highpass', hcutoff, hresonance, filtenv, to || hcutoff, over || hapDuration, t); + chain.push(filter1); + if (order === 24) { + const filter2 = createFilter(ac, 'highpass', hcutoff, hresonance, filtenv, to || hcutoff, over || hapDuration, t); + chain.push(filter2); + } + } + + if (bandf !== undefined) { + const filter1 = createFilter(ac, 'bandpass', bandf, bandq, filtenv, to || bandf, over || hapDuration, t); + chain.push(filter1); + if (order === 24) { + const filter2 = createFilter(ac, 'bandpass', bandf, bandq, filtenv, to || bandf, over || hapDuration, t); + chain.push(filter2); + } + } + + if (vowel !== undefined) { + const vowelFilter = ac.createVowelFilter(vowel); + chain.push(vowelFilter); + } // effects coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse })); @@ -282,6 +313,7 @@ export const superdough = async (value, deadline, hapDuration) => { analyserSend = effectSend(post, analyserNode, analyze); } + console.log(chain); // connect chain elements together chain.slice(1).reduce((last, current) => last.connect(current), chain[0]); From fdc201a799b841d4e2be20466fdeb56ae3c8c7d6 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 4 Sep 2023 06:03:05 +0200 Subject: [PATCH 002/175] Adding vibrato to synth oscillator --- packages/superdough/synth.mjs | 43 ++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index a409d990..b216a427 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -40,6 +40,8 @@ export function registerSynthSounds() { fmrelease: fmRelease, fmvelocity: fmVelocity, fmwave: fmWaveform = 'sine', + vibrato = 0, + vdepth = 100, } = value; let { n, note, freq } = value; // with synths, n and note are the same thing @@ -53,7 +55,7 @@ export function registerSynthSounds() { } // maybe pull out the above frequency resolution?? (there is also getFrequency but it has no default) // make oscillator - const { node: o, stop } = getOscillator({ t, s: wave, freq, partials: n }); + const { node: o, stop } = getOscillator({ t, s: wave, freq, vibrato, vdepth, partials: n }); // FM + FM envelope let stopFm, fmEnvelope; @@ -137,8 +139,14 @@ export function waveformN(partials, type) { return osc; } -export function getOscillator({ s, freq, t, partials }) { - // make oscillator +export function getOscillator({ s, freq, t, vibrato, vdepth, partials }) { + // Additional oscillator for vibrato effect + if (vibrato > 0) { + var vibrato_oscillator = getAudioContext().createOscillator(); + vibrato_oscillator.frequency.value = vibrato; + } + + // Make oscillator with partial count let o; if (!partials || s === 'sine') { o = getAudioContext().createOscillator(); @@ -146,9 +154,28 @@ export function getOscillator({ s, freq, t, partials }) { } else { o = waveformN(partials, s); } - o.frequency.value = Number(freq); - o.start(t); - //o.stop(t + duration + release); - const stop = (time) => o.stop(time); - return { node: o, stop }; + + if (vibrato > 0) { + // Vibrato by creating a gain node + o.frequency.value = Number(freq); + var gain = getAudioContext().createGain(); + gain.gain.value = vdepth * 100; + vibrato_oscillator.connect(gain); + gain.connect(o.detune); + vibrato_oscillator.start(t); + o.start(t); + return { + node: o, + stop: (time) => { + vibrato_oscillator.stop(time); + o.stop(time); + }, + }; + } else { + // Normal operation, without vibrato + o.frequency.value = Number(freq); + o.start(t); + const stop = (time) => o.stop(time); + return { node: o, stop }; + } } From 60f5032b1270084efa5185f4560e8c70da24e3a9 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 4 Sep 2023 06:25:49 +0200 Subject: [PATCH 003/175] Implement pitch slide --- packages/superdough/synth.mjs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index b216a427..e1d7905c 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -42,6 +42,8 @@ export function registerSynthSounds() { fmwave: fmWaveform = 'sine', vibrato = 0, vdepth = 100, + slide, + slide_speed = 1, } = value; let { n, note, freq } = value; // with synths, n and note are the same thing @@ -55,7 +57,16 @@ export function registerSynthSounds() { } // maybe pull out the above frequency resolution?? (there is also getFrequency but it has no default) // make oscillator - const { node: o, stop } = getOscillator({ t, s: wave, freq, vibrato, vdepth, partials: n }); + const { node: o, stop } = getOscillator({ + t, + s: wave, + freq, + vibrato, + vdepth, + slide: slide * freq, + slide_speed: sustain / slide_speed, + partials: n, + }); // FM + FM envelope let stopFm, fmEnvelope; @@ -139,7 +150,7 @@ export function waveformN(partials, type) { return osc; } -export function getOscillator({ s, freq, t, vibrato, vdepth, partials }) { +export function getOscillator({ s, freq, t, vibrato, vdepth, slide, slide_speed, partials }) { // Additional oscillator for vibrato effect if (vibrato > 0) { var vibrato_oscillator = getAudioContext().createOscillator(); @@ -156,8 +167,8 @@ export function getOscillator({ s, freq, t, vibrato, vdepth, partials }) { } if (vibrato > 0) { - // Vibrato by creating a gain node o.frequency.value = Number(freq); + slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slide_speed); var gain = getAudioContext().createGain(); gain.gain.value = vdepth * 100; vibrato_oscillator.connect(gain); @@ -174,6 +185,7 @@ export function getOscillator({ s, freq, t, vibrato, vdepth, partials }) { } else { // Normal operation, without vibrato o.frequency.value = Number(freq); + slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slide_speed); o.start(t); const stop = (time) => o.stop(time); return { node: o, stop }; From 3ba195c2d91af5cfe5675e0e8b00f3f242af688c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 4 Sep 2023 18:38:05 +0200 Subject: [PATCH 004/175] add new controls + rename slide_speed > slidespeed --- packages/core/controls.mjs | 3 +++ packages/superdough/synth.mjs | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 71f58427..36a5728b 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -664,7 +664,10 @@ const generic_params = [ // TODO: LFO rate see https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare ['rate'], // TODO: slide param for certain synths + ['vibrato'], + ['vdepth'], ['slide'], + ['slidespeed'], // TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare ['semitone'], // TODO: dedup with synth param, see https://tidalcycles.org/docs/reference/synthesizers/#superpiano diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index e1d7905c..4ebfb3ac 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -43,7 +43,7 @@ export function registerSynthSounds() { vibrato = 0, vdepth = 100, slide, - slide_speed = 1, + slidespeed = 1, } = value; let { n, note, freq } = value; // with synths, n and note are the same thing @@ -64,7 +64,7 @@ export function registerSynthSounds() { vibrato, vdepth, slide: slide * freq, - slide_speed: sustain / slide_speed, + slidespeed: sustain / slidespeed, partials: n, }); @@ -150,7 +150,7 @@ export function waveformN(partials, type) { return osc; } -export function getOscillator({ s, freq, t, vibrato, vdepth, slide, slide_speed, partials }) { +export function getOscillator({ s, freq, t, vibrato, vdepth, slide, slidespeed, partials }) { // Additional oscillator for vibrato effect if (vibrato > 0) { var vibrato_oscillator = getAudioContext().createOscillator(); @@ -168,7 +168,7 @@ export function getOscillator({ s, freq, t, vibrato, vdepth, slide, slide_speed, if (vibrato > 0) { o.frequency.value = Number(freq); - slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slide_speed); + slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slidespeed); var gain = getAudioContext().createGain(); gain.gain.value = vdepth * 100; vibrato_oscillator.connect(gain); @@ -185,7 +185,7 @@ export function getOscillator({ s, freq, t, vibrato, vdepth, slide, slide_speed, } else { // Normal operation, without vibrato o.frequency.value = Number(freq); - slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slide_speed); + slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slidespeed); o.start(t); const stop = (time) => o.stop(time); return { node: o, stop }; From 5be78985227ede43217fd848f44c3ea2e19e5e88 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 4 Sep 2023 21:17:16 +0200 Subject: [PATCH 005/175] New technique using ADSR envelope --- packages/superdough/helpers.mjs | 16 ++++--- packages/superdough/superdough.mjs | 76 +++++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 20 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 9ce197e1..4fda54eb 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -66,18 +66,20 @@ export const getADSR = (attack, decay, sustain, release, velocity, begin, end) = return gainNode; }; -export function createFilter(context, type, frequency, Q, curve, to, over, t) { +export function createFilter(context, type, frequency, Q, attack, decay, sustain, release, fenvmod, t) { const filter = context.createBiquadFilter(); filter.type = type; filter.frequency.value = frequency; filter.Q.value = Q; - if (to !== null && over !== null) { - if (curve === 'lin') { - filter.frequency.linearRampToValueAtTime(to, t + over); - } else { - filter.frequency.exponentialRampToValueAtTime(to, t + over); - } + // Apply ADSR to filter frequency + if (fenvmod > 0) { + const sustainFreq = sustain * frequency; + filter.frequency.linearRampToValueAtTime(frequency * fenvmod, t + attack); + filter.frequency.linearRampToValueAtTime(sustainFreq, t + attack + decay); + filter.frequency.setValueAtTime(sustainFreq, end); + filter.frequency.linearRampToValueAtTime(frequency, end + release); } + return filter; } diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index cf3c231e..6605662a 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -178,18 +178,32 @@ export const superdough = async (value, deadline, hapDuration) => { source, gain = 0.8, // filters - order = 12, - to, - filtenv = 'lin', - over, + order = '12db', + fenvmod = 2, // low pass + lpattack, + lpdecay, + lpsustain, + lprelease, cutoff, resonance = 1, // high pass + hpattack, + hpdecay, + hpsustain, + hprelease, hcutoff, hresonance = 1, + // full adsr for filter + lpadsr, + hpadsr, + bpadsr, // band pass bandf, + bpattack, + bpdecay, + bpsustain, + bprelease, bandq = 1, // coarse, @@ -215,6 +229,9 @@ export const superdough = async (value, deadline, hapDuration) => { if (bank && s) { s = `${bank}_${s}`; } + lpadsr && (lpattack = lpadsr[0]) && (lpdecay = lpadsr[1]) && (lpsustain = lpadsr[2]) && (lprelease = lpadsr[3]); + bpadsr && (bpattack = bpadsr[0]) && (bpdecay = bpadsr[1]) && (bpsustain = bpadsr[2]) && (bprelease = bpadsr[3]); + hpadsr && (hpattack = hpadsr[0]) && (hpdecay = hpadsr[1]) && (hpsustain = hpadsr[2]) && (hprelease = hpadsr[3]); // get source AudioNode let sourceNode; if (source) { @@ -245,28 +262,61 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(gainNode(gain)); if (cutoff !== undefined) { - const filter1 = createFilter(ac, 'lowpass', cutoff, resonance, filtenv, to || cutoff, over || hapDuration, t); + const filter1 = createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, fmodenv, t); chain.push(filter1); - if (order === 24) { - const filter2 = createFilter(ac, 'lowpass', cutoff, resonance, filtenv, to || cutoff, over || hapDuration, t); + if (order === '24db') { + const filter2 = createFilter( + ac, + 'lowpass', + cutoff, + resonance, + lpattack, + lpdecay, + lpsustain, + lprelease, + fmodenv, + t, + ); chain.push(filter2); } } if (hcutoff !== undefined) { - const filter1 = createFilter(ac, 'highpass', hcutoff, hresonance, filtenv, to || hcutoff, over || hapDuration, t); + const filter1 = createFilter( + ac, + 'highpass', + hcutoff, + hresonance, + hpattack, + hpdecay, + hpsustain, + hprelease, + fenvmod, + t, + ); chain.push(filter1); - if (order === 24) { - const filter2 = createFilter(ac, 'highpass', hcutoff, hresonance, filtenv, to || hcutoff, over || hapDuration, t); + if (order === '24db') { + const filter2 = createFilter( + ac, + 'highpass', + hcutoff, + hresonance, + hpattack, + hpdecay, + hpsustain, + hprelease, + fenvmod, + t, + ); chain.push(filter2); } } if (bandf !== undefined) { - const filter1 = createFilter(ac, 'bandpass', bandf, bandq, filtenv, to || bandf, over || hapDuration, t); + const filter1 = createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, fenvmod, t); chain.push(filter1); - if (order === 24) { - const filter2 = createFilter(ac, 'bandpass', bandf, bandq, filtenv, to || bandf, over || hapDuration, t); + if (order === '24db') { + const filter2 = createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, fenvmod, t); chain.push(filter2); } } From 4319df0cb62b8ac3964a5dcfcf612b00532247c7 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 4 Sep 2023 21:24:42 +0200 Subject: [PATCH 006/175] replace odd envelope --- packages/superdough/helpers.mjs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 4fda54eb..22f84048 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -74,11 +74,8 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain // Apply ADSR to filter frequency if (fenvmod > 0) { - const sustainFreq = sustain * frequency; - filter.frequency.linearRampToValueAtTime(frequency * fenvmod, t + attack); - filter.frequency.linearRampToValueAtTime(sustainFreq, t + attack + decay); - filter.frequency.setValueAtTime(sustainFreq, end); - filter.frequency.linearRampToValueAtTime(frequency, end + release); + const gainNode = getADSR(attack, decay, sustain, release, fenvmod, t, t + attack + decay + release); + gainNode.connect(filter.frequency); } return filter; From 37842d4fbde955bbf9f4c3594da6e12351f51938 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Tue, 5 Sep 2023 09:01:04 +0200 Subject: [PATCH 007/175] Revert "replace odd envelope" This reverts commit 4319df0cb62b8ac3964a5dcfcf612b00532247c7. --- packages/superdough/helpers.mjs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 22f84048..4fda54eb 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -74,8 +74,11 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain // Apply ADSR to filter frequency if (fenvmod > 0) { - const gainNode = getADSR(attack, decay, sustain, release, fenvmod, t, t + attack + decay + release); - gainNode.connect(filter.frequency); + const sustainFreq = sustain * frequency; + filter.frequency.linearRampToValueAtTime(frequency * fenvmod, t + attack); + filter.frequency.linearRampToValueAtTime(sustainFreq, t + attack + decay); + filter.frequency.setValueAtTime(sustainFreq, end); + filter.frequency.linearRampToValueAtTime(frequency, end + release); } return filter; From 16c8dcf788dc18246e276937926208808e6cd1b3 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Tue, 5 Sep 2023 09:56:49 +0200 Subject: [PATCH 008/175] stable version --- packages/superdough/helpers.mjs | 28 +++++++++--- packages/superdough/superdough.mjs | 68 ++++++++++-------------------- 2 files changed, 44 insertions(+), 52 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 4fda54eb..f28fcfae 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -66,19 +66,33 @@ export const getADSR = (attack, decay, sustain, release, velocity, begin, end) = return gainNode; }; -export function createFilter(context, type, frequency, Q, attack, decay, sustain, release, fenvmod, t) { +export const getParamADSR = (param, attack, decay, sustain, release, velocity, begin, end) => { + param.setValueAtTime(0, begin); + param.linearRampToValueAtTime(velocity, begin + attack); + param.linearRampToValueAtTime(sustain * velocity, begin + attack + decay); + param.setValueAtTime(sustain * velocity, end); + param.linearRampToValueAtTime(0, end + release - 0.1); +}; + +export function createFilter(context, type, frequency, Q, attack, decay, sustain, release, fenv, t) { const filter = context.createBiquadFilter(); filter.type = type; filter.frequency.value = frequency; filter.Q.value = Q; // Apply ADSR to filter frequency - if (fenvmod > 0) { - const sustainFreq = sustain * frequency; - filter.frequency.linearRampToValueAtTime(frequency * fenvmod, t + attack); - filter.frequency.linearRampToValueAtTime(sustainFreq, t + attack + decay); - filter.frequency.setValueAtTime(sustainFreq, end); - filter.frequency.linearRampToValueAtTime(frequency, end + release); + if (fenv > 0) { + const envelope = getParamADSR( + filter.frequency, + attack, + decay, + sustain, + release, + frequency * fenv > 22000 ? 22000 : frequency * fenv, + t, + t + attack + decay + release, + ); + return filter; } return filter; diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 6605662a..b5c55b0a 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -179,32 +179,32 @@ export const superdough = async (value, deadline, hapDuration) => { gain = 0.8, // filters order = '12db', - fenvmod = 2, + fenv, // low pass - lpattack, - lpdecay, - lpsustain, - lprelease, cutoff, + lpattack = 0.01, + lpdecay = 0.5, + lpsustain = 0.6, + lprelease = 0.01, resonance = 1, // high pass - hpattack, - hpdecay, - hpsustain, - hprelease, hcutoff, + hpattack = 0.01, + hpdecay = 0.5, + hpsustain = 0.6, + hprelease = 0.01, hresonance = 1, + // band pass + bandf, + bpattack = 0.01, + bpdecay = 0.5, + bpsustain = 0.6, + bprelease = 0.01, + bandq = 1, // full adsr for filter lpadsr, hpadsr, bpadsr, - // band pass - bandf, - bpattack, - bpdecay, - bpsustain, - bprelease, - bandq = 1, // coarse, crush, @@ -230,8 +230,8 @@ export const superdough = async (value, deadline, hapDuration) => { s = `${bank}_${s}`; } lpadsr && (lpattack = lpadsr[0]) && (lpdecay = lpadsr[1]) && (lpsustain = lpadsr[2]) && (lprelease = lpadsr[3]); - bpadsr && (bpattack = bpadsr[0]) && (bpdecay = bpadsr[1]) && (bpsustain = bpadsr[2]) && (bprelease = bpadsr[3]); hpadsr && (hpattack = hpadsr[0]) && (hpdecay = hpadsr[1]) && (hpsustain = hpadsr[2]) && (hprelease = hpadsr[3]); + bpadsr && (bpattack = bpadsr[0]) && (bpdecay = bpadsr[1]) && (bpsustain = bpadsr[2]) && (bprelease = bpadsr[3]); // get source AudioNode let sourceNode; if (source) { @@ -262,38 +262,16 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(gainNode(gain)); if (cutoff !== undefined) { - const filter1 = createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, fmodenv, t); + const filter1 = createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, fenv, t); chain.push(filter1); if (order === '24db') { - const filter2 = createFilter( - ac, - 'lowpass', - cutoff, - resonance, - lpattack, - lpdecay, - lpsustain, - lprelease, - fmodenv, - t, - ); + const filter2 = createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, fenv, t); chain.push(filter2); } } if (hcutoff !== undefined) { - const filter1 = createFilter( - ac, - 'highpass', - hcutoff, - hresonance, - hpattack, - hpdecay, - hpsustain, - hprelease, - fenvmod, - t, - ); + const filter1 = createFilter(ac, 'highpass', hcutoff, hresonance, hpattack, hpdecay, hpsustain, hprelease, fenv, t); chain.push(filter1); if (order === '24db') { const filter2 = createFilter( @@ -305,7 +283,7 @@ export const superdough = async (value, deadline, hapDuration) => { hpdecay, hpsustain, hprelease, - fenvmod, + fenv, t, ); chain.push(filter2); @@ -313,10 +291,10 @@ export const superdough = async (value, deadline, hapDuration) => { } if (bandf !== undefined) { - const filter1 = createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, fenvmod, t); + const filter1 = createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, fenv, t); chain.push(filter1); if (order === '24db') { - const filter2 = createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, fenvmod, t); + const filter2 = createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, fenv, t); chain.push(filter2); } } From e597b6473d47c3914964b66097c0367b1eda4536 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Tue, 5 Sep 2023 10:44:41 +0200 Subject: [PATCH 009/175] remove test console log statement --- packages/superdough/superdough.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index b5c55b0a..8e4a0148 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -341,7 +341,6 @@ export const superdough = async (value, deadline, hapDuration) => { analyserSend = effectSend(post, analyserNode, analyze); } - console.log(chain); // connect chain elements together chain.slice(1).reduce((last, current) => last.connect(current), chain[0]); From fc9525e7d80f1a23332c7271c043dcd08be58ea9 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Tue, 5 Sep 2023 11:24:21 +0200 Subject: [PATCH 010/175] saner vibrato default --- packages/core/controls.mjs | 2 ++ packages/superdough/synth.mjs | 27 ++++++++++++++------------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 36a5728b..c2cf917e 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -393,6 +393,8 @@ const generic_params = [ */ // currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496 // ['hpf'], + [['vib'], 'vib'], + [['vibmod'], 'vibmod'], [['hcutoff', 'hresonance'], 'hpf', 'hp'], /** * Controls the **h**igh-**p**ass **q**-value. diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 4ebfb3ac..f02a1909 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -40,10 +40,10 @@ export function registerSynthSounds() { fmrelease: fmRelease, fmvelocity: fmVelocity, fmwave: fmWaveform = 'sine', - vibrato = 0, - vdepth = 100, + vib = 0, + vibmod = 1, slide, - slidespeed = 1, + slide_speed = 1, } = value; let { n, note, freq } = value; // with synths, n and note are the same thing @@ -61,10 +61,10 @@ export function registerSynthSounds() { t, s: wave, freq, - vibrato, - vdepth, + vib, + vibmod, slide: slide * freq, - slidespeed: sustain / slidespeed, + slide_speed: sustain / slide_speed, partials: n, }); @@ -150,11 +150,11 @@ export function waveformN(partials, type) { return osc; } -export function getOscillator({ s, freq, t, vibrato, vdepth, slide, slidespeed, partials }) { +export function getOscillator({ s, freq, t, vib, vibmod, slide, slide_speed, partials }) { // Additional oscillator for vibrato effect - if (vibrato > 0) { + if (vib > 0) { var vibrato_oscillator = getAudioContext().createOscillator(); - vibrato_oscillator.frequency.value = vibrato; + vibrato_oscillator.frequency.value = vib; } // Make oscillator with partial count @@ -166,11 +166,12 @@ export function getOscillator({ s, freq, t, vibrato, vdepth, slide, slidespeed, o = waveformN(partials, s); } - if (vibrato > 0) { + if (vib > 0) { o.frequency.value = Number(freq); - slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slidespeed); + slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slide_speed); var gain = getAudioContext().createGain(); - gain.gain.value = vdepth * 100; + // Vibmod is the amount of vibrato, in semitones + gain.gain.value = vibmod * freq; vibrato_oscillator.connect(gain); gain.connect(o.detune); vibrato_oscillator.start(t); @@ -185,7 +186,7 @@ export function getOscillator({ s, freq, t, vibrato, vdepth, slide, slidespeed, } else { // Normal operation, without vibrato o.frequency.value = Number(freq); - slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slidespeed); + slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slide_speed); o.start(t); const stop = (time) => o.stop(time); return { node: o, stop }; From 76051987742f2703c78fab3378fb9e6490cc65d1 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Tue, 5 Sep 2023 11:27:42 +0200 Subject: [PATCH 011/175] parameter renaming --- packages/superdough/synth.mjs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index f02a1909..4101aaee 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -42,8 +42,8 @@ export function registerSynthSounds() { fmwave: fmWaveform = 'sine', vib = 0, vibmod = 1, - slide, - slide_speed = 1, + pitchJump, + pitchJumpSpeed = 1, } = value; let { n, note, freq } = value; // with synths, n and note are the same thing @@ -63,8 +63,8 @@ export function registerSynthSounds() { freq, vib, vibmod, - slide: slide * freq, - slide_speed: sustain / slide_speed, + pitchJump: pitchJump * freq, + pitchJumpSpeed: sustain / pitchJumpSpeed, partials: n, }); @@ -150,7 +150,7 @@ export function waveformN(partials, type) { return osc; } -export function getOscillator({ s, freq, t, vib, vibmod, slide, slide_speed, partials }) { +export function getOscillator({ s, freq, t, vib, vibmod, pitchJump, pitchJumpSpeed, partials }) { // Additional oscillator for vibrato effect if (vib > 0) { var vibrato_oscillator = getAudioContext().createOscillator(); @@ -168,7 +168,7 @@ export function getOscillator({ s, freq, t, vib, vibmod, slide, slide_speed, par if (vib > 0) { o.frequency.value = Number(freq); - slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slide_speed); + slide > 0 && o.frequency.linearRampToValueAtTime(freq + pitchJump, t + pitchJumpSpeed); var gain = getAudioContext().createGain(); // Vibmod is the amount of vibrato, in semitones gain.gain.value = vibmod * freq; From e2711ba911c2faffc70d04527b8c69134db813f3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 8 Sep 2023 01:40:10 +0200 Subject: [PATCH 012/175] fix: filter envelopes + simplify --- packages/superdough/helpers.mjs | 16 +++++++------- packages/superdough/superdough.mjs | 35 +++++++++++++----------------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index f28fcfae..15c81522 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -66,15 +66,15 @@ export const getADSR = (attack, decay, sustain, release, velocity, begin, end) = return gainNode; }; -export const getParamADSR = (param, attack, decay, sustain, release, velocity, begin, end) => { +export const getParamADSR = (param, attack, decay, sustain, release, max, begin, end) => { param.setValueAtTime(0, begin); - param.linearRampToValueAtTime(velocity, begin + attack); - param.linearRampToValueAtTime(sustain * velocity, begin + attack + decay); - param.setValueAtTime(sustain * velocity, end); - param.linearRampToValueAtTime(0, end + release - 0.1); + param.linearRampToValueAtTime(max, begin + attack); + param.linearRampToValueAtTime(sustain * max, begin + attack + decay); + param.setValueAtTime(sustain * max, end); + param.linearRampToValueAtTime(0, end + release); }; -export function createFilter(context, type, frequency, Q, attack, decay, sustain, release, fenv, t) { +export function createFilter(context, type, frequency, Q, attack, decay, sustain, release, fenv, start, end) { const filter = context.createBiquadFilter(); filter.type = type; filter.frequency.value = frequency; @@ -89,8 +89,8 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain sustain, release, frequency * fenv > 22000 ? 22000 : frequency * fenv, - t, - t + attack + decay + release, + start, + end + release, ); return filter; } diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 8e4a0148..cddddbb4 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -201,10 +201,6 @@ export const superdough = async (value, deadline, hapDuration) => { bpsustain = 0.6, bprelease = 0.01, bandq = 1, - // full adsr for filter - lpadsr, - hpadsr, - bpadsr, // coarse, crush, @@ -229,9 +225,6 @@ export const superdough = async (value, deadline, hapDuration) => { if (bank && s) { s = `${bank}_${s}`; } - lpadsr && (lpattack = lpadsr[0]) && (lpdecay = lpadsr[1]) && (lpsustain = lpadsr[2]) && (lprelease = lpadsr[3]); - hpadsr && (hpattack = hpadsr[0]) && (hpdecay = hpadsr[1]) && (hpsustain = hpadsr[2]) && (hprelease = hpadsr[3]); - bpadsr && (bpattack = bpadsr[0]) && (bpdecay = bpadsr[1]) && (bpsustain = bpadsr[2]) && (bprelease = bpadsr[3]); // get source AudioNode let sourceNode; if (source) { @@ -262,19 +255,18 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(gainNode(gain)); if (cutoff !== undefined) { - const filter1 = createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, fenv, t); - chain.push(filter1); + console.log('lpattack', lpattack); + let lp = () => + createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, fenv, t, t + hapDuration); + chain.push(lp()); if (order === '24db') { - const filter2 = createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, fenv, t); - chain.push(filter2); + chain.push(lp()); } } if (hcutoff !== undefined) { - const filter1 = createFilter(ac, 'highpass', hcutoff, hresonance, hpattack, hpdecay, hpsustain, hprelease, fenv, t); - chain.push(filter1); - if (order === '24db') { - const filter2 = createFilter( + let hp = () => + createFilter( ac, 'highpass', hcutoff, @@ -285,17 +277,20 @@ export const superdough = async (value, deadline, hapDuration) => { hprelease, fenv, t, + t + hapDuration, ); - chain.push(filter2); + chain.push(hp()); + if (order === '24db') { + chain.push(hp()); } } if (bandf !== undefined) { - const filter1 = createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, fenv, t); - chain.push(filter1); + let bp = () => + createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, fenv, t, t + hapDuration); + chain.push(bp()); if (order === '24db') { - const filter2 = createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, fenv, t); - chain.push(filter2); + chain.push(bp()); } } From 75a974643b16cb37541a577a3263b8038da70de4 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 8 Sep 2023 01:41:11 +0200 Subject: [PATCH 013/175] add missing controls --- packages/core/controls.mjs | 13 +++++++++++++ packages/superdough/superdough.mjs | 1 - 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 71f58427..ce08fc68 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -377,6 +377,19 @@ const generic_params = [ * */ [['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'], + ['fenv'], + ['lpattack', 'lpa'], + ['lpdecay', 'lpd'], + ['lpsustain', 'lps'], + ['lprelease', 'lpr'], + ['hpattack', 'hpa'], + ['hpdecay', 'hpd'], + ['hpsustain', 'hps'], + ['hprelease', 'hpr'], + ['bpattack', 'bpa'], + ['bpdecay', 'bpd'], + ['bpsustain', 'bps'], + ['bprelease', 'bpr'], /** * Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter. * diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index cddddbb4..f17c277e 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -255,7 +255,6 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(gainNode(gain)); if (cutoff !== undefined) { - console.log('lpattack', lpattack); let lp = () => createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, fenv, t, t + hapDuration); chain.push(lp()); From 9e4c548c694d0f6e7cb564bd93916549e2f4df21 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 8 Sep 2023 02:06:03 +0200 Subject: [PATCH 014/175] fix: filter clicks --- packages/superdough/helpers.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 15c81522..a1a0f708 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -77,7 +77,6 @@ export const getParamADSR = (param, attack, decay, sustain, release, max, begin, export function createFilter(context, type, frequency, Q, attack, decay, sustain, release, fenv, start, end) { const filter = context.createBiquadFilter(); filter.type = type; - filter.frequency.value = frequency; filter.Q.value = Q; // Apply ADSR to filter frequency @@ -88,11 +87,13 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain decay, sustain, release, - frequency * fenv > 22000 ? 22000 : frequency * fenv, + Math.min(frequency * fenv, 20000), start, end + release, ); return filter; + } else { + filter.frequency.value = frequency; } return filter; From 606dcc8cc3c952812ba1783f757ceccf6c73334c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 8 Sep 2023 02:27:28 +0200 Subject: [PATCH 015/175] use fenv to scale above base cutoff? --- packages/superdough/helpers.mjs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index a1a0f708..12c6f08c 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -66,12 +66,13 @@ export const getADSR = (attack, decay, sustain, release, velocity, begin, end) = return gainNode; }; -export const getParamADSR = (param, attack, decay, sustain, release, max, begin, end) => { - param.setValueAtTime(0, begin); - param.linearRampToValueAtTime(max, begin + attack); - param.linearRampToValueAtTime(sustain * max, begin + attack + decay); - param.setValueAtTime(sustain * max, end); - param.linearRampToValueAtTime(0, end + release); +export const getParamADSR = (param, attack, decay, sustain, release, min, max, begin, end) => { + const range = max - min; + param.setValueAtTime(min, begin); + param.linearRampToValueAtTime(min + range, begin + attack); + param.linearRampToValueAtTime(min + sustain * range, begin + attack + decay); + param.setValueAtTime(min + sustain * range, end); + param.linearRampToValueAtTime(min, end + release); }; export function createFilter(context, type, frequency, Q, attack, decay, sustain, release, fenv, start, end) { @@ -87,7 +88,8 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain decay, sustain, release, - Math.min(frequency * fenv, 20000), + frequency, + Math.min(frequency + 200 * 2 ** fenv, 20000), start, end + release, ); From 48753b2539bb756a51ca43221ffa02954cd69cd9 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 8 Sep 2023 02:53:08 +0200 Subject: [PATCH 016/175] fix last crack? --- packages/superdough/helpers.mjs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 12c6f08c..d58f2355 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -68,10 +68,12 @@ export const getADSR = (attack, decay, sustain, release, velocity, begin, end) = export const getParamADSR = (param, attack, decay, sustain, release, min, max, begin, end) => { const range = max - min; + const peak = min + range; + const sustainLevel = min + sustain * range; param.setValueAtTime(min, begin); - param.linearRampToValueAtTime(min + range, begin + attack); - param.linearRampToValueAtTime(min + sustain * range, begin + attack + decay); - param.setValueAtTime(min + sustain * range, end); + param.linearRampToValueAtTime(peak, begin + attack); + param.linearRampToValueAtTime(sustainLevel, begin + attack + decay); + param.setValueAtTime(sustainLevel, end); param.linearRampToValueAtTime(min, end + release); }; @@ -79,23 +81,15 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain const filter = context.createBiquadFilter(); filter.type = type; filter.Q.value = Q; + frequency = Math.max(frequency, 20); + filter.frequency.value = frequency; // Apply ADSR to filter frequency if (fenv > 0) { - const envelope = getParamADSR( - filter.frequency, - attack, - decay, - sustain, - release, - frequency, - Math.min(frequency + 200 * 2 ** fenv, 20000), - start, - end + release, - ); + const min = frequency; + const max = Math.min(frequency + 200 * 2 ** fenv, 20000); + getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end); return filter; - } else { - filter.frequency.value = frequency; } return filter; From 18640d59daca002cc8260f46cffcb9915bcc40aa Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 8 Sep 2023 03:00:49 +0200 Subject: [PATCH 017/175] acid party --- packages/core/controls.mjs | 1 + packages/superdough/helpers.mjs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index ce08fc68..268638cb 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -390,6 +390,7 @@ const generic_params = [ ['bpdecay', 'bpd'], ['bpsustain', 'bps'], ['bprelease', 'bpr'], + ['order'], /** * Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter. * diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index d58f2355..45162a36 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -74,7 +74,7 @@ export const getParamADSR = (param, attack, decay, sustain, release, min, max, b param.linearRampToValueAtTime(peak, begin + attack); param.linearRampToValueAtTime(sustainLevel, begin + attack + decay); param.setValueAtTime(sustainLevel, end); - param.linearRampToValueAtTime(min, end + release); + param.linearRampToValueAtTime(min, end + Math.max(release, 0.1)); }; export function createFilter(context, type, frequency, Q, attack, decay, sustain, release, fenv, start, end) { From c5fb247de6dd7440fea1cfbf00922c5598040d97 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Fri, 8 Sep 2023 12:38:39 +0200 Subject: [PATCH 018/175] Documentation for filter envelope --- packages/core/controls.mjs | 51 +++++++++++++++++++++++++++++ website/src/pages/learn/effects.mdx | 41 +++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 268638cb..84b7526d 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -377,10 +377,61 @@ const generic_params = [ * */ [['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'], + + /** + * Sets the filter envelope modulation depth. + * @name fenv + * @param {number | Pattern} modulation depth of the filter envelope between 0 and _n_ + * @example + * note("c2 c3").fast(2).sound("sawtooth") + * .cutoff(500).fenv("<1 2 3 4 5 6 7 8>") + */ ['fenv'], + /** + * Sets the attack duration for the lowpass filter envelope. + * @name lpattack + * @param {number | Pattern} attack time of the filter envelope + * @synonyms lpa + * @example + * note("c3 e3 f3 g3 ab3 bb3") + * .sound('square').cutoff(1000) + * .lpattack("<0.05 0.1 0.25 0.5>/2").fenv(1) + * .release(0.2).attack(0) + */ ['lpattack', 'lpa'], + /** + * Sets the decay duration for the lowpass filter envelope. + * @name lpdecay + * @param {number | Pattern} decay time of the filter envelope + * @synonyms lpd + * @example + * "baba" + * note("c3 e3 f3 g3 ab3 bb3") + * .sound('square').cutoff(1000) + * .lpdecay("<0.05 0.1 0.125>/2") + * .fenv("4").lps(0).lpr(0) + */ ['lpdecay', 'lpd'], + /** + * Sets the sustain amplitude for the lowpass filter envelope. + * @name lpsustain + * @param {number | Pattern} sustain amplitude of the filter envelope + * @synonyms lps + * @example + * note("c3 e3 f3 g3 ab3 bb3") + * .sound('square').cutoff(200) + * .lpd(0.1).lpsustain("<0.1 0.5 0.75 1>") + * .fenv("2") + */ ['lpsustain', 'lps'], + /** + * Sets the release time for the lowpass filter envelope. + * @name lprelease + * @param {number | Pattern} release time of the filter envelope + * @synonyms lpr + * @example + * note("c3 e3 g3 c4").lpr("<0.1 0.25 0.5>").fenv(0.5) + */ ['lprelease', 'lpr'], ['hpattack', 'hpa'], ['hpdecay', 'hpd'], diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index 12e57846..31562f98 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -78,6 +78,47 @@ Strudel uses ADSR envelopes, which are probably the most common way to describe +# Filter Envelope + +Each filter can receive an additional filter envelope controlling the cutoff value dynamically. It uses an ADSR envelope similar to the one used for amplitude. There is an additional parameter to control the depth of the filter modulation: `fenv`. This allows you to play subtle or huge filter modulations just the same by only increasing or decreasing the depth. + +There is one filter envelope for each filter type and thus one set of envelope filter parameters preceded either by `lp`, `hp` or `bp`: + +- `lpattack`, `lpdecay`, `lpsustain`, `lprelease`: filter envelope for the lowpass filter. + - alternatively: `lpa`, `lpd`, `lps` and `lpr`. +- `hpattack`, `hpdecay`, `hpsustain`, `hprelease`: filter envelope for the highpass filter. + - alternatively: `hpa`, `hpd`, `hps` and `hpr`. +- `bpattack`, `bpdecay`, `bpsustain`, `bprelease`: filter envelope for the bandpass filter. + - alternatively: `bpa`, `bpd`, `bps` and `bpr`. + +## lpattack + +- Also `hpattack` and `bpattack`. + + + +## lpdecay + +- Also `hpdecay` and `bpdecay`. + + + +## lpsustain + +- Also `hpsustain` and `bpsustain`. + + + +## lprelease + +- Also `hprelease` and `bprelease`. + + + +## fenv + + + # Dynamics ## gain From 34318039807c8d0faa83b3bd032b609704a93ba7 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Fri, 8 Sep 2023 13:08:00 +0200 Subject: [PATCH 019/175] documenting vib and vibmod --- packages/core/controls.mjs | 23 ++++++++++++++++++++--- website/src/pages/learn/synths.mdx | 10 ++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index c2cf917e..f7f029e0 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -393,9 +393,28 @@ const generic_params = [ */ // currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496 // ['hpf'], - [['vib'], 'vib'], + /** + * Applies a vibrato to the frequency of the oscillator. + * + * @name vib + * @param {number | Pattern} frequency of the vibrato in hertz + * @synonyms vibrato + * @example + * sound("triangle").freq(300).vib("<1 2 4 8 16>") + */ + [['vibrato'], 'vib'], + /** + * Sets the vibrato depth as a multiple of base frequency (not vibrato speed!). + * + * @name vibmod + * @param {number | Pattern} depth of vibrato (multiple of base frequency) + * @example + * sound("triangle").freq(300).vib("<8 16>").vibmod("<0.25 0.5 0.75 1 2 4>") + */ [['vibmod'], 'vibmod'], [['hcutoff', 'hresonance'], 'hpf', 'hp'], + ['vib'], + ['vibmod'], /** * Controls the **h**igh-**p**ass **q**-value. * @@ -666,8 +685,6 @@ const generic_params = [ // TODO: LFO rate see https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare ['rate'], // TODO: slide param for certain synths - ['vibrato'], - ['vdepth'], ['slide'], ['slidespeed'], // TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index b24726cf..68bbee34 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -48,6 +48,16 @@ You can also set `n` directly in mini notation with `sound`: Note for tidal users: `n` in tidal is synonymous to `note` for synths only. In strudel, this is not the case, where `n` will always change timbre, be it though different samples or different waveforms. +### Vibrato + +#### vib + + + +#### vibmod + + + ## FM Synthesis FM Synthesis is a technique that changes the frequency of a basic waveform rapidly to alter the timbre. From 74442b0d76eb12b3a44e824c9422aaba6b8e9eb1 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Fri, 8 Sep 2023 13:43:43 +0200 Subject: [PATCH 020/175] documenting vibrato and removing broken slide/pitchJump mechanism --- packages/core/controls.mjs | 8 ++++++-- packages/superdough/synth.mjs | 8 +------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index f7f029e0..f6fcc89f 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -686,6 +686,7 @@ const generic_params = [ ['rate'], // TODO: slide param for certain synths ['slide'], + ['slidespeed'], // TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare ['semitone'], @@ -893,10 +894,13 @@ const generic_params = [ // ZZFX ['zrand'], ['curve'], - ['slide'], // superdirt duplicate - ['deltaSlide'], ['pitchJump'], ['pitchJumpTime'], + ['slide'], // superdirt duplicate + ['deltaSlide'], + /** + * + */ ['lfo', 'repeatTime'], ['noise'], ['zmod'], diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 4101aaee..8a240340 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -42,8 +42,6 @@ export function registerSynthSounds() { fmwave: fmWaveform = 'sine', vib = 0, vibmod = 1, - pitchJump, - pitchJumpSpeed = 1, } = value; let { n, note, freq } = value; // with synths, n and note are the same thing @@ -63,8 +61,6 @@ export function registerSynthSounds() { freq, vib, vibmod, - pitchJump: pitchJump * freq, - pitchJumpSpeed: sustain / pitchJumpSpeed, partials: n, }); @@ -150,7 +146,7 @@ export function waveformN(partials, type) { return osc; } -export function getOscillator({ s, freq, t, vib, vibmod, pitchJump, pitchJumpSpeed, partials }) { +export function getOscillator({ s, freq, t, vib, vibmod, partials }) { // Additional oscillator for vibrato effect if (vib > 0) { var vibrato_oscillator = getAudioContext().createOscillator(); @@ -168,7 +164,6 @@ export function getOscillator({ s, freq, t, vib, vibmod, pitchJump, pitchJumpSpe if (vib > 0) { o.frequency.value = Number(freq); - slide > 0 && o.frequency.linearRampToValueAtTime(freq + pitchJump, t + pitchJumpSpeed); var gain = getAudioContext().createGain(); // Vibmod is the amount of vibrato, in semitones gain.gain.value = vibmod * freq; @@ -186,7 +181,6 @@ export function getOscillator({ s, freq, t, vib, vibmod, pitchJump, pitchJumpSpe } else { // Normal operation, without vibrato o.frequency.value = Number(freq); - slide > 0 && o.frequency.linearRampToValueAtTime(freq + slide, t + slide_speed); o.start(t); const stop = (time) => o.stop(time); return { node: o, stop }; From 534e3f7f81394de9b168e95b68ecfab94337f89d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 10 Sep 2023 00:48:04 +0200 Subject: [PATCH 021/175] add snapshots --- test/__snapshots__/examples.test.mjs.snap | 129 ++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 60b39c53..8fc41df1 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1762,6 +1762,27 @@ exports[`runs examples > example "fastGap" example index 0 1`] = ` ] `; +exports[`runs examples > example "fenv" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c2 s:sawtooth cutoff:500 fenv:1 ]", + "[ 1/4 → 1/2 | note:c3 s:sawtooth cutoff:500 fenv:1 ]", + "[ 1/2 → 3/4 | note:c2 s:sawtooth cutoff:500 fenv:1 ]", + "[ 3/4 → 1/1 | note:c3 s:sawtooth cutoff:500 fenv:1 ]", + "[ 1/1 → 5/4 | note:c2 s:sawtooth cutoff:500 fenv:2 ]", + "[ 5/4 → 3/2 | note:c3 s:sawtooth cutoff:500 fenv:2 ]", + "[ 3/2 → 7/4 | note:c2 s:sawtooth cutoff:500 fenv:2 ]", + "[ 7/4 → 2/1 | note:c3 s:sawtooth cutoff:500 fenv:2 ]", + "[ 2/1 → 9/4 | note:c2 s:sawtooth cutoff:500 fenv:3 ]", + "[ 9/4 → 5/2 | note:c3 s:sawtooth cutoff:500 fenv:3 ]", + "[ 5/2 → 11/4 | note:c2 s:sawtooth cutoff:500 fenv:3 ]", + "[ 11/4 → 3/1 | note:c3 s:sawtooth cutoff:500 fenv:3 ]", + "[ 3/1 → 13/4 | note:c2 s:sawtooth cutoff:500 fenv:4 ]", + "[ 13/4 → 7/2 | note:c3 s:sawtooth cutoff:500 fenv:4 ]", + "[ 7/2 → 15/4 | note:c2 s:sawtooth cutoff:500 fenv:4 ]", + "[ 15/4 → 4/1 | note:c3 s:sawtooth cutoff:500 fenv:4 ]", +] +`; + exports[`runs examples > example "firstOf" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:g3 ]", @@ -2566,6 +2587,64 @@ exports[`runs examples > example "loopAtCps" example index 0 1`] = ` ] `; +exports[`runs examples > example "lpattack" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 1/6 → 1/3 | note:e3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 1/3 → 1/2 | note:f3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 1/2 → 2/3 | note:g3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 2/3 → 5/6 | note:ab3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 5/6 → 1/1 | note:bb3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 1/1 → 7/6 | note:c3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 7/6 → 4/3 | note:e3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 4/3 → 3/2 | note:f3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 3/2 → 5/3 | note:g3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 5/3 → 11/6 | note:ab3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 11/6 → 2/1 | note:bb3 s:square cutoff:1000 lpattack:0.05 fenv:1 release:0.2 attack:0 ]", + "[ 2/1 → 13/6 | note:c3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 13/6 → 7/3 | note:e3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 7/3 → 5/2 | note:f3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 5/2 → 8/3 | note:g3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 8/3 → 17/6 | note:ab3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 17/6 → 3/1 | note:bb3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 3/1 → 19/6 | note:c3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 19/6 → 10/3 | note:e3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 10/3 → 7/2 | note:f3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 7/2 → 11/3 | note:g3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 11/3 → 23/6 | note:ab3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", + "[ 23/6 → 4/1 | note:bb3 s:square cutoff:1000 lpattack:0.1 fenv:1 release:0.2 attack:0 ]", +] +`; + +exports[`runs examples > example "lpdecay" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 1/6 → 1/3 | note:e3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 1/3 → 1/2 | note:f3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 1/2 → 2/3 | note:g3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 2/3 → 5/6 | note:ab3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 5/6 → 1/1 | note:bb3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 1/1 → 7/6 | note:c3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 7/6 → 4/3 | note:e3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 4/3 → 3/2 | note:f3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 3/2 → 5/3 | note:g3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 5/3 → 11/6 | note:ab3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 11/6 → 2/1 | note:bb3 s:square cutoff:1000 lpdecay:0.05 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 2/1 → 13/6 | note:c3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 13/6 → 7/3 | note:e3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 7/3 → 5/2 | note:f3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 5/2 → 8/3 | note:g3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 8/3 → 17/6 | note:ab3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 17/6 → 3/1 | note:bb3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 3/1 → 19/6 | note:c3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 19/6 → 10/3 | note:e3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 10/3 → 7/2 | note:f3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 7/2 → 11/3 | note:g3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 11/3 → 23/6 | note:ab3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", + "[ 23/6 → 4/1 | note:bb3 s:square cutoff:1000 lpdecay:0.1 fenv:4 lpsustain:0 lprelease:0 ]", +] +`; + exports[`runs examples > example "lpf" example index 0 1`] = ` [ "[ 0/1 → 1/3 | s:hh cutoff:4000 ]", @@ -2657,6 +2736,56 @@ exports[`runs examples > example "lpq" example index 0 1`] = ` ] `; +exports[`runs examples > example "lprelease" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c3 lprelease:0.1 fenv:0.5 ]", + "[ 1/4 → 1/2 | note:e3 lprelease:0.1 fenv:0.5 ]", + "[ 1/2 → 3/4 | note:g3 lprelease:0.1 fenv:0.5 ]", + "[ 3/4 → 1/1 | note:c4 lprelease:0.1 fenv:0.5 ]", + "[ 1/1 → 5/4 | note:c3 lprelease:0.25 fenv:0.5 ]", + "[ 5/4 → 3/2 | note:e3 lprelease:0.25 fenv:0.5 ]", + "[ 3/2 → 7/4 | note:g3 lprelease:0.25 fenv:0.5 ]", + "[ 7/4 → 2/1 | note:c4 lprelease:0.25 fenv:0.5 ]", + "[ 2/1 → 9/4 | note:c3 lprelease:0.5 fenv:0.5 ]", + "[ 9/4 → 5/2 | note:e3 lprelease:0.5 fenv:0.5 ]", + "[ 5/2 → 11/4 | note:g3 lprelease:0.5 fenv:0.5 ]", + "[ 11/4 → 3/1 | note:c4 lprelease:0.5 fenv:0.5 ]", + "[ 3/1 → 13/4 | note:c3 lprelease:0.1 fenv:0.5 ]", + "[ 13/4 → 7/2 | note:e3 lprelease:0.1 fenv:0.5 ]", + "[ 7/2 → 15/4 | note:g3 lprelease:0.1 fenv:0.5 ]", + "[ 15/4 → 4/1 | note:c4 lprelease:0.1 fenv:0.5 ]", +] +`; + +exports[`runs examples > example "lpsustain" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 fenv:2 ]", + "[ 1/6 → 1/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 fenv:2 ]", + "[ 1/3 → 1/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 fenv:2 ]", + "[ 1/2 → 2/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 fenv:2 ]", + "[ 2/3 → 5/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 fenv:2 ]", + "[ 5/6 → 1/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 fenv:2 ]", + "[ 1/1 → 7/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 fenv:2 ]", + "[ 7/6 → 4/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 fenv:2 ]", + "[ 4/3 → 3/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 fenv:2 ]", + "[ 3/2 → 5/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 fenv:2 ]", + "[ 5/3 → 11/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 fenv:2 ]", + "[ 11/6 → 2/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 fenv:2 ]", + "[ 2/1 → 13/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 fenv:2 ]", + "[ 13/6 → 7/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 fenv:2 ]", + "[ 7/3 → 5/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 fenv:2 ]", + "[ 5/2 → 8/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 fenv:2 ]", + "[ 8/3 → 17/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 fenv:2 ]", + "[ 17/6 → 3/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 fenv:2 ]", + "[ 3/1 → 19/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 fenv:2 ]", + "[ 19/6 → 10/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 fenv:2 ]", + "[ 10/3 → 7/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 fenv:2 ]", + "[ 7/2 → 11/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 fenv:2 ]", + "[ 11/3 → 23/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 fenv:2 ]", + "[ 23/6 → 4/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 fenv:2 ]", +] +`; + exports[`runs examples > example "lrate" example index 0 1`] = ` [ "[ 0/1 → 1/1 | n:0 s:supersquare leslie:1 lrate:1 ]", From 78ccec5d7b4922cc211fa5244601d9d68197da18 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 10 Sep 2023 09:14:41 +0200 Subject: [PATCH 022/175] adding test run --- test/__snapshots__/examples.test.mjs.snap | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 60b39c53..76a7cf11 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -4557,6 +4557,24 @@ exports[`runs examples > example "velocity" example index 0 1`] = ` ] `; +exports[`runs examples > example "vib" example index 0 1`] = ` +[ + "[ 0/1 → 1/1 | s:triangle freq:300 vib:1 ]", + "[ 1/1 → 2/1 | s:triangle freq:300 vib:2 ]", + "[ 2/1 → 3/1 | s:triangle freq:300 vib:4 ]", + "[ 3/1 → 4/1 | s:triangle freq:300 vib:8 ]", +] +`; + +exports[`runs examples > example "vibmod" example index 0 1`] = ` +[ + "[ 0/1 → 1/1 | s:triangle freq:300 vib:8 vibmod:0.25 ]", + "[ 1/1 → 2/1 | s:triangle freq:300 vib:16 vibmod:0.5 ]", + "[ 2/1 → 3/1 | s:triangle freq:300 vib:8 vibmod:0.75 ]", + "[ 3/1 → 4/1 | s:triangle freq:300 vib:16 vibmod:1 ]", +] +`; + exports[`runs examples > example "voicing" example index 0 1`] = ` [ "[ 0/1 → 1/1 | note:E4 ]", From bea9a3c2dc31483e1bf5956e5fe0f5d11de2ae7a Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 10 Sep 2023 09:28:07 +0200 Subject: [PATCH 023/175] replacing fenv by lpenv, hpenv, bpenv --- packages/superdough/superdough.mjs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index f17c277e..fda26277 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -179,15 +179,16 @@ export const superdough = async (value, deadline, hapDuration) => { gain = 0.8, // filters order = '12db', - fenv, // low pass cutoff, + lpenv, lpattack = 0.01, lpdecay = 0.5, lpsustain = 0.6, lprelease = 0.01, resonance = 1, // high pass + hpenv, hcutoff, hpattack = 0.01, hpdecay = 0.5, @@ -195,6 +196,7 @@ export const superdough = async (value, deadline, hapDuration) => { hprelease = 0.01, hresonance = 1, // band pass + bpenv, bandf, bpattack = 0.01, bpdecay = 0.5, @@ -256,7 +258,7 @@ export const superdough = async (value, deadline, hapDuration) => { if (cutoff !== undefined) { let lp = () => - createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, fenv, t, t + hapDuration); + createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, lpenv, t, t + hapDuration); chain.push(lp()); if (order === '24db') { chain.push(lp()); @@ -274,7 +276,7 @@ export const superdough = async (value, deadline, hapDuration) => { hpdecay, hpsustain, hprelease, - fenv, + hpenv, t, t + hapDuration, ); @@ -286,7 +288,7 @@ export const superdough = async (value, deadline, hapDuration) => { if (bandf !== undefined) { let bp = () => - createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, fenv, t, t + hapDuration); + createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, bpenv, t, t + hapDuration); chain.push(bp()); if (order === '24db') { chain.push(bp()); From 1383af62083b280e3c1c9642dc8333ac5cd0d3fb Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 10 Sep 2023 09:42:29 +0200 Subject: [PATCH 024/175] documenting filters more + tests --- packages/core/controls.mjs | 139 +++++++- packages/superdough/superdough.mjs | 22 +- test/__snapshots__/examples.test.mjs.snap | 387 ++++++++++++++++++++++ 3 files changed, 526 insertions(+), 22 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 84b7526d..86ec5869 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -379,14 +379,35 @@ const generic_params = [ [['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'], /** - * Sets the filter envelope modulation depth. - * @name fenv - * @param {number | Pattern} modulation depth of the filter envelope between 0 and _n_ + * Sets the lowpass filter envelope modulation depth. + * @name lpenv + * @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_ + * @synonyms lpe * @example * note("c2 c3").fast(2).sound("sawtooth") - * .cutoff(500).fenv("<1 2 3 4 5 6 7 8>") + * .cutoff(500).lpenv("<1 2 3 4 5 6 7 8>") */ - ['fenv'], + ['lpenv', 'lpe'], + /** + * Sets the highpass filter envelope modulation depth. + * @name hpenv + * @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_ + * @synonyms hpe + * @example + * note("c2 c3").fast(2).sound("sawtooth") + * .hcutoff(500).hpenv("<1 2 3 4 5 6 7 8>") + */ + ['hpenv', 'hpe'], + /** + * Sets the bandpass filter envelope modulation depth. + * @name bpenv + * @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_ + * @synonyms bpe + * @example + * note("c2 c3").fast(2).sound("sawtooth") + * .bandf(500).bpenv("<1 2 3 4 5 6 7 8>") + */ + ['bpenv', 'bpe'], /** * Sets the attack duration for the lowpass filter envelope. * @name lpattack @@ -395,10 +416,34 @@ const generic_params = [ * @example * note("c3 e3 f3 g3 ab3 bb3") * .sound('square').cutoff(1000) - * .lpattack("<0.05 0.1 0.25 0.5>/2").fenv(1) + * .lpattack("<0.05 0.1 0.25 0.5>/2").ftype('12db') * .release(0.2).attack(0) */ ['lpattack', 'lpa'], + /** + * Sets the attack duration for the highpass filter envelope. + * @name hpattack + * @param {number | Pattern} attack time of the highpass filter envelope + * @synonyms hpa + * @example + * note("c3 e3 f3 g3 ab3 bb3") + * .sound('square').hcutoff(1000) + * .hpattack("<0.05 0.1 0.25 0.5>/2").ftype('12db') + * .release(0.2).attack(0) + */ + ['hpattack', 'hpa'], + /** + * Sets the attack duration for the bandpass filter envelope. + * @name hpattack + * @param {number | Pattern} attack time of the bandpass filter envelope + * @synonyms bpa + * @example + * note("c3 e3 f3 g3 ab3 bb3") + * .sound('square').bandf(1000) + * .bpattack("<0.05 0.1 0.25 0.5>/2").ftype('12db') + * .release(0.2).attack(0) + */ + ['bpattack', 'bpa'], /** * Sets the decay duration for the lowpass filter envelope. * @name lpdecay @@ -409,39 +454,99 @@ const generic_params = [ * note("c3 e3 f3 g3 ab3 bb3") * .sound('square').cutoff(1000) * .lpdecay("<0.05 0.1 0.125>/2") - * .fenv("4").lps(0).lpr(0) + * .ftype("12db").lps(0).lpr(0) */ ['lpdecay', 'lpd'], + /** + * Sets the decay duration for the highpass filter envelope. + * @name hpdecay + * @param {number | Pattern} decay time of the highpass filter envelope + * @synonyms hpd + * @example + * "baba" + * note("c3 e3 f3 g3 ab3 bb3") + * .sound('square').hcutoff(1000) + * .hpdecay("<0.05 0.1 0.125>/2") + * .ftype("12db").hps(0).hpr(0) + */ + ['hpdecay', 'hpd'], + /** + * Sets the decay duration for the bandpass filter envelope. + * @name bpdecay + * @param {number | Pattern} decay time of the bandpass filter envelope + * @synonyms bpd + * @example + * "baba" + * note("c3 e3 f3 g3 ab3 bb3") + * .sound('square').bandf(1000) + * .bpdecay("<0.05 0.1 0.125>/2") + * .ftype("12db").bps(0).bpr(0) + */ + ['bpdecay', 'bpd'], /** * Sets the sustain amplitude for the lowpass filter envelope. * @name lpsustain - * @param {number | Pattern} sustain amplitude of the filter envelope + * @param {number | Pattern} sustain amplitude of the lowpass filter envelope * @synonyms lps * @example * note("c3 e3 f3 g3 ab3 bb3") * .sound('square').cutoff(200) * .lpd(0.1).lpsustain("<0.1 0.5 0.75 1>") - * .fenv("2") + * .ftype("12db") */ ['lpsustain', 'lps'], + /** + * Sets the sustain amplitude for the highpass filter envelope. + * @name lpsustain + * @param {number | Pattern} sustain amplitude of the highpass filter envelope + * @synonyms hps + * @example + * note("c3 e3 f3 g3 ab3 bb3") + * .sound('square').hcutoff(200) + * .hpd(0.1).hpsustain("<0.1 0.5 0.75 1>") + * .ftype("12db") + */ + ['hpsustain', 'hps'], + /** + * Sets the sustain amplitude for the bandpass filter envelope. + * @name lpsustain + * @param {number | Pattern} sustain amplitude of the bandpass filter envelope + * @synonyms bps + * @example + * note("c3 e3 f3 g3 ab3 bb3") + * .sound('square').bandf(200) + * .bpd(0.1).bpsustain("<0.1 0.5 0.75 1>") + * .ftype("12db") + */ + ['bpsustain', 'bps'], /** * Sets the release time for the lowpass filter envelope. * @name lprelease * @param {number | Pattern} release time of the filter envelope * @synonyms lpr * @example - * note("c3 e3 g3 c4").lpr("<0.1 0.25 0.5>").fenv(0.5) + * note("c3 e3 g3 c4").lpr("<0.1 0.25 0.5>").ftype('12db') */ ['lprelease', 'lpr'], - ['hpattack', 'hpa'], - ['hpdecay', 'hpd'], - ['hpsustain', 'hps'], + /** + * Sets the release time for the highpass filter envelope. + * @name lprelease + * @param {number | Pattern} release time of the highpass filter envelope + * @synonyms hpr + * @example + * note("c3 e3 g3 c4").hpr("<0.1 0.25 0.5>").ftype('12db') + */ ['hprelease', 'hpr'], - ['bpattack', 'bpa'], - ['bpdecay', 'bpd'], - ['bpsustain', 'bps'], + /** + * Sets the release time for the bandpass filter envelope. + * @name lprelease + * @param {number | Pattern} release time of the bandpass filter envelope + * @synonyms bpr + * @example + * note("c3 e3 g3 c4").bpr("<0.1 0.25 0.5>").ftype('12db') + */ ['bprelease', 'bpr'], - ['order'], + ['ftype'], /** * Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter. * diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index fda26277..3afe470e 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -178,7 +178,7 @@ export const superdough = async (value, deadline, hapDuration) => { source, gain = 0.8, // filters - order = '12db', + ftype = '12db', // low pass cutoff, lpenv, @@ -258,9 +258,21 @@ export const superdough = async (value, deadline, hapDuration) => { if (cutoff !== undefined) { let lp = () => - createFilter(ac, 'lowpass', cutoff, resonance, lpattack, lpdecay, lpsustain, lprelease, lpenv, t, t + hapDuration); + createFilter( + ac, + 'lowpass', + cutoff, + resonance, + lpattack, + lpdecay, + lpsustain, + lprelease, + lpenv, + t, + t + hapDuration, + ); chain.push(lp()); - if (order === '24db') { + if (ftype === '24db') { chain.push(lp()); } } @@ -281,7 +293,7 @@ export const superdough = async (value, deadline, hapDuration) => { t + hapDuration, ); chain.push(hp()); - if (order === '24db') { + if (ftype === '24db') { chain.push(hp()); } } @@ -290,7 +302,7 @@ export const superdough = async (value, deadline, hapDuration) => { let bp = () => createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, bpenv, t, t + hapDuration); chain.push(bp()); - if (order === '24db') { + if (ftype === '24db') { chain.push(bp()); } } diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 60b39c53..4cb261ae 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -900,6 +900,56 @@ exports[`runs examples > example "begin" example index 0 1`] = ` ] `; +exports[`runs examples > example "bpdecay" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 1/6 → 1/3 | note:e3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 1/3 → 1/2 | note:f3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 1/2 → 2/3 | note:g3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 2/3 → 5/6 | note:ab3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 5/6 → 1/1 | note:bb3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 1/1 → 7/6 | note:c3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 7/6 → 4/3 | note:e3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 4/3 → 3/2 | note:f3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 3/2 → 5/3 | note:g3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 5/3 → 11/6 | note:ab3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 11/6 → 2/1 | note:bb3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 2/1 → 13/6 | note:c3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 13/6 → 7/3 | note:e3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 7/3 → 5/2 | note:f3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 5/2 → 8/3 | note:g3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 8/3 → 17/6 | note:ab3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 17/6 → 3/1 | note:bb3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 3/1 → 19/6 | note:c3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 19/6 → 10/3 | note:e3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 10/3 → 7/2 | note:f3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 7/2 → 11/3 | note:g3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 11/3 → 23/6 | note:ab3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 23/6 → 4/1 | note:bb3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", +] +`; + +exports[`runs examples > example "bpenv" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c2 s:sawtooth bandf:500 bpenv:1 ]", + "[ 1/4 → 1/2 | note:c3 s:sawtooth bandf:500 bpenv:1 ]", + "[ 1/2 → 3/4 | note:c2 s:sawtooth bandf:500 bpenv:1 ]", + "[ 3/4 → 1/1 | note:c3 s:sawtooth bandf:500 bpenv:1 ]", + "[ 1/1 → 5/4 | note:c2 s:sawtooth bandf:500 bpenv:2 ]", + "[ 5/4 → 3/2 | note:c3 s:sawtooth bandf:500 bpenv:2 ]", + "[ 3/2 → 7/4 | note:c2 s:sawtooth bandf:500 bpenv:2 ]", + "[ 7/4 → 2/1 | note:c3 s:sawtooth bandf:500 bpenv:2 ]", + "[ 2/1 → 9/4 | note:c2 s:sawtooth bandf:500 bpenv:3 ]", + "[ 9/4 → 5/2 | note:c3 s:sawtooth bandf:500 bpenv:3 ]", + "[ 5/2 → 11/4 | note:c2 s:sawtooth bandf:500 bpenv:3 ]", + "[ 11/4 → 3/1 | note:c3 s:sawtooth bandf:500 bpenv:3 ]", + "[ 3/1 → 13/4 | note:c2 s:sawtooth bandf:500 bpenv:4 ]", + "[ 13/4 → 7/2 | note:c3 s:sawtooth bandf:500 bpenv:4 ]", + "[ 7/2 → 15/4 | note:c2 s:sawtooth bandf:500 bpenv:4 ]", + "[ 15/4 → 4/1 | note:c3 s:sawtooth bandf:500 bpenv:4 ]", +] +`; + exports[`runs examples > example "bpf" example index 0 1`] = ` [ "[ 0/1 → 1/3 | s:hh bandf:1000 ]", @@ -2050,6 +2100,114 @@ exports[`runs examples > example "gain" example index 0 1`] = ` ] `; +exports[`runs examples > example "hpattack" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/6 → 1/3 | note:e3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/3 → 1/2 | note:f3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/2 → 2/3 | note:g3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 2/3 → 5/6 | note:ab3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 5/6 → 1/1 | note:bb3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/1 → 7/6 | note:c3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 7/6 → 4/3 | note:e3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 4/3 → 3/2 | note:f3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 3/2 → 5/3 | note:g3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 5/3 → 11/6 | note:ab3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 11/6 → 2/1 | note:bb3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 2/1 → 13/6 | note:c3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 13/6 → 7/3 | note:e3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 7/3 → 5/2 | note:f3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 5/2 → 8/3 | note:g3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 8/3 → 17/6 | note:ab3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 17/6 → 3/1 | note:bb3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 3/1 → 19/6 | note:c3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 19/6 → 10/3 | note:e3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 10/3 → 7/2 | note:f3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 7/2 → 11/3 | note:g3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 11/3 → 23/6 | note:ab3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 23/6 → 4/1 | note:bb3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", +] +`; + +exports[`runs examples > example "hpattack" example index 0 2`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/6 → 1/3 | note:e3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/3 → 1/2 | note:f3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/2 → 2/3 | note:g3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 2/3 → 5/6 | note:ab3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 5/6 → 1/1 | note:bb3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/1 → 7/6 | note:c3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 7/6 → 4/3 | note:e3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 4/3 → 3/2 | note:f3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 3/2 → 5/3 | note:g3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 5/3 → 11/6 | note:ab3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 11/6 → 2/1 | note:bb3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 2/1 → 13/6 | note:c3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 13/6 → 7/3 | note:e3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 7/3 → 5/2 | note:f3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 5/2 → 8/3 | note:g3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 8/3 → 17/6 | note:ab3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 17/6 → 3/1 | note:bb3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 3/1 → 19/6 | note:c3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 19/6 → 10/3 | note:e3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 10/3 → 7/2 | note:f3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 7/2 → 11/3 | note:g3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 11/3 → 23/6 | note:ab3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 23/6 → 4/1 | note:bb3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", +] +`; + +exports[`runs examples > example "hpdecay" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 1/6 → 1/3 | note:e3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 1/3 → 1/2 | note:f3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 1/2 → 2/3 | note:g3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 2/3 → 5/6 | note:ab3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 5/6 → 1/1 | note:bb3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 1/1 → 7/6 | note:c3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 7/6 → 4/3 | note:e3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 4/3 → 3/2 | note:f3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 3/2 → 5/3 | note:g3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 5/3 → 11/6 | note:ab3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 11/6 → 2/1 | note:bb3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 2/1 → 13/6 | note:c3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 13/6 → 7/3 | note:e3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 7/3 → 5/2 | note:f3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 5/2 → 8/3 | note:g3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 8/3 → 17/6 | note:ab3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 17/6 → 3/1 | note:bb3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 3/1 → 19/6 | note:c3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 19/6 → 10/3 | note:e3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 10/3 → 7/2 | note:f3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 7/2 → 11/3 | note:g3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 11/3 → 23/6 | note:ab3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 23/6 → 4/1 | note:bb3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", +] +`; + +exports[`runs examples > example "hpenv" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c2 s:sawtooth hcutoff:500 hpenv:1 ]", + "[ 1/4 → 1/2 | note:c3 s:sawtooth hcutoff:500 hpenv:1 ]", + "[ 1/2 → 3/4 | note:c2 s:sawtooth hcutoff:500 hpenv:1 ]", + "[ 3/4 → 1/1 | note:c3 s:sawtooth hcutoff:500 hpenv:1 ]", + "[ 1/1 → 5/4 | note:c2 s:sawtooth hcutoff:500 hpenv:2 ]", + "[ 5/4 → 3/2 | note:c3 s:sawtooth hcutoff:500 hpenv:2 ]", + "[ 3/2 → 7/4 | note:c2 s:sawtooth hcutoff:500 hpenv:2 ]", + "[ 7/4 → 2/1 | note:c3 s:sawtooth hcutoff:500 hpenv:2 ]", + "[ 2/1 → 9/4 | note:c2 s:sawtooth hcutoff:500 hpenv:3 ]", + "[ 9/4 → 5/2 | note:c3 s:sawtooth hcutoff:500 hpenv:3 ]", + "[ 5/2 → 11/4 | note:c2 s:sawtooth hcutoff:500 hpenv:3 ]", + "[ 11/4 → 3/1 | note:c3 s:sawtooth hcutoff:500 hpenv:3 ]", + "[ 3/1 → 13/4 | note:c2 s:sawtooth hcutoff:500 hpenv:4 ]", + "[ 13/4 → 7/2 | note:c3 s:sawtooth hcutoff:500 hpenv:4 ]", + "[ 7/2 → 15/4 | note:c2 s:sawtooth hcutoff:500 hpenv:4 ]", + "[ 15/4 → 4/1 | note:c3 s:sawtooth hcutoff:500 hpenv:4 ]", +] +`; + exports[`runs examples > example "hpf" example index 0 1`] = ` [ "[ 0/1 → 1/4 | s:hh hcutoff:4000 ]", @@ -2566,6 +2724,85 @@ exports[`runs examples > example "loopAtCps" example index 0 1`] = ` ] `; +exports[`runs examples > example "lpattack" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/6 → 1/3 | note:e3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/3 → 1/2 | note:f3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/2 → 2/3 | note:g3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 2/3 → 5/6 | note:ab3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 5/6 → 1/1 | note:bb3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 1/1 → 7/6 | note:c3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 7/6 → 4/3 | note:e3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 4/3 → 3/2 | note:f3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 3/2 → 5/3 | note:g3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 5/3 → 11/6 | note:ab3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 11/6 → 2/1 | note:bb3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", + "[ 2/1 → 13/6 | note:c3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 13/6 → 7/3 | note:e3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 7/3 → 5/2 | note:f3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 5/2 → 8/3 | note:g3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 8/3 → 17/6 | note:ab3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 17/6 → 3/1 | note:bb3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 3/1 → 19/6 | note:c3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 19/6 → 10/3 | note:e3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 10/3 → 7/2 | note:f3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 7/2 → 11/3 | note:g3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 11/3 → 23/6 | note:ab3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 23/6 → 4/1 | note:bb3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", +] +`; + +exports[`runs examples > example "lpdecay" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 1/6 → 1/3 | note:e3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 1/3 → 1/2 | note:f3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 1/2 → 2/3 | note:g3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 2/3 → 5/6 | note:ab3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 5/6 → 1/1 | note:bb3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 1/1 → 7/6 | note:c3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 7/6 → 4/3 | note:e3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 4/3 → 3/2 | note:f3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 3/2 → 5/3 | note:g3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 5/3 → 11/6 | note:ab3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 11/6 → 2/1 | note:bb3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 2/1 → 13/6 | note:c3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 13/6 → 7/3 | note:e3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 7/3 → 5/2 | note:f3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 5/2 → 8/3 | note:g3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 8/3 → 17/6 | note:ab3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 17/6 → 3/1 | note:bb3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 3/1 → 19/6 | note:c3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 19/6 → 10/3 | note:e3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 10/3 → 7/2 | note:f3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 7/2 → 11/3 | note:g3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 11/3 → 23/6 | note:ab3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 23/6 → 4/1 | note:bb3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", +] +`; + +exports[`runs examples > example "lpenv" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c2 s:sawtooth cutoff:500 lpenv:1 ]", + "[ 1/4 → 1/2 | note:c3 s:sawtooth cutoff:500 lpenv:1 ]", + "[ 1/2 → 3/4 | note:c2 s:sawtooth cutoff:500 lpenv:1 ]", + "[ 3/4 → 1/1 | note:c3 s:sawtooth cutoff:500 lpenv:1 ]", + "[ 1/1 → 5/4 | note:c2 s:sawtooth cutoff:500 lpenv:2 ]", + "[ 5/4 → 3/2 | note:c3 s:sawtooth cutoff:500 lpenv:2 ]", + "[ 3/2 → 7/4 | note:c2 s:sawtooth cutoff:500 lpenv:2 ]", + "[ 7/4 → 2/1 | note:c3 s:sawtooth cutoff:500 lpenv:2 ]", + "[ 2/1 → 9/4 | note:c2 s:sawtooth cutoff:500 lpenv:3 ]", + "[ 9/4 → 5/2 | note:c3 s:sawtooth cutoff:500 lpenv:3 ]", + "[ 5/2 → 11/4 | note:c2 s:sawtooth cutoff:500 lpenv:3 ]", + "[ 11/4 → 3/1 | note:c3 s:sawtooth cutoff:500 lpenv:3 ]", + "[ 3/1 → 13/4 | note:c2 s:sawtooth cutoff:500 lpenv:4 ]", + "[ 13/4 → 7/2 | note:c3 s:sawtooth cutoff:500 lpenv:4 ]", + "[ 7/2 → 15/4 | note:c2 s:sawtooth cutoff:500 lpenv:4 ]", + "[ 15/4 → 4/1 | note:c3 s:sawtooth cutoff:500 lpenv:4 ]", +] +`; + exports[`runs examples > example "lpf" example index 0 1`] = ` [ "[ 0/1 → 1/3 | s:hh cutoff:4000 ]", @@ -2657,6 +2894,156 @@ exports[`runs examples > example "lpq" example index 0 1`] = ` ] `; +exports[`runs examples > example "lprelease" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c3 lprelease:0.1 ftype:12db ]", + "[ 1/4 → 1/2 | note:e3 lprelease:0.1 ftype:12db ]", + "[ 1/2 → 3/4 | note:g3 lprelease:0.1 ftype:12db ]", + "[ 3/4 → 1/1 | note:c4 lprelease:0.1 ftype:12db ]", + "[ 1/1 → 5/4 | note:c3 lprelease:0.25 ftype:12db ]", + "[ 5/4 → 3/2 | note:e3 lprelease:0.25 ftype:12db ]", + "[ 3/2 → 7/4 | note:g3 lprelease:0.25 ftype:12db ]", + "[ 7/4 → 2/1 | note:c4 lprelease:0.25 ftype:12db ]", + "[ 2/1 → 9/4 | note:c3 lprelease:0.5 ftype:12db ]", + "[ 9/4 → 5/2 | note:e3 lprelease:0.5 ftype:12db ]", + "[ 5/2 → 11/4 | note:g3 lprelease:0.5 ftype:12db ]", + "[ 11/4 → 3/1 | note:c4 lprelease:0.5 ftype:12db ]", + "[ 3/1 → 13/4 | note:c3 lprelease:0.1 ftype:12db ]", + "[ 13/4 → 7/2 | note:e3 lprelease:0.1 ftype:12db ]", + "[ 7/2 → 15/4 | note:g3 lprelease:0.1 ftype:12db ]", + "[ 15/4 → 4/1 | note:c4 lprelease:0.1 ftype:12db ]", +] +`; + +exports[`runs examples > example "lprelease" example index 0 2`] = ` +[ + "[ 0/1 → 1/4 | note:c3 hprelease:0.1 ftype:12db ]", + "[ 1/4 → 1/2 | note:e3 hprelease:0.1 ftype:12db ]", + "[ 1/2 → 3/4 | note:g3 hprelease:0.1 ftype:12db ]", + "[ 3/4 → 1/1 | note:c4 hprelease:0.1 ftype:12db ]", + "[ 1/1 → 5/4 | note:c3 hprelease:0.25 ftype:12db ]", + "[ 5/4 → 3/2 | note:e3 hprelease:0.25 ftype:12db ]", + "[ 3/2 → 7/4 | note:g3 hprelease:0.25 ftype:12db ]", + "[ 7/4 → 2/1 | note:c4 hprelease:0.25 ftype:12db ]", + "[ 2/1 → 9/4 | note:c3 hprelease:0.5 ftype:12db ]", + "[ 9/4 → 5/2 | note:e3 hprelease:0.5 ftype:12db ]", + "[ 5/2 → 11/4 | note:g3 hprelease:0.5 ftype:12db ]", + "[ 11/4 → 3/1 | note:c4 hprelease:0.5 ftype:12db ]", + "[ 3/1 → 13/4 | note:c3 hprelease:0.1 ftype:12db ]", + "[ 13/4 → 7/2 | note:e3 hprelease:0.1 ftype:12db ]", + "[ 7/2 → 15/4 | note:g3 hprelease:0.1 ftype:12db ]", + "[ 15/4 → 4/1 | note:c4 hprelease:0.1 ftype:12db ]", +] +`; + +exports[`runs examples > example "lprelease" example index 0 3`] = ` +[ + "[ 0/1 → 1/4 | note:c3 bprelease:0.1 ftype:12db ]", + "[ 1/4 → 1/2 | note:e3 bprelease:0.1 ftype:12db ]", + "[ 1/2 → 3/4 | note:g3 bprelease:0.1 ftype:12db ]", + "[ 3/4 → 1/1 | note:c4 bprelease:0.1 ftype:12db ]", + "[ 1/1 → 5/4 | note:c3 bprelease:0.25 ftype:12db ]", + "[ 5/4 → 3/2 | note:e3 bprelease:0.25 ftype:12db ]", + "[ 3/2 → 7/4 | note:g3 bprelease:0.25 ftype:12db ]", + "[ 7/4 → 2/1 | note:c4 bprelease:0.25 ftype:12db ]", + "[ 2/1 → 9/4 | note:c3 bprelease:0.5 ftype:12db ]", + "[ 9/4 → 5/2 | note:e3 bprelease:0.5 ftype:12db ]", + "[ 5/2 → 11/4 | note:g3 bprelease:0.5 ftype:12db ]", + "[ 11/4 → 3/1 | note:c4 bprelease:0.5 ftype:12db ]", + "[ 3/1 → 13/4 | note:c3 bprelease:0.1 ftype:12db ]", + "[ 13/4 → 7/2 | note:e3 bprelease:0.1 ftype:12db ]", + "[ 7/2 → 15/4 | note:g3 bprelease:0.1 ftype:12db ]", + "[ 15/4 → 4/1 | note:c4 bprelease:0.1 ftype:12db ]", +] +`; + +exports[`runs examples > example "lpsustain" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", + "[ 1/6 → 1/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", + "[ 1/3 → 1/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", + "[ 1/2 → 2/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", + "[ 2/3 → 5/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", + "[ 5/6 → 1/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", + "[ 1/1 → 7/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", + "[ 7/6 → 4/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", + "[ 4/3 → 3/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", + "[ 3/2 → 5/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", + "[ 5/3 → 11/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", + "[ 11/6 → 2/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", + "[ 2/1 → 13/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", + "[ 13/6 → 7/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", + "[ 7/3 → 5/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", + "[ 5/2 → 8/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", + "[ 8/3 → 17/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", + "[ 17/6 → 3/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", + "[ 3/1 → 19/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", + "[ 19/6 → 10/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", + "[ 10/3 → 7/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", + "[ 7/2 → 11/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", + "[ 11/3 → 23/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", + "[ 23/6 → 4/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", +] +`; + +exports[`runs examples > example "lpsustain" example index 0 2`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 1/6 → 1/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 1/3 → 1/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 1/2 → 2/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 2/3 → 5/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 5/6 → 1/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 1/1 → 7/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 7/6 → 4/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 4/3 → 3/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 3/2 → 5/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 5/3 → 11/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 11/6 → 2/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 2/1 → 13/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 13/6 → 7/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 7/3 → 5/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 5/2 → 8/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 8/3 → 17/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 17/6 → 3/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 3/1 → 19/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", + "[ 19/6 → 10/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", + "[ 10/3 → 7/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", + "[ 7/2 → 11/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", + "[ 11/3 → 23/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", + "[ 23/6 → 4/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", +] +`; + +exports[`runs examples > example "lpsustain" example index 0 3`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 1/6 → 1/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 1/3 → 1/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 1/2 → 2/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 2/3 → 5/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 5/6 → 1/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 1/1 → 7/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 7/6 → 4/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 4/3 → 3/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 3/2 → 5/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 5/3 → 11/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 11/6 → 2/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 2/1 → 13/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 13/6 → 7/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 7/3 → 5/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 5/2 → 8/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 8/3 → 17/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 17/6 → 3/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 3/1 → 19/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 19/6 → 10/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 10/3 → 7/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 7/2 → 11/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 11/3 → 23/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 23/6 → 4/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", +] +`; + exports[`runs examples > example "lrate" example index 0 1`] = ` [ "[ 0/1 → 1/1 | n:0 s:supersquare leslie:1 lrate:1 ]", From 3582ae9163e2c95bb7babe6fe4df4ebba44a65f7 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 10 Sep 2023 18:34:21 +0200 Subject: [PATCH 025/175] adding loopBegin and loopEnd --- packages/core/controls.mjs | 2 ++ packages/superdough/sampler.mjs | 17 +++++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 71f58427..2b99bdb3 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -882,6 +882,8 @@ const generic_params = [ ['zdelay'], ['tremolo'], ['zzfx'], + ['loopBegin'], + ['loopEnd'], ]; // TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13 diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 02e5eada..60e61534 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -207,7 +207,9 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { n = 0, note, speed = 1, // sample playback speed + loopBegin = 0, begin = 0, + loopEnd = 1, end = 1, } = value; // load sample @@ -242,19 +244,14 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { // 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; - bufferSource.start(time, offset); const bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value; - /*if (loop) { - // TODO: idea for loopBegin / loopEnd - // if one of [loopBegin,loopEnd] is <= 1, interpret it as normlized - // if [loopBegin,loopEnd] is bigger >= 1, interpret it as sample number - // this will simplify perfectly looping things, while still keeping the normalized option - // the only drawback is that looping between samples 0 and 1 is not possible (which is not real use case) + if (loop) { bufferSource.loop = true; - bufferSource.loopStart = offset; - bufferSource.loopEnd = offset + duration; + bufferSource.loopStart = loopBegin * bufferDuration - offset; + bufferSource.loopEnd = loopEnd * bufferDuration - offset; duration = loop * duration; - }*/ + } + bufferSource.start(time, offset); const { node: envelope, stop: releaseEnvelope } = getEnvelope(attack, decay, sustain, release, 1, t); bufferSource.connect(envelope); const out = ac.createGain(); // we need a separate gain for the cutgroups because firefox... From bac8594c5f1db32d618696c1dacf41bb88a33fb4 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 10 Sep 2023 20:36:09 +0200 Subject: [PATCH 026/175] beginning documentation work (breaks) --- packages/core/controls.mjs | 39 ++++++++++++++++------- test/__snapshots__/examples.test.mjs.snap | 18 +++++++++++ website/src/pages/learn/synths.mdx | 11 +++++++ 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 2b99bdb3..4d427da3 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -309,6 +309,33 @@ const generic_params = [ * */ ['loop'], + /** + * @name loopBegin + * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample + * @synonyms loopb + * @example + * s("numbers").loopBegin("<0 .25 .5 .75>").loop(1) + * + */ + ['loopBegin', 'loopb'], + /** + * @name loopEnd + * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample + * @synonyms loope + * @example + * s("numbers").loopEnd("<0 .25 .5 .75>").loop(1) + * + */ + ['loopEnd', 'loope'], + /** + * bit crusher effect. + * + * @name crush + * @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction). + * @example + * s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>") + * + */ // TODO: currently duplicated with "native" legato // TODO: superdirt legato will do more: https://youtu.be/dQPmE1WaD1k?t=419 /** @@ -323,15 +350,6 @@ const generic_params = [ */ // ['legato'], // ['clhatdecay'], - /** - * bit crusher effect. - * - * @name crush - * @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction). - * @example - * s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>") - * - */ ['crush'], /** * fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers @@ -343,7 +361,6 @@ const generic_params = [ * */ ['coarse'], - /** * choose the channel the pattern is sent to in superdirt * @@ -882,8 +899,6 @@ const generic_params = [ ['zdelay'], ['tremolo'], ['zzfx'], - ['loopBegin'], - ['loopEnd'], ]; // TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13 diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 60b39c53..3e2d81bd 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2566,6 +2566,24 @@ exports[`runs examples > example "loopAtCps" example index 0 1`] = ` ] `; +exports[`runs examples > example "loopBegin" example index 0 1`] = ` +[ + "[ 0/1 → 1/1 | s:numbers loopBegin:0 loop:1 ]", + "[ 1/1 → 2/1 | s:numbers loopBegin:0.25 loop:1 ]", + "[ 2/1 → 3/1 | s:numbers loopBegin:0.5 loop:1 ]", + "[ 3/1 → 4/1 | s:numbers loopBegin:0.75 loop:1 ]", +] +`; + +exports[`runs examples > example "loopEnd" example index 0 1`] = ` +[ + "[ 0/1 → 1/1 | s:numbers loopEnd:0 loop:1 ]", + "[ 1/1 → 2/1 | s:numbers loopEnd:0.25 loop:1 ]", + "[ 2/1 → 3/1 | s:numbers loopEnd:0.5 loop:1 ]", + "[ 3/1 → 4/1 | s:numbers loopEnd:0.75 loop:1 ]", +] +`; + exports[`runs examples > example "lpf" example index 0 1`] = ` [ "[ 0/1 → 1/3 | s:hh cutoff:4000 ]", diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index b24726cf..6a2d7395 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -78,6 +78,17 @@ You can use fm with any of the above waveforms, although the below examples all +## Wavetable Synthesis + +Strudel can also use wavetables to create custom waveforms instead of the default ones used by WebAudio. There is a default set of wavetables accessible by default (approximatively 1000 coming from the [AKWF](https://www.adventurekid.se/akrt/waveforms/adventure-kid-waveforms/) set) but you can also import/use your own. A wavetable is a one-cycle waveform, which is then repeated to create a sound at the desired frequency. It is a classic but very effective synthesis technique. Wavetable synthesis is based on sample looping, using the `loop`, `loopBegin` and `loopEnd` properties of the sampler: + +- `loop`: either `0` (no loop) or `1` (loop) +- `loopBegin`: start of the loop (between 0 and 1) +- `loopEnd`: end of the loop (between 0 and 1) + + + + ## ZZFX The "Zuper Zmall Zound Zynth" [ZZFX](https://github.com/KilledByAPixel/ZzFX) is also integrated in strudel. From f09b89ed6320c3364b44aa60c9ec00a9efae4c72 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 10 Sep 2023 20:55:59 +0200 Subject: [PATCH 027/175] fix: duration for loops --- packages/superdough/sampler.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 60e61534..13944299 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -262,7 +262,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { out.disconnect(); onended(); }; - const stop = (endTime, playWholeBuffer = clip === undefined) => { + const stop = (endTime, playWholeBuffer = clip === undefined && loop === undefined) => { let releaseTime = endTime; if (playWholeBuffer) { releaseTime = t + (end - begin) * bufferDuration; From ba27f2ba28a61fa4914ad394cc1e4c22946e000c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 10 Sep 2023 21:05:57 +0200 Subject: [PATCH 028/175] fix: looped samples pitch --- packages/superdough/sampler.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 13944299..26611c0a 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -244,11 +244,10 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { // 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 bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value; if (loop) { bufferSource.loop = true; - bufferSource.loopStart = loopBegin * bufferDuration - offset; - bufferSource.loopEnd = loopEnd * bufferDuration - offset; + bufferSource.loopStart = loopBegin * bufferSource.buffer.duration - offset; + bufferSource.loopEnd = loopEnd * bufferSource.buffer.duration - offset; duration = loop * duration; } bufferSource.start(time, offset); @@ -265,6 +264,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { const stop = (endTime, playWholeBuffer = clip === undefined && loop === undefined) => { let releaseTime = endTime; if (playWholeBuffer) { + const bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value; releaseTime = t + (end - begin) * bufferDuration; } bufferSource.stop(releaseTime + release); From 6de04f77817c4ed739ec580ef3b1d638a790490e Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 10 Sep 2023 23:29:09 +0200 Subject: [PATCH 029/175] turn loop on for samples starting with wt_ --- packages/superdough/sampler.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 26611c0a..28f09082 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -196,7 +196,7 @@ export const samples = async (sampleMap, baseUrl = sampleMap._base || '', option const cutGroups = []; export async function onTriggerSample(t, value, onended, bank, resolveUrl) { - const { + let { s, freq, unit, @@ -217,6 +217,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { // no playback return; } + loop = s.startsWith('wt_') ? 1 : value.loop; const ac = getAudioContext(); // destructure adsr here, because the default should be different for synths and samples const { attack = 0.001, decay = 0.001, sustain = 1, release = 0.001 } = value; From 7a74189771f2d14ab584275d9423f158ebb4d1d9 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 11 Sep 2023 00:41:55 +0200 Subject: [PATCH 030/175] document wavetable synthesis --- website/src/pages/learn/synths.mdx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index 6a2d7395..26e94467 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -80,14 +80,20 @@ You can use fm with any of the above waveforms, although the below examples all ## Wavetable Synthesis -Strudel can also use wavetables to create custom waveforms instead of the default ones used by WebAudio. There is a default set of wavetables accessible by default (approximatively 1000 coming from the [AKWF](https://www.adventurekid.se/akrt/waveforms/adventure-kid-waveforms/) set) but you can also import/use your own. A wavetable is a one-cycle waveform, which is then repeated to create a sound at the desired frequency. It is a classic but very effective synthesis technique. Wavetable synthesis is based on sample looping, using the `loop`, `loopBegin` and `loopEnd` properties of the sampler: +Strudel can also use the sampler to load custom waveforms as a replacement of the default waveforms used by WebAudio for the base synth. A default set of more than 1000 wavetables is accessible by default (coming from the [AKWF](https://www.adventurekid.se/akrt/waveforms/adventure-kid-waveforms/) set). You can also import/use your own. A wavetable is a one-cycle waveform, which is then repeated to create a sound at the desired frequency. It is a classic but very effective synthesis technique. -- `loop`: either `0` (no loop) or `1` (loop) -- `loopBegin`: start of the loop (between 0 and 1) -- `loopEnd`: end of the loop (between 0 and 1) +Any sample preceded by the `wt_` prefix will be loaded as a wavetable. This means that the `loop` argument will be set to `1` by defalt. You can scan over the wavetable by using `loopBegin` and `loopEnd` as well. - - +") +.n("<1 2 3 4 5 6 7 8 9 10>/2").room(0.5).size(0.9) +.s('wt_flute').velocity(0.25).often(n => n.ply(2)) +.release(0.125).decay("<0.1 0.25 0.3 0.4>").sustain(0) +.cutoff(2000).scope({}).cutoff("<1000 2000 4000>").fast(2)`} +/> ## ZZFX From 843d9d52c33b33b6d4b3f556ee325e629b28c9ba Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 11 Sep 2023 00:46:31 +0200 Subject: [PATCH 031/175] add documentation but it crashes --- packages/core/controls.mjs | 13 +++++++++---- website/src/pages/learn/samples.mdx | 12 ++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 4d427da3..a490463d 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -314,8 +314,10 @@ const generic_params = [ * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample * @synonyms loopb * @example - * s("numbers").loopBegin("<0 .25 .5 .75>").loop(1) - * + * s("numbers") + * .loop(1) + * .begin(0).end(1) + * .loopBegin("<0 .25 .5 .75>") */ ['loopBegin', 'loopb'], /** @@ -323,8 +325,11 @@ const generic_params = [ * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample * @synonyms loope * @example - * s("numbers").loopEnd("<0 .25 .5 .75>").loop(1) - * + * s("numbers") + * .loop(1) + * .begin(0).end(1) + * .loopBegin("<0 .25 .5 .75>") + * .loopEnd("<0.1 .35 .6 .85>") */ ['loopEnd', 'loope'], /** diff --git a/website/src/pages/learn/samples.mdx b/website/src/pages/learn/samples.mdx index 9f79e54a..b1ef1cd3 100644 --- a/website/src/pages/learn/samples.mdx +++ b/website/src/pages/learn/samples.mdx @@ -303,6 +303,18 @@ Sampler effects are functions that can be used to change the behaviour of sample +### loop + + + +### loopBegin + + + +### loopEnd + + + ### cut From 4a65113bff85ee36dba1511c2f17e9015496aaea Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 11 Sep 2023 00:52:49 +0200 Subject: [PATCH 032/175] do not panic when no description --- website/src/docs/JsDoc.jsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/website/src/docs/JsDoc.jsx b/website/src/docs/JsDoc.jsx index 88a775a5..1ba80e0a 100644 --- a/website/src/docs/JsDoc.jsx +++ b/website/src/docs/JsDoc.jsx @@ -12,10 +12,11 @@ export function JsDoc({ name, h = 3, hideDescription, punchcard, canvasHeight }) } const synonyms = getTag('synonyms', item)?.split(', ') || []; const CustomHeading = `h${h}`; - const description = item.description.replaceAll(/\{@link ([a-zA-Z\.]+)?#?([a-zA-Z]*)\}/g, (_, a, b) => { - // console.log(_, 'a', a, 'b', b); - return `${a}${b ? `#${b}` : ''}`; - }); + const description = + item.description?.replaceAll(/\{@link ([a-zA-Z\.]+)?#?([a-zA-Z]*)\}/g, (_, a, b) => { + // console.log(_, 'a', a, 'b', b); + return `${a}${b ? `#${b}` : ''}`; + }) || ''; return ( <> {!!h && {item.longname}} From 78adaaedef56b45095cdce922292989980838cb2 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 11 Sep 2023 00:56:43 +0200 Subject: [PATCH 033/175] fixing minor bugs and adding description --- packages/core/controls.mjs | 7 +++++++ packages/superdough/sampler.mjs | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index a490463d..42f98a17 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -310,6 +310,9 @@ const generic_params = [ */ ['loop'], /** + * Begin to loop at a specific point in the sample (inbetween `begin` and `end`). + * Note that the loop point must be inbetween `begin` and `end`, and before `loopEnd`! + * * @name loopBegin * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample * @synonyms loopb @@ -321,6 +324,10 @@ const generic_params = [ */ ['loopBegin', 'loopb'], /** + * + * End the looping section at a specific point in the sample (inbetween `begin` and `end`). + * Note that the loop point must be inbetween `begin` and `end`, and after `loopBegin`! + * * @name loopEnd * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample * @synonyms loope diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 28f09082..76b6a542 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -249,7 +249,6 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { bufferSource.loop = true; bufferSource.loopStart = loopBegin * bufferSource.buffer.duration - offset; bufferSource.loopEnd = loopEnd * bufferSource.buffer.duration - offset; - duration = loop * duration; } bufferSource.start(time, offset); const { node: envelope, stop: releaseEnvelope } = getEnvelope(attack, decay, sustain, release, 1, t); From 4cb93ddcded1d14794787de057c1a59d1efbb1c1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 13 Sep 2023 12:59:51 +0200 Subject: [PATCH 034/175] fix: eval scope --- website/src/repl/Repl.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 173bb455..eb61a216 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -33,7 +33,7 @@ const supabase = createClient( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM', ); -const modules = [ +let modules = [ import('@strudel.cycles/core'), import('@strudel.cycles/tonal'), import('@strudel.cycles/mini'), @@ -45,13 +45,13 @@ const modules = [ import('@strudel.cycles/csound'), ]; if (isTauri()) { - modules.concat([ + modules = modules.concat([ import('@strudel/desktopbridge/loggerbridge.mjs'), import('@strudel/desktopbridge/midibridge.mjs'), import('@strudel/desktopbridge/oscbridge.mjs'), ]); } else { - modules.concat([import('@strudel.cycles/midi'), import('@strudel.cycles/osc')]); + modules = modules.concat([import('@strudel.cycles/midi'), import('@strudel.cycles/osc')]); } const modulesLoading = evalScope( From 0a8874180cf5b22c85d8a844c7035623e7230573 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 13 Sep 2023 13:48:33 +0200 Subject: [PATCH 035/175] generalize getDevice + begin midiIn implementation --- packages/midi/midi.mjs | 49 ++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index 98509b46..831c3afd 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -8,6 +8,7 @@ import * as _WebMidi from 'webmidi'; import { Pattern, isPattern, logger } from '@strudel.cycles/core'; import { noteToMidi } from '@strudel.cycles/core'; import { Note } from 'webmidi'; +import EventEmitter from 'events'; // if you use WebMidi from outside of this package, make sure to import that instance: export const { WebMidi } = _WebMidi; @@ -15,8 +16,8 @@ function supportsMidi() { return typeof navigator.requestMIDIAccess === 'function'; } -function getMidiDeviceNamesString(outputs) { - return outputs.map((o) => `'${o.name}'`).join(' | '); +function getMidiDeviceNamesString(devices) { + return devices.map((o) => `'${o.name}'`).join(' | '); } export function enableWebMidi(options = {}) { @@ -52,26 +53,24 @@ export function enableWebMidi(options = {}) { }); }); } -// const outputByName = (name: string) => WebMidi.getOutputByName(name); -const outputByName = (name) => WebMidi.getOutputByName(name); -// output?: string | number, outputs: typeof WebMidi.outputs -function getDevice(output, outputs) { - if (!outputs.length) { +function getDevice(indexOrName, devices) { + if (!devices.length) { throw new Error(`🔌 No MIDI devices found. Connect a device or enable IAC Driver.`); } - if (typeof output === 'number') { - return outputs[output]; + if (typeof indexOrName === 'number') { + return devices[indexOrName]; } - if (typeof output === 'string') { - return outputByName(output); + const byName = (name) => devices.find((output) => output.name.includes(name)); + if (typeof indexOrName === 'string') { + return byName(indexOrName); } // attempt to default to first IAC device if none is specified - const IACOutput = outputs.find((output) => output.name.includes('IAC')); - const device = IACOutput ?? outputs[0]; + const IACOutput = byName('IAC'); + const device = IACOutput ?? devices[0]; if (!device) { throw new Error( - `🔌 MIDI device '${output ? output : ''}' not found. Use one of ${getMidiDeviceNamesString(WebMidi.outputs)}`, + `🔌 MIDI device '${device ? device : ''}' not found. Use one of ${getMidiDeviceNamesString(devices)}`, ); } @@ -137,3 +136,25 @@ Pattern.prototype.midi = function (output) { } }); }; + +export async function midiIn(input) { + console.log('midi in...'); + const initial = await enableWebMidi(); // only returns on first init + const device = getDevice(input, WebMidi.inputs); + + if (initial) { + const otherInputs = WebMidi.inputs.filter((o) => o.name !== device.name); + logger( + `Midi enabled! Using "${device.name}". ${ + otherInputs?.length ? `Also available: ${getMidiDeviceNamesString(otherInputs)}` : '' + }`, + ); + } + return (fn) => { + device.addListener(EventEmitter.ANY_EVENT, (...args) => { + console.log('event!', args); + fn(args); + }); + return; + }; +} From 0f72729f0de9fedd7e4bdccf8c717746351942c8 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 14 Sep 2023 09:36:06 +0200 Subject: [PATCH 036/175] midi cc input poc --- packages/core/pattern.mjs | 6 ++++++ packages/midi/midi.mjs | 24 ++++++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 7e694f49..d29fde3f 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2336,3 +2336,9 @@ export const fit = register('fit', (pat) => export const { loopAtCps, loopatcps } = register(['loopAtCps', 'loopatcps'], function (factor, cps, pat) { return _loopAt(factor, pat, cps); }); + +/** exposes a custom value at query time. basically allows mutating state without evaluation */ +export const ref = (accessor) => + pure(1) + .withValue(() => reify(accessor())) + .innerJoin(); diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index 831c3afd..95af837e 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -8,7 +8,6 @@ import * as _WebMidi from 'webmidi'; import { Pattern, isPattern, logger } from '@strudel.cycles/core'; import { noteToMidi } from '@strudel.cycles/core'; import { Note } from 'webmidi'; -import EventEmitter from 'events'; // if you use WebMidi from outside of this package, make sure to import that instance: export const { WebMidi } = _WebMidi; @@ -137,7 +136,10 @@ Pattern.prototype.midi = function (output) { }); }; -export async function midiIn(input) { +let listeners = {}; +const refs = {}; + +export async function midin(input) { console.log('midi in...'); const initial = await enableWebMidi(); // only returns on first init const device = getDevice(input, WebMidi.inputs); @@ -149,12 +151,18 @@ export async function midiIn(input) { otherInputs?.length ? `Also available: ${getMidiDeviceNamesString(otherInputs)}` : '' }`, ); + refs[input] = {}; } - return (fn) => { - device.addListener(EventEmitter.ANY_EVENT, (...args) => { - console.log('event!', args); - fn(args); - }); - return; + const cc = (cc) => ref(() => refs[input][cc] || 0); + + listeners[input] && device.removeListener('midimessage', listeners[input]); + listeners[input] = (e) => { + const cc = e.dataBytes[0]; + const v = e.dataBytes[1]; + console.log(cc, v); + refs[input][cc] = v / 127; }; + device.addListener('midimessage', listeners[input]); + //return { cc }; + return cc; } From 3a69fd50bb7d0c314dae7f961e7beae1f6c674a1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 14 Sep 2023 09:39:31 +0200 Subject: [PATCH 037/175] fix: linting errors --- packages/midi/midi.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index 95af837e..bc65497a 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th */ import * as _WebMidi from 'webmidi'; -import { Pattern, isPattern, logger } from '@strudel.cycles/core'; +import { Pattern, isPattern, logger, ref } from '@strudel.cycles/core'; import { noteToMidi } from '@strudel.cycles/core'; import { Note } from 'webmidi'; // if you use WebMidi from outside of this package, make sure to import that instance: @@ -73,7 +73,7 @@ function getDevice(indexOrName, devices) { ); } - return IACOutput ?? outputs[0]; + return IACOutput ?? devices[0]; } Pattern.prototype.midi = function (output) { From 30d96dcb65fd176ea6c515e9145d4181358de04a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 14 Sep 2023 16:28:47 +0200 Subject: [PATCH 038/175] remove log --- packages/midi/midi.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index bc65497a..688b7a9b 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -159,7 +159,6 @@ export async function midin(input) { listeners[input] = (e) => { const cc = e.dataBytes[0]; const v = e.dataBytes[1]; - console.log(cc, v); refs[input][cc] = v / 127; }; device.addListener('midimessage', listeners[input]); From 445881992ed15962482ab61b5270c64ef666ea23 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 15 Sep 2023 21:43:03 +0200 Subject: [PATCH 039/175] slow down examples + simplify --- packages/core/controls.mjs | 55 +++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 3bdb885b..c31c68aa 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -384,8 +384,11 @@ const generic_params = [ * @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_ * @synonyms lpe * @example - * note("c2 c3").fast(2).sound("sawtooth") - * .cutoff(500).lpenv("<1 2 3 4 5 6 7 8>") + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpa(.1).lpd(.1).lps(.5) + * .lpenv("<8 4 2 0>/4") */ ['lpenv', 'lpe'], /** @@ -414,10 +417,11 @@ const generic_params = [ * @param {number | Pattern} attack time of the filter envelope * @synonyms lpa * @example - * note("c3 e3 f3 g3 ab3 bb3") - * .sound('square').cutoff(1000) - * .lpattack("<0.05 0.1 0.25 0.5>/2").ftype("12db") - * .release(0.2).attack(0) + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpa("<.5 .25 .1 .01>/4") + * .lpenv(4) */ ['lpattack', 'lpa'], /** @@ -428,7 +432,7 @@ const generic_params = [ * @example * note("c3 e3 f3 g3 ab3 bb3") * .sound('square').hcutoff(1000) - * .hpattack("<0.05 0.1 0.25 0.5>/2").ftype("12db") + * .hpattack("<0.5 0.25 0.1 0.01>/2").ftype("12db") * .release(0.2).attack(0) */ ['hpattack', 'hpa'], @@ -450,11 +454,12 @@ const generic_params = [ * @param {number | Pattern} decay time of the filter envelope * @synonyms lpd * @example - * "baba" - * note("c3 e3 f3 g3 ab3 bb3") - * .sound('square').cutoff(1000) - * .lpdecay("<0.05 0.1 0.125>/2") - * .ftype("12db").lps(0).lpr(0) + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpd("<.5 .25 .1 0>/4") + * .lps(0.2) + * .lpenv(4) */ ['lpdecay', 'lpd'], /** @@ -489,15 +494,17 @@ const generic_params = [ * @param {number | Pattern} sustain amplitude of the lowpass filter envelope * @synonyms lps * @example - * note("c3 e3 f3 g3 ab3 bb3") - * .sound('square').cutoff(200) - * .lpd(0.1).lpsustain("<0.1 0.5 0.75 1>") - * .ftype("12db") + * note("") + * .sound('sawtooth') + * .lpf(0) + * .lpd(.5) + * .lps("<0 .25 .5 1>/4") + * .lpenv(4) */ ['lpsustain', 'lps'], /** * Sets the sustain amplitude for the highpass filter envelope. - * @name lpsustain + * @name hpsustain * @param {number | Pattern} sustain amplitude of the highpass filter envelope * @synonyms hps * @example @@ -509,7 +516,7 @@ const generic_params = [ ['hpsustain', 'hps'], /** * Sets the sustain amplitude for the bandpass filter envelope. - * @name lpsustain + * @name hpsustain * @param {number | Pattern} sustain amplitude of the bandpass filter envelope * @synonyms bps * @example @@ -525,12 +532,18 @@ const generic_params = [ * @param {number | Pattern} release time of the filter envelope * @synonyms lpr * @example - * note("c3 e3 g3 c4").lpr("<0.1 0.25 0.5>").ftype("12db") + * note("") + * .sound('sawtooth') + * .clip(.5) + * .lpf(0) + * .lpenv(4) + * .lpr("<.5 .25 .1 0>/4") + * .release(.5) */ ['lprelease', 'lpr'], /** * Sets the release time for the highpass filter envelope. - * @name lprelease + * @name hprelease * @param {number | Pattern} release time of the highpass filter envelope * @synonyms hpr * @example @@ -539,7 +552,7 @@ const generic_params = [ ['hprelease', 'hpr'], /** * Sets the release time for the bandpass filter envelope. - * @name lprelease + * @name bprelease * @param {number | Pattern} release time of the bandpass filter envelope * @synonyms bpr * @example From b8932390f7c0f40a9a4f258844d662b10f3e2805 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 15 Sep 2023 21:44:24 +0200 Subject: [PATCH 040/175] update snapshot --- test/__snapshots__/examples.test.mjs.snap | 372 +++++++++------------- 1 file changed, 144 insertions(+), 228 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 4cb261ae..7f9dd6f9 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -988,6 +988,27 @@ exports[`runs examples > example "bpq" example index 0 1`] = ` ] `; +exports[`runs examples > example "bprelease" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c3 bprelease:0.1 ftype:12db ]", + "[ 1/4 → 1/2 | note:e3 bprelease:0.1 ftype:12db ]", + "[ 1/2 → 3/4 | note:g3 bprelease:0.1 ftype:12db ]", + "[ 3/4 → 1/1 | note:c4 bprelease:0.1 ftype:12db ]", + "[ 1/1 → 5/4 | note:c3 bprelease:0.25 ftype:12db ]", + "[ 5/4 → 3/2 | note:e3 bprelease:0.25 ftype:12db ]", + "[ 3/2 → 7/4 | note:g3 bprelease:0.25 ftype:12db ]", + "[ 7/4 → 2/1 | note:c4 bprelease:0.25 ftype:12db ]", + "[ 2/1 → 9/4 | note:c3 bprelease:0.5 ftype:12db ]", + "[ 9/4 → 5/2 | note:e3 bprelease:0.5 ftype:12db ]", + "[ 5/2 → 11/4 | note:g3 bprelease:0.5 ftype:12db ]", + "[ 11/4 → 3/1 | note:c4 bprelease:0.5 ftype:12db ]", + "[ 3/1 → 13/4 | note:c3 bprelease:0.1 ftype:12db ]", + "[ 13/4 → 7/2 | note:e3 bprelease:0.1 ftype:12db ]", + "[ 7/2 → 15/4 | note:g3 bprelease:0.1 ftype:12db ]", + "[ 15/4 → 4/1 | note:c4 bprelease:0.1 ftype:12db ]", +] +`; + exports[`runs examples > example "cat" example index 0 1`] = ` [ "[ 0/1 → 1/2 | s:hh ]", @@ -2102,30 +2123,30 @@ exports[`runs examples > example "gain" example index 0 1`] = ` exports[`runs examples > example "hpattack" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/6 → 1/3 | note:e3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/3 → 1/2 | note:f3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/2 → 2/3 | note:g3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 2/3 → 5/6 | note:ab3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 5/6 → 1/1 | note:bb3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/1 → 7/6 | note:c3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 7/6 → 4/3 | note:e3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 4/3 → 3/2 | note:f3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 3/2 → 5/3 | note:g3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 5/3 → 11/6 | note:ab3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 11/6 → 2/1 | note:bb3 s:square hcutoff:1000 hpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 2/1 → 13/6 | note:c3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 13/6 → 7/3 | note:e3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 7/3 → 5/2 | note:f3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 5/2 → 8/3 | note:g3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 8/3 → 17/6 | note:ab3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 17/6 → 3/1 | note:bb3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 3/1 → 19/6 | note:c3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 19/6 → 10/3 | note:e3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 10/3 → 7/2 | note:f3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 7/2 → 11/3 | note:g3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 11/3 → 23/6 | note:ab3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 23/6 → 4/1 | note:bb3 s:square hcutoff:1000 hpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 0/1 → 1/6 | note:c3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 1/6 → 1/3 | note:e3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 1/3 → 1/2 | note:f3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 1/2 → 2/3 | note:g3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 2/3 → 5/6 | note:ab3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 5/6 → 1/1 | note:bb3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 1/1 → 7/6 | note:c3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 7/6 → 4/3 | note:e3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 4/3 → 3/2 | note:f3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 3/2 → 5/3 | note:g3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 5/3 → 11/6 | note:ab3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 11/6 → 2/1 | note:bb3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", + "[ 2/1 → 13/6 | note:c3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 13/6 → 7/3 | note:e3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 7/3 → 5/2 | note:f3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 5/2 → 8/3 | note:g3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 8/3 → 17/6 | note:ab3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 17/6 → 3/1 | note:bb3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 3/1 → 19/6 | note:c3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 19/6 → 10/3 | note:e3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 10/3 → 7/2 | note:f3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 7/2 → 11/3 | note:g3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 11/3 → 23/6 | note:ab3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", + "[ 23/6 → 4/1 | note:bb3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", ] `; @@ -2295,6 +2316,85 @@ exports[`runs examples > example "hpq" example index 0 1`] = ` ] `; +exports[`runs examples > example "hprelease" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c3 hprelease:0.1 ftype:12db ]", + "[ 1/4 → 1/2 | note:e3 hprelease:0.1 ftype:12db ]", + "[ 1/2 → 3/4 | note:g3 hprelease:0.1 ftype:12db ]", + "[ 3/4 → 1/1 | note:c4 hprelease:0.1 ftype:12db ]", + "[ 1/1 → 5/4 | note:c3 hprelease:0.25 ftype:12db ]", + "[ 5/4 → 3/2 | note:e3 hprelease:0.25 ftype:12db ]", + "[ 3/2 → 7/4 | note:g3 hprelease:0.25 ftype:12db ]", + "[ 7/4 → 2/1 | note:c4 hprelease:0.25 ftype:12db ]", + "[ 2/1 → 9/4 | note:c3 hprelease:0.5 ftype:12db ]", + "[ 9/4 → 5/2 | note:e3 hprelease:0.5 ftype:12db ]", + "[ 5/2 → 11/4 | note:g3 hprelease:0.5 ftype:12db ]", + "[ 11/4 → 3/1 | note:c4 hprelease:0.5 ftype:12db ]", + "[ 3/1 → 13/4 | note:c3 hprelease:0.1 ftype:12db ]", + "[ 13/4 → 7/2 | note:e3 hprelease:0.1 ftype:12db ]", + "[ 7/2 → 15/4 | note:g3 hprelease:0.1 ftype:12db ]", + "[ 15/4 → 4/1 | note:c4 hprelease:0.1 ftype:12db ]", +] +`; + +exports[`runs examples > example "hpsustain" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 1/6 → 1/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 1/3 → 1/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 1/2 → 2/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 2/3 → 5/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 5/6 → 1/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", + "[ 1/1 → 7/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 7/6 → 4/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 4/3 → 3/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 3/2 → 5/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 5/3 → 11/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 11/6 → 2/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", + "[ 2/1 → 13/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 13/6 → 7/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 7/3 → 5/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 5/2 → 8/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 8/3 → 17/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 17/6 → 3/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", + "[ 3/1 → 19/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", + "[ 19/6 → 10/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", + "[ 10/3 → 7/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", + "[ 7/2 → 11/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", + "[ 11/3 → 23/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", + "[ 23/6 → 4/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", +] +`; + +exports[`runs examples > example "hpsustain" example index 0 2`] = ` +[ + "[ 0/1 → 1/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 1/6 → 1/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 1/3 → 1/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 1/2 → 2/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 2/3 → 5/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 5/6 → 1/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", + "[ 1/1 → 7/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 7/6 → 4/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 4/3 → 3/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 3/2 → 5/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 5/3 → 11/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 11/6 → 2/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", + "[ 2/1 → 13/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 13/6 → 7/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 7/3 → 5/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 5/2 → 8/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 8/3 → 17/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 17/6 → 3/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", + "[ 3/1 → 19/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 19/6 → 10/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 10/3 → 7/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 7/2 → 11/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 11/3 → 23/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 23/6 → 4/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", +] +`; + exports[`runs examples > example "hurry" example index 0 1`] = ` [ "[ 0/1 → 3/4 | s:bd speed:1 ]", @@ -2726,80 +2826,28 @@ exports[`runs examples > example "loopAtCps" example index 0 1`] = ` exports[`runs examples > example "lpattack" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/6 → 1/3 | note:e3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/3 → 1/2 | note:f3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/2 → 2/3 | note:g3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 2/3 → 5/6 | note:ab3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 5/6 → 1/1 | note:bb3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/1 → 7/6 | note:c3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 7/6 → 4/3 | note:e3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 4/3 → 3/2 | note:f3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 3/2 → 5/3 | note:g3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 5/3 → 11/6 | note:ab3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 11/6 → 2/1 | note:bb3 s:square cutoff:1000 lpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 2/1 → 13/6 | note:c3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 13/6 → 7/3 | note:e3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 7/3 → 5/2 | note:f3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 5/2 → 8/3 | note:g3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 8/3 → 17/6 | note:ab3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 17/6 → 3/1 | note:bb3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 3/1 → 19/6 | note:c3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 19/6 → 10/3 | note:e3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 10/3 → 7/2 | note:f3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 7/2 → 11/3 | note:g3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 11/3 → 23/6 | note:ab3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 23/6 → 4/1 | note:bb3 s:square cutoff:1000 lpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:500 lpattack:0.5 lpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth cutoff:500 lpattack:0.5 lpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth cutoff:500 lpattack:0.5 lpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth cutoff:500 lpattack:0.5 lpenv:4 ]", ] `; exports[`runs examples > example "lpdecay" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 1/6 → 1/3 | note:e3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 1/3 → 1/2 | note:f3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 1/2 → 2/3 | note:g3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 2/3 → 5/6 | note:ab3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 5/6 → 1/1 | note:bb3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 1/1 → 7/6 | note:c3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 7/6 → 4/3 | note:e3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 4/3 → 3/2 | note:f3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 3/2 → 5/3 | note:g3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 5/3 → 11/6 | note:ab3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 11/6 → 2/1 | note:bb3 s:square cutoff:1000 lpdecay:0.05 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 2/1 → 13/6 | note:c3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 13/6 → 7/3 | note:e3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 7/3 → 5/2 | note:f3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 5/2 → 8/3 | note:g3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 8/3 → 17/6 | note:ab3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 17/6 → 3/1 | note:bb3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 3/1 → 19/6 | note:c3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 19/6 → 10/3 | note:e3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 10/3 → 7/2 | note:f3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 7/2 → 11/3 | note:g3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 11/3 → 23/6 | note:ab3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", - "[ 23/6 → 4/1 | note:bb3 s:square cutoff:1000 lpdecay:0.1 ftype:12db lpsustain:0 lprelease:0 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:500 lpdecay:0.5 lpsustain:0.2 lpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth cutoff:500 lpdecay:0.5 lpsustain:0.2 lpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth cutoff:500 lpdecay:0.5 lpsustain:0.2 lpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth cutoff:500 lpdecay:0.5 lpsustain:0.2 lpenv:4 ]", ] `; exports[`runs examples > example "lpenv" example index 0 1`] = ` [ - "[ 0/1 → 1/4 | note:c2 s:sawtooth cutoff:500 lpenv:1 ]", - "[ 1/4 → 1/2 | note:c3 s:sawtooth cutoff:500 lpenv:1 ]", - "[ 1/2 → 3/4 | note:c2 s:sawtooth cutoff:500 lpenv:1 ]", - "[ 3/4 → 1/1 | note:c3 s:sawtooth cutoff:500 lpenv:1 ]", - "[ 1/1 → 5/4 | note:c2 s:sawtooth cutoff:500 lpenv:2 ]", - "[ 5/4 → 3/2 | note:c3 s:sawtooth cutoff:500 lpenv:2 ]", - "[ 3/2 → 7/4 | note:c2 s:sawtooth cutoff:500 lpenv:2 ]", - "[ 7/4 → 2/1 | note:c3 s:sawtooth cutoff:500 lpenv:2 ]", - "[ 2/1 → 9/4 | note:c2 s:sawtooth cutoff:500 lpenv:3 ]", - "[ 9/4 → 5/2 | note:c3 s:sawtooth cutoff:500 lpenv:3 ]", - "[ 5/2 → 11/4 | note:c2 s:sawtooth cutoff:500 lpenv:3 ]", - "[ 11/4 → 3/1 | note:c3 s:sawtooth cutoff:500 lpenv:3 ]", - "[ 3/1 → 13/4 | note:c2 s:sawtooth cutoff:500 lpenv:4 ]", - "[ 13/4 → 7/2 | note:c3 s:sawtooth cutoff:500 lpenv:4 ]", - "[ 7/2 → 15/4 | note:c2 s:sawtooth cutoff:500 lpenv:4 ]", - "[ 15/4 → 4/1 | note:c3 s:sawtooth cutoff:500 lpenv:4 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:500 lpattack:0.1 lpdecay:0.1 lpsustain:0.5 lpenv:8 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth cutoff:500 lpattack:0.1 lpdecay:0.1 lpsustain:0.5 lpenv:8 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth cutoff:500 lpattack:0.1 lpdecay:0.1 lpsustain:0.5 lpenv:8 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth cutoff:500 lpattack:0.1 lpdecay:0.1 lpsustain:0.5 lpenv:8 ]", ] `; @@ -2896,151 +2944,19 @@ exports[`runs examples > example "lpq" example index 0 1`] = ` exports[`runs examples > example "lprelease" example index 0 1`] = ` [ - "[ 0/1 → 1/4 | note:c3 lprelease:0.1 ftype:12db ]", - "[ 1/4 → 1/2 | note:e3 lprelease:0.1 ftype:12db ]", - "[ 1/2 → 3/4 | note:g3 lprelease:0.1 ftype:12db ]", - "[ 3/4 → 1/1 | note:c4 lprelease:0.1 ftype:12db ]", - "[ 1/1 → 5/4 | note:c3 lprelease:0.25 ftype:12db ]", - "[ 5/4 → 3/2 | note:e3 lprelease:0.25 ftype:12db ]", - "[ 3/2 → 7/4 | note:g3 lprelease:0.25 ftype:12db ]", - "[ 7/4 → 2/1 | note:c4 lprelease:0.25 ftype:12db ]", - "[ 2/1 → 9/4 | note:c3 lprelease:0.5 ftype:12db ]", - "[ 9/4 → 5/2 | note:e3 lprelease:0.5 ftype:12db ]", - "[ 5/2 → 11/4 | note:g3 lprelease:0.5 ftype:12db ]", - "[ 11/4 → 3/1 | note:c4 lprelease:0.5 ftype:12db ]", - "[ 3/1 → 13/4 | note:c3 lprelease:0.1 ftype:12db ]", - "[ 13/4 → 7/2 | note:e3 lprelease:0.1 ftype:12db ]", - "[ 7/2 → 15/4 | note:g3 lprelease:0.1 ftype:12db ]", - "[ 15/4 → 4/1 | note:c4 lprelease:0.1 ftype:12db ]", -] -`; - -exports[`runs examples > example "lprelease" example index 0 2`] = ` -[ - "[ 0/1 → 1/4 | note:c3 hprelease:0.1 ftype:12db ]", - "[ 1/4 → 1/2 | note:e3 hprelease:0.1 ftype:12db ]", - "[ 1/2 → 3/4 | note:g3 hprelease:0.1 ftype:12db ]", - "[ 3/4 → 1/1 | note:c4 hprelease:0.1 ftype:12db ]", - "[ 1/1 → 5/4 | note:c3 hprelease:0.25 ftype:12db ]", - "[ 5/4 → 3/2 | note:e3 hprelease:0.25 ftype:12db ]", - "[ 3/2 → 7/4 | note:g3 hprelease:0.25 ftype:12db ]", - "[ 7/4 → 2/1 | note:c4 hprelease:0.25 ftype:12db ]", - "[ 2/1 → 9/4 | note:c3 hprelease:0.5 ftype:12db ]", - "[ 9/4 → 5/2 | note:e3 hprelease:0.5 ftype:12db ]", - "[ 5/2 → 11/4 | note:g3 hprelease:0.5 ftype:12db ]", - "[ 11/4 → 3/1 | note:c4 hprelease:0.5 ftype:12db ]", - "[ 3/1 → 13/4 | note:c3 hprelease:0.1 ftype:12db ]", - "[ 13/4 → 7/2 | note:e3 hprelease:0.1 ftype:12db ]", - "[ 7/2 → 15/4 | note:g3 hprelease:0.1 ftype:12db ]", - "[ 15/4 → 4/1 | note:c4 hprelease:0.1 ftype:12db ]", -] -`; - -exports[`runs examples > example "lprelease" example index 0 3`] = ` -[ - "[ 0/1 → 1/4 | note:c3 bprelease:0.1 ftype:12db ]", - "[ 1/4 → 1/2 | note:e3 bprelease:0.1 ftype:12db ]", - "[ 1/2 → 3/4 | note:g3 bprelease:0.1 ftype:12db ]", - "[ 3/4 → 1/1 | note:c4 bprelease:0.1 ftype:12db ]", - "[ 1/1 → 5/4 | note:c3 bprelease:0.25 ftype:12db ]", - "[ 5/4 → 3/2 | note:e3 bprelease:0.25 ftype:12db ]", - "[ 3/2 → 7/4 | note:g3 bprelease:0.25 ftype:12db ]", - "[ 7/4 → 2/1 | note:c4 bprelease:0.25 ftype:12db ]", - "[ 2/1 → 9/4 | note:c3 bprelease:0.5 ftype:12db ]", - "[ 9/4 → 5/2 | note:e3 bprelease:0.5 ftype:12db ]", - "[ 5/2 → 11/4 | note:g3 bprelease:0.5 ftype:12db ]", - "[ 11/4 → 3/1 | note:c4 bprelease:0.5 ftype:12db ]", - "[ 3/1 → 13/4 | note:c3 bprelease:0.1 ftype:12db ]", - "[ 13/4 → 7/2 | note:e3 bprelease:0.1 ftype:12db ]", - "[ 7/2 → 15/4 | note:g3 bprelease:0.1 ftype:12db ]", - "[ 15/4 → 4/1 | note:c4 bprelease:0.1 ftype:12db ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth clip:0.5 cutoff:0 lpenv:4 lprelease:0.5 release:0.5 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth clip:0.5 cutoff:0 lpenv:4 lprelease:0.5 release:0.5 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth clip:0.5 cutoff:0 lpenv:4 lprelease:0.5 release:0.5 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth clip:0.5 cutoff:0 lpenv:4 lprelease:0.5 release:0.5 ]", ] `; exports[`runs examples > example "lpsustain" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", - "[ 1/6 → 1/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", - "[ 1/3 → 1/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", - "[ 1/2 → 2/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", - "[ 2/3 → 5/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", - "[ 5/6 → 1/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.1 ftype:12db ]", - "[ 1/1 → 7/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", - "[ 7/6 → 4/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", - "[ 4/3 → 3/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", - "[ 3/2 → 5/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", - "[ 5/3 → 11/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", - "[ 11/6 → 2/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.5 ftype:12db ]", - "[ 2/1 → 13/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", - "[ 13/6 → 7/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", - "[ 7/3 → 5/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", - "[ 5/2 → 8/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", - "[ 8/3 → 17/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", - "[ 17/6 → 3/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:0.75 ftype:12db ]", - "[ 3/1 → 19/6 | note:c3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", - "[ 19/6 → 10/3 | note:e3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", - "[ 10/3 → 7/2 | note:f3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", - "[ 7/2 → 11/3 | note:g3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", - "[ 11/3 → 23/6 | note:ab3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", - "[ 23/6 → 4/1 | note:bb3 s:square cutoff:200 lpdecay:0.1 lpsustain:1 ftype:12db ]", -] -`; - -exports[`runs examples > example "lpsustain" example index 0 2`] = ` -[ - "[ 0/1 → 1/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 1/6 → 1/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 1/3 → 1/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 1/2 → 2/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 2/3 → 5/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 5/6 → 1/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 1/1 → 7/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 7/6 → 4/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 4/3 → 3/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 3/2 → 5/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 5/3 → 11/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 11/6 → 2/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 2/1 → 13/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 13/6 → 7/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 7/3 → 5/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 5/2 → 8/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 8/3 → 17/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 17/6 → 3/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 3/1 → 19/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", - "[ 19/6 → 10/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", - "[ 10/3 → 7/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", - "[ 7/2 → 11/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", - "[ 11/3 → 23/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", - "[ 23/6 → 4/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", -] -`; - -exports[`runs examples > example "lpsustain" example index 0 3`] = ` -[ - "[ 0/1 → 1/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 1/6 → 1/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 1/3 → 1/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 1/2 → 2/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 2/3 → 5/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 5/6 → 1/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 1/1 → 7/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 7/6 → 4/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 4/3 → 3/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 3/2 → 5/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 5/3 → 11/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 11/6 → 2/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 2/1 → 13/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 13/6 → 7/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 7/3 → 5/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 5/2 → 8/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 8/3 → 17/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 17/6 → 3/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 3/1 → 19/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", - "[ 19/6 → 10/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", - "[ 10/3 → 7/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", - "[ 7/2 → 11/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", - "[ 11/3 → 23/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", - "[ 23/6 → 4/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:0 lpdecay:0.5 lpsustain:0 lpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth cutoff:0 lpdecay:0.5 lpsustain:0 lpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth cutoff:0 lpdecay:0.5 lpsustain:0 lpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth cutoff:0 lpdecay:0.5 lpsustain:0 lpenv:4 ]", ] `; From 9d5f9190234becd327b800384b30b1960063c1fb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 15 Sep 2023 23:12:39 +0200 Subject: [PATCH 041/175] add all filter envelope examples to doc --- packages/core/controls.mjs | 100 ++++++++++++++++++---------- website/src/pages/learn/effects.mdx | 69 ++++++++++++++++--- 2 files changed, 127 insertions(+), 42 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index c31c68aa..dd865df5 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -397,8 +397,17 @@ const generic_params = [ * @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_ * @synonyms hpe * @example - * note("c2 c3").fast(2).sound("sawtooth") - * .hcutoff(500).hpenv("<1 2 3 4 5 6 7 8>") + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpa(.1).hpd(.1).hps(.5) + * .hpenv("<8 4 2 0>/4") + * @example + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpa(.5) + * .hpenv("<2 -2>/4") */ ['hpenv', 'hpe'], /** @@ -407,8 +416,11 @@ const generic_params = [ * @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_ * @synonyms bpe * @example - * note("c2 c3").fast(2).sound("sawtooth") - * .bandf(500).bpenv("<1 2 3 4 5 6 7 8>") + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpa(.1).bpd(.1).bps(.5) + * .bpenv("<8 4 2 0>/4") */ ['bpenv', 'bpe'], /** @@ -430,22 +442,24 @@ const generic_params = [ * @param {number | Pattern} attack time of the highpass filter envelope * @synonyms hpa * @example - * note("c3 e3 f3 g3 ab3 bb3") - * .sound('square').hcutoff(1000) - * .hpattack("<0.5 0.25 0.1 0.01>/2").ftype("12db") - * .release(0.2).attack(0) + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpa("<.5 .25 .1 .01>/4") + * .hpenv(4) */ ['hpattack', 'hpa'], /** * Sets the attack duration for the bandpass filter envelope. - * @name hpattack + * @name bpattack * @param {number | Pattern} attack time of the bandpass filter envelope * @synonyms bpa * @example - * note("c3 e3 f3 g3 ab3 bb3") - * .sound('square').bandf(1000) - * .bpattack("<0.05 0.1 0.25 0.5>/2").ftype("12db") - * .release(0.2).attack(0) + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpa("<.5 .25 .1 .01>/4") + * .bpenv(4) */ ['bpattack', 'bpa'], /** @@ -468,11 +482,12 @@ const generic_params = [ * @param {number | Pattern} decay time of the highpass filter envelope * @synonyms hpd * @example - * "baba" - * note("c3 e3 f3 g3 ab3 bb3") - * .sound('square').hcutoff(1000) - * .hpdecay("<0.05 0.1 0.125>/2") - * .ftype("12db").hps(0).hpr(0) + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpd("<.5 .25 .1 0>/4") + * .hps(0.2) + * .hpenv(4) */ ['hpdecay', 'hpd'], /** @@ -481,11 +496,12 @@ const generic_params = [ * @param {number | Pattern} decay time of the bandpass filter envelope * @synonyms bpd * @example - * "baba" - * note("c3 e3 f3 g3 ab3 bb3") - * .sound('square').bandf(1000) - * .bpdecay("<0.05 0.1 0.125>/2") - * .ftype("12db").bps(0).bpr(0) + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpd("<.5 .25 .1 0>/4") + * .bps(0.2) + * .bpenv(4) */ ['bpdecay', 'bpd'], /** @@ -508,22 +524,26 @@ const generic_params = [ * @param {number | Pattern} sustain amplitude of the highpass filter envelope * @synonyms hps * @example - * note("c3 e3 f3 g3 ab3 bb3") - * .sound('square').hcutoff(200) - * .hpd(0.1).hpsustain("<0.1 0.5 0.75 1>") - * .ftype("12db") + * note("") + * .sound('sawtooth') + * .hpf(0) + * .hpd(.5) + * .hps("<0 .25 .5 1>/4") + * .hpenv(4) */ ['hpsustain', 'hps'], /** * Sets the sustain amplitude for the bandpass filter envelope. - * @name hpsustain + * @name bpsustain * @param {number | Pattern} sustain amplitude of the bandpass filter envelope * @synonyms bps * @example - * note("c3 e3 f3 g3 ab3 bb3") - * .sound('square').bandf(200) - * .bpd(0.1).bpsustain("<0.1 0.5 0.75 1>") - * .ftype("12db") + * note("") + * .sound('sawtooth') + * .bpf(0) + * .bpd(.5) + * .bps("<0 .25 .5 1>/4") + * .bpenv(4) */ ['bpsustain', 'bps'], /** @@ -547,7 +567,13 @@ const generic_params = [ * @param {number | Pattern} release time of the highpass filter envelope * @synonyms hpr * @example - * note("c3 e3 g3 c4").hpr("<0.1 0.25 0.5>").ftype("12db") + * note("") + * .sound('sawtooth') + * .clip(.5) + * .hpf(0) + * .hpenv(4) + * .hpr("<.5 .25 .1 0>/4") + * .release(.5) */ ['hprelease', 'hpr'], /** @@ -556,7 +582,13 @@ const generic_params = [ * @param {number | Pattern} release time of the bandpass filter envelope * @synonyms bpr * @example - * note("c3 e3 g3 c4").bpr("<0.1 0.25 0.5>").ftype("12db") + * note("") + * .sound('sawtooth') + * .clip(.5) + * .bpf(0) + * .bpenv(4) + * .bpr("<.5 .25 .1 0>/4") + * .release(.5) */ ['bprelease', 'bpr'], ['ftype'], diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index 90f9510e..62e3a52d 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -93,32 +93,85 @@ There is one filter envelope for each filter type and thus one set of envelope f ## lpattack -- Also `hpattack` and `bpattack`. - ## lpdecay -- Also `hpdecay` and `bpdecay`. - ## lpsustain -- Also `hpsustain` and `bpsustain`. - ## lprelease -- Also `hprelease` and `bprelease`. - ## lpenv +## hpattack + + + +## hpdecay + + + +## hpsustain + + + +## hprelease + + + +## hpenv + + + +## hpattack + + + +## hpdecay + + + +## hpsustain + + + +## hprelease + + + +## hpenv + + + +## bpattack + + + +## bpdecay + + + +## bpsustain + + + +## bprelease + + + +## bpenv + + + + # Dynamics ## gain From 828e4759219b49ec3d403856e6f0502cb72f5aa9 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 15 Sep 2023 23:12:51 +0200 Subject: [PATCH 042/175] support negative fenv --- packages/superdough/helpers.mjs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 45162a36..b6530343 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -1,4 +1,5 @@ import { getAudioContext } from './superdough.mjs'; +import { clamp } from './util.mjs'; export function gainNode(value) { const node = getAudioContext().createGain(); @@ -85,9 +86,19 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain filter.frequency.value = frequency; // Apply ADSR to filter frequency - if (fenv > 0) { - const min = frequency; - const max = Math.min(frequency + 200 * 2 ** fenv, 20000); + if (fenv !== 0) { + let min = 0; + let max = Math.sign(fenv) * 200 * 2 ** Math.abs(fenv); + if (max < min) { + // offset by max: keep range when *penv sign is flipped + // comment those lines out to center around cutoff instead peak + min += Math.abs(max); + max += Math.abs(max); + } + + min = clamp(min + frequency, 0, 20000); + max = clamp(max + frequency, 0, 20000); + // console.log('min', min, 'max', max); getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end); return filter; } From 7e55258bbf63c91756007254f62dd39e152ff5a6 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 15 Sep 2023 23:13:30 +0200 Subject: [PATCH 043/175] update snapshots --- test/__snapshots__/examples.test.mjs.snap | 277 +++++----------------- 1 file changed, 59 insertions(+), 218 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 7f9dd6f9..ed05a561 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -900,53 +900,30 @@ exports[`runs examples > example "begin" example index 0 1`] = ` ] `; +exports[`runs examples > example "bpattack" example index 0 1`] = ` +[ + "[ 0/1 → 1/1 | note:c2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]", +] +`; + exports[`runs examples > example "bpdecay" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 1/6 → 1/3 | note:e3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 1/3 → 1/2 | note:f3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 1/2 → 2/3 | note:g3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 2/3 → 5/6 | note:ab3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 5/6 → 1/1 | note:bb3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 1/1 → 7/6 | note:c3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 7/6 → 4/3 | note:e3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 4/3 → 3/2 | note:f3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 3/2 → 5/3 | note:g3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 5/3 → 11/6 | note:ab3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 11/6 → 2/1 | note:bb3 s:square bandf:1000 bpdecay:0.05 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 2/1 → 13/6 | note:c3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 13/6 → 7/3 | note:e3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 7/3 → 5/2 | note:f3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 5/2 → 8/3 | note:g3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 8/3 → 17/6 | note:ab3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 17/6 → 3/1 | note:bb3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 3/1 → 19/6 | note:c3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 19/6 → 10/3 | note:e3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 10/3 → 7/2 | note:f3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 7/2 → 11/3 | note:g3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 11/3 → 23/6 | note:ab3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", - "[ 23/6 → 4/1 | note:bb3 s:square bandf:1000 bpdecay:0.1 ftype:12db bpsustain:0 bprelease:0 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth bandf:500 bpdecay:0.5 bpsustain:0.2 bpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth bandf:500 bpdecay:0.5 bpsustain:0.2 bpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth bandf:500 bpdecay:0.5 bpsustain:0.2 bpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth bandf:500 bpdecay:0.5 bpsustain:0.2 bpenv:4 ]", ] `; exports[`runs examples > example "bpenv" example index 0 1`] = ` [ - "[ 0/1 → 1/4 | note:c2 s:sawtooth bandf:500 bpenv:1 ]", - "[ 1/4 → 1/2 | note:c3 s:sawtooth bandf:500 bpenv:1 ]", - "[ 1/2 → 3/4 | note:c2 s:sawtooth bandf:500 bpenv:1 ]", - "[ 3/4 → 1/1 | note:c3 s:sawtooth bandf:500 bpenv:1 ]", - "[ 1/1 → 5/4 | note:c2 s:sawtooth bandf:500 bpenv:2 ]", - "[ 5/4 → 3/2 | note:c3 s:sawtooth bandf:500 bpenv:2 ]", - "[ 3/2 → 7/4 | note:c2 s:sawtooth bandf:500 bpenv:2 ]", - "[ 7/4 → 2/1 | note:c3 s:sawtooth bandf:500 bpenv:2 ]", - "[ 2/1 → 9/4 | note:c2 s:sawtooth bandf:500 bpenv:3 ]", - "[ 9/4 → 5/2 | note:c3 s:sawtooth bandf:500 bpenv:3 ]", - "[ 5/2 → 11/4 | note:c2 s:sawtooth bandf:500 bpenv:3 ]", - "[ 11/4 → 3/1 | note:c3 s:sawtooth bandf:500 bpenv:3 ]", - "[ 3/1 → 13/4 | note:c2 s:sawtooth bandf:500 bpenv:4 ]", - "[ 13/4 → 7/2 | note:c3 s:sawtooth bandf:500 bpenv:4 ]", - "[ 7/2 → 15/4 | note:c2 s:sawtooth bandf:500 bpenv:4 ]", - "[ 15/4 → 4/1 | note:c3 s:sawtooth bandf:500 bpenv:4 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth bandf:500 bpattack:0.1 bpdecay:0.1 bpsustain:0.5 bpenv:8 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth bandf:500 bpattack:0.1 bpdecay:0.1 bpsustain:0.5 bpenv:8 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth bandf:500 bpattack:0.1 bpdecay:0.1 bpsustain:0.5 bpenv:8 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth bandf:500 bpattack:0.1 bpdecay:0.1 bpsustain:0.5 bpenv:8 ]", ] `; @@ -990,22 +967,19 @@ exports[`runs examples > example "bpq" example index 0 1`] = ` exports[`runs examples > example "bprelease" example index 0 1`] = ` [ - "[ 0/1 → 1/4 | note:c3 bprelease:0.1 ftype:12db ]", - "[ 1/4 → 1/2 | note:e3 bprelease:0.1 ftype:12db ]", - "[ 1/2 → 3/4 | note:g3 bprelease:0.1 ftype:12db ]", - "[ 3/4 → 1/1 | note:c4 bprelease:0.1 ftype:12db ]", - "[ 1/1 → 5/4 | note:c3 bprelease:0.25 ftype:12db ]", - "[ 5/4 → 3/2 | note:e3 bprelease:0.25 ftype:12db ]", - "[ 3/2 → 7/4 | note:g3 bprelease:0.25 ftype:12db ]", - "[ 7/4 → 2/1 | note:c4 bprelease:0.25 ftype:12db ]", - "[ 2/1 → 9/4 | note:c3 bprelease:0.5 ftype:12db ]", - "[ 9/4 → 5/2 | note:e3 bprelease:0.5 ftype:12db ]", - "[ 5/2 → 11/4 | note:g3 bprelease:0.5 ftype:12db ]", - "[ 11/4 → 3/1 | note:c4 bprelease:0.5 ftype:12db ]", - "[ 3/1 → 13/4 | note:c3 bprelease:0.1 ftype:12db ]", - "[ 13/4 → 7/2 | note:e3 bprelease:0.1 ftype:12db ]", - "[ 7/2 → 15/4 | note:g3 bprelease:0.1 ftype:12db ]", - "[ 15/4 → 4/1 | note:c4 bprelease:0.1 ftype:12db ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth clip:0.5 bandf:0 bpenv:4 bprelease:0.5 release:0.5 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth clip:0.5 bandf:0 bpenv:4 bprelease:0.5 release:0.5 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth clip:0.5 bandf:0 bpenv:4 bprelease:0.5 release:0.5 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth clip:0.5 bandf:0 bpenv:4 bprelease:0.5 release:0.5 ]", +] +`; + +exports[`runs examples > example "bpsustain" example index 0 1`] = ` +[ + "[ 0/1 → 1/1 | note:c2 s:sawtooth bandf:0 bpdecay:0.5 bpsustain:0 bpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth bandf:0 bpdecay:0.5 bpsustain:0 bpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth bandf:0 bpdecay:0.5 bpsustain:0 bpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth bandf:0 bpdecay:0.5 bpsustain:0 bpenv:4 ]", ] `; @@ -2123,109 +2097,37 @@ exports[`runs examples > example "gain" example index 0 1`] = ` exports[`runs examples > example "hpattack" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 1/6 → 1/3 | note:e3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 1/3 → 1/2 | note:f3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 1/2 → 2/3 | note:g3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 2/3 → 5/6 | note:ab3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 5/6 → 1/1 | note:bb3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 1/1 → 7/6 | note:c3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 7/6 → 4/3 | note:e3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 4/3 → 3/2 | note:f3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 3/2 → 5/3 | note:g3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 5/3 → 11/6 | note:ab3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 11/6 → 2/1 | note:bb3 s:square hcutoff:1000 hpattack:0.5 ftype:12db release:0.2 attack:0 ]", - "[ 2/1 → 13/6 | note:c3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 13/6 → 7/3 | note:e3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 7/3 → 5/2 | note:f3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 5/2 → 8/3 | note:g3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 8/3 → 17/6 | note:ab3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 17/6 → 3/1 | note:bb3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 3/1 → 19/6 | note:c3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 19/6 → 10/3 | note:e3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 10/3 → 7/2 | note:f3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 7/2 → 11/3 | note:g3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 11/3 → 23/6 | note:ab3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", - "[ 23/6 → 4/1 | note:bb3 s:square hcutoff:1000 hpattack:0.25 ftype:12db release:0.2 attack:0 ]", -] -`; - -exports[`runs examples > example "hpattack" example index 0 2`] = ` -[ - "[ 0/1 → 1/6 | note:c3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/6 → 1/3 | note:e3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/3 → 1/2 | note:f3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/2 → 2/3 | note:g3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 2/3 → 5/6 | note:ab3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 5/6 → 1/1 | note:bb3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 1/1 → 7/6 | note:c3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 7/6 → 4/3 | note:e3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 4/3 → 3/2 | note:f3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 3/2 → 5/3 | note:g3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 5/3 → 11/6 | note:ab3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 11/6 → 2/1 | note:bb3 s:square bandf:1000 bpattack:0.05 ftype:12db release:0.2 attack:0 ]", - "[ 2/1 → 13/6 | note:c3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 13/6 → 7/3 | note:e3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 7/3 → 5/2 | note:f3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 5/2 → 8/3 | note:g3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 8/3 → 17/6 | note:ab3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 17/6 → 3/1 | note:bb3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 3/1 → 19/6 | note:c3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 19/6 → 10/3 | note:e3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 10/3 → 7/2 | note:f3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 7/2 → 11/3 | note:g3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 11/3 → 23/6 | note:ab3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", - "[ 23/6 → 4/1 | note:bb3 s:square bandf:1000 bpattack:0.1 ftype:12db release:0.2 attack:0 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:4 ]", ] `; exports[`runs examples > example "hpdecay" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 1/6 → 1/3 | note:e3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 1/3 → 1/2 | note:f3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 1/2 → 2/3 | note:g3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 2/3 → 5/6 | note:ab3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 5/6 → 1/1 | note:bb3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 1/1 → 7/6 | note:c3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 7/6 → 4/3 | note:e3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 4/3 → 3/2 | note:f3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 3/2 → 5/3 | note:g3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 5/3 → 11/6 | note:ab3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 11/6 → 2/1 | note:bb3 s:square hcutoff:1000 hpdecay:0.05 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 2/1 → 13/6 | note:c3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 13/6 → 7/3 | note:e3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 7/3 → 5/2 | note:f3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 5/2 → 8/3 | note:g3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 8/3 → 17/6 | note:ab3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 17/6 → 3/1 | note:bb3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 3/1 → 19/6 | note:c3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 19/6 → 10/3 | note:e3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 10/3 → 7/2 | note:f3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 7/2 → 11/3 | note:g3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 11/3 → 23/6 | note:ab3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", - "[ 23/6 → 4/1 | note:bb3 s:square hcutoff:1000 hpdecay:0.1 ftype:12db hpsustain:0 hprelease:0 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth hcutoff:500 hpdecay:0.5 hpsustain:0.2 hpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth hcutoff:500 hpdecay:0.5 hpsustain:0.2 hpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth hcutoff:500 hpdecay:0.5 hpsustain:0.2 hpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth hcutoff:500 hpdecay:0.5 hpsustain:0.2 hpenv:4 ]", ] `; exports[`runs examples > example "hpenv" example index 0 1`] = ` [ - "[ 0/1 → 1/4 | note:c2 s:sawtooth hcutoff:500 hpenv:1 ]", - "[ 1/4 → 1/2 | note:c3 s:sawtooth hcutoff:500 hpenv:1 ]", - "[ 1/2 → 3/4 | note:c2 s:sawtooth hcutoff:500 hpenv:1 ]", - "[ 3/4 → 1/1 | note:c3 s:sawtooth hcutoff:500 hpenv:1 ]", - "[ 1/1 → 5/4 | note:c2 s:sawtooth hcutoff:500 hpenv:2 ]", - "[ 5/4 → 3/2 | note:c3 s:sawtooth hcutoff:500 hpenv:2 ]", - "[ 3/2 → 7/4 | note:c2 s:sawtooth hcutoff:500 hpenv:2 ]", - "[ 7/4 → 2/1 | note:c3 s:sawtooth hcutoff:500 hpenv:2 ]", - "[ 2/1 → 9/4 | note:c2 s:sawtooth hcutoff:500 hpenv:3 ]", - "[ 9/4 → 5/2 | note:c3 s:sawtooth hcutoff:500 hpenv:3 ]", - "[ 5/2 → 11/4 | note:c2 s:sawtooth hcutoff:500 hpenv:3 ]", - "[ 11/4 → 3/1 | note:c3 s:sawtooth hcutoff:500 hpenv:3 ]", - "[ 3/1 → 13/4 | note:c2 s:sawtooth hcutoff:500 hpenv:4 ]", - "[ 13/4 → 7/2 | note:c3 s:sawtooth hcutoff:500 hpenv:4 ]", - "[ 7/2 → 15/4 | note:c2 s:sawtooth hcutoff:500 hpenv:4 ]", - "[ 15/4 → 4/1 | note:c3 s:sawtooth hcutoff:500 hpenv:4 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth hcutoff:500 hpattack:0.1 hpdecay:0.1 hpsustain:0.5 hpenv:8 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth hcutoff:500 hpattack:0.1 hpdecay:0.1 hpsustain:0.5 hpenv:8 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth hcutoff:500 hpattack:0.1 hpdecay:0.1 hpsustain:0.5 hpenv:8 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth hcutoff:500 hpattack:0.1 hpdecay:0.1 hpsustain:0.5 hpenv:8 ]", +] +`; + +exports[`runs examples > example "hpenv" example index 1 1`] = ` +[ + "[ 0/1 → 1/1 | note:c2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:2 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:2 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:2 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:2 ]", ] `; @@ -2318,80 +2220,19 @@ exports[`runs examples > example "hpq" example index 0 1`] = ` exports[`runs examples > example "hprelease" example index 0 1`] = ` [ - "[ 0/1 → 1/4 | note:c3 hprelease:0.1 ftype:12db ]", - "[ 1/4 → 1/2 | note:e3 hprelease:0.1 ftype:12db ]", - "[ 1/2 → 3/4 | note:g3 hprelease:0.1 ftype:12db ]", - "[ 3/4 → 1/1 | note:c4 hprelease:0.1 ftype:12db ]", - "[ 1/1 → 5/4 | note:c3 hprelease:0.25 ftype:12db ]", - "[ 5/4 → 3/2 | note:e3 hprelease:0.25 ftype:12db ]", - "[ 3/2 → 7/4 | note:g3 hprelease:0.25 ftype:12db ]", - "[ 7/4 → 2/1 | note:c4 hprelease:0.25 ftype:12db ]", - "[ 2/1 → 9/4 | note:c3 hprelease:0.5 ftype:12db ]", - "[ 9/4 → 5/2 | note:e3 hprelease:0.5 ftype:12db ]", - "[ 5/2 → 11/4 | note:g3 hprelease:0.5 ftype:12db ]", - "[ 11/4 → 3/1 | note:c4 hprelease:0.5 ftype:12db ]", - "[ 3/1 → 13/4 | note:c3 hprelease:0.1 ftype:12db ]", - "[ 13/4 → 7/2 | note:e3 hprelease:0.1 ftype:12db ]", - "[ 7/2 → 15/4 | note:g3 hprelease:0.1 ftype:12db ]", - "[ 15/4 → 4/1 | note:c4 hprelease:0.1 ftype:12db ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth clip:0.5 hcutoff:0 hpenv:4 hprelease:0.5 release:0.5 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth clip:0.5 hcutoff:0 hpenv:4 hprelease:0.5 release:0.5 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth clip:0.5 hcutoff:0 hpenv:4 hprelease:0.5 release:0.5 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth clip:0.5 hcutoff:0 hpenv:4 hprelease:0.5 release:0.5 ]", ] `; exports[`runs examples > example "hpsustain" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 1/6 → 1/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 1/3 → 1/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 1/2 → 2/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 2/3 → 5/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 5/6 → 1/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.1 ftype:12db ]", - "[ 1/1 → 7/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 7/6 → 4/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 4/3 → 3/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 3/2 → 5/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 5/3 → 11/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 11/6 → 2/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.5 ftype:12db ]", - "[ 2/1 → 13/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 13/6 → 7/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 7/3 → 5/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 5/2 → 8/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 8/3 → 17/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 17/6 → 3/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:0.75 ftype:12db ]", - "[ 3/1 → 19/6 | note:c3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", - "[ 19/6 → 10/3 | note:e3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", - "[ 10/3 → 7/2 | note:f3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", - "[ 7/2 → 11/3 | note:g3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", - "[ 11/3 → 23/6 | note:ab3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", - "[ 23/6 → 4/1 | note:bb3 s:square hcutoff:200 hpdecay:0.1 hpsustain:1 ftype:12db ]", -] -`; - -exports[`runs examples > example "hpsustain" example index 0 2`] = ` -[ - "[ 0/1 → 1/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 1/6 → 1/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 1/3 → 1/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 1/2 → 2/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 2/3 → 5/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 5/6 → 1/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.1 ftype:12db ]", - "[ 1/1 → 7/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 7/6 → 4/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 4/3 → 3/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 3/2 → 5/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 5/3 → 11/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 11/6 → 2/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.5 ftype:12db ]", - "[ 2/1 → 13/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 13/6 → 7/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 7/3 → 5/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 5/2 → 8/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 8/3 → 17/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 17/6 → 3/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:0.75 ftype:12db ]", - "[ 3/1 → 19/6 | note:c3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", - "[ 19/6 → 10/3 | note:e3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", - "[ 10/3 → 7/2 | note:f3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", - "[ 7/2 → 11/3 | note:g3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", - "[ 11/3 → 23/6 | note:ab3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", - "[ 23/6 → 4/1 | note:bb3 s:square bandf:200 bpdecay:0.1 bpsustain:1 ftype:12db ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth hcutoff:0 hpdecay:0.5 hpsustain:0 hpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth hcutoff:0 hpdecay:0.5 hpsustain:0 hpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth hcutoff:0 hpdecay:0.5 hpsustain:0 hpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth hcutoff:0 hpdecay:0.5 hpsustain:0 hpenv:4 ]", ] `; From 4688c0bf103b5157ae91d8c3de375abbf709f69d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 15 Sep 2023 23:13:49 +0200 Subject: [PATCH 044/175] format --- website/src/pages/learn/effects.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index 62e3a52d..f5ee12ab 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -171,7 +171,6 @@ There is one filter envelope for each filter type and thus one set of envelope f - # Dynamics ## gain From 9142fb753a143e3c5bf641d534cec624a8e14c37 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 15 Sep 2023 23:36:55 +0200 Subject: [PATCH 045/175] cleaner default filter envelope - fixes some unexpected envelope glitches --- packages/superdough/superdough.mjs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 3afe470e..601ab9e0 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -183,24 +183,24 @@ export const superdough = async (value, deadline, hapDuration) => { cutoff, lpenv, lpattack = 0.01, - lpdecay = 0.5, - lpsustain = 0.6, + lpdecay = 0.01, + lpsustain = 1, lprelease = 0.01, resonance = 1, // high pass hpenv, hcutoff, hpattack = 0.01, - hpdecay = 0.5, - hpsustain = 0.6, + hpdecay = 0.01, + hpsustain = 1, hprelease = 0.01, hresonance = 1, // band pass bpenv, bandf, bpattack = 0.01, - bpdecay = 0.5, - bpsustain = 0.6, + bpdecay = 0.01, + bpsustain = 1, bprelease = 0.01, bandq = 1, // From 88c029202cd24bf3e2457b4c61307e7e94461837 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 15 Sep 2023 23:37:27 +0200 Subject: [PATCH 046/175] simplify fenv examples --- packages/core/controls.mjs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index dd865df5..36742755 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -387,8 +387,8 @@ const generic_params = [ * note("") * .sound('sawtooth') * .lpf(500) - * .lpa(.1).lpd(.1).lps(.5) - * .lpenv("<8 4 2 0>/4") + * .lpa(.5) + * .lpenv("<4 2 1 0>/4") */ ['lpenv', 'lpe'], /** @@ -400,8 +400,8 @@ const generic_params = [ * note("") * .sound('sawtooth') * .hpf(500) - * .hpa(.1).hpd(.1).hps(.5) - * .hpenv("<8 4 2 0>/4") + * .hpa(.5) + * .hpenv("<4 2 1 0>/4") * @example * note("") * .sound('sawtooth') @@ -419,8 +419,8 @@ const generic_params = [ * note("") * .sound('sawtooth') * .bpf(500) - * .bpa(.1).bpd(.1).bps(.5) - * .bpenv("<8 4 2 0>/4") + * .bpa(.5) + * .bpenv("<4 2 1 0>/4") */ ['bpenv', 'bpe'], /** From 9049a8b964d277d60071667a247ed37e77d42736 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 15 Sep 2023 23:37:36 +0200 Subject: [PATCH 047/175] simplify fenv --- packages/superdough/helpers.mjs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index b6530343..45371500 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -87,18 +87,16 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain // Apply ADSR to filter frequency if (fenv !== 0) { - let min = 0; - let max = Math.sign(fenv) * 200 * 2 ** Math.abs(fenv); - if (max < min) { - // offset by max: keep range when *penv sign is flipped - // comment those lines out to center around cutoff instead peak - min += Math.abs(max); - max += Math.abs(max); + let min = frequency; + let max = frequency * 2 ** Math.abs(fenv); + if (fenv < 0) { + // flip min max to keep range the same for negative envelope + // comment this out to flip the range as well... + [min, max] = [max, min]; } - + // console.log('min', min, 'max', max); min = clamp(min + frequency, 0, 20000); max = clamp(max + frequency, 0, 20000); - // console.log('min', min, 'max', max); getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end); return filter; } From ee314e9b03538c0ccd25296e281dd58aefcea15f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 15 Sep 2023 23:38:37 +0200 Subject: [PATCH 048/175] snapshot --- test/__snapshots__/examples.test.mjs.snap | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index ed05a561..a40ede3b 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -920,10 +920,10 @@ exports[`runs examples > example "bpdecay" example index 0 1`] = ` exports[`runs examples > example "bpenv" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | note:c2 s:sawtooth bandf:500 bpattack:0.1 bpdecay:0.1 bpsustain:0.5 bpenv:8 ]", - "[ 1/1 → 2/1 | note:e2 s:sawtooth bandf:500 bpattack:0.1 bpdecay:0.1 bpsustain:0.5 bpenv:8 ]", - "[ 2/1 → 3/1 | note:f2 s:sawtooth bandf:500 bpattack:0.1 bpdecay:0.1 bpsustain:0.5 bpenv:8 ]", - "[ 3/1 → 4/1 | note:g2 s:sawtooth bandf:500 bpattack:0.1 bpdecay:0.1 bpsustain:0.5 bpenv:8 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]", ] `; @@ -2115,10 +2115,10 @@ exports[`runs examples > example "hpdecay" example index 0 1`] = ` exports[`runs examples > example "hpenv" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | note:c2 s:sawtooth hcutoff:500 hpattack:0.1 hpdecay:0.1 hpsustain:0.5 hpenv:8 ]", - "[ 1/1 → 2/1 | note:e2 s:sawtooth hcutoff:500 hpattack:0.1 hpdecay:0.1 hpsustain:0.5 hpenv:8 ]", - "[ 2/1 → 3/1 | note:f2 s:sawtooth hcutoff:500 hpattack:0.1 hpdecay:0.1 hpsustain:0.5 hpenv:8 ]", - "[ 3/1 → 4/1 | note:g2 s:sawtooth hcutoff:500 hpattack:0.1 hpdecay:0.1 hpsustain:0.5 hpenv:8 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:4 ]", ] `; @@ -2685,10 +2685,10 @@ exports[`runs examples > example "lpdecay" example index 0 1`] = ` exports[`runs examples > example "lpenv" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:500 lpattack:0.1 lpdecay:0.1 lpsustain:0.5 lpenv:8 ]", - "[ 1/1 → 2/1 | note:e2 s:sawtooth cutoff:500 lpattack:0.1 lpdecay:0.1 lpsustain:0.5 lpenv:8 ]", - "[ 2/1 → 3/1 | note:f2 s:sawtooth cutoff:500 lpattack:0.1 lpdecay:0.1 lpsustain:0.5 lpenv:8 ]", - "[ 3/1 → 4/1 | note:g2 s:sawtooth cutoff:500 lpattack:0.1 lpdecay:0.1 lpsustain:0.5 lpenv:8 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:500 lpattack:0.5 lpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth cutoff:500 lpattack:0.5 lpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth cutoff:500 lpattack:0.5 lpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth cutoff:500 lpattack:0.5 lpenv:4 ]", ] `; From df211c994d2ed795036da9e8a1d831a60df55095 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 00:44:03 +0200 Subject: [PATCH 049/175] anchored fenv, more logical with negative values - defaulting to .5 for now... --- packages/superdough/helpers.mjs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 45371500..0f50a527 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -87,14 +87,15 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain // Apply ADSR to filter frequency if (fenv !== 0) { - let min = frequency; - let max = frequency * 2 ** Math.abs(fenv); - if (fenv < 0) { - // flip min max to keep range the same for negative envelope - // comment this out to flip the range as well... - [min, max] = [max, min]; - } - // console.log('min', min, 'max', max); + let anchor = 0.5; + let offset = fenv * anchor; + let min = 2 ** -offset; + let max = 2 ** (fenv - offset); + min *= frequency; + max *= frequency; + + //console.log('min', min, 'max', max); + min = clamp(min + frequency, 0, 20000); max = clamp(max + frequency, 0, 20000); getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end); From 40de717cc90f410115069ee34792cc1a55a90be4 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 00:46:50 +0200 Subject: [PATCH 050/175] fix: don't add frequency --- packages/superdough/helpers.mjs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 0f50a527..92a5584f 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -94,10 +94,11 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain min *= frequency; max *= frequency; - //console.log('min', min, 'max', max); + min = clamp(min, 0, 20000); + max = clamp(max, 0, 20000); + + console.log('min', min, 'max', max); - min = clamp(min + frequency, 0, 20000); - max = clamp(max + frequency, 0, 20000); getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end); return filter; } From 7f86eac8f1b611b77484e8db3c5d28a20b2762b2 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 00:51:36 +0200 Subject: [PATCH 051/175] simplify --- packages/superdough/helpers.mjs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 92a5584f..c15bdb83 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -82,22 +82,17 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain const filter = context.createBiquadFilter(); filter.type = type; filter.Q.value = Q; - frequency = Math.max(frequency, 20); filter.frequency.value = frequency; // Apply ADSR to filter frequency if (fenv !== 0) { - let anchor = 0.5; - let offset = fenv * anchor; - let min = 2 ** -offset; - let max = 2 ** (fenv - offset); - min *= frequency; - max *= frequency; + const anchor = 0.5; + const offset = fenv * anchor; - min = clamp(min, 0, 20000); - max = clamp(max, 0, 20000); + const min = clamp(2 ** -offset * frequency, 0, 20000); + const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000); - console.log('min', min, 'max', max); + // console.log('min', min, 'max', max); getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end); return filter; From 7dbcc90450d032a63e8feaf9c75053b1b0cedbe6 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 01:07:10 +0200 Subject: [PATCH 052/175] fix: docs after fenv change --- packages/core/controls.mjs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 36742755..ce52d670 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -388,7 +388,7 @@ const generic_params = [ * .sound('sawtooth') * .lpf(500) * .lpa(.5) - * .lpenv("<4 2 1 0>/4") + * .lpenv("<4 2 1 0 -1 -2 -4>/4") */ ['lpenv', 'lpe'], /** @@ -401,13 +401,7 @@ const generic_params = [ * .sound('sawtooth') * .hpf(500) * .hpa(.5) - * .hpenv("<4 2 1 0>/4") - * @example - * note("") - * .sound('sawtooth') - * .hpf(500) - * .hpa(.5) - * .hpenv("<2 -2>/4") + * .hpenv("<4 2 1 0 -1 -2 -4>/4") */ ['hpenv', 'hpe'], /** @@ -420,7 +414,7 @@ const generic_params = [ * .sound('sawtooth') * .bpf(500) * .bpa(.5) - * .bpenv("<4 2 1 0>/4") + * .bpenv("<4 2 1 0 -1 -2 -4>/4") */ ['bpenv', 'bpe'], /** @@ -512,7 +506,7 @@ const generic_params = [ * @example * note("") * .sound('sawtooth') - * .lpf(0) + * .lpf(500) * .lpd(.5) * .lps("<0 .25 .5 1>/4") * .lpenv(4) @@ -526,7 +520,7 @@ const generic_params = [ * @example * note("") * .sound('sawtooth') - * .hpf(0) + * .hpf(500) * .hpd(.5) * .hps("<0 .25 .5 1>/4") * .hpenv(4) @@ -540,7 +534,7 @@ const generic_params = [ * @example * note("") * .sound('sawtooth') - * .bpf(0) + * .bpf(500) * .bpd(.5) * .bps("<0 .25 .5 1>/4") * .bpenv(4) @@ -555,7 +549,7 @@ const generic_params = [ * note("") * .sound('sawtooth') * .clip(.5) - * .lpf(0) + * .lpf(500) * .lpenv(4) * .lpr("<.5 .25 .1 0>/4") * .release(.5) @@ -570,7 +564,7 @@ const generic_params = [ * note("") * .sound('sawtooth') * .clip(.5) - * .hpf(0) + * .hpf(500) * .hpenv(4) * .hpr("<.5 .25 .1 0>/4") * .release(.5) @@ -585,7 +579,7 @@ const generic_params = [ * note("") * .sound('sawtooth') * .clip(.5) - * .bpf(0) + * .bpf(500) * .bpenv(4) * .bpr("<.5 .25 .1 0>/4") * .release(.5) From e959c275fd6915b9562801e2f04de4143b08cd1a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 01:14:14 +0200 Subject: [PATCH 053/175] add fanchor --- packages/core/controls.mjs | 1 + packages/superdough/helpers.mjs | 18 +++++++++++++++--- packages/superdough/superdough.mjs | 18 +++++++++++++++++- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index ce52d670..58c4efa1 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -586,6 +586,7 @@ const generic_params = [ */ ['bprelease', 'bpr'], ['ftype'], + ['fanchor'], /** * Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter. * diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index c15bdb83..92f670d9 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -78,7 +78,20 @@ export const getParamADSR = (param, attack, decay, sustain, release, min, max, b param.linearRampToValueAtTime(min, end + Math.max(release, 0.1)); }; -export function createFilter(context, type, frequency, Q, attack, decay, sustain, release, fenv, start, end) { +export function createFilter( + context, + type, + frequency, + Q, + attack, + decay, + sustain, + release, + fenv, + start, + end, + fanchor = 0.5, +) { const filter = context.createBiquadFilter(); filter.type = type; filter.Q.value = Q; @@ -86,8 +99,7 @@ export function createFilter(context, type, frequency, Q, attack, decay, sustain // Apply ADSR to filter frequency if (fenv !== 0) { - const anchor = 0.5; - const offset = fenv * anchor; + const offset = fenv * fanchor; const min = clamp(2 ** -offset * frequency, 0, 20000); const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000); diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 601ab9e0..289e8d97 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -179,6 +179,7 @@ export const superdough = async (value, deadline, hapDuration) => { gain = 0.8, // filters ftype = '12db', + fanchor = 0.5, // low pass cutoff, lpenv, @@ -270,6 +271,7 @@ export const superdough = async (value, deadline, hapDuration) => { lpenv, t, t + hapDuration, + fanchor, ); chain.push(lp()); if (ftype === '24db') { @@ -291,6 +293,7 @@ export const superdough = async (value, deadline, hapDuration) => { hpenv, t, t + hapDuration, + fanchor, ); chain.push(hp()); if (ftype === '24db') { @@ -300,7 +303,20 @@ export const superdough = async (value, deadline, hapDuration) => { if (bandf !== undefined) { let bp = () => - createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, bpenv, t, t + hapDuration); + createFilter( + ac, + 'bandpass', + bandf, + bandq, + bpattack, + bpdecay, + bpsustain, + bprelease, + bpenv, + t, + t + hapDuration, + fanchor, + ); chain.push(bp()); if (ftype === '24db') { chain.push(bp()); From 735f892a087ce949dfb482e605eb4947b7dfb469 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 01:14:53 +0200 Subject: [PATCH 054/175] fix: snapshots --- test/__snapshots__/examples.test.mjs.snap | 57 ++++++++++------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index a40ede3b..c46ca717 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -967,19 +967,19 @@ exports[`runs examples > example "bpq" example index 0 1`] = ` exports[`runs examples > example "bprelease" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | note:c2 s:sawtooth clip:0.5 bandf:0 bpenv:4 bprelease:0.5 release:0.5 ]", - "[ 1/1 → 2/1 | note:e2 s:sawtooth clip:0.5 bandf:0 bpenv:4 bprelease:0.5 release:0.5 ]", - "[ 2/1 → 3/1 | note:f2 s:sawtooth clip:0.5 bandf:0 bpenv:4 bprelease:0.5 release:0.5 ]", - "[ 3/1 → 4/1 | note:g2 s:sawtooth clip:0.5 bandf:0 bpenv:4 bprelease:0.5 release:0.5 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth clip:0.5 bandf:500 bpenv:4 bprelease:0.5 release:0.5 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth clip:0.5 bandf:500 bpenv:4 bprelease:0.5 release:0.5 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth clip:0.5 bandf:500 bpenv:4 bprelease:0.5 release:0.5 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth clip:0.5 bandf:500 bpenv:4 bprelease:0.5 release:0.5 ]", ] `; exports[`runs examples > example "bpsustain" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | note:c2 s:sawtooth bandf:0 bpdecay:0.5 bpsustain:0 bpenv:4 ]", - "[ 1/1 → 2/1 | note:e2 s:sawtooth bandf:0 bpdecay:0.5 bpsustain:0 bpenv:4 ]", - "[ 2/1 → 3/1 | note:f2 s:sawtooth bandf:0 bpdecay:0.5 bpsustain:0 bpenv:4 ]", - "[ 3/1 → 4/1 | note:g2 s:sawtooth bandf:0 bpdecay:0.5 bpsustain:0 bpenv:4 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth bandf:500 bpdecay:0.5 bpsustain:0 bpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth bandf:500 bpdecay:0.5 bpsustain:0 bpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth bandf:500 bpdecay:0.5 bpsustain:0 bpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth bandf:500 bpdecay:0.5 bpsustain:0 bpenv:4 ]", ] `; @@ -2122,15 +2122,6 @@ exports[`runs examples > example "hpenv" example index 0 1`] = ` ] `; -exports[`runs examples > example "hpenv" example index 1 1`] = ` -[ - "[ 0/1 → 1/1 | note:c2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:2 ]", - "[ 1/1 → 2/1 | note:e2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:2 ]", - "[ 2/1 → 3/1 | note:f2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:2 ]", - "[ 3/1 → 4/1 | note:g2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:2 ]", -] -`; - exports[`runs examples > example "hpf" example index 0 1`] = ` [ "[ 0/1 → 1/4 | s:hh hcutoff:4000 ]", @@ -2220,19 +2211,19 @@ exports[`runs examples > example "hpq" example index 0 1`] = ` exports[`runs examples > example "hprelease" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | note:c2 s:sawtooth clip:0.5 hcutoff:0 hpenv:4 hprelease:0.5 release:0.5 ]", - "[ 1/1 → 2/1 | note:e2 s:sawtooth clip:0.5 hcutoff:0 hpenv:4 hprelease:0.5 release:0.5 ]", - "[ 2/1 → 3/1 | note:f2 s:sawtooth clip:0.5 hcutoff:0 hpenv:4 hprelease:0.5 release:0.5 ]", - "[ 3/1 → 4/1 | note:g2 s:sawtooth clip:0.5 hcutoff:0 hpenv:4 hprelease:0.5 release:0.5 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth clip:0.5 hcutoff:500 hpenv:4 hprelease:0.5 release:0.5 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth clip:0.5 hcutoff:500 hpenv:4 hprelease:0.5 release:0.5 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth clip:0.5 hcutoff:500 hpenv:4 hprelease:0.5 release:0.5 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth clip:0.5 hcutoff:500 hpenv:4 hprelease:0.5 release:0.5 ]", ] `; exports[`runs examples > example "hpsustain" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | note:c2 s:sawtooth hcutoff:0 hpdecay:0.5 hpsustain:0 hpenv:4 ]", - "[ 1/1 → 2/1 | note:e2 s:sawtooth hcutoff:0 hpdecay:0.5 hpsustain:0 hpenv:4 ]", - "[ 2/1 → 3/1 | note:f2 s:sawtooth hcutoff:0 hpdecay:0.5 hpsustain:0 hpenv:4 ]", - "[ 3/1 → 4/1 | note:g2 s:sawtooth hcutoff:0 hpdecay:0.5 hpsustain:0 hpenv:4 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth hcutoff:500 hpdecay:0.5 hpsustain:0 hpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth hcutoff:500 hpdecay:0.5 hpsustain:0 hpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth hcutoff:500 hpdecay:0.5 hpsustain:0 hpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth hcutoff:500 hpdecay:0.5 hpsustain:0 hpenv:4 ]", ] `; @@ -2785,19 +2776,19 @@ exports[`runs examples > example "lpq" example index 0 1`] = ` exports[`runs examples > example "lprelease" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | note:c2 s:sawtooth clip:0.5 cutoff:0 lpenv:4 lprelease:0.5 release:0.5 ]", - "[ 1/1 → 2/1 | note:e2 s:sawtooth clip:0.5 cutoff:0 lpenv:4 lprelease:0.5 release:0.5 ]", - "[ 2/1 → 3/1 | note:f2 s:sawtooth clip:0.5 cutoff:0 lpenv:4 lprelease:0.5 release:0.5 ]", - "[ 3/1 → 4/1 | note:g2 s:sawtooth clip:0.5 cutoff:0 lpenv:4 lprelease:0.5 release:0.5 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth clip:0.5 cutoff:500 lpenv:4 lprelease:0.5 release:0.5 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth clip:0.5 cutoff:500 lpenv:4 lprelease:0.5 release:0.5 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth clip:0.5 cutoff:500 lpenv:4 lprelease:0.5 release:0.5 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth clip:0.5 cutoff:500 lpenv:4 lprelease:0.5 release:0.5 ]", ] `; exports[`runs examples > example "lpsustain" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:0 lpdecay:0.5 lpsustain:0 lpenv:4 ]", - "[ 1/1 → 2/1 | note:e2 s:sawtooth cutoff:0 lpdecay:0.5 lpsustain:0 lpenv:4 ]", - "[ 2/1 → 3/1 | note:f2 s:sawtooth cutoff:0 lpdecay:0.5 lpsustain:0 lpenv:4 ]", - "[ 3/1 → 4/1 | note:g2 s:sawtooth cutoff:0 lpdecay:0.5 lpsustain:0 lpenv:4 ]", + "[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:500 lpdecay:0.5 lpsustain:0 lpenv:4 ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth cutoff:500 lpdecay:0.5 lpsustain:0 lpenv:4 ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth cutoff:500 lpdecay:0.5 lpsustain:0 lpenv:4 ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth cutoff:500 lpdecay:0.5 lpsustain:0 lpenv:4 ]", ] `; From 989dc0aabe4111891049fa5fadf4c857dfde8d6c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 01:33:09 +0200 Subject: [PATCH 055/175] fix: filters without envelopes --- packages/superdough/helpers.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 92f670d9..32ca0bb2 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -98,7 +98,7 @@ export function createFilter( filter.frequency.value = frequency; // Apply ADSR to filter frequency - if (fenv !== 0) { + if (!isNaN(fenv) && fenv !== 0) { const offset = fenv * fanchor; const min = clamp(2 ** -offset * frequency, 0, 20000); From b96e8093a02c8f824c25267b0dc23552ed2b58c7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 01:33:17 +0200 Subject: [PATCH 056/175] doc: fenv --- packages/core/controls.mjs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 58c4efa1..780b4a44 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -585,6 +585,17 @@ const generic_params = [ * .release(.5) */ ['bprelease', 'bpr'], + /** + * Sets the filter type. The 24db filter is more aggressive. More types might be added in the future. + * @name ftype + * @param {number | Pattern} type 12db (default) or 24db + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .bpenv(4) + * .ftype("<12db 24db>") + */ ['ftype'], ['fanchor'], /** From af6a5b85f55eef2527639df6b632c0619d581c83 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 01:33:34 +0200 Subject: [PATCH 057/175] keep only lp envelopes as examples --- website/src/pages/learn/effects.mdx | 64 ++--------------------------- 1 file changed, 4 insertions(+), 60 deletions(-) diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index f5ee12ab..4982f4cd 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -49,6 +49,10 @@ Each filter has 2 parameters: +## ftype + + + ## vowel @@ -111,66 +115,6 @@ There is one filter envelope for each filter type and thus one set of envelope f -## hpattack - - - -## hpdecay - - - -## hpsustain - - - -## hprelease - - - -## hpenv - - - -## hpattack - - - -## hpdecay - - - -## hpsustain - - - -## hprelease - - - -## hpenv - - - -## bpattack - - - -## bpdecay - - - -## bpsustain - - - -## bprelease - - - -## bpenv - - - # Dynamics ## gain From a7eb0bb04af0d83283d3407999990fac9967ac2a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 01:34:00 +0200 Subject: [PATCH 058/175] snapshot --- test/__snapshots__/examples.test.mjs.snap | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index c46ca717..cd7595b5 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2058,6 +2058,15 @@ exports[`runs examples > example "freq" example index 1 1`] = ` ] `; +exports[`runs examples > example "ftype" example index 0 1`] = ` +[ + "[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:500 bpenv:4 ftype:12db ]", + "[ 1/1 → 2/1 | note:e2 s:sawtooth cutoff:500 bpenv:4 ftype:24db ]", + "[ 2/1 → 3/1 | note:f2 s:sawtooth cutoff:500 bpenv:4 ftype:12db ]", + "[ 3/1 → 4/1 | note:g2 s:sawtooth cutoff:500 bpenv:4 ftype:24db ]", +] +`; + exports[`runs examples > example "gain" example index 0 1`] = ` [ "[ 0/1 → 1/8 | s:hh gain:0.4 ]", From 536427310d4f3f551429a446a81b928ef07ddc19 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 01:50:23 +0200 Subject: [PATCH 059/175] add some filter envelopes here and there --- website/src/repl/tunes.mjs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/website/src/repl/tunes.mjs b/website/src/repl/tunes.mjs index dd524283..2ab546b7 100644 --- a/website/src/repl/tunes.mjs +++ b/website/src/repl/tunes.mjs @@ -229,7 +229,9 @@ stack( .add("0,.02") .note().gain(.3) .clip("<1@3 [.3 1]>/2") - .s('sawtooth').cutoff(600).color('#F8E71C'), + .cutoff(600) + .lpa(.2).lpenv(-4) + .s('sawtooth').color('#F8E71C'), ).fast(3/2) //.pianoroll({fold:1})`; @@ -468,7 +470,9 @@ stack( .note() .s("sawtooth,square") .gain(.3).attack(0.01).decay(0.1).sustain(.5) - .apply(filter1), + .apply(filter1) + .lpa(.1).lpenv(2).ftype('24db') + , "~@3 [<2 3>,<4 5>]" .echo(4,1/16,.7) .scale(scales) @@ -803,14 +807,14 @@ stack( sine.add(saw.slow(4)).range(0,7).segment(8) .superimpose(x=>x.add(.1)) .scale('G0 minor').note() - .s("sawtooth").decay(.1).sustain(0) + .s("sawtooth").decay(.1).sustain(0).lpa(.1).lpenv(4) .gain(.4).cutoff(perlin.range(300,3000).slow(8)).resonance(10) .degradeBy("0 0.1 .5 .1") .rarely(add(note("12"))) , // chord note("Bb3,D4".superimpose(x=>x.add(.2))) - .s('sawtooth').cutoff(1000).struct("<~@3 [~ x]>") + .s('sawtooth').lpf(1000).struct("<~@3 [~ x]>") .decay(.05).sustain(.0).delay(.8).delaytime(.125).room(.8) , // alien From e0c424eb9262a331f31cbcae4e5a0c2369dd2c10 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 01:50:45 +0200 Subject: [PATCH 060/175] update snapshots --- test/__snapshots__/tunes.test.mjs.snap | 232 ++++++++++++------------- 1 file changed, 116 insertions(+), 116 deletions(-) diff --git a/test/__snapshots__/tunes.test.mjs.snap b/test/__snapshots__/tunes.test.mjs.snap index 3c072ca2..484c1380 100644 --- a/test/__snapshots__/tunes.test.mjs.snap +++ b/test/__snapshots__/tunes.test.mjs.snap @@ -3,23 +3,23 @@ exports[`renders tunes > tune: amensister 1`] = ` [ "[ 0/1 → 1/16 | s:breath room:1 shape:0.6 begin:0.9375 end:1 ]", - "[ 0/1 → 1/8 | note:Eb1 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:300.0066107586751 resonance:10 ]", - "[ 0/1 → 1/8 | note:F1 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:300.0066107586751 resonance:10 ]", + "[ 0/1 → 1/8 | note:Eb1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.0066107586751 resonance:10 ]", + "[ 0/1 → 1/8 | note:F1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.0066107586751 resonance:10 ]", "[ 0/1 → 1/4 | n:0 s:amencutup room:0.5 ]", "[ 1/16 → 1/8 | s:breath room:1 shape:0.6 begin:0.875 end:0.9375 ]", "[ 1/8 → 3/16 | s:breath room:1 shape:0.6 begin:0.8125 end:0.875 ]", - "[ 1/8 → 1/4 | note:45 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:300.174310575404 resonance:10 ]", - "[ 1/8 → 1/4 | note:45 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:300.174310575404 resonance:10 ]", + "[ 1/8 → 1/4 | note:45 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.174310575404 resonance:10 ]", + "[ 1/8 → 1/4 | note:45 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.174310575404 resonance:10 ]", "[ 3/16 → 1/4 | s:breath room:1 shape:0.6 begin:0.75 end:0.8125 ]", "[ 1/4 → 5/16 | s:breath room:1 shape:0.6 begin:0.6875 end:0.75 ]", "[ 1/4 → 3/8 | n:1 speed:2 delay:0.5 s:amencutup room:0.5 ]", - "[ 1/4 → 3/8 | note:A1 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:300.7878869297153 resonance:10 ]", - "[ 1/4 → 3/8 | note:A1 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:300.7878869297153 resonance:10 ]", + "[ 1/4 → 3/8 | note:A1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.7878869297153 resonance:10 ]", + "[ 1/4 → 3/8 | note:A1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.7878869297153 resonance:10 ]", "[ 5/16 → 3/8 | s:breath room:1 shape:0.6 begin:0.625 end:0.6875 ]", "[ 3/8 → 7/16 | s:breath room:1 shape:0.6 begin:0.5625 end:0.625 ]", "[ 3/8 → 1/2 | n:1 s:amencutup room:0.5 ]", - "[ 3/8 → 1/2 | note:F1 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:302.11020572391345 resonance:10 ]", - "[ 3/8 → 1/2 | note:F1 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:302.11020572391345 resonance:10 ]", + "[ 3/8 → 1/2 | note:F1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:302.11020572391345 resonance:10 ]", + "[ 3/8 → 1/2 | note:F1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:302.11020572391345 resonance:10 ]", "[ 7/16 → 1/2 | s:breath room:1 shape:0.6 begin:0.5 end:0.5625 ]", "[ 1/2 → 9/16 | s:breath room:1 shape:0.6 begin:0.4375 end:0.5 ]", "[ 1/2 → 3/4 | n:2 s:amencutup room:0.5 ]", @@ -28,13 +28,13 @@ exports[`renders tunes > tune: amensister 1`] = ` "[ 11/16 → 3/4 | s:breath room:1 shape:0.6 begin:0.25 end:0.3125 ]", "[ 3/4 → 13/16 | s:breath room:1 shape:0.6 begin:0.1875 end:0.25 ]", "[ 3/4 → 7/8 | n:3 s:amencutup room:0.5 ]", - "[ 3/4 → 7/8 | note:Bb0 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:312.54769231985796 resonance:10 ]", - "[ 3/4 → 7/8 | note:Bb0 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:312.54769231985796 resonance:10 ]", + "[ 3/4 → 7/8 | note:Bb0 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:312.54769231985796 resonance:10 ]", + "[ 3/4 → 7/8 | note:Bb0 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:312.54769231985796 resonance:10 ]", "[ 13/16 → 7/8 | s:breath room:1 shape:0.6 begin:0.125 end:0.1875 ]", "[ 7/8 → 15/16 | s:breath room:1 shape:0.6 begin:0.0625 end:0.125 ]", "[ 7/8 → 1/1 | n:3 s:amencutup room:0.5 ]", - "[ 7/8 → 1/1 | note:D1 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:318.7927796831686 resonance:10 ]", - "[ 7/8 → 1/1 | note:D1 s:sawtooth decay:0.1 sustain:0 gain:0.4 cutoff:318.7927796831686 resonance:10 ]", + "[ 7/8 → 1/1 | note:D1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:318.7927796831686 resonance:10 ]", + "[ 7/8 → 1/1 | note:D1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:318.7927796831686 resonance:10 ]", "[ 15/16 → 1/1 | s:breath room:1 shape:0.6 begin:0 end:0.0625 ]", ] `; @@ -323,8 +323,8 @@ exports[`renders tunes > tune: blippyRhodes 1`] = ` [ "[ 0/1 → 1/6 | note:G4 clip:0.3 s:rhodes room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]", "[ 0/1 → 1/3 | s:bd ]", - "[ (0/1 → 2/3) ⇝ 4/3 | note:36 gain:0.3 clip:1 s:sawtooth cutoff:600 ]", - "[ (0/1 → 2/3) ⇝ 4/3 | note:36.02 gain:0.3 clip:1 s:sawtooth cutoff:600 ]", + "[ (0/1 → 2/3) ⇝ 4/3 | note:36 gain:0.3 clip:1 cutoff:600 lpattack:0.2 lpenv:-4 s:sawtooth ]", + "[ (0/1 → 2/3) ⇝ 4/3 | note:36.02 gain:0.3 clip:1 cutoff:600 lpattack:0.2 lpenv:-4 s:sawtooth ]", "[ 1/6 → 1/3 | note:G4 clip:0.3 s:rhodes room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]", "[ 1/3 → 1/2 | note:B3 clip:0.3 s:rhodes room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]", "[ 1/3 → 1/2 | note:E4 clip:0.3 s:rhodes room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]", @@ -332,8 +332,8 @@ exports[`renders tunes > tune: blippyRhodes 1`] = ` "[ 1/2 → 2/3 | note:B3 clip:0.3 s:rhodes room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]", "[ 1/2 → 2/3 | note:E4 clip:0.3 s:rhodes room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]", "[ 2/3 → 5/6 | note:G3 clip:0.3 s:rhodes room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]", - "[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:36 gain:0.3 clip:1 s:sawtooth cutoff:600 ]", - "[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:36.02 gain:0.3 clip:1 s:sawtooth cutoff:600 ]", + "[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:36 gain:0.3 clip:1 cutoff:600 lpattack:0.2 lpenv:-4 s:sawtooth ]", + "[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:36.02 gain:0.3 clip:1 cutoff:600 lpattack:0.2 lpenv:-4 s:sawtooth ]", "[ 2/3 → 1/1 | s:sn ]", "[ 5/6 → 1/1 | note:G3 clip:0.3 s:rhodes room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]", ] @@ -7722,8 +7722,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ -1/8 ⇜ (0/1 → 3/8) | note:B3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:1699.6897509708342 ]", "[ -1/4 ⇜ (1/12 → 1/8) | note:A5 s:sawtooth gain:0.2536811842784369 attack:0.001 decay:0.2 sustain:0 hcutoff:5999.785818935017 cutoff:4000 ]", "[ -1/4 ⇜ (1/12 → 1/8) | note:C#5 s:sawtooth gain:0.2536811842784369 attack:0.001 decay:0.2 sustain:0 hcutoff:5999.785818935017 cutoff:4000 ]", - "[ 1/8 → 1/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1699.6897509708342 ]", - "[ 1/8 → 1/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1699.6897509708342 ]", + "[ 1/8 → 1/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1699.6897509708342 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 1/8 → 1/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1699.6897509708342 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (1/8 → 5/12) ⇝ 1/2 | note:A5 s:sawtooth gain:0.26836160127988246 attack:0.001 decay:0.2 sustain:0 hcutoff:5994.647308096509 cutoff:4000 ]", "[ (1/8 → 5/12) ⇝ 1/2 | note:C#5 s:sawtooth gain:0.26836160127988246 attack:0.001 decay:0.2 sustain:0 hcutoff:5994.647308096509 cutoff:4000 ]", "[ -1/8 ⇜ (1/6 → 1/4) | note:F#5 s:sawtooth gain:0.2573601511491127 attack:0.001 decay:0.2 sustain:0 hcutoff:5999.143312438893 cutoff:4000 ]", @@ -7735,14 +7735,14 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (1/4 → 7/12) ⇝ 5/8 | note:E5 s:sawtooth gain:0.2756442833140452 attack:0.001 decay:0.2 sustain:0 hcutoff:5989.512318936654 cutoff:4000 ]", "[ 0/1 ⇜ (1/3 → 3/8) | note:A5 s:sawtooth gain:0.26103468453995016 attack:0.001 decay:0.2 sustain:0 hcutoff:5998.072590601808 cutoff:4000 ]", "[ 0/1 ⇜ (1/3 → 3/8) | note:C#5 s:sawtooth gain:0.26103468453995016 attack:0.001 decay:0.2 sustain:0 hcutoff:5998.072590601808 cutoff:4000 ]", - "[ 3/8 → 1/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1765.826371664994 ]", - "[ 3/8 → 1/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1765.826371664994 ]", + "[ 3/8 → 1/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1765.826371664994 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 3/8 → 1/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1765.826371664994 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (3/8 → 2/3) ⇝ 3/4 | note:A5 s:sawtooth gain:0.2828651860235305 attack:0.001 decay:0.2 sustain:0 hcutoff:5982.671142387316 cutoff:4000 ]", "[ (3/8 → 2/3) ⇝ 3/4 | note:C#5 s:sawtooth gain:0.2828651860235305 attack:0.001 decay:0.2 sustain:0 hcutoff:5982.671142387316 cutoff:4000 ]", "[ 1/8 ⇜ (5/12 → 1/2) | note:F#5 s:sawtooth gain:0.26836160127988246 attack:0.001 decay:0.2 sustain:0 hcutoff:5994.647308096509 cutoff:4000 ]", "[ 1/8 ⇜ (5/12 → 1/2) | note:A4 s:sawtooth gain:0.26836160127988246 attack:0.001 decay:0.2 sustain:0 hcutoff:5994.647308096509 cutoff:4000 ]", - "[ 1/2 → 5/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1798.799979846742 ]", - "[ 1/2 → 5/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1798.799979846742 ]", + "[ 1/2 → 5/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1798.799979846742 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 1/2 → 5/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1798.799979846742 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 1/2 → 3/4 | note:F#5 s:sawtooth gain:0.28644702698548963 attack:0.001 decay:0.2 sustain:0 hcutoff:5978.612153434527 cutoff:4000 ]", "[ 1/2 → 3/4 | note:A4 s:sawtooth gain:0.28644702698548963 attack:0.001 decay:0.2 sustain:0 hcutoff:5978.612153434527 cutoff:4000 ]", "[ 1/2 → 3/4 | s:bd gain:0.7 ]", @@ -7755,8 +7755,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (5/8 → 11/12) ⇝ 1/1 | note:C#5 s:sawtooth gain:0.29705226105983373 attack:0.001 decay:0.2 sustain:0 hcutoff:5963.890147645195 cutoff:4000 ]", "[ 3/8 ⇜ (2/3 → 3/4) | note:F#5 s:sawtooth gain:0.2828651860235305 attack:0.001 decay:0.2 sustain:0 hcutoff:5982.671142387316 cutoff:4000 ]", "[ 3/8 ⇜ (2/3 → 3/4) | note:A4 s:sawtooth gain:0.2828651860235305 attack:0.001 decay:0.2 sustain:0 hcutoff:5982.671142387316 cutoff:4000 ]", - "[ 3/4 → 7/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1864.4584935007128 ]", - "[ 3/4 → 7/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1864.4584935007128 ]", + "[ 3/4 → 7/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1864.4584935007128 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 3/4 → 7/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1864.4584935007128 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 3/4 → 1/1 | note:F#5 s:sawtooth gain:0.300533478008833 attack:0.001 decay:0.2 sustain:0 hcutoff:5958.137268909887 cutoff:4000 ]", "[ 3/4 → 1/1 | note:A4 s:sawtooth gain:0.300533478008833 attack:0.001 decay:0.2 sustain:0 hcutoff:5958.137268909887 cutoff:4000 ]", "[ 3/4 → 1/1 | s:hh3 gain:0.7 ]", @@ -7764,8 +7764,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (3/4 → 1/1) ⇝ 9/8 | note:E5 s:sawtooth gain:0.30398425548024827 attack:0.001 decay:0.2 sustain:0 hcutoff:5951.963201008076 cutoff:4000 ]", "[ 1/2 ⇜ (5/6 → 7/8) | note:A5 s:sawtooth gain:0.29000691362123476 attack:0.001 decay:0.2 sustain:0 hcutoff:5974.128467049176 cutoff:4000 ]", "[ 1/2 ⇜ (5/6 → 7/8) | note:C#5 s:sawtooth gain:0.29000691362123476 attack:0.001 decay:0.2 sustain:0 hcutoff:5974.128467049176 cutoff:4000 ]", - "[ 7/8 → 1/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1897.1038487394403 ]", - "[ 7/8 → 1/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1897.1038487394403 ]", + "[ 7/8 → 1/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1897.1038487394403 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 7/8 → 1/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1897.1038487394403 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (7/8 → 1/1) ⇝ 5/4 | note:A5 s:sawtooth gain:0.3107861971007485 attack:0.001 decay:0.2 sustain:0 hcutoff:5938.355801271282 cutoff:4000 ]", "[ (7/8 → 1/1) ⇝ 5/4 | note:C#5 s:sawtooth gain:0.3107861971007485 attack:0.001 decay:0.2 sustain:0 hcutoff:5938.355801271282 cutoff:4000 ]", "[ 5/8 ⇜ (11/12 → 1/1) | note:F#5 s:sawtooth gain:0.29705226105983373 attack:0.001 decay:0.2 sustain:0 hcutoff:5963.890147645195 cutoff:4000 ]", @@ -7781,8 +7781,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (1/1 → 4/3) ⇝ 11/8 | note:E5 s:sawtooth gain:0.317441699448191 attack:0.001 decay:0.2 sustain:0 hcutoff:5923.077274266886 cutoff:4000 ]", "[ 3/4 ⇜ (13/12 → 9/8) | note:A5 s:sawtooth gain:0.30398425548024827 attack:0.001 decay:0.2 sustain:0 hcutoff:5951.963201008076 cutoff:4000 ]", "[ 3/4 ⇜ (13/12 → 9/8) | note:C#5 s:sawtooth gain:0.30398425548024827 attack:0.001 decay:0.2 sustain:0 hcutoff:5951.963201008076 cutoff:4000 ]", - "[ 9/8 → 5/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1961.928446178906 ]", - "[ 9/8 → 5/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1961.928446178906 ]", + "[ 9/8 → 5/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1961.928446178906 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 9/8 → 5/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:1961.928446178906 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (9/8 → 17/12) ⇝ 3/2 | note:A5 s:sawtooth gain:0.3239347288344676 attack:0.001 decay:0.2 sustain:0 hcutoff:5906.1380911341175 cutoff:4000 ]", "[ (9/8 → 17/12) ⇝ 3/2 | note:C#5 s:sawtooth gain:0.3239347288344676 attack:0.001 decay:0.2 sustain:0 hcutoff:5906.1380911341175 cutoff:4000 ]", "[ 7/8 ⇜ (7/6 → 5/4) | note:F#5 s:sawtooth gain:0.3107861971007485 attack:0.001 decay:0.2 sustain:0 hcutoff:5938.355801271282 cutoff:4000 ]", @@ -7794,14 +7794,14 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (5/4 → 19/12) ⇝ 13/8 | note:E5 s:sawtooth gain:0.3302496429830646 attack:0.001 decay:0.2 sustain:0 hcutoff:5887.549861142967 cutoff:4000 ]", "[ 1/1 ⇜ (4/3 → 11/8) | note:A5 s:sawtooth gain:0.317441699448191 attack:0.001 decay:0.2 sustain:0 hcutoff:5923.077274266886 cutoff:4000 ]", "[ 1/1 ⇜ (4/3 → 11/8) | note:C#5 s:sawtooth gain:0.317441699448191 attack:0.001 decay:0.2 sustain:0 hcutoff:5923.077274266886 cutoff:4000 ]", - "[ 11/8 → 3/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2026.0015806698216 ]", - "[ 11/8 → 3/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2026.0015806698216 ]", + "[ 11/8 → 3/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2026.0015806698216 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 11/8 → 3/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2026.0015806698216 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (11/8 → 5/3) ⇝ 7/4 | note:A5 s:sawtooth gain:0.3363712287126769 attack:0.001 decay:0.2 sustain:0 hcutoff:5867.325323737765 cutoff:4000 ]", "[ (11/8 → 5/3) ⇝ 7/4 | note:C#5 s:sawtooth gain:0.3363712287126769 attack:0.001 decay:0.2 sustain:0 hcutoff:5867.325323737765 cutoff:4000 ]", "[ 9/8 ⇜ (17/12 → 3/2) | note:F#5 s:sawtooth gain:0.3239347288344676 attack:0.001 decay:0.2 sustain:0 hcutoff:5906.1380911341175 cutoff:4000 ]", "[ 9/8 ⇜ (17/12 → 3/2) | note:A4 s:sawtooth gain:0.3239347288344676 attack:0.001 decay:0.2 sustain:0 hcutoff:5906.1380911341175 cutoff:4000 ]", - "[ 3/2 → 13/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2057.708031580958 ]", - "[ 3/2 → 13/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2057.708031580958 ]", + "[ 3/2 → 13/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2057.708031580958 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 3/2 → 13/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2057.708031580958 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 3/2 → 7/4 | note:F#5 s:sawtooth gain:0.339354895673865 attack:0.001 decay:0.2 sustain:0 hcutoff:5856.603727730447 cutoff:4000 ]", "[ 3/2 → 7/4 | note:A4 s:sawtooth gain:0.339354895673865 attack:0.001 decay:0.2 sustain:0 hcutoff:5856.603727730447 cutoff:4000 ]", "[ 3/2 → 7/4 | s:bd gain:0.7 ]", @@ -7818,8 +7818,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (13/8 → 2/1) ⇝ 17/8 | note:A3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2120.3652183367367 ]", "[ 11/8 ⇜ (5/3 → 7/4) | note:F#5 s:sawtooth gain:0.3363712287126769 attack:0.001 decay:0.2 sustain:0 hcutoff:5867.325323737765 cutoff:4000 ]", "[ 11/8 ⇜ (5/3 → 7/4) | note:A4 s:sawtooth gain:0.3363712287126769 attack:0.001 decay:0.2 sustain:0 hcutoff:5867.325323737765 cutoff:4000 ]", - "[ 7/4 → 15/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2120.3652183367367 ]", - "[ 7/4 → 15/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2120.3652183367367 ]", + "[ 7/4 → 15/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2120.3652183367367 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 7/4 → 15/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2120.3652183367367 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 7/4 → 2/1 | note:F#5 s:sawtooth gain:0.3507338432270528 attack:0.001 decay:0.2 sustain:0 hcutoff:5809.698831278217 cutoff:4000 ]", "[ 7/4 → 2/1 | note:A4 s:sawtooth gain:0.3507338432270528 attack:0.001 decay:0.2 sustain:0 hcutoff:5809.698831278217 cutoff:4000 ]", "[ 7/4 → 2/1 | s:hh3 gain:0.7 ]", @@ -7829,8 +7829,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (7/4 → 2/1) ⇝ 9/4 | note:A3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2135.8582993222344 ]", "[ 3/2 ⇜ (11/6 → 15/8) | note:A5 s:sawtooth gain:0.3422847385870941 attack:0.001 decay:0.2 sustain:0 hcutoff:5845.47833980621 cutoff:4000 ]", "[ 3/2 ⇜ (11/6 → 15/8) | note:C#5 s:sawtooth gain:0.3422847385870941 attack:0.001 decay:0.2 sustain:0 hcutoff:5845.47833980621 cutoff:4000 ]", - "[ 15/8 → 2/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2151.2782118349805 ]", - "[ 15/8 → 2/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2151.2782118349805 ]", + "[ 15/8 → 2/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2151.2782118349805 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 15/8 → 2/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2151.2782118349805 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (15/8 → 2/1) ⇝ 9/4 | note:A5 s:sawtooth gain:0.35343108171056004 attack:0.001 decay:0.2 sustain:0 hcutoff:5796.978025372246 cutoff:4000 ]", "[ (15/8 → 2/1) ⇝ 9/4 | note:C#5 s:sawtooth gain:0.35343108171056004 attack:0.001 decay:0.2 sustain:0 hcutoff:5796.978025372246 cutoff:4000 ]", "[ (15/8 → 2/1) ⇝ 19/8 | note:F#3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2151.2782118349805 ]", @@ -7854,8 +7854,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ 15/8 ⇜ (2/1 → 19/8) | note:A3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2212.17990613181 ]", "[ 7/4 ⇜ (25/12 → 17/8) | note:A5 s:sawtooth gain:0.3586370624427201 attack:0.001 decay:0.2 sustain:0 hcutoff:5770.357934562703 cutoff:4000 ]", "[ 7/4 ⇜ (25/12 → 17/8) | note:C#5 s:sawtooth gain:0.3586370624427201 attack:0.001 decay:0.2 sustain:0 hcutoff:5770.357934562703 cutoff:4000 ]", - "[ 17/8 → 9/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2212.17990613181 ]", - "[ 17/8 → 9/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2212.17990613181 ]", + "[ 17/8 → 9/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2212.17990613181 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 17/8 → 9/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2212.17990613181 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (17/8 → 29/12) ⇝ 5/2 | note:A5 s:sawtooth gain:0.368251964143991 attack:0.001 decay:0.2 sustain:0 hcutoff:5712.469093657604 cutoff:4000 ]", "[ (17/8 → 29/12) ⇝ 5/2 | note:C#5 s:sawtooth gain:0.368251964143991 attack:0.001 decay:0.2 sustain:0 hcutoff:5712.469093657604 cutoff:4000 ]", "[ 15/8 ⇜ (13/6 → 9/4) | note:F#5 s:sawtooth gain:0.36114266880324397 attack:0.001 decay:0.2 sustain:0 hcutoff:5756.463210874651 cutoff:4000 ]", @@ -7867,14 +7867,14 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (9/4 → 31/12) ⇝ 21/8 | note:E5 s:sawtooth gain:0.3726377219727376 attack:0.001 decay:0.2 sustain:0 hcutoff:5681.240017681994 cutoff:4000 ]", "[ 2/1 ⇜ (7/3 → 19/8) | note:A5 s:sawtooth gain:0.3635813269759728 attack:0.001 decay:0.2 sustain:0 hcutoff:5742.18185383172 cutoff:4000 ]", "[ 2/1 ⇜ (7/3 → 19/8) | note:C#5 s:sawtooth gain:0.3635813269759728 attack:0.001 decay:0.2 sustain:0 hcutoff:5742.18185383172 cutoff:4000 ]", - "[ 19/8 → 5/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2271.727259793624 ]", - "[ 19/8 → 5/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2271.727259793624 ]", + "[ 19/8 → 5/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2271.727259793624 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 19/8 → 5/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2271.727259793624 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (19/8 → 8/3) ⇝ 11/4 | note:A5 s:sawtooth gain:0.3767280347874561 attack:0.001 decay:0.2 sustain:0 hcutoff:5648.516028753632 cutoff:4000 ]", "[ (19/8 → 8/3) ⇝ 11/4 | note:C#5 s:sawtooth gain:0.3767280347874561 attack:0.001 decay:0.2 sustain:0 hcutoff:5648.516028753632 cutoff:4000 ]", "[ 17/8 ⇜ (29/12 → 5/2) | note:F#5 s:sawtooth gain:0.368251964143991 attack:0.001 decay:0.2 sustain:0 hcutoff:5712.469093657604 cutoff:4000 ]", "[ 17/8 ⇜ (29/12 → 5/2) | note:A4 s:sawtooth gain:0.368251964143991 attack:0.001 decay:0.2 sustain:0 hcutoff:5712.469093657604 cutoff:4000 ]", - "[ 5/2 → 21/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2300.948092306816 ]", - "[ 5/2 → 21/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2300.948092306816 ]", + "[ 5/2 → 21/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2300.948092306816 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 5/2 → 21/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2300.948092306816 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 5/2 → 11/4 | note:F#5 s:sawtooth gain:0.37865929150004085 attack:0.001 decay:0.2 sustain:0 hcutoff:5631.60041088523 cutoff:4000 ]", "[ 5/2 → 11/4 | note:A4 s:sawtooth gain:0.37865929150004085 attack:0.001 decay:0.2 sustain:0 hcutoff:5631.60041088523 cutoff:4000 ]", "[ 5/2 → 11/4 | s:bd gain:0.7 ]", @@ -7887,8 +7887,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (21/8 → 35/12) ⇝ 3/1 | note:C#5 s:sawtooth gain:0.38398364517932737 attack:0.001 decay:0.2 sustain:0 hcutoff:5578.674030756363 cutoff:4000 ]", "[ 19/8 ⇜ (8/3 → 11/4) | note:F#5 s:sawtooth gain:0.3767280347874561 attack:0.001 decay:0.2 sustain:0 hcutoff:5648.516028753632 cutoff:4000 ]", "[ 19/8 ⇜ (8/3 → 11/4) | note:A4 s:sawtooth gain:0.3767280347874561 attack:0.001 decay:0.2 sustain:0 hcutoff:5648.516028753632 cutoff:4000 ]", - "[ 11/4 → 23/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2358.1960716159333 ]", - "[ 11/4 → 23/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2358.1960716159333 ]", + "[ 11/4 → 23/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2358.1960716159333 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 11/4 → 23/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2358.1960716159333 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 11/4 → 3/1 | note:F#5 s:sawtooth gain:0.3855983939685166 attack:0.001 decay:0.2 sustain:0 hcutoff:5560.31547155504 cutoff:4000 ]", "[ 11/4 → 3/1 | note:A4 s:sawtooth gain:0.3855983939685166 attack:0.001 decay:0.2 sustain:0 hcutoff:5560.31547155504 cutoff:4000 ]", "[ 11/4 → 3/1 | s:hh3 gain:0.7 ]", @@ -7896,8 +7896,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (11/4 → 3/1) ⇝ 25/8 | note:E5 s:sawtooth gain:0.3871314633555296 attack:0.001 decay:0.2 sustain:0 hcutoff:5541.603887904197 cutoff:4000 ]", "[ 5/2 ⇜ (17/6 → 23/8) | note:A5 s:sawtooth gain:0.38051304866630675 attack:0.001 decay:0.2 sustain:0 hcutoff:5614.319554259933 cutoff:4000 ]", "[ 5/2 ⇜ (17/6 → 23/8) | note:C#5 s:sawtooth gain:0.38051304866630675 attack:0.001 decay:0.2 sustain:0 hcutoff:5614.319554259933 cutoff:4000 ]", - "[ 23/8 → 3/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2386.1887343697626 ]", - "[ 23/8 → 3/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2386.1887343697626 ]", + "[ 23/8 → 3/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2386.1887343697626 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 23/8 → 3/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2386.1887343697626 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (23/8 → 3/1) ⇝ 13/4 | note:A5 s:sawtooth gain:0.38994891982521085 attack:0.001 decay:0.2 sustain:0 hcutoff:5503.134531727652 cutoff:4000 ]", "[ (23/8 → 3/1) ⇝ 13/4 | note:C#5 s:sawtooth gain:0.38994891982521085 attack:0.001 decay:0.2 sustain:0 hcutoff:5503.134531727652 cutoff:4000 ]", "[ 21/8 ⇜ (35/12 → 3/1) | note:F#5 s:sawtooth gain:0.38398364517932737 attack:0.001 decay:0.2 sustain:0 hcutoff:5578.674030756363 cutoff:4000 ]", @@ -7913,8 +7913,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (3/1 → 10/3) ⇝ 27/8 | note:E5 s:sawtooth gain:0.39242922708895556 attack:0.001 decay:0.2 sustain:0 hcutoff:5463.2923272018625 cutoff:4000 ]", "[ 11/4 ⇜ (37/12 → 25/8) | note:A5 s:sawtooth gain:0.3871314633555296 attack:0.001 decay:0.2 sustain:0 hcutoff:5541.603887904197 cutoff:4000 ]", "[ 11/4 ⇜ (37/12 → 25/8) | note:C#5 s:sawtooth gain:0.3871314633555296 attack:0.001 decay:0.2 sustain:0 hcutoff:5541.603887904197 cutoff:4000 ]", - "[ 25/8 → 13/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2440.8271075661924 ]", - "[ 25/8 → 13/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2440.8271075661924 ]", + "[ 25/8 → 13/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2440.8271075661924 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 25/8 → 13/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2440.8271075661924 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (25/8 → 41/12) ⇝ 7/2 | note:A5 s:sawtooth gain:0.394566409869316 attack:0.001 decay:0.2 sustain:0 hcutoff:5422.104580183649 cutoff:4000 ]", "[ (25/8 → 41/12) ⇝ 7/2 | note:C#5 s:sawtooth gain:0.394566409869316 attack:0.001 decay:0.2 sustain:0 hcutoff:5422.104580183649 cutoff:4000 ]", "[ 23/8 ⇜ (19/6 → 13/4) | note:F#5 s:sawtooth gain:0.38994891982521085 attack:0.001 decay:0.2 sustain:0 hcutoff:5503.134531727652 cutoff:4000 ]", @@ -7926,14 +7926,14 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (13/4 → 43/12) ⇝ 29/8 | note:E5 s:sawtooth gain:0.3963553195057793 attack:0.001 decay:0.2 sustain:0 hcutoff:5379.599518697443 cutoff:4000 ]", "[ 3/1 ⇜ (10/3 → 27/8) | note:A5 s:sawtooth gain:0.39242922708895556 attack:0.001 decay:0.2 sustain:0 hcutoff:5463.2923272018625 cutoff:4000 ]", "[ 3/1 ⇜ (10/3 → 27/8) | note:C#5 s:sawtooth gain:0.39242922708895556 attack:0.001 decay:0.2 sustain:0 hcutoff:5463.2923272018625 cutoff:4000 ]", - "[ 27/8 → 7/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2493.5603089922215 ]", - "[ 27/8 → 7/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2493.5603089922215 ]", + "[ 27/8 → 7/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2493.5603089922215 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 27/8 → 7/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2493.5603089922215 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (27/8 → 11/3) ⇝ 15/4 | note:A5 s:sawtooth gain:0.3977916463583412 attack:0.001 decay:0.2 sustain:0 hcutoff:5335.806273589214 cutoff:4000 ]", "[ (27/8 → 11/3) ⇝ 15/4 | note:C#5 s:sawtooth gain:0.3977916463583412 attack:0.001 decay:0.2 sustain:0 hcutoff:5335.806273589214 cutoff:4000 ]", "[ 25/8 ⇜ (41/12 → 7/2) | note:F#5 s:sawtooth gain:0.394566409869316 attack:0.001 decay:0.2 sustain:0 hcutoff:5422.104580183649 cutoff:4000 ]", "[ 25/8 ⇜ (41/12 → 7/2) | note:A4 s:sawtooth gain:0.394566409869316 attack:0.001 decay:0.2 sustain:0 hcutoff:5422.104580183649 cutoff:4000 ]", - "[ 7/2 → 29/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2519.1725829012184 ]", - "[ 7/2 → 29/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2519.1725829012184 ]", + "[ 7/2 → 29/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2519.1725829012184 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 7/2 → 29/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2519.1725829012184 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 7/2 → 15/4 | note:F#5 s:sawtooth gain:0.3983764764947172 attack:0.001 decay:0.2 sustain:0 hcutoff:5313.435927530719 cutoff:4000 ]", "[ 7/2 → 15/4 | note:A4 s:sawtooth gain:0.3983764764947172 attack:0.001 decay:0.2 sustain:0 hcutoff:5313.435927530719 cutoff:4000 ]", "[ 7/2 → 15/4 | s:bd gain:0.7 ]", @@ -7950,8 +7950,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (29/8 → 4/1) ⇝ 33/8 | note:B3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2568.811347023862 ]", "[ 27/8 ⇜ (11/3 → 15/4) | note:F#5 s:sawtooth gain:0.3977916463583412 attack:0.001 decay:0.2 sustain:0 hcutoff:5335.806273589214 cutoff:4000 ]", "[ 27/8 ⇜ (11/3 → 15/4) | note:A4 s:sawtooth gain:0.3977916463583412 attack:0.001 decay:0.2 sustain:0 hcutoff:5335.806273589214 cutoff:4000 ]", - "[ 15/4 → 31/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2568.811347023862 ]", - "[ 15/4 → 31/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2568.811347023862 ]", + "[ 15/4 → 31/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2568.811347023862 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 15/4 → 31/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2568.811347023862 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 15/4 → 4/1 | note:F#5 s:sawtooth gain:0.3998193184307759 attack:0.001 decay:0.2 sustain:0 hcutoff:5220.886439234386 cutoff:4000 ]", "[ 15/4 → 4/1 | note:A4 s:sawtooth gain:0.3998193184307759 attack:0.001 decay:0.2 sustain:0 hcutoff:5220.886439234386 cutoff:4000 ]", "[ 15/4 → 4/1 | s:hh3 gain:0.7 ]", @@ -7961,8 +7961,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (15/4 → 4/1) ⇝ 17/4 | note:B3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2580.8797353950404 ]", "[ 7/2 ⇜ (23/6 → 31/8) | note:A5 s:sawtooth gain:0.3988719301898066 attack:0.001 decay:0.2 sustain:0 hcutoff:5290.754858561636 cutoff:4000 ]", "[ 7/2 ⇜ (23/6 → 31/8) | note:C#5 s:sawtooth gain:0.3988719301898066 attack:0.001 decay:0.2 sustain:0 hcutoff:5290.754858561636 cutoff:4000 ]", - "[ 31/8 → 4/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2592.8079367021132 ]", - "[ 31/8 → 4/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2592.8079367021132 ]", + "[ 31/8 → 4/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2592.8079367021132 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 31/8 → 4/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2592.8079367021132 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 31/8 → 4/1 | s:bd gain:0.7 ]", "[ (31/8 → 4/1) ⇝ 17/4 | note:A5 s:sawtooth gain:0.3999548228044306 attack:0.001 decay:0.2 sustain:0 hcutoff:5197.0018638323545 cutoff:4000 ]", "[ (31/8 → 4/1) ⇝ 17/4 | note:C#5 s:sawtooth gain:0.3999548228044306 attack:0.001 decay:0.2 sustain:0 hcutoff:5197.0018638323545 cutoff:4000 ]", @@ -7987,8 +7987,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ 31/8 ⇜ (4/1 → 35/8) | note:B3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2639.083266757757 ]", "[ 15/4 ⇜ (49/12 → 33/8) | note:A5 s:sawtooth gain:0.3999548228044306 attack:0.001 decay:0.2 sustain:0 hcutoff:5148.3645377501725 cutoff:4000 ]", "[ 15/4 ⇜ (49/12 → 33/8) | note:C#5 s:sawtooth gain:0.3999548228044306 attack:0.001 decay:0.2 sustain:0 hcutoff:5148.3645377501725 cutoff:4000 ]", - "[ 33/8 → 17/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2639.083266757757 ]", - "[ 33/8 → 17/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2639.083266757757 ]", + "[ 33/8 → 17/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2639.083266757757 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 33/8 → 17/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2639.083266757757 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (33/8 → 53/12) ⇝ 9/2 | note:A5 s:sawtooth gain:0.3988719301898066 attack:0.001 decay:0.2 sustain:0 hcutoff:5047.734873274585 cutoff:4000 ]", "[ (33/8 → 53/12) ⇝ 9/2 | note:C#5 s:sawtooth gain:0.3988719301898066 attack:0.001 decay:0.2 sustain:0 hcutoff:5047.734873274585 cutoff:4000 ]", "[ 31/8 ⇜ (25/6 → 17/4) | note:F#5 s:sawtooth gain:0.3998193184307759 attack:0.001 decay:0.2 sustain:0 hcutoff:5123.62012082546 cutoff:4000 ]", @@ -8000,14 +8000,14 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (17/4 → 55/12) ⇝ 37/8 | note:E5 s:sawtooth gain:0.3977916463583412 attack:0.001 decay:0.2 sustain:0 hcutoff:4995.811501426648 cutoff:4000 ]", "[ 4/1 ⇜ (13/3 → 35/8) | note:A5 s:sawtooth gain:0.3995935685018036 attack:0.001 decay:0.2 sustain:0 hcutoff:5098.597504951462 cutoff:4000 ]", "[ 4/1 ⇜ (13/3 → 35/8) | note:C#5 s:sawtooth gain:0.3995935685018036 attack:0.001 decay:0.2 sustain:0 hcutoff:5098.597504951462 cutoff:4000 ]", - "[ 35/8 → 9/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2682.97580859032 ]", - "[ 35/8 → 9/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2682.97580859032 ]", + "[ 35/8 → 9/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2682.97580859032 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 35/8 → 9/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2682.97580859032 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (35/8 → 14/3) ⇝ 19/4 | note:A5 s:sawtooth gain:0.3963553195057793 attack:0.001 decay:0.2 sustain:0 hcutoff:4942.862975093085 cutoff:4000 ]", "[ (35/8 → 14/3) ⇝ 19/4 | note:C#5 s:sawtooth gain:0.3963553195057793 attack:0.001 decay:0.2 sustain:0 hcutoff:4942.862975093085 cutoff:4000 ]", "[ 33/8 ⇜ (53/12 → 9/2) | note:F#5 s:sawtooth gain:0.3988719301898066 attack:0.001 decay:0.2 sustain:0 hcutoff:5047.734873274585 cutoff:4000 ]", "[ 33/8 ⇜ (53/12 → 9/2) | note:A4 s:sawtooth gain:0.3988719301898066 attack:0.001 decay:0.2 sustain:0 hcutoff:5047.734873274585 cutoff:4000 ]", - "[ 9/2 → 37/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2703.995258572327 ]", - "[ 9/2 → 37/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2703.995258572327 ]", + "[ 9/2 → 37/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2703.995258572327 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 9/2 → 37/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2703.995258572327 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 9/2 → 19/4 | note:F#5 s:sawtooth gain:0.3955046879791817 attack:0.001 decay:0.2 sustain:0 hcutoff:4916.015592312082 cutoff:4000 ]", "[ 9/2 → 19/4 | note:A4 s:sawtooth gain:0.3955046879791817 attack:0.001 decay:0.2 sustain:0 hcutoff:4916.015592312082 cutoff:4000 ]", "[ 9/2 → 19/4 | s:bd gain:0.7 ]", @@ -8020,8 +8020,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (37/8 → 59/12) ⇝ 5/1 | note:C#5 s:sawtooth gain:0.39242922708895556 attack:0.001 decay:0.2 sustain:0 hcutoff:4834.036289789029 cutoff:4000 ]", "[ 35/8 ⇜ (14/3 → 19/4) | note:F#5 s:sawtooth gain:0.3963553195057793 attack:0.001 decay:0.2 sustain:0 hcutoff:4942.862975093085 cutoff:4000 ]", "[ 35/8 ⇜ (14/3 → 19/4) | note:A4 s:sawtooth gain:0.3963553195057793 attack:0.001 decay:0.2 sustain:0 hcutoff:4942.862975093085 cutoff:4000 ]", - "[ 19/4 → 39/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2744.1172176410028 ]", - "[ 19/4 → 39/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2744.1172176410028 ]", + "[ 19/4 → 39/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2744.1172176410028 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 19/4 → 39/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2744.1172176410028 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 19/4 → 5/1 | note:F#5 s:sawtooth gain:0.3912316097774532 attack:0.001 decay:0.2 sustain:0 hcutoff:4806.246411789873 cutoff:4000 ]", "[ 19/4 → 5/1 | note:A4 s:sawtooth gain:0.3912316097774532 attack:0.001 decay:0.2 sustain:0 hcutoff:4806.246411789873 cutoff:4000 ]", "[ 19/4 → 5/1 | s:hh3 gain:0.7 ]", @@ -8029,8 +8029,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (19/4 → 5/1) ⇝ 41/8 | note:E5 s:sawtooth gain:0.38994891982521085 attack:0.001 decay:0.2 sustain:0 hcutoff:4778.23271519263 cutoff:4000 ]", "[ 9/2 ⇜ (29/6 → 39/8) | note:A5 s:sawtooth gain:0.394566409869316 attack:0.001 decay:0.2 sustain:0 hcutoff:4888.925582549005 cutoff:4000 ]", "[ 9/2 ⇜ (29/6 → 39/8) | note:C#5 s:sawtooth gain:0.394566409869316 attack:0.001 decay:0.2 sustain:0 hcutoff:4888.925582549005 cutoff:4000 ]", - "[ 39/8 → 5/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2763.195558759784 ]", - "[ 39/8 → 5/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2763.195558759784 ]", + "[ 39/8 → 5/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2763.195558759784 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 39/8 → 5/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2763.195558759784 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (39/8 → 5/1) ⇝ 21/4 | note:A5 s:sawtooth gain:0.3871314633555296 attack:0.001 decay:0.2 sustain:0 hcutoff:4721.553103742387 cutoff:4000 ]", "[ (39/8 → 5/1) ⇝ 21/4 | note:C#5 s:sawtooth gain:0.3871314633555296 attack:0.001 decay:0.2 sustain:0 hcutoff:4721.553103742387 cutoff:4000 ]", "[ 37/8 ⇜ (59/12 → 5/1) | note:F#5 s:sawtooth gain:0.39242922708895556 attack:0.001 decay:0.2 sustain:0 hcutoff:4834.036289789029 cutoff:4000 ]", @@ -8046,8 +8046,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (5/1 → 16/3) ⇝ 43/8 | note:E5 s:sawtooth gain:0.38398364517932737 attack:0.001 decay:0.2 sustain:0 hcutoff:4664.036300812779 cutoff:4000 ]", "[ 19/4 ⇜ (61/12 → 41/8) | note:A5 s:sawtooth gain:0.38994891982521085 attack:0.001 decay:0.2 sustain:0 hcutoff:4778.23271519263 cutoff:4000 ]", "[ 19/4 ⇜ (61/12 → 41/8) | note:C#5 s:sawtooth gain:0.38994891982521085 attack:0.001 decay:0.2 sustain:0 hcutoff:4778.23271519263 cutoff:4000 ]", - "[ 41/8 → 21/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2799.329510692108 ]", - "[ 41/8 → 21/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2799.329510692108 ]", + "[ 41/8 → 21/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2799.329510692108 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 41/8 → 21/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2799.329510692108 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (41/8 → 65/12) ⇝ 11/2 | note:A5 s:sawtooth gain:0.38051304866630675 attack:0.001 decay:0.2 sustain:0 hcutoff:4605.721725547503 cutoff:4000 ]", "[ (41/8 → 65/12) ⇝ 11/2 | note:C#5 s:sawtooth gain:0.38051304866630675 attack:0.001 decay:0.2 sustain:0 hcutoff:4605.721725547503 cutoff:4000 ]", "[ 39/8 ⇜ (31/6 → 21/4) | note:F#5 s:sawtooth gain:0.3871314633555296 attack:0.001 decay:0.2 sustain:0 hcutoff:4721.553103742387 cutoff:4000 ]", @@ -8059,14 +8059,14 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (21/4 → 67/12) ⇝ 45/8 | note:E5 s:sawtooth gain:0.3767280347874561 attack:0.001 decay:0.2 sustain:0 hcutoff:4546.64934384357 cutoff:4000 ]", "[ 5/1 ⇜ (16/3 → 43/8) | note:A5 s:sawtooth gain:0.38398364517932737 attack:0.001 decay:0.2 sustain:0 hcutoff:4664.036300812779 cutoff:4000 ]", "[ 5/1 ⇜ (16/3 → 43/8) | note:C#5 s:sawtooth gain:0.38398364517932737 attack:0.001 decay:0.2 sustain:0 hcutoff:4664.036300812779 cutoff:4000 ]", - "[ 43/8 → 11/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2832.694627163799 ]", - "[ 43/8 → 11/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2832.694627163799 ]", + "[ 43/8 → 11/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2832.694627163799 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 43/8 → 11/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2832.694627163799 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (43/8 → 17/3) ⇝ 23/4 | note:A5 s:sawtooth gain:0.3726377219727376 attack:0.001 decay:0.2 sustain:0 hcutoff:4486.859640960669 cutoff:4000 ]", "[ (43/8 → 17/3) ⇝ 23/4 | note:C#5 s:sawtooth gain:0.3726377219727376 attack:0.001 decay:0.2 sustain:0 hcutoff:4486.859640960669 cutoff:4000 ]", "[ 41/8 ⇜ (65/12 → 11/2) | note:F#5 s:sawtooth gain:0.38051304866630675 attack:0.001 decay:0.2 sustain:0 hcutoff:4605.721725547503 cutoff:4000 ]", "[ 41/8 ⇜ (65/12 → 11/2) | note:A4 s:sawtooth gain:0.38051304866630675 attack:0.001 decay:0.2 sustain:0 hcutoff:4605.721725547503 cutoff:4000 ]", - "[ 11/2 → 45/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2848.313487543853 ]", - "[ 11/2 → 45/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2848.313487543853 ]", + "[ 11/2 → 45/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2848.313487543853 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 11/2 → 45/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2848.313487543853 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 11/2 → 23/4 | note:F#5 s:sawtooth gain:0.3704811297220968 attack:0.001 decay:0.2 sustain:0 hcutoff:4456.708580912725 cutoff:4000 ]", "[ 11/2 → 23/4 | note:A4 s:sawtooth gain:0.3704811297220968 attack:0.001 decay:0.2 sustain:0 hcutoff:4456.708580912725 cutoff:4000 ]", "[ 11/2 → 23/4 | s:bd gain:0.7 ]", @@ -8083,8 +8083,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (45/8 → 6/1) ⇝ 49/8 | note:A3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2877.376777172205 ]", "[ 43/8 ⇜ (17/3 → 23/4) | note:F#5 s:sawtooth gain:0.3726377219727376 attack:0.001 decay:0.2 sustain:0 hcutoff:4486.859640960669 cutoff:4000 ]", "[ 43/8 ⇜ (17/3 → 23/4) | note:A4 s:sawtooth gain:0.3726377219727376 attack:0.001 decay:0.2 sustain:0 hcutoff:4486.859640960669 cutoff:4000 ]", - "[ 23/4 → 47/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2877.376777172205 ]", - "[ 23/4 → 47/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2877.376777172205 ]", + "[ 23/4 → 47/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2877.376777172205 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 23/4 → 47/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2877.376777172205 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 23/4 → 6/1 | note:F#5 s:sawtooth gain:0.36114266880324386 attack:0.001 decay:0.2 sustain:0 hcutoff:4334.517148084427 cutoff:4000 ]", "[ 23/4 → 6/1 | note:A4 s:sawtooth gain:0.36114266880324386 attack:0.001 decay:0.2 sustain:0 hcutoff:4334.517148084427 cutoff:4000 ]", "[ 23/4 → 6/1 | s:hh3 gain:0.7 ]", @@ -8094,8 +8094,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (23/4 → 6/1) ⇝ 25/4 | note:A3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2884.183170199766 ]", "[ 11/2 ⇜ (35/6 → 47/8) | note:A5 s:sawtooth gain:0.368251964143991 attack:0.001 decay:0.2 sustain:0 hcutoff:4426.39359377459 cutoff:4000 ]", "[ 11/2 ⇜ (35/6 → 47/8) | note:C#5 s:sawtooth gain:0.368251964143991 attack:0.001 decay:0.2 sustain:0 hcutoff:4426.39359377459 cutoff:4000 ]", - "[ 47/8 → 6/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2890.803699781578 ]", - "[ 47/8 → 6/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2890.803699781578 ]", + "[ 47/8 → 6/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2890.803699781578 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 47/8 → 6/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2890.803699781578 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (47/8 → 6/1) ⇝ 25/4 | note:A5 s:sawtooth gain:0.3586370624427201 attack:0.001 decay:0.2 sustain:0 hcutoff:4303.598663257904 cutoff:4000 ]", "[ (47/8 → 6/1) ⇝ 25/4 | note:C#5 s:sawtooth gain:0.3586370624427201 attack:0.001 decay:0.2 sustain:0 hcutoff:4303.598663257904 cutoff:4000 ]", "[ (47/8 → 6/1) ⇝ 51/8 | note:F#3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2890.803699781578 ]", @@ -8119,8 +8119,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ 47/8 ⇜ (6/1 → 51/8) | note:A3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2915.4076660819765 ]", "[ 23/4 ⇜ (73/12 → 49/8) | note:A5 s:sawtooth gain:0.35343108171056015 attack:0.001 decay:0.2 sustain:0 hcutoff:4241.3539374389275 cutoff:4000 ]", "[ 23/4 ⇜ (73/12 → 49/8) | note:C#5 s:sawtooth gain:0.35343108171056015 attack:0.001 decay:0.2 sustain:0 hcutoff:4241.3539374389275 cutoff:4000 ]", - "[ 49/8 → 25/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2915.4076660819765 ]", - "[ 49/8 → 25/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2915.4076660819765 ]", + "[ 49/8 → 25/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2915.4076660819765 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 49/8 → 25/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2915.4076660819765 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (49/8 → 77/12) ⇝ 13/2 | note:A5 s:sawtooth gain:0.3422847385870941 attack:0.001 decay:0.2 sustain:0 hcutoff:4115.383232572483 cutoff:4000 ]", "[ (49/8 → 77/12) ⇝ 13/2 | note:C#5 s:sawtooth gain:0.3422847385870941 attack:0.001 decay:0.2 sustain:0 hcutoff:4115.383232572483 cutoff:4000 ]", "[ 47/8 ⇜ (37/6 → 25/4) | note:F#5 s:sawtooth gain:0.3507338432270528 attack:0.001 decay:0.2 sustain:0 hcutoff:4210.038361759807 cutoff:4000 ]", @@ -8132,14 +8132,14 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (25/4 → 79/12) ⇝ 53/8 | note:E5 s:sawtooth gain:0.3363712287126769 attack:0.001 decay:0.2 sustain:0 hcutoff:4051.743587553753 cutoff:4000 ]", "[ 6/1 ⇜ (19/3 → 51/8) | note:A5 s:sawtooth gain:0.3479759264430665 attack:0.001 decay:0.2 sustain:0 hcutoff:4178.601124662687 cutoff:4000 ]", "[ 6/1 ⇜ (19/3 → 51/8) | note:C#5 s:sawtooth gain:0.3479759264430665 attack:0.001 decay:0.2 sustain:0 hcutoff:4178.601124662687 cutoff:4000 ]", - "[ 51/8 → 13/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2936.9631544781614 ]", - "[ 51/8 → 13/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2936.9631544781614 ]", + "[ 51/8 → 13/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2936.9631544781614 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 51/8 → 13/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2936.9631544781614 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (51/8 → 20/3) ⇝ 27/4 | note:A5 s:sawtooth gain:0.3302496429830646 attack:0.001 decay:0.2 sustain:0 hcutoff:3987.7258050403216 cutoff:4000 ]", "[ (51/8 → 20/3) ⇝ 27/4 | note:C#5 s:sawtooth gain:0.3302496429830646 attack:0.001 decay:0.2 sustain:0 hcutoff:3987.7258050403216 cutoff:4000 ]", "[ 49/8 ⇜ (77/12 → 13/2) | note:F#5 s:sawtooth gain:0.3422847385870941 attack:0.001 decay:0.2 sustain:0 hcutoff:4115.383232572483 cutoff:4000 ]", "[ 49/8 ⇜ (77/12 → 13/2) | note:A4 s:sawtooth gain:0.3422847385870941 attack:0.001 decay:0.2 sustain:0 hcutoff:4115.383232572483 cutoff:4000 ]", - "[ 13/2 → 53/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2946.5812012110136 ]", - "[ 13/2 → 53/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2946.5812012110136 ]", + "[ 13/2 → 53/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2946.5812012110136 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 13/2 → 53/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2946.5812012110136 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 13/2 → 27/4 | note:F#5 s:sawtooth gain:0.3271154116289833 attack:0.001 decay:0.2 sustain:0 hcutoff:3955.588813730369 cutoff:4000 ]", "[ 13/2 → 27/4 | note:A4 s:sawtooth gain:0.3271154116289833 attack:0.001 decay:0.2 sustain:0 hcutoff:3955.588813730369 cutoff:4000 ]", "[ 13/2 → 27/4 | s:bd gain:0.7 ]", @@ -8152,8 +8152,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (53/8 → 83/12) ⇝ 7/1 | note:C#5 s:sawtooth gain:0.3174416994481911 attack:0.001 decay:0.2 sustain:0 hcutoff:3858.7315549779487 cutoff:4000 ]", "[ 51/8 ⇜ (20/3 → 27/4) | note:F#5 s:sawtooth gain:0.3302496429830646 attack:0.001 decay:0.2 sustain:0 hcutoff:3987.7258050403216 cutoff:4000 ]", "[ 51/8 ⇜ (20/3 → 27/4) | note:A4 s:sawtooth gain:0.3302496429830646 attack:0.001 decay:0.2 sustain:0 hcutoff:3987.7258050403216 cutoff:4000 ]", - "[ 27/4 → 55/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2963.468935477506 ]", - "[ 27/4 → 55/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2963.468935477506 ]", + "[ 27/4 → 55/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2963.468935477506 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 27/4 → 55/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2963.468935477506 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 27/4 → 7/1 | note:F#5 s:sawtooth gain:0.31413326401454233 attack:0.001 decay:0.2 sustain:0 hcutoff:3826.315480550129 cutoff:4000 ]", "[ 27/4 → 7/1 | note:A4 s:sawtooth gain:0.31413326401454233 attack:0.001 decay:0.2 sustain:0 hcutoff:3826.315480550129 cutoff:4000 ]", "[ 27/4 → 7/1 | s:hh3 gain:0.7 ]", @@ -8161,8 +8161,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (27/4 → 7/1) ⇝ 57/8 | note:E5 s:sawtooth gain:0.3107861971007485 attack:0.001 decay:0.2 sustain:0 hcutoff:3793.8434936445938 cutoff:4000 ]", "[ 13/2 ⇜ (41/6 → 55/8) | note:A5 s:sawtooth gain:0.32393472883446767 attack:0.001 decay:0.2 sustain:0 hcutoff:3923.373759622562 cutoff:4000 ]", "[ 13/2 ⇜ (41/6 → 55/8) | note:C#5 s:sawtooth gain:0.32393472883446767 attack:0.001 decay:0.2 sustain:0 hcutoff:3923.373759622562 cutoff:4000 ]", - "[ 55/8 → 7/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2970.728450471497 ]", - "[ 55/8 → 7/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2970.728450471497 ]", + "[ 55/8 → 7/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2970.728450471497 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 55/8 → 7/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2970.728450471497 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (55/8 → 7/1) ⇝ 29/4 | note:A5 s:sawtooth gain:0.30398425548024827 attack:0.001 decay:0.2 sustain:0 hcutoff:3728.7540466585065 cutoff:4000 ]", "[ (55/8 → 7/1) ⇝ 29/4 | note:C#5 s:sawtooth gain:0.30398425548024827 attack:0.001 decay:0.2 sustain:0 hcutoff:3728.7540466585065 cutoff:4000 ]", "[ 53/8 ⇜ (83/12 → 7/1) | note:F#5 s:sawtooth gain:0.3174416994481911 attack:0.001 decay:0.2 sustain:0 hcutoff:3858.7315549779487 cutoff:4000 ]", @@ -8178,8 +8178,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (7/1 → 22/3) ⇝ 59/8 | note:E5 s:sawtooth gain:0.29705226105983373 attack:0.001 decay:0.2 sustain:0 hcutoff:3663.507823075358 cutoff:4000 ]", "[ 27/4 ⇜ (85/12 → 57/8) | note:A5 s:sawtooth gain:0.3107861971007485 attack:0.001 decay:0.2 sustain:0 hcutoff:3793.8434936445938 cutoff:4000 ]", "[ 27/4 ⇜ (85/12 → 57/8) | note:C#5 s:sawtooth gain:0.3107861971007485 attack:0.001 decay:0.2 sustain:0 hcutoff:3793.8434936445938 cutoff:4000 ]", - "[ 57/8 → 29/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2982.856914513109 ]", - "[ 57/8 → 29/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2982.856914513109 ]", + "[ 57/8 → 29/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2982.856914513109 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 57/8 → 29/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2982.856914513109 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (57/8 → 89/12) ⇝ 15/2 | note:A5 s:sawtooth gain:0.29000691362123476 attack:0.001 decay:0.2 sustain:0 hcutoff:3598.149539397671 cutoff:4000 ]", "[ (57/8 → 89/12) ⇝ 15/2 | note:C#5 s:sawtooth gain:0.29000691362123476 attack:0.001 decay:0.2 sustain:0 hcutoff:3598.149539397671 cutoff:4000 ]", "[ 55/8 ⇜ (43/6 → 29/4) | note:F#5 s:sawtooth gain:0.30398425548024827 attack:0.001 decay:0.2 sustain:0 hcutoff:3728.7540466585065 cutoff:4000 ]", @@ -8191,14 +8191,14 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (29/4 → 91/12) ⇝ 61/8 | note:E5 s:sawtooth gain:0.28286518602353056 attack:0.001 decay:0.2 sustain:0 hcutoff:3532.7239889283615 cutoff:4000 ]", "[ 7/1 ⇜ (22/3 → 59/8) | note:A5 s:sawtooth gain:0.29705226105983373 attack:0.001 decay:0.2 sustain:0 hcutoff:3663.507823075358 cutoff:4000 ]", "[ 7/1 ⇜ (22/3 → 59/8) | note:C#5 s:sawtooth gain:0.29705226105983373 attack:0.001 decay:0.2 sustain:0 hcutoff:3663.507823075358 cutoff:4000 ]", - "[ 59/8 → 15/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2991.774409503181 ]", - "[ 59/8 → 15/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2991.774409503181 ]", + "[ 59/8 → 15/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2991.774409503181 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 59/8 → 15/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2991.774409503181 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (59/8 → 23/3) ⇝ 31/4 | note:A5 s:sawtooth gain:0.2756442833140452 attack:0.001 decay:0.2 sustain:0 hcutoff:3467.276011071639 cutoff:4000 ]", "[ (59/8 → 23/3) ⇝ 31/4 | note:C#5 s:sawtooth gain:0.2756442833140452 attack:0.001 decay:0.2 sustain:0 hcutoff:3467.276011071639 cutoff:4000 ]", "[ 57/8 ⇜ (89/12 → 15/2) | note:F#5 s:sawtooth gain:0.29000691362123476 attack:0.001 decay:0.2 sustain:0 hcutoff:3598.149539397671 cutoff:4000 ]", "[ 57/8 ⇜ (89/12 → 15/2) | note:A4 s:sawtooth gain:0.29000691362123476 attack:0.001 decay:0.2 sustain:0 hcutoff:3598.149539397671 cutoff:4000 ]", - "[ 15/2 → 61/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2995.0220264467503 ]", - "[ 15/2 → 61/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2995.0220264467503 ]", + "[ 15/2 → 61/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2995.0220264467503 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 15/2 → 61/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2995.0220264467503 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 15/2 → 31/4 | note:F#5 s:sawtooth gain:0.2720095711683043 attack:0.001 decay:0.2 sustain:0 hcutoff:3434.557629230318 cutoff:4000 ]", "[ 15/2 → 31/4 | note:A4 s:sawtooth gain:0.2720095711683043 attack:0.001 decay:0.2 sustain:0 hcutoff:3434.557629230318 cutoff:4000 ]", "[ 15/2 → 31/4 | s:bd gain:0.7 ]", @@ -8215,8 +8215,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (61/8 → 8/1) ⇝ 65/8 | note:B3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2999.0852191942718 ]", "[ 59/8 ⇜ (23/3 → 31/4) | note:F#5 s:sawtooth gain:0.2756442833140452 attack:0.001 decay:0.2 sustain:0 hcutoff:3467.276011071639 cutoff:4000 ]", "[ 59/8 ⇜ (23/3 → 31/4) | note:A4 s:sawtooth gain:0.2756442833140452 attack:0.001 decay:0.2 sustain:0 hcutoff:3467.276011071639 cutoff:4000 ]", - "[ 31/4 → 63/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.0852191942718 ]", - "[ 31/4 → 63/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.0852191942718 ]", + "[ 31/4 → 63/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.0852191942718 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 31/4 → 63/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.0852191942718 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 31/4 → 8/1 | note:F#5 s:sawtooth gain:0.2573601511491127 attack:0.001 decay:0.2 sustain:0 hcutoff:3303.852260680389 cutoff:4000 ]", "[ 31/4 → 8/1 | note:A4 s:sawtooth gain:0.2573601511491127 attack:0.001 decay:0.2 sustain:0 hcutoff:3303.852260680389 cutoff:4000 ]", "[ 31/4 → 8/1 | s:hh3 gain:0.7 ]", @@ -8226,8 +8226,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (31/4 → 8/1) ⇝ 33/4 | note:B3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2999.5934052398757 ]", "[ 15/2 ⇜ (47/6 → 63/8) | note:A5 s:sawtooth gain:0.2683616012798825 attack:0.001 decay:0.2 sustain:0 hcutoff:3401.8504606023293 cutoff:4000 ]", "[ 15/2 ⇜ (47/6 → 63/8) | note:C#5 s:sawtooth gain:0.2683616012798825 attack:0.001 decay:0.2 sustain:0 hcutoff:3401.8504606023293 cutoff:4000 ]", - "[ 63/8 → 8/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.898347482845 ]", - "[ 63/8 → 8/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.898347482845 ]", + "[ 63/8 → 8/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.898347482845 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 63/8 → 8/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.898347482845 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 63/8 → 8/1 | s:bd gain:0.7 ]", "[ (63/8 → 8/1) ⇝ 33/4 | note:A5 s:sawtooth gain:0.2536811842784369 attack:0.001 decay:0.2 sustain:0 hcutoff:3271.2459533414954 cutoff:4000 ]", "[ (63/8 → 8/1) ⇝ 33/4 | note:C#5 s:sawtooth gain:0.2536811842784369 attack:0.001 decay:0.2 sustain:0 hcutoff:3271.2459533414954 cutoff:4000 ]", @@ -8252,8 +8252,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ 63/8 ⇜ (8/1 → 67/8) | note:B3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2999.0852191942718 ]", "[ 31/4 ⇜ (97/12 → 65/8) | note:A5 s:sawtooth gain:0.24631881572156322 attack:0.001 decay:0.2 sustain:0 hcutoff:3206.156506355406 cutoff:4000 ]", "[ 31/4 ⇜ (97/12 → 65/8) | note:C#5 s:sawtooth gain:0.24631881572156322 attack:0.001 decay:0.2 sustain:0 hcutoff:3206.156506355406 cutoff:4000 ]", - "[ 65/8 → 33/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.0852191942718 ]", - "[ 65/8 → 33/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.0852191942718 ]", + "[ 65/8 → 33/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.0852191942718 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 65/8 → 33/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2999.0852191942718 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (65/8 → 101/12) ⇝ 17/2 | note:A5 s:sawtooth gain:0.2316383987201176 attack:0.001 decay:0.2 sustain:0 hcutoff:3076.6262403774385 cutoff:4000 ]", "[ (65/8 → 101/12) ⇝ 17/2 | note:C#5 s:sawtooth gain:0.2316383987201176 attack:0.001 decay:0.2 sustain:0 hcutoff:3076.6262403774385 cutoff:4000 ]", "[ 63/8 ⇜ (49/6 → 33/4) | note:F#5 s:sawtooth gain:0.24263984885088735 attack:0.001 decay:0.2 sustain:0 hcutoff:3173.6845194498705 cutoff:4000 ]", @@ -8265,14 +8265,14 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (33/4 → 103/12) ⇝ 69/8 | note:E5 s:sawtooth gain:0.2243557166859549 attack:0.001 decay:0.2 sustain:0 hcutoff:3012.274194959679 cutoff:4000 ]", "[ 8/1 ⇜ (25/3 → 67/8) | note:A5 s:sawtooth gain:0.2389653154600499 attack:0.001 decay:0.2 sustain:0 hcutoff:3141.2684450220513 cutoff:4000 ]", "[ 8/1 ⇜ (25/3 → 67/8) | note:C#5 s:sawtooth gain:0.2389653154600499 attack:0.001 decay:0.2 sustain:0 hcutoff:3141.2684450220513 cutoff:4000 ]", - "[ 67/8 → 17/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2995.0220264467503 ]", - "[ 67/8 → 17/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2995.0220264467503 ]", + "[ 67/8 → 17/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2995.0220264467503 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 67/8 → 17/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2995.0220264467503 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (67/8 → 26/3) ⇝ 35/4 | note:A5 s:sawtooth gain:0.21713481397646955 attack:0.001 decay:0.2 sustain:0 hcutoff:2948.256412446248 cutoff:4000 ]", "[ (67/8 → 26/3) ⇝ 35/4 | note:C#5 s:sawtooth gain:0.21713481397646955 attack:0.001 decay:0.2 sustain:0 hcutoff:2948.256412446248 cutoff:4000 ]", "[ 65/8 ⇜ (101/12 → 17/2) | note:F#5 s:sawtooth gain:0.2316383987201176 attack:0.001 decay:0.2 sustain:0 hcutoff:3076.6262403774385 cutoff:4000 ]", "[ 65/8 ⇜ (101/12 → 17/2) | note:A4 s:sawtooth gain:0.2316383987201176 attack:0.001 decay:0.2 sustain:0 hcutoff:3076.6262403774385 cutoff:4000 ]", - "[ 17/2 → 69/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2991.774409503181 ]", - "[ 17/2 → 69/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2991.774409503181 ]", + "[ 17/2 → 69/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2991.774409503181 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 17/2 → 69/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2991.774409503181 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 17/2 → 35/4 | note:F#5 s:sawtooth gain:0.21355297301451046 attack:0.001 decay:0.2 sustain:0 hcutoff:2916.386590360237 cutoff:4000 ]", "[ 17/2 → 35/4 | note:A4 s:sawtooth gain:0.21355297301451046 attack:0.001 decay:0.2 sustain:0 hcutoff:2916.386590360237 cutoff:4000 ]", "[ 17/2 → 35/4 | s:bd gain:0.7 ]", @@ -8285,8 +8285,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (69/8 → 107/12) ⇝ 9/1 | note:C#5 s:sawtooth gain:0.20294773894016632 attack:0.001 decay:0.2 sustain:0 hcutoff:2821.398875337315 cutoff:4000 ]", "[ 67/8 ⇜ (26/3 → 35/4) | note:F#5 s:sawtooth gain:0.21713481397646955 attack:0.001 decay:0.2 sustain:0 hcutoff:2948.256412446248 cutoff:4000 ]", "[ 67/8 ⇜ (26/3 → 35/4) | note:A4 s:sawtooth gain:0.21713481397646955 attack:0.001 decay:0.2 sustain:0 hcutoff:2948.256412446248 cutoff:4000 ]", - "[ 35/4 → 71/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2982.856914513109 ]", - "[ 35/4 → 71/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2982.856914513109 ]", + "[ 35/4 → 71/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2982.856914513109 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 35/4 → 71/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2982.856914513109 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 35/4 → 9/1 | note:F#5 s:sawtooth gain:0.19946652199116702 attack:0.001 decay:0.2 sustain:0 hcutoff:2789.9616382401937 cutoff:4000 ]", "[ 35/4 → 9/1 | note:A4 s:sawtooth gain:0.19946652199116702 attack:0.001 decay:0.2 sustain:0 hcutoff:2789.9616382401937 cutoff:4000 ]", "[ 35/4 → 9/1 | s:hh3 gain:0.7 ]", @@ -8294,8 +8294,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (35/4 → 9/1) ⇝ 73/8 | note:E5 s:sawtooth gain:0.1960157445197518 attack:0.001 decay:0.2 sustain:0 hcutoff:2758.6460625610725 cutoff:4000 ]", "[ 17/2 ⇜ (53/6 → 71/8) | note:A5 s:sawtooth gain:0.2099930863787653 attack:0.001 decay:0.2 sustain:0 hcutoff:2884.6167674275184 cutoff:4000 ]", "[ 17/2 ⇜ (53/6 → 71/8) | note:C#5 s:sawtooth gain:0.2099930863787653 attack:0.001 decay:0.2 sustain:0 hcutoff:2884.6167674275184 cutoff:4000 ]", - "[ 71/8 → 9/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2977.1924080321423 ]", - "[ 71/8 → 9/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2977.1924080321423 ]", + "[ 71/8 → 9/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2977.1924080321423 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 71/8 → 9/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2977.1924080321423 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (71/8 → 9/1) ⇝ 37/4 | note:A5 s:sawtooth gain:0.18921380289925155 attack:0.001 decay:0.2 sustain:0 hcutoff:2696.4013367420957 cutoff:4000 ]", "[ (71/8 → 9/1) ⇝ 37/4 | note:C#5 s:sawtooth gain:0.18921380289925155 attack:0.001 decay:0.2 sustain:0 hcutoff:2696.4013367420957 cutoff:4000 ]", "[ 69/8 ⇜ (107/12 → 9/1) | note:F#5 s:sawtooth gain:0.20294773894016632 attack:0.001 decay:0.2 sustain:0 hcutoff:2821.398875337315 cutoff:4000 ]", @@ -8311,8 +8311,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (9/1 → 28/3) ⇝ 75/8 | note:E5 s:sawtooth gain:0.182558300551809 attack:0.001 decay:0.2 sustain:0 hcutoff:2634.707357306267 cutoff:4000 ]", "[ 35/4 ⇜ (109/12 → 73/8) | note:A5 s:sawtooth gain:0.1960157445197518 attack:0.001 decay:0.2 sustain:0 hcutoff:2758.6460625610725 cutoff:4000 ]", "[ 35/4 ⇜ (109/12 → 73/8) | note:C#5 s:sawtooth gain:0.1960157445197518 attack:0.001 decay:0.2 sustain:0 hcutoff:2758.6460625610725 cutoff:4000 ]", - "[ 73/8 → 37/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2963.4689354775064 ]", - "[ 73/8 → 37/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2963.4689354775064 ]", + "[ 73/8 → 37/4 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2963.4689354775064 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 73/8 → 37/4 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2963.4689354775064 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (73/8 → 113/12) ⇝ 19/2 | note:A5 s:sawtooth gain:0.17606527116553244 attack:0.001 decay:0.2 sustain:0 hcutoff:2573.60640622541 cutoff:4000 ]", "[ (73/8 → 113/12) ⇝ 19/2 | note:C#5 s:sawtooth gain:0.17606527116553244 attack:0.001 decay:0.2 sustain:0 hcutoff:2573.60640622541 cutoff:4000 ]", "[ 71/8 ⇜ (55/6 → 37/4) | note:F#5 s:sawtooth gain:0.18921380289925155 attack:0.001 decay:0.2 sustain:0 hcutoff:2696.4013367420957 cutoff:4000 ]", @@ -8324,14 +8324,14 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (37/4 → 115/12) ⇝ 77/8 | note:E5 s:sawtooth gain:0.16975035701693547 attack:0.001 decay:0.2 sustain:0 hcutoff:2513.140359039332 cutoff:4000 ]", "[ 9/1 ⇜ (28/3 → 75/8) | note:A5 s:sawtooth gain:0.182558300551809 attack:0.001 decay:0.2 sustain:0 hcutoff:2634.707357306267 cutoff:4000 ]", "[ 9/1 ⇜ (28/3 → 75/8) | note:C#5 s:sawtooth gain:0.182558300551809 attack:0.001 decay:0.2 sustain:0 hcutoff:2634.707357306267 cutoff:4000 ]", - "[ 75/8 → 19/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2946.5812012110136 ]", - "[ 75/8 → 19/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2946.5812012110136 ]", + "[ 75/8 → 19/2 | note:D2 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2946.5812012110136 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 75/8 → 19/2 | note:D2 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2946.5812012110136 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (75/8 → 29/3) ⇝ 39/4 | note:A5 s:sawtooth gain:0.16362877128732323 attack:0.001 decay:0.2 sustain:0 hcutoff:2453.350656156431 cutoff:4000 ]", "[ (75/8 → 29/3) ⇝ 39/4 | note:C#5 s:sawtooth gain:0.16362877128732323 attack:0.001 decay:0.2 sustain:0 hcutoff:2453.350656156431 cutoff:4000 ]", "[ 73/8 ⇜ (113/12 → 19/2) | note:F#5 s:sawtooth gain:0.17606527116553244 attack:0.001 decay:0.2 sustain:0 hcutoff:2573.60640622541 cutoff:4000 ]", "[ 73/8 ⇜ (113/12 → 19/2) | note:A4 s:sawtooth gain:0.17606527116553244 attack:0.001 decay:0.2 sustain:0 hcutoff:2573.60640622541 cutoff:4000 ]", - "[ 19/2 → 77/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2936.9631544781614 ]", - "[ 19/2 → 77/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2936.9631544781614 ]", + "[ 19/2 → 77/8 | note:D1 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2936.9631544781614 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 19/2 → 77/8 | note:D1 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2936.9631544781614 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 19/2 → 39/4 | note:F#5 s:sawtooth gain:0.16064510432613502 attack:0.001 decay:0.2 sustain:0 hcutoff:2423.7222579792624 cutoff:4000 ]", "[ 19/2 → 39/4 | note:A4 s:sawtooth gain:0.16064510432613502 attack:0.001 decay:0.2 sustain:0 hcutoff:2423.7222579792624 cutoff:4000 ]", "[ 19/2 → 39/4 | s:bd gain:0.7 ]", @@ -8348,8 +8348,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (77/8 → 10/1) ⇝ 81/8 | note:A3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2915.4076660819765 ]", "[ 75/8 ⇜ (29/3 → 39/4) | note:F#5 s:sawtooth gain:0.16362877128732323 attack:0.001 decay:0.2 sustain:0 hcutoff:2453.350656156431 cutoff:4000 ]", "[ 75/8 ⇜ (29/3 → 39/4) | note:A4 s:sawtooth gain:0.16362877128732323 attack:0.001 decay:0.2 sustain:0 hcutoff:2453.350656156431 cutoff:4000 ]", - "[ 39/4 → 79/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2915.4076660819765 ]", - "[ 39/4 → 79/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2915.4076660819765 ]", + "[ 39/4 → 79/8 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2915.4076660819765 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 39/4 → 79/8 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2915.4076660819765 lpattack:0.1 lpenv:2 ftype:24db ]", "[ 39/4 → 10/1 | note:F#5 s:sawtooth gain:0.14926615677294724 attack:0.001 decay:0.2 sustain:0 hcutoff:2307.1030993509794 cutoff:4000 ]", "[ 39/4 → 10/1 | note:A4 s:sawtooth gain:0.14926615677294724 attack:0.001 decay:0.2 sustain:0 hcutoff:2307.1030993509794 cutoff:4000 ]", "[ 39/4 → 10/1 | s:hh3 gain:0.7 ]", @@ -8359,8 +8359,8 @@ exports[`renders tunes > tune: hyperpop 1`] = ` "[ (39/4 → 10/1) ⇝ 41/4 | note:A3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2909.5402784268977 ]", "[ 19/2 ⇜ (59/6 → 79/8) | note:A5 s:sawtooth gain:0.157715261412906 attack:0.001 decay:0.2 sustain:0 hcutoff:2394.2782744524975 cutoff:4000 ]", "[ 19/2 ⇜ (59/6 → 79/8) | note:C#5 s:sawtooth gain:0.157715261412906 attack:0.001 decay:0.2 sustain:0 hcutoff:2394.2782744524975 cutoff:4000 ]", - "[ 79/8 → 10/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2903.483208638841 ]", - "[ 79/8 → 10/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2903.483208638841 ]", + "[ 79/8 → 10/1 | note:D3 s:sawtooth gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2903.483208638841 lpattack:0.1 lpenv:2 ftype:24db ]", + "[ 79/8 → 10/1 | note:D3 s:square gain:0.3 attack:0.01 decay:0.1 sustain:0.5 cutoff:2903.483208638841 lpattack:0.1 lpenv:2 ftype:24db ]", "[ (79/8 → 10/1) ⇝ 41/4 | note:A5 s:sawtooth gain:0.14656891828944 attack:0.001 decay:0.2 sustain:0 hcutoff:2278.446896257612 cutoff:4000 ]", "[ (79/8 → 10/1) ⇝ 41/4 | note:C#5 s:sawtooth gain:0.14656891828944 attack:0.001 decay:0.2 sustain:0 hcutoff:2278.446896257612 cutoff:4000 ]", "[ (79/8 → 10/1) ⇝ 83/8 | note:F#3 s:square gain:0.7 attack:0.01 decay:0.1 sustain:0 cutoff:2903.483208638841 ]", From e3b7d0f84df946d868cf0cfa8694aa2341f50beb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 02:01:46 +0200 Subject: [PATCH 061/175] drop some acid in there --- website/src/pages/learn/effects.mdx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index 4982f4cd..f77ab4c4 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -86,6 +86,25 @@ Strudel uses ADSR envelopes, which are probably the most common way to describe Each filter can receive an additional filter envelope controlling the cutoff value dynamically. It uses an ADSR envelope similar to the one used for amplitude. There is an additional parameter to control the depth of the filter modulation: `lpenv`|`hpenv`|`bpenv`. This allows you to play subtle or huge filter modulations just the same by only increasing or decreasing the depth. +](3,8,<0 1>)".sub(12)) + .s("/64") + .lpf(sine.range(500,3000).slow(16)) + .lpa(0.005) + .lpd(perlin.range(.02,.2)) + .lps(perlin.range(0,.5).slow(3)) + .lpq(sine.range(2,10).slow(32)) + .release(.5) + .lpenv(perlin.range(1,8).slow(2)) + .ftype('24db') + .room(1) + .juxBy(.5,rev) + .sometimes(add(note(12))) + .stack(s("bd*2").bank('RolandTR909')) + .gain(.5)`} +/> + There is one filter envelope for each filter type and thus one set of envelope filter parameters preceded either by `lp`, `hp` or `bp`: - `lpattack`, `lpdecay`, `lpsustain`, `lprelease`, `lpenv`: filter envelope for the lowpass filter. From 7ec5ab0c20e93d56571e2b38954438d363b6908f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 02:05:49 +0200 Subject: [PATCH 062/175] fix: tune --- website/src/repl/tunes.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/src/repl/tunes.mjs b/website/src/repl/tunes.mjs index 2ab546b7..e33482cf 100644 --- a/website/src/repl/tunes.mjs +++ b/website/src/repl/tunes.mjs @@ -580,8 +580,8 @@ chord("*2").dict('lefthand').anchor("G4").voicing() .s("gm_epiano1:1") .color('steelblue') .stack( - n("<-7 ~@2 [~@2 -7] -9 ~@2 [~@2 -9] -10!2 ~ [~@2 -10] -5 ~ [-3 -2 -10]@2>*2") - .scale('C3 major') + "<-7 ~@2 [~@2 -7] -9 ~@2 [~@2 -9] -10!2 ~ [~@2 -10] -5 ~ [-3 -2 -10]@2>*2" + .scale('C3 major').note() .s('sawtooth').color('brown') ) .attack(0.05).decay(.1).sustain(.7) From a82eeb44c030097337e0fa85531515593565b7d3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 02:08:25 +0200 Subject: [PATCH 063/175] update snapshot --- test/__snapshots__/tunes.test.mjs.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/__snapshots__/tunes.test.mjs.snap b/test/__snapshots__/tunes.test.mjs.snap index 484c1380..aca92b55 100644 --- a/test/__snapshots__/tunes.test.mjs.snap +++ b/test/__snapshots__/tunes.test.mjs.snap @@ -8484,7 +8484,7 @@ exports[`renders tunes > tune: orbit 1`] = ` exports[`renders tunes > tune: outroMusic 1`] = ` [ "[ 0/1 → 1/2 | s:hh speed:0.9036881079621337 n:3 ]", - "[ 0/1 → 3/4 | n:-7 note:C2 s:sawtooth attack:0.05 decay:0.1 sustain:0.7 cutoff:864.536878321087 gain:0.3 ]", + "[ 0/1 → 3/4 | note:C2 s:sawtooth attack:0.05 decay:0.1 sustain:0.7 cutoff:864.536878321087 gain:0.3 ]", "[ 0/1 → 3/4 | s:bd speed:0.9107561463868479 n:3 ]", "[ (0/1 → 1/1) ⇝ 3/1 | note:B3 s:gm_epiano1 n:1 attack:0.05 decay:0.1 sustain:0.7 cutoff:1111.7252990603447 gain:0.3 ]", "[ (0/1 → 1/1) ⇝ 3/1 | note:D4 s:gm_epiano1 n:1 attack:0.05 decay:0.1 sustain:0.7 cutoff:1111.7252990603447 gain:0.3 ]", From 4fecad16e4db7d72379ff647d248b5d2b5c529ab Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 16 Sep 2023 02:21:10 +0200 Subject: [PATCH 064/175] superdough 0.9.7 --- packages/superdough/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/package.json b/packages/superdough/package.json index bab58658..22b58cc5 100644 --- a/packages/superdough/package.json +++ b/packages/superdough/package.json @@ -1,6 +1,6 @@ { "name": "superdough", - "version": "0.9.6", + "version": "0.9.7", "description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.", "main": "index.mjs", "type": "module", From 2deafe214a6c060decdeee0e36830b2f3e8972b5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 07:59:55 +0200 Subject: [PATCH 065/175] update loop examples --- packages/core/controls.mjs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index b54170c1..0c166e11 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -299,13 +299,14 @@ const generic_params = [ */ ['end'], /** - * Loops the sample (from `begin` to `end`) the specified number of times. + * Loops the sample. * Note that the tempo of the loop is not synced with the cycle tempo. + * To change the loop region, use loopBegin / loopEnd. * * @name loop - * @param {number | Pattern} times How often the sample is looped + * @param {number | Pattern} on If 1, the sample is looped * @example - * s("bd").loop("<1 2 3 4>").osc() + * s("casio").loop(1) * */ ['loop'], @@ -314,13 +315,11 @@ const generic_params = [ * Note that the loop point must be inbetween `begin` and `end`, and before `loopEnd`! * * @name loopBegin - * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample + * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample * @synonyms loopb * @example - * s("numbers") - * .loop(1) - * .begin(0).end(1) - * .loopBegin("<0 .25 .5 .75>") + * s("space").loop(1) + * .loopBegin("<0 .125 .25>").scope() */ ['loopBegin', 'loopb'], /** @@ -329,14 +328,11 @@ const generic_params = [ * Note that the loop point must be inbetween `begin` and `end`, and after `loopBegin`! * * @name loopEnd - * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample + * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample * @synonyms loope * @example - * s("numbers") - * .loop(1) - * .begin(0).end(1) - * .loopBegin("<0 .25 .5 .75>") - * .loopEnd("<0.1 .35 .6 .85>") + * s("space").loop(1) + * .loopEnd("<1 .75 .5 .25>").scope() */ ['loopEnd', 'loope'], /** From b98e24fabf77b8acaa1567485224f53fff6b1c8d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 08:02:02 +0200 Subject: [PATCH 066/175] docs: fit + splice --- packages/core/pattern.mjs | 19 +++++++++++++------ website/src/pages/learn/samples.mdx | 8 ++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 7e694f49..e3efb427 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2273,14 +2273,14 @@ export const slice = register( false, // turns off auto-patternification ); -/* +/** * Works the same as slice, but changes the playback speed of each slice to match the duration of its step. * @name splice - * @memberof Pattern - * @returns Pattern * @example * await samples('github:tidalcycles/Dirt-Samples/master') - * s("breaks165").splice(8, "0 1 [2 3 0]@2 3 0@2 7").hurry(0.65) + * s("breaks165") + * .splice(8, "0 1 [2 3 0]@2 3 0@2 7") + * .hurry(0.65) */ export const splice = register( @@ -2307,9 +2307,16 @@ export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (facto return _loopAt(factor, pat, 1); }); -// this function will be redefined in repl.mjs to use the correct cps value. +// the fit function will be redefined in repl.mjs to use the correct cps value. // It is still here to work in cases where repl.mjs is not used - +/** + * Makes the sample fit its event duration. Good for rhythmical loops like drum breaks. + * Similar to loopAt. + * @name fit + * @example + * samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' }) + * s("rhodes/4").fit() + */ export const fit = register('fit', (pat) => pat.withHap((hap) => hap.withValue((v) => ({ diff --git a/website/src/pages/learn/samples.mdx b/website/src/pages/learn/samples.mdx index b1ef1cd3..10d8c730 100644 --- a/website/src/pages/learn/samples.mdx +++ b/website/src/pages/learn/samples.mdx @@ -327,6 +327,10 @@ Sampler effects are functions that can be used to change the behaviour of sample +### fit + + + ### chop @@ -335,6 +339,10 @@ Sampler effects are functions that can be used to change the behaviour of sample +### splice + + + ### speed From 4490681fa375fb692d27043e302560bcfbd985cc Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 08:03:09 +0200 Subject: [PATCH 067/175] add note about wt_ --- packages/core/controls.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 0c166e11..f988f0a7 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -313,6 +313,7 @@ const generic_params = [ /** * Begin to loop at a specific point in the sample (inbetween `begin` and `end`). * Note that the loop point must be inbetween `begin` and `end`, and before `loopEnd`! + * Note: Samples starting with wt_ will automatically loop! (wt = wavetable) * * @name loopBegin * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample From 3879b01ddd55f3674d0c068478b9829f8ce918a7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 08:04:02 +0200 Subject: [PATCH 068/175] snapshots --- test/__snapshots__/examples.test.mjs.snap | 63 ++++++++++++++++++----- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index ad0ce7b9..48835a48 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1828,6 +1828,15 @@ exports[`runs examples > example "firstOf" example index 0 1`] = ` ] `; +exports[`runs examples > example "fit" example index 0 1`] = ` +[ + "[ (0/1 → 1/1) ⇝ 4/1 | s:rhodes speed:0.25 unit:c ]", + "[ 0/1 ⇜ (1/1 → 2/1) ⇝ 4/1 | s:rhodes speed:0.25 unit:c ]", + "[ 0/1 ⇜ (2/1 → 3/1) ⇝ 4/1 | s:rhodes speed:0.25 unit:c ]", + "[ 0/1 ⇜ (3/1 → 4/1) | s:rhodes speed:0.25 unit:c ]", +] +`; + exports[`runs examples > example "floor" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:42 ]", @@ -2640,10 +2649,10 @@ exports[`runs examples > example "linger" example index 0 1`] = ` exports[`runs examples > example "loop" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | s:bd loop:1 ]", - "[ 1/1 → 2/1 | s:bd loop:2 ]", - "[ 2/1 → 3/1 | s:bd loop:3 ]", - "[ 3/1 → 4/1 | s:bd loop:4 ]", + "[ 0/1 → 1/1 | s:casio loop:1 ]", + "[ 1/1 → 2/1 | s:casio loop:1 ]", + "[ 2/1 → 3/1 | s:casio loop:1 ]", + "[ 3/1 → 4/1 | s:casio loop:1 ]", ] `; @@ -2667,19 +2676,19 @@ exports[`runs examples > example "loopAtCps" example index 0 1`] = ` exports[`runs examples > example "loopBegin" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | s:numbers loop:1 begin:0 end:1 loopBegin:0 ]", - "[ 1/1 → 2/1 | s:numbers loop:1 begin:0 end:1 loopBegin:0.25 ]", - "[ 2/1 → 3/1 | s:numbers loop:1 begin:0 end:1 loopBegin:0.5 ]", - "[ 3/1 → 4/1 | s:numbers loop:1 begin:0 end:1 loopBegin:0.75 ]", + "[ 0/1 → 1/1 | s:space loop:1 loopBegin:0 analyze:1 ]", + "[ 1/1 → 2/1 | s:space loop:1 loopBegin:0.125 analyze:1 ]", + "[ 2/1 → 3/1 | s:space loop:1 loopBegin:0.25 analyze:1 ]", + "[ 3/1 → 4/1 | s:space loop:1 loopBegin:0 analyze:1 ]", ] `; exports[`runs examples > example "loopEnd" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | s:numbers loop:1 begin:0 end:1 loopBegin:0 loopEnd:0.1 ]", - "[ 1/1 → 2/1 | s:numbers loop:1 begin:0 end:1 loopBegin:0.25 loopEnd:0.35 ]", - "[ 2/1 → 3/1 | s:numbers loop:1 begin:0 end:1 loopBegin:0.5 loopEnd:0.6 ]", - "[ 3/1 → 4/1 | s:numbers loop:1 begin:0 end:1 loopBegin:0.75 loopEnd:0.85 ]", + "[ 0/1 → 1/1 | s:space loop:1 loopEnd:1 analyze:1 ]", + "[ 1/1 → 2/1 | s:space loop:1 loopEnd:0.75 analyze:1 ]", + "[ 2/1 → 3/1 | s:space loop:1 loopEnd:0.5 analyze:1 ]", + "[ 3/1 → 4/1 | s:space loop:1 loopEnd:0.25 analyze:1 ]", ] `; @@ -4341,6 +4350,36 @@ exports[`runs examples > example "speed" example index 1 1`] = ` ] `; +exports[`runs examples > example "splice" example index 0 1`] = ` +[ + "[ 0/1 → 5/26 | speed:0.65 unit:c begin:0 end:0.125 _slices:8 s:breaks165 ]", + "[ 5/26 → 5/13 | speed:0.65 unit:c begin:0.125 end:0.25 _slices:8 s:breaks165 ]", + "[ 5/13 → 20/39 | speed:0.9750000000000001 unit:c begin:0.25 end:0.375 _slices:8 s:breaks165 ]", + "[ 20/39 → 25/39 | speed:0.9750000000000001 unit:c begin:0.375 end:0.5 _slices:8 s:breaks165 ]", + "[ 25/39 → 10/13 | speed:0.9750000000000001 unit:c begin:0 end:0.125 _slices:8 s:breaks165 ]", + "[ 10/13 → 25/26 | speed:0.65 unit:c begin:0.375 end:0.5 _slices:8 s:breaks165 ]", + "[ (25/26 → 1/1) ⇝ 35/26 | speed:0.325 unit:c begin:0 end:0.125 _slices:8 s:breaks165 ]", + "[ 25/26 ⇜ (1/1 → 35/26) | speed:0.325 unit:c begin:0 end:0.125 _slices:8 s:breaks165 ]", + "[ 35/26 → 20/13 | speed:0.65 unit:c begin:0.875 end:1 _slices:8 s:breaks165 ]", + "[ 20/13 → 45/26 | speed:0.65 unit:c begin:0 end:0.125 _slices:8 s:breaks165 ]", + "[ 45/26 → 25/13 | speed:0.65 unit:c begin:0.125 end:0.25 _slices:8 s:breaks165 ]", + "[ (25/13 → 2/1) ⇝ 80/39 | speed:0.9750000000000001 unit:c begin:0.25 end:0.375 _slices:8 s:breaks165 ]", + "[ 25/13 ⇜ (2/1 → 80/39) | speed:0.9750000000000001 unit:c begin:0.25 end:0.375 _slices:8 s:breaks165 ]", + "[ 80/39 → 85/39 | speed:0.9750000000000001 unit:c begin:0.375 end:0.5 _slices:8 s:breaks165 ]", + "[ 85/39 → 30/13 | speed:0.9750000000000001 unit:c begin:0 end:0.125 _slices:8 s:breaks165 ]", + "[ 30/13 → 5/2 | speed:0.65 unit:c begin:0.375 end:0.5 _slices:8 s:breaks165 ]", + "[ 5/2 → 75/26 | speed:0.325 unit:c begin:0 end:0.125 _slices:8 s:breaks165 ]", + "[ (75/26 → 3/1) ⇝ 40/13 | speed:0.65 unit:c begin:0.875 end:1 _slices:8 s:breaks165 ]", + "[ 75/26 ⇜ (3/1 → 40/13) | speed:0.65 unit:c begin:0.875 end:1 _slices:8 s:breaks165 ]", + "[ 40/13 → 85/26 | speed:0.65 unit:c begin:0 end:0.125 _slices:8 s:breaks165 ]", + "[ 85/26 → 45/13 | speed:0.65 unit:c begin:0.125 end:0.25 _slices:8 s:breaks165 ]", + "[ 45/13 → 140/39 | speed:0.9750000000000001 unit:c begin:0.25 end:0.375 _slices:8 s:breaks165 ]", + "[ 140/39 → 145/39 | speed:0.9750000000000001 unit:c begin:0.375 end:0.5 _slices:8 s:breaks165 ]", + "[ 145/39 → 50/13 | speed:0.9750000000000001 unit:c begin:0 end:0.125 _slices:8 s:breaks165 ]", + "[ (50/13 → 4/1) ⇝ 105/26 | speed:0.65 unit:c begin:0.375 end:0.5 _slices:8 s:breaks165 ]", +] +`; + exports[`runs examples > example "square" example index 0 1`] = ` [ "[ 0/1 → 1/2 | note:C3 ]", From 5c5df748600891860811bac1805bb0edbacf22e8 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 10:15:02 +0200 Subject: [PATCH 069/175] fix: control naming --- packages/core/controls.mjs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 69c43bfa..57ed4b91 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -649,7 +649,7 @@ const generic_params = [ * @example * sound("triangle").freq(300).vib("<1 2 4 8 16>") */ - [['vibrato'], 'vib'], + ['vib', 'vibrato'], /** * Sets the vibrato depth as a multiple of base frequency (not vibrato speed!). * @@ -658,10 +658,8 @@ const generic_params = [ * @example * sound("triangle").freq(300).vib("<8 16>").vibmod("<0.25 0.5 0.75 1 2 4>") */ - [['vibmod'], 'vibmod'], - [['hcutoff', 'hresonance'], 'hpf', 'hp'], - ['vib'], ['vibmod'], + [['hcutoff', 'hresonance'], 'hpf', 'hp'], /** * Controls the **h**igh-**p**ass **q**-value. * @@ -933,8 +931,6 @@ const generic_params = [ ['rate'], // TODO: slide param for certain synths ['slide'], - - ['slidespeed'], // TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare ['semitone'], // TODO: dedup with synth param, see https://tidalcycles.org/docs/reference/synthesizers/#superpiano From c354ee32e3d391f53c4819f8f4373e1b200c8793 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 10:15:33 +0200 Subject: [PATCH 070/175] simplify vibrato logic --- packages/superdough/synth.mjs | 39 ++++++++++++++--------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 8a240340..2e2b7cb2 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -147,12 +147,6 @@ export function waveformN(partials, type) { } export function getOscillator({ s, freq, t, vib, vibmod, partials }) { - // Additional oscillator for vibrato effect - if (vib > 0) { - var vibrato_oscillator = getAudioContext().createOscillator(); - vibrato_oscillator.frequency.value = vib; - } - // Make oscillator with partial count let o; if (!partials || s === 'sine') { @@ -161,28 +155,27 @@ export function getOscillator({ s, freq, t, vib, vibmod, partials }) { } else { o = waveformN(partials, s); } + o.frequency.value = Number(freq); + o.start(t); + // Additional oscillator for vibrato effect + let vibrato_oscillator; if (vib > 0) { - o.frequency.value = Number(freq); - var gain = getAudioContext().createGain(); + vibrato_oscillator = getAudioContext().createOscillator(); + vibrato_oscillator.frequency.value = vib; + const gain = getAudioContext().createGain(); // Vibmod is the amount of vibrato, in semitones - gain.gain.value = vibmod * freq; + gain.gain.value = vibmod * 100; vibrato_oscillator.connect(gain); gain.connect(o.detune); vibrato_oscillator.start(t); - o.start(t); - return { - node: o, - stop: (time) => { - vibrato_oscillator.stop(time); - o.stop(time); - }, - }; - } else { - // Normal operation, without vibrato - o.frequency.value = Number(freq); - o.start(t); - const stop = (time) => o.stop(time); - return { node: o, stop }; } + + return { + node: o, + stop: (time) => { + vibrato_oscillator?.stop(time); + o.stop(time); + }, + }; } From cd6d1fb2d21f05d70605d3af5db1c6bfc8ae67d5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 10:41:02 +0200 Subject: [PATCH 071/175] fix: headings --- website/src/pages/learn/synths.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index a9cf094c..9f21204f 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -48,13 +48,13 @@ You can also set `n` directly in mini notation with `sound`: Note for tidal users: `n` in tidal is synonymous to `note` for synths only. In strudel, this is not the case, where `n` will always change timbre, be it though different samples or different waveforms. -### Vibrato +## Vibrato -#### vib +### vib -#### vibmod +### vibmod From c2560e0cf8b521443a12c846e0e39c3d72fb9b5b Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 10:41:13 +0200 Subject: [PATCH 072/175] set vib default to .5 --- packages/superdough/synth.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 2e2b7cb2..5ca62105 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -41,7 +41,7 @@ export function registerSynthSounds() { fmvelocity: fmVelocity, fmwave: fmWaveform = 'sine', vib = 0, - vibmod = 1, + vibmod = .5, } = value; let { n, note, freq } = value; // with synths, n and note are the same thing From f052adb93a7ded3c3161031b6779842bb5d3988a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 10:41:22 +0200 Subject: [PATCH 073/175] simplify examples --- packages/core/controls.mjs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 57ed4b91..072dc83f 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -644,21 +644,24 @@ const generic_params = [ * Applies a vibrato to the frequency of the oscillator. * * @name vib + * @synonyms vibrato, v * @param {number | Pattern} frequency of the vibrato in hertz - * @synonyms vibrato * @example - * sound("triangle").freq(300).vib("<1 2 4 8 16>") + * note("a") + * .vib("<.5 1 2 4 8 16>") */ - ['vib', 'vibrato'], + [['vib', 'vibmod'], 'vibrato', 'v'], /** - * Sets the vibrato depth as a multiple of base frequency (not vibrato speed!). + * Sets the vibrato depth in semitones. * * @name vibmod - * @param {number | Pattern} depth of vibrato (multiple of base frequency) + * @synonyms vmod + * @param {number | Pattern} depth of vibrato (in semitones) * @example - * sound("triangle").freq(300).vib("<8 16>").vibmod("<0.25 0.5 0.75 1 2 4>") + * note("a").vib(4) + * .vibmod("<.25 .5 1 2 12>") */ - ['vibmod'], + [['vibmod', 'vib'], 'vmod'], [['hcutoff', 'hresonance'], 'hpf', 'hp'], /** * Controls the **h**igh-**p**ass **q**-value. From a97384cec1ec3a0a92637a509ea89ac9edf07dfc Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 10:42:21 +0200 Subject: [PATCH 074/175] format --- packages/superdough/synth.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 5ca62105..633d0113 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -41,7 +41,7 @@ export function registerSynthSounds() { fmvelocity: fmVelocity, fmwave: fmWaveform = 'sine', vib = 0, - vibmod = .5, + vibmod = 0.5, } = value; let { n, note, freq } = value; // with synths, n and note are the same thing From c6a74c040e258db1dd2684e48384422285fefd57 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 10:42:51 +0200 Subject: [PATCH 075/175] snapshot --- test/__snapshots__/examples.test.mjs.snap | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index d146a065..858e30e7 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -4760,19 +4760,19 @@ exports[`runs examples > example "velocity" example index 0 1`] = ` exports[`runs examples > example "vib" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | s:triangle freq:300 vib:1 ]", - "[ 1/1 → 2/1 | s:triangle freq:300 vib:2 ]", - "[ 2/1 → 3/1 | s:triangle freq:300 vib:4 ]", - "[ 3/1 → 4/1 | s:triangle freq:300 vib:8 ]", + "[ 0/1 → 1/1 | note:a vib:0.5 ]", + "[ 1/1 → 2/1 | note:a vib:1 ]", + "[ 2/1 → 3/1 | note:a vib:2 ]", + "[ 3/1 → 4/1 | note:a vib:4 ]", ] `; exports[`runs examples > example "vibmod" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | s:triangle freq:300 vib:8 vibmod:0.25 ]", - "[ 1/1 → 2/1 | s:triangle freq:300 vib:16 vibmod:0.5 ]", - "[ 2/1 → 3/1 | s:triangle freq:300 vib:8 vibmod:0.75 ]", - "[ 3/1 → 4/1 | s:triangle freq:300 vib:16 vibmod:1 ]", + "[ 0/1 → 1/1 | note:a vib:4 vibmod:0.25 ]", + "[ 1/1 → 2/1 | note:a vib:4 vibmod:0.5 ]", + "[ 2/1 → 3/1 | note:a vib:4 vibmod:1 ]", + "[ 3/1 → 4/1 | note:a vib:4 vibmod:2 ]", ] `; From 32fee6313b4f1ac41eb4b00c58f3d998e1666eb8 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 10:44:15 +0200 Subject: [PATCH 076/175] move stuff back --- packages/core/controls.mjs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 072dc83f..edbb77d4 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1140,13 +1140,10 @@ const generic_params = [ // ZZFX ['zrand'], ['curve'], - ['pitchJump'], - ['pitchJumpTime'], ['slide'], // superdirt duplicate ['deltaSlide'], - /** - * - */ + ['pitchJump'], + ['pitchJumpTime'], ['lfo', 'repeatTime'], ['noise'], ['zmod'], From 0e7c9a4001c3acf50c5f56f0c5555d95668fbbce Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 11:01:12 +0200 Subject: [PATCH 077/175] add vib examples for : notation --- packages/core/controls.mjs | 10 +++++++++- test/__snapshots__/examples.test.mjs.snap | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index edbb77d4..6cac6e54 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -649,10 +649,14 @@ const generic_params = [ * @example * note("a") * .vib("<.5 1 2 4 8 16>") + * @example + * // change the modulation depth with ":" + * note("a") + * .vib("<.5 1 2 4 8 16>:12") */ [['vib', 'vibmod'], 'vibrato', 'v'], /** - * Sets the vibrato depth in semitones. + * Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set * * @name vibmod * @synonyms vmod @@ -660,6 +664,10 @@ const generic_params = [ * @example * note("a").vib(4) * .vibmod("<.25 .5 1 2 12>") + * @example + * // change the vibrato frequency with ":" + * note("a") + * .vibmod("<.25 .5 1 2 12>:8") */ [['vibmod', 'vib'], 'vmod'], [['hcutoff', 'hresonance'], 'hpf', 'hp'], diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 858e30e7..e026f9c4 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -4767,6 +4767,15 @@ exports[`runs examples > example "vib" example index 0 1`] = ` ] `; +exports[`runs examples > example "vib" example index 1 1`] = ` +[ + "[ 0/1 → 1/1 | note:a vib:0.5 vibmod:12 ]", + "[ 1/1 → 2/1 | note:a vib:1 vibmod:12 ]", + "[ 2/1 → 3/1 | note:a vib:2 vibmod:12 ]", + "[ 3/1 → 4/1 | note:a vib:4 vibmod:12 ]", +] +`; + exports[`runs examples > example "vibmod" example index 0 1`] = ` [ "[ 0/1 → 1/1 | note:a vib:4 vibmod:0.25 ]", @@ -4776,6 +4785,15 @@ exports[`runs examples > example "vibmod" example index 0 1`] = ` ] `; +exports[`runs examples > example "vibmod" example index 1 1`] = ` +[ + "[ 0/1 → 1/1 | note:a vibmod:0.25 vib:8 ]", + "[ 1/1 → 2/1 | note:a vibmod:0.5 vib:8 ]", + "[ 2/1 → 3/1 | note:a vibmod:1 vib:8 ]", + "[ 3/1 → 4/1 | note:a vibmod:2 vib:8 ]", +] +`; + exports[`runs examples > example "voicing" example index 0 1`] = ` [ "[ 0/1 → 1/1 | note:E4 ]", From 578bede46b4310d5b5e49b7a88b895b38062c102 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 11:17:37 +0200 Subject: [PATCH 078/175] fix: tune n -> note --- website/src/repl/tunes.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/repl/tunes.mjs b/website/src/repl/tunes.mjs index e33482cf..fdfc47d8 100644 --- a/website/src/repl/tunes.mjs +++ b/website/src/repl/tunes.mjs @@ -432,7 +432,7 @@ export const waa2 = `// "Waa2" // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @by Felix Roos -n( +note( "a4 [a3 c3] a3 c3" .sub("<7 12 5 12>".slow(2)) .off(1/4,x=>x.add(7)) From 4fb364195cf43021e26810ab6061cdd1b358181b Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 11:18:20 +0200 Subject: [PATCH 079/175] snapshot --- test/__snapshots__/tunes.test.mjs.snap | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/__snapshots__/tunes.test.mjs.snap b/test/__snapshots__/tunes.test.mjs.snap index aca92b55..4485f4ca 100644 --- a/test/__snapshots__/tunes.test.mjs.snap +++ b/test/__snapshots__/tunes.test.mjs.snap @@ -10180,22 +10180,22 @@ exports[`renders tunes > tune: undergroundPlumber 1`] = ` exports[`renders tunes > tune: waa2 1`] = ` [ - "[ -1/4 ⇜ (0/1 → 1/4) | n:48 clip:1.1738393178344886 s:sawtooth cutoff:3997.892048359052 gain:0.5 room:0.5 ]", - "[ -1/4 ⇜ (0/1 → 1/4) | n:64 clip:1.1738393178344886 s:sawtooth cutoff:3997.892048359052 gain:0.5 room:0.5 ]", - "[ (0/1 → 1/4) ⇝ 1/2 | n:62 clip:1.197659880151613 s:sawtooth cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", - "[ (0/1 → 1/4) ⇝ 1/2 | n:43 clip:1.197659880151613 s:sawtooth cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", - "[ 0/1 ⇜ (1/4 → 1/2) | n:62 clip:1.197659880151613 s:square cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", - "[ 0/1 ⇜ (1/4 → 1/2) | n:43 clip:1.197659880151613 s:square cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", - "[ (1/4 → 1/2) ⇝ 3/4 | n:74 clip:1.2451698046878117 s:square cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", - "[ (1/4 → 1/2) ⇝ 3/4 | n:55 clip:1.2451698046878117 s:square cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", - "[ 1/4 ⇜ (1/2 → 3/4) | n:74 clip:1.2451698046878117 s:sawtooth cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", - "[ 1/4 ⇜ (1/2 → 3/4) | n:55 clip:1.2451698046878117 s:sawtooth cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", - "[ 1/2 → 3/4 | n:50 clip:1.2688217886051745 s:sawtooth cutoff:3947.554693090452 gain:0.5 room:0.5 ]", - "[ (1/2 → 3/4) ⇝ 1/1 | n:69 clip:1.292380289809026 s:sawtooth cutoff:3924.645587531366 gain:0.5 room:0.5 ]", - "[ 1/2 ⇜ (3/4 → 1/1) | n:69 clip:1.292380289809026 s:square cutoff:3924.645587531366 gain:0.5 room:0.5 ]", - "[ 3/4 → 1/1 | n:41 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 ]", - "[ 3/4 → 1/1 | n:62 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 ]", - "[ (3/4 → 1/1) ⇝ 5/4 | n:81 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 ]", + "[ -1/4 ⇜ (0/1 → 1/4) | note:48 clip:1.1738393178344886 s:sawtooth cutoff:3997.892048359052 gain:0.5 room:0.5 ]", + "[ -1/4 ⇜ (0/1 → 1/4) | note:64 clip:1.1738393178344886 s:sawtooth cutoff:3997.892048359052 gain:0.5 room:0.5 ]", + "[ (0/1 → 1/4) ⇝ 1/2 | note:62 clip:1.197659880151613 s:sawtooth cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", + "[ (0/1 → 1/4) ⇝ 1/2 | note:43 clip:1.197659880151613 s:sawtooth cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", + "[ 0/1 ⇜ (1/4 → 1/2) | note:62 clip:1.197659880151613 s:square cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", + "[ 0/1 ⇜ (1/4 → 1/2) | note:43 clip:1.197659880151613 s:square cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", + "[ (1/4 → 1/2) ⇝ 3/4 | note:74 clip:1.2451698046878117 s:square cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", + "[ (1/4 → 1/2) ⇝ 3/4 | note:55 clip:1.2451698046878117 s:square cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", + "[ 1/4 ⇜ (1/2 → 3/4) | note:74 clip:1.2451698046878117 s:sawtooth cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", + "[ 1/4 ⇜ (1/2 → 3/4) | note:55 clip:1.2451698046878117 s:sawtooth cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", + "[ 1/2 → 3/4 | note:50 clip:1.2688217886051745 s:sawtooth cutoff:3947.554693090452 gain:0.5 room:0.5 ]", + "[ (1/2 → 3/4) ⇝ 1/1 | note:69 clip:1.292380289809026 s:sawtooth cutoff:3924.645587531366 gain:0.5 room:0.5 ]", + "[ 1/2 ⇜ (3/4 → 1/1) | note:69 clip:1.292380289809026 s:square cutoff:3924.645587531366 gain:0.5 room:0.5 ]", + "[ 3/4 → 1/1 | note:41 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 ]", + "[ 3/4 → 1/1 | note:62 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 ]", + "[ (3/4 → 1/1) ⇝ 5/4 | note:81 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 ]", ] `; From b7ef2d97e23651a7cc9fd99993fc8db1e0bba05c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 11:50:18 +0200 Subject: [PATCH 080/175] make desktopbridge private for now --- packages/desktopbridge/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/desktopbridge/package.json b/packages/desktopbridge/package.json index c2acba9e..d750a82b 100644 --- a/packages/desktopbridge/package.json +++ b/packages/desktopbridge/package.json @@ -1,6 +1,7 @@ { "name": "@strudel/desktopbridge", "version": "0.1.0", + "private": true, "description": "tools/shims for communicating between the JS and Tauri (Rust) sides of the Studel desktop app", "main": "index.mjs", "type": "module", From 57265b9e33cd832b39309ec82eddb29dbd866253 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 12:34:01 +0200 Subject: [PATCH 081/175] add filter envelopes here and there + comment out outroMusic (lame) --- website/src/repl/tunes.mjs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/website/src/repl/tunes.mjs b/website/src/repl/tunes.mjs index fdfc47d8..5f68ee93 100644 --- a/website/src/repl/tunes.mjs +++ b/website/src/repl/tunes.mjs @@ -444,7 +444,7 @@ note( .cutoff(cosine.range(500,4000).slow(16)) .gain(.5) .room(.5) - `; + .lpa(.125).lpenv(-2).v("8:.125").fanchor(.25)`; export const hyperpop = `// "Hyperpop" // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ @@ -541,6 +541,7 @@ stack( .s('sawtooth') // waveform .gain(.4) // turn down .cutoff(sine.slow(7).range(300,5000)) // automate cutoff + .lpa(.1).lpenv(-2) //.hush() ,chord(">") .dict('lefthand').voicing() // chords @@ -563,6 +564,7 @@ stack( ) .slow(3/2)`; +/* export const outroMusic = `// "Outro music" // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @by Felix Roos @@ -593,7 +595,8 @@ chord("*2").dict('lefthand').anchor("G4").voicing() .n(3).color('gray') ).slow(3/2) //.pianoroll({autorange:1,vertical:1,fold:0}) - `; + `; +*/ export const bassFuge = `// "Bass fuge" // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ @@ -776,7 +779,8 @@ stack( .gain("0.4,0.4(5,8,-1)"), note("<0 2 5 3>".scale('G1 minor')).struct("x(5,8,-1)") - .s('sawtooth').decay(.1).sustain(0), + .s('sawtooth').decay(.1).sustain(0) + .lpa(.1).lpenv(-4).lpf(800).lpq(8), note(",Bb3,D3").struct("~ x*2").s('square').clip(1) .cutoff(sine.range(500,4000).slow(16)).resonance(10) @@ -807,8 +811,10 @@ stack( sine.add(saw.slow(4)).range(0,7).segment(8) .superimpose(x=>x.add(.1)) .scale('G0 minor').note() - .s("sawtooth").decay(.1).sustain(0).lpa(.1).lpenv(4) - .gain(.4).cutoff(perlin.range(300,3000).slow(8)).resonance(10) + .s("sawtooth") + .gain(.4).decay(.1).sustain(0) + .lpa(.1).lpenv(-4).lpq(10) + .cutoff(perlin.range(300,3000).slow(8)) .degradeBy("0 0.1 .5 .1") .rarely(add(note("12"))) , @@ -831,8 +837,8 @@ note("c3 eb3 g3 bb3").palindrome() .s('sawtooth') .jux(x=>x.rev().color('green').s('sawtooth')) .off(1/4, x=>x.add(note("<7 12>/2")).slow(2).late(.005).s('triangle')) -//.delay(.5) -.fast(1).cutoff(sine.range(200,2000).slow(8)) +.lpf(sine.range(200,2000).slow(8)) +.lpa(.2).lpenv(-2) .decay(.05).sustain(0) .room(.6) .delay(.5).delaytime(.1).delayfeedback(.4) @@ -911,7 +917,13 @@ n("[0,3] 2 [1,3] 2".fast(3).lastOf(4, fast(2))).clip(2) .delay(.2) .room(.5).pan(sine.range(.3,.6)) .s('piano') - .stack("<!2 F2 [F2 E2]>".add.out("0 -5".fast(2)).add("0,.12").note().s('sawtooth').clip(1).cutoff(300)) + .stack( + "<!2 F2 F2>" + .add.out("0 -5".fast(2)) + .add("0,.12").note() + .s('sawtooth').cutoff(180) + .lpa(.1).lpenv(2) + ) .slow(4) .stack(s("bd*4, [~ [hh hh? hh?]]*2,~ [sd ~ [sd:2? bd?]]").bank('RolandTR909').gain(.5).slow(2)) `; From de9a52366f6658a4f241d5fe054a854b159e7642 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 12:35:03 +0200 Subject: [PATCH 082/175] Publish - @strudel/codemirror@0.9.0 - @strudel.cycles/core@0.9.0 - @strudel.cycles/csound@0.9.0 - @strudel.cycles/midi@0.9.0 - @strudel.cycles/mini@0.9.0 - @strudel.cycles/osc@0.9.0 - @strudel.cycles/react@0.9.0 - @strudel.cycles/serial@0.9.0 - @strudel.cycles/soundfonts@0.9.0 - superdough@0.9.8 - @strudel.cycles/tonal@0.9.0 - @strudel.cycles/transpiler@0.9.0 - @strudel/web@0.9.0 - @strudel.cycles/webaudio@0.9.0 - @strudel.cycles/xen@0.9.0 --- packages/codemirror/package.json | 2 +- packages/core/package.json | 2 +- packages/csound/package.json | 2 +- packages/midi/package.json | 2 +- packages/mini/package.json | 2 +- packages/osc/package.json | 2 +- packages/react/package.json | 2 +- packages/serial/package.json | 2 +- packages/soundfonts/package.json | 2 +- packages/superdough/package.json | 2 +- packages/tonal/package.json | 2 +- packages/transpiler/package.json | 2 +- packages/web/package.json | 2 +- packages/webaudio/package.json | 2 +- packages/xen/package.json | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/codemirror/package.json b/packages/codemirror/package.json index 0e32fef6..4e443648 100644 --- a/packages/codemirror/package.json +++ b/packages/codemirror/package.json @@ -1,6 +1,6 @@ { "name": "@strudel/codemirror", - "version": "0.8.4", + "version": "0.9.0", "description": "Codemirror Extensions for Strudel", "main": "index.mjs", "publishConfig": { diff --git a/packages/core/package.json b/packages/core/package.json index 16581904..8fd57242 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/core", - "version": "0.8.2", + "version": "0.9.0", "description": "Port of Tidal Cycles to JavaScript", "main": "index.mjs", "type": "module", diff --git a/packages/csound/package.json b/packages/csound/package.json index e15cfeaf..a0d21b9f 100644 --- a/packages/csound/package.json +++ b/packages/csound/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/csound", - "version": "0.8.0", + "version": "0.9.0", "description": "csound bindings for strudel", "main": "index.mjs", "publishConfig": { diff --git a/packages/midi/package.json b/packages/midi/package.json index 42679804..e13887e2 100644 --- a/packages/midi/package.json +++ b/packages/midi/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/midi", - "version": "0.8.0", + "version": "0.9.0", "description": "Midi API for strudel", "main": "index.mjs", "publishConfig": { diff --git a/packages/mini/package.json b/packages/mini/package.json index 16bd724c..29ba3e83 100644 --- a/packages/mini/package.json +++ b/packages/mini/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/mini", - "version": "0.8.2", + "version": "0.9.0", "description": "Mini notation for strudel", "main": "index.mjs", "type": "module", diff --git a/packages/osc/package.json b/packages/osc/package.json index af2c9954..dd61c3a7 100644 --- a/packages/osc/package.json +++ b/packages/osc/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/osc", - "version": "0.8.0", + "version": "0.9.0", "description": "OSC messaging for strudel", "main": "osc.mjs", "publishConfig": { diff --git a/packages/react/package.json b/packages/react/package.json index 51916049..deef95d8 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/react", - "version": "0.8.0", + "version": "0.9.0", "description": "React components for strudel", "main": "src/index.js", "publishConfig": { diff --git a/packages/serial/package.json b/packages/serial/package.json index 09a3267a..c25c806a 100644 --- a/packages/serial/package.json +++ b/packages/serial/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/serial", - "version": "0.8.0", + "version": "0.9.0", "description": "Webserial API for strudel", "main": "serial.mjs", "publishConfig": { diff --git a/packages/soundfonts/package.json b/packages/soundfonts/package.json index 1f7b70e6..c4bf1032 100644 --- a/packages/soundfonts/package.json +++ b/packages/soundfonts/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/soundfonts", - "version": "0.8.2", + "version": "0.9.0", "description": "Soundsfont support for strudel", "main": "index.mjs", "publishConfig": { diff --git a/packages/superdough/package.json b/packages/superdough/package.json index 22b58cc5..69ba6f8c 100644 --- a/packages/superdough/package.json +++ b/packages/superdough/package.json @@ -1,6 +1,6 @@ { "name": "superdough", - "version": "0.9.7", + "version": "0.9.8", "description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.", "main": "index.mjs", "type": "module", diff --git a/packages/tonal/package.json b/packages/tonal/package.json index d98d565f..bef3c2f0 100644 --- a/packages/tonal/package.json +++ b/packages/tonal/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/tonal", - "version": "0.8.2", + "version": "0.9.0", "description": "Tonal functions for strudel", "main": "index.mjs", "publishConfig": { diff --git a/packages/transpiler/package.json b/packages/transpiler/package.json index 95fbfee7..b546bce2 100644 --- a/packages/transpiler/package.json +++ b/packages/transpiler/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/transpiler", - "version": "0.8.2", + "version": "0.9.0", "description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.", "main": "index.mjs", "publishConfig": { diff --git a/packages/web/package.json b/packages/web/package.json index 9e866bf1..7e182f40 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,6 +1,6 @@ { "name": "@strudel/web", - "version": "0.8.3", + "version": "0.9.0", "description": "Easy to setup, opiniated bundle of Strudel for the browser.", "main": "web.mjs", "publishConfig": { diff --git a/packages/webaudio/package.json b/packages/webaudio/package.json index edd53cbd..cebb30f3 100644 --- a/packages/webaudio/package.json +++ b/packages/webaudio/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/webaudio", - "version": "0.8.2", + "version": "0.9.0", "description": "Web Audio helpers for Strudel", "main": "index.mjs", "type": "module", diff --git a/packages/xen/package.json b/packages/xen/package.json index 42ce4805..ef2e04d2 100644 --- a/packages/xen/package.json +++ b/packages/xen/package.json @@ -1,6 +1,6 @@ { "name": "@strudel.cycles/xen", - "version": "0.8.0", + "version": "0.9.0", "description": "Xenharmonic API for strudel", "main": "index.mjs", "publishConfig": { From 9c73ef770fd1395a306b35d14dc8c0be81d30dc4 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 17 Sep 2023 13:37:16 +0200 Subject: [PATCH 083/175] snapshot --- test/__snapshots__/tunes.test.mjs.snap | 109 +++++++++++-------------- 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/test/__snapshots__/tunes.test.mjs.snap b/test/__snapshots__/tunes.test.mjs.snap index 4485f4ca..cd89ee3f 100644 --- a/test/__snapshots__/tunes.test.mjs.snap +++ b/test/__snapshots__/tunes.test.mjs.snap @@ -3,23 +3,23 @@ exports[`renders tunes > tune: amensister 1`] = ` [ "[ 0/1 → 1/16 | s:breath room:1 shape:0.6 begin:0.9375 end:1 ]", - "[ 0/1 → 1/8 | note:Eb1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.0066107586751 resonance:10 ]", - "[ 0/1 → 1/8 | note:F1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.0066107586751 resonance:10 ]", + "[ 0/1 → 1/8 | note:Eb1 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:300.0066107586751 ]", + "[ 0/1 → 1/8 | note:F1 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:300.0066107586751 ]", "[ 0/1 → 1/4 | n:0 s:amencutup room:0.5 ]", "[ 1/16 → 1/8 | s:breath room:1 shape:0.6 begin:0.875 end:0.9375 ]", "[ 1/8 → 3/16 | s:breath room:1 shape:0.6 begin:0.8125 end:0.875 ]", - "[ 1/8 → 1/4 | note:45 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.174310575404 resonance:10 ]", - "[ 1/8 → 1/4 | note:45 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.174310575404 resonance:10 ]", + "[ 1/8 → 1/4 | note:45 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:300.174310575404 ]", + "[ 1/8 → 1/4 | note:45 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:300.174310575404 ]", "[ 3/16 → 1/4 | s:breath room:1 shape:0.6 begin:0.75 end:0.8125 ]", "[ 1/4 → 5/16 | s:breath room:1 shape:0.6 begin:0.6875 end:0.75 ]", "[ 1/4 → 3/8 | n:1 speed:2 delay:0.5 s:amencutup room:0.5 ]", - "[ 1/4 → 3/8 | note:A1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.7878869297153 resonance:10 ]", - "[ 1/4 → 3/8 | note:A1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:300.7878869297153 resonance:10 ]", + "[ 1/4 → 3/8 | note:A1 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:300.7878869297153 ]", + "[ 1/4 → 3/8 | note:A1 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:300.7878869297153 ]", "[ 5/16 → 3/8 | s:breath room:1 shape:0.6 begin:0.625 end:0.6875 ]", "[ 3/8 → 7/16 | s:breath room:1 shape:0.6 begin:0.5625 end:0.625 ]", "[ 3/8 → 1/2 | n:1 s:amencutup room:0.5 ]", - "[ 3/8 → 1/2 | note:F1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:302.11020572391345 resonance:10 ]", - "[ 3/8 → 1/2 | note:F1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:302.11020572391345 resonance:10 ]", + "[ 3/8 → 1/2 | note:F1 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:302.11020572391345 ]", + "[ 3/8 → 1/2 | note:F1 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:302.11020572391345 ]", "[ 7/16 → 1/2 | s:breath room:1 shape:0.6 begin:0.5 end:0.5625 ]", "[ 1/2 → 9/16 | s:breath room:1 shape:0.6 begin:0.4375 end:0.5 ]", "[ 1/2 → 3/4 | n:2 s:amencutup room:0.5 ]", @@ -28,13 +28,13 @@ exports[`renders tunes > tune: amensister 1`] = ` "[ 11/16 → 3/4 | s:breath room:1 shape:0.6 begin:0.25 end:0.3125 ]", "[ 3/4 → 13/16 | s:breath room:1 shape:0.6 begin:0.1875 end:0.25 ]", "[ 3/4 → 7/8 | n:3 s:amencutup room:0.5 ]", - "[ 3/4 → 7/8 | note:Bb0 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:312.54769231985796 resonance:10 ]", - "[ 3/4 → 7/8 | note:Bb0 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:312.54769231985796 resonance:10 ]", + "[ 3/4 → 7/8 | note:Bb0 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:312.54769231985796 ]", + "[ 3/4 → 7/8 | note:Bb0 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:312.54769231985796 ]", "[ 13/16 → 7/8 | s:breath room:1 shape:0.6 begin:0.125 end:0.1875 ]", "[ 7/8 → 15/16 | s:breath room:1 shape:0.6 begin:0.0625 end:0.125 ]", "[ 7/8 → 1/1 | n:3 s:amencutup room:0.5 ]", - "[ 7/8 → 1/1 | note:D1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:318.7927796831686 resonance:10 ]", - "[ 7/8 → 1/1 | note:D1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:4 gain:0.4 cutoff:318.7927796831686 resonance:10 ]", + "[ 7/8 → 1/1 | note:D1 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:318.7927796831686 ]", + "[ 7/8 → 1/1 | note:D1 s:sawtooth gain:0.4 decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 resonance:10 cutoff:318.7927796831686 ]", "[ 15/16 → 1/1 | s:breath room:1 shape:0.6 begin:0 end:0.0625 ]", ] `; @@ -44,8 +44,8 @@ exports[`renders tunes > tune: arpoon 1`] = ` "[ (0/1 → 1/4) ⇝ 1/3 | note:55.000070545713186 clip:2 cutoff:501.2345499807435 resonance:12 gain:0.5 decay:0.16 sustain:0.5 delay:0.2 room:0.5 pan:0.48882285676537807 s:piano ]", "[ (0/1 → 1/4) ⇝ 1/3 | note:64.00007054571319 clip:2 cutoff:501.2345499807435 resonance:12 gain:0.5 decay:0.16 sustain:0.5 delay:0.2 room:0.5 pan:0.48882285676537807 s:piano ]", "[ 0/1 → 1/2 | s:bd bank:RolandTR909 gain:0.5 ]", - "[ 0/1 → 1/1 | note:33 s:sawtooth clip:1 cutoff:300 ]", - "[ 0/1 → 1/1 | note:33.12 s:sawtooth clip:1 cutoff:300 ]", + "[ 0/1 → 1/1 | note:33 s:sawtooth cutoff:180 lpattack:0.1 lpenv:2 ]", + "[ 0/1 → 1/1 | note:33.12 s:sawtooth cutoff:180 lpattack:0.1 lpenv:2 ]", "[ 0/1 ⇜ (1/4 → 1/3) | note:55.000070545713186 clip:2 cutoff:501.2345499807435 resonance:12 gain:0.8 decay:0.16 sustain:0.5 delay:0.2 room:0.5 pan:0.48882285676537807 s:piano ]", "[ 0/1 ⇜ (1/4 → 1/3) | note:64.00007054571319 clip:2 cutoff:501.2345499807435 resonance:12 gain:0.8 decay:0.16 sustain:0.5 delay:0.2 room:0.5 pan:0.48882285676537807 s:piano ]", "[ (1/3 → 1/2) ⇝ 2/3 | note:60.00166796373806 clip:2 cutoff:529.1893654159594 resonance:12 gain:0.8 decay:0.16 sustain:0.5 delay:0.2 room:0.5 pan:0.5560660171779821 s:piano ]", @@ -7315,20 +7315,20 @@ exports[`renders tunes > tune: flatrave 1`] = ` "[ 0/1 ⇜ (1/8 → 1/4) | s:hh n:1 end:0.02000058072071123 bank:RolandTR909 room:0.5 gain:0.4 ]", "[ 1/8 → 1/4 | s:hh n:1 speed:0.5 delay:0.5 end:0.020001936784171157 bank:RolandTR909 room:0.5 gain:0.4 ]", "[ 1/8 → 1/4 | s:hh n:1 speed:0.5 delay:0.5 end:0.020001936784171157 bank:RolandTR909 room:0.5 gain:0.4 ]", - "[ 1/8 → 1/4 | note:G1 s:sawtooth decay:0.1 sustain:0 ]", + "[ 1/8 → 1/4 | note:G1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 cutoff:800 resonance:8 ]", "[ 1/4 → 3/8 | s:hh n:1 end:0.02000875429921906 bank:RolandTR909 room:0.5 gain:0.4 ]", "[ 1/4 → 3/8 | s:hh n:1 end:0.02000875429921906 bank:RolandTR909 room:0.5 gain:0.4 ]", - "[ 1/4 → 3/8 | note:G1 s:sawtooth decay:0.1 sustain:0 ]", + "[ 1/4 → 3/8 | note:G1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 cutoff:800 resonance:8 ]", "[ 3/8 → 1/2 | s:hh n:1 end:0.020023446730265706 bank:RolandTR909 room:0.5 gain:0.4 ]", - "[ 1/2 → 5/8 | note:G1 s:sawtooth decay:0.1 sustain:0 ]", + "[ 1/2 → 5/8 | note:G1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 cutoff:800 resonance:8 ]", "[ 1/2 → 1/1 | s:bd bank:RolandTR909 ]", "[ 1/2 → 1/1 | s:cp bank:RolandTR909 ]", "[ 1/2 → 1/1 | s:sd bank:RolandTR909 ]", "[ 5/8 → 3/4 | s:hh n:1 end:0.020086608138500644 bank:RolandTR909 room:0.5 gain:0.4 ]", "[ 5/8 → 3/4 | s:hh n:1 end:0.020086608138500644 bank:RolandTR909 room:0.5 gain:0.4 ]", - "[ 5/8 → 3/4 | note:G1 s:sawtooth decay:0.1 sustain:0 ]", + "[ 5/8 → 3/4 | note:G1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 cutoff:800 resonance:8 ]", "[ 3/4 → 7/8 | s:hh n:1 end:0.02013941880355398 bank:RolandTR909 room:0.5 gain:0.4 ]", - "[ 7/8 → 1/1 | note:G1 s:sawtooth decay:0.1 sustain:0 ]", + "[ 7/8 → 1/1 | note:G1 s:sawtooth decay:0.1 sustain:0 lpattack:0.1 lpenv:-4 cutoff:800 resonance:8 ]", ] `; @@ -8372,16 +8372,16 @@ exports[`renders tunes > tune: hyperpop 1`] = ` exports[`renders tunes > tune: juxUndTollerei 1`] = ` [ - "[ 0/1 → 1/4 | note:bb3 s:sawtooth pan:0 cutoff:1188.2154262966046 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", - "[ 0/1 → 1/4 | note:c3 s:sawtooth pan:1 cutoff:1188.2154262966046 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", - "[ 1/4 → 1/2 | note:g3 s:sawtooth pan:0 cutoff:1361.2562095290161 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", - "[ 1/4 → 1/2 | note:eb3 s:sawtooth pan:1 cutoff:1361.2562095290161 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", - "[ 1/2 → 3/4 | note:eb3 s:sawtooth pan:0 cutoff:1524.257063143398 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", - "[ 1/2 → 3/4 | note:g3 s:sawtooth pan:1 cutoff:1524.257063143398 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", - "[ (101/200 → 1/1) ⇝ 201/200 | note:65 s:triangle pan:0 cutoff:1601.4815730092653 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", - "[ (101/200 → 1/1) ⇝ 201/200 | note:55 s:triangle pan:1 cutoff:1601.4815730092653 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", - "[ 3/4 → 1/1 | note:c3 s:sawtooth pan:0 cutoff:1670.953955747281 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", - "[ 3/4 → 1/1 | note:bb3 s:sawtooth pan:1 cutoff:1670.953955747281 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", + "[ 0/1 → 1/4 | note:bb3 s:sawtooth pan:0 cutoff:1188.2154262966046 lpattack:0.2 lpenv:-2 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", + "[ 0/1 → 1/4 | note:c3 s:sawtooth pan:1 cutoff:1188.2154262966046 lpattack:0.2 lpenv:-2 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", + "[ 1/4 → 1/2 | note:g3 s:sawtooth pan:0 cutoff:1361.2562095290161 lpattack:0.2 lpenv:-2 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", + "[ 1/4 → 1/2 | note:eb3 s:sawtooth pan:1 cutoff:1361.2562095290161 lpattack:0.2 lpenv:-2 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", + "[ 1/2 → 3/4 | note:eb3 s:sawtooth pan:0 cutoff:1524.257063143398 lpattack:0.2 lpenv:-2 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", + "[ 1/2 → 3/4 | note:g3 s:sawtooth pan:1 cutoff:1524.257063143398 lpattack:0.2 lpenv:-2 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", + "[ (101/200 → 1/1) ⇝ 201/200 | note:65 s:triangle pan:0 cutoff:1601.4815730092653 lpattack:0.2 lpenv:-2 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", + "[ (101/200 → 1/1) ⇝ 201/200 | note:55 s:triangle pan:1 cutoff:1601.4815730092653 lpattack:0.2 lpenv:-2 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", + "[ 3/4 → 1/1 | note:c3 s:sawtooth pan:0 cutoff:1670.953955747281 lpattack:0.2 lpenv:-2 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", + "[ 3/4 → 1/1 | note:bb3 s:sawtooth pan:1 cutoff:1670.953955747281 lpattack:0.2 lpenv:-2 decay:0.05 sustain:0 room:0.6 delay:0.5 delaytime:0.1 delayfeedback:0.4 ]", ] `; @@ -8422,8 +8422,8 @@ exports[`renders tunes > tune: meltingsubmarine 1`] = ` "[ 0/1 → 3/16 | note:93.00057728554401 decay:0.1 sustain:0 s:triangle gain:0.075 ]", "[ 0/1 → 3/16 | note:93.04057728554402 decay:0.1 sustain:0 s:triangle gain:0.075 ]", "[ (0/1 → 1/1) ⇝ 3/2 | s:bd n:5 speed:0.7519542165100574 ]", - "[ (0/1 → 1/1) ⇝ 3/2 | note:33.129885541275144 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]", - "[ (0/1 → 1/1) ⇝ 3/2 | note:33.17988554127514 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]", + "[ (0/1 → 1/1) ⇝ 3/2 | note:33.129885541275144 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 lpattack:0.1 lpenv:-2 ]", + "[ (0/1 → 1/1) ⇝ 3/2 | note:33.17988554127514 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 lpattack:0.1 lpenv:-2 ]", "[ (0/1 → 1/1) ⇝ 3/2 | note:60.129885541275144 s:sawtooth gain:0.16 cutoff:500 attack:1 ]", "[ (0/1 → 1/1) ⇝ 3/2 | note:60.16988554127514 s:sawtooth gain:0.16 cutoff:500 attack:1 ]", "[ (0/1 → 1/1) ⇝ 3/2 | note:64.12988554127514 s:sawtooth gain:0.16 cutoff:500 attack:1 ]", @@ -8481,21 +8481,6 @@ exports[`renders tunes > tune: orbit 1`] = ` ] `; -exports[`renders tunes > tune: outroMusic 1`] = ` -[ - "[ 0/1 → 1/2 | s:hh speed:0.9036881079621337 n:3 ]", - "[ 0/1 → 3/4 | note:C2 s:sawtooth attack:0.05 decay:0.1 sustain:0.7 cutoff:864.536878321087 gain:0.3 ]", - "[ 0/1 → 3/4 | s:bd speed:0.9107561463868479 n:3 ]", - "[ (0/1 → 1/1) ⇝ 3/1 | note:B3 s:gm_epiano1 n:1 attack:0.05 decay:0.1 sustain:0.7 cutoff:1111.7252990603447 gain:0.3 ]", - "[ (0/1 → 1/1) ⇝ 3/1 | note:D4 s:gm_epiano1 n:1 attack:0.05 decay:0.1 sustain:0.7 cutoff:1111.7252990603447 gain:0.3 ]", - "[ (0/1 → 1/1) ⇝ 3/1 | note:E4 s:gm_epiano1 n:1 attack:0.05 decay:0.1 sustain:0.7 cutoff:1111.7252990603447 gain:0.3 ]", - "[ (0/1 → 1/1) ⇝ 3/1 | note:G4 s:gm_epiano1 n:1 attack:0.05 decay:0.1 sustain:0.7 cutoff:1111.7252990603447 gain:0.3 ]", - "[ (0/1 → 1/1) ⇝ 9/2 | n:1 note:C5 s:gm_epiano1 attack:0.05 decay:0.1 sustain:0.7 cutoff:1111.7252990603447 gain:0.3 ]", - "[ 1/2 → 1/1 | s:hh speed:0.9519542165100575 n:3 ]", - "[ (3/4 → 1/1) ⇝ 3/2 | s:sd speed:0.9931522866332672 n:3 ]", -] -`; - exports[`renders tunes > tune: randomBells 1`] = ` [ "[ -9/8 ⇜ (0/1 → 3/8) | note:G4 s:bell gain:0.6 delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]", @@ -10180,22 +10165,22 @@ exports[`renders tunes > tune: undergroundPlumber 1`] = ` exports[`renders tunes > tune: waa2 1`] = ` [ - "[ -1/4 ⇜ (0/1 → 1/4) | note:48 clip:1.1738393178344886 s:sawtooth cutoff:3997.892048359052 gain:0.5 room:0.5 ]", - "[ -1/4 ⇜ (0/1 → 1/4) | note:64 clip:1.1738393178344886 s:sawtooth cutoff:3997.892048359052 gain:0.5 room:0.5 ]", - "[ (0/1 → 1/4) ⇝ 1/2 | note:62 clip:1.197659880151613 s:sawtooth cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", - "[ (0/1 → 1/4) ⇝ 1/2 | note:43 clip:1.197659880151613 s:sawtooth cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", - "[ 0/1 ⇜ (1/4 → 1/2) | note:62 clip:1.197659880151613 s:square cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", - "[ 0/1 ⇜ (1/4 → 1/2) | note:43 clip:1.197659880151613 s:square cutoff:3991.5732716763446 gain:0.5 room:0.5 ]", - "[ (1/4 → 1/2) ⇝ 3/4 | note:74 clip:1.2451698046878117 s:square cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", - "[ (1/4 → 1/2) ⇝ 3/4 | note:55 clip:1.2451698046878117 s:square cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", - "[ 1/4 ⇜ (1/2 → 3/4) | note:74 clip:1.2451698046878117 s:sawtooth cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", - "[ 1/4 ⇜ (1/2 → 3/4) | note:55 clip:1.2451698046878117 s:sawtooth cutoff:3966.3742407056534 gain:0.5 room:0.5 ]", - "[ 1/2 → 3/4 | note:50 clip:1.2688217886051745 s:sawtooth cutoff:3947.554693090452 gain:0.5 room:0.5 ]", - "[ (1/2 → 3/4) ⇝ 1/1 | note:69 clip:1.292380289809026 s:sawtooth cutoff:3924.645587531366 gain:0.5 room:0.5 ]", - "[ 1/2 ⇜ (3/4 → 1/1) | note:69 clip:1.292380289809026 s:square cutoff:3924.645587531366 gain:0.5 room:0.5 ]", - "[ 3/4 → 1/1 | note:41 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 ]", - "[ 3/4 → 1/1 | note:62 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 ]", - "[ (3/4 → 1/1) ⇝ 5/4 | note:81 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 ]", + "[ -1/4 ⇜ (0/1 → 1/4) | note:48 clip:1.1738393178344886 s:sawtooth cutoff:3997.892048359052 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ -1/4 ⇜ (0/1 → 1/4) | note:64 clip:1.1738393178344886 s:sawtooth cutoff:3997.892048359052 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ (0/1 → 1/4) ⇝ 1/2 | note:62 clip:1.197659880151613 s:sawtooth cutoff:3991.5732716763446 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ (0/1 → 1/4) ⇝ 1/2 | note:43 clip:1.197659880151613 s:sawtooth cutoff:3991.5732716763446 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ 0/1 ⇜ (1/4 → 1/2) | note:62 clip:1.197659880151613 s:square cutoff:3991.5732716763446 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ 0/1 ⇜ (1/4 → 1/2) | note:43 clip:1.197659880151613 s:square cutoff:3991.5732716763446 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ (1/4 → 1/2) ⇝ 3/4 | note:74 clip:1.2451698046878117 s:square cutoff:3966.3742407056534 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ (1/4 → 1/2) ⇝ 3/4 | note:55 clip:1.2451698046878117 s:square cutoff:3966.3742407056534 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ 1/4 ⇜ (1/2 → 3/4) | note:74 clip:1.2451698046878117 s:sawtooth cutoff:3966.3742407056534 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ 1/4 ⇜ (1/2 → 3/4) | note:55 clip:1.2451698046878117 s:sawtooth cutoff:3966.3742407056534 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ 1/2 → 3/4 | note:50 clip:1.2688217886051745 s:sawtooth cutoff:3947.554693090452 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ (1/2 → 3/4) ⇝ 1/1 | note:69 clip:1.292380289809026 s:sawtooth cutoff:3924.645587531366 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ 1/2 ⇜ (3/4 → 1/1) | note:69 clip:1.292380289809026 s:square cutoff:3924.645587531366 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ 3/4 → 1/1 | note:41 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ 3/4 → 1/1 | note:62 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", + "[ (3/4 → 1/1) ⇝ 5/4 | note:81 clip:1.315826773713709 s:square cutoff:3897.7021140702864 gain:0.5 room:0.5 lpattack:0.125 lpenv:-2 vib:8 vibmod:0.125 fanchor:0.25 ]", ] `; From 258eb88684a136b26190616d8b7cdc8c6e7572a8 Mon Sep 17 00:00:00 2001 From: vmilovidov Date: Sun, 17 Sep 2023 13:14:13 +0000 Subject: [PATCH 084/175] Update tauri.yml workflow --- .github/workflows/tauri.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tauri.yml b/.github/workflows/tauri.yml index 39ec34ca..dde52a25 100644 --- a/.github/workflows/tauri.yml +++ b/.github/workflows/tauri.yml @@ -42,7 +42,7 @@ jobs: if: matrix.platform == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf + sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf pkg-config alsa-tools libasound2-dev - name: Install app dependencies from lockfile and build web run: pnpm install From 05c09eff192ea66f0c64dac87693c6553907752b Mon Sep 17 00:00:00 2001 From: vmilovidov Date: Sun, 17 Sep 2023 13:26:58 +0000 Subject: [PATCH 085/175] Update tauri.yml workflow file --- .github/workflows/tauri.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tauri.yml b/.github/workflows/tauri.yml index dde52a25..07fd91be 100644 --- a/.github/workflows/tauri.yml +++ b/.github/workflows/tauri.yml @@ -42,7 +42,7 @@ jobs: if: matrix.platform == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf pkg-config alsa-tools libasound2-dev + sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf libasound2-dev - name: Install app dependencies from lockfile and build web run: pnpm install From 6e26f3975165ff4430b2079242937be351c40317 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 25 Sep 2023 22:34:31 +0200 Subject: [PATCH 086/175] add dough function for raw dsp --- packages/superdough/dspworklet.mjs | 80 ++++++++++++++++++++++++++++++ packages/superdough/index.mjs | 1 + website/src/repl/Repl.jsx | 7 ++- 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 packages/superdough/dspworklet.mjs diff --git a/packages/superdough/dspworklet.mjs b/packages/superdough/dspworklet.mjs new file mode 100644 index 00000000..ac51c8fc --- /dev/null +++ b/packages/superdough/dspworklet.mjs @@ -0,0 +1,80 @@ +import { Pattern } from '@strudel.cycles/core'; +import { getAudioContext } from './superdough.mjs'; + +let worklet; +export async function dspWorklet(ac, code) { + const name = `dsp-worklet-${Date.now()}`; + const workletCode = `${code} +let __q = []; // trigger queue +class MyProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.t = 0; + this.stopped = false; + this.port.onmessage = (e) => { + if(e.data==='stop') { + this.stopped = true; + } else if(e.data?.dough) { + const deadline = e.data.time-currentTime; + __q.push(e.data) + } else { + msg?.(e.data) + } + }; + } + process(inputs, outputs, parameters) { + const output = outputs[0]; + if(__q.length) { + __q = __q.filter((el) => { + const deadline = el.time-currentTime; + return deadline>0 ? true : trigger(el.dough) + }) + } + for (let i = 0; i < output[0].length; i++) { + const out = dsp(this.t / sampleRate); + output.forEach((channel) => { + channel[i] = out; + }); + this.t++; + } + return !this.stopped; + } +} +registerProcessor('${name}', MyProcessor); +`; + const base64String = btoa(workletCode); + const dataURL = `data:text/javascript;base64,${base64String}`; + await ac.audioWorklet.addModule(dataURL); + const node = new AudioWorkletNode(ac, name); + const stop = () => node.port.postMessage('stop'); + return { node, stop }; +} +const stop = () => { + if (worklet) { + worklet?.stop(); + worklet?.node?.disconnect(); + } +}; + +if (typeof window !== 'undefined') { + window.addEventListener('message', (e) => { + if (e.data === 'strudel-stop') { + stop(); + } else if (e.data?.dough) { + worklet?.node.port.postMessage(e.data); + } + }); +} + +export const dough = async (code) => { + const ac = getAudioContext(); + stop(); + worklet = await dspWorklet(ac, code); + worklet.node.connect(ac.destination); +}; + +Pattern.prototype.dough = function () { + return this.onTrigger((t, hap) => { + window.postMessage({ time: t, dough: hap.value }); + }, 1); +}; diff --git a/packages/superdough/index.mjs b/packages/superdough/index.mjs index e5d4498b..3247c5b4 100644 --- a/packages/superdough/index.mjs +++ b/packages/superdough/index.mjs @@ -10,3 +10,4 @@ export * from './helpers.mjs'; export * from './synth.mjs'; export * from './zzfx.mjs'; export * from './logger.mjs'; +export * from './dspworklet.mjs'; diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 173bb455..fe32e741 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -149,7 +149,12 @@ export function Repl({ embedded = false }) { onEvalError: (err) => { setPending(false); }, - onToggle: (play) => !play && cleanupDraw(false), + onToggle: (play) => { + if (!play) { + cleanupDraw(false); + window.postMessage('strudel-stop'); + } + }, drawContext, // drawTime: [0, 6], paintOptions, From 52c01abbe9e62abc18820143bfea0569e2c7d31a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 25 Sep 2023 22:39:03 +0200 Subject: [PATCH 087/175] encapsulate .dough --- packages/superdough/dspworklet.mjs | 9 +++------ packages/webaudio/webaudio.mjs | 6 +++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/superdough/dspworklet.mjs b/packages/superdough/dspworklet.mjs index ac51c8fc..2a77de53 100644 --- a/packages/superdough/dspworklet.mjs +++ b/packages/superdough/dspworklet.mjs @@ -1,4 +1,3 @@ -import { Pattern } from '@strudel.cycles/core'; import { getAudioContext } from './superdough.mjs'; let worklet; @@ -73,8 +72,6 @@ export const dough = async (code) => { worklet.node.connect(ac.destination); }; -Pattern.prototype.dough = function () { - return this.onTrigger((t, hap) => { - window.postMessage({ time: t, dough: hap.value }); - }, 1); -}; +export function doughTrigger(t, hap, currentTime, duration, cps) { + window.postMessage({ time: t, dough: hap.value, currentTime, duration, cps }); +} diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 8b32a90c..fb4a3d7d 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th */ import * as strudel from '@strudel.cycles/core'; -import { superdough, getAudioContext, setLogger } from 'superdough'; +import { superdough, getAudioContext, setLogger, doughTrigger } from 'superdough'; const { Pattern, logger } = strudel; setLogger(logger); @@ -35,3 +35,7 @@ export function webaudioScheduler(options = {}) { onTrigger: strudel.getTrigger({ defaultOutput, getTime }), }); } + +Pattern.prototype.dough = function () { + return this.onTrigger(doughTrigger, 1); +}; From 7078e20200bcbcc98e61de795604fc174d9495e3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 25 Sep 2023 22:56:44 +0200 Subject: [PATCH 088/175] less garbage --- packages/superdough/dspworklet.mjs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/superdough/dspworklet.mjs b/packages/superdough/dspworklet.mjs index 2a77de53..1c109452 100644 --- a/packages/superdough/dspworklet.mjs +++ b/packages/superdough/dspworklet.mjs @@ -24,10 +24,13 @@ class MyProcessor extends AudioWorkletProcessor { process(inputs, outputs, parameters) { const output = outputs[0]; if(__q.length) { - __q = __q.filter((el) => { - const deadline = el.time-currentTime; - return deadline>0 ? true : trigger(el.dough) - }) + for(let i=0;i<__q.length;++i) { + const deadline = __q[i].time-currentTime; + if(deadline<=0) { + trigger(__q[i].dough) + __q.splice(i,1) + } + } } for (let i = 0; i < output[0].length; i++) { const out = dsp(this.t / sampleRate); From eec3752b5a9b2ba0318029fbe4c51e03e9bf4dc7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 25 Sep 2023 23:57:09 +0200 Subject: [PATCH 089/175] cleanup --- packages/superdough/dspworklet.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/superdough/dspworklet.mjs b/packages/superdough/dspworklet.mjs index 1c109452..deff485a 100644 --- a/packages/superdough/dspworklet.mjs +++ b/packages/superdough/dspworklet.mjs @@ -14,7 +14,6 @@ class MyProcessor extends AudioWorkletProcessor { if(e.data==='stop') { this.stopped = true; } else if(e.data?.dough) { - const deadline = e.data.time-currentTime; __q.push(e.data) } else { msg?.(e.data) From 62743edf4540356e7e7aae474ff4adbf4a3bfe53 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 25 Sep 2023 23:57:19 +0200 Subject: [PATCH 090/175] bump superdough to 0.9.9 --- packages/superdough/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/package.json b/packages/superdough/package.json index 69ba6f8c..387749c8 100644 --- a/packages/superdough/package.json +++ b/packages/superdough/package.json @@ -1,6 +1,6 @@ { "name": "superdough", - "version": "0.9.8", + "version": "0.9.9", "description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.", "main": "index.mjs", "type": "module", From cf72e3bba5f22a6109c381af47634ebb34c2141a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 27 Sep 2023 21:25:30 +0200 Subject: [PATCH 091/175] fix: add conditional imports to eval scope + fire postMessage on start --- website/src/repl/Repl.jsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index fe32e741..4002eba8 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -33,7 +33,7 @@ const supabase = createClient( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM', ); -const modules = [ +let modules = [ import('@strudel.cycles/core'), import('@strudel.cycles/tonal'), import('@strudel.cycles/mini'), @@ -45,13 +45,13 @@ const modules = [ import('@strudel.cycles/csound'), ]; if (isTauri()) { - modules.concat([ + modules = modules.concat([ import('@strudel/desktopbridge/loggerbridge.mjs'), import('@strudel/desktopbridge/midibridge.mjs'), import('@strudel/desktopbridge/oscbridge.mjs'), ]); } else { - modules.concat([import('@strudel.cycles/midi'), import('@strudel.cycles/osc')]); + modules = modules.concat([import('@strudel.cycles/midi'), import('@strudel.cycles/osc')]); } const modulesLoading = evalScope( @@ -153,6 +153,8 @@ export function Repl({ embedded = false }) { if (!play) { cleanupDraw(false); window.postMessage('strudel-stop'); + } else { + window.postMessage('strudel-start'); } }, drawContext, From 68ab43b3ab2c79691e55e3cf2ca288573bc00e72 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 27 Sep 2023 21:26:24 +0200 Subject: [PATCH 092/175] support midi clock via "clock" control (not on desktop yet) --- packages/core/controls.mjs | 1 + packages/midi/midi.mjs | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 6cac6e54..62cfdd46 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1066,6 +1066,7 @@ const generic_params = [ */ ['waveloss'], // TODO: midi effects? + ['clock'], ['dur'], // ['modwheel'], ['expression'], diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index 98509b46..32583d75 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -90,6 +90,13 @@ Pattern.prototype.midi = function (output) { enableWebMidi({ onEnabled: ({ outputs }) => { const device = getDevice(output, outputs); + if (typeof window !== 'undefined') { + window.addEventListener('message', (e) => { + if (e.data === 'strudel-stop') { + device.sendStop(); + } + }); + } const otherOutputs = outputs.filter((o) => o.name !== device.name); logger( `Midi enabled! Using "${device.name}". ${ @@ -103,6 +110,7 @@ Pattern.prototype.midi = function (output) { return this.onTrigger((time, hap, currentTime, cps) => { if (!WebMidi.enabled) { + console.log('not enabled'); return; } const device = getDevice(output, WebMidi.outputs); @@ -113,7 +121,7 @@ Pattern.prototype.midi = function (output) { const timeOffsetString = `+${offset}`; // destructure value - const { note, nrpnn, nrpv, ccn, ccv, midichan = 1 } = hap.value; + const { note, nrpnn, nrpv, ccn, ccv, midichan = 1, clock } = hap.value; const velocity = hap.context?.velocity ?? 0.9; // TODO: refactor velocity // note off messages will often a few ms arrive late, try to prevent glitching by subtracting from the duration length @@ -125,7 +133,7 @@ Pattern.prototype.midi = function (output) { time: timeOffsetString, }); } - if (ccv && ccn) { + if (ccv !== undefined && ccn !== undefined) { if (typeof ccv !== 'number' || ccv < 0 || ccv > 1) { throw new Error('expected ccv to be a number between 0 and 1'); } @@ -135,5 +143,12 @@ Pattern.prototype.midi = function (output) { const scaled = Math.round(ccv * 127); device.sendControlChange(ccn, scaled, midichan, { time: timeOffsetString }); } + const begin = hap.whole.begin + 0; + if (begin === 0) { + device.sendStart({ time: timeOffsetString }); + } + if (clock) { + device.sendClock({ time: timeOffsetString }); + } }); }; From dea1c31701a9ad8b0bbb081c85401b088f480f88 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 27 Sep 2023 22:10:21 +0200 Subject: [PATCH 093/175] use midicmd instead of clock --- packages/core/controls.mjs | 2 +- packages/midi/midi.mjs | 21 ++++++++------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 62cfdd46..d1a9ce7f 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1066,7 +1066,7 @@ const generic_params = [ */ ['waveloss'], // TODO: midi effects? - ['clock'], + ['midicmd'], ['dur'], // ['modwheel'], ['expression'], diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index 32583d75..ee111d7e 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -90,13 +90,6 @@ Pattern.prototype.midi = function (output) { enableWebMidi({ onEnabled: ({ outputs }) => { const device = getDevice(output, outputs); - if (typeof window !== 'undefined') { - window.addEventListener('message', (e) => { - if (e.data === 'strudel-stop') { - device.sendStop(); - } - }); - } const otherOutputs = outputs.filter((o) => o.name !== device.name); logger( `Midi enabled! Using "${device.name}". ${ @@ -121,7 +114,7 @@ Pattern.prototype.midi = function (output) { const timeOffsetString = `+${offset}`; // destructure value - const { note, nrpnn, nrpv, ccn, ccv, midichan = 1, clock } = hap.value; + const { note, nrpnn, nrpv, ccn, ccv, midichan = 1, midicmd } = hap.value; const velocity = hap.context?.velocity ?? 0.9; // TODO: refactor velocity // note off messages will often a few ms arrive late, try to prevent glitching by subtracting from the duration length @@ -143,12 +136,14 @@ Pattern.prototype.midi = function (output) { const scaled = Math.round(ccv * 127); device.sendControlChange(ccn, scaled, midichan, { time: timeOffsetString }); } - const begin = hap.whole.begin + 0; - if (begin === 0) { - device.sendStart({ time: timeOffsetString }); - } - if (clock) { + if (['clock', 'midiClock'].includes(midicmd)) { device.sendClock({ time: timeOffsetString }); + } else if (['start'].includes(midicmd)) { + device.sendStart({ time: timeOffsetString }); + } else if (['stop'].includes(midicmd)) { + device.sendStop({ time: timeOffsetString }); + } else if (['continue'].includes(midicmd)) { + device.sendContinue({ time: timeOffsetString }); } }); }; From f11462bf41ee9898cac562970e6252035cdd77a4 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 27 Sep 2023 22:28:52 +0200 Subject: [PATCH 094/175] sync start / stop automatically too --- packages/midi/midi.mjs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index ee111d7e..e3ce0b3e 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -78,6 +78,20 @@ function getDevice(output, outputs) { return IACOutput ?? outputs[0]; } +// send start/stop messages to outputs when repl starts/stops +if (typeof window !== 'undefined') { + window.addEventListener('message', (e) => { + if (!WebMidi?.enabled) { + return; + } + if (e.data === 'strudel-stop') { + WebMidi.outputs.forEach((output) => output.sendStop()); + } else if (e.data === 'strudel-start') { + WebMidi.outputs.forEach((output) => output.sendStart()); + } + }); +} + Pattern.prototype.midi = function (output) { if (isPattern(output)) { throw new Error( From 4eb0a7b7c0606acd5469b93f5275481dff86132a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 27 Sep 2023 22:42:35 +0200 Subject: [PATCH 095/175] send start with accurate timing --- packages/midi/midi.mjs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index e3ce0b3e..07e6e65c 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -86,9 +86,8 @@ if (typeof window !== 'undefined') { } if (e.data === 'strudel-stop') { WebMidi.outputs.forEach((output) => output.sendStop()); - } else if (e.data === 'strudel-start') { - WebMidi.outputs.forEach((output) => output.sendStart()); } + // cannot start here, since we have no timing info, see sendStart below }); } @@ -150,6 +149,10 @@ Pattern.prototype.midi = function (output) { const scaled = Math.round(ccv * 127); device.sendControlChange(ccn, scaled, midichan, { time: timeOffsetString }); } + if (hap.whole.begin + 0 === 0) { + // we need to start here because we have the timing info + device.sendStart({ time: timeOffsetString }); + } if (['clock', 'midiClock'].includes(midicmd)) { device.sendClock({ time: timeOffsetString }); } else if (['start'].includes(midicmd)) { From 6c3a3b9e29123286f686c00851c4ff44a28e142a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 28 Sep 2023 10:40:44 +0200 Subject: [PATCH 096/175] dedupe --- packages/core/controls.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index d1a9ce7f..6cac6e54 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1066,7 +1066,6 @@ const generic_params = [ */ ['waveloss'], // TODO: midi effects? - ['midicmd'], ['dur'], // ['modwheel'], ['expression'], From 0dcc55ee167a6dd26cf4a671ae73e326e62ae997 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 28 Sep 2023 10:48:31 +0200 Subject: [PATCH 097/175] prevent error --- packages/midi/midi.mjs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index 1d89b6dc..ab59c2e4 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -167,7 +167,6 @@ let listeners = {}; const refs = {}; export async function midin(input) { - console.log('midi in...'); const initial = await enableWebMidi(); // only returns on first init const device = getDevice(input, WebMidi.inputs); @@ -186,9 +185,8 @@ export async function midin(input) { listeners[input] = (e) => { const cc = e.dataBytes[0]; const v = e.dataBytes[1]; - refs[input][cc] = v / 127; + refs[input] && (refs[input][cc] = v / 127); }; device.addListener('midimessage', listeners[input]); - //return { cc }; return cc; } From aa094bf9309ccef568b1d34726aaf878437df802 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 29 Sep 2023 10:40:00 +0200 Subject: [PATCH 098/175] checkbox + number slider --- packages/codemirror/checkbox.mjs | 87 ++++++++++++ packages/codemirror/slider.mjs | 129 ++++++++++++++++++ packages/react/src/components/CodeMirror6.jsx | 4 +- 3 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 packages/codemirror/checkbox.mjs create mode 100644 packages/codemirror/slider.mjs diff --git a/packages/codemirror/checkbox.mjs b/packages/codemirror/checkbox.mjs new file mode 100644 index 00000000..279e2eb8 --- /dev/null +++ b/packages/codemirror/checkbox.mjs @@ -0,0 +1,87 @@ +import { WidgetType } from '@codemirror/view'; +import { ViewPlugin, Decoration } from '@codemirror/view'; +import { syntaxTree } from '@codemirror/language'; + +export class CheckboxWidget extends WidgetType { + constructor(checked) { + super(); + this.checked = checked; + } + + eq(other) { + return other.checked == this.checked; + } + + toDOM() { + let wrap = document.createElement('span'); + wrap.setAttribute('aria-hidden', 'true'); + wrap.className = 'cm-boolean-toggle'; + let box = wrap.appendChild(document.createElement('input')); + box.type = 'checkbox'; + box.checked = this.checked; + return wrap; + } + + ignoreEvent() { + return false; + } +} + +// EditorView +export function checkboxes(view) { + let widgets = []; + for (let { from, to } of view.visibleRanges) { + syntaxTree(view.state).iterate({ + from, + to, + enter: (node) => { + if (node.name == 'BooleanLiteral') { + let isTrue = view.state.doc.sliceString(node.from, node.to) == 'true'; + let deco = Decoration.widget({ + widget: new CheckboxWidget(isTrue), + side: 1, + }); + widgets.push(deco.range(node.from)); + } + }, + }); + } + return Decoration.set(widgets); +} + +export const checkboxPlugin = ViewPlugin.fromClass( + class { + decorations; //: DecorationSet + + constructor(view /* : EditorView */) { + this.decorations = checkboxes(view); + } + + update(update /* : ViewUpdate */) { + if (update.docChanged || update.viewportChanged) this.decorations = checkboxes(update.view); + } + }, + { + decorations: (v) => v.decorations, + + eventHandlers: { + mousedown: (e, view) => { + let target = e.target; /* as HTMLElement */ + if (target.nodeName == 'INPUT' && target.parentElement.classList.contains('cm-boolean-toggle')) + return toggleBoolean(view, view.posAtDOM(target)); + }, + }, + }, +); + +function toggleBoolean(view /* : EditorView */, pos /* : number */) { + let before = view.state.doc.sliceString(Math.max(0, pos), pos + 5).trim(); + let change; + if (!['true', 'false'].includes(before)) { + return false; + } + let insert = before === 'true' ? 'false' : 'true'; + change = { from: pos, to: pos + before.length, insert }; + view.dispatch({ changes: change }); + return true; +} diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs new file mode 100644 index 00000000..f03dba18 --- /dev/null +++ b/packages/codemirror/slider.mjs @@ -0,0 +1,129 @@ +import { WidgetType } from '@codemirror/view'; +import { ViewPlugin, Decoration } from '@codemirror/view'; +import { syntaxTree } from '@codemirror/language'; + +export class SliderWidget extends WidgetType { + constructor(value, min, max, from, to) { + super(); + this.value = value; + this.min = min; + this.max = max; + this.from = from; + this.to = to; + } + + eq(other) { + const isSame = other.value.toFixed(4) == this.value.toFixed(4); + return isSame; + } + + toDOM() { + let wrap = document.createElement('span'); + wrap.setAttribute('aria-hidden', 'true'); + wrap.className = 'cm-slider'; // inline-flex items-center + let slider = wrap.appendChild(document.createElement('input')); + slider.type = 'range'; + slider.min = this.min; + slider.max = this.max; + slider.step = (this.max - this.min) / 1000; + slider.value = this.value; + slider.from = this.from; + slider.to = this.to; + slider.className = 'w-16'; + return wrap; + } + + ignoreEvent() { + return false; + } +} + +// EditorView +export function sliders(view) { + let widgets = []; + for (let { from, to } of view.visibleRanges) { + syntaxTree(view.state).iterate({ + from, + to, + enter: (node) => { + if (node.name == 'Number') { + let value = view.state.doc.sliceString(node.from, node.to); + value = Number(value); + /* let min = Math.min(0, value); + let max = Math.max(value, 1); */ + let min = 0; + let max = 10; + //console.log('from', node.from, 'to', node.to); + let deco = Decoration.widget({ + widget: new SliderWidget(value, min, max, node.from, node.to), + side: 1, + }); + widgets.push(deco.range(node.from)); + } + }, + }); + } + return Decoration.set(widgets); +} + +let draggedSlider, init; +export const sliderPlugin = ViewPlugin.fromClass( + class { + decorations; //: DecorationSet + + constructor(view /* : EditorView */) { + this.decorations = sliders(view); + } + + update(update /* : ViewUpdate */) { + if (update.docChanged || update.viewportChanged) { + !init && (this.decorations = sliders(update.view)); + //init = true; + } + } + }, + { + decorations: (v) => v.decorations, + + eventHandlers: { + mousedown: (e, view) => { + let target = e.target; /* as HTMLElement */ + if (target.nodeName == 'INPUT' && target.parentElement.classList.contains('cm-slider')) { + draggedSlider = target; + // remember offsetLeft / clientWidth, as they will vanish inside mousemove events for some reason + draggedSlider._offsetLeft = draggedSlider.offsetLeft; + draggedSlider._clientWidth = draggedSlider.clientWidth; + return updateSliderValue(view, e); + } + }, + mouseup: () => { + draggedSlider = undefined; + }, + mousemove: (e, view) => { + draggedSlider && updateSliderValue(view, e); + }, + }, + }, +); + +function updateSliderValue(view, e) { + const mouseX = e.clientX; + let progress = (mouseX - draggedSlider._offsetLeft) / draggedSlider._clientWidth; + progress = Math.max(Math.min(1, progress), 0); + let min = Number(draggedSlider.min); + let max = Number(draggedSlider.max); + const next = Number(progress * (max - min) + min); + let insert = next.toFixed(2); + let before = view.state.doc.sliceString(draggedSlider.from, draggedSlider.to).trim(); + before = Number(before).toFixed(4); + if (before === next) { + return false; + } + //console.log('before', before, '->', insert); + let change = { from: draggedSlider.from, to: draggedSlider.to, insert }; + draggedSlider.to = draggedSlider.from + insert.length; + //console.log('change', change); + view.dispatch({ changes: change }); + + return true; +} diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx index 0f1b2274..f3c764e0 100644 --- a/packages/react/src/components/CodeMirror6.jsx +++ b/packages/react/src/components/CodeMirror6.jsx @@ -15,10 +15,12 @@ import { updateMiniLocations, } from '@strudel/codemirror'; import './style.css'; +import { checkboxPlugin } from '@strudel/codemirror/checkbox.mjs'; +import { sliderPlugin } from '@strudel/codemirror/slider.mjs'; export { flash, highlightMiniLocations, updateMiniLocations }; -const staticExtensions = [javascript(), flashField, highlightExtension]; +const staticExtensions = [javascript(), flashField, highlightExtension, checkboxPlugin, sliderPlugin]; export default function CodeMirror({ value, From c93e4a951a003a21431e8cc9388968bc55dc68e7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 29 Sep 2023 12:58:16 +0200 Subject: [PATCH 099/175] match number.slider --- packages/codemirror/slider.mjs | 57 ++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index f03dba18..423d3651 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -38,6 +38,43 @@ export class SliderWidget extends WidgetType { } } +let nodeValue = (node, view) => view.state.doc.sliceString(node.from, node.to); + +// matches a number and returns slider widget +/* let matchNumber = (node, view) => { + if (node.name == 'Number') { + const value = view.state.doc.sliceString(node.from, node.to); + let min = 0; + let max = 10; + return Decoration.widget({ + widget: new SliderWidget(Number(value), min, max, node.from, node.to), + side: 0, + }); + } +}; */ +// matches something like 123.xxx and returns slider widget +let matchNumberSlider = (node, view) => { + if ( + node.name === 'MemberExpression' && + node.node.firstChild.name === 'Number' && + node.node.lastChild.name === 'PropertyName' + ) { + // node is sth like 123.xxx + let prop = nodeValue(node.node.lastChild, view); // get prop name (e.g. xxx) + if (prop === 'slider') { + let value = nodeValue(node.node.firstChild, view); // get number (e.g. 123) + // console.log('slider value', value); + let { from, to } = node.node.firstChild; + let min = 0; + let max = 10; + return Decoration.widget({ + widget: new SliderWidget(Number(value), min, max, from, to), + side: 0, + }); + } + } +}; + // EditorView export function sliders(view) { let widgets = []; @@ -46,20 +83,14 @@ export function sliders(view) { from, to, enter: (node) => { - if (node.name == 'Number') { - let value = view.state.doc.sliceString(node.from, node.to); - value = Number(value); - /* let min = Math.min(0, value); - let max = Math.max(value, 1); */ - let min = 0; - let max = 10; - //console.log('from', node.from, 'to', node.to); - let deco = Decoration.widget({ - widget: new SliderWidget(value, min, max, node.from, node.to), - side: 1, - }); - widgets.push(deco.range(node.from)); + let numberSlider = matchNumberSlider(node, view); + if (numberSlider) { + widgets.push(numberSlider.range(node.from)); } + /* let number = matchNumber(node, view); + if (number) { + widgets.push(number.range(node.from)); + } */ }, }); } From c2481e460b5c455662999fd61a8d2b9ec1ffb22c Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sat, 30 Sep 2023 14:07:33 +0200 Subject: [PATCH 100/175] Add pink, white and brown oscillators --- packages/superdough/synth.mjs | 282 ++++++++++++++++++++-------------- 1 file changed, 167 insertions(+), 115 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 633d0113..3ab3720f 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -20,100 +20,102 @@ const fm = (osc, harmonicityRatio, modulationIndex, wave = 'sine') => { return mod(modfreq, modgain, wave); }; + export function registerSynthSounds() { - ['sine', 'square', 'triangle', 'sawtooth'].forEach((wave) => { - registerSound( - wave, - (t, value, onended) => { - // destructure adsr here, because the default should be different for synths and samples - let { - attack = 0.001, - decay = 0.05, - sustain = 0.6, - release = 0.01, - fmh: fmHarmonicity = 1, - fmi: fmModulationIndex, - fmenv: fmEnvelopeType = 'lin', - fmattack: fmAttack, - fmdecay: fmDecay, - fmsustain: fmSustain, - fmrelease: fmRelease, - fmvelocity: fmVelocity, - fmwave: fmWaveform = 'sine', - vib = 0, - vibmod = 0.5, - } = value; - let { n, note, freq } = value; - // with synths, n and note are the same thing - note = note || 36; - if (typeof note === 'string') { - note = noteToMidi(note); // e.g. c3 => 48 - } - // get frequency - if (!freq && typeof note === 'number') { - freq = midiToFreq(note); // + 48); - } - // maybe pull out the above frequency resolution?? (there is also getFrequency but it has no default) - // make oscillator - const { node: o, stop } = getOscillator({ - t, - s: wave, - freq, - vib, - vibmod, - partials: n, - }); - - // FM + FM envelope - let stopFm, fmEnvelope; - if (fmModulationIndex) { - const { node: modulator, stop } = fm(o, fmHarmonicity, fmModulationIndex, fmWaveform); - if (![fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity].find((v) => v !== undefined)) { - // no envelope by default - modulator.connect(o.frequency); - } else { - fmAttack = fmAttack ?? 0.001; - fmDecay = fmDecay ?? 0.001; - fmSustain = fmSustain ?? 1; - fmRelease = fmRelease ?? 0.001; - fmVelocity = fmVelocity ?? 1; - fmEnvelope = getEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); - if (fmEnvelopeType === 'exp') { - fmEnvelope = getExpEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); - fmEnvelope.node.maxValue = fmModulationIndex * 2; - fmEnvelope.node.minValue = 0.00001; - } - modulator.connect(fmEnvelope.node); - fmEnvelope.node.connect(o.frequency); + ['sine', 'square', 'triangle', + 'sawtooth', 'pink', 'white', + 'brown'].forEach((wave) => { + registerSound( + wave, + (t, value, onended) => { + // destructure adsr here, because the default should be different for synths and samples + let { + attack = 0.001, + decay = 0.05, + sustain = 0.6, + release = 0.01, + fmh: fmHarmonicity = 1, + fmi: fmModulationIndex, + fmenv: fmEnvelopeType = 'lin', + fmattack: fmAttack, + fmdecay: fmDecay, + fmsustain: fmSustain, + fmrelease: fmRelease, + fmvelocity: fmVelocity, + fmwave: fmWaveform = 'sine', + vib = 0, + vibmod = 0.5, + } = value; + let { n, note, freq } = value; + // with synths, n and note are the same thing + note = note || 36; + if (typeof note === 'string') { + note = noteToMidi(note); // e.g. c3 => 48 + } + // get frequency + if (!freq && typeof note === 'number') { + freq = midiToFreq(note); // + 48); + } + // maybe pull out the above frequency resolution?? (there is also getFrequency but it has no default) + // make oscillator + const { node: o, stop } = getOscillator({ + t, + s: wave, + freq, + vib, + vibmod, + partials: n, + }); + // FM + FM envelope + let stopFm, fmEnvelope; + if (fmModulationIndex) { + const { node: modulator, stop } = fm(o, fmHarmonicity, fmModulationIndex, fmWaveform); + if (![fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity].find((v) => v !== undefined)) { + // no envelope by default + modulator.connect(o.frequency); + } else { + fmAttack = fmAttack ?? 0.001; + fmDecay = fmDecay ?? 0.001; + fmSustain = fmSustain ?? 1; + fmRelease = fmRelease ?? 0.001; + fmVelocity = fmVelocity ?? 1; + fmEnvelope = getEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); + if (fmEnvelopeType === 'exp') { + fmEnvelope = getExpEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); + fmEnvelope.node.maxValue = fmModulationIndex * 2; + fmEnvelope.node.minValue = 0.00001; + } + modulator.connect(fmEnvelope.node); + fmEnvelope.node.connect(o.frequency); + } + stopFm = stop; } - stopFm = stop; - } - // turn down - const g = gainNode(0.3); + // turn down + const g = gainNode(0.3); - // gain envelope - const { node: envelope, stop: releaseEnvelope } = getEnvelope(attack, decay, sustain, release, 1, t); + // gain envelope + const { node: envelope, stop: releaseEnvelope } = getEnvelope(attack, decay, sustain, release, 1, t); - o.onended = () => { - o.disconnect(); - g.disconnect(); - onended(); - }; - return { - node: o.connect(g).connect(envelope), - stop: (releaseTime) => { - releaseEnvelope(releaseTime); - fmEnvelope?.stop(releaseTime); - let end = releaseTime + release; - stop(end); - stopFm?.(end); - }, - }; - }, - { type: 'synth', prebake: true }, - ); - }); + o.onended = () => { + o.disconnect(); + g.disconnect(); + onended(); + }; + return { + node: o.connect(g).connect(envelope), + stop: (releaseTime) => { + releaseEnvelope(releaseTime); + fmEnvelope?.stop(releaseTime); + let end = releaseTime + release; + stop(end); + stopFm?.(end); + }, + }; + }, + { type: 'synth', prebake: true }, + ); + }); } export function waveformN(partials, type) { @@ -146,36 +148,86 @@ export function waveformN(partials, type) { return osc; } -export function getOscillator({ s, freq, t, vib, vibmod, partials }) { - // Make oscillator with partial count - let o; - if (!partials || s === 'sine') { - o = getAudioContext().createOscillator(); - o.type = s || 'triangle'; - } else { - o = waveformN(partials, s); - } - o.frequency.value = Number(freq); - o.start(t); +export function getNoiseOscillator({ t, ac, type = 'white' }) { + const bufferSize = 2 * ac.sampleRate; + const noiseBuffer = ac.createBuffer(1, bufferSize, ac.sampleRate); + const output = noiseBuffer.getChannelData(0); + let lastOut = 0; + let b0, b1, b2, b3, b4, b5, b6; + b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0; - // Additional oscillator for vibrato effect - let vibrato_oscillator; - if (vib > 0) { - vibrato_oscillator = getAudioContext().createOscillator(); - vibrato_oscillator.frequency.value = vib; - const gain = getAudioContext().createGain(); - // Vibmod is the amount of vibrato, in semitones - gain.gain.value = vibmod * 100; - vibrato_oscillator.connect(gain); - gain.connect(o.detune); - vibrato_oscillator.start(t); + for (let i = 0; i < bufferSize; i++) { + if (type === 'white') { + output[i] = Math.random() * 2 - 1; + } else if (type === 'brown') { + let white = Math.random() * 2 - 1; + output[i] = (lastOut + (0.02 * white)) / 1.02; + lastOut = output[i]; + } else if (type === 'pink') { + let white = Math.random() * 2 - 1; + b0 = 0.99886 * b0 + white * 0.0555179; + b1 = 0.99332 * b1 + white * 0.0750759; + b2 = 0.96900 * b2 + white * 0.1538520; + b3 = 0.86650 * b3 + white * 0.3104856; + b4 = 0.55000 * b4 + white * 0.5329522; + b5 = -0.7616 * b5 - white * 0.0168980; + output[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362; + output[i] *= 0.11; + b6 = white * 0.115926; + } } + const o = ac.createBufferSource(); + o.buffer = noiseBuffer; + o.loop = true; + o.start(t); + return { node: o, - stop: (time) => { - vibrato_oscillator?.stop(time); - o.stop(time); - }, + stop: (time) => o.stop(time) }; } + +export function getOscillator({ s, freq, t, vib, vibmod, partials }) { + // Make oscillator with partial count + let o; + + if (['pink', 'white', 'brown'].includes(s)) { + let noiseOscillator = getNoiseOscillator({ t: t, ac: getAudioContext(), type: s }) + return { + node: noiseOscillator.node, + stop: noiseOscillator.stop + } + } else { + if (!partials || s === 'sine') { + o = getAudioContext().createOscillator(); + o.type = s || 'triangle'; + } else { + o = waveformN(partials, s); + } + o.frequency.value = Number(freq); + o.start(t); + + // Additional oscillator for vibrato effect + let vibrato_oscillator; + if (vib > 0) { + vibrato_oscillator = getAudioContext().createOscillator(); + vibrato_oscillator.frequency.value = vib; + const gain = getAudioContext().createGain(); + // Vibmod is the amount of vibrato, in semitones + gain.gain.value = vibmod * 100; + vibrato_oscillator.connect(gain); + gain.connect(o.detune); + vibrato_oscillator.start(t); + } + + return { + node: o, + stop: (time) => { + vibrato_oscillator?.stop(time); + o.stop(time); + }, + }; + } +} + From 389c7be264c22fd7ce7fb2374dad9936ad4ffc15 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sat, 30 Sep 2023 14:39:44 +0200 Subject: [PATCH 101/175] Add noise parameter for base oscillators --- packages/superdough/synth.mjs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 3ab3720f..aa7b63ee 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -45,6 +45,7 @@ export function registerSynthSounds() { fmwave: fmWaveform = 'sine', vib = 0, vibmod = 0.5, + noise = 0, } = value; let { n, note, freq } = value; // with synths, n and note are the same thing @@ -65,6 +66,7 @@ export function registerSynthSounds() { vib, vibmod, partials: n, + noise: noise, }); // FM + FM envelope let stopFm, fmEnvelope; @@ -188,8 +190,9 @@ export function getNoiseOscillator({ t, ac, type = 'white' }) { }; } -export function getOscillator({ s, freq, t, vib, vibmod, partials }) { +export function getOscillator({ s, freq, t, vib, vibmod, partials, noise }) { // Make oscillator with partial count + let ac = getAudioContext(); let o; if (['pink', 'white', 'brown'].includes(s)) { @@ -221,6 +224,33 @@ export function getOscillator({ s, freq, t, vib, vibmod, partials }) { vibrato_oscillator.start(t); } + if (noise > 0) { + // Two gain nodes to set the oscillators to their respective levels + let o_gain = ac.createGain(); + let n_gain = ac.createGain(); + o_gain.gain.setValueAtTime(1 - noise, ac.currentTime); + n_gain.gain.setValueAtTime(noise, ac.currentTime); + + // Instanciating a mixer to blend sources together + let mix_gain = ac.createGain(); + + // Connecting the main oscillator to the gain node + o.connect(o_gain).connect(mix_gain); + + // Instanciating a noise oscillator and connecting + const noiseOscillator = getNoiseOscillator({ t: t, ac: ac, type: 'pink' }); + noiseOscillator.node.connect(n_gain).connect(mix_gain); + + return { + node: mix_gain, + stop: (time) => { + vibrato_oscillator?.stop(time); + o.stop(time); + noiseOscillator.stop(time); + } + } + } + return { node: o, stop: (time) => { From bb7b8c2fabe72b520e9e312e2d2d02c8cb2e17c9 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sat, 30 Sep 2023 14:59:43 +0200 Subject: [PATCH 102/175] Fix noise parameter and FM parameters compatibility --- packages/superdough/synth.mjs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index aa7b63ee..cd523de8 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -59,7 +59,7 @@ export function registerSynthSounds() { } // maybe pull out the above frequency resolution?? (there is also getFrequency but it has no default) // make oscillator - const { node: o, stop } = getOscillator({ + const { node: o, stop, dry_node = null } = getOscillator({ t, s: wave, freq, @@ -71,10 +71,10 @@ export function registerSynthSounds() { // FM + FM envelope let stopFm, fmEnvelope; if (fmModulationIndex) { - const { node: modulator, stop } = fm(o, fmHarmonicity, fmModulationIndex, fmWaveform); + const { node: modulator, stop } = fm(dry_node !== null ? dry_node : o, fmHarmonicity, fmModulationIndex, fmWaveform); if (![fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity].find((v) => v !== undefined)) { // no envelope by default - modulator.connect(o.frequency); + modulator.connect(dry_node !== null ? dry_node.frequency : o.frequency); } else { fmAttack = fmAttack ?? 0.001; fmDecay = fmDecay ?? 0.001; @@ -88,7 +88,7 @@ export function registerSynthSounds() { fmEnvelope.node.minValue = 0.00001; } modulator.connect(fmEnvelope.node); - fmEnvelope.node.connect(o.frequency); + fmEnvelope.node.connect(dry_node !== null ? dry_node.frequency : o.frequency); } stopFm = stop; } @@ -243,6 +243,7 @@ export function getOscillator({ s, freq, t, vib, vibmod, partials, noise }) { return { node: mix_gain, + dry_node: o, stop: (time) => { vibrato_oscillator?.stop(time); o.stop(time); From e3333e716fc6b30da5a792eced45a5487dd59a35 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sat, 30 Sep 2023 15:08:09 +0200 Subject: [PATCH 103/175] Cap noise amount to 1 --- packages/superdough/synth.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index cd523de8..e5f84bcf 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -226,6 +226,7 @@ export function getOscillator({ s, freq, t, vib, vibmod, partials, noise }) { if (noise > 0) { // Two gain nodes to set the oscillators to their respective levels + noise = noise > 1 ? 1 : noise; let o_gain = ac.createGain(); let n_gain = ac.createGain(); o_gain.gain.setValueAtTime(1 - noise, ac.currentTime); From b2acff40c4354b5390334fcd9ec83b5aeacd2502 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sat, 30 Sep 2023 15:17:22 +0200 Subject: [PATCH 104/175] Add documentation about noise sources --- website/src/pages/learn/synths.mdx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index 9f21204f..661ec860 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -23,6 +23,23 @@ The basic waveforms are `sine`, `sawtooth`, `square` and `triangle`, which can b If you don't set a `sound` but a `note` the default value for `sound` is `triangle`! +You can also use noise as a source by setting the waveform to: `white`, `pink` or `brown`. These are different +flavours of noise, here written from hard to soft. + +>") +.sound("/2") +.scope()`} +/> + +Some amount of pink noise can also be added to any oscillator by using the `noise` paremeter: + +").scope()`} +/> + ### Additive Synthesis To tame the harsh sound of the basic waveforms, we can set the `n` control to limit the overtones of the waveform: From 276cf858fcf851bbe92a7b3f4a31dac405714c64 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 30 Sep 2023 20:39:03 +0200 Subject: [PATCH 105/175] match slider as function --- packages/codemirror/slider.mjs | 53 ++++++++++++++++------------------ website/tailwind.config.cjs | 1 + 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 423d3651..63015051 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -13,7 +13,7 @@ export class SliderWidget extends WidgetType { } eq(other) { - const isSame = other.value.toFixed(4) == this.value.toFixed(4); + const isSame = other.value.toFixed(4) == this.value.toFixed(4) && other.min == this.min && other.max == this.max; return isSame; } @@ -29,7 +29,7 @@ export class SliderWidget extends WidgetType { slider.value = this.value; slider.from = this.from; slider.to = this.to; - slider.className = 'w-16'; + slider.className = 'w-16 translate-y-1.5'; return wrap; } @@ -52,26 +52,28 @@ let nodeValue = (node, view) => view.state.doc.sliceString(node.from, node.to); }); } }; */ -// matches something like 123.xxx and returns slider widget -let matchNumberSlider = (node, view) => { - if ( - node.name === 'MemberExpression' && - node.node.firstChild.name === 'Number' && - node.node.lastChild.name === 'PropertyName' - ) { - // node is sth like 123.xxx - let prop = nodeValue(node.node.lastChild, view); // get prop name (e.g. xxx) - if (prop === 'slider') { - let value = nodeValue(node.node.firstChild, view); // get number (e.g. 123) - // console.log('slider value', value); - let { from, to } = node.node.firstChild; - let min = 0; - let max = 10; - return Decoration.widget({ + +// matches something like slider(123) and returns slider widget +let matchSliderFunction = (node, view) => { + if (node.name === 'CallExpression' /* && node.node.firstChild.name === 'ArgList' */) { + let name = nodeValue(node.node.firstChild, view); // slider ? + if (name === 'slider') { + const args = node.node.lastChild.getChildren('Number'); + if (!args.length) { + return; + } + const [value, min = 0, max = 1] = args.map((node) => nodeValue(node, view)); + //console.log('slider value', value, min, max); + let { from, to } = args[0]; + let widget = Decoration.widget({ widget: new SliderWidget(Number(value), min, max, from, to), side: 0, }); + //widget._range = widget.range(from); + widget._range = widget.range(node.from); + return widget; } + // node is sth like 123.xxx } }; @@ -83,14 +85,11 @@ export function sliders(view) { from, to, enter: (node) => { - let numberSlider = matchNumberSlider(node, view); - if (numberSlider) { - widgets.push(numberSlider.range(node.from)); + let widget = matchSliderFunction(node, view); + // let widget = matchNumber(node, view); + if (widget) { + widgets.push(widget._range || widget.range(node.from)); } - /* let number = matchNumber(node, view); - if (number) { - widgets.push(number.range(node.from)); - } */ }, }); } @@ -150,11 +149,9 @@ function updateSliderValue(view, e) { if (before === next) { return false; } - //console.log('before', before, '->', insert); let change = { from: draggedSlider.from, to: draggedSlider.to, insert }; draggedSlider.to = draggedSlider.from + insert.length; - //console.log('change', change); view.dispatch({ changes: change }); - + window.postMessage({ type: 'slider-change', value: next }); return true; } diff --git a/website/tailwind.config.cjs b/website/tailwind.config.cjs index d92d5949..2c682d7d 100644 --- a/website/tailwind.config.cjs +++ b/website/tailwind.config.cjs @@ -7,6 +7,7 @@ module.exports = { content: [ './src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}', '../packages/react/src/**/*.{html,js,jsx,md,mdx,ts,tsx}', + '../packages/codemirror/slider.mjs', ], theme: { extend: { From 2731e70fb7c41b654d01cb2cd21a65afcfcbf758 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 30 Sep 2023 21:03:28 +0200 Subject: [PATCH 106/175] use loc as slider id --- packages/codemirror/slider.mjs | 2 +- packages/transpiler/transpiler.mjs | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 63015051..2e75959b 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -152,6 +152,6 @@ function updateSliderValue(view, e) { let change = { from: draggedSlider.from, to: draggedSlider.to, insert }; draggedSlider.to = draggedSlider.from + insert.length; view.dispatch({ changes: change }); - window.postMessage({ type: 'slider-change', value: next }); + window.postMessage({ type: 'cm-slider', value: next, loc: draggedSlider.from }); return true; } diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 78aae9f7..9ff558cb 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -35,6 +35,10 @@ export function transpiler(input, options = {}) { emitMiniLocations && collectMiniLocations(value, node); return this.replace(miniWithLocation(value, node)); } + if (isWidgetFunction(node)) { + // collectSliderLocations? + return this.replace(widgetWithLocation(node)); + } // TODO: remove pseudo note variables? if (node.type === 'Identifier' && isNoteWithOctave(node.name)) { this.skip(); @@ -68,11 +72,10 @@ export function transpiler(input, options = {}) { } function isStringWithDoubleQuotes(node, locations, code) { - const { raw, type } = node; - if (type !== 'Literal') { + if (node.type !== 'Literal') { return false; } - return raw[0] === '"'; + return node.raw[0] === '"'; } function isBackTickString(node, parent) { @@ -94,3 +97,19 @@ function miniWithLocation(value, node) { optional: false, }; } + +function isWidgetFunction(node) { + return node.type === 'CallExpression' && node.callee.name === 'slider'; +} + +function widgetWithLocation(node) { + const loc = node.arguments[0].start; + // add loc as identifier to first argument + // the slider function is assumed to be slider(loc, value, min?, max?) + node.arguments.unshift({ + type: 'Literal', + value: loc, + raw: loc + '', + }); + return node; +} From b36cee93f7e86b003e65b438caee14bdd24b976c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 30 Sep 2023 21:22:49 +0200 Subject: [PATCH 107/175] add slider function to scope --- packages/codemirror/index.mjs | 1 + packages/codemirror/slider.mjs | 25 +++++++++++++++++++++++-- packages/transpiler/transpiler.mjs | 10 ++++++---- website/src/repl/Repl.jsx | 1 + 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/packages/codemirror/index.mjs b/packages/codemirror/index.mjs index bf7ce971..c847c32c 100644 --- a/packages/codemirror/index.mjs +++ b/packages/codemirror/index.mjs @@ -1,3 +1,4 @@ export * from './codemirror.mjs'; export * from './highlight.mjs'; export * from './flash.mjs'; +export * from './slider.mjs'; diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 2e75959b..7695cee6 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -13,7 +13,12 @@ export class SliderWidget extends WidgetType { } eq(other) { - const isSame = other.value.toFixed(4) == this.value.toFixed(4) && other.min == this.min && other.max == this.max; + const isSame = + other.value.toFixed(4) == this.value.toFixed(4) && + other.min == this.min && + other.max == this.max && + other.from === this.from && + other.to === this.to; return isSame; } @@ -152,6 +157,22 @@ function updateSliderValue(view, e) { let change = { from: draggedSlider.from, to: draggedSlider.to, insert }; draggedSlider.to = draggedSlider.from + insert.length; view.dispatch({ changes: change }); - window.postMessage({ type: 'cm-slider', value: next, loc: draggedSlider.from }); + const id = 'slider_' + draggedSlider.from; // matches id generated in transpiler + window.postMessage({ type: 'cm-slider', value: next, id }); return true; } + +export let sliderValues = {}; + +export let slider = (id, value, min, max) => { + sliderValues[id] = value; // sync state at eval time (code -> state) + return ref(() => sliderValues[id]); // use state at query time +}; +if (typeof window !== 'undefined') { + window.addEventListener('message', (e) => { + if (e.data.type === 'cm-slider') { + // update state when slider is moved + sliderValues[e.data.id] = e.data.value; + } + }); +} diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 9ff558cb..28f7fdfa 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -98,18 +98,20 @@ function miniWithLocation(value, node) { }; } +// these functions are connected to @strudel/codemirror -> slider.mjs +// maybe someday there will be pluggable transpiler functions, then move this there function isWidgetFunction(node) { return node.type === 'CallExpression' && node.callee.name === 'slider'; } function widgetWithLocation(node) { - const loc = node.arguments[0].start; + const id = 'slider_' + node.arguments[0].start; // use loc of first arg for id // add loc as identifier to first argument - // the slider function is assumed to be slider(loc, value, min?, max?) + // the slider function is assumed to be slider(id, value, min?, max?) node.arguments.unshift({ type: 'Literal', - value: loc, - raw: loc + '', + value: id, + raw: id, }); return node; } diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 4002eba8..9d80cc53 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -39,6 +39,7 @@ let modules = [ import('@strudel.cycles/mini'), import('@strudel.cycles/xen'), import('@strudel.cycles/webaudio'), + import('@strudel/codemirror'), import('@strudel.cycles/serial'), import('@strudel.cycles/soundfonts'), From 0ad0046a769db952c8e68f097a730374e2b94a1e Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sat, 30 Sep 2023 22:04:22 +0200 Subject: [PATCH 108/175] Replacing old reverb by better convolution --- packages/superdough/reverb.mjs | 34 ++--- packages/superdough/reverbGen.mjs | 209 +++++++++++++++++++++++++++++ packages/superdough/superdough.mjs | 9 +- 3 files changed, 236 insertions(+), 16 deletions(-) create mode 100644 packages/superdough/reverbGen.mjs diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index e6d31f6a..4d5f655f 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -1,23 +1,27 @@ -if (typeof AudioContext !== 'undefined') { - AudioContext.prototype.impulseResponse = function (duration, channels = 1) { - const length = this.sampleRate * duration; - const impulse = this.createBuffer(channels, length, this.sampleRate); - const IR = impulse.getChannelData(0); - for (let i = 0; i < length; i++) IR[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, duration); - return impulse; - }; +import reverbGen from './reverbGen.mjs'; - AudioContext.prototype.createReverb = function (duration) { +if (typeof AudioContext !== 'undefined') { + AudioContext.prototype.generateReverb = reverbGen.generateReverb; + AudioContext.prototype.createReverb = function(duration, audioContext) { const convolver = this.createConvolver(); convolver.setDuration = (d) => { - convolver.buffer = this.impulseResponse(d); - convolver.duration = duration; - return convolver; + this.generateReverb( + { + audioContext, + sampleRate: 44100, + numChannels: 2, + decayTime: d, + fadeInTime: d, + lpFreqStart: 2000, + lpFreqEnd: 15000, + }, + (buffer) => { + convolver.buffer = buffer; + } + ); + convolver.duration = d; }; convolver.setDuration(duration); return convolver; }; } - -// TODO: make the reverb more exciting -// check out https://blog.gskinner.com/archives/2019/02/reverb-web-audio-api.html diff --git a/packages/superdough/reverbGen.mjs b/packages/superdough/reverbGen.mjs new file mode 100644 index 00000000..1d05ee82 --- /dev/null +++ b/packages/superdough/reverbGen.mjs @@ -0,0 +1,209 @@ +// Copyright 2014 Alan deLespinasse +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +"use strict"; + + +var reverbGen = {}; + +/** Generates a reverb impulse response. + + @param {!Object} params TODO: Document the properties. + @param {!function(!AudioBuffer)} callback Function to call when + the impulse response has been generated. The impulse response + is passed to this function as its parameter. May be called + immediately within the current execution context, or later. */ +reverbGen.generateReverb = function(params, callback) { + var audioContext = params.audioContext || new AudioContext(); + var sampleRate = params.sampleRate || 44100; + var numChannels = params.numChannels || 2; + // params.decayTime is the -60dB fade time. We let it go 50% longer to get to -90dB. + var totalTime = params.decayTime * 1.5; + var decaySampleFrames = Math.round(params.decayTime * sampleRate); + var numSampleFrames = Math.round(totalTime * sampleRate); + var fadeInSampleFrames = Math.round((params.fadeInTime || 0) * sampleRate); + // 60dB is a factor of 1 million in power, or 1000 in amplitude. + var decayBase = Math.pow(1 / 1000, 1 / decaySampleFrames); + var reverbIR = audioContext.createBuffer(numChannels, numSampleFrames, sampleRate); + for (var i = 0; i < numChannels; i++) { + var chan = reverbIR.getChannelData(i); + for (var j = 0; j < numSampleFrames; j++) { + chan[j] = randomSample() * Math.pow(decayBase, j); + } + for (var j = 0; j < fadeInSampleFrames; j++) { + chan[j] *= (j / fadeInSampleFrames); + } + } + + applyGradualLowpass(reverbIR, params.lpFreqStart || 0, params.lpFreqEnd || 0, params.decayTime, callback); +}; + +/** Creates a canvas element showing a graph of the given data. + + @param {!Float32Array} data An array of numbers, or a Float32Array. + @param {number} width Width in pixels of the canvas. + @param {number} height Height in pixels of the canvas. + @param {number} min Minimum value of data for the graph (lower edge). + @param {number} max Maximum value of data in the graph (upper edge). + @return {!CanvasElement} The generated canvas element. */ +reverbGen.generateGraph = function(data, width, height, min, max) { + var canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + var gc = canvas.getContext('2d'); + gc.fillStyle = '#000'; + gc.fillRect(0, 0, canvas.width, canvas.height); + gc.fillStyle = '#fff'; + var xscale = width / data.length; + var yscale = height / (max - min); + for (var i = 0; i < data.length; i++) { + gc.fillRect(i * xscale, height - (data[i] - min) * yscale, 1, 1); + } + return canvas; +} + +/** Saves an AudioBuffer as a 16-bit WAV file on the client's host + file system. Normalizes it to peak at +-32767, and optionally + truncates it if there's a lot of "silence" at the end. + + @param {!AudioBuffer} buffer The buffer to save. + @param {string} name Name of file to create. + @param {number?} opt_minTail Defines what counts as "silence" for + auto-truncating the buffer. If there is a point past which every + value of every channel is less than opt_minTail, then the buffer + is truncated at that point. This is expressed as an integer, + applying to the post-normalized and integer-converted + buffer. The default is 0, meaning don't truncate. */ +reverbGen.saveWavFile = function(buffer, name, opt_minTail) { + var bitsPerSample = 16; + var bytesPerSample = 2; + var sampleRate = buffer.sampleRate; + var numChannels = buffer.numberOfChannels; + var channels = getAllChannelData(buffer); + var numSampleFrames = channels[0].length; + var scale = 32767; + // Find normalization constant. + var max = 0; + for (var i = 0; i < numChannels; i++) { + for (var j = 0; j < numSampleFrames; j++) { + max = Math.max(max, Math.abs(channels[i][j])); + } + } + if (max) { + scale = 32767 / max; + } + // Find truncation point. + if (opt_minTail) { + var truncateAt = 0; + for (var i = 0; i < numChannels; i++) { + for (var j = 0; j < numSampleFrames; j++) { + var absSample = Math.abs(Math.round(scale * channels[i][j])); + if (absSample > opt_minTail) { + truncateAt = j; + } + } + } + numSampleFrames = truncateAt + 1; + } + var sampleDataBytes = bytesPerSample * numChannels * numSampleFrames; + var fileBytes = sampleDataBytes + 44; + var arrayBuffer = new ArrayBuffer(fileBytes); + var dataView = new DataView(arrayBuffer); + dataView.setUint32(0, 1179011410, true); // "RIFF" + dataView.setUint32(4, fileBytes - 8, true); // file length + dataView.setUint32(8, 1163280727, true); // "WAVE" + dataView.setUint32(12, 544501094, true); // "fmt " + dataView.setUint32(16, 16, true) // fmt chunk length + dataView.setUint16(20, 1, true); // PCM format + dataView.setUint16(22, numChannels, true); // NumChannels + dataView.setUint32(24, sampleRate, true); // SampleRate + var bytesPerSampleFrame = numChannels * bytesPerSample; + dataView.setUint32(28, sampleRate * bytesPerSampleFrame, true); // ByteRate + dataView.setUint16(32, bytesPerSampleFrame, true); // BlockAlign + dataView.setUint16(34, bitsPerSample, true); // BitsPerSample + dataView.setUint32(36, 1635017060, true); // "data" + dataView.setUint32(40, sampleDataBytes, true); + for (var j = 0; j < numSampleFrames; j++) { + for (var i = 0; i < numChannels; i++) { + dataView.setInt16(44 + j * bytesPerSampleFrame + i * bytesPerSample, + Math.round(scale * channels[i][j]), true); + } + } + var blob = new Blob([arrayBuffer], { 'type': 'audio/wav' }); + var url = window.URL.createObjectURL(blob); + var linkEl = document.createElement('a'); + linkEl.href = url; + linkEl.download = name; + linkEl.style.display = 'none'; + document.body.appendChild(linkEl); + linkEl.click(); +}; + +/** Applies a constantly changing lowpass filter to the given sound. + + @private + @param {!AudioBuffer} input + @param {number} lpFreqStart + @param {number} lpFreqEnd + @param {number} lpFreqEndAt + @param {!function(!AudioBuffer)} callback May be called + immediately within the current execution context, or later.*/ +var applyGradualLowpass = function(input, lpFreqStart, lpFreqEnd, lpFreqEndAt, callback) { + if (lpFreqStart == 0) { + callback(input); + return; + } + var channelData = getAllChannelData(input); + var context = new OfflineAudioContext(input.numberOfChannels, channelData[0].length, input.sampleRate); + var player = context.createBufferSource(); + player.buffer = input; + var filter = context.createBiquadFilter(); + + lpFreqStart = Math.min(lpFreqStart, input.sampleRate / 2); + lpFreqEnd = Math.min(lpFreqEnd, input.sampleRate / 2); + + filter.type = "lowpass"; + filter.Q.value = 0.0001; + filter.frequency.setValueAtTime(lpFreqStart, 0); + filter.frequency.linearRampToValueAtTime(lpFreqEnd, lpFreqEndAt); + + player.connect(filter); + filter.connect(context.destination); + player.start(); + context.oncomplete = function(event) { + callback(event.renderedBuffer); + }; + context.startRendering(); + + window.filterNode = filter; +}; + +/** @private + @param {!AudioBuffer} buffer + @return {!Array.} An array containing the Float32Array of each channel's samples. */ +var getAllChannelData = function(buffer) { + var channels = []; + for (var i = 0; i < buffer.numberOfChannels; i++) { + channels[i] = buffer.getChannelData(i); + } + return channels; +}; + +/** @private + @return {number} A random number from -1 to 1. */ +var randomSample = function() { + return Math.random() * 2 - 1; +}; + +export default reverbGen; diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 289e8d97..9010c85d 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -107,17 +107,24 @@ function getDelay(orbit, delaytime, delayfeedback, t) { } let reverbs = {}; + function getReverb(orbit, duration = 2) { + + // If no reverb has been created for a given orbit, create one if (!reverbs[orbit]) { const ac = getAudioContext(); - const reverb = ac.createReverb(duration); + const reverb = ac.createReverb(duration, getAudioContext()); reverb.connect(getDestination()); + console.log(reverb) reverbs[orbit] = reverb; } + + // Update the reverb duration if needed after instanciation if (reverbs[orbit].duration !== duration) { reverbs[orbit] = reverbs[orbit].setDuration(duration); reverbs[orbit].duration = duration; } + return reverbs[orbit]; } From 062d92690036394418717821499ebc71225e1114 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 00:24:31 +0200 Subject: [PATCH 109/175] make sliders work! --- packages/codemirror/slider.mjs | 149 +++++++++++------------- packages/react/src/hooks/useWidgets.mjs | 13 +++ packages/transpiler/transpiler.mjs | 14 ++- website/src/repl/Repl.jsx | 6 +- 4 files changed, 95 insertions(+), 87 deletions(-) create mode 100644 packages/react/src/hooks/useWidgets.mjs diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 7695cee6..6510f511 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -1,6 +1,8 @@ -import { WidgetType } from '@codemirror/view'; -import { ViewPlugin, Decoration } from '@codemirror/view'; -import { syntaxTree } from '@codemirror/language'; +import { WidgetType, ViewPlugin, Decoration } from '@codemirror/view'; +import { StateEffect, StateField } from '@codemirror/state'; + +export let sliderValues = {}; +const getSliderID = (from) => `slider_${from}`; export class SliderWidget extends WidgetType { constructor(value, min, max, from, to) { @@ -9,17 +11,12 @@ export class SliderWidget extends WidgetType { this.min = min; this.max = max; this.from = from; + this.originalFrom = from; this.to = to; } - eq(other) { - const isSame = - other.value.toFixed(4) == this.value.toFixed(4) && - other.min == this.min && - other.max == this.max && - other.from === this.from && - other.to === this.to; - return isSame; + eq() { + return false; } toDOM() { @@ -31,10 +28,15 @@ export class SliderWidget extends WidgetType { slider.min = this.min; slider.max = this.max; slider.step = (this.max - this.min) / 1000; - slider.value = this.value; + slider.originalValue = this.value.toFixed(2); + // to make sure the code stays in sync, let's save the original value + // becuase .value automatically clamps values so it'll desync with the code + slider.value = slider.originalValue; slider.from = this.from; + slider.originalFrom = this.originalFrom; slider.to = this.to; - slider.className = 'w-16 translate-y-1.5'; + slider.className = 'w-16 translate-y-1.5 mx-2'; + this.slider = slider; return wrap; } @@ -43,78 +45,50 @@ export class SliderWidget extends WidgetType { } } -let nodeValue = (node, view) => view.state.doc.sliceString(node.from, node.to); +export const setWidgets = StateEffect.define(); -// matches a number and returns slider widget -/* let matchNumber = (node, view) => { - if (node.name == 'Number') { - const value = view.state.doc.sliceString(node.from, node.to); - let min = 0; - let max = 10; - return Decoration.widget({ - widget: new SliderWidget(Number(value), min, max, node.from, node.to), - side: 0, - }); - } -}; */ - -// matches something like slider(123) and returns slider widget -let matchSliderFunction = (node, view) => { - if (node.name === 'CallExpression' /* && node.node.firstChild.name === 'ArgList' */) { - let name = nodeValue(node.node.firstChild, view); // slider ? - if (name === 'slider') { - const args = node.node.lastChild.getChildren('Number'); - if (!args.length) { - return; - } - const [value, min = 0, max = 1] = args.map((node) => nodeValue(node, view)); - //console.log('slider value', value, min, max); - let { from, to } = args[0]; - let widget = Decoration.widget({ - widget: new SliderWidget(Number(value), min, max, from, to), - side: 0, - }); - //widget._range = widget.range(from); - widget._range = widget.range(node.from); - return widget; - } - // node is sth like 123.xxx - } +export const updateWidgets = (view, widgets) => { + view.dispatch({ effects: setWidgets.of(widgets) }); }; -// EditorView -export function sliders(view) { - let widgets = []; - for (let { from, to } of view.visibleRanges) { - syntaxTree(view.state).iterate({ - from, - to, - enter: (node) => { - let widget = matchSliderFunction(node, view); - // let widget = matchNumber(node, view); - if (widget) { - widgets.push(widget._range || widget.range(node.from)); - } - }, - }); - } - return Decoration.set(widgets); +let draggedSlider; + +function getWidgets(widgetConfigs) { + return widgetConfigs.map(({ from, to, value, min, max }) => { + return Decoration.widget({ + widget: new SliderWidget(Number(value), min, max, from, to), + side: 0, + }).range(from /* , to */); + }); } -let draggedSlider, init; export const sliderPlugin = ViewPlugin.fromClass( class { decorations; //: DecorationSet constructor(view /* : EditorView */) { - this.decorations = sliders(view); + this.decorations = Decoration.set([]); } update(update /* : ViewUpdate */) { - if (update.docChanged || update.viewportChanged) { - !init && (this.decorations = sliders(update.view)); - //init = true; - } + update.transactions.forEach((tr) => { + if (tr.docChanged) { + this.decorations = this.decorations.map(tr.changes); + const iterator = this.decorations.iter(); + while (iterator.value) { + // when the widgets are moved, we need to tell the dom node the current position + // this is important because the updateSliderValue function has to work with the dom node + iterator.value.widget.slider.from = iterator.from; + iterator.value.widget.slider.to = iterator.to; + iterator.next(); + } + } + for (let e of tr.effects) { + if (e.is(setWidgets)) { + this.decorations = Decoration.set(getWidgets(e.value)); + } + } + }); } }, { @@ -124,6 +98,8 @@ export const sliderPlugin = ViewPlugin.fromClass( mousedown: (e, view) => { let target = e.target; /* as HTMLElement */ if (target.nodeName == 'INPUT' && target.parentElement.classList.contains('cm-slider')) { + e.preventDefault(); + e.stopPropagation(); draggedSlider = target; // remember offsetLeft / clientWidth, as they will vanish inside mousemove events for some reason draggedSlider._offsetLeft = draggedSlider.offsetLeft; @@ -141,6 +117,7 @@ export const sliderPlugin = ViewPlugin.fromClass( }, ); +// moves slider on mouse event function updateSliderValue(view, e) { const mouseX = e.clientX; let progress = (mouseX - draggedSlider._offsetLeft) / draggedSlider._clientWidth; @@ -149,30 +126,38 @@ function updateSliderValue(view, e) { let max = Number(draggedSlider.max); const next = Number(progress * (max - min) + min); let insert = next.toFixed(2); - let before = view.state.doc.sliceString(draggedSlider.from, draggedSlider.to).trim(); - before = Number(before).toFixed(4); - if (before === next) { + //let before = view.state.doc.sliceString(draggedSlider.from, draggedSlider.to).trim(); + let before = draggedSlider.originalValue; + before = Number(before).toFixed(2); + // console.log('before', before, 'insert', insert, 'v'); + if (before === insert) { return false; } - let change = { from: draggedSlider.from, to: draggedSlider.to, insert }; - draggedSlider.to = draggedSlider.from + insert.length; + const to = draggedSlider.from + before.length; + let change = { from: draggedSlider.from, to, insert }; + draggedSlider.originalValue = insert; + draggedSlider.value = insert; view.dispatch({ changes: change }); - const id = 'slider_' + draggedSlider.from; // matches id generated in transpiler + const id = getSliderID(draggedSlider.originalFrom); // matches id generated in transpiler window.postMessage({ type: 'cm-slider', value: next, id }); return true; } -export let sliderValues = {}; - +// user api export let slider = (id, value, min, max) => { sliderValues[id] = value; // sync state at eval time (code -> state) return ref(() => sliderValues[id]); // use state at query time }; +// update state when sliders are moved if (typeof window !== 'undefined') { window.addEventListener('message', (e) => { if (e.data.type === 'cm-slider') { - // update state when slider is moved - sliderValues[e.data.id] = e.data.value; + if (sliderValues[e.data.id] !== undefined) { + // update state when slider is moved + sliderValues[e.data.id] = e.data.value; + } else { + console.warn(`slider with id "${e.data.id}" is not registered. Only ${Object.keys(sliderValues)}`); + } } }); } diff --git a/packages/react/src/hooks/useWidgets.mjs b/packages/react/src/hooks/useWidgets.mjs new file mode 100644 index 00000000..e7ca136a --- /dev/null +++ b/packages/react/src/hooks/useWidgets.mjs @@ -0,0 +1,13 @@ +import { useEffect, useState } from 'react'; +import { updateWidgets } from '@strudel/codemirror'; + +// i know this is ugly.. in the future, repl needs to run without react +export function useWidgets(view) { + const [widgets, setWidgets] = useState([]); + useEffect(() => { + if (view) { + updateWidgets(view, widgets); + } + }, [view, widgets]); + return { widgets, setWidgets }; +} diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 28f7fdfa..48b223d4 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -5,7 +5,7 @@ import { isNoteWithOctave } from '@strudel.cycles/core'; import { getLeafLocations } from '@strudel.cycles/mini'; export function transpiler(input, options = {}) { - const { wrapAsync = false, addReturn = true, emitMiniLocations = true } = options; + const { wrapAsync = false, addReturn = true, emitMiniLocations = true, emitWidgets = true } = options; let ast = parse(input, { ecmaVersion: 2022, @@ -16,9 +16,9 @@ export function transpiler(input, options = {}) { let miniLocations = []; const collectMiniLocations = (value, node) => { const leafLocs = getLeafLocations(`"${value}"`, node.start); // stimmt! - //const withOffset = leafLocs.map((offsets) => offsets.map((o) => o + node.start)); miniLocations = miniLocations.concat(leafLocs); }; + let widgets = []; walk(ast, { enter(node, parent /* , prop, index */) { @@ -37,6 +37,14 @@ export function transpiler(input, options = {}) { } if (isWidgetFunction(node)) { // collectSliderLocations? + emitWidgets && + widgets.push({ + from: node.arguments[0].start, + to: node.arguments[0].end, + value: node.arguments[0].value, + min: node.arguments[1]?.value ?? 0, + max: node.arguments[2]?.value ?? 1, + }); return this.replace(widgetWithLocation(node)); } // TODO: remove pseudo note variables? @@ -68,7 +76,7 @@ export function transpiler(input, options = {}) { if (!emitMiniLocations) { return { output }; } - return { output, miniLocations }; + return { output, miniLocations, widgets }; } function isStringWithDoubleQuotes(node, locations, code) { diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 9d80cc53..8fe43c6d 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -22,6 +22,7 @@ import Loader from './Loader'; import { settingPatterns } from '../settings.mjs'; import { code2hash, hash2code } from './helpers.mjs'; import { isTauri } from '../tauri.mjs'; +import { useWidgets } from '@strudel.cycles/react/src/hooks/useWidgets.mjs'; const { latestCode } = settingsMap.get(); @@ -129,7 +130,7 @@ export function Repl({ embedded = false }) { } = useSettings(); const paintOptions = useMemo(() => ({ fontFamily }), [fontFamily]); - + const { setWidgets } = useWidgets(view); const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } = useStrudel({ initialCode: '// LOADING...', @@ -143,6 +144,7 @@ export function Repl({ embedded = false }) { }, afterEval: ({ code, meta }) => { setMiniLocations(meta.miniLocations); + setWidgets(meta.widgets); setPending(false); setLatestCode(code); window.location.hash = '#' + code2hash(code); @@ -220,7 +222,7 @@ export function Repl({ embedded = false }) { const handleChangeCode = useCallback( (c) => { setCode(c); - started && logger('[edit] code changed. hit ctrl+enter to update'); + //started && logger('[edit] code changed. hit ctrl+enter to update'); }, [started], ); From 33c40e5ef84af31a1f395d1cf30416c9602aa9e8 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 00:33:10 +0200 Subject: [PATCH 110/175] fix some odd number / string problems --- packages/codemirror/slider.mjs | 6 +++--- packages/transpiler/transpiler.mjs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 6510f511..5c2dcdab 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -28,7 +28,7 @@ export class SliderWidget extends WidgetType { slider.min = this.min; slider.max = this.max; slider.step = (this.max - this.min) / 1000; - slider.originalValue = this.value.toFixed(2); + slider.originalValue = this.value; // to make sure the code stays in sync, let's save the original value // becuase .value automatically clamps values so it'll desync with the code slider.value = slider.originalValue; @@ -56,7 +56,7 @@ let draggedSlider; function getWidgets(widgetConfigs) { return widgetConfigs.map(({ from, to, value, min, max }) => { return Decoration.widget({ - widget: new SliderWidget(Number(value), min, max, from, to), + widget: new SliderWidget(value, min, max, from, to), side: 0, }).range(from /* , to */); }); @@ -133,7 +133,7 @@ function updateSliderValue(view, e) { if (before === insert) { return false; } - const to = draggedSlider.from + before.length; + const to = draggedSlider.from + draggedSlider.originalValue.length; let change = { from: draggedSlider.from, to, insert }; draggedSlider.originalValue = insert; draggedSlider.value = insert; diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 48b223d4..5fa9dc49 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -41,7 +41,7 @@ export function transpiler(input, options = {}) { widgets.push({ from: node.arguments[0].start, to: node.arguments[0].end, - value: node.arguments[0].value, + value: node.arguments[0].raw, // don't use value! min: node.arguments[1]?.value ?? 0, max: node.arguments[2]?.value ?? 1, }); From d7bc309eeb06bbe5f2f0e8aa12f9c9af2015452f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 00:36:34 +0200 Subject: [PATCH 111/175] fix: import --- packages/codemirror/slider.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 5c2dcdab..44875e25 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -1,3 +1,4 @@ +import { ref } from '@strudel.cycles/core'; import { WidgetType, ViewPlugin, Decoration } from '@codemirror/view'; import { StateEffect, StateField } from '@codemirror/state'; From fd18508266086e756220dc4c2657455910930502 Mon Sep 17 00:00:00 2001 From: Vasilii Milovidov Date: Sun, 1 Oct 2023 05:15:47 +0400 Subject: [PATCH 112/175] wip: use sample as an impulse response for the reverb --- packages/core/controls.mjs | 2375 ++++++++++++++-------------- packages/superdough/reverb.mjs | 18 +- packages/superdough/superdough.mjs | 31 +- 3 files changed, 1232 insertions(+), 1192 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 6cac6e54..76a278a5 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -4,1220 +4,1231 @@ Copyright (C) 2022 Strudel contributors - see . */ -import { Pattern, register, sequence } from './pattern.mjs'; -import { zipWith } from './util.mjs'; +import {Pattern, register, sequence} from './pattern.mjs'; +import {zipWith} from './util.mjs'; const controls = {}; const generic_params = [ - /** - * Select a sound / sample by name. When using mininotation, you can also optionally supply 'n' and 'gain' parameters - * separated by ':'. - * - * @name s - * @param {string | Pattern} sound The sound / pattern of sounds to pick - * @synonyms sound - * @example - * s("bd hh") - * @example - * s("bd:0 bd:1 bd:0:0.3 bd:1:1.4") - * - */ - [['s', 'n', 'gain'], 'sound'], - /** - * Define a custom webaudio node to use as a sound source. - * - * @name source - * @param {function} getSource - * @synonyms src - * - */ - ['source', 'src'], - /** - * Selects the given index from the sample map. - * Numbers too high will wrap around. - * `n` can also be used to play midi numbers, but it is recommended to use `note` instead. - * - * @name n - * @param {number | Pattern} value sample index starting from 0 - * @example - * s("bd sd,hh*3").n("<0 1>") - */ - // also see https://github.com/tidalcycles/strudel/pull/63 - ['n'], - /** - * Plays the given note name or midi number. A note name consists of - * - * - a letter (a-g or A-G) - * - optional accidentals (b or #) - * - optional octave number (0-9). Defaults to 3 - * - * Examples of valid note names: `c`, `bb`, `Bb`, `f#`, `c3`, `A4`, `Eb2`, `c#5` - * - * You can also use midi numbers instead of note names, where 69 is mapped to A4 440Hz in 12EDO. - * - * @name note - * @example - * note("c a f e") - * @example - * note("c4 a4 f4 e4") - * @example - * note("60 69 65 64") - */ - [['note', 'n']], + /** + * Select a sound / sample by name. When using mininotation, you can also optionally supply 'n' and 'gain' parameters + * separated by ':'. + * + * @name s + * @param {string | Pattern} sound The sound / pattern of sounds to pick + * @synonyms sound + * @example + * s("bd hh") + * @example + * s("bd:0 bd:1 bd:0:0.3 bd:1:1.4") + * + */ + [['s', 'n', 'gain'], 'sound'], + /** + * Define a custom webaudio node to use as a sound source. + * + * @name source + * @param {function} getSource + * @synonyms src + * + */ + ['source', 'src'], + /** + * Selects the given index from the sample map. + * Numbers too high will wrap around. + * `n` can also be used to play midi numbers, but it is recommended to use `note` instead. + * + * @name n + * @param {number | Pattern} value sample index starting from 0 + * @example + * s("bd sd,hh*3").n("<0 1>") + */ + // also see https://github.com/tidalcycles/strudel/pull/63 + ['n'], + /** + * Plays the given note name or midi number. A note name consists of + * + * - a letter (a-g or A-G) + * - optional accidentals (b or #) + * - optional octave number (0-9). Defaults to 3 + * + * Examples of valid note names: `c`, `bb`, `Bb`, `f#`, `c3`, `A4`, `Eb2`, `c#5` + * + * You can also use midi numbers instead of note names, where 69 is mapped to A4 440Hz in 12EDO. + * + * @name note + * @example + * note("c a f e") + * @example + * note("c4 a4 f4 e4") + * @example + * note("60 69 65 64") + */ + [['note', 'n']], - /** - * A pattern of numbers that speed up (or slow down) samples while they play. Currently only supported by osc / superdirt. - * - * @name accelerate - * @param {number | Pattern} amount acceleration. - * @superdirtOnly - * @example - * s("sax").accelerate("<0 1 2 4 8 16>").slow(2).osc() - * - */ - ['accelerate'], - /** - * Controls the gain by an exponential amount. - * - * @name gain - * @param {number | Pattern} amount gain. - * @example - * s("hh*8").gain(".4!2 1 .4!2 1 .4 1") - * - */ - ['gain'], - /** - * Like {@link gain}, but linear. - * - * @name amp - * @param {number | Pattern} amount gain. - * @superdirtOnly - * @example - * s("bd*8").amp(".1*2 .5 .1*2 .5 .1 .5").osc() - * - */ - ['amp'], - /** - * Amplitude envelope attack time: Specifies how long it takes for the sound to reach its peak value, relative to the onset. - * - * @name attack - * @param {number | Pattern} attack time in seconds. - * @synonyms att - * @example - * note("c3 e3").attack("<0 .1 .5>") - * - */ - ['attack', 'att'], + /** + * A pattern of numbers that speed up (or slow down) samples while they play. Currently only supported by osc / superdirt. + * + * @name accelerate + * @param {number | Pattern} amount acceleration. + * @superdirtOnly + * @example + * s("sax").accelerate("<0 1 2 4 8 16>").slow(2).osc() + * + */ + ['accelerate'], + /** + * Controls the gain by an exponential amount. + * + * @name gain + * @param {number | Pattern} amount gain. + * @example + * s("hh*8").gain(".4!2 1 .4!2 1 .4 1") + * + */ + ['gain'], + /** + * Like {@link gain}, but linear. + * + * @name amp + * @param {number | Pattern} amount gain. + * @superdirtOnly + * @example + * s("bd*8").amp(".1*2 .5 .1*2 .5 .1 .5").osc() + * + */ + ['amp'], + /** + * Amplitude envelope attack time: Specifies how long it takes for the sound to reach its peak value, relative to the onset. + * + * @name attack + * @param {number | Pattern} attack time in seconds. + * @synonyms att + * @example + * note("c3 e3").attack("<0 .1 .5>") + * + */ + ['attack', 'att'], - /** - * Sets the Frequency Modulation Harmonicity Ratio. - * Controls the timbre of the sound. - * Whole numbers and simple ratios sound more natural, - * while decimal numbers and complex ratios sound metallic. - * - * @name fmh - * @param {number | Pattern} harmonicity - * @example - * note("c e g b") - * .fm(4) - * .fmh("<1 2 1.5 1.61>") - * .scope() - * - */ - [['fmh', 'fmi'], 'fmh'], - /** - * Sets the Frequency Modulation of the synth. - * Controls the modulation index, which defines the brightness of the sound. - * - * @name fm - * @param {number | Pattern} brightness modulation index - * @synonyms fmi - * @example - * note("c e g b") - * .fm("<0 1 2 8 32>") - * .scope() - * - */ - [['fmi', 'fmh'], 'fm'], - // fm envelope - /** - * Ramp type of fm envelope. Exp might be a bit broken.. - * - * @name fmenv - * @param {number | Pattern} type lin | exp - * @example - * note("c e g b") - * .fm(4) - * .fmdecay(.2) - * .fmsustain(0) - * .fmenv("") - * .scope() - * - */ - ['fmenv'], - /** - * Attack time for the FM envelope: time it takes to reach maximum modulation - * - * @name fmattack - * @param {number | Pattern} time attack time - * @example - * note("c e g b") - * .fm(4) - * .fmattack("<0 .05 .1 .2>") - * .scope() - * - */ - ['fmattack'], - /** - * Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase. - * - * @name fmdecay - * @param {number | Pattern} time decay time - * @example - * note("c e g b") - * .fm(4) - * .fmdecay("<.01 .05 .1 .2>") - * .fmsustain(.4) - * .scope() - * - */ - ['fmdecay'], - /** - * Sustain level for the FM envelope: how much modulation is applied after the decay phase - * - * @name fmsustain - * @param {number | Pattern} level sustain level - * @example - * note("c e g b") - * .fm(4) - * .fmdecay(.1) - * .fmsustain("<1 .75 .5 0>") - * .scope() - * - */ - ['fmsustain'], - // these are not really useful... skipping for now - ['fmrelease'], - ['fmvelocity'], + /** + * Sets the Frequency Modulation Harmonicity Ratio. + * Controls the timbre of the sound. + * Whole numbers and simple ratios sound more natural, + * while decimal numbers and complex ratios sound metallic. + * + * @name fmh + * @param {number | Pattern} harmonicity + * @example + * note("c e g b") + * .fm(4) + * .fmh("<1 2 1.5 1.61>") + * .scope() + * + */ + [['fmh', 'fmi'], 'fmh'], + /** + * Sets the Frequency Modulation of the synth. + * Controls the modulation index, which defines the brightness of the sound. + * + * @name fm + * @param {number | Pattern} brightness modulation index + * @synonyms fmi + * @example + * note("c e g b") + * .fm("<0 1 2 8 32>") + * .scope() + * + */ + [['fmi', 'fmh'], 'fm'], + // fm envelope + /** + * Ramp type of fm envelope. Exp might be a bit broken.. + * + * @name fmenv + * @param {number | Pattern} type lin | exp + * @example + * note("c e g b") + * .fm(4) + * .fmdecay(.2) + * .fmsustain(0) + * .fmenv("") + * .scope() + * + */ + ['fmenv'], + /** + * Attack time for the FM envelope: time it takes to reach maximum modulation + * + * @name fmattack + * @param {number | Pattern} time attack time + * @example + * note("c e g b") + * .fm(4) + * .fmattack("<0 .05 .1 .2>") + * .scope() + * + */ + ['fmattack'], + /** + * Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase. + * + * @name fmdecay + * @param {number | Pattern} time decay time + * @example + * note("c e g b") + * .fm(4) + * .fmdecay("<.01 .05 .1 .2>") + * .fmsustain(.4) + * .scope() + * + */ + ['fmdecay'], + /** + * Sustain level for the FM envelope: how much modulation is applied after the decay phase + * + * @name fmsustain + * @param {number | Pattern} level sustain level + * @example + * note("c e g b") + * .fm(4) + * .fmdecay(.1) + * .fmsustain("<1 .75 .5 0>") + * .scope() + * + */ + ['fmsustain'], + // these are not really useful... skipping for now + ['fmrelease'], + ['fmvelocity'], - /** - * Select the sound bank to use. To be used together with `s`. The bank name (+ "_") will be prepended to the value of `s`. - * - * @name bank - * @param {string | Pattern} bank the name of the bank - * @example - * s("bd sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd") - * - */ - ['bank'], + /** + * Select the sound bank to use. To be used together with `s`. The bank name (+ "_") will be prepended to the value of `s`. + * + * @name bank + * @param {string | Pattern} bank the name of the bank + * @example + * s("bd sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd") + * + */ + ['bank'], - ['analyze'], // analyser node send amount 0 - 1 (used by scope) - ['fft'], // fftSize of analyser + ['analyze'], // analyser node send amount 0 - 1 (used by scope) + ['fft'], // fftSize of analyser - /** - * Amplitude envelope decay time: the time it takes after the attack time to reach the sustain level. - * Note that the decay is only audible if the sustain value is lower than 1. - * - * @name decay - * @param {number | Pattern} time decay time in seconds - * @example - * note("c3 e3").decay("<.1 .2 .3 .4>").sustain(0) - * - */ - ['decay'], - /** - * Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset. - * - * @name sustain - * @param {number | Pattern} gain sustain level between 0 and 1 - * @synonyms sus - * @example - * note("c3 e3").decay(.2).sustain("<0 .1 .4 .6 1>") - * - */ - ['sustain', 'sus'], - /** - * Amplitude envelope release time: The time it takes after the offset to go from sustain level to zero. - * - * @name release - * @param {number | Pattern} time release time in seconds - * @synonyms rel - * @example - * note("c3 e3 g3 c4").release("<0 .1 .4 .6 1>/2") - * - */ - ['release', 'rel'], - ['hold'], - // TODO: in tidal, it seems to be normalized - /** - * Sets the center frequency of the **b**and-**p**ass **f**ilter. When using mininotation, you - * can also optionally supply the 'bpq' parameter separated by ':'. - * - * @name bpf - * @param {number | Pattern} frequency center frequency - * @synonyms bandf, bp - * @example - * s("bd sd,hh*3").bpf("<1000 2000 4000 8000>") - * - */ - [['bandf', 'bandq'], 'bpf', 'bp'], - // TODO: in tidal, it seems to be normalized - /** - * Sets the **b**and-**p**ass **q**-factor (resonance). - * - * @name bpq - * @param {number | Pattern} q q factor - * @synonyms bandq - * @example - * s("bd sd").bpf(500).bpq("<0 1 2 3>") - * - */ - // currently an alias of 'bandq' https://github.com/tidalcycles/strudel/issues/496 - // ['bpq'], - ['bandq', 'bpq'], - /** - * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample. - * - * @memberof Pattern - * @name begin - * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample - * @example - * samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/') - * s("rave").begin("<0 .25 .5 .75>") - * - */ - ['begin'], - /** - * The same as .begin, but cuts off the end off each sample. - * - * @memberof Pattern - * @name end - * @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc.. - * @example - * s("bd*2,oh*4").end("<.1 .2 .5 1>") - * - */ - ['end'], - /** - * Loops the sample. - * Note that the tempo of the loop is not synced with the cycle tempo. - * To change the loop region, use loopBegin / loopEnd. - * - * @name loop - * @param {number | Pattern} on If 1, the sample is looped - * @example - * s("casio").loop(1) - * - */ - ['loop'], - /** - * Begin to loop at a specific point in the sample (inbetween `begin` and `end`). - * Note that the loop point must be inbetween `begin` and `end`, and before `loopEnd`! - * Note: Samples starting with wt_ will automatically loop! (wt = wavetable) - * - * @name loopBegin - * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample - * @synonyms loopb - * @example - * s("space").loop(1) - * .loopBegin("<0 .125 .25>").scope() - */ - ['loopBegin', 'loopb'], - /** - * - * End the looping section at a specific point in the sample (inbetween `begin` and `end`). - * Note that the loop point must be inbetween `begin` and `end`, and after `loopBegin`! - * - * @name loopEnd - * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample - * @synonyms loope - * @example - * s("space").loop(1) - * .loopEnd("<1 .75 .5 .25>").scope() - */ - ['loopEnd', 'loope'], - /** - * bit crusher effect. - * - * @name crush - * @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction). - * @example - * s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>") - * - */ - // TODO: currently duplicated with "native" legato - // TODO: superdirt legato will do more: https://youtu.be/dQPmE1WaD1k?t=419 - /** - * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample. - * - * @name legato - * @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time - * @noAutocomplete - * @example - * "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>") - * - */ - // ['legato'], - // ['clhatdecay'], - ['crush'], - /** - * fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers - * - * @name coarse - * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on. - * @example - * s("bd sd,hh*4").coarse("<1 4 8 16 32>") - * - */ - ['coarse'], - /** - * choose the channel the pattern is sent to in superdirt - * - * @name channel - * @param {number | Pattern} channel channel number - * - */ - ['channel'], - /** - * In the style of classic drum-machines, `cut` will stop a playing sample as soon as another samples with in same cutgroup is to be played. An example would be an open hi-hat followed by a closed one, essentially muting the open. - * - * @name cut - * @param {number | Pattern} group cut group number - * @example - * s("rd*4").cut(1) - * - */ - ['cut'], - /** - * Applies the cutoff frequency of the **l**ow-**p**ass **f**ilter. - * - * When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'. - * - * @name lpf - * @param {number | Pattern} frequency audible between 0 and 20000 - * @synonyms cutoff, ctf, lp - * @example - * s("bd sd,hh*3").lpf("<4000 2000 1000 500 200 100>") - * @example - * s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30") - * - */ - [['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'], + /** + * Amplitude envelope decay time: the time it takes after the attack time to reach the sustain level. + * Note that the decay is only audible if the sustain value is lower than 1. + * + * @name decay + * @param {number | Pattern} time decay time in seconds + * @example + * note("c3 e3").decay("<.1 .2 .3 .4>").sustain(0) + * + */ + ['decay'], + /** + * Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset. + * + * @name sustain + * @param {number | Pattern} gain sustain level between 0 and 1 + * @synonyms sus + * @example + * note("c3 e3").decay(.2).sustain("<0 .1 .4 .6 1>") + * + */ + ['sustain', 'sus'], + /** + * Amplitude envelope release time: The time it takes after the offset to go from sustain level to zero. + * + * @name release + * @param {number | Pattern} time release time in seconds + * @synonyms rel + * @example + * note("c3 e3 g3 c4").release("<0 .1 .4 .6 1>/2") + * + */ + ['release', 'rel'], + ['hold'], + // TODO: in tidal, it seems to be normalized + /** + * Sets the center frequency of the **b**and-**p**ass **f**ilter. When using mininotation, you + * can also optionally supply the 'bpq' parameter separated by ':'. + * + * @name bpf + * @param {number | Pattern} frequency center frequency + * @synonyms bandf, bp + * @example + * s("bd sd,hh*3").bpf("<1000 2000 4000 8000>") + * + */ + [['bandf', 'bandq'], 'bpf', 'bp'], + // TODO: in tidal, it seems to be normalized + /** + * Sets the **b**and-**p**ass **q**-factor (resonance). + * + * @name bpq + * @param {number | Pattern} q q factor + * @synonyms bandq + * @example + * s("bd sd").bpf(500).bpq("<0 1 2 3>") + * + */ + // currently an alias of 'bandq' https://github.com/tidalcycles/strudel/issues/496 + // ['bpq'], + ['bandq', 'bpq'], + /** + * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample. + * + * @memberof Pattern + * @name begin + * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample + * @example + * samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/') + * s("rave").begin("<0 .25 .5 .75>") + * + */ + ['begin'], + /** + * The same as .begin, but cuts off the end off each sample. + * + * @memberof Pattern + * @name end + * @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc.. + * @example + * s("bd*2,oh*4").end("<.1 .2 .5 1>") + * + */ + ['end'], + /** + * Loops the sample. + * Note that the tempo of the loop is not synced with the cycle tempo. + * To change the loop region, use loopBegin / loopEnd. + * + * @name loop + * @param {number | Pattern} on If 1, the sample is looped + * @example + * s("casio").loop(1) + * + */ + ['loop'], + /** + * Begin to loop at a specific point in the sample (inbetween `begin` and `end`). + * Note that the loop point must be inbetween `begin` and `end`, and before `loopEnd`! + * Note: Samples starting with wt_ will automatically loop! (wt = wavetable) + * + * @name loopBegin + * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample + * @synonyms loopb + * @example + * s("space").loop(1) + * .loopBegin("<0 .125 .25>").scope() + */ + ['loopBegin', 'loopb'], + /** + * + * End the looping section at a specific point in the sample (inbetween `begin` and `end`). + * Note that the loop point must be inbetween `begin` and `end`, and after `loopBegin`! + * + * @name loopEnd + * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample + * @synonyms loope + * @example + * s("space").loop(1) + * .loopEnd("<1 .75 .5 .25>").scope() + */ + ['loopEnd', 'loope'], + /** + * bit crusher effect. + * + * @name crush + * @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction). + * @example + * s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>") + * + */ + // TODO: currently duplicated with "native" legato + // TODO: superdirt legato will do more: https://youtu.be/dQPmE1WaD1k?t=419 + /** + * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample. + * + * @name legato + * @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time + * @noAutocomplete + * @example + * "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>") + * + */ + // ['legato'], + // ['clhatdecay'], + ['crush'], + /** + * fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers + * + * @name coarse + * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on. + * @example + * s("bd sd,hh*4").coarse("<1 4 8 16 32>") + * + */ + ['coarse'], + /** + * choose the channel the pattern is sent to in superdirt + * + * @name channel + * @param {number | Pattern} channel channel number + * + */ + ['channel'], + /** + * In the style of classic drum-machines, `cut` will stop a playing sample as soon as another samples with in same cutgroup is to be played. An example would be an open hi-hat followed by a closed one, essentially muting the open. + * + * @name cut + * @param {number | Pattern} group cut group number + * @example + * s("rd*4").cut(1) + * + */ + ['cut'], + /** + * Applies the cutoff frequency of the **l**ow-**p**ass **f**ilter. + * + * When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'. + * + * @name lpf + * @param {number | Pattern} frequency audible between 0 and 20000 + * @synonyms cutoff, ctf, lp + * @example + * s("bd sd,hh*3").lpf("<4000 2000 1000 500 200 100>") + * @example + * s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30") + * + */ + [['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'], - /** - * Sets the lowpass filter envelope modulation depth. - * @name lpenv - * @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_ - * @synonyms lpe - * @example - * note("") - * .sound('sawtooth') - * .lpf(500) - * .lpa(.5) - * .lpenv("<4 2 1 0 -1 -2 -4>/4") - */ - ['lpenv', 'lpe'], - /** - * Sets the highpass filter envelope modulation depth. - * @name hpenv - * @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_ - * @synonyms hpe - * @example - * note("") - * .sound('sawtooth') - * .hpf(500) - * .hpa(.5) - * .hpenv("<4 2 1 0 -1 -2 -4>/4") - */ - ['hpenv', 'hpe'], - /** - * Sets the bandpass filter envelope modulation depth. - * @name bpenv - * @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_ - * @synonyms bpe - * @example - * note("") - * .sound('sawtooth') - * .bpf(500) - * .bpa(.5) - * .bpenv("<4 2 1 0 -1 -2 -4>/4") - */ - ['bpenv', 'bpe'], - /** - * Sets the attack duration for the lowpass filter envelope. - * @name lpattack - * @param {number | Pattern} attack time of the filter envelope - * @synonyms lpa - * @example - * note("") - * .sound('sawtooth') - * .lpf(500) - * .lpa("<.5 .25 .1 .01>/4") - * .lpenv(4) - */ - ['lpattack', 'lpa'], - /** - * Sets the attack duration for the highpass filter envelope. - * @name hpattack - * @param {number | Pattern} attack time of the highpass filter envelope - * @synonyms hpa - * @example - * note("") - * .sound('sawtooth') - * .hpf(500) - * .hpa("<.5 .25 .1 .01>/4") - * .hpenv(4) - */ - ['hpattack', 'hpa'], - /** - * Sets the attack duration for the bandpass filter envelope. - * @name bpattack - * @param {number | Pattern} attack time of the bandpass filter envelope - * @synonyms bpa - * @example - * note("") - * .sound('sawtooth') - * .bpf(500) - * .bpa("<.5 .25 .1 .01>/4") - * .bpenv(4) - */ - ['bpattack', 'bpa'], - /** - * Sets the decay duration for the lowpass filter envelope. - * @name lpdecay - * @param {number | Pattern} decay time of the filter envelope - * @synonyms lpd - * @example - * note("") - * .sound('sawtooth') - * .lpf(500) - * .lpd("<.5 .25 .1 0>/4") - * .lps(0.2) - * .lpenv(4) - */ - ['lpdecay', 'lpd'], - /** - * Sets the decay duration for the highpass filter envelope. - * @name hpdecay - * @param {number | Pattern} decay time of the highpass filter envelope - * @synonyms hpd - * @example - * note("") - * .sound('sawtooth') - * .hpf(500) - * .hpd("<.5 .25 .1 0>/4") - * .hps(0.2) - * .hpenv(4) - */ - ['hpdecay', 'hpd'], - /** - * Sets the decay duration for the bandpass filter envelope. - * @name bpdecay - * @param {number | Pattern} decay time of the bandpass filter envelope - * @synonyms bpd - * @example - * note("") - * .sound('sawtooth') - * .bpf(500) - * .bpd("<.5 .25 .1 0>/4") - * .bps(0.2) - * .bpenv(4) - */ - ['bpdecay', 'bpd'], - /** - * Sets the sustain amplitude for the lowpass filter envelope. - * @name lpsustain - * @param {number | Pattern} sustain amplitude of the lowpass filter envelope - * @synonyms lps - * @example - * note("") - * .sound('sawtooth') - * .lpf(500) - * .lpd(.5) - * .lps("<0 .25 .5 1>/4") - * .lpenv(4) - */ - ['lpsustain', 'lps'], - /** - * Sets the sustain amplitude for the highpass filter envelope. - * @name hpsustain - * @param {number | Pattern} sustain amplitude of the highpass filter envelope - * @synonyms hps - * @example - * note("") - * .sound('sawtooth') - * .hpf(500) - * .hpd(.5) - * .hps("<0 .25 .5 1>/4") - * .hpenv(4) - */ - ['hpsustain', 'hps'], - /** - * Sets the sustain amplitude for the bandpass filter envelope. - * @name bpsustain - * @param {number | Pattern} sustain amplitude of the bandpass filter envelope - * @synonyms bps - * @example - * note("") - * .sound('sawtooth') - * .bpf(500) - * .bpd(.5) - * .bps("<0 .25 .5 1>/4") - * .bpenv(4) - */ - ['bpsustain', 'bps'], - /** - * Sets the release time for the lowpass filter envelope. - * @name lprelease - * @param {number | Pattern} release time of the filter envelope - * @synonyms lpr - * @example - * note("") - * .sound('sawtooth') - * .clip(.5) - * .lpf(500) - * .lpenv(4) - * .lpr("<.5 .25 .1 0>/4") - * .release(.5) - */ - ['lprelease', 'lpr'], - /** - * Sets the release time for the highpass filter envelope. - * @name hprelease - * @param {number | Pattern} release time of the highpass filter envelope - * @synonyms hpr - * @example - * note("") - * .sound('sawtooth') - * .clip(.5) - * .hpf(500) - * .hpenv(4) - * .hpr("<.5 .25 .1 0>/4") - * .release(.5) - */ - ['hprelease', 'hpr'], - /** - * Sets the release time for the bandpass filter envelope. - * @name bprelease - * @param {number | Pattern} release time of the bandpass filter envelope - * @synonyms bpr - * @example - * note("") - * .sound('sawtooth') - * .clip(.5) - * .bpf(500) - * .bpenv(4) - * .bpr("<.5 .25 .1 0>/4") - * .release(.5) - */ - ['bprelease', 'bpr'], - /** - * Sets the filter type. The 24db filter is more aggressive. More types might be added in the future. - * @name ftype - * @param {number | Pattern} type 12db (default) or 24db - * @example - * note("") - * .sound('sawtooth') - * .lpf(500) - * .bpenv(4) - * .ftype("<12db 24db>") - */ - ['ftype'], - ['fanchor'], - /** - * Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter. - * - * When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'. - * - * @name hpf - * @param {number | Pattern} frequency audible between 0 and 20000 - * @synonyms hp, hcutoff - * @example - * s("bd sd,hh*4").hpf("<4000 2000 1000 500 200 100>") - * @example - * s("bd sd,hh*4").hpf("<2000 2000:25>") - * - */ - // currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496 - // ['hpf'], - /** - * Applies a vibrato to the frequency of the oscillator. - * - * @name vib - * @synonyms vibrato, v - * @param {number | Pattern} frequency of the vibrato in hertz - * @example - * note("a") - * .vib("<.5 1 2 4 8 16>") - * @example - * // change the modulation depth with ":" - * note("a") - * .vib("<.5 1 2 4 8 16>:12") - */ - [['vib', 'vibmod'], 'vibrato', 'v'], - /** - * Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set - * - * @name vibmod - * @synonyms vmod - * @param {number | Pattern} depth of vibrato (in semitones) - * @example - * note("a").vib(4) - * .vibmod("<.25 .5 1 2 12>") - * @example - * // change the vibrato frequency with ":" - * note("a") - * .vibmod("<.25 .5 1 2 12>:8") - */ - [['vibmod', 'vib'], 'vmod'], - [['hcutoff', 'hresonance'], 'hpf', 'hp'], - /** - * Controls the **h**igh-**p**ass **q**-value. - * - * @name hpq - * @param {number | Pattern} q resonance factor between 0 and 50 - * @synonyms hresonance - * @example - * s("bd sd,hh*4").hpf(2000).hpq("<0 10 20 30>") - * - */ - ['hresonance', 'hpq'], - /** - * Controls the **l**ow-**p**ass **q**-value. - * - * @name lpq - * @param {number | Pattern} q resonance factor between 0 and 50 - * @synonyms resonance - * @example - * s("bd sd,hh*4").lpf(2000).lpq("<0 10 20 30>") - * - */ - // currently an alias of 'resonance' https://github.com/tidalcycles/strudel/issues/496 - ['resonance', 'lpq'], - /** - * DJ filter, below 0.5 is low pass filter, above is high pass filter. - * - * @name djf - * @param {number | Pattern} cutoff below 0.5 is low pass filter, above is high pass filter - * @example - * n("0 3 7 [10,24]").s('superzow').octave(3).djf("<.5 .25 .5 .75>").osc() - * - */ - ['djf'], - // ['cutoffegint'], - // TODO: does not seem to work - /** - * Sets the level of the delay signal. - * - * When using mininotation, you can also optionally add the 'delaytime' and 'delayfeedback' parameter, - * separated by ':'. - * - * - * @name delay - * @param {number | Pattern} level between 0 and 1 - * @example - * s("bd").delay("<0 .25 .5 1>") - * @example - * s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7") - * - */ - [['delay', 'delaytime', 'delayfeedback']], - /** - * Sets the level of the signal that is fed back into the delay. - * Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it - * - * @name delayfeedback - * @param {number | Pattern} feedback between 0 and 1 - * @synonyms delayfb, dfb - * @example - * s("bd").delay(.25).delayfeedback("<.25 .5 .75 1>").slow(2) - * - */ - ['delayfeedback', 'delayfb', 'dfb'], - /** - * Sets the time of the delay effect. - * - * @name delaytime - * @param {number | Pattern} seconds between 0 and Infinity - * @synonyms delayt, dt - * @example - * s("bd").delay(.25).delaytime("<.125 .25 .5 1>").slow(2) - * - */ - ['delaytime', 'delayt', 'dt'], - /* // 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. - * @example - * s("sd").delay().lock(1).osc() - * - */ - ['lock'], - /** - * Set detune of oscillators. Works only with some synths, see tidal doc - * - * @name detune - * @param {number | Pattern} amount between 0 and 1 - * @synonyms det - * @superdirtOnly - * @example - * n("0 3 7").s('superzow').octave(3).detune("<0 .25 .5 1 2>").osc() - * - */ - ['detune', 'det'], - /** - * Set dryness of reverb. See {@link room} and {@link size} for more information about reverb. - * - * @name dry - * @param {number | Pattern} dry 0 = wet, 1 = dry - * @example - * n("[0,3,7](3,8)").s("superpiano").room(.7).dry("<0 .5 .75 1>").osc() - * @superdirtOnly - * - */ - ['dry'], - // TODO: does not seem to do anything - /* - * Used when using {@link begin}/{@link end} or {@link chop}/{@link striate} and friends, to change the fade out time of the 'grain' envelope. - * - * @name fadeTime - * @param {number | Pattern} time between 0 and 1 - * @example - * s("oh*4").end(.1).fadeTime("<0 .2 .4 .8>").osc() - * - */ - ['fadeTime', 'fadeOutTime'], - // TODO: see above - ['fadeInTime'], - /** - * Set frequency of sound. - * - * @name freq - * @param {number | Pattern} frequency in Hz. the audible range is between 20 and 20000 Hz - * @example - * freq("220 110 440 110").s("superzow").osc() - * @example - * freq("110".mul.out(".5 1.5 .6 [2 3]")).s("superzow").osc() - * - */ - ['freq'], - // TODO: https://tidalcycles.org/docs/configuration/MIDIOSC/control-voltage/#gate - ['gate', 'gat'], - // ['hatgrain'], - // ['lagogo'], - // ['lclap'], - // ['lclaves'], - // ['lclhat'], - // ['lcrash'], - // TODO: - // https://tidalcycles.org/docs/reference/audio_effects/#leslie-1 - // https://tidalcycles.org/docs/reference/audio_effects/#leslie - /** - * Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet. - * - * @name leslie - * @param {number | Pattern} wet between 0 and 1 - * @example - * n("0,4,7").s("supersquare").leslie("<0 .4 .6 1>").osc() - * @superdirtOnly - * - */ - ['leslie'], - /** - * Rate of modulation / rotation for leslie effect - * - * @name lrate - * @param {number | Pattern} rate 6.7 for fast, 0.7 for slow - * @example - * n("0,4,7").s("supersquare").leslie(1).lrate("<1 2 4 8>").osc() - * @superdirtOnly - * - */ - // TODO: the rate seems to "lag" (in the example, 1 will be fast) - ['lrate'], - /** - * Physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble) - * - * @name lsize - * @param {number | Pattern} meters somewhere between 0 and 1 - * @example - * n("0,4,7").s("supersquare").leslie(1).lrate(2).lsize("<.1 .5 1>").osc() - * @superdirtOnly - * - */ - ['lsize'], - // label for pianoroll - ['activeLabel'], - [['label', 'activeLabel']], - // ['lfo'], - // ['lfocutoffint'], - // ['lfodelay'], - // ['lfoint'], - // ['lfopitchint'], - // ['lfoshape'], - // ['lfosync'], - // ['lhitom'], - // ['lkick'], - // ['llotom'], - // ['lophat'], - // ['lsnare'], - ['degree'], // TODO: what is this? not found in tidal doc - ['mtranspose'], // TODO: what is this? not found in tidal doc - ['ctranspose'], // TODO: what is this? not found in tidal doc - ['harmonic'], // TODO: what is this? not found in tidal doc - ['stepsPerOctave'], // TODO: what is this? not found in tidal doc - ['octaveR'], // TODO: what is this? not found in tidal doc - // TODO: why is this needed? what's the difference to late / early? Answer: it's in seconds, and delays the message at - // OSC time (so can't be negative, at least not beyond the latency value) - ['nudge'], - // TODO: the following doc is just a guess, it's not documented in tidal doc. - /** - * Sets the default octave of a synth. - * - * @name octave - * @param {number | Pattern} octave octave number - * @example - * n("0,4,7").s('supersquare').octave("<3 4 5 6>").osc() - * @superDirtOnly - */ - ['octave'], + /** + * Sets the lowpass filter envelope modulation depth. + * @name lpenv + * @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_ + * @synonyms lpe + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpa(.5) + * .lpenv("<4 2 1 0 -1 -2 -4>/4") + */ + ['lpenv', 'lpe'], + /** + * Sets the highpass filter envelope modulation depth. + * @name hpenv + * @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_ + * @synonyms hpe + * @example + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpa(.5) + * .hpenv("<4 2 1 0 -1 -2 -4>/4") + */ + ['hpenv', 'hpe'], + /** + * Sets the bandpass filter envelope modulation depth. + * @name bpenv + * @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_ + * @synonyms bpe + * @example + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpa(.5) + * .bpenv("<4 2 1 0 -1 -2 -4>/4") + */ + ['bpenv', 'bpe'], + /** + * Sets the attack duration for the lowpass filter envelope. + * @name lpattack + * @param {number | Pattern} attack time of the filter envelope + * @synonyms lpa + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpa("<.5 .25 .1 .01>/4") + * .lpenv(4) + */ + ['lpattack', 'lpa'], + /** + * Sets the attack duration for the highpass filter envelope. + * @name hpattack + * @param {number | Pattern} attack time of the highpass filter envelope + * @synonyms hpa + * @example + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpa("<.5 .25 .1 .01>/4") + * .hpenv(4) + */ + ['hpattack', 'hpa'], + /** + * Sets the attack duration for the bandpass filter envelope. + * @name bpattack + * @param {number | Pattern} attack time of the bandpass filter envelope + * @synonyms bpa + * @example + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpa("<.5 .25 .1 .01>/4") + * .bpenv(4) + */ + ['bpattack', 'bpa'], + /** + * Sets the decay duration for the lowpass filter envelope. + * @name lpdecay + * @param {number | Pattern} decay time of the filter envelope + * @synonyms lpd + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpd("<.5 .25 .1 0>/4") + * .lps(0.2) + * .lpenv(4) + */ + ['lpdecay', 'lpd'], + /** + * Sets the decay duration for the highpass filter envelope. + * @name hpdecay + * @param {number | Pattern} decay time of the highpass filter envelope + * @synonyms hpd + * @example + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpd("<.5 .25 .1 0>/4") + * .hps(0.2) + * .hpenv(4) + */ + ['hpdecay', 'hpd'], + /** + * Sets the decay duration for the bandpass filter envelope. + * @name bpdecay + * @param {number | Pattern} decay time of the bandpass filter envelope + * @synonyms bpd + * @example + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpd("<.5 .25 .1 0>/4") + * .bps(0.2) + * .bpenv(4) + */ + ['bpdecay', 'bpd'], + /** + * Sets the sustain amplitude for the lowpass filter envelope. + * @name lpsustain + * @param {number | Pattern} sustain amplitude of the lowpass filter envelope + * @synonyms lps + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpd(.5) + * .lps("<0 .25 .5 1>/4") + * .lpenv(4) + */ + ['lpsustain', 'lps'], + /** + * Sets the sustain amplitude for the highpass filter envelope. + * @name hpsustain + * @param {number | Pattern} sustain amplitude of the highpass filter envelope + * @synonyms hps + * @example + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpd(.5) + * .hps("<0 .25 .5 1>/4") + * .hpenv(4) + */ + ['hpsustain', 'hps'], + /** + * Sets the sustain amplitude for the bandpass filter envelope. + * @name bpsustain + * @param {number | Pattern} sustain amplitude of the bandpass filter envelope + * @synonyms bps + * @example + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpd(.5) + * .bps("<0 .25 .5 1>/4") + * .bpenv(4) + */ + ['bpsustain', 'bps'], + /** + * Sets the release time for the lowpass filter envelope. + * @name lprelease + * @param {number | Pattern} release time of the filter envelope + * @synonyms lpr + * @example + * note("") + * .sound('sawtooth') + * .clip(.5) + * .lpf(500) + * .lpenv(4) + * .lpr("<.5 .25 .1 0>/4") + * .release(.5) + */ + ['lprelease', 'lpr'], + /** + * Sets the release time for the highpass filter envelope. + * @name hprelease + * @param {number | Pattern} release time of the highpass filter envelope + * @synonyms hpr + * @example + * note("") + * .sound('sawtooth') + * .clip(.5) + * .hpf(500) + * .hpenv(4) + * .hpr("<.5 .25 .1 0>/4") + * .release(.5) + */ + ['hprelease', 'hpr'], + /** + * Sets the release time for the bandpass filter envelope. + * @name bprelease + * @param {number | Pattern} release time of the bandpass filter envelope + * @synonyms bpr + * @example + * note("") + * .sound('sawtooth') + * .clip(.5) + * .bpf(500) + * .bpenv(4) + * .bpr("<.5 .25 .1 0>/4") + * .release(.5) + */ + ['bprelease', 'bpr'], + /** + * Sets the filter type. The 24db filter is more aggressive. More types might be added in the future. + * @name ftype + * @param {number | Pattern} type 12db (default) or 24db + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .bpenv(4) + * .ftype("<12db 24db>") + */ + ['ftype'], + ['fanchor'], + /** + * Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter. + * + * When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'. + * + * @name hpf + * @param {number | Pattern} frequency audible between 0 and 20000 + * @synonyms hp, hcutoff + * @example + * s("bd sd,hh*4").hpf("<4000 2000 1000 500 200 100>") + * @example + * s("bd sd,hh*4").hpf("<2000 2000:25>") + * + */ + // currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496 + // ['hpf'], + /** + * Applies a vibrato to the frequency of the oscillator. + * + * @name vib + * @synonyms vibrato, v + * @param {number | Pattern} frequency of the vibrato in hertz + * @example + * note("a") + * .vib("<.5 1 2 4 8 16>") + * @example + * // change the modulation depth with ":" + * note("a") + * .vib("<.5 1 2 4 8 16>:12") + */ + [['vib', 'vibmod'], 'vibrato', 'v'], + /** + * Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set + * + * @name vibmod + * @synonyms vmod + * @param {number | Pattern} depth of vibrato (in semitones) + * @example + * note("a").vib(4) + * .vibmod("<.25 .5 1 2 12>") + * @example + * // change the vibrato frequency with ":" + * note("a") + * .vibmod("<.25 .5 1 2 12>:8") + */ + [['vibmod', 'vib'], 'vmod'], + [['hcutoff', 'hresonance'], 'hpf', 'hp'], + /** + * Controls the **h**igh-**p**ass **q**-value. + * + * @name hpq + * @param {number | Pattern} q resonance factor between 0 and 50 + * @synonyms hresonance + * @example + * s("bd sd,hh*4").hpf(2000).hpq("<0 10 20 30>") + * + */ + ['hresonance', 'hpq'], + /** + * Controls the **l**ow-**p**ass **q**-value. + * + * @name lpq + * @param {number | Pattern} q resonance factor between 0 and 50 + * @synonyms resonance + * @example + * s("bd sd,hh*4").lpf(2000).lpq("<0 10 20 30>") + * + */ + // currently an alias of 'resonance' https://github.com/tidalcycles/strudel/issues/496 + ['resonance', 'lpq'], + /** + * DJ filter, below 0.5 is low pass filter, above is high pass filter. + * + * @name djf + * @param {number | Pattern} cutoff below 0.5 is low pass filter, above is high pass filter + * @example + * n("0 3 7 [10,24]").s('superzow').octave(3).djf("<.5 .25 .5 .75>").osc() + * + */ + ['djf'], + // ['cutoffegint'], + // TODO: does not seem to work + /** + * Sets the level of the delay signal. + * + * When using mininotation, you can also optionally add the 'delaytime' and 'delayfeedback' parameter, + * separated by ':'. + * + * + * @name delay + * @param {number | Pattern} level between 0 and 1 + * @example + * s("bd").delay("<0 .25 .5 1>") + * @example + * s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7") + * + */ + [['delay', 'delaytime', 'delayfeedback']], + /** + * Sets the level of the signal that is fed back into the delay. + * Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it + * + * @name delayfeedback + * @param {number | Pattern} feedback between 0 and 1 + * @synonyms delayfb, dfb + * @example + * s("bd").delay(.25).delayfeedback("<.25 .5 .75 1>").slow(2) + * + */ + ['delayfeedback', 'delayfb', 'dfb'], + /** + * Sets the time of the delay effect. + * + * @name delaytime + * @param {number | Pattern} seconds between 0 and Infinity + * @synonyms delayt, dt + * @example + * s("bd").delay(.25).delaytime("<.125 .25 .5 1>").slow(2) + * + */ + ['delaytime', 'delayt', 'dt'], + /* // 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. + * @example + * s("sd").delay().lock(1).osc() + * + */ + ['lock'], + /** + * Set detune of oscillators. Works only with some synths, see tidal doc + * + * @name detune + * @param {number | Pattern} amount between 0 and 1 + * @synonyms det + * @superdirtOnly + * @example + * n("0 3 7").s('superzow').octave(3).detune("<0 .25 .5 1 2>").osc() + * + */ + ['detune', 'det'], + /** + * Set dryness of reverb. See {@link room} and {@link size} for more information about reverb. + * + * @name dry + * @param {number | Pattern} dry 0 = wet, 1 = dry + * @example + * n("[0,3,7](3,8)").s("superpiano").room(.7).dry("<0 .5 .75 1>").osc() + * @superdirtOnly + * + */ + ['dry'], + // TODO: does not seem to do anything + /* + * Used when using {@link begin}/{@link end} or {@link chop}/{@link striate} and friends, to change the fade out time of the 'grain' envelope. + * + * @name fadeTime + * @param {number | Pattern} time between 0 and 1 + * @example + * s("oh*4").end(.1).fadeTime("<0 .2 .4 .8>").osc() + * + */ + ['fadeTime', 'fadeOutTime'], + // TODO: see above + ['fadeInTime'], + /** + * Set frequency of sound. + * + * @name freq + * @param {number | Pattern} frequency in Hz. the audible range is between 20 and 20000 Hz + * @example + * freq("220 110 440 110").s("superzow").osc() + * @example + * freq("110".mul.out(".5 1.5 .6 [2 3]")).s("superzow").osc() + * + */ + ['freq'], + // TODO: https://tidalcycles.org/docs/configuration/MIDIOSC/control-voltage/#gate + ['gate', 'gat'], + // ['hatgrain'], + // ['lagogo'], + // ['lclap'], + // ['lclaves'], + // ['lclhat'], + // ['lcrash'], + // TODO: + // https://tidalcycles.org/docs/reference/audio_effects/#leslie-1 + // https://tidalcycles.org/docs/reference/audio_effects/#leslie + /** + * Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet. + * + * @name leslie + * @param {number | Pattern} wet between 0 and 1 + * @example + * n("0,4,7").s("supersquare").leslie("<0 .4 .6 1>").osc() + * @superdirtOnly + * + */ + ['leslie'], + /** + * Rate of modulation / rotation for leslie effect + * + * @name lrate + * @param {number | Pattern} rate 6.7 for fast, 0.7 for slow + * @example + * n("0,4,7").s("supersquare").leslie(1).lrate("<1 2 4 8>").osc() + * @superdirtOnly + * + */ + // TODO: the rate seems to "lag" (in the example, 1 will be fast) + ['lrate'], + /** + * Physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble) + * + * @name lsize + * @param {number | Pattern} meters somewhere between 0 and 1 + * @example + * n("0,4,7").s("supersquare").leslie(1).lrate(2).lsize("<.1 .5 1>").osc() + * @superdirtOnly + * + */ + ['lsize'], + // label for pianoroll + ['activeLabel'], + [['label', 'activeLabel']], + // ['lfo'], + // ['lfocutoffint'], + // ['lfodelay'], + // ['lfoint'], + // ['lfopitchint'], + // ['lfoshape'], + // ['lfosync'], + // ['lhitom'], + // ['lkick'], + // ['llotom'], + // ['lophat'], + // ['lsnare'], + ['degree'], // TODO: what is this? not found in tidal doc + ['mtranspose'], // TODO: what is this? not found in tidal doc + ['ctranspose'], // TODO: what is this? not found in tidal doc + ['harmonic'], // TODO: what is this? not found in tidal doc + ['stepsPerOctave'], // TODO: what is this? not found in tidal doc + ['octaveR'], // TODO: what is this? not found in tidal doc + // TODO: why is this needed? what's the difference to late / early? Answer: it's in seconds, and delays the message at + // OSC time (so can't be negative, at least not beyond the latency value) + ['nudge'], + // TODO: the following doc is just a guess, it's not documented in tidal doc. + /** + * Sets the default octave of a synth. + * + * @name octave + * @param {number | Pattern} octave octave number + * @example + * n("0,4,7").s('supersquare').octave("<3 4 5 6>").osc() + * @superDirtOnly + */ + ['octave'], - // ['ophatdecay'], - // TODO: example - /** - * An `orbit` is a global parameter context for patterns. Patterns with the same orbit will share the same global effects. - * - * @name orbit - * @param {number | Pattern} number - * @example - * stack( - * s("hh*3").delay(.5).delaytime(.25).orbit(1), - * s("~ sd").delay(.5).delaytime(.125).orbit(2) - * ) - */ - ['orbit'], - ['overgain'], // TODO: what is this? not found in tidal doc Answer: gain is limited to maximum of 2. This allows you to go over that - ['overshape'], // TODO: what is this? not found in tidal doc. Similar to above, but limited to 1 - /** - * Sets position in stereo. - * - * @name pan - * @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel) - * @example - * s("[bd hh]*2").pan("<.5 1 .5 0>") - * - */ - ['pan'], - // TODO: this has no effect (see example) - /* - * Controls how much multichannel output is fanned out - * - * @name panspan - * @param {number | Pattern} span between -inf and inf, negative is backwards ordering - * @example - * s("[bd hh]*2").pan("<.5 1 .5 0>").panspan("<0 .5 1>").osc() - * - */ - ['panspan'], - // TODO: this has no effect (see example) - /* - * Controls how much multichannel output is spread - * - * @name pansplay - * @param {number | Pattern} spread between 0 and 1 - * @example - * s("[bd hh]*2").pan("<.5 1 .5 0>").pansplay("<0 .5 1>").osc() - * - */ - ['pansplay'], - ['panwidth'], - ['panorient'], - // ['pitch1'], - // ['pitch2'], - // ['pitch3'], - // ['portamento'], - // TODO: LFO rate see https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare - ['rate'], - // TODO: slide param for certain synths - ['slide'], - // TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare - ['semitone'], - // TODO: dedup with synth param, see https://tidalcycles.org/docs/reference/synthesizers/#superpiano - // ['velocity'], - ['voice'], // TODO: synth param + // ['ophatdecay'], + // TODO: example + /** + * An `orbit` is a global parameter context for patterns. Patterns with the same orbit will share the same global effects. + * + * @name orbit + * @param {number | Pattern} number + * @example + * stack( + * s("hh*3").delay(.5).delaytime(.25).orbit(1), + * s("~ sd").delay(.5).delaytime(.125).orbit(2) + * ) + */ + ['orbit'], + ['overgain'], // TODO: what is this? not found in tidal doc Answer: gain is limited to maximum of 2. This allows you to go over that + ['overshape'], // TODO: what is this? not found in tidal doc. Similar to above, but limited to 1 + /** + * Sets position in stereo. + * + * @name pan + * @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel) + * @example + * s("[bd hh]*2").pan("<.5 1 .5 0>") + * + */ + ['pan'], + // TODO: this has no effect (see example) + /* + * Controls how much multichannel output is fanned out + * + * @name panspan + * @param {number | Pattern} span between -inf and inf, negative is backwards ordering + * @example + * s("[bd hh]*2").pan("<.5 1 .5 0>").panspan("<0 .5 1>").osc() + * + */ + ['panspan'], + // TODO: this has no effect (see example) + /* + * Controls how much multichannel output is spread + * + * @name pansplay + * @param {number | Pattern} spread between 0 and 1 + * @example + * s("[bd hh]*2").pan("<.5 1 .5 0>").pansplay("<0 .5 1>").osc() + * + */ + ['pansplay'], + ['panwidth'], + ['panorient'], + // ['pitch1'], + // ['pitch2'], + // ['pitch3'], + // ['portamento'], + // TODO: LFO rate see https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare + ['rate'], + // TODO: slide param for certain synths + ['slide'], + // TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare + ['semitone'], + // TODO: dedup with synth param, see https://tidalcycles.org/docs/reference/synthesizers/#superpiano + // ['velocity'], + ['voice'], // TODO: synth param - // voicings // https://github.com/tidalcycles/strudel/issues/506 - ['chord'], // chord to voice, like C Eb Fm7 G7. the symbols can be defined via addVoicings - ['dictionary', 'dict'], // which dictionary to use for the voicings - ['anchor'], // the top note to align the voicing to, defaults to c5 - ['offset'], // how the voicing is offset from the anchored position - ['octaves'], // how many octaves are voicing steps spread apart, defaults to 1 - [['mode', 'anchor']], // below = anchor note will be removed from the voicing, useful for melody harmonization + // voicings // https://github.com/tidalcycles/strudel/issues/506 + ['chord'], // chord to voice, like C Eb Fm7 G7. the symbols can be defined via addVoicings + ['dictionary', 'dict'], // which dictionary to use for the voicings + ['anchor'], // the top note to align the voicing to, defaults to c5 + ['offset'], // how the voicing is offset from the anchored position + ['octaves'], // how many octaves are voicing steps spread apart, defaults to 1 + [['mode', 'anchor']], // below = anchor note will be removed from the voicing, useful for melody harmonization - /** - * Sets the level of reverb. - * - * When using mininotation, you can also optionally add the 'size' parameter, separated by ':'. - * - * @name room - * @param {number | Pattern} level between 0 and 1 - * @example - * s("bd sd").room("<0 .2 .4 .6 .8 1>") - * @example - * s("bd sd").room("<0.9:1 0.9:4>") - * - */ - [['room', 'size']], - /** - * Sets the room size of the reverb, see {@link room}. - * - * @name roomsize - * @param {number | Pattern} size between 0 and 10 - * @synonyms size, sz - * @example - * s("bd sd").room(.8).roomsize("<0 1 2 4 8>") - * - */ - // TODO: find out why : - // s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc() - // .. does not work. Is it because room is only one effect? - ['size', 'sz', 'roomsize'], - // ['sagogo'], - // ['sclap'], - // ['sclaves'], - // ['scrash'], - /** - * Wave shaping distortion. CAUTION: it might get loud - * - * @name shape - * @param {number | Pattern} distortion between 0 and 1 - * @example - * s("bd sd,hh*4").shape("<0 .2 .4 .6 .8>") - * - */ - ['shape'], - /** - * Changes the speed of sample playback, i.e. a cheap way of changing pitch. - * - * @name speed - * @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards. - * @example - * s("bd").speed("<1 2 4 1 -2 -4>") - * @example - * speed("1 1.5*2 [2 1.1]").s("piano").clip(1) - * - */ - ['speed'], - /** - * Used in conjunction with {@link speed}, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`. - * - * @name unit - * @param {number | string | Pattern} unit see description above - * @example - * speed("1 2 .5 3").s("bd").unit("c").osc() - * @superdirtOnly - * - */ - ['unit'], - /** - * Made by Calum Gunn. Reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter. The SuperCollider manual defines Squiz as: - * - * "A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated." - * - * @name squiz - * @param {number | Pattern} squiz Try passing multiples of 2 to it - 2, 4, 8 etc. - * @example - * squiz("2 4/2 6 [8 16]").s("bd").osc() - * @superdirtOnly - * - */ - ['squiz'], - // ['stutterdepth'], // TODO: what is this? not found in tidal doc - // ['stuttertime'], // TODO: what is this? not found in tidal doc - // ['timescale'], // TODO: what is this? not found in tidal doc - // ['timescalewin'], // TODO: what is this? not found in tidal doc - // ['tomdecay'], - // ['vcfegint'], - // ['vcoegint'], - // TODO: Use a rest (~) to override the effect <- vowel - /** - * - * Formant filter to make things sound like vowels. - * - * @name vowel - * @param {string | Pattern} vowel You can use a e i o u. - * @example - * note("c2 >").s('sawtooth') - * .vowel(">") - * - */ - ['vowel'], - /* // TODO: find out how it works - * Made by Calum Gunn. Divides an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discards a fraction of them. Takes a number between 1 and 100, denoted the percentage of segments to drop. The SuperCollider manual describes the Waveloss effect this way: - * - * Divide an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discard a fraction of them (i.e. replace them with silence of the same length). The technique was described by Trevor Wishart in a lecture. Parameters: the filter drops drop out of out of chunks. mode can be 1 to drop chunks in a simple deterministic fashion (e.g. always dropping the first 30 out of a set of 40 segments), or 2 to drop chunks randomly but in an appropriate proportion.) - * - * mode: ? - * waveloss: ? - * - * @name waveloss - */ - ['waveloss'], - // TODO: midi effects? - ['dur'], - // ['modwheel'], - ['expression'], - ['sustainpedal'], - /* // TODO: doesn't seem to do anything - * - * Tremolo Audio DSP effect - * - * @name tremolodepth - * @param {number | Pattern} depth between 0 and 1 - * @example - * n("0,4,7").tremolodepth("<0 .3 .6 .9>").osc() - * - */ - ['tremolodepth', 'tremdp'], - ['tremolorate', 'tremr'], - // TODO: doesn't seem to do anything - ['phaserdepth', 'phasdp'], - ['phaserrate', 'phasr'], + /** + * Sets the level of reverb. + * + * When using mininotation, you can also optionally add the 'size' parameter, separated by ':'. + * + * @name room + * @param {number | Pattern} level between 0 and 1 + * @example + * s("bd sd").room("<0 .2 .4 .6 .8 1>") + * @example + * s("bd sd").room("<0.9:1 0.9:4>") + * + */ + [['room', 'size']], + /** + * Sets the room size of the reverb, see {@link room}. + * + * @name roomsize + * @param {number | Pattern} size between 0 and 10 + * @synonyms size, sz + * @example + * s("bd sd").room(.8).roomsize("<0 1 2 4 8>") + * + */ + // TODO: find out why : + // s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc() + // .. does not work. Is it because room is only one effect? + ['size', 'sz', 'roomsize'], + // ['sagogo'], + // ['sclap'], + // ['sclaves'], + // ['scrash'], - ['fshift'], - ['fshiftnote'], - ['fshiftphase'], + /** + * Sets the sample to use as an impulse response for the reverb. + * + * @name iresponse + * @param {string | Pattern} Sets the impulse response + * @example + * s("bd sd").room(.8).ir("") + * + */ + [['ir', 'i'], 'iresponse'], + /** + * Wave shaping distortion. CAUTION: it might get loud + * + * @name shape + * @param {number | Pattern} distortion between 0 and 1 + * @example + * s("bd sd,hh*4").shape("<0 .2 .4 .6 .8>") + * + */ + ['shape'], + /** + * Changes the speed of sample playback, i.e. a cheap way of changing pitch. + * + * @name speed + * @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards. + * @example + * s("bd").speed("<1 2 4 1 -2 -4>") + * @example + * speed("1 1.5*2 [2 1.1]").s("piano").clip(1) + * + */ + ['speed'], + /** + * Used in conjunction with {@link speed}, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`. + * + * @name unit + * @param {number | string | Pattern} unit see description above + * @example + * speed("1 2 .5 3").s("bd").unit("c").osc() + * @superdirtOnly + * + */ + ['unit'], + /** + * Made by Calum Gunn. Reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter. The SuperCollider manual defines Squiz as: + * + * "A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated." + * + * @name squiz + * @param {number | Pattern} squiz Try passing multiples of 2 to it - 2, 4, 8 etc. + * @example + * squiz("2 4/2 6 [8 16]").s("bd").osc() + * @superdirtOnly + * + */ + ['squiz'], + // ['stutterdepth'], // TODO: what is this? not found in tidal doc + // ['stuttertime'], // TODO: what is this? not found in tidal doc + // ['timescale'], // TODO: what is this? not found in tidal doc + // ['timescalewin'], // TODO: what is this? not found in tidal doc + // ['tomdecay'], + // ['vcfegint'], + // ['vcoegint'], + // TODO: Use a rest (~) to override the effect <- vowel + /** + * + * Formant filter to make things sound like vowels. + * + * @name vowel + * @param {string | Pattern} vowel You can use a e i o u. + * @example + * note("c2 >").s('sawtooth') + * .vowel(">") + * + */ + ['vowel'], + /* // TODO: find out how it works + * Made by Calum Gunn. Divides an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discards a fraction of them. Takes a number between 1 and 100, denoted the percentage of segments to drop. The SuperCollider manual describes the Waveloss effect this way: + * + * Divide an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discard a fraction of them (i.e. replace them with silence of the same length). The technique was described by Trevor Wishart in a lecture. Parameters: the filter drops drop out of out of chunks. mode can be 1 to drop chunks in a simple deterministic fashion (e.g. always dropping the first 30 out of a set of 40 segments), or 2 to drop chunks randomly but in an appropriate proportion.) + * + * mode: ? + * waveloss: ? + * + * @name waveloss + */ + ['waveloss'], + // TODO: midi effects? + ['dur'], + // ['modwheel'], + ['expression'], + ['sustainpedal'], + /* // TODO: doesn't seem to do anything + * + * Tremolo Audio DSP effect + * + * @name tremolodepth + * @param {number | Pattern} depth between 0 and 1 + * @example + * n("0,4,7").tremolodepth("<0 .3 .6 .9>").osc() + * + */ + ['tremolodepth', 'tremdp'], + ['tremolorate', 'tremr'], + // TODO: doesn't seem to do anything + ['phaserdepth', 'phasdp'], + ['phaserrate', 'phasr'], - ['triode'], - ['krush'], - ['kcutoff'], - ['octer'], - ['octersub'], - ['octersubsub'], - ['ring'], - ['ringf'], - ['ringdf'], - ['distort'], - ['freeze'], - ['xsdelay'], - ['tsdelay'], - ['real'], - ['imag'], - ['enhance'], - ['partials'], - ['comb'], - ['smear'], - ['scram'], - ['binshift'], - ['hbrick'], - ['lbrick'], - ['midichan'], - ['control'], - ['ccn'], - ['ccv'], - ['polyTouch'], - ['midibend'], - ['miditouch'], - ['ctlNum'], - ['frameRate'], - ['frames'], - ['hours'], - ['midicmd'], - ['minutes'], - ['progNum'], - ['seconds'], - ['songPtr'], - ['uid'], - ['val'], - ['cps'], - /** - * Multiplies the duration with the given number. Also cuts samples off at the end if they exceed the duration. - * In tidal, this would be done with legato, [which has a complicated history in strudel](https://github.com/tidalcycles/strudel/issues/111). - * For now, if you're coming from tidal, just think clip = legato. - * - * @name clip - * @param {number | Pattern} factor >= 0 - * @example - * note("c a f e").s("piano").clip("<.5 1 2>") - * - */ - ['clip'], + ['fshift'], + ['fshiftnote'], + ['fshiftphase'], - // ZZFX - ['zrand'], - ['curve'], - ['slide'], // superdirt duplicate - ['deltaSlide'], - ['pitchJump'], - ['pitchJumpTime'], - ['lfo', 'repeatTime'], - ['noise'], - ['zmod'], - ['zcrush'], // like crush but scaled differently - ['zdelay'], - ['tremolo'], - ['zzfx'], + ['triode'], + ['krush'], + ['kcutoff'], + ['octer'], + ['octersub'], + ['octersubsub'], + ['ring'], + ['ringf'], + ['ringdf'], + ['distort'], + ['freeze'], + ['xsdelay'], + ['tsdelay'], + ['real'], + ['imag'], + ['enhance'], + ['partials'], + ['comb'], + ['smear'], + ['scram'], + ['binshift'], + ['hbrick'], + ['lbrick'], + ['midichan'], + ['control'], + ['ccn'], + ['ccv'], + ['polyTouch'], + ['midibend'], + ['miditouch'], + ['ctlNum'], + ['frameRate'], + ['frames'], + ['hours'], + ['midicmd'], + ['minutes'], + ['progNum'], + ['seconds'], + ['songPtr'], + ['uid'], + ['val'], + ['cps'], + /** + * Multiplies the duration with the given number. Also cuts samples off at the end if they exceed the duration. + * In tidal, this would be done with legato, [which has a complicated history in strudel](https://github.com/tidalcycles/strudel/issues/111). + * For now, if you're coming from tidal, just think clip = legato. + * + * @name clip + * @param {number | Pattern} factor >= 0 + * @example + * note("c a f e").s("piano").clip("<.5 1 2>") + * + */ + ['clip'], + + // ZZFX + ['zrand'], + ['curve'], + ['slide'], // superdirt duplicate + ['deltaSlide'], + ['pitchJump'], + ['pitchJumpTime'], + ['lfo', 'repeatTime'], + ['noise'], + ['zmod'], + ['zcrush'], // like crush but scaled differently + ['zdelay'], + ['tremolo'], + ['zzfx'], ]; // TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13 controls.createParam = function (names) { - const name = Array.isArray(names) ? names[0] : names; + const name = Array.isArray(names) ? names[0] : names; - var withVal; - if (Array.isArray(names)) { - withVal = (xs) => { - if (Array.isArray(xs)) { - const result = {}; - xs.forEach((x, i) => { - if (i < names.length) { - result[names[i]] = x; - } - }); - return result; - } else { - return { [name]: xs }; - } - }; - } else { - withVal = (x) => ({ [name]: x }); - } - - const func = (...pats) => sequence(...pats).withValue(withVal); - - const setter = function (...pats) { - if (!pats.length) { - return this.fmap(withVal); + var withVal; + if (Array.isArray(names)) { + withVal = (xs) => { + if (Array.isArray(xs)) { + const result = {}; + xs.forEach((x, i) => { + if (i < names.length) { + result[names[i]] = x; + } + }); + return result; + } else { + return {[name]: xs}; + } + }; + } else { + withVal = (x) => ({[name]: x}); } - return this.set(func(...pats)); - }; - Pattern.prototype[name] = setter; - return func; + + const func = (...pats) => sequence(...pats).withValue(withVal); + + const setter = function (...pats) { + if (!pats.length) { + return this.fmap(withVal); + } + return this.set(func(...pats)); + }; + Pattern.prototype[name] = setter; + return func; }; generic_params.forEach(([names, ...aliases]) => { - const name = Array.isArray(names) ? names[0] : names; - controls[name] = controls.createParam(names); + const name = Array.isArray(names) ? names[0] : names; + controls[name] = controls.createParam(names); - aliases.forEach((alias) => { - controls[alias] = controls[name]; - Pattern.prototype[alias] = Pattern.prototype[name]; - }); + aliases.forEach((alias) => { + controls[alias] = controls[name]; + Pattern.prototype[alias] = Pattern.prototype[name]; + }); }); controls.createParams = (...names) => - names.reduce((acc, name) => Object.assign(acc, { [name]: controls.createParam(name) }), {}); + names.reduce((acc, name) => Object.assign(acc, {[name]: controls.createParam(name)}), {}); controls.adsr = register('adsr', (adsr, pat) => { - adsr = !Array.isArray(adsr) ? [adsr] : adsr; - const [attack, decay, sustain, release] = adsr; - return pat.set({ attack, decay, sustain, release }); + adsr = !Array.isArray(adsr) ? [adsr] : adsr; + const [attack, decay, sustain, release] = adsr; + return pat.set({attack, decay, sustain, release}); }); controls.ds = register('ds', (ds, pat) => { - ds = !Array.isArray(ds) ? [ds] : ds; - const [decay, sustain] = ds; - return pat.set({ decay, sustain }); + ds = !Array.isArray(ds) ? [ds] : ds; + const [decay, sustain] = ds; + return pat.set({decay, sustain}); }); export default controls; diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index e6d31f6a..72709085 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -7,14 +7,22 @@ if (typeof AudioContext !== 'undefined') { return impulse; }; - AudioContext.prototype.createReverb = function (duration) { + AudioContext.prototype.createReverb = function (duration, buffer) { const convolver = this.createConvolver(); - convolver.setDuration = (d) => { - convolver.buffer = this.impulseResponse(d); - convolver.duration = duration; + convolver.setDuration = (d, i) => { + convolver.buffer = i !== undefined ? buffer : this.impulseResponse(d); + convolver.duration = d; return convolver; }; - convolver.setDuration(duration); + convolver.setIR = (i) => { + convolver.buffer = i; + return convolver; + }; + if (buffer !== undefined) { + convolver.setIR(buffer); + } else { + convolver.setDuration(duration); + } return convolver; }; } diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 289e8d97..2b46ae3c 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -12,14 +12,18 @@ import workletsUrl from './worklets.mjs?url'; import { createFilter, gainNode } from './helpers.mjs'; import { map } from 'nanostores'; import { logger } from './logger.mjs'; +import { loadBuffer } from './sampler.mjs'; export const soundMap = map(); + export function registerSound(key, onTrigger, data = {}) { soundMap.setKey(key, { onTrigger, data }); } + export function getSound(s) { return soundMap.get()[s]; } + export const resetLoadedSounds = () => soundMap.set({}); let audioContext; @@ -46,6 +50,7 @@ export const panic = () => { }; let workletsLoading; + function loadWorklets() { if (workletsLoading) { return workletsLoading; @@ -89,6 +94,7 @@ export async function initAudioOnFirstClick(options) { let delays = {}; const maxfeedback = 0.98; + function getDelay(orbit, delaytime, delayfeedback, t) { if (delayfeedback > maxfeedback) { //logger(`delayfeedback was clamped to ${maxfeedback} to save your ears`); @@ -107,10 +113,11 @@ function getDelay(orbit, delaytime, delayfeedback, t) { } let reverbs = {}; -function getReverb(orbit, duration = 2) { + +function getReverb(orbit, duration = 2, ir) { if (!reverbs[orbit]) { const ac = getAudioContext(); - const reverb = ac.createReverb(duration); + const reverb = ac.createReverb(duration, ir); reverb.connect(getDestination()); reverbs[orbit] = reverb; } @@ -118,10 +125,15 @@ function getReverb(orbit, duration = 2) { reverbs[orbit] = reverbs[orbit].setDuration(duration); reverbs[orbit].duration = duration; } + if (reverbs[orbit].ir !== ir) { + reverbs[orbit] = reverbs[orbit].setIR(ir); + reverbs[orbit].ir = ir; + } return reverbs[orbit]; } export let analyser, analyserData /* s = {} */; + export function getAnalyser(/* orbit, */ fftSize = 2048) { if (!analyser /*s [orbit] */) { const analyserNode = getAudioContext().createAnalyser(); @@ -151,7 +163,7 @@ export function getAnalyzerData(type = 'time') { return analyserData; } -function effectSend(input, effect, wet) { +function effectSend(input, effect, wet, size) { const send = gainNode(wet); input.connect(send); send.connect(effect); @@ -219,6 +231,8 @@ export const superdough = async (value, deadline, hapDuration) => { velocity = 1, analyze, // analyser wet fft = 8, // fftSize 0 - 10 + ir, + i = 0, } = value; gain *= velocity; // legacy fix for velocity let toDisconnect = []; // audio nodes that will be disconnected when the source has ended @@ -247,6 +261,7 @@ export const superdough = async (value, deadline, hapDuration) => { // this can be used for things like speed(0) in the sampler return; } + if (ac.currentTime > t) { logger('[webaudio] skip hap: still loading', ac.currentTime - t); return; @@ -352,10 +367,16 @@ export const superdough = async (value, deadline, hapDuration) => { delaySend = effectSend(post, delyNode, delay); } // reverb + let buffer; + if (ir !== undefined) { + let sample = getSound(ir); + let url = sample.data.samples[i % sample.data.samples.length]; + buffer = await loadBuffer(url, ac, ir, 0); + } let reverbSend; if (room > 0 && size > 0) { - const reverbNode = getReverb(orbit, size); - reverbSend = effectSend(post, reverbNode, room); + const reverbNode = getReverb(orbit, size, buffer); + reverbSend = effectSend(post, reverbNode, room, size); } // analyser From abff27970746fecb4620d54a272abc5b67972d0c Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 1 Oct 2023 11:52:24 +0200 Subject: [PATCH 113/175] Document reverb controls --- packages/core/controls.mjs | 39 ++++++++++++++++++++++++++++-- packages/superdough/reverb.mjs | 14 ++++++++--- packages/superdough/superdough.mjs | 11 ++++++++- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 6cac6e54..216b7001 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -970,6 +970,41 @@ const generic_params = [ * */ [['room', 'size']], + /** + * Reverb lowpass starting frequency (in hertz). + * + * @name revlp + * @param {number} level between 0 and 20000hz + * @example + * s("bd sd").room(0.5).revlp(10000) + * @example + * s("bd sd").room(0.5).revlp(5000) + */ + ['revlp'], + /** + * Reverb lowpass frequency at -60dB (in hertz). + * + * @name revdim + * @param {number} level between 0 and 20000hz + * @example + * s("bd sd").room(0.5).revlp(10000).revdim(8000) + * @example + * s("bd sd").room(0.5).revlp(5000).revdim(400) + * + */ + ['revdim'], + /** + * Reverb fade time (in seconds). + * + * @name fade + * @param {number} seconds for the reverb to fade + * @example + * s("bd sd").room(0.5).revlp(10000).fade(0.5) + * @example + * s("bd sd").room(0.5).revlp(5000).fade(4) + * + */ + ['fade'], /** * Sets the room size of the reverb, see {@link room}. * @@ -1162,7 +1197,7 @@ const generic_params = [ ]; // TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13 -controls.createParam = function (names) { +controls.createParam = function(names) { const name = Array.isArray(names) ? names[0] : names; var withVal; @@ -1186,7 +1221,7 @@ controls.createParam = function (names) { const func = (...pats) => sequence(...pats).withValue(withVal); - const setter = function (...pats) { + const setter = function(...pats) { if (!pats.length) { return this.fmap(withVal); } diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index 4d5f655f..505d0ac2 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -2,7 +2,13 @@ import reverbGen from './reverbGen.mjs'; if (typeof AudioContext !== 'undefined') { AudioContext.prototype.generateReverb = reverbGen.generateReverb; - AudioContext.prototype.createReverb = function(duration, audioContext) { + AudioContext.prototype.createReverb = function( + duration, + audioContext, + fade, + revlp, + revdim + ) { const convolver = this.createConvolver(); convolver.setDuration = (d) => { this.generateReverb( @@ -11,9 +17,9 @@ if (typeof AudioContext !== 'undefined') { sampleRate: 44100, numChannels: 2, decayTime: d, - fadeInTime: d, - lpFreqStart: 2000, - lpFreqEnd: 15000, + fadeInTime: fade, + lpFreqStart: revlp, + lpFreqEnd: revdim, }, (buffer) => { convolver.buffer = buffer; diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 9010c85d..33c108f2 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -113,7 +113,13 @@ function getReverb(orbit, duration = 2) { // If no reverb has been created for a given orbit, create one if (!reverbs[orbit]) { const ac = getAudioContext(); - const reverb = ac.createReverb(duration, getAudioContext()); + const reverb = ac.createReverb( + duration, + getAudioContext(), + fade, + revlp, + revdim, + ); reverb.connect(getDestination()); console.log(reverb) reverbs[orbit] = reverb; @@ -222,6 +228,9 @@ export const superdough = async (value, deadline, hapDuration) => { delaytime = 0.25, orbit = 1, room, + fade = 0.1, + revlp = 15000, + revdim = 1000, size = 2, velocity = 1, analyze, // analyser wet From e600b91a8569685444bb1f719f9c6ed4b8910b9b Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 1 Oct 2023 12:02:17 +0200 Subject: [PATCH 114/175] bugfixes for parameter passing --- packages/superdough/reverb.mjs | 4 ++-- packages/superdough/superdough.mjs | 12 +++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index 505d0ac2..4c5bc1d1 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -3,14 +3,14 @@ import reverbGen from './reverbGen.mjs'; if (typeof AudioContext !== 'undefined') { AudioContext.prototype.generateReverb = reverbGen.generateReverb; AudioContext.prototype.createReverb = function( - duration, audioContext, + duration, fade, revlp, revdim ) { const convolver = this.createConvolver(); - convolver.setDuration = (d) => { + convolver.setDuration = (d, fade, revlp, revdim) => { this.generateReverb( { audioContext, diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 33c108f2..607c649d 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -108,29 +108,27 @@ function getDelay(orbit, delaytime, delayfeedback, t) { let reverbs = {}; -function getReverb(orbit, duration = 2) { +function getReverb(orbit, duration = 2, fade, revlp, revdim) { // If no reverb has been created for a given orbit, create one if (!reverbs[orbit]) { const ac = getAudioContext(); const reverb = ac.createReverb( - duration, getAudioContext(), + duration, fade, revlp, - revdim, ); reverb.connect(getDestination()); console.log(reverb) reverbs[orbit] = reverb; } - // Update the reverb duration if needed after instanciation if (reverbs[orbit].duration !== duration) { - reverbs[orbit] = reverbs[orbit].setDuration(duration); + reverbs[orbit] = reverbs[orbit].setDuration( + duration, fade, revlp, revdim); reverbs[orbit].duration = duration; } - return reverbs[orbit]; } @@ -370,7 +368,7 @@ export const superdough = async (value, deadline, hapDuration) => { // reverb let reverbSend; if (room > 0 && size > 0) { - const reverbNode = getReverb(orbit, size); + const reverbNode = getReverb(orbit, size, fade, revlp, revdim); reverbSend = effectSend(post, reverbNode, room); } From c6ecd31ea11baef947f4f261f7edcea31290ebec Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 13:27:44 +0200 Subject: [PATCH 115/175] improve mouse tracking --- packages/codemirror/slider.mjs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 44875e25..d4fbcefa 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -36,7 +36,7 @@ export class SliderWidget extends WidgetType { slider.from = this.from; slider.originalFrom = this.originalFrom; slider.to = this.to; - slider.className = 'w-16 translate-y-1.5 mx-2'; + slider.className = 'w-16 translate-y-1'; this.slider = slider; return wrap; } @@ -97,7 +97,7 @@ export const sliderPlugin = ViewPlugin.fromClass( eventHandlers: { mousedown: (e, view) => { - let target = e.target; /* as HTMLElement */ + let target = e.target; if (target.nodeName == 'INPUT' && target.parentElement.classList.contains('cm-slider')) { e.preventDefault(); e.stopPropagation(); @@ -121,7 +121,8 @@ export const sliderPlugin = ViewPlugin.fromClass( // moves slider on mouse event function updateSliderValue(view, e) { const mouseX = e.clientX; - let progress = (mouseX - draggedSlider._offsetLeft) / draggedSlider._clientWidth; + let mx = 10; + let progress = (mouseX - draggedSlider._offsetLeft - mx) / (draggedSlider._clientWidth - mx * 2); progress = Math.max(Math.min(1, progress), 0); let min = Number(draggedSlider.min); let max = Number(draggedSlider.max); From 755e24315e04223f75d22ac7680d05576b034c2f Mon Sep 17 00:00:00 2001 From: Vasilii Milovidov Date: Sun, 1 Oct 2023 15:31:10 +0400 Subject: [PATCH 116/175] use sample as an impulse response for the reverb --- packages/core/controls.mjs | 2386 ++++++++++++++-------------- packages/superdough/reverb.mjs | 29 +- packages/superdough/superdough.mjs | 11 +- 3 files changed, 1221 insertions(+), 1205 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 76a278a5..bc06ecc2 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -4,1231 +4,1233 @@ Copyright (C) 2022 Strudel contributors - see . */ -import {Pattern, register, sequence} from './pattern.mjs'; -import {zipWith} from './util.mjs'; +import { Pattern, register, sequence } from './pattern.mjs'; +import { zipWith } from './util.mjs'; const controls = {}; const generic_params = [ - /** - * Select a sound / sample by name. When using mininotation, you can also optionally supply 'n' and 'gain' parameters - * separated by ':'. - * - * @name s - * @param {string | Pattern} sound The sound / pattern of sounds to pick - * @synonyms sound - * @example - * s("bd hh") - * @example - * s("bd:0 bd:1 bd:0:0.3 bd:1:1.4") - * - */ - [['s', 'n', 'gain'], 'sound'], - /** - * Define a custom webaudio node to use as a sound source. - * - * @name source - * @param {function} getSource - * @synonyms src - * - */ - ['source', 'src'], - /** - * Selects the given index from the sample map. - * Numbers too high will wrap around. - * `n` can also be used to play midi numbers, but it is recommended to use `note` instead. - * - * @name n - * @param {number | Pattern} value sample index starting from 0 - * @example - * s("bd sd,hh*3").n("<0 1>") - */ - // also see https://github.com/tidalcycles/strudel/pull/63 - ['n'], - /** - * Plays the given note name or midi number. A note name consists of - * - * - a letter (a-g or A-G) - * - optional accidentals (b or #) - * - optional octave number (0-9). Defaults to 3 - * - * Examples of valid note names: `c`, `bb`, `Bb`, `f#`, `c3`, `A4`, `Eb2`, `c#5` - * - * You can also use midi numbers instead of note names, where 69 is mapped to A4 440Hz in 12EDO. - * - * @name note - * @example - * note("c a f e") - * @example - * note("c4 a4 f4 e4") - * @example - * note("60 69 65 64") - */ - [['note', 'n']], + /** + * Select a sound / sample by name. When using mininotation, you can also optionally supply 'n' and 'gain' parameters + * separated by ':'. + * + * @name s + * @param {string | Pattern} sound The sound / pattern of sounds to pick + * @synonyms sound + * @example + * s("bd hh") + * @example + * s("bd:0 bd:1 bd:0:0.3 bd:1:1.4") + * + */ + [['s', 'n', 'gain'], 'sound'], + /** + * Define a custom webaudio node to use as a sound source. + * + * @name source + * @param {function} getSource + * @synonyms src + * + */ + ['source', 'src'], + /** + * Selects the given index from the sample map. + * Numbers too high will wrap around. + * `n` can also be used to play midi numbers, but it is recommended to use `note` instead. + * + * @name n + * @param {number | Pattern} value sample index starting from 0 + * @example + * s("bd sd,hh*3").n("<0 1>") + */ + // also see https://github.com/tidalcycles/strudel/pull/63 + ['n'], + /** + * Plays the given note name or midi number. A note name consists of + * + * - a letter (a-g or A-G) + * - optional accidentals (b or #) + * - optional octave number (0-9). Defaults to 3 + * + * Examples of valid note names: `c`, `bb`, `Bb`, `f#`, `c3`, `A4`, `Eb2`, `c#5` + * + * You can also use midi numbers instead of note names, where 69 is mapped to A4 440Hz in 12EDO. + * + * @name note + * @example + * note("c a f e") + * @example + * note("c4 a4 f4 e4") + * @example + * note("60 69 65 64") + */ + [['note', 'n']], - /** - * A pattern of numbers that speed up (or slow down) samples while they play. Currently only supported by osc / superdirt. - * - * @name accelerate - * @param {number | Pattern} amount acceleration. - * @superdirtOnly - * @example - * s("sax").accelerate("<0 1 2 4 8 16>").slow(2).osc() - * - */ - ['accelerate'], - /** - * Controls the gain by an exponential amount. - * - * @name gain - * @param {number | Pattern} amount gain. - * @example - * s("hh*8").gain(".4!2 1 .4!2 1 .4 1") - * - */ - ['gain'], - /** - * Like {@link gain}, but linear. - * - * @name amp - * @param {number | Pattern} amount gain. - * @superdirtOnly - * @example - * s("bd*8").amp(".1*2 .5 .1*2 .5 .1 .5").osc() - * - */ - ['amp'], - /** - * Amplitude envelope attack time: Specifies how long it takes for the sound to reach its peak value, relative to the onset. - * - * @name attack - * @param {number | Pattern} attack time in seconds. - * @synonyms att - * @example - * note("c3 e3").attack("<0 .1 .5>") - * - */ - ['attack', 'att'], + /** + * A pattern of numbers that speed up (or slow down) samples while they play. Currently only supported by osc / superdirt. + * + * @name accelerate + * @param {number | Pattern} amount acceleration. + * @superdirtOnly + * @example + * s("sax").accelerate("<0 1 2 4 8 16>").slow(2).osc() + * + */ + ['accelerate'], + /** + * Controls the gain by an exponential amount. + * + * @name gain + * @param {number | Pattern} amount gain. + * @example + * s("hh*8").gain(".4!2 1 .4!2 1 .4 1") + * + */ + ['gain'], + /** + * Like {@link gain}, but linear. + * + * @name amp + * @param {number | Pattern} amount gain. + * @superdirtOnly + * @example + * s("bd*8").amp(".1*2 .5 .1*2 .5 .1 .5").osc() + * + */ + ['amp'], + /** + * Amplitude envelope attack time: Specifies how long it takes for the sound to reach its peak value, relative to the onset. + * + * @name attack + * @param {number | Pattern} attack time in seconds. + * @synonyms att + * @example + * note("c3 e3").attack("<0 .1 .5>") + * + */ + ['attack', 'att'], - /** - * Sets the Frequency Modulation Harmonicity Ratio. - * Controls the timbre of the sound. - * Whole numbers and simple ratios sound more natural, - * while decimal numbers and complex ratios sound metallic. - * - * @name fmh - * @param {number | Pattern} harmonicity - * @example - * note("c e g b") - * .fm(4) - * .fmh("<1 2 1.5 1.61>") - * .scope() - * - */ - [['fmh', 'fmi'], 'fmh'], - /** - * Sets the Frequency Modulation of the synth. - * Controls the modulation index, which defines the brightness of the sound. - * - * @name fm - * @param {number | Pattern} brightness modulation index - * @synonyms fmi - * @example - * note("c e g b") - * .fm("<0 1 2 8 32>") - * .scope() - * - */ - [['fmi', 'fmh'], 'fm'], - // fm envelope - /** - * Ramp type of fm envelope. Exp might be a bit broken.. - * - * @name fmenv - * @param {number | Pattern} type lin | exp - * @example - * note("c e g b") - * .fm(4) - * .fmdecay(.2) - * .fmsustain(0) - * .fmenv("") - * .scope() - * - */ - ['fmenv'], - /** - * Attack time for the FM envelope: time it takes to reach maximum modulation - * - * @name fmattack - * @param {number | Pattern} time attack time - * @example - * note("c e g b") - * .fm(4) - * .fmattack("<0 .05 .1 .2>") - * .scope() - * - */ - ['fmattack'], - /** - * Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase. - * - * @name fmdecay - * @param {number | Pattern} time decay time - * @example - * note("c e g b") - * .fm(4) - * .fmdecay("<.01 .05 .1 .2>") - * .fmsustain(.4) - * .scope() - * - */ - ['fmdecay'], - /** - * Sustain level for the FM envelope: how much modulation is applied after the decay phase - * - * @name fmsustain - * @param {number | Pattern} level sustain level - * @example - * note("c e g b") - * .fm(4) - * .fmdecay(.1) - * .fmsustain("<1 .75 .5 0>") - * .scope() - * - */ - ['fmsustain'], - // these are not really useful... skipping for now - ['fmrelease'], - ['fmvelocity'], + /** + * Sets the Frequency Modulation Harmonicity Ratio. + * Controls the timbre of the sound. + * Whole numbers and simple ratios sound more natural, + * while decimal numbers and complex ratios sound metallic. + * + * @name fmh + * @param {number | Pattern} harmonicity + * @example + * note("c e g b") + * .fm(4) + * .fmh("<1 2 1.5 1.61>") + * .scope() + * + */ + [['fmh', 'fmi'], 'fmh'], + /** + * Sets the Frequency Modulation of the synth. + * Controls the modulation index, which defines the brightness of the sound. + * + * @name fm + * @param {number | Pattern} brightness modulation index + * @synonyms fmi + * @example + * note("c e g b") + * .fm("<0 1 2 8 32>") + * .scope() + * + */ + [['fmi', 'fmh'], 'fm'], + // fm envelope + /** + * Ramp type of fm envelope. Exp might be a bit broken.. + * + * @name fmenv + * @param {number | Pattern} type lin | exp + * @example + * note("c e g b") + * .fm(4) + * .fmdecay(.2) + * .fmsustain(0) + * .fmenv("") + * .scope() + * + */ + ['fmenv'], + /** + * Attack time for the FM envelope: time it takes to reach maximum modulation + * + * @name fmattack + * @param {number | Pattern} time attack time + * @example + * note("c e g b") + * .fm(4) + * .fmattack("<0 .05 .1 .2>") + * .scope() + * + */ + ['fmattack'], + /** + * Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase. + * + * @name fmdecay + * @param {number | Pattern} time decay time + * @example + * note("c e g b") + * .fm(4) + * .fmdecay("<.01 .05 .1 .2>") + * .fmsustain(.4) + * .scope() + * + */ + ['fmdecay'], + /** + * Sustain level for the FM envelope: how much modulation is applied after the decay phase + * + * @name fmsustain + * @param {number | Pattern} level sustain level + * @example + * note("c e g b") + * .fm(4) + * .fmdecay(.1) + * .fmsustain("<1 .75 .5 0>") + * .scope() + * + */ + ['fmsustain'], + // these are not really useful... skipping for now + ['fmrelease'], + ['fmvelocity'], - /** - * Select the sound bank to use. To be used together with `s`. The bank name (+ "_") will be prepended to the value of `s`. - * - * @name bank - * @param {string | Pattern} bank the name of the bank - * @example - * s("bd sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd") - * - */ - ['bank'], + /** + * Select the sound bank to use. To be used together with `s`. The bank name (+ "_") will be prepended to the value of `s`. + * + * @name bank + * @param {string | Pattern} bank the name of the bank + * @example + * s("bd sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd") + * + */ + ['bank'], - ['analyze'], // analyser node send amount 0 - 1 (used by scope) - ['fft'], // fftSize of analyser + ['analyze'], // analyser node send amount 0 - 1 (used by scope) + ['fft'], // fftSize of analyser - /** - * Amplitude envelope decay time: the time it takes after the attack time to reach the sustain level. - * Note that the decay is only audible if the sustain value is lower than 1. - * - * @name decay - * @param {number | Pattern} time decay time in seconds - * @example - * note("c3 e3").decay("<.1 .2 .3 .4>").sustain(0) - * - */ - ['decay'], - /** - * Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset. - * - * @name sustain - * @param {number | Pattern} gain sustain level between 0 and 1 - * @synonyms sus - * @example - * note("c3 e3").decay(.2).sustain("<0 .1 .4 .6 1>") - * - */ - ['sustain', 'sus'], - /** - * Amplitude envelope release time: The time it takes after the offset to go from sustain level to zero. - * - * @name release - * @param {number | Pattern} time release time in seconds - * @synonyms rel - * @example - * note("c3 e3 g3 c4").release("<0 .1 .4 .6 1>/2") - * - */ - ['release', 'rel'], - ['hold'], - // TODO: in tidal, it seems to be normalized - /** - * Sets the center frequency of the **b**and-**p**ass **f**ilter. When using mininotation, you - * can also optionally supply the 'bpq' parameter separated by ':'. - * - * @name bpf - * @param {number | Pattern} frequency center frequency - * @synonyms bandf, bp - * @example - * s("bd sd,hh*3").bpf("<1000 2000 4000 8000>") - * - */ - [['bandf', 'bandq'], 'bpf', 'bp'], - // TODO: in tidal, it seems to be normalized - /** - * Sets the **b**and-**p**ass **q**-factor (resonance). - * - * @name bpq - * @param {number | Pattern} q q factor - * @synonyms bandq - * @example - * s("bd sd").bpf(500).bpq("<0 1 2 3>") - * - */ - // currently an alias of 'bandq' https://github.com/tidalcycles/strudel/issues/496 - // ['bpq'], - ['bandq', 'bpq'], - /** - * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample. - * - * @memberof Pattern - * @name begin - * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample - * @example - * samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/') - * s("rave").begin("<0 .25 .5 .75>") - * - */ - ['begin'], - /** - * The same as .begin, but cuts off the end off each sample. - * - * @memberof Pattern - * @name end - * @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc.. - * @example - * s("bd*2,oh*4").end("<.1 .2 .5 1>") - * - */ - ['end'], - /** - * Loops the sample. - * Note that the tempo of the loop is not synced with the cycle tempo. - * To change the loop region, use loopBegin / loopEnd. - * - * @name loop - * @param {number | Pattern} on If 1, the sample is looped - * @example - * s("casio").loop(1) - * - */ - ['loop'], - /** - * Begin to loop at a specific point in the sample (inbetween `begin` and `end`). - * Note that the loop point must be inbetween `begin` and `end`, and before `loopEnd`! - * Note: Samples starting with wt_ will automatically loop! (wt = wavetable) - * - * @name loopBegin - * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample - * @synonyms loopb - * @example - * s("space").loop(1) - * .loopBegin("<0 .125 .25>").scope() - */ - ['loopBegin', 'loopb'], - /** - * - * End the looping section at a specific point in the sample (inbetween `begin` and `end`). - * Note that the loop point must be inbetween `begin` and `end`, and after `loopBegin`! - * - * @name loopEnd - * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample - * @synonyms loope - * @example - * s("space").loop(1) - * .loopEnd("<1 .75 .5 .25>").scope() - */ - ['loopEnd', 'loope'], - /** - * bit crusher effect. - * - * @name crush - * @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction). - * @example - * s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>") - * - */ - // TODO: currently duplicated with "native" legato - // TODO: superdirt legato will do more: https://youtu.be/dQPmE1WaD1k?t=419 - /** - * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample. - * - * @name legato - * @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time - * @noAutocomplete - * @example - * "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>") - * - */ - // ['legato'], - // ['clhatdecay'], - ['crush'], - /** - * fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers - * - * @name coarse - * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on. - * @example - * s("bd sd,hh*4").coarse("<1 4 8 16 32>") - * - */ - ['coarse'], - /** - * choose the channel the pattern is sent to in superdirt - * - * @name channel - * @param {number | Pattern} channel channel number - * - */ - ['channel'], - /** - * In the style of classic drum-machines, `cut` will stop a playing sample as soon as another samples with in same cutgroup is to be played. An example would be an open hi-hat followed by a closed one, essentially muting the open. - * - * @name cut - * @param {number | Pattern} group cut group number - * @example - * s("rd*4").cut(1) - * - */ - ['cut'], - /** - * Applies the cutoff frequency of the **l**ow-**p**ass **f**ilter. - * - * When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'. - * - * @name lpf - * @param {number | Pattern} frequency audible between 0 and 20000 - * @synonyms cutoff, ctf, lp - * @example - * s("bd sd,hh*3").lpf("<4000 2000 1000 500 200 100>") - * @example - * s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30") - * - */ - [['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'], + /** + * Amplitude envelope decay time: the time it takes after the attack time to reach the sustain level. + * Note that the decay is only audible if the sustain value is lower than 1. + * + * @name decay + * @param {number | Pattern} time decay time in seconds + * @example + * note("c3 e3").decay("<.1 .2 .3 .4>").sustain(0) + * + */ + ['decay'], + /** + * Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset. + * + * @name sustain + * @param {number | Pattern} gain sustain level between 0 and 1 + * @synonyms sus + * @example + * note("c3 e3").decay(.2).sustain("<0 .1 .4 .6 1>") + * + */ + ['sustain', 'sus'], + /** + * Amplitude envelope release time: The time it takes after the offset to go from sustain level to zero. + * + * @name release + * @param {number | Pattern} time release time in seconds + * @synonyms rel + * @example + * note("c3 e3 g3 c4").release("<0 .1 .4 .6 1>/2") + * + */ + ['release', 'rel'], + ['hold'], + // TODO: in tidal, it seems to be normalized + /** + * Sets the center frequency of the **b**and-**p**ass **f**ilter. When using mininotation, you + * can also optionally supply the 'bpq' parameter separated by ':'. + * + * @name bpf + * @param {number | Pattern} frequency center frequency + * @synonyms bandf, bp + * @example + * s("bd sd,hh*3").bpf("<1000 2000 4000 8000>") + * + */ + [['bandf', 'bandq'], 'bpf', 'bp'], + // TODO: in tidal, it seems to be normalized + /** + * Sets the **b**and-**p**ass **q**-factor (resonance). + * + * @name bpq + * @param {number | Pattern} q q factor + * @synonyms bandq + * @example + * s("bd sd").bpf(500).bpq("<0 1 2 3>") + * + */ + // currently an alias of 'bandq' https://github.com/tidalcycles/strudel/issues/496 + // ['bpq'], + ['bandq', 'bpq'], + /** + * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample. + * + * @memberof Pattern + * @name begin + * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample + * @example + * samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/') + * s("rave").begin("<0 .25 .5 .75>") + * + */ + ['begin'], + /** + * The same as .begin, but cuts off the end off each sample. + * + * @memberof Pattern + * @name end + * @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc.. + * @example + * s("bd*2,oh*4").end("<.1 .2 .5 1>") + * + */ + ['end'], + /** + * Loops the sample. + * Note that the tempo of the loop is not synced with the cycle tempo. + * To change the loop region, use loopBegin / loopEnd. + * + * @name loop + * @param {number | Pattern} on If 1, the sample is looped + * @example + * s("casio").loop(1) + * + */ + ['loop'], + /** + * Begin to loop at a specific point in the sample (inbetween `begin` and `end`). + * Note that the loop point must be inbetween `begin` and `end`, and before `loopEnd`! + * Note: Samples starting with wt_ will automatically loop! (wt = wavetable) + * + * @name loopBegin + * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample + * @synonyms loopb + * @example + * s("space").loop(1) + * .loopBegin("<0 .125 .25>").scope() + */ + ['loopBegin', 'loopb'], + /** + * + * End the looping section at a specific point in the sample (inbetween `begin` and `end`). + * Note that the loop point must be inbetween `begin` and `end`, and after `loopBegin`! + * + * @name loopEnd + * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample + * @synonyms loope + * @example + * s("space").loop(1) + * .loopEnd("<1 .75 .5 .25>").scope() + */ + ['loopEnd', 'loope'], + /** + * bit crusher effect. + * + * @name crush + * @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction). + * @example + * s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>") + * + */ + // TODO: currently duplicated with "native" legato + // TODO: superdirt legato will do more: https://youtu.be/dQPmE1WaD1k?t=419 + /** + * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample. + * + * @name legato + * @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time + * @noAutocomplete + * @example + * "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>") + * + */ + // ['legato'], + // ['clhatdecay'], + ['crush'], + /** + * fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers + * + * @name coarse + * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on. + * @example + * s("bd sd,hh*4").coarse("<1 4 8 16 32>") + * + */ + ['coarse'], + /** + * choose the channel the pattern is sent to in superdirt + * + * @name channel + * @param {number | Pattern} channel channel number + * + */ + ['channel'], + /** + * In the style of classic drum-machines, `cut` will stop a playing sample as soon as another samples with in same cutgroup is to be played. An example would be an open hi-hat followed by a closed one, essentially muting the open. + * + * @name cut + * @param {number | Pattern} group cut group number + * @example + * s("rd*4").cut(1) + * + */ + ['cut'], + /** + * Applies the cutoff frequency of the **l**ow-**p**ass **f**ilter. + * + * When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'. + * + * @name lpf + * @param {number | Pattern} frequency audible between 0 and 20000 + * @synonyms cutoff, ctf, lp + * @example + * s("bd sd,hh*3").lpf("<4000 2000 1000 500 200 100>") + * @example + * s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30") + * + */ + [['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'], - /** - * Sets the lowpass filter envelope modulation depth. - * @name lpenv - * @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_ - * @synonyms lpe - * @example - * note("") - * .sound('sawtooth') - * .lpf(500) - * .lpa(.5) - * .lpenv("<4 2 1 0 -1 -2 -4>/4") - */ - ['lpenv', 'lpe'], - /** - * Sets the highpass filter envelope modulation depth. - * @name hpenv - * @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_ - * @synonyms hpe - * @example - * note("") - * .sound('sawtooth') - * .hpf(500) - * .hpa(.5) - * .hpenv("<4 2 1 0 -1 -2 -4>/4") - */ - ['hpenv', 'hpe'], - /** - * Sets the bandpass filter envelope modulation depth. - * @name bpenv - * @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_ - * @synonyms bpe - * @example - * note("") - * .sound('sawtooth') - * .bpf(500) - * .bpa(.5) - * .bpenv("<4 2 1 0 -1 -2 -4>/4") - */ - ['bpenv', 'bpe'], - /** - * Sets the attack duration for the lowpass filter envelope. - * @name lpattack - * @param {number | Pattern} attack time of the filter envelope - * @synonyms lpa - * @example - * note("") - * .sound('sawtooth') - * .lpf(500) - * .lpa("<.5 .25 .1 .01>/4") - * .lpenv(4) - */ - ['lpattack', 'lpa'], - /** - * Sets the attack duration for the highpass filter envelope. - * @name hpattack - * @param {number | Pattern} attack time of the highpass filter envelope - * @synonyms hpa - * @example - * note("") - * .sound('sawtooth') - * .hpf(500) - * .hpa("<.5 .25 .1 .01>/4") - * .hpenv(4) - */ - ['hpattack', 'hpa'], - /** - * Sets the attack duration for the bandpass filter envelope. - * @name bpattack - * @param {number | Pattern} attack time of the bandpass filter envelope - * @synonyms bpa - * @example - * note("") - * .sound('sawtooth') - * .bpf(500) - * .bpa("<.5 .25 .1 .01>/4") - * .bpenv(4) - */ - ['bpattack', 'bpa'], - /** - * Sets the decay duration for the lowpass filter envelope. - * @name lpdecay - * @param {number | Pattern} decay time of the filter envelope - * @synonyms lpd - * @example - * note("") - * .sound('sawtooth') - * .lpf(500) - * .lpd("<.5 .25 .1 0>/4") - * .lps(0.2) - * .lpenv(4) - */ - ['lpdecay', 'lpd'], - /** - * Sets the decay duration for the highpass filter envelope. - * @name hpdecay - * @param {number | Pattern} decay time of the highpass filter envelope - * @synonyms hpd - * @example - * note("") - * .sound('sawtooth') - * .hpf(500) - * .hpd("<.5 .25 .1 0>/4") - * .hps(0.2) - * .hpenv(4) - */ - ['hpdecay', 'hpd'], - /** - * Sets the decay duration for the bandpass filter envelope. - * @name bpdecay - * @param {number | Pattern} decay time of the bandpass filter envelope - * @synonyms bpd - * @example - * note("") - * .sound('sawtooth') - * .bpf(500) - * .bpd("<.5 .25 .1 0>/4") - * .bps(0.2) - * .bpenv(4) - */ - ['bpdecay', 'bpd'], - /** - * Sets the sustain amplitude for the lowpass filter envelope. - * @name lpsustain - * @param {number | Pattern} sustain amplitude of the lowpass filter envelope - * @synonyms lps - * @example - * note("") - * .sound('sawtooth') - * .lpf(500) - * .lpd(.5) - * .lps("<0 .25 .5 1>/4") - * .lpenv(4) - */ - ['lpsustain', 'lps'], - /** - * Sets the sustain amplitude for the highpass filter envelope. - * @name hpsustain - * @param {number | Pattern} sustain amplitude of the highpass filter envelope - * @synonyms hps - * @example - * note("") - * .sound('sawtooth') - * .hpf(500) - * .hpd(.5) - * .hps("<0 .25 .5 1>/4") - * .hpenv(4) - */ - ['hpsustain', 'hps'], - /** - * Sets the sustain amplitude for the bandpass filter envelope. - * @name bpsustain - * @param {number | Pattern} sustain amplitude of the bandpass filter envelope - * @synonyms bps - * @example - * note("") - * .sound('sawtooth') - * .bpf(500) - * .bpd(.5) - * .bps("<0 .25 .5 1>/4") - * .bpenv(4) - */ - ['bpsustain', 'bps'], - /** - * Sets the release time for the lowpass filter envelope. - * @name lprelease - * @param {number | Pattern} release time of the filter envelope - * @synonyms lpr - * @example - * note("") - * .sound('sawtooth') - * .clip(.5) - * .lpf(500) - * .lpenv(4) - * .lpr("<.5 .25 .1 0>/4") - * .release(.5) - */ - ['lprelease', 'lpr'], - /** - * Sets the release time for the highpass filter envelope. - * @name hprelease - * @param {number | Pattern} release time of the highpass filter envelope - * @synonyms hpr - * @example - * note("") - * .sound('sawtooth') - * .clip(.5) - * .hpf(500) - * .hpenv(4) - * .hpr("<.5 .25 .1 0>/4") - * .release(.5) - */ - ['hprelease', 'hpr'], - /** - * Sets the release time for the bandpass filter envelope. - * @name bprelease - * @param {number | Pattern} release time of the bandpass filter envelope - * @synonyms bpr - * @example - * note("") - * .sound('sawtooth') - * .clip(.5) - * .bpf(500) - * .bpenv(4) - * .bpr("<.5 .25 .1 0>/4") - * .release(.5) - */ - ['bprelease', 'bpr'], - /** - * Sets the filter type. The 24db filter is more aggressive. More types might be added in the future. - * @name ftype - * @param {number | Pattern} type 12db (default) or 24db - * @example - * note("") - * .sound('sawtooth') - * .lpf(500) - * .bpenv(4) - * .ftype("<12db 24db>") - */ - ['ftype'], - ['fanchor'], - /** - * Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter. - * - * When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'. - * - * @name hpf - * @param {number | Pattern} frequency audible between 0 and 20000 - * @synonyms hp, hcutoff - * @example - * s("bd sd,hh*4").hpf("<4000 2000 1000 500 200 100>") - * @example - * s("bd sd,hh*4").hpf("<2000 2000:25>") - * - */ - // currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496 - // ['hpf'], - /** - * Applies a vibrato to the frequency of the oscillator. - * - * @name vib - * @synonyms vibrato, v - * @param {number | Pattern} frequency of the vibrato in hertz - * @example - * note("a") - * .vib("<.5 1 2 4 8 16>") - * @example - * // change the modulation depth with ":" - * note("a") - * .vib("<.5 1 2 4 8 16>:12") - */ - [['vib', 'vibmod'], 'vibrato', 'v'], - /** - * Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set - * - * @name vibmod - * @synonyms vmod - * @param {number | Pattern} depth of vibrato (in semitones) - * @example - * note("a").vib(4) - * .vibmod("<.25 .5 1 2 12>") - * @example - * // change the vibrato frequency with ":" - * note("a") - * .vibmod("<.25 .5 1 2 12>:8") - */ - [['vibmod', 'vib'], 'vmod'], - [['hcutoff', 'hresonance'], 'hpf', 'hp'], - /** - * Controls the **h**igh-**p**ass **q**-value. - * - * @name hpq - * @param {number | Pattern} q resonance factor between 0 and 50 - * @synonyms hresonance - * @example - * s("bd sd,hh*4").hpf(2000).hpq("<0 10 20 30>") - * - */ - ['hresonance', 'hpq'], - /** - * Controls the **l**ow-**p**ass **q**-value. - * - * @name lpq - * @param {number | Pattern} q resonance factor between 0 and 50 - * @synonyms resonance - * @example - * s("bd sd,hh*4").lpf(2000).lpq("<0 10 20 30>") - * - */ - // currently an alias of 'resonance' https://github.com/tidalcycles/strudel/issues/496 - ['resonance', 'lpq'], - /** - * DJ filter, below 0.5 is low pass filter, above is high pass filter. - * - * @name djf - * @param {number | Pattern} cutoff below 0.5 is low pass filter, above is high pass filter - * @example - * n("0 3 7 [10,24]").s('superzow').octave(3).djf("<.5 .25 .5 .75>").osc() - * - */ - ['djf'], - // ['cutoffegint'], - // TODO: does not seem to work - /** - * Sets the level of the delay signal. - * - * When using mininotation, you can also optionally add the 'delaytime' and 'delayfeedback' parameter, - * separated by ':'. - * - * - * @name delay - * @param {number | Pattern} level between 0 and 1 - * @example - * s("bd").delay("<0 .25 .5 1>") - * @example - * s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7") - * - */ - [['delay', 'delaytime', 'delayfeedback']], - /** - * Sets the level of the signal that is fed back into the delay. - * Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it - * - * @name delayfeedback - * @param {number | Pattern} feedback between 0 and 1 - * @synonyms delayfb, dfb - * @example - * s("bd").delay(.25).delayfeedback("<.25 .5 .75 1>").slow(2) - * - */ - ['delayfeedback', 'delayfb', 'dfb'], - /** - * Sets the time of the delay effect. - * - * @name delaytime - * @param {number | Pattern} seconds between 0 and Infinity - * @synonyms delayt, dt - * @example - * s("bd").delay(.25).delaytime("<.125 .25 .5 1>").slow(2) - * - */ - ['delaytime', 'delayt', 'dt'], - /* // 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. - * @example - * s("sd").delay().lock(1).osc() - * - */ - ['lock'], - /** - * Set detune of oscillators. Works only with some synths, see tidal doc - * - * @name detune - * @param {number | Pattern} amount between 0 and 1 - * @synonyms det - * @superdirtOnly - * @example - * n("0 3 7").s('superzow').octave(3).detune("<0 .25 .5 1 2>").osc() - * - */ - ['detune', 'det'], - /** - * Set dryness of reverb. See {@link room} and {@link size} for more information about reverb. - * - * @name dry - * @param {number | Pattern} dry 0 = wet, 1 = dry - * @example - * n("[0,3,7](3,8)").s("superpiano").room(.7).dry("<0 .5 .75 1>").osc() - * @superdirtOnly - * - */ - ['dry'], - // TODO: does not seem to do anything - /* - * Used when using {@link begin}/{@link end} or {@link chop}/{@link striate} and friends, to change the fade out time of the 'grain' envelope. - * - * @name fadeTime - * @param {number | Pattern} time between 0 and 1 - * @example - * s("oh*4").end(.1).fadeTime("<0 .2 .4 .8>").osc() - * - */ - ['fadeTime', 'fadeOutTime'], - // TODO: see above - ['fadeInTime'], - /** - * Set frequency of sound. - * - * @name freq - * @param {number | Pattern} frequency in Hz. the audible range is between 20 and 20000 Hz - * @example - * freq("220 110 440 110").s("superzow").osc() - * @example - * freq("110".mul.out(".5 1.5 .6 [2 3]")).s("superzow").osc() - * - */ - ['freq'], - // TODO: https://tidalcycles.org/docs/configuration/MIDIOSC/control-voltage/#gate - ['gate', 'gat'], - // ['hatgrain'], - // ['lagogo'], - // ['lclap'], - // ['lclaves'], - // ['lclhat'], - // ['lcrash'], - // TODO: - // https://tidalcycles.org/docs/reference/audio_effects/#leslie-1 - // https://tidalcycles.org/docs/reference/audio_effects/#leslie - /** - * Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet. - * - * @name leslie - * @param {number | Pattern} wet between 0 and 1 - * @example - * n("0,4,7").s("supersquare").leslie("<0 .4 .6 1>").osc() - * @superdirtOnly - * - */ - ['leslie'], - /** - * Rate of modulation / rotation for leslie effect - * - * @name lrate - * @param {number | Pattern} rate 6.7 for fast, 0.7 for slow - * @example - * n("0,4,7").s("supersquare").leslie(1).lrate("<1 2 4 8>").osc() - * @superdirtOnly - * - */ - // TODO: the rate seems to "lag" (in the example, 1 will be fast) - ['lrate'], - /** - * Physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble) - * - * @name lsize - * @param {number | Pattern} meters somewhere between 0 and 1 - * @example - * n("0,4,7").s("supersquare").leslie(1).lrate(2).lsize("<.1 .5 1>").osc() - * @superdirtOnly - * - */ - ['lsize'], - // label for pianoroll - ['activeLabel'], - [['label', 'activeLabel']], - // ['lfo'], - // ['lfocutoffint'], - // ['lfodelay'], - // ['lfoint'], - // ['lfopitchint'], - // ['lfoshape'], - // ['lfosync'], - // ['lhitom'], - // ['lkick'], - // ['llotom'], - // ['lophat'], - // ['lsnare'], - ['degree'], // TODO: what is this? not found in tidal doc - ['mtranspose'], // TODO: what is this? not found in tidal doc - ['ctranspose'], // TODO: what is this? not found in tidal doc - ['harmonic'], // TODO: what is this? not found in tidal doc - ['stepsPerOctave'], // TODO: what is this? not found in tidal doc - ['octaveR'], // TODO: what is this? not found in tidal doc - // TODO: why is this needed? what's the difference to late / early? Answer: it's in seconds, and delays the message at - // OSC time (so can't be negative, at least not beyond the latency value) - ['nudge'], - // TODO: the following doc is just a guess, it's not documented in tidal doc. - /** - * Sets the default octave of a synth. - * - * @name octave - * @param {number | Pattern} octave octave number - * @example - * n("0,4,7").s('supersquare').octave("<3 4 5 6>").osc() - * @superDirtOnly - */ - ['octave'], + /** + * Sets the lowpass filter envelope modulation depth. + * @name lpenv + * @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_ + * @synonyms lpe + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpa(.5) + * .lpenv("<4 2 1 0 -1 -2 -4>/4") + */ + ['lpenv', 'lpe'], + /** + * Sets the highpass filter envelope modulation depth. + * @name hpenv + * @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_ + * @synonyms hpe + * @example + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpa(.5) + * .hpenv("<4 2 1 0 -1 -2 -4>/4") + */ + ['hpenv', 'hpe'], + /** + * Sets the bandpass filter envelope modulation depth. + * @name bpenv + * @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_ + * @synonyms bpe + * @example + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpa(.5) + * .bpenv("<4 2 1 0 -1 -2 -4>/4") + */ + ['bpenv', 'bpe'], + /** + * Sets the attack duration for the lowpass filter envelope. + * @name lpattack + * @param {number | Pattern} attack time of the filter envelope + * @synonyms lpa + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpa("<.5 .25 .1 .01>/4") + * .lpenv(4) + */ + ['lpattack', 'lpa'], + /** + * Sets the attack duration for the highpass filter envelope. + * @name hpattack + * @param {number | Pattern} attack time of the highpass filter envelope + * @synonyms hpa + * @example + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpa("<.5 .25 .1 .01>/4") + * .hpenv(4) + */ + ['hpattack', 'hpa'], + /** + * Sets the attack duration for the bandpass filter envelope. + * @name bpattack + * @param {number | Pattern} attack time of the bandpass filter envelope + * @synonyms bpa + * @example + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpa("<.5 .25 .1 .01>/4") + * .bpenv(4) + */ + ['bpattack', 'bpa'], + /** + * Sets the decay duration for the lowpass filter envelope. + * @name lpdecay + * @param {number | Pattern} decay time of the filter envelope + * @synonyms lpd + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpd("<.5 .25 .1 0>/4") + * .lps(0.2) + * .lpenv(4) + */ + ['lpdecay', 'lpd'], + /** + * Sets the decay duration for the highpass filter envelope. + * @name hpdecay + * @param {number | Pattern} decay time of the highpass filter envelope + * @synonyms hpd + * @example + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpd("<.5 .25 .1 0>/4") + * .hps(0.2) + * .hpenv(4) + */ + ['hpdecay', 'hpd'], + /** + * Sets the decay duration for the bandpass filter envelope. + * @name bpdecay + * @param {number | Pattern} decay time of the bandpass filter envelope + * @synonyms bpd + * @example + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpd("<.5 .25 .1 0>/4") + * .bps(0.2) + * .bpenv(4) + */ + ['bpdecay', 'bpd'], + /** + * Sets the sustain amplitude for the lowpass filter envelope. + * @name lpsustain + * @param {number | Pattern} sustain amplitude of the lowpass filter envelope + * @synonyms lps + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .lpd(.5) + * .lps("<0 .25 .5 1>/4") + * .lpenv(4) + */ + ['lpsustain', 'lps'], + /** + * Sets the sustain amplitude for the highpass filter envelope. + * @name hpsustain + * @param {number | Pattern} sustain amplitude of the highpass filter envelope + * @synonyms hps + * @example + * note("") + * .sound('sawtooth') + * .hpf(500) + * .hpd(.5) + * .hps("<0 .25 .5 1>/4") + * .hpenv(4) + */ + ['hpsustain', 'hps'], + /** + * Sets the sustain amplitude for the bandpass filter envelope. + * @name bpsustain + * @param {number | Pattern} sustain amplitude of the bandpass filter envelope + * @synonyms bps + * @example + * note("") + * .sound('sawtooth') + * .bpf(500) + * .bpd(.5) + * .bps("<0 .25 .5 1>/4") + * .bpenv(4) + */ + ['bpsustain', 'bps'], + /** + * Sets the release time for the lowpass filter envelope. + * @name lprelease + * @param {number | Pattern} release time of the filter envelope + * @synonyms lpr + * @example + * note("") + * .sound('sawtooth') + * .clip(.5) + * .lpf(500) + * .lpenv(4) + * .lpr("<.5 .25 .1 0>/4") + * .release(.5) + */ + ['lprelease', 'lpr'], + /** + * Sets the release time for the highpass filter envelope. + * @name hprelease + * @param {number | Pattern} release time of the highpass filter envelope + * @synonyms hpr + * @example + * note("") + * .sound('sawtooth') + * .clip(.5) + * .hpf(500) + * .hpenv(4) + * .hpr("<.5 .25 .1 0>/4") + * .release(.5) + */ + ['hprelease', 'hpr'], + /** + * Sets the release time for the bandpass filter envelope. + * @name bprelease + * @param {number | Pattern} release time of the bandpass filter envelope + * @synonyms bpr + * @example + * note("") + * .sound('sawtooth') + * .clip(.5) + * .bpf(500) + * .bpenv(4) + * .bpr("<.5 .25 .1 0>/4") + * .release(.5) + */ + ['bprelease', 'bpr'], + /** + * Sets the filter type. The 24db filter is more aggressive. More types might be added in the future. + * @name ftype + * @param {number | Pattern} type 12db (default) or 24db + * @example + * note("") + * .sound('sawtooth') + * .lpf(500) + * .bpenv(4) + * .ftype("<12db 24db>") + */ + ['ftype'], + ['fanchor'], + /** + * Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter. + * + * When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'. + * + * @name hpf + * @param {number | Pattern} frequency audible between 0 and 20000 + * @synonyms hp, hcutoff + * @example + * s("bd sd,hh*4").hpf("<4000 2000 1000 500 200 100>") + * @example + * s("bd sd,hh*4").hpf("<2000 2000:25>") + * + */ + // currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496 + // ['hpf'], + /** + * Applies a vibrato to the frequency of the oscillator. + * + * @name vib + * @synonyms vibrato, v + * @param {number | Pattern} frequency of the vibrato in hertz + * @example + * note("a") + * .vib("<.5 1 2 4 8 16>") + * @example + * // change the modulation depth with ":" + * note("a") + * .vib("<.5 1 2 4 8 16>:12") + */ + [['vib', 'vibmod'], 'vibrato', 'v'], + /** + * Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set + * + * @name vibmod + * @synonyms vmod + * @param {number | Pattern} depth of vibrato (in semitones) + * @example + * note("a").vib(4) + * .vibmod("<.25 .5 1 2 12>") + * @example + * // change the vibrato frequency with ":" + * note("a") + * .vibmod("<.25 .5 1 2 12>:8") + */ + [['vibmod', 'vib'], 'vmod'], + [['hcutoff', 'hresonance'], 'hpf', 'hp'], + /** + * Controls the **h**igh-**p**ass **q**-value. + * + * @name hpq + * @param {number | Pattern} q resonance factor between 0 and 50 + * @synonyms hresonance + * @example + * s("bd sd,hh*4").hpf(2000).hpq("<0 10 20 30>") + * + */ + ['hresonance', 'hpq'], + /** + * Controls the **l**ow-**p**ass **q**-value. + * + * @name lpq + * @param {number | Pattern} q resonance factor between 0 and 50 + * @synonyms resonance + * @example + * s("bd sd,hh*4").lpf(2000).lpq("<0 10 20 30>") + * + */ + // currently an alias of 'resonance' https://github.com/tidalcycles/strudel/issues/496 + ['resonance', 'lpq'], + /** + * DJ filter, below 0.5 is low pass filter, above is high pass filter. + * + * @name djf + * @param {number | Pattern} cutoff below 0.5 is low pass filter, above is high pass filter + * @example + * n("0 3 7 [10,24]").s('superzow').octave(3).djf("<.5 .25 .5 .75>").osc() + * + */ + ['djf'], + // ['cutoffegint'], + // TODO: does not seem to work + /** + * Sets the level of the delay signal. + * + * When using mininotation, you can also optionally add the 'delaytime' and 'delayfeedback' parameter, + * separated by ':'. + * + * + * @name delay + * @param {number | Pattern} level between 0 and 1 + * @example + * s("bd").delay("<0 .25 .5 1>") + * @example + * s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7") + * + */ + [['delay', 'delaytime', 'delayfeedback']], + /** + * Sets the level of the signal that is fed back into the delay. + * Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it + * + * @name delayfeedback + * @param {number | Pattern} feedback between 0 and 1 + * @synonyms delayfb, dfb + * @example + * s("bd").delay(.25).delayfeedback("<.25 .5 .75 1>").slow(2) + * + */ + ['delayfeedback', 'delayfb', 'dfb'], + /** + * Sets the time of the delay effect. + * + * @name delaytime + * @param {number | Pattern} seconds between 0 and Infinity + * @synonyms delayt, dt + * @example + * s("bd").delay(.25).delaytime("<.125 .25 .5 1>").slow(2) + * + */ + ['delaytime', 'delayt', 'dt'], + /* // 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. + * @example + * s("sd").delay().lock(1).osc() + * + */ + ['lock'], + /** + * Set detune of oscillators. Works only with some synths, see tidal doc + * + * @name detune + * @param {number | Pattern} amount between 0 and 1 + * @synonyms det + * @superdirtOnly + * @example + * n("0 3 7").s('superzow').octave(3).detune("<0 .25 .5 1 2>").osc() + * + */ + ['detune', 'det'], + /** + * Set dryness of reverb. See {@link room} and {@link size} for more information about reverb. + * + * @name dry + * @param {number | Pattern} dry 0 = wet, 1 = dry + * @example + * n("[0,3,7](3,8)").s("superpiano").room(.7).dry("<0 .5 .75 1>").osc() + * @superdirtOnly + * + */ + ['dry'], + // TODO: does not seem to do anything + /* + * Used when using {@link begin}/{@link end} or {@link chop}/{@link striate} and friends, to change the fade out time of the 'grain' envelope. + * + * @name fadeTime + * @param {number | Pattern} time between 0 and 1 + * @example + * s("oh*4").end(.1).fadeTime("<0 .2 .4 .8>").osc() + * + */ + ['fadeTime', 'fadeOutTime'], + // TODO: see above + ['fadeInTime'], + /** + * Set frequency of sound. + * + * @name freq + * @param {number | Pattern} frequency in Hz. the audible range is between 20 and 20000 Hz + * @example + * freq("220 110 440 110").s("superzow").osc() + * @example + * freq("110".mul.out(".5 1.5 .6 [2 3]")).s("superzow").osc() + * + */ + ['freq'], + // TODO: https://tidalcycles.org/docs/configuration/MIDIOSC/control-voltage/#gate + ['gate', 'gat'], + // ['hatgrain'], + // ['lagogo'], + // ['lclap'], + // ['lclaves'], + // ['lclhat'], + // ['lcrash'], + // TODO: + // https://tidalcycles.org/docs/reference/audio_effects/#leslie-1 + // https://tidalcycles.org/docs/reference/audio_effects/#leslie + /** + * Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet. + * + * @name leslie + * @param {number | Pattern} wet between 0 and 1 + * @example + * n("0,4,7").s("supersquare").leslie("<0 .4 .6 1>").osc() + * @superdirtOnly + * + */ + ['leslie'], + /** + * Rate of modulation / rotation for leslie effect + * + * @name lrate + * @param {number | Pattern} rate 6.7 for fast, 0.7 for slow + * @example + * n("0,4,7").s("supersquare").leslie(1).lrate("<1 2 4 8>").osc() + * @superdirtOnly + * + */ + // TODO: the rate seems to "lag" (in the example, 1 will be fast) + ['lrate'], + /** + * Physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble) + * + * @name lsize + * @param {number | Pattern} meters somewhere between 0 and 1 + * @example + * n("0,4,7").s("supersquare").leslie(1).lrate(2).lsize("<.1 .5 1>").osc() + * @superdirtOnly + * + */ + ['lsize'], + // label for pianoroll + ['activeLabel'], + [['label', 'activeLabel']], + // ['lfo'], + // ['lfocutoffint'], + // ['lfodelay'], + // ['lfoint'], + // ['lfopitchint'], + // ['lfoshape'], + // ['lfosync'], + // ['lhitom'], + // ['lkick'], + // ['llotom'], + // ['lophat'], + // ['lsnare'], + ['degree'], // TODO: what is this? not found in tidal doc + ['mtranspose'], // TODO: what is this? not found in tidal doc + ['ctranspose'], // TODO: what is this? not found in tidal doc + ['harmonic'], // TODO: what is this? not found in tidal doc + ['stepsPerOctave'], // TODO: what is this? not found in tidal doc + ['octaveR'], // TODO: what is this? not found in tidal doc + // TODO: why is this needed? what's the difference to late / early? Answer: it's in seconds, and delays the message at + // OSC time (so can't be negative, at least not beyond the latency value) + ['nudge'], + // TODO: the following doc is just a guess, it's not documented in tidal doc. + /** + * Sets the default octave of a synth. + * + * @name octave + * @param {number | Pattern} octave octave number + * @example + * n("0,4,7").s('supersquare').octave("<3 4 5 6>").osc() + * @superDirtOnly + */ + ['octave'], - // ['ophatdecay'], - // TODO: example - /** - * An `orbit` is a global parameter context for patterns. Patterns with the same orbit will share the same global effects. - * - * @name orbit - * @param {number | Pattern} number - * @example - * stack( - * s("hh*3").delay(.5).delaytime(.25).orbit(1), - * s("~ sd").delay(.5).delaytime(.125).orbit(2) - * ) - */ - ['orbit'], - ['overgain'], // TODO: what is this? not found in tidal doc Answer: gain is limited to maximum of 2. This allows you to go over that - ['overshape'], // TODO: what is this? not found in tidal doc. Similar to above, but limited to 1 - /** - * Sets position in stereo. - * - * @name pan - * @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel) - * @example - * s("[bd hh]*2").pan("<.5 1 .5 0>") - * - */ - ['pan'], - // TODO: this has no effect (see example) - /* - * Controls how much multichannel output is fanned out - * - * @name panspan - * @param {number | Pattern} span between -inf and inf, negative is backwards ordering - * @example - * s("[bd hh]*2").pan("<.5 1 .5 0>").panspan("<0 .5 1>").osc() - * - */ - ['panspan'], - // TODO: this has no effect (see example) - /* - * Controls how much multichannel output is spread - * - * @name pansplay - * @param {number | Pattern} spread between 0 and 1 - * @example - * s("[bd hh]*2").pan("<.5 1 .5 0>").pansplay("<0 .5 1>").osc() - * - */ - ['pansplay'], - ['panwidth'], - ['panorient'], - // ['pitch1'], - // ['pitch2'], - // ['pitch3'], - // ['portamento'], - // TODO: LFO rate see https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare - ['rate'], - // TODO: slide param for certain synths - ['slide'], - // TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare - ['semitone'], - // TODO: dedup with synth param, see https://tidalcycles.org/docs/reference/synthesizers/#superpiano - // ['velocity'], - ['voice'], // TODO: synth param + // ['ophatdecay'], + // TODO: example + /** + * An `orbit` is a global parameter context for patterns. Patterns with the same orbit will share the same global effects. + * + * @name orbit + * @param {number | Pattern} number + * @example + * stack( + * s("hh*3").delay(.5).delaytime(.25).orbit(1), + * s("~ sd").delay(.5).delaytime(.125).orbit(2) + * ) + */ + ['orbit'], + ['overgain'], // TODO: what is this? not found in tidal doc Answer: gain is limited to maximum of 2. This allows you to go over that + ['overshape'], // TODO: what is this? not found in tidal doc. Similar to above, but limited to 1 + /** + * Sets position in stereo. + * + * @name pan + * @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel) + * @example + * s("[bd hh]*2").pan("<.5 1 .5 0>") + * + */ + ['pan'], + // TODO: this has no effect (see example) + /* + * Controls how much multichannel output is fanned out + * + * @name panspan + * @param {number | Pattern} span between -inf and inf, negative is backwards ordering + * @example + * s("[bd hh]*2").pan("<.5 1 .5 0>").panspan("<0 .5 1>").osc() + * + */ + ['panspan'], + // TODO: this has no effect (see example) + /* + * Controls how much multichannel output is spread + * + * @name pansplay + * @param {number | Pattern} spread between 0 and 1 + * @example + * s("[bd hh]*2").pan("<.5 1 .5 0>").pansplay("<0 .5 1>").osc() + * + */ + ['pansplay'], + ['panwidth'], + ['panorient'], + // ['pitch1'], + // ['pitch2'], + // ['pitch3'], + // ['portamento'], + // TODO: LFO rate see https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare + ['rate'], + // TODO: slide param for certain synths + ['slide'], + // TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare + ['semitone'], + // TODO: dedup with synth param, see https://tidalcycles.org/docs/reference/synthesizers/#superpiano + // ['velocity'], + ['voice'], // TODO: synth param - // voicings // https://github.com/tidalcycles/strudel/issues/506 - ['chord'], // chord to voice, like C Eb Fm7 G7. the symbols can be defined via addVoicings - ['dictionary', 'dict'], // which dictionary to use for the voicings - ['anchor'], // the top note to align the voicing to, defaults to c5 - ['offset'], // how the voicing is offset from the anchored position - ['octaves'], // how many octaves are voicing steps spread apart, defaults to 1 - [['mode', 'anchor']], // below = anchor note will be removed from the voicing, useful for melody harmonization + // voicings // https://github.com/tidalcycles/strudel/issues/506 + ['chord'], // chord to voice, like C Eb Fm7 G7. the symbols can be defined via addVoicings + ['dictionary', 'dict'], // which dictionary to use for the voicings + ['anchor'], // the top note to align the voicing to, defaults to c5 + ['offset'], // how the voicing is offset from the anchored position + ['octaves'], // how many octaves are voicing steps spread apart, defaults to 1 + [['mode', 'anchor']], // below = anchor note will be removed from the voicing, useful for melody harmonization - /** - * Sets the level of reverb. - * - * When using mininotation, you can also optionally add the 'size' parameter, separated by ':'. - * - * @name room - * @param {number | Pattern} level between 0 and 1 - * @example - * s("bd sd").room("<0 .2 .4 .6 .8 1>") - * @example - * s("bd sd").room("<0.9:1 0.9:4>") - * - */ - [['room', 'size']], - /** - * Sets the room size of the reverb, see {@link room}. - * - * @name roomsize - * @param {number | Pattern} size between 0 and 10 - * @synonyms size, sz - * @example - * s("bd sd").room(.8).roomsize("<0 1 2 4 8>") - * - */ - // TODO: find out why : - // s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc() - // .. does not work. Is it because room is only one effect? - ['size', 'sz', 'roomsize'], - // ['sagogo'], - // ['sclap'], - // ['sclaves'], - // ['scrash'], + /** + * Sets the level of reverb. + * + * When using mininotation, you can also optionally add the 'size' parameter, separated by ':'. + * + * @name room + * @param {number | Pattern} level between 0 and 1 + * @example + * s("bd sd").room("<0 .2 .4 .6 .8 1>") + * @example + * s("bd sd").room("<0.9:1 0.9:4>") + * + */ + [['room', 'size']], + /** + * Sets the room size of the reverb, see {@link room}. + * + * @name roomsize + * @param {number | Pattern} size between 0 and 10 + * @synonyms size, sz + * @example + * s("bd sd").room(.8).roomsize("<0 1 2 4 8>") + * + */ - /** - * Sets the sample to use as an impulse response for the reverb. - * - * @name iresponse - * @param {string | Pattern} Sets the impulse response - * @example - * s("bd sd").room(.8).ir("") - * - */ - [['ir', 'i'], 'iresponse'], - /** - * Wave shaping distortion. CAUTION: it might get loud - * - * @name shape - * @param {number | Pattern} distortion between 0 and 1 - * @example - * s("bd sd,hh*4").shape("<0 .2 .4 .6 .8>") - * - */ - ['shape'], - /** - * Changes the speed of sample playback, i.e. a cheap way of changing pitch. - * - * @name speed - * @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards. - * @example - * s("bd").speed("<1 2 4 1 -2 -4>") - * @example - * speed("1 1.5*2 [2 1.1]").s("piano").clip(1) - * - */ - ['speed'], - /** - * Used in conjunction with {@link speed}, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`. - * - * @name unit - * @param {number | string | Pattern} unit see description above - * @example - * speed("1 2 .5 3").s("bd").unit("c").osc() - * @superdirtOnly - * - */ - ['unit'], - /** - * Made by Calum Gunn. Reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter. The SuperCollider manual defines Squiz as: - * - * "A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated." - * - * @name squiz - * @param {number | Pattern} squiz Try passing multiples of 2 to it - 2, 4, 8 etc. - * @example - * squiz("2 4/2 6 [8 16]").s("bd").osc() - * @superdirtOnly - * - */ - ['squiz'], - // ['stutterdepth'], // TODO: what is this? not found in tidal doc - // ['stuttertime'], // TODO: what is this? not found in tidal doc - // ['timescale'], // TODO: what is this? not found in tidal doc - // ['timescalewin'], // TODO: what is this? not found in tidal doc - // ['tomdecay'], - // ['vcfegint'], - // ['vcoegint'], - // TODO: Use a rest (~) to override the effect <- vowel - /** - * - * Formant filter to make things sound like vowels. - * - * @name vowel - * @param {string | Pattern} vowel You can use a e i o u. - * @example - * note("c2 >").s('sawtooth') - * .vowel(">") - * - */ - ['vowel'], - /* // TODO: find out how it works - * Made by Calum Gunn. Divides an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discards a fraction of them. Takes a number between 1 and 100, denoted the percentage of segments to drop. The SuperCollider manual describes the Waveloss effect this way: - * - * Divide an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discard a fraction of them (i.e. replace them with silence of the same length). The technique was described by Trevor Wishart in a lecture. Parameters: the filter drops drop out of out of chunks. mode can be 1 to drop chunks in a simple deterministic fashion (e.g. always dropping the first 30 out of a set of 40 segments), or 2 to drop chunks randomly but in an appropriate proportion.) - * - * mode: ? - * waveloss: ? - * - * @name waveloss - */ - ['waveloss'], - // TODO: midi effects? - ['dur'], - // ['modwheel'], - ['expression'], - ['sustainpedal'], - /* // TODO: doesn't seem to do anything - * - * Tremolo Audio DSP effect - * - * @name tremolodepth - * @param {number | Pattern} depth between 0 and 1 - * @example - * n("0,4,7").tremolodepth("<0 .3 .6 .9>").osc() - * - */ - ['tremolodepth', 'tremdp'], - ['tremolorate', 'tremr'], - // TODO: doesn't seem to do anything - ['phaserdepth', 'phasdp'], - ['phaserrate', 'phasr'], + // TODO: find out why : + // s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc() + // .. does not work. Is it because room is only one effect? + ['size', 'sz', 'roomsize'], + // ['sagogo'], + // ['sclap'], + // ['sclaves'], + // ['scrash'], - ['fshift'], - ['fshiftnote'], - ['fshiftphase'], + /** + * Sets the sample to use as an impulse response for the reverb. + * + * @name iresponse + * @param {string | Pattern} Sets the impulse response + * @example + * s("bd sd").room(.8).ir("") + * + */ + [['ir', 'i'], 'iresponse'], - ['triode'], - ['krush'], - ['kcutoff'], - ['octer'], - ['octersub'], - ['octersubsub'], - ['ring'], - ['ringf'], - ['ringdf'], - ['distort'], - ['freeze'], - ['xsdelay'], - ['tsdelay'], - ['real'], - ['imag'], - ['enhance'], - ['partials'], - ['comb'], - ['smear'], - ['scram'], - ['binshift'], - ['hbrick'], - ['lbrick'], - ['midichan'], - ['control'], - ['ccn'], - ['ccv'], - ['polyTouch'], - ['midibend'], - ['miditouch'], - ['ctlNum'], - ['frameRate'], - ['frames'], - ['hours'], - ['midicmd'], - ['minutes'], - ['progNum'], - ['seconds'], - ['songPtr'], - ['uid'], - ['val'], - ['cps'], - /** - * Multiplies the duration with the given number. Also cuts samples off at the end if they exceed the duration. - * In tidal, this would be done with legato, [which has a complicated history in strudel](https://github.com/tidalcycles/strudel/issues/111). - * For now, if you're coming from tidal, just think clip = legato. - * - * @name clip - * @param {number | Pattern} factor >= 0 - * @example - * note("c a f e").s("piano").clip("<.5 1 2>") - * - */ - ['clip'], + /** + * Wave shaping distortion. CAUTION: it might get loud + * + * @name shape + * @param {number | Pattern} distortion between 0 and 1 + * @example + * s("bd sd,hh*4").shape("<0 .2 .4 .6 .8>") + * + */ + ['shape'], + /** + * Changes the speed of sample playback, i.e. a cheap way of changing pitch. + * + * @name speed + * @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards. + * @example + * s("bd").speed("<1 2 4 1 -2 -4>") + * @example + * speed("1 1.5*2 [2 1.1]").s("piano").clip(1) + * + */ + ['speed'], + /** + * Used in conjunction with {@link speed}, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`. + * + * @name unit + * @param {number | string | Pattern} unit see description above + * @example + * speed("1 2 .5 3").s("bd").unit("c").osc() + * @superdirtOnly + * + */ + ['unit'], + /** + * Made by Calum Gunn. Reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter. The SuperCollider manual defines Squiz as: + * + * "A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated." + * + * @name squiz + * @param {number | Pattern} squiz Try passing multiples of 2 to it - 2, 4, 8 etc. + * @example + * squiz("2 4/2 6 [8 16]").s("bd").osc() + * @superdirtOnly + * + */ + ['squiz'], + // ['stutterdepth'], // TODO: what is this? not found in tidal doc + // ['stuttertime'], // TODO: what is this? not found in tidal doc + // ['timescale'], // TODO: what is this? not found in tidal doc + // ['timescalewin'], // TODO: what is this? not found in tidal doc + // ['tomdecay'], + // ['vcfegint'], + // ['vcoegint'], + // TODO: Use a rest (~) to override the effect <- vowel + /** + * + * Formant filter to make things sound like vowels. + * + * @name vowel + * @param {string | Pattern} vowel You can use a e i o u. + * @example + * note("c2 >").s('sawtooth') + * .vowel(">") + * + */ + ['vowel'], + /* // TODO: find out how it works + * Made by Calum Gunn. Divides an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discards a fraction of them. Takes a number between 1 and 100, denoted the percentage of segments to drop. The SuperCollider manual describes the Waveloss effect this way: + * + * Divide an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discard a fraction of them (i.e. replace them with silence of the same length). The technique was described by Trevor Wishart in a lecture. Parameters: the filter drops drop out of out of chunks. mode can be 1 to drop chunks in a simple deterministic fashion (e.g. always dropping the first 30 out of a set of 40 segments), or 2 to drop chunks randomly but in an appropriate proportion.) + * + * mode: ? + * waveloss: ? + * + * @name waveloss + */ + ['waveloss'], + // TODO: midi effects? + ['dur'], + // ['modwheel'], + ['expression'], + ['sustainpedal'], + /* // TODO: doesn't seem to do anything + * + * Tremolo Audio DSP effect + * + * @name tremolodepth + * @param {number | Pattern} depth between 0 and 1 + * @example + * n("0,4,7").tremolodepth("<0 .3 .6 .9>").osc() + * + */ + ['tremolodepth', 'tremdp'], + ['tremolorate', 'tremr'], + // TODO: doesn't seem to do anything + ['phaserdepth', 'phasdp'], + ['phaserrate', 'phasr'], - // ZZFX - ['zrand'], - ['curve'], - ['slide'], // superdirt duplicate - ['deltaSlide'], - ['pitchJump'], - ['pitchJumpTime'], - ['lfo', 'repeatTime'], - ['noise'], - ['zmod'], - ['zcrush'], // like crush but scaled differently - ['zdelay'], - ['tremolo'], - ['zzfx'], + ['fshift'], + ['fshiftnote'], + ['fshiftphase'], + + ['triode'], + ['krush'], + ['kcutoff'], + ['octer'], + ['octersub'], + ['octersubsub'], + ['ring'], + ['ringf'], + ['ringdf'], + ['distort'], + ['freeze'], + ['xsdelay'], + ['tsdelay'], + ['real'], + ['imag'], + ['enhance'], + ['partials'], + ['comb'], + ['smear'], + ['scram'], + ['binshift'], + ['hbrick'], + ['lbrick'], + ['midichan'], + ['control'], + ['ccn'], + ['ccv'], + ['polyTouch'], + ['midibend'], + ['miditouch'], + ['ctlNum'], + ['frameRate'], + ['frames'], + ['hours'], + ['midicmd'], + ['minutes'], + ['progNum'], + ['seconds'], + ['songPtr'], + ['uid'], + ['val'], + ['cps'], + /** + * Multiplies the duration with the given number. Also cuts samples off at the end if they exceed the duration. + * In tidal, this would be done with legato, [which has a complicated history in strudel](https://github.com/tidalcycles/strudel/issues/111). + * For now, if you're coming from tidal, just think clip = legato. + * + * @name clip + * @param {number | Pattern} factor >= 0 + * @example + * note("c a f e").s("piano").clip("<.5 1 2>") + * + */ + ['clip'], + + // ZZFX + ['zrand'], + ['curve'], + ['slide'], // superdirt duplicate + ['deltaSlide'], + ['pitchJump'], + ['pitchJumpTime'], + ['lfo', 'repeatTime'], + ['noise'], + ['zmod'], + ['zcrush'], // like crush but scaled differently + ['zdelay'], + ['tremolo'], + ['zzfx'], ]; // TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13 controls.createParam = function (names) { - const name = Array.isArray(names) ? names[0] : names; + const name = Array.isArray(names) ? names[0] : names; - var withVal; - if (Array.isArray(names)) { - withVal = (xs) => { - if (Array.isArray(xs)) { - const result = {}; - xs.forEach((x, i) => { - if (i < names.length) { - result[names[i]] = x; - } - }); - return result; - } else { - return {[name]: xs}; - } - }; - } else { - withVal = (x) => ({[name]: x}); - } - - const func = (...pats) => sequence(...pats).withValue(withVal); - - const setter = function (...pats) { - if (!pats.length) { - return this.fmap(withVal); - } - return this.set(func(...pats)); + var withVal; + if (Array.isArray(names)) { + withVal = (xs) => { + if (Array.isArray(xs)) { + const result = {}; + xs.forEach((x, i) => { + if (i < names.length) { + result[names[i]] = x; + } + }); + return result; + } else { + return { [name]: xs }; + } }; - Pattern.prototype[name] = setter; - return func; + } else { + withVal = (x) => ({ [name]: x }); + } + + const func = (...pats) => sequence(...pats).withValue(withVal); + + const setter = function (...pats) { + if (!pats.length) { + return this.fmap(withVal); + } + return this.set(func(...pats)); + }; + Pattern.prototype[name] = setter; + return func; }; generic_params.forEach(([names, ...aliases]) => { - const name = Array.isArray(names) ? names[0] : names; - controls[name] = controls.createParam(names); + const name = Array.isArray(names) ? names[0] : names; + controls[name] = controls.createParam(names); - aliases.forEach((alias) => { - controls[alias] = controls[name]; - Pattern.prototype[alias] = Pattern.prototype[name]; - }); + aliases.forEach((alias) => { + controls[alias] = controls[name]; + Pattern.prototype[alias] = Pattern.prototype[name]; + }); }); controls.createParams = (...names) => - names.reduce((acc, name) => Object.assign(acc, {[name]: controls.createParam(name)}), {}); + names.reduce((acc, name) => Object.assign(acc, { [name]: controls.createParam(name) }), {}); controls.adsr = register('adsr', (adsr, pat) => { - adsr = !Array.isArray(adsr) ? [adsr] : adsr; - const [attack, decay, sustain, release] = adsr; - return pat.set({attack, decay, sustain, release}); + adsr = !Array.isArray(adsr) ? [adsr] : adsr; + const [attack, decay, sustain, release] = adsr; + return pat.set({ attack, decay, sustain, release }); }); controls.ds = register('ds', (ds, pat) => { - ds = !Array.isArray(ds) ? [ds] : ds; - const [decay, sustain] = ds; - return pat.set({decay, sustain}); + ds = !Array.isArray(ds) ? [ds] : ds; + const [decay, sustain] = ds; + return pat.set({ decay, sustain }); }); export default controls; diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index 72709085..e72af033 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -7,22 +7,31 @@ if (typeof AudioContext !== 'undefined') { return impulse; }; + AudioContext.prototype.adjustLength = function (duration, buffer) { + const newLength = buffer.sampleRate * duration; + const newBuffer = this.createBuffer(buffer.numberOfChannels, buffer.length, buffer.sampleRate); + for (let channel = 0; channel < buffer.numberOfChannels; channel++) { + let oldData = buffer.getChannelData(channel); + let newData = newBuffer.getChannelData(channel); + + for (let i = 0; i < newLength; i++) { + newData[i] = oldData[i] || 0; + } + } + return newBuffer; + }; + AudioContext.prototype.createReverb = function (duration, buffer) { const convolver = this.createConvolver(); - convolver.setDuration = (d, i) => { - convolver.buffer = i !== undefined ? buffer : this.impulseResponse(d); - convolver.duration = d; + convolver.setDuration = (dur, imp) => { + convolver.buffer = imp ? this.adjustLength(dur, imp) : this.impulseResponse(dur); return convolver; }; - convolver.setIR = (i) => { - convolver.buffer = i; + convolver.setIR = (dur, imp) => { + convolver.buffer = imp ? this.adjustLength(dur, imp) : this.impulseResponse(dur); return convolver; }; - if (buffer !== undefined) { - convolver.setIR(buffer); - } else { - convolver.setDuration(duration); - } + convolver.setDuration(duration, buffer); return convolver; }; } diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 2b46ae3c..b61c9568 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -122,11 +122,11 @@ function getReverb(orbit, duration = 2, ir) { reverbs[orbit] = reverb; } if (reverbs[orbit].duration !== duration) { - reverbs[orbit] = reverbs[orbit].setDuration(duration); + reverbs[orbit] = reverbs[orbit].setDuration(duration, ir); reverbs[orbit].duration = duration; } if (reverbs[orbit].ir !== ir) { - reverbs[orbit] = reverbs[orbit].setIR(ir); + reverbs[orbit] = reverbs[orbit].setIR(duration, ir); reverbs[orbit].ir = ir; } return reverbs[orbit]; @@ -368,9 +368,14 @@ export const superdough = async (value, deadline, hapDuration) => { } // reverb let buffer; + let url; if (ir !== undefined) { let sample = getSound(ir); - let url = sample.data.samples[i % sample.data.samples.length]; + if (Array.isArray(sample)) { + url = sample.data.samples[i % sample.data.samples.length]; + } else if (typeof sample === 'object') { + url = Object.values(sample.data.samples)[i & Object.values(sample.data.samples).length]; + } buffer = await loadBuffer(url, ac, ir, 0); } let reverbSend; From ac9c629c0b271790b5b39d0efd5e4ac63480aa2a Mon Sep 17 00:00:00 2001 From: Vasilii Milovidov Date: Sun, 1 Oct 2023 15:36:52 +0400 Subject: [PATCH 117/175] cleanup --- packages/superdough/superdough.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index b61c9568..fdf42c02 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -163,7 +163,7 @@ export function getAnalyzerData(type = 'time') { return analyserData; } -function effectSend(input, effect, wet, size) { +function effectSend(input, effect, wet) { const send = gainNode(wet); input.connect(send); send.connect(effect); @@ -381,7 +381,7 @@ export const superdough = async (value, deadline, hapDuration) => { let reverbSend; if (room > 0 && size > 0) { const reverbNode = getReverb(orbit, size, buffer); - reverbSend = effectSend(post, reverbNode, room, size); + reverbSend = effectSend(post, reverbNode, room); } // analyser From b550ff038c33b1ecabff5f52e8916f0092740e31 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 13:42:29 +0200 Subject: [PATCH 118/175] simplify: use native events --- packages/codemirror/slider.mjs | 75 +++++++++------------------------- 1 file changed, 19 insertions(+), 56 deletions(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index d4fbcefa..a4ee6a93 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -6,7 +6,7 @@ export let sliderValues = {}; const getSliderID = (from) => `slider_${from}`; export class SliderWidget extends WidgetType { - constructor(value, min, max, from, to) { + constructor(value, min, max, from, to, view) { super(); this.value = value; this.min = min; @@ -14,6 +14,7 @@ export class SliderWidget extends WidgetType { this.from = from; this.originalFrom = from; this.to = to; + this.view = view; } eq() { @@ -38,11 +39,23 @@ export class SliderWidget extends WidgetType { slider.to = this.to; slider.className = 'w-16 translate-y-1'; this.slider = slider; + slider.addEventListener('input', (e) => { + const next = e.target.value; + let insert = next; + //let insert = next.toFixed(2); + const to = slider.from + slider.originalValue.length; + let change = { from: slider.from, to, insert }; + slider.originalValue = insert; + slider.value = insert; + this.view.dispatch({ changes: change }); + const id = getSliderID(slider.originalFrom); // matches id generated in transpiler + window.postMessage({ type: 'cm-slider', value: Number(next), id }); + }); return wrap; } - ignoreEvent() { - return false; + ignoreEvent(e) { + return true; } } @@ -52,12 +65,10 @@ export const updateWidgets = (view, widgets) => { view.dispatch({ effects: setWidgets.of(widgets) }); }; -let draggedSlider; - -function getWidgets(widgetConfigs) { +function getWidgets(widgetConfigs, view) { return widgetConfigs.map(({ from, to, value, min, max }) => { return Decoration.widget({ - widget: new SliderWidget(value, min, max, from, to), + widget: new SliderWidget(value, min, max, from, to, view), side: 0, }).range(from /* , to */); }); @@ -86,7 +97,7 @@ export const sliderPlugin = ViewPlugin.fromClass( } for (let e of tr.effects) { if (e.is(setWidgets)) { - this.decorations = Decoration.set(getWidgets(e.value)); + this.decorations = Decoration.set(getWidgets(e.value, update.view)); } } }); @@ -94,57 +105,9 @@ export const sliderPlugin = ViewPlugin.fromClass( }, { decorations: (v) => v.decorations, - - eventHandlers: { - mousedown: (e, view) => { - let target = e.target; - if (target.nodeName == 'INPUT' && target.parentElement.classList.contains('cm-slider')) { - e.preventDefault(); - e.stopPropagation(); - draggedSlider = target; - // remember offsetLeft / clientWidth, as they will vanish inside mousemove events for some reason - draggedSlider._offsetLeft = draggedSlider.offsetLeft; - draggedSlider._clientWidth = draggedSlider.clientWidth; - return updateSliderValue(view, e); - } - }, - mouseup: () => { - draggedSlider = undefined; - }, - mousemove: (e, view) => { - draggedSlider && updateSliderValue(view, e); - }, - }, }, ); -// moves slider on mouse event -function updateSliderValue(view, e) { - const mouseX = e.clientX; - let mx = 10; - let progress = (mouseX - draggedSlider._offsetLeft - mx) / (draggedSlider._clientWidth - mx * 2); - progress = Math.max(Math.min(1, progress), 0); - let min = Number(draggedSlider.min); - let max = Number(draggedSlider.max); - const next = Number(progress * (max - min) + min); - let insert = next.toFixed(2); - //let before = view.state.doc.sliceString(draggedSlider.from, draggedSlider.to).trim(); - let before = draggedSlider.originalValue; - before = Number(before).toFixed(2); - // console.log('before', before, 'insert', insert, 'v'); - if (before === insert) { - return false; - } - const to = draggedSlider.from + draggedSlider.originalValue.length; - let change = { from: draggedSlider.from, to, insert }; - draggedSlider.originalValue = insert; - draggedSlider.value = insert; - view.dispatch({ changes: change }); - const id = getSliderID(draggedSlider.originalFrom); // matches id generated in transpiler - window.postMessage({ type: 'cm-slider', value: next, id }); - return true; -} - // user api export let slider = (id, value, min, max) => { sliderValues[id] = value; // sync state at eval time (code -> state) From f84d5ba3a02d7d498cef44df7baaee654ab378b0 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 13:44:41 +0200 Subject: [PATCH 119/175] add back some margin --- packages/codemirror/slider.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index a4ee6a93..47bb7509 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -37,7 +37,7 @@ export class SliderWidget extends WidgetType { slider.from = this.from; slider.originalFrom = this.originalFrom; slider.to = this.to; - slider.className = 'w-16 translate-y-1'; + slider.className = 'w-16 translate-y-1 mr-1'; this.slider = slider; slider.addEventListener('input', (e) => { const next = e.target.value; From d4bf358eae42ccbd78e1c6b9df81f9f1bba44d8c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 13:56:57 +0200 Subject: [PATCH 120/175] use raw css instead of tailwind --- packages/codemirror/slider.mjs | 2 +- website/tailwind.config.cjs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 47bb7509..e7be78f7 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -37,7 +37,7 @@ export class SliderWidget extends WidgetType { slider.from = this.from; slider.originalFrom = this.originalFrom; slider.to = this.to; - slider.className = 'w-16 translate-y-1 mr-1'; + slider.style = 'width:64px;margin-right:4px;transform:translateY(4px)'; this.slider = slider; slider.addEventListener('input', (e) => { const next = e.target.value; diff --git a/website/tailwind.config.cjs b/website/tailwind.config.cjs index 2c682d7d..d92d5949 100644 --- a/website/tailwind.config.cjs +++ b/website/tailwind.config.cjs @@ -7,7 +7,6 @@ module.exports = { content: [ './src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}', '../packages/react/src/**/*.{html,js,jsx,md,mdx,ts,tsx}', - '../packages/codemirror/slider.mjs', ], theme: { extend: { From 564697e175e99ffea7430db1bb6d48d1757bf284 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 14:05:16 +0200 Subject: [PATCH 121/175] add extra sliderWithID function + add warning to slider function --- packages/codemirror/slider.mjs | 8 ++++++-- packages/transpiler/transpiler.mjs | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index e7be78f7..159e4fd1 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -108,8 +108,12 @@ export const sliderPlugin = ViewPlugin.fromClass( }, ); -// user api -export let slider = (id, value, min, max) => { +export let slider = (value) => { + console.warn('slider will only work when the transpiler is used... passing value as is'); + return pure(value); +}; +// function transpiled from slider = (value, min, max) +export let sliderWithID = (id, value, min, max) => { sliderValues[id] = value; // sync state at eval time (code -> state) return ref(() => sliderValues[id]); // use state at query time }; diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 5fa9dc49..37a937bc 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -121,5 +121,6 @@ function widgetWithLocation(node) { value: id, raw: id, }); + node.callee.name = 'sliderWithID'; return node; } From c051a1249d7a6adede3817f85cb3fa0992e33ba5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 14:06:32 +0200 Subject: [PATCH 122/175] remove checkbox --- packages/codemirror/checkbox.mjs | 87 ------------------- packages/react/src/components/CodeMirror6.jsx | 3 +- 2 files changed, 1 insertion(+), 89 deletions(-) delete mode 100644 packages/codemirror/checkbox.mjs diff --git a/packages/codemirror/checkbox.mjs b/packages/codemirror/checkbox.mjs deleted file mode 100644 index 279e2eb8..00000000 --- a/packages/codemirror/checkbox.mjs +++ /dev/null @@ -1,87 +0,0 @@ -import { WidgetType } from '@codemirror/view'; -import { ViewPlugin, Decoration } from '@codemirror/view'; -import { syntaxTree } from '@codemirror/language'; - -export class CheckboxWidget extends WidgetType { - constructor(checked) { - super(); - this.checked = checked; - } - - eq(other) { - return other.checked == this.checked; - } - - toDOM() { - let wrap = document.createElement('span'); - wrap.setAttribute('aria-hidden', 'true'); - wrap.className = 'cm-boolean-toggle'; - let box = wrap.appendChild(document.createElement('input')); - box.type = 'checkbox'; - box.checked = this.checked; - return wrap; - } - - ignoreEvent() { - return false; - } -} - -// EditorView -export function checkboxes(view) { - let widgets = []; - for (let { from, to } of view.visibleRanges) { - syntaxTree(view.state).iterate({ - from, - to, - enter: (node) => { - if (node.name == 'BooleanLiteral') { - let isTrue = view.state.doc.sliceString(node.from, node.to) == 'true'; - let deco = Decoration.widget({ - widget: new CheckboxWidget(isTrue), - side: 1, - }); - widgets.push(deco.range(node.from)); - } - }, - }); - } - return Decoration.set(widgets); -} - -export const checkboxPlugin = ViewPlugin.fromClass( - class { - decorations; //: DecorationSet - - constructor(view /* : EditorView */) { - this.decorations = checkboxes(view); - } - - update(update /* : ViewUpdate */) { - if (update.docChanged || update.viewportChanged) this.decorations = checkboxes(update.view); - } - }, - { - decorations: (v) => v.decorations, - - eventHandlers: { - mousedown: (e, view) => { - let target = e.target; /* as HTMLElement */ - if (target.nodeName == 'INPUT' && target.parentElement.classList.contains('cm-boolean-toggle')) - return toggleBoolean(view, view.posAtDOM(target)); - }, - }, - }, -); - -function toggleBoolean(view /* : EditorView */, pos /* : number */) { - let before = view.state.doc.sliceString(Math.max(0, pos), pos + 5).trim(); - let change; - if (!['true', 'false'].includes(before)) { - return false; - } - let insert = before === 'true' ? 'false' : 'true'; - change = { from: pos, to: pos + before.length, insert }; - view.dispatch({ changes: change }); - return true; -} diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx index f3c764e0..a5af5312 100644 --- a/packages/react/src/components/CodeMirror6.jsx +++ b/packages/react/src/components/CodeMirror6.jsx @@ -15,12 +15,11 @@ import { updateMiniLocations, } from '@strudel/codemirror'; import './style.css'; -import { checkboxPlugin } from '@strudel/codemirror/checkbox.mjs'; import { sliderPlugin } from '@strudel/codemirror/slider.mjs'; export { flash, highlightMiniLocations, updateMiniLocations }; -const staticExtensions = [javascript(), flashField, highlightExtension, checkboxPlugin, sliderPlugin]; +const staticExtensions = [javascript(), flashField, highlightExtension, sliderPlugin]; export default function CodeMirror({ value, From 21b99b3810eeb9b114d8a39f83faab8c1bd97f40 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 14:07:48 +0200 Subject: [PATCH 123/175] remove comment --- packages/transpiler/transpiler.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 37a937bc..dced458f 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -36,7 +36,6 @@ export function transpiler(input, options = {}) { return this.replace(miniWithLocation(value, node)); } if (isWidgetFunction(node)) { - // collectSliderLocations? emitWidgets && widgets.push({ from: node.arguments[0].start, From 935d8e8aea53362c247d9e3541ece5105769fa0d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 14:08:41 +0200 Subject: [PATCH 124/175] fix: comment --- packages/transpiler/transpiler.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index dced458f..6eac171f 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -114,7 +114,7 @@ function isWidgetFunction(node) { function widgetWithLocation(node) { const id = 'slider_' + node.arguments[0].start; // use loc of first arg for id // add loc as identifier to first argument - // the slider function is assumed to be slider(id, value, min?, max?) + // the sliderWithID function is assumed to be sliderWithID(id, value, min?, max?) node.arguments.unshift({ type: 'Literal', value: id, From 96f06d802644c4ec1175328ec893d0df10f345c4 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 14:09:07 +0200 Subject: [PATCH 125/175] fix: import --- packages/codemirror/slider.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 159e4fd1..47b686c8 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -1,4 +1,4 @@ -import { ref } from '@strudel.cycles/core'; +import { ref, pure } from '@strudel.cycles/core'; import { WidgetType, ViewPlugin, Decoration } from '@codemirror/view'; import { StateEffect, StateField } from '@codemirror/state'; From edbd437d7b8076a9ce3b020a6900b9e6a043d0ed Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 14:20:30 +0200 Subject: [PATCH 126/175] hotfix: add missing dependency --- pnpm-lock.yaml | 18 ++++++++++++++++++ website/package.json | 1 + 2 files changed, 19 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b48a93f..9f222a20 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -588,6 +588,9 @@ importers: '@strudel.cycles/xen': specifier: workspace:* version: link:../packages/xen + '@strudel/codemirror': + specifier: workspace:* + version: link:../packages/codemirror '@strudel/desktopbridge': specifier: workspace:* version: link:../packages/desktopbridge @@ -1426,6 +1429,7 @@ packages: /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.21.5): resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1441,6 +1445,7 @@ packages: /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.21.5): resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1454,6 +1459,7 @@ packages: /@babel/plugin-proposal-class-static-block@7.20.7(@babel/core@7.21.5): resolution: {integrity: sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-static-block instead. peerDependencies: '@babel/core': ^7.12.0 dependencies: @@ -1468,6 +1474,7 @@ packages: /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.21.5): resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1479,6 +1486,7 @@ packages: /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.21.5): resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1490,6 +1498,7 @@ packages: /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.21.5): resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1501,6 +1510,7 @@ packages: /@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.21.5): resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1512,6 +1522,7 @@ packages: /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.21.5): resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1523,6 +1534,7 @@ packages: /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.21.5): resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1534,6 +1546,7 @@ packages: /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.21.5): resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1548,6 +1561,7 @@ packages: /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.21.5): resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1559,6 +1573,7 @@ packages: /@babel/plugin-proposal-optional-chaining@7.20.7(@babel/core@7.21.5): resolution: {integrity: sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1571,6 +1586,7 @@ packages: /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.21.5): resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1584,6 +1600,7 @@ packages: /@babel/plugin-proposal-private-property-in-object@7.20.5(@babel/core@7.21.5): resolution: {integrity: sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1599,6 +1616,7 @@ packages: /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.21.5): resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==} engines: {node: '>=4'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: diff --git a/website/package.json b/website/package.json index 6ac799d3..c8fec20c 100644 --- a/website/package.json +++ b/website/package.json @@ -28,6 +28,7 @@ "@strudel.cycles/mini": "workspace:*", "@strudel.cycles/osc": "workspace:*", "@strudel.cycles/react": "workspace:*", + "@strudel/codemirror": "workspace:*", "@strudel.cycles/serial": "workspace:*", "@strudel.cycles/soundfonts": "workspace:*", "@strudel.cycles/tonal": "workspace:*", From fd316c81c0b9529a25c8d08ede3f4f2c3ccce6c2 Mon Sep 17 00:00:00 2001 From: Alex McLean Date: Sun, 1 Oct 2023 13:20:49 +0100 Subject: [PATCH 127/175] support mininotation '..' range operator, fixes #715 (#716) * support mininotation .. range operator, fixes #715 * remove logs --- packages/mini/krill-parser.js | 437 +++++++++++++++++-------------- packages/mini/krill.pegjs | 8 +- packages/mini/mini.mjs | 11 + packages/mini/test/mini.test.mjs | 6 + 4 files changed, 270 insertions(+), 192 deletions(-) diff --git a/packages/mini/krill-parser.js b/packages/mini/krill-parser.js index e85e3363..7831087b 100644 --- a/packages/mini/krill-parser.js +++ b/packages/mini/krill-parser.js @@ -200,20 +200,21 @@ function peg$parse(input, options) { var peg$c23 = "*"; var peg$c24 = "?"; var peg$c25 = ":"; - var peg$c26 = "struct"; - var peg$c27 = "target"; - var peg$c28 = "euclid"; - var peg$c29 = "slow"; - var peg$c30 = "rotL"; - var peg$c31 = "rotR"; - var peg$c32 = "fast"; - var peg$c33 = "scale"; - var peg$c34 = "//"; - var peg$c35 = "cat"; - var peg$c36 = "$"; - var peg$c37 = "setcps"; - var peg$c38 = "setbpm"; - var peg$c39 = "hush"; + var peg$c26 = ".."; + var peg$c27 = "struct"; + var peg$c28 = "target"; + var peg$c29 = "euclid"; + var peg$c30 = "slow"; + var peg$c31 = "rotL"; + var peg$c32 = "rotR"; + var peg$c33 = "fast"; + var peg$c34 = "scale"; + var peg$c35 = "//"; + var peg$c36 = "cat"; + var peg$c37 = "$"; + var peg$c38 = "setcps"; + var peg$c39 = "setbpm"; + var peg$c40 = "hush"; var peg$r0 = /^[1-9]/; var peg$r1 = /^[eE]/; @@ -255,64 +256,67 @@ function peg$parse(input, options) { var peg$e30 = peg$literalExpectation("*", false); var peg$e31 = peg$literalExpectation("?", false); var peg$e32 = peg$literalExpectation(":", false); - var peg$e33 = peg$literalExpectation("struct", false); - var peg$e34 = peg$literalExpectation("target", false); - var peg$e35 = peg$literalExpectation("euclid", false); - var peg$e36 = peg$literalExpectation("slow", false); - var peg$e37 = peg$literalExpectation("rotL", false); - var peg$e38 = peg$literalExpectation("rotR", false); - var peg$e39 = peg$literalExpectation("fast", false); - var peg$e40 = peg$literalExpectation("scale", false); - var peg$e41 = peg$literalExpectation("//", false); - var peg$e42 = peg$classExpectation(["\n"], true, false); - var peg$e43 = peg$literalExpectation("cat", false); - var peg$e44 = peg$literalExpectation("$", false); - var peg$e45 = peg$literalExpectation("setcps", false); - var peg$e46 = peg$literalExpectation("setbpm", false); - var peg$e47 = peg$literalExpectation("hush", false); + var peg$e33 = peg$literalExpectation("..", false); + var peg$e34 = peg$literalExpectation("struct", false); + var peg$e35 = peg$literalExpectation("target", false); + var peg$e36 = peg$literalExpectation("euclid", false); + var peg$e37 = peg$literalExpectation("slow", false); + var peg$e38 = peg$literalExpectation("rotL", false); + var peg$e39 = peg$literalExpectation("rotR", false); + var peg$e40 = peg$literalExpectation("fast", false); + var peg$e41 = peg$literalExpectation("scale", false); + var peg$e42 = peg$literalExpectation("//", false); + var peg$e43 = peg$classExpectation(["\n"], true, false); + var peg$e44 = peg$literalExpectation("cat", false); + var peg$e45 = peg$literalExpectation("$", false); + var peg$e46 = peg$literalExpectation("setcps", false); + var peg$e47 = peg$literalExpectation("setbpm", false); + var peg$e48 = peg$literalExpectation("hush", false); var peg$f0 = function() { return parseFloat(text()); }; - var peg$f1 = function(chars) { return new AtomStub(chars.join("")) }; - var peg$f2 = function(s) { return s }; - var peg$f3 = function(s, stepsPerCycle) { s.arguments_.stepsPerCycle = stepsPerCycle ; return s; }; - var peg$f4 = function(a) { return a }; - var peg$f5 = function(s) { s.arguments_.alignment = 'slowcat'; return s; }; - var peg$f6 = function(a) { return x => x.options_['weight'] = a }; - var peg$f7 = function(a) { return x => x.options_['reps'] = a }; - var peg$f8 = function(p, s, r) { return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) }; - var peg$f9 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'slow' }}) }; - var peg$f10 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'fast' }}) }; - var peg$f11 = function(a) { return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a, seed: seed++ } }) }; - var peg$f12 = function(s) { return x => x.options_['ops'].push({ type_: "tail", arguments_ :{ element:s } }) }; - var peg$f13 = function(s, ops) { const result = new ElementStub(s, {ops: [], weight: 1, reps: 1}); + var peg$f1 = function() { return parseInt(text()); }; + var peg$f2 = function(chars) { return new AtomStub(chars.join("")) }; + var peg$f3 = function(s) { return s }; + var peg$f4 = function(s, stepsPerCycle) { s.arguments_.stepsPerCycle = stepsPerCycle ; return s; }; + var peg$f5 = function(a) { return a }; + var peg$f6 = function(s) { s.arguments_.alignment = 'slowcat'; return s; }; + var peg$f7 = function(a) { return x => x.options_['weight'] = a }; + var peg$f8 = function(a) { return x => x.options_['reps'] = a }; + var peg$f9 = function(p, s, r) { return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) }; + var peg$f10 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'slow' }}) }; + var peg$f11 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'fast' }}) }; + var peg$f12 = function(a) { return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a, seed: seed++ } }) }; + var peg$f13 = function(s) { return x => x.options_['ops'].push({ type_: "tail", arguments_ :{ element:s } }) }; + var peg$f14 = function(s) { return x => x.options_['ops'].push({ type_: "range", arguments_ :{ element:s } }) }; + var peg$f15 = function(s, ops) { const result = new ElementStub(s, {ops: [], weight: 1, reps: 1}); for (const op of ops) { op(result); } return result; }; - var peg$f14 = function(s) { return new PatternStub(s, 'fastcat'); }; - var peg$f15 = function(tail) { return { alignment: 'stack', list: tail }; }; - var peg$f16 = function(tail) { return { alignment: 'rand', list: tail, seed: seed++ }; }; - var peg$f17 = function(head, tail) { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment, tail.seed); } else { return head; } }; - var peg$f18 = function(head, tail) { return new PatternStub(tail ? [head, ...tail.list] : [head], 'polymeter'); }; - var peg$f19 = function(sc) { return sc; }; - var peg$f20 = function(s) { return { name: "struct", args: { mini:s }}}; - var peg$f21 = function(s) { return { name: "target", args : { name:s}}}; - var peg$f22 = function(p, s, r) { return { name: "bjorklund", args :{ pulse: p, step:parseInt(s) }}}; - var peg$f23 = function(a) { return { name: "stretch", args :{ amount: a}}}; - var peg$f24 = function(a) { return { name: "shift", args :{ amount: "-"+a}}}; - var peg$f25 = function(a) { return { name: "shift", args :{ amount: a}}}; - var peg$f26 = function(a) { return { name: "stretch", args :{ amount: "1/"+a}}}; - var peg$f27 = function(s) { return { name: "scale", args :{ scale: s.join("")}}}; - var peg$f28 = function(s, v) { return v}; - var peg$f29 = function(s, ss) { ss.unshift(s); return new PatternStub(ss, 'slowcat'); }; - var peg$f30 = function(sg) {return sg}; - var peg$f31 = function(o, soc) { return new OperatorStub(o.name,o.args,soc)}; - var peg$f32 = function(sc) { return sc }; - var peg$f33 = function(c) { return c }; - var peg$f34 = function(v) { return new CommandStub("setcps", { value: v})}; - var peg$f35 = function(v) { return new CommandStub("setcps", { value: (v/120/2)})}; - var peg$f36 = function() { return new CommandStub("hush")}; + var peg$f16 = function(s) { return new PatternStub(s, 'fastcat'); }; + var peg$f17 = function(tail) { return { alignment: 'stack', list: tail }; }; + var peg$f18 = function(tail) { return { alignment: 'rand', list: tail, seed: seed++ }; }; + var peg$f19 = function(head, tail) { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment, tail.seed); } else { return head; } }; + var peg$f20 = function(head, tail) { return new PatternStub(tail ? [head, ...tail.list] : [head], 'polymeter'); }; + var peg$f21 = function(sc) { return sc; }; + var peg$f22 = function(s) { return { name: "struct", args: { mini:s }}}; + var peg$f23 = function(s) { return { name: "target", args : { name:s}}}; + var peg$f24 = function(p, s, r) { return { name: "bjorklund", args :{ pulse: p, step:parseInt(s) }}}; + var peg$f25 = function(a) { return { name: "stretch", args :{ amount: a}}}; + var peg$f26 = function(a) { return { name: "shift", args :{ amount: "-"+a}}}; + var peg$f27 = function(a) { return { name: "shift", args :{ amount: a}}}; + var peg$f28 = function(a) { return { name: "stretch", args :{ amount: "1/"+a}}}; + var peg$f29 = function(s) { return { name: "scale", args :{ scale: s.join("")}}}; + var peg$f30 = function(s, v) { return v}; + var peg$f31 = function(s, ss) { ss.unshift(s); return new PatternStub(ss, 'slowcat'); }; + var peg$f32 = function(sg) {return sg}; + var peg$f33 = function(o, soc) { return new OperatorStub(o.name,o.args,soc)}; + var peg$f34 = function(sc) { return sc }; + var peg$f35 = function(c) { return c }; + var peg$f36 = function(v) { return new CommandStub("setcps", { value: v})}; + var peg$f37 = function(v) { return new CommandStub("setcps", { value: (v/120/2)})}; + var peg$f38 = function() { return new CommandStub("hush")}; var peg$currPos = 0; var peg$savedPos = 0; var peg$posDetailsCache = [{ line: 1, column: 1 }]; @@ -651,6 +655,26 @@ function peg$parse(input, options) { return s0; } + function peg$parseintneg() { + var s0, s1, s2; + + s0 = peg$currPos; + s1 = peg$parseminus(); + if (s1 === peg$FAILED) { + s1 = null; + } + s2 = peg$parseint(); + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f1(); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + function peg$parseminus() { var s0; @@ -884,7 +908,7 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = peg$parsews(); peg$savedPos = s0; - s0 = peg$f1(s2); + s0 = peg$f2(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -920,7 +944,7 @@ function peg$parse(input, options) { if (s6 !== peg$FAILED) { s7 = peg$parsews(); peg$savedPos = s0; - s0 = peg$f2(s4); + s0 = peg$f3(s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -968,7 +992,7 @@ function peg$parse(input, options) { } s8 = peg$parsews(); peg$savedPos = s0; - s0 = peg$f3(s4, s7); + s0 = peg$f4(s4, s7); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1000,7 +1024,7 @@ function peg$parse(input, options) { s2 = peg$parseslice(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f4(s2); + s0 = peg$f5(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1040,7 +1064,7 @@ function peg$parse(input, options) { if (s6 !== peg$FAILED) { s7 = peg$parsews(); peg$savedPos = s0; - s0 = peg$f5(s4); + s0 = peg$f6(s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1090,6 +1114,9 @@ function peg$parse(input, options) { s0 = peg$parseop_degrade(); if (s0 === peg$FAILED) { s0 = peg$parseop_tail(); + if (s0 === peg$FAILED) { + s0 = peg$parseop_range(); + } } } } @@ -1115,7 +1142,7 @@ function peg$parse(input, options) { s2 = peg$parsenumber(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f6(s2); + s0 = peg$f7(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1143,7 +1170,7 @@ function peg$parse(input, options) { s2 = peg$parsenumber(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f7(s2); + s0 = peg$f8(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1197,7 +1224,7 @@ function peg$parse(input, options) { } if (s13 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f8(s3, s7, s11); + s0 = peg$f9(s3, s7, s11); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1237,7 +1264,7 @@ function peg$parse(input, options) { s2 = peg$parseslice(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f9(s2); + s0 = peg$f10(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1265,7 +1292,7 @@ function peg$parse(input, options) { s2 = peg$parseslice(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f10(s2); + s0 = peg$f11(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1295,7 +1322,7 @@ function peg$parse(input, options) { s2 = null; } peg$savedPos = s0; - s0 = peg$f11(s2); + s0 = peg$f12(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1319,7 +1346,35 @@ function peg$parse(input, options) { s2 = peg$parseslice(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f12(s2); + s0 = peg$f13(s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + + function peg$parseop_range() { + var s0, s1, s2; + + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c26) { + s1 = peg$c26; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e33); } + } + if (s1 !== peg$FAILED) { + s2 = peg$parseslice(); + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f14(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1345,7 +1400,7 @@ function peg$parse(input, options) { s3 = peg$parseslice_op(); } peg$savedPos = s0; - s0 = peg$f13(s1, s2); + s0 = peg$f15(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1370,7 +1425,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f14(s1); + s1 = peg$f16(s1); } s0 = s1; @@ -1419,7 +1474,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f15(s1); + s1 = peg$f17(s1); } s0 = s1; @@ -1468,7 +1523,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f16(s1); + s1 = peg$f18(s1); } s0 = s1; @@ -1489,7 +1544,7 @@ function peg$parse(input, options) { s2 = null; } peg$savedPos = s0; - s0 = peg$f17(s1, s2); + s0 = peg$f19(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1509,7 +1564,7 @@ function peg$parse(input, options) { s2 = null; } peg$savedPos = s0; - s0 = peg$f18(s1, s2); + s0 = peg$f20(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1532,7 +1587,7 @@ function peg$parse(input, options) { s6 = peg$parsequote(); if (s6 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f19(s4); + s0 = peg$f21(s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1582,19 +1637,19 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c26) { - s1 = peg$c26; + if (input.substr(peg$currPos, 6) === peg$c27) { + s1 = peg$c27; peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e33); } + if (peg$silentFails === 0) { peg$fail(peg$e34); } } if (s1 !== peg$FAILED) { s2 = peg$parsews(); s3 = peg$parsemini_or_operator(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f20(s3); + s0 = peg$f22(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1611,12 +1666,12 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5; s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c27) { - s1 = peg$c27; + if (input.substr(peg$currPos, 6) === peg$c28) { + s1 = peg$c28; peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e34); } + if (peg$silentFails === 0) { peg$fail(peg$e35); } } if (s1 !== peg$FAILED) { s2 = peg$parsews(); @@ -1627,7 +1682,7 @@ function peg$parse(input, options) { s5 = peg$parsequote(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f21(s4); + s0 = peg$f23(s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1652,12 +1707,12 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7; s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c28) { - s1 = peg$c28; + if (input.substr(peg$currPos, 6) === peg$c29) { + s1 = peg$c29; peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e35); } + if (peg$silentFails === 0) { peg$fail(peg$e36); } } if (s1 !== peg$FAILED) { s2 = peg$parsews(); @@ -1672,7 +1727,7 @@ function peg$parse(input, options) { s7 = null; } peg$savedPos = s0; - s0 = peg$f22(s3, s5, s7); + s0 = peg$f24(s3, s5, s7); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1692,35 +1747,6 @@ function peg$parse(input, options) { function peg$parseslow() { var s0, s1, s2, s3; - s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c29) { - s1 = peg$c29; - peg$currPos += 4; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e36); } - } - if (s1 !== peg$FAILED) { - s2 = peg$parsews(); - s3 = peg$parsenumber(); - if (s3 !== peg$FAILED) { - peg$savedPos = s0; - s0 = peg$f23(s3); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parserotL() { - var s0, s1, s2, s3; - s0 = peg$currPos; if (input.substr(peg$currPos, 4) === peg$c30) { s1 = peg$c30; @@ -1729,35 +1755,6 @@ function peg$parse(input, options) { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e37); } } - if (s1 !== peg$FAILED) { - s2 = peg$parsews(); - s3 = peg$parsenumber(); - if (s3 !== peg$FAILED) { - peg$savedPos = s0; - s0 = peg$f24(s3); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parserotR() { - var s0, s1, s2, s3; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c31) { - s1 = peg$c31; - peg$currPos += 4; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e38); } - } if (s1 !== peg$FAILED) { s2 = peg$parsews(); s3 = peg$parsenumber(); @@ -1776,16 +1773,16 @@ function peg$parse(input, options) { return s0; } - function peg$parsefast() { + function peg$parserotL() { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c32) { - s1 = peg$c32; + if (input.substr(peg$currPos, 4) === peg$c31) { + s1 = peg$c31; peg$currPos += 4; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e39); } + if (peg$silentFails === 0) { peg$fail(peg$e38); } } if (s1 !== peg$FAILED) { s2 = peg$parsews(); @@ -1805,16 +1802,74 @@ function peg$parse(input, options) { return s0; } + function peg$parserotR() { + var s0, s1, s2, s3; + + s0 = peg$currPos; + if (input.substr(peg$currPos, 4) === peg$c32) { + s1 = peg$c32; + peg$currPos += 4; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e39); } + } + if (s1 !== peg$FAILED) { + s2 = peg$parsews(); + s3 = peg$parsenumber(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f27(s3); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + + function peg$parsefast() { + var s0, s1, s2, s3; + + s0 = peg$currPos; + if (input.substr(peg$currPos, 4) === peg$c33) { + s1 = peg$c33; + peg$currPos += 4; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e40); } + } + if (s1 !== peg$FAILED) { + s2 = peg$parsews(); + s3 = peg$parsenumber(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f28(s3); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + function peg$parsescale() { var s0, s1, s2, s3, s4, s5; s0 = peg$currPos; - if (input.substr(peg$currPos, 5) === peg$c33) { - s1 = peg$c33; + if (input.substr(peg$currPos, 5) === peg$c34) { + s1 = peg$c34; peg$currPos += 5; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e40); } + if (peg$silentFails === 0) { peg$fail(peg$e41); } } if (s1 !== peg$FAILED) { s2 = peg$parsews(); @@ -1834,7 +1889,7 @@ function peg$parse(input, options) { s5 = peg$parsequote(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f27(s4); + s0 = peg$f29(s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1859,12 +1914,12 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c34) { - s1 = peg$c34; + if (input.substr(peg$currPos, 2) === peg$c35) { + s1 = peg$c35; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e41); } + if (peg$silentFails === 0) { peg$fail(peg$e42); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1873,7 +1928,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e42); } + if (peg$silentFails === 0) { peg$fail(peg$e43); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -1882,7 +1937,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e42); } + if (peg$silentFails === 0) { peg$fail(peg$e43); } } } s1 = [s1, s2]; @@ -1899,12 +1954,12 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; s0 = peg$currPos; - if (input.substr(peg$currPos, 3) === peg$c35) { - s1 = peg$c35; + if (input.substr(peg$currPos, 3) === peg$c36) { + s1 = peg$c36; peg$currPos += 3; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e43); } + if (peg$silentFails === 0) { peg$fail(peg$e44); } } if (s1 !== peg$FAILED) { s2 = peg$parsews(); @@ -1926,7 +1981,7 @@ function peg$parse(input, options) { s9 = peg$parsemini_or_operator(); if (s9 !== peg$FAILED) { peg$savedPos = s7; - s7 = peg$f28(s5, s9); + s7 = peg$f30(s5, s9); } else { peg$currPos = s7; s7 = peg$FAILED; @@ -1943,7 +1998,7 @@ function peg$parse(input, options) { s9 = peg$parsemini_or_operator(); if (s9 !== peg$FAILED) { peg$savedPos = s7; - s7 = peg$f28(s5, s9); + s7 = peg$f30(s5, s9); } else { peg$currPos = s7; s7 = peg$FAILED; @@ -1963,7 +2018,7 @@ function peg$parse(input, options) { } if (s8 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f29(s5, s6); + s0 = peg$f31(s5, s6); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2009,7 +2064,7 @@ function peg$parse(input, options) { s4 = peg$parsecomment(); } peg$savedPos = s0; - s0 = peg$f30(s1); + s0 = peg$f32(s1); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2020,18 +2075,18 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parsews(); if (input.charCodeAt(peg$currPos) === 36) { - s3 = peg$c36; + s3 = peg$c37; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e44); } + if (peg$silentFails === 0) { peg$fail(peg$e45); } } if (s3 !== peg$FAILED) { s4 = peg$parsews(); s5 = peg$parsemini_or_operator(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f31(s1, s5); + s0 = peg$f33(s1, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2056,7 +2111,7 @@ function peg$parse(input, options) { s1 = peg$parsemini_or_operator(); if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f32(s1); + s1 = peg$f34(s1); } s0 = s1; if (s0 === peg$FAILED) { @@ -2089,7 +2144,7 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = peg$parsews(); peg$savedPos = s0; - s0 = peg$f33(s2); + s0 = peg$f35(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2102,19 +2157,19 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c37) { - s1 = peg$c37; + if (input.substr(peg$currPos, 6) === peg$c38) { + s1 = peg$c38; peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e45); } + if (peg$silentFails === 0) { peg$fail(peg$e46); } } if (s1 !== peg$FAILED) { s2 = peg$parsews(); s3 = peg$parsenumber(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f34(s3); + s0 = peg$f36(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2131,19 +2186,19 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c38) { - s1 = peg$c38; + if (input.substr(peg$currPos, 6) === peg$c39) { + s1 = peg$c39; peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e46); } + if (peg$silentFails === 0) { peg$fail(peg$e47); } } if (s1 !== peg$FAILED) { s2 = peg$parsews(); s3 = peg$parsenumber(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f35(s3); + s0 = peg$f37(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2160,16 +2215,16 @@ function peg$parse(input, options) { var s0, s1; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c39) { - s1 = peg$c39; + if (input.substr(peg$currPos, 4) === peg$c40) { + s1 = peg$c40; peg$currPos += 4; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e47); } + if (peg$silentFails === 0) { peg$fail(peg$e48); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f36(); + s1 = peg$f38(); } s0 = s1; diff --git a/packages/mini/krill.pegjs b/packages/mini/krill.pegjs index 72b453be..f52743bf 100644 --- a/packages/mini/krill.pegjs +++ b/packages/mini/krill.pegjs @@ -79,6 +79,9 @@ frac int = zero / (digit1_9 DIGIT*) +intneg + = minus? int { return parseInt(text()); } + minus = "-" @@ -123,7 +126,7 @@ slice = step / sub_cycle / polymeter / slow_sequence // slice modifier affects the timing/size of a slice (e.g. [a b c]@3) // at this point, we assume we can represent them as regular sequence operators -slice_op = op_weight / op_bjorklund / op_slow / op_fast / op_replicate / op_degrade / op_tail +slice_op = op_weight / op_bjorklund / op_slow / op_fast / op_replicate / op_degrade / op_tail / op_range op_weight = "@" a:number { return x => x.options_['weight'] = a } @@ -146,6 +149,9 @@ op_degrade = "?"a:number? op_tail = ":" s:slice { return x => x.options_['ops'].push({ type_: "tail", arguments_ :{ element:s } }) } +op_range = ".." s:slice + { return x => x.options_['ops'].push({ type_: "range", arguments_ :{ element:s } }) } + // a slice with an modifier applied i.e [bd@4 sd@3]@2 hh] slice_with_ops = s:slice ops:slice_op* { const result = new ElementStub(s, {ops: [], weight: 1, reps: 1}); diff --git a/packages/mini/mini.mjs b/packages/mini/mini.mjs index 3321e7bc..8e6b844f 100644 --- a/packages/mini/mini.mjs +++ b/packages/mini/mini.mjs @@ -45,6 +45,17 @@ const applyOptions = (parent, enter) => (pat, i) => { pat = pat.fmap((a) => (b) => Array.isArray(a) ? [...a, b] : [a, b]).appLeft(friend); break; } + case 'range': { + const friend = enter(op.arguments_.element); + pat = strudel.reify(pat); + const arrayRange = (start, stop, step = 1) => + Array.from({ length: Math.abs(stop - start) / step + 1 }, (value, index) => + start < stop ? start + index * step : start - index * step, + ); + let range = (apat, bpat) => apat.squeezeBind((a) => bpat.bind((b) => strudel.fastcat(...arrayRange(a, b)))); + pat = range(pat, friend); + break; + } default: { console.warn(`operator "${op.type_}" not implemented`); } diff --git a/packages/mini/test/mini.test.mjs b/packages/mini/test/mini.test.mjs index 0c7f381e..6d9ac367 100644 --- a/packages/mini/test/mini.test.mjs +++ b/packages/mini/test/mini.test.mjs @@ -184,6 +184,12 @@ describe('mini', () => { it('supports lists', () => { expect(minV('a:b c:d:[e:f] g')).toEqual([['a', 'b'], ['c', 'd', ['e', 'f']], 'g']); }); + it('supports ranges', () => { + expect(minV('0 .. 4')).toEqual([0, 1, 2, 3, 4]); + }); + it('supports patterned ranges', () => { + expect(minS('[<0 1> .. <2 4>]*2')).toEqual(minS('[0 1 2] [1 2 3 4]')); + }); }); describe('getLeafLocation', () => { From 2d07eeb518e9b200bae4e38b818808ef2a388849 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 1 Oct 2023 14:44:34 +0200 Subject: [PATCH 128/175] Connecting all parameters to convolution generator --- packages/superdough/reverb.mjs | 5 ++++- packages/superdough/superdough.mjs | 20 ++++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index 4c5bc1d1..54019fc2 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -26,8 +26,11 @@ if (typeof AudioContext !== 'undefined') { } ); convolver.duration = d; + convolver.fade = fade; + convolver.revlp = revlp; + convolver.revdim = revdim; }; - convolver.setDuration(duration); + convolver.setDuration(duration, fade, revlp, revdim); return convolver; }; } diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 607c649d..0d08c8ad 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -118,17 +118,29 @@ function getReverb(orbit, duration = 2, fade, revlp, revdim) { duration, fade, revlp, + revdim, ); reverb.connect(getDestination()); - console.log(reverb) reverbs[orbit] = reverb; + console.log(reverbs[orbit]); } - // Update the reverb duration if needed after instanciation - if (reverbs[orbit].duration !== duration) { + + if ( + reverbs[orbit].duration !== duration || + reverbs[orbit].fade !== fade || + reverbs[orbit].revlp !== revlp || + reverbs[orbit].revdim !== revdim + ) { reverbs[orbit] = reverbs[orbit].setDuration( - duration, fade, revlp, revdim); + duration, fade, revlp, revdim + ); reverbs[orbit].duration = duration; + reverbs[orbit].fade = fade; + reverbs[orbit].revlp = revlp; + reverbs[orbit].revdim = revdim; + } + return reverbs[orbit]; } From 1909caf769d83e89fbc6ace74b464f25179fe20d Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 1 Oct 2023 14:50:29 +0200 Subject: [PATCH 129/175] Connecting new reverb documentation --- website/src/pages/learn/effects.mdx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index f77ab4c4..062a1947 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -203,4 +203,16 @@ global effects use the same chain for all events of the same orbit: +## fade + + + +## revlp + + + +## revdim + + + Next, we'll look at strudel's support for [Csound](/learn/csound). From 6ca99e33aba268442e519760e1488d9e87460ab5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 23:20:05 +0200 Subject: [PATCH 130/175] codeformat --- packages/core/controls.mjs | 4 +-- packages/superdough/reverb.mjs | 10 ++------ packages/superdough/reverbGen.mjs | 40 ++++++++++++++---------------- packages/superdough/superdough.mjs | 15 ++--------- 4 files changed, 24 insertions(+), 45 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 216b7001..e72f006d 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1197,7 +1197,7 @@ const generic_params = [ ]; // TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13 -controls.createParam = function(names) { +controls.createParam = function (names) { const name = Array.isArray(names) ? names[0] : names; var withVal; @@ -1221,7 +1221,7 @@ controls.createParam = function(names) { const func = (...pats) => sequence(...pats).withValue(withVal); - const setter = function(...pats) { + const setter = function (...pats) { if (!pats.length) { return this.fmap(withVal); } diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index 54019fc2..7151e7fc 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -2,13 +2,7 @@ import reverbGen from './reverbGen.mjs'; if (typeof AudioContext !== 'undefined') { AudioContext.prototype.generateReverb = reverbGen.generateReverb; - AudioContext.prototype.createReverb = function( - audioContext, - duration, - fade, - revlp, - revdim - ) { + AudioContext.prototype.createReverb = function (audioContext, duration, fade, revlp, revdim) { const convolver = this.createConvolver(); convolver.setDuration = (d, fade, revlp, revdim) => { this.generateReverb( @@ -23,7 +17,7 @@ if (typeof AudioContext !== 'undefined') { }, (buffer) => { convolver.buffer = buffer; - } + }, ); convolver.duration = d; convolver.fade = fade; diff --git a/packages/superdough/reverbGen.mjs b/packages/superdough/reverbGen.mjs index 1d05ee82..cac5d24a 100644 --- a/packages/superdough/reverbGen.mjs +++ b/packages/superdough/reverbGen.mjs @@ -12,9 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -"use strict"; - - var reverbGen = {}; /** Generates a reverb impulse response. @@ -24,7 +21,7 @@ var reverbGen = {}; the impulse response has been generated. The impulse response is passed to this function as its parameter. May be called immediately within the current execution context, or later. */ -reverbGen.generateReverb = function(params, callback) { +reverbGen.generateReverb = function (params, callback) { var audioContext = params.audioContext || new AudioContext(); var sampleRate = params.sampleRate || 44100; var numChannels = params.numChannels || 2; @@ -42,7 +39,7 @@ reverbGen.generateReverb = function(params, callback) { chan[j] = randomSample() * Math.pow(decayBase, j); } for (var j = 0; j < fadeInSampleFrames; j++) { - chan[j] *= (j / fadeInSampleFrames); + chan[j] *= j / fadeInSampleFrames; } } @@ -57,7 +54,7 @@ reverbGen.generateReverb = function(params, callback) { @param {number} min Minimum value of data for the graph (lower edge). @param {number} max Maximum value of data in the graph (upper edge). @return {!CanvasElement} The generated canvas element. */ -reverbGen.generateGraph = function(data, width, height, min, max) { +reverbGen.generateGraph = function (data, width, height, min, max) { var canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; @@ -71,7 +68,7 @@ reverbGen.generateGraph = function(data, width, height, min, max) { gc.fillRect(i * xscale, height - (data[i] - min) * yscale, 1, 1); } return canvas; -} +}; /** Saves an AudioBuffer as a 16-bit WAV file on the client's host file system. Normalizes it to peak at +-32767, and optionally @@ -85,7 +82,7 @@ reverbGen.generateGraph = function(data, width, height, min, max) { is truncated at that point. This is expressed as an integer, applying to the post-normalized and integer-converted buffer. The default is 0, meaning don't truncate. */ -reverbGen.saveWavFile = function(buffer, name, opt_minTail) { +reverbGen.saveWavFile = function (buffer, name, opt_minTail) { var bitsPerSample = 16; var bytesPerSample = 2; var sampleRate = buffer.sampleRate; @@ -124,23 +121,22 @@ reverbGen.saveWavFile = function(buffer, name, opt_minTail) { dataView.setUint32(4, fileBytes - 8, true); // file length dataView.setUint32(8, 1163280727, true); // "WAVE" dataView.setUint32(12, 544501094, true); // "fmt " - dataView.setUint32(16, 16, true) // fmt chunk length - dataView.setUint16(20, 1, true); // PCM format + dataView.setUint32(16, 16, true); // fmt chunk length + dataView.setUint16(20, 1, true); // PCM format dataView.setUint16(22, numChannels, true); // NumChannels - dataView.setUint32(24, sampleRate, true); // SampleRate + dataView.setUint32(24, sampleRate, true); // SampleRate var bytesPerSampleFrame = numChannels * bytesPerSample; dataView.setUint32(28, sampleRate * bytesPerSampleFrame, true); // ByteRate - dataView.setUint16(32, bytesPerSampleFrame, true); // BlockAlign - dataView.setUint16(34, bitsPerSample, true); // BitsPerSample - dataView.setUint32(36, 1635017060, true); // "data" + dataView.setUint16(32, bytesPerSampleFrame, true); // BlockAlign + dataView.setUint16(34, bitsPerSample, true); // BitsPerSample + dataView.setUint32(36, 1635017060, true); // "data" dataView.setUint32(40, sampleDataBytes, true); for (var j = 0; j < numSampleFrames; j++) { for (var i = 0; i < numChannels; i++) { - dataView.setInt16(44 + j * bytesPerSampleFrame + i * bytesPerSample, - Math.round(scale * channels[i][j]), true); + dataView.setInt16(44 + j * bytesPerSampleFrame + i * bytesPerSample, Math.round(scale * channels[i][j]), true); } } - var blob = new Blob([arrayBuffer], { 'type': 'audio/wav' }); + var blob = new Blob([arrayBuffer], { type: 'audio/wav' }); var url = window.URL.createObjectURL(blob); var linkEl = document.createElement('a'); linkEl.href = url; @@ -159,7 +155,7 @@ reverbGen.saveWavFile = function(buffer, name, opt_minTail) { @param {number} lpFreqEndAt @param {!function(!AudioBuffer)} callback May be called immediately within the current execution context, or later.*/ -var applyGradualLowpass = function(input, lpFreqStart, lpFreqEnd, lpFreqEndAt, callback) { +var applyGradualLowpass = function (input, lpFreqStart, lpFreqEnd, lpFreqEndAt, callback) { if (lpFreqStart == 0) { callback(input); return; @@ -173,7 +169,7 @@ var applyGradualLowpass = function(input, lpFreqStart, lpFreqEnd, lpFreqEndAt, c lpFreqStart = Math.min(lpFreqStart, input.sampleRate / 2); lpFreqEnd = Math.min(lpFreqEnd, input.sampleRate / 2); - filter.type = "lowpass"; + filter.type = 'lowpass'; filter.Q.value = 0.0001; filter.frequency.setValueAtTime(lpFreqStart, 0); filter.frequency.linearRampToValueAtTime(lpFreqEnd, lpFreqEndAt); @@ -181,7 +177,7 @@ var applyGradualLowpass = function(input, lpFreqStart, lpFreqEnd, lpFreqEndAt, c player.connect(filter); filter.connect(context.destination); player.start(); - context.oncomplete = function(event) { + context.oncomplete = function (event) { callback(event.renderedBuffer); }; context.startRendering(); @@ -192,7 +188,7 @@ var applyGradualLowpass = function(input, lpFreqStart, lpFreqEnd, lpFreqEndAt, c /** @private @param {!AudioBuffer} buffer @return {!Array.} An array containing the Float32Array of each channel's samples. */ -var getAllChannelData = function(buffer) { +var getAllChannelData = function (buffer) { var channels = []; for (var i = 0; i < buffer.numberOfChannels; i++) { channels[i] = buffer.getChannelData(i); @@ -202,7 +198,7 @@ var getAllChannelData = function(buffer) { /** @private @return {number} A random number from -1 to 1. */ -var randomSample = function() { +var randomSample = function () { return Math.random() * 2 - 1; }; diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 0d08c8ad..39e05e79 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -109,20 +109,12 @@ function getDelay(orbit, delaytime, delayfeedback, t) { let reverbs = {}; function getReverb(orbit, duration = 2, fade, revlp, revdim) { - // If no reverb has been created for a given orbit, create one if (!reverbs[orbit]) { const ac = getAudioContext(); - const reverb = ac.createReverb( - getAudioContext(), - duration, - fade, - revlp, - revdim, - ); + const reverb = ac.createReverb(getAudioContext(), duration, fade, revlp, revdim); reverb.connect(getDestination()); reverbs[orbit] = reverb; - console.log(reverbs[orbit]); } if ( @@ -131,14 +123,11 @@ function getReverb(orbit, duration = 2, fade, revlp, revdim) { reverbs[orbit].revlp !== revlp || reverbs[orbit].revdim !== revdim ) { - reverbs[orbit] = reverbs[orbit].setDuration( - duration, fade, revlp, revdim - ); + reverbs[orbit] = reverbs[orbit].setDuration(duration, fade, revlp, revdim); reverbs[orbit].duration = duration; reverbs[orbit].fade = fade; reverbs[orbit].revlp = revlp; reverbs[orbit].revdim = revdim; - } return reverbs[orbit]; From 275796c241f3740e71bc1366e501a4855d7cbc8d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 23:21:02 +0200 Subject: [PATCH 131/175] fix: reverbs[orbit] is undefined --- packages/superdough/superdough.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 39e05e79..28f4c261 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -123,7 +123,7 @@ function getReverb(orbit, duration = 2, fade, revlp, revdim) { reverbs[orbit].revlp !== revlp || reverbs[orbit].revdim !== revdim ) { - reverbs[orbit] = reverbs[orbit].setDuration(duration, fade, revlp, revdim); + reverbs[orbit].setDuration(duration, fade, revlp, revdim); reverbs[orbit].duration = duration; reverbs[orbit].fade = fade; reverbs[orbit].revlp = revlp; From dfdd9e02ca43f7117fe995cd9baba57ed7bed561 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 1 Oct 2023 23:22:32 +0200 Subject: [PATCH 132/175] eslint ignore reverbGen + snapshot --- .eslintignore | 3 +- test/__snapshots__/examples.test.mjs.snap | 78 +++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 13e635f3..58d3643d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -18,4 +18,5 @@ vite.config.js **/*.json **/dev-dist **/dist -/src-tauri/target/**/* \ No newline at end of file +/src-tauri/target/**/* +reverbGen.mjs \ No newline at end of file diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index e026f9c4..616fff12 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1773,6 +1773,32 @@ exports[`runs examples > example "every" example index 0 1`] = ` ] `; +exports[`runs examples > example "fade" example index 0 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 revlp:10000 fade:0.5 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 revlp:10000 fade:0.5 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 revlp:10000 fade:0.5 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 revlp:10000 fade:0.5 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 revlp:10000 fade:0.5 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 revlp:10000 fade:0.5 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 revlp:10000 fade:0.5 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 revlp:10000 fade:0.5 ]", +] +`; + +exports[`runs examples > example "fade" example index 1 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 revlp:5000 fade:4 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 revlp:5000 fade:4 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 revlp:5000 fade:4 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 revlp:5000 fade:4 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 revlp:5000 fade:4 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 revlp:5000 fade:4 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 revlp:5000 fade:4 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 revlp:5000 fade:4 ]", +] +`; + exports[`runs examples > example "fast" example index 0 1`] = ` [ "[ 0/1 → 1/4 | s:bd ]", @@ -3607,6 +3633,58 @@ exports[`runs examples > example "rev" example index 0 1`] = ` ] `; +exports[`runs examples > example "revdim" example index 0 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 revlp:10000 revdim:8000 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 revlp:10000 revdim:8000 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 revlp:10000 revdim:8000 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 revlp:10000 revdim:8000 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 revlp:10000 revdim:8000 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 revlp:10000 revdim:8000 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 revlp:10000 revdim:8000 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 revlp:10000 revdim:8000 ]", +] +`; + +exports[`runs examples > example "revdim" example index 1 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 revlp:5000 revdim:400 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 revlp:5000 revdim:400 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 revlp:5000 revdim:400 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 revlp:5000 revdim:400 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 revlp:5000 revdim:400 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 revlp:5000 revdim:400 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 revlp:5000 revdim:400 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 revlp:5000 revdim:400 ]", +] +`; + +exports[`runs examples > example "revlp" example index 0 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 revlp:10000 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 revlp:10000 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 revlp:10000 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 revlp:10000 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 revlp:10000 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 revlp:10000 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 revlp:10000 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 revlp:10000 ]", +] +`; + +exports[`runs examples > example "revlp" example index 1 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 revlp:5000 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 revlp:5000 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 revlp:5000 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 revlp:5000 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 revlp:5000 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 revlp:5000 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 revlp:5000 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 revlp:5000 ]", +] +`; + exports[`runs examples > example "ribbon" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:C3 ]", From 13cb32903a8e44f2fb11a74a62a6776caf3d6624 Mon Sep 17 00:00:00 2001 From: Vasilii Milovidov Date: Mon, 2 Oct 2023 12:13:44 +0400 Subject: [PATCH 133/175] Prepare to merge with PR #718 --- packages/core/controls.mjs | 68 +++++++-- packages/superdough/reverb.mjs | 53 +++++-- packages/superdough/reverbGen.mjs | 207 ++++++++++++++++++++++++++++ packages/superdough/superdough.mjs | 34 +++-- website/src/pages/learn/effects.mdx | 16 +++ 5 files changed, 341 insertions(+), 37 deletions(-) create mode 100644 packages/superdough/reverbGen.mjs diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index bc06ecc2..d909423f 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -980,7 +980,62 @@ const generic_params = [ * s("bd sd").room(.8).roomsize("<0 1 2 4 8>") * */ - + /** + * Reverb lowpass starting frequency (in hertz). + * + * @name revlp + * @param {number} level between 0 and 20000hz + * @example + * s("bd sd").room(0.5).revlp(10000) + * @example + * s("bd sd").room(0.5).revlp(5000) + */ + ['revlp'], + /** + * Reverb lowpass frequency at -60dB (in hertz). + * + * @name revdim + * @param {number} level between 0 and 20000hz + * @example + * s("bd sd").room(0.5).revlp(10000).revdim(8000) + * @example + * s("bd sd").room(0.5).revlp(5000).revdim(400) + * + */ + ['revdim'], + /** + * Reverb fade time (in seconds). + * + * @name fade + * @param {number} seconds for the reverb to fade + * @example + * s("bd sd").room(0.5).revlp(10000).fade(0.5) + * @example + * s("bd sd").room(0.5).revlp(5000).fade(4) + * + */ + ['fade'], + /** + * Sets the sample to use as an impulse response for the reverb. + * + * @name iresponse + * @param {string | Pattern} sample sample to pick as an impulse response + * @synonyms ir + * @example + * s("bd sd").room(.8).ir("") + * + */ + [['ir', 'i'], 'iresponse'], + /** + * Sets the room size of the reverb, see {@link room}. + * + * @name roomsize + * @param {number | Pattern} size between 0 and 10 + * @synonyms size, sz + * @example + * s("bd sd").room(.8).roomsize("<0 1 2 4 8>") + * + */ // TODO: find out why : // s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc() // .. does not work. Is it because room is only one effect? @@ -990,17 +1045,6 @@ const generic_params = [ // ['sclaves'], // ['scrash'], - /** - * Sets the sample to use as an impulse response for the reverb. - * - * @name iresponse - * @param {string | Pattern} Sets the impulse response - * @example - * s("bd sd").room(.8).ir("") - * - */ - [['ir', 'i'], 'iresponse'], - /** * Wave shaping distortion. CAUTION: it might get loud * diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index e72af033..5e4ce8f1 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -1,11 +1,7 @@ +import reverbGen from './reverbGen.mjs'; + if (typeof AudioContext !== 'undefined') { - AudioContext.prototype.impulseResponse = function (duration, channels = 1) { - const length = this.sampleRate * duration; - const impulse = this.createBuffer(channels, length, this.sampleRate); - const IR = impulse.getChannelData(0); - for (let i = 0; i < length; i++) IR[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, duration); - return impulse; - }; + AudioContext.prototype.generateReverb = reverbGen.generateReverb; AudioContext.prototype.adjustLength = function (duration, buffer) { const newLength = buffer.sampleRate * duration; @@ -21,17 +17,44 @@ if (typeof AudioContext !== 'undefined') { return newBuffer; }; - AudioContext.prototype.createReverb = function (duration, buffer) { + AudioContext.prototype.createReverb = function (audioContext, duration, fade, revlp, revdim, imp) { const convolver = this.createConvolver(); - convolver.setDuration = (dur, imp) => { - convolver.buffer = imp ? this.adjustLength(dur, imp) : this.impulseResponse(dur); + + convolver.setDuration = (d, fade, revlp, revdim, imp) => { + if (imp) { + convolver.buffer = this.adjustLength(d, imp); + return convolver; + } else { + this.generateReverb( + { + audioContext, + sampleRate: 44100, + numChannels: 2, + decayTime: d, + fadeInTime: fade, + lpFreqStart: revlp, + lpFreqEnd: revdim, + }, + (buffer) => { + convolver.buffer = buffer; + }, + ); + convolver.duration = duration; + convolver.fade = fade; + convolver.revlp = revlp; + convolver.revdim = revdim; + return convolver; + } + }; + convolver.setIR = (d, fade, revlp, revdim, imp) => { + if (imp) { + convolver.buffer = this.adjustLength(d, imp); + } else { + convolver.setDuration(d, fade, revlp, revdim, imp); + } return convolver; }; - convolver.setIR = (dur, imp) => { - convolver.buffer = imp ? this.adjustLength(dur, imp) : this.impulseResponse(dur); - return convolver; - }; - convolver.setDuration(duration, buffer); + convolver.setDuration(duration, fade, revlp, revdim, imp); return convolver; }; } diff --git a/packages/superdough/reverbGen.mjs b/packages/superdough/reverbGen.mjs new file mode 100644 index 00000000..9fb46173 --- /dev/null +++ b/packages/superdough/reverbGen.mjs @@ -0,0 +1,207 @@ +// Copyright 2014 Alan deLespinasse +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +var reverbGen = {}; + +/** Generates a reverb impulse response. + + @param {!Object} params TODO: Document the properties. + @param {!function(!AudioBuffer)} callback Function to call when + the impulse response has been generated. The impulse response + is passed to this function as its parameter. May be called + immediately within the current execution context, or later. */ +reverbGen.generateReverb = function (params, callback) { + var audioContext = params.audioContext || new AudioContext(); + var sampleRate = params.sampleRate || 44100; + var numChannels = params.numChannels || 2; + // params.decayTime is the -60dB fade time. We let it go 50% longer to get to -90dB. + var totalTime = params.decayTime * 1.5; + var decaySampleFrames = Math.round(params.decayTime * sampleRate); + var numSampleFrames = Math.round(totalTime * sampleRate); + var fadeInSampleFrames = Math.round((params.fadeInTime || 0) * sampleRate); + // 60dB is a factor of 1 million in power, or 1000 in amplitude. + var decayBase = Math.pow(1 / 1000, 1 / decaySampleFrames); + var reverbIR = audioContext.createBuffer(numChannels, numSampleFrames, sampleRate); + for (var i = 0; i < numChannels; i++) { + var chan = reverbIR.getChannelData(i); + for (var j = 0; j < numSampleFrames; j++) { + chan[j] = randomSample() * Math.pow(decayBase, j); + } + for (var j = 0; j < fadeInSampleFrames; j++) { + chan[j] *= j / fadeInSampleFrames; + } + } + + applyGradualLowpass(reverbIR, params.lpFreqStart || 0, params.lpFreqEnd || 0, params.decayTime, callback); +}; + +/** Creates a canvas element showing a graph of the given data. + + @param {!Float32Array} data An array of numbers, or a Float32Array. + @param {number} width Width in pixels of the canvas. + @param {number} height Height in pixels of the canvas. + @param {number} min Minimum value of data for the graph (lower edge). + @param {number} max Maximum value of data in the graph (upper edge). + @return {!CanvasElement} The generated canvas element. */ +reverbGen.generateGraph = function (data, width, height, min, max) { + var canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + var gc = canvas.getContext('2d'); + gc.fillStyle = '#000'; + gc.fillRect(0, 0, canvas.width, canvas.height); + gc.fillStyle = '#fff'; + var xscale = width / data.length; + var yscale = height / (max - min); + for (var i = 0; i < data.length; i++) { + gc.fillRect(i * xscale, height - (data[i] - min) * yscale, 1, 1); + } + return canvas; +}; + +/** Saves an AudioBuffer as a 16-bit WAV file on the client's host + file system. Normalizes it to peak at +-32767, and optionally + truncates it if there's a lot of "silence" at the end. + + @param {!AudioBuffer} buffer The buffer to save. + @param {string} name Name of file to create. + @param {number?} opt_minTail Defines what counts as "silence" for + auto-truncating the buffer. If there is a point past which every + value of every channel is less than opt_minTail, then the buffer + is truncated at that point. This is expressed as an integer, + applying to the post-normalized and integer-converted + buffer. The default is 0, meaning don't truncate. */ +reverbGen.saveWavFile = function (buffer, name, opt_minTail) { + var bitsPerSample = 16; + var bytesPerSample = 2; + var sampleRate = buffer.sampleRate; + var numChannels = buffer.numberOfChannels; + var channels = getAllChannelData(buffer); + var numSampleFrames = channels[0].length; + var scale = 32767; + // Find normalization constant. + var max = 0; + for (var i = 0; i < numChannels; i++) { + for (var j = 0; j < numSampleFrames; j++) { + max = Math.max(max, Math.abs(channels[i][j])); + } + } + if (max) { + scale = 32767 / max; + } + // Find truncation point. + if (opt_minTail) { + var truncateAt = 0; + for (var i = 0; i < numChannels; i++) { + for (var j = 0; j < numSampleFrames; j++) { + var absSample = Math.abs(Math.round(scale * channels[i][j])); + if (absSample > opt_minTail) { + truncateAt = j; + } + } + } + numSampleFrames = truncateAt + 1; + } + var sampleDataBytes = bytesPerSample * numChannels * numSampleFrames; + var fileBytes = sampleDataBytes + 44; + var arrayBuffer = new ArrayBuffer(fileBytes); + var dataView = new DataView(arrayBuffer); + dataView.setUint32(0, 1179011410, true); // "RIFF" + dataView.setUint32(4, fileBytes - 8, true); // file length + dataView.setUint32(8, 1163280727, true); // "WAVE" + dataView.setUint32(12, 544501094, true); // "fmt " + dataView.setUint32(16, 16, true); // fmt chunk length + dataView.setUint16(20, 1, true); // PCM format + dataView.setUint16(22, numChannels, true); // NumChannels + dataView.setUint32(24, sampleRate, true); // SampleRate + var bytesPerSampleFrame = numChannels * bytesPerSample; + dataView.setUint32(28, sampleRate * bytesPerSampleFrame, true); // ByteRate + dataView.setUint16(32, bytesPerSampleFrame, true); // BlockAlign + dataView.setUint16(34, bitsPerSample, true); // BitsPerSample + dataView.setUint32(36, 1635017060, true); // "data" + dataView.setUint32(40, sampleDataBytes, true); + for (var j = 0; j < numSampleFrames; j++) { + for (var i = 0; i < numChannels; i++) { + dataView.setInt16(44 + j * bytesPerSampleFrame + i * bytesPerSample, Math.round(scale * channels[i][j]), true); + } + } + var blob = new Blob([arrayBuffer], { type: 'audio/wav' }); + var url = window.URL.createObjectURL(blob); + var linkEl = document.createElement('a'); + linkEl.href = url; + linkEl.download = name; + linkEl.style.display = 'none'; + document.body.appendChild(linkEl); + linkEl.click(); +}; + +/** Applies a constantly changing lowpass filter to the given sound. + + @private + @param {!AudioBuffer} input + @param {number} lpFreqStart + @param {number} lpFreqEnd + @param {number} lpFreqEndAt + @param {!function(!AudioBuffer)} callback May be called + immediately within the current execution context, or later.*/ +var applyGradualLowpass = function (input, lpFreqStart, lpFreqEnd, lpFreqEndAt, callback) { + if (lpFreqStart == 0) { + callback(input); + return; + } + var channelData = getAllChannelData(input); + var context = new OfflineAudioContext(input.numberOfChannels, channelData[0].length, input.sampleRate); + var player = context.createBufferSource(); + player.buffer = input; + var filter = context.createBiquadFilter(); + + lpFreqStart = Math.min(lpFreqStart, input.sampleRate / 2); + lpFreqEnd = Math.min(lpFreqEnd, input.sampleRate / 2); + + filter.type = 'lowpass'; + filter.Q.value = 0.0001; + filter.frequency.setValueAtTime(lpFreqStart, 0); + filter.frequency.linearRampToValueAtTime(lpFreqEnd, lpFreqEndAt); + + player.connect(filter); + filter.connect(context.destination); + player.start(); + context.oncomplete = function (event) { + callback(event.renderedBuffer); + }; + context.startRendering(); + + window.filterNode = filter; +}; + +/** @private + @param {!AudioBuffer} buffer + @return {!Array.} An array containing the Float32Array of each channel's samples. */ +var getAllChannelData = function (buffer) { + var channels = []; + for (var i = 0; i < buffer.numberOfChannels; i++) { + channels[i] = buffer.getChannelData(i); + } + return channels; +}; + +/** @private + @return {number} A random number from -1 to 1. */ +var randomSample = function () { + return Math.random() * 2 - 1; +}; + +export default reverbGen; diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index fdf42c02..ec3b981e 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -114,20 +114,31 @@ function getDelay(orbit, delaytime, delayfeedback, t) { let reverbs = {}; -function getReverb(orbit, duration = 2, ir) { +function getReverb(orbit, duration = 2, fade, revlp, revdim, imp) { if (!reverbs[orbit]) { const ac = getAudioContext(); - const reverb = ac.createReverb(duration, ir); + const reverb = ac.createReverb(getAudioContext(), duration, fade, revlp, revdim, imp); reverb.connect(getDestination()); reverbs[orbit] = reverb; } - if (reverbs[orbit].duration !== duration) { - reverbs[orbit] = reverbs[orbit].setDuration(duration, ir); + + const reverbOrbit = reverbs[orbit]; + + if ( + reverbs[orbit].duration !== duration || + reverbs[orbit].fade !== fade || + reverbs[orbit].revlp !== revlp || + reverbs[orbit].revdim !== revdim + ) { + reverbs[orbit].setDuration(duration, fade, revlp, revdim); reverbs[orbit].duration = duration; + reverbs[orbit].fade = fade; + reverbs[orbit].revlp = revlp; + reverbs[orbit].revdim = revdim; } - if (reverbs[orbit].ir !== ir) { - reverbs[orbit] = reverbs[orbit].setIR(duration, ir); - reverbs[orbit].ir = ir; + if (reverbs[orbit].ir !== imp) { + reverbs[orbit] = reverbs[orbit].setIR(duration, fade, revlp, revdim, imp); + reverbs[orbit].ir = imp; } return reverbs[orbit]; } @@ -227,12 +238,15 @@ export const superdough = async (value, deadline, hapDuration) => { delaytime = 0.25, orbit = 1, room, + fade = 0.1, + revlp = 15000, + revdim = 1000, size = 2, + ir, + i = 0, velocity = 1, analyze, // analyser wet fft = 8, // fftSize 0 - 10 - ir, - i = 0, } = value; gain *= velocity; // legacy fix for velocity let toDisconnect = []; // audio nodes that will be disconnected when the source has ended @@ -380,7 +394,7 @@ export const superdough = async (value, deadline, hapDuration) => { } let reverbSend; if (room > 0 && size > 0) { - const reverbNode = getReverb(orbit, size, buffer); + const reverbNode = getReverb(orbit, size, fade, revlp, revdim, buffer); reverbSend = effectSend(post, reverbNode, room); } diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index f77ab4c4..3ca43f69 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -203,4 +203,20 @@ global effects use the same chain for all events of the same orbit: +## fade + + + +## revlp + + + +## revdim + + + +## iresponse + + + Next, we'll look at strudel's support for [Csound](/learn/csound). From 28966739f61222d83087355baf99413168ef5607 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 2 Oct 2023 20:44:51 +0200 Subject: [PATCH 134/175] feat: add step as slider param --- packages/codemirror/slider.mjs | 9 +++++---- packages/transpiler/transpiler.mjs | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 47b686c8..62ec33c2 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -6,7 +6,7 @@ export let sliderValues = {}; const getSliderID = (from) => `slider_${from}`; export class SliderWidget extends WidgetType { - constructor(value, min, max, from, to, view) { + constructor(value, min, max, from, to, step, view) { super(); this.value = value; this.min = min; @@ -14,6 +14,7 @@ export class SliderWidget extends WidgetType { this.from = from; this.originalFrom = from; this.to = to; + this.step = step; this.view = view; } @@ -29,7 +30,7 @@ export class SliderWidget extends WidgetType { slider.type = 'range'; slider.min = this.min; slider.max = this.max; - slider.step = (this.max - this.min) / 1000; + slider.step = this.step ?? (this.max - this.min) / 1000; slider.originalValue = this.value; // to make sure the code stays in sync, let's save the original value // becuase .value automatically clamps values so it'll desync with the code @@ -66,9 +67,9 @@ export const updateWidgets = (view, widgets) => { }; function getWidgets(widgetConfigs, view) { - return widgetConfigs.map(({ from, to, value, min, max }) => { + return widgetConfigs.map(({ from, to, value, min, max, step }) => { return Decoration.widget({ - widget: new SliderWidget(value, min, max, from, to, view), + widget: new SliderWidget(value, min, max, from, to, step, view), side: 0, }).range(from /* , to */); }); diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 6eac171f..256be1d2 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -43,6 +43,7 @@ export function transpiler(input, options = {}) { value: node.arguments[0].raw, // don't use value! min: node.arguments[1]?.value ?? 0, max: node.arguments[2]?.value ?? 1, + step: node.arguments[3]?.value, }); return this.replace(widgetWithLocation(node)); } From a3649148c1ab0975a1a3486a3bd68313c762dbb5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 3 Oct 2023 08:35:15 +0200 Subject: [PATCH 135/175] more logical naming + update docs --- packages/core/controls.mjs | 43 +++++++++++++++++------------ packages/superdough/superdough.mjs | 12 ++++---- website/src/pages/learn/effects.mdx | 26 +++++++++-------- 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index e72f006d..63ffdaf4 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -972,53 +972,62 @@ const generic_params = [ [['room', 'size']], /** * Reverb lowpass starting frequency (in hertz). + * When this property is changed, the reverb will be recaculated, so only change this sparsely.. * - * @name revlp - * @param {number} level between 0 and 20000hz + * @name roomlp + * @synonyms rlp + * @param {number} frequency between 0 and 20000hz * @example - * s("bd sd").room(0.5).revlp(10000) + * s("bd sd").room(0.5).rlp(10000) * @example - * s("bd sd").room(0.5).revlp(5000) + * s("bd sd").room(0.5).rlp(5000) */ - ['revlp'], + ['roomlp', 'rlp'], /** * Reverb lowpass frequency at -60dB (in hertz). + * When this property is changed, the reverb will be recaculated, so only change this sparsely.. * - * @name revdim - * @param {number} level between 0 and 20000hz + * @name roomdim + * @synonyms rdim + * @param {number} frequency between 0 and 20000hz * @example - * s("bd sd").room(0.5).revlp(10000).revdim(8000) + * s("bd sd").room(0.5).rlp(10000).rdim(8000) * @example - * s("bd sd").room(0.5).revlp(5000).revdim(400) + * s("bd sd").room(0.5).rlp(5000).rdim(400) * */ - ['revdim'], + ['roomdim', 'rdim'], /** * Reverb fade time (in seconds). + * When this property is changed, the reverb will be recaculated, so only change this sparsely.. * - * @name fade + * @name roomfade + * @synonyms rfade * @param {number} seconds for the reverb to fade * @example - * s("bd sd").room(0.5).revlp(10000).fade(0.5) + * s("bd sd").room(0.5).rlp(10000).rfade(0.5) * @example - * s("bd sd").room(0.5).revlp(5000).fade(4) + * s("bd sd").room(0.5).rlp(5000).rfade(4) * */ - ['fade'], + ['roomfade', 'rfade'], /** * Sets the room size of the reverb, see {@link room}. + * When this property is changed, the reverb will be recaculated, so only change this sparsely.. * * @name roomsize * @param {number | Pattern} size between 0 and 10 - * @synonyms size, sz + * @synonyms rsize, sz, size * @example - * s("bd sd").room(.8).roomsize("<0 1 2 4 8>") + * s("bd sd").room(.8).rsize(1) + * @example + * s("bd sd").room(.8).rsize(4) * */ // TODO: find out why : // s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc() // .. does not work. Is it because room is only one effect? - ['size', 'sz', 'roomsize'], + ['roomsize', 'size', 'sz', 'rsize'], // ['sagogo'], // ['sclap'], // ['sclaves'], diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 28f4c261..e387ff6c 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -227,10 +227,10 @@ export const superdough = async (value, deadline, hapDuration) => { delaytime = 0.25, orbit = 1, room, - fade = 0.1, - revlp = 15000, - revdim = 1000, - size = 2, + roomfade = 0.1, + roomlp = 15000, + roomdim = 1000, + roomsize = 2, velocity = 1, analyze, // analyser wet fft = 8, // fftSize 0 - 10 @@ -368,8 +368,8 @@ export const superdough = async (value, deadline, hapDuration) => { } // reverb let reverbSend; - if (room > 0 && size > 0) { - const reverbNode = getReverb(orbit, size, fade, revlp, revdim); + if (room > 0 && roomsize > 0) { + const reverbNode = getReverb(orbit, roomsize, roomfade, roomlp, roomdim); reverbSend = effectSend(post, reverbNode, room); } diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index 062a1947..2ee6c44a 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -183,36 +183,40 @@ global effects use the same chain for all events of the same orbit: -## delay +## Delay + +### delay -## delaytime +### delaytime -## delayfeedback +### delayfeedback -## room +## Reverb + +### room -## roomsize +### roomsize -## fade +### roomfade - + -## revlp +### roomlp - + -## revdim +### roomdim - + Next, we'll look at strudel's support for [Csound](/learn/csound). From 904306454349862a7356f355c294e3e89f457842 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 3 Oct 2023 08:36:52 +0200 Subject: [PATCH 136/175] snapshot --- test/__snapshots__/examples.test.mjs.snap | 185 ++++++++++++---------- 1 file changed, 99 insertions(+), 86 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 616fff12..99d078ea 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1773,32 +1773,6 @@ exports[`runs examples > example "every" example index 0 1`] = ` ] `; -exports[`runs examples > example "fade" example index 0 1`] = ` -[ - "[ 0/1 → 1/2 | s:bd room:0.5 revlp:10000 fade:0.5 ]", - "[ 1/2 → 1/1 | s:sd room:0.5 revlp:10000 fade:0.5 ]", - "[ 1/1 → 3/2 | s:bd room:0.5 revlp:10000 fade:0.5 ]", - "[ 3/2 → 2/1 | s:sd room:0.5 revlp:10000 fade:0.5 ]", - "[ 2/1 → 5/2 | s:bd room:0.5 revlp:10000 fade:0.5 ]", - "[ 5/2 → 3/1 | s:sd room:0.5 revlp:10000 fade:0.5 ]", - "[ 3/1 → 7/2 | s:bd room:0.5 revlp:10000 fade:0.5 ]", - "[ 7/2 → 4/1 | s:sd room:0.5 revlp:10000 fade:0.5 ]", -] -`; - -exports[`runs examples > example "fade" example index 1 1`] = ` -[ - "[ 0/1 → 1/2 | s:bd room:0.5 revlp:5000 fade:4 ]", - "[ 1/2 → 1/1 | s:sd room:0.5 revlp:5000 fade:4 ]", - "[ 1/1 → 3/2 | s:bd room:0.5 revlp:5000 fade:4 ]", - "[ 3/2 → 2/1 | s:sd room:0.5 revlp:5000 fade:4 ]", - "[ 2/1 → 5/2 | s:bd room:0.5 revlp:5000 fade:4 ]", - "[ 5/2 → 3/1 | s:sd room:0.5 revlp:5000 fade:4 ]", - "[ 3/1 → 7/2 | s:bd room:0.5 revlp:5000 fade:4 ]", - "[ 7/2 → 4/1 | s:sd room:0.5 revlp:5000 fade:4 ]", -] -`; - exports[`runs examples > example "fast" example index 0 1`] = ` [ "[ 0/1 → 1/4 | s:bd ]", @@ -3633,58 +3607,6 @@ exports[`runs examples > example "rev" example index 0 1`] = ` ] `; -exports[`runs examples > example "revdim" example index 0 1`] = ` -[ - "[ 0/1 → 1/2 | s:bd room:0.5 revlp:10000 revdim:8000 ]", - "[ 1/2 → 1/1 | s:sd room:0.5 revlp:10000 revdim:8000 ]", - "[ 1/1 → 3/2 | s:bd room:0.5 revlp:10000 revdim:8000 ]", - "[ 3/2 → 2/1 | s:sd room:0.5 revlp:10000 revdim:8000 ]", - "[ 2/1 → 5/2 | s:bd room:0.5 revlp:10000 revdim:8000 ]", - "[ 5/2 → 3/1 | s:sd room:0.5 revlp:10000 revdim:8000 ]", - "[ 3/1 → 7/2 | s:bd room:0.5 revlp:10000 revdim:8000 ]", - "[ 7/2 → 4/1 | s:sd room:0.5 revlp:10000 revdim:8000 ]", -] -`; - -exports[`runs examples > example "revdim" example index 1 1`] = ` -[ - "[ 0/1 → 1/2 | s:bd room:0.5 revlp:5000 revdim:400 ]", - "[ 1/2 → 1/1 | s:sd room:0.5 revlp:5000 revdim:400 ]", - "[ 1/1 → 3/2 | s:bd room:0.5 revlp:5000 revdim:400 ]", - "[ 3/2 → 2/1 | s:sd room:0.5 revlp:5000 revdim:400 ]", - "[ 2/1 → 5/2 | s:bd room:0.5 revlp:5000 revdim:400 ]", - "[ 5/2 → 3/1 | s:sd room:0.5 revlp:5000 revdim:400 ]", - "[ 3/1 → 7/2 | s:bd room:0.5 revlp:5000 revdim:400 ]", - "[ 7/2 → 4/1 | s:sd room:0.5 revlp:5000 revdim:400 ]", -] -`; - -exports[`runs examples > example "revlp" example index 0 1`] = ` -[ - "[ 0/1 → 1/2 | s:bd room:0.5 revlp:10000 ]", - "[ 1/2 → 1/1 | s:sd room:0.5 revlp:10000 ]", - "[ 1/1 → 3/2 | s:bd room:0.5 revlp:10000 ]", - "[ 3/2 → 2/1 | s:sd room:0.5 revlp:10000 ]", - "[ 2/1 → 5/2 | s:bd room:0.5 revlp:10000 ]", - "[ 5/2 → 3/1 | s:sd room:0.5 revlp:10000 ]", - "[ 3/1 → 7/2 | s:bd room:0.5 revlp:10000 ]", - "[ 7/2 → 4/1 | s:sd room:0.5 revlp:10000 ]", -] -`; - -exports[`runs examples > example "revlp" example index 1 1`] = ` -[ - "[ 0/1 → 1/2 | s:bd room:0.5 revlp:5000 ]", - "[ 1/2 → 1/1 | s:sd room:0.5 revlp:5000 ]", - "[ 1/1 → 3/2 | s:bd room:0.5 revlp:5000 ]", - "[ 3/2 → 2/1 | s:sd room:0.5 revlp:5000 ]", - "[ 2/1 → 5/2 | s:bd room:0.5 revlp:5000 ]", - "[ 5/2 → 3/1 | s:sd room:0.5 revlp:5000 ]", - "[ 3/1 → 7/2 | s:bd room:0.5 revlp:5000 ]", - "[ 7/2 → 4/1 | s:sd room:0.5 revlp:5000 ]", -] -`; - exports[`runs examples > example "ribbon" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:C3 ]", @@ -3732,16 +3654,107 @@ exports[`runs examples > example "room" example index 1 1`] = ` ] `; +exports[`runs examples > example "roomdim" example index 0 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 roomlp:10000 roomdim:8000 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 roomlp:10000 roomdim:8000 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 roomlp:10000 roomdim:8000 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 roomlp:10000 roomdim:8000 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 roomlp:10000 roomdim:8000 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 roomlp:10000 roomdim:8000 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 roomlp:10000 roomdim:8000 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 roomlp:10000 roomdim:8000 ]", +] +`; + +exports[`runs examples > example "roomdim" example index 1 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 roomlp:5000 roomdim:400 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 roomlp:5000 roomdim:400 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 roomlp:5000 roomdim:400 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 roomlp:5000 roomdim:400 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 roomlp:5000 roomdim:400 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 roomlp:5000 roomdim:400 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 roomlp:5000 roomdim:400 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 roomlp:5000 roomdim:400 ]", +] +`; + +exports[`runs examples > example "roomfade" example index 0 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 roomlp:10000 roomfade:0.5 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 roomlp:10000 roomfade:0.5 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 roomlp:10000 roomfade:0.5 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 roomlp:10000 roomfade:0.5 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 roomlp:10000 roomfade:0.5 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 roomlp:10000 roomfade:0.5 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 roomlp:10000 roomfade:0.5 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 roomlp:10000 roomfade:0.5 ]", +] +`; + +exports[`runs examples > example "roomfade" example index 1 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 roomlp:5000 roomfade:4 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 roomlp:5000 roomfade:4 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 roomlp:5000 roomfade:4 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 roomlp:5000 roomfade:4 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 roomlp:5000 roomfade:4 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 roomlp:5000 roomfade:4 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 roomlp:5000 roomfade:4 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 roomlp:5000 roomfade:4 ]", +] +`; + +exports[`runs examples > example "roomlp" example index 0 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 roomlp:10000 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 roomlp:10000 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 roomlp:10000 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 roomlp:10000 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 roomlp:10000 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 roomlp:10000 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 roomlp:10000 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 roomlp:10000 ]", +] +`; + +exports[`runs examples > example "roomlp" example index 1 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.5 roomlp:5000 ]", + "[ 1/2 → 1/1 | s:sd room:0.5 roomlp:5000 ]", + "[ 1/1 → 3/2 | s:bd room:0.5 roomlp:5000 ]", + "[ 3/2 → 2/1 | s:sd room:0.5 roomlp:5000 ]", + "[ 2/1 → 5/2 | s:bd room:0.5 roomlp:5000 ]", + "[ 5/2 → 3/1 | s:sd room:0.5 roomlp:5000 ]", + "[ 3/1 → 7/2 | s:bd room:0.5 roomlp:5000 ]", + "[ 7/2 → 4/1 | s:sd room:0.5 roomlp:5000 ]", +] +`; + exports[`runs examples > example "roomsize" example index 0 1`] = ` [ - "[ 0/1 → 1/2 | s:bd room:0.8 size:0 ]", - "[ 1/2 → 1/1 | s:sd room:0.8 size:0 ]", - "[ 1/1 → 3/2 | s:bd room:0.8 size:1 ]", - "[ 3/2 → 2/1 | s:sd room:0.8 size:1 ]", - "[ 2/1 → 5/2 | s:bd room:0.8 size:2 ]", - "[ 5/2 → 3/1 | s:sd room:0.8 size:2 ]", - "[ 3/1 → 7/2 | s:bd room:0.8 size:4 ]", - "[ 7/2 → 4/1 | s:sd room:0.8 size:4 ]", + "[ 0/1 → 1/2 | s:bd room:0.8 roomsize:1 ]", + "[ 1/2 → 1/1 | s:sd room:0.8 roomsize:1 ]", + "[ 1/1 → 3/2 | s:bd room:0.8 roomsize:1 ]", + "[ 3/2 → 2/1 | s:sd room:0.8 roomsize:1 ]", + "[ 2/1 → 5/2 | s:bd room:0.8 roomsize:1 ]", + "[ 5/2 → 3/1 | s:sd room:0.8 roomsize:1 ]", + "[ 3/1 → 7/2 | s:bd room:0.8 roomsize:1 ]", + "[ 7/2 → 4/1 | s:sd room:0.8 roomsize:1 ]", +] +`; + +exports[`runs examples > example "roomsize" example index 1 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.8 roomsize:4 ]", + "[ 1/2 → 1/1 | s:sd room:0.8 roomsize:4 ]", + "[ 1/1 → 3/2 | s:bd room:0.8 roomsize:4 ]", + "[ 3/2 → 2/1 | s:sd room:0.8 roomsize:4 ]", + "[ 2/1 → 5/2 | s:bd room:0.8 roomsize:4 ]", + "[ 5/2 → 3/1 | s:sd room:0.8 roomsize:4 ]", + "[ 3/1 → 7/2 | s:bd room:0.8 roomsize:4 ]", + "[ 7/2 → 4/1 | s:sd room:0.8 roomsize:4 ]", ] `; From 1e352fdf8001696b243cdb7f7fc777e34b151eb5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 3 Oct 2023 08:51:35 +0200 Subject: [PATCH 137/175] codeformat --- packages/superdough/synth.mjs | 215 +++++++++++++++-------------- website/src/pages/learn/synths.mdx | 5 +- 2 files changed, 111 insertions(+), 109 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index e5f84bcf..51d56993 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -20,104 +20,110 @@ const fm = (osc, harmonicityRatio, modulationIndex, wave = 'sine') => { return mod(modfreq, modgain, wave); }; - export function registerSynthSounds() { - ['sine', 'square', 'triangle', - 'sawtooth', 'pink', 'white', - 'brown'].forEach((wave) => { - registerSound( - wave, - (t, value, onended) => { - // destructure adsr here, because the default should be different for synths and samples - let { - attack = 0.001, - decay = 0.05, - sustain = 0.6, - release = 0.01, - fmh: fmHarmonicity = 1, - fmi: fmModulationIndex, - fmenv: fmEnvelopeType = 'lin', - fmattack: fmAttack, - fmdecay: fmDecay, - fmsustain: fmSustain, - fmrelease: fmRelease, - fmvelocity: fmVelocity, - fmwave: fmWaveform = 'sine', - vib = 0, - vibmod = 0.5, - noise = 0, - } = value; - let { n, note, freq } = value; - // with synths, n and note are the same thing - note = note || 36; - if (typeof note === 'string') { - note = noteToMidi(note); // e.g. c3 => 48 - } - // get frequency - if (!freq && typeof note === 'number') { - freq = midiToFreq(note); // + 48); - } - // maybe pull out the above frequency resolution?? (there is also getFrequency but it has no default) - // make oscillator - const { node: o, stop, dry_node = null } = getOscillator({ - t, - s: wave, - freq, - vib, - vibmod, - partials: n, - noise: noise, - }); - // FM + FM envelope - let stopFm, fmEnvelope; - if (fmModulationIndex) { - const { node: modulator, stop } = fm(dry_node !== null ? dry_node : o, fmHarmonicity, fmModulationIndex, fmWaveform); - if (![fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity].find((v) => v !== undefined)) { - // no envelope by default - modulator.connect(dry_node !== null ? dry_node.frequency : o.frequency); - } else { - fmAttack = fmAttack ?? 0.001; - fmDecay = fmDecay ?? 0.001; - fmSustain = fmSustain ?? 1; - fmRelease = fmRelease ?? 0.001; - fmVelocity = fmVelocity ?? 1; - fmEnvelope = getEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); - if (fmEnvelopeType === 'exp') { - fmEnvelope = getExpEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); - fmEnvelope.node.maxValue = fmModulationIndex * 2; - fmEnvelope.node.minValue = 0.00001; - } - modulator.connect(fmEnvelope.node); - fmEnvelope.node.connect(dry_node !== null ? dry_node.frequency : o.frequency); + ['sine', 'square', 'triangle', 'sawtooth', 'pink', 'white', 'brown'].forEach((wave) => { + registerSound( + wave, + (t, value, onended) => { + // destructure adsr here, because the default should be different for synths and samples + let { + attack = 0.001, + decay = 0.05, + sustain = 0.6, + release = 0.01, + fmh: fmHarmonicity = 1, + fmi: fmModulationIndex, + fmenv: fmEnvelopeType = 'lin', + fmattack: fmAttack, + fmdecay: fmDecay, + fmsustain: fmSustain, + fmrelease: fmRelease, + fmvelocity: fmVelocity, + fmwave: fmWaveform = 'sine', + vib = 0, + vibmod = 0.5, + noise = 0, + } = value; + let { n, note, freq } = value; + // with synths, n and note are the same thing + note = note || 36; + if (typeof note === 'string') { + note = noteToMidi(note); // e.g. c3 => 48 + } + // get frequency + if (!freq && typeof note === 'number') { + freq = midiToFreq(note); // + 48); + } + // maybe pull out the above frequency resolution?? (there is also getFrequency but it has no default) + // make oscillator + const { + node: o, + stop, + dry_node = null, + } = getOscillator({ + t, + s: wave, + freq, + vib, + vibmod, + partials: n, + noise: noise, + }); + // FM + FM envelope + let stopFm, fmEnvelope; + if (fmModulationIndex) { + const { node: modulator, stop } = fm( + dry_node !== null ? dry_node : o, + fmHarmonicity, + fmModulationIndex, + fmWaveform, + ); + if (![fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity].find((v) => v !== undefined)) { + // no envelope by default + modulator.connect(dry_node !== null ? dry_node.frequency : o.frequency); + } else { + fmAttack = fmAttack ?? 0.001; + fmDecay = fmDecay ?? 0.001; + fmSustain = fmSustain ?? 1; + fmRelease = fmRelease ?? 0.001; + fmVelocity = fmVelocity ?? 1; + fmEnvelope = getEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); + if (fmEnvelopeType === 'exp') { + fmEnvelope = getExpEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); + fmEnvelope.node.maxValue = fmModulationIndex * 2; + fmEnvelope.node.minValue = 0.00001; } - stopFm = stop; + modulator.connect(fmEnvelope.node); + fmEnvelope.node.connect(dry_node !== null ? dry_node.frequency : o.frequency); } + stopFm = stop; + } - // turn down - const g = gainNode(0.3); + // turn down + const g = gainNode(0.3); - // gain envelope - const { node: envelope, stop: releaseEnvelope } = getEnvelope(attack, decay, sustain, release, 1, t); + // gain envelope + const { node: envelope, stop: releaseEnvelope } = getEnvelope(attack, decay, sustain, release, 1, t); - o.onended = () => { - o.disconnect(); - g.disconnect(); - onended(); - }; - return { - node: o.connect(g).connect(envelope), - stop: (releaseTime) => { - releaseEnvelope(releaseTime); - fmEnvelope?.stop(releaseTime); - let end = releaseTime + release; - stop(end); - stopFm?.(end); - }, - }; - }, - { type: 'synth', prebake: true }, - ); - }); + o.onended = () => { + o.disconnect(); + g.disconnect(); + onended(); + }; + return { + node: o.connect(g).connect(envelope), + stop: (releaseTime) => { + releaseEnvelope(releaseTime); + fmEnvelope?.stop(releaseTime); + let end = releaseTime + release; + stop(end); + stopFm?.(end); + }, + }; + }, + { type: 'synth', prebake: true }, + ); + }); } export function waveformN(partials, type) { @@ -163,16 +169,16 @@ export function getNoiseOscillator({ t, ac, type = 'white' }) { output[i] = Math.random() * 2 - 1; } else if (type === 'brown') { let white = Math.random() * 2 - 1; - output[i] = (lastOut + (0.02 * white)) / 1.02; + output[i] = (lastOut + 0.02 * white) / 1.02; lastOut = output[i]; } else if (type === 'pink') { let white = Math.random() * 2 - 1; b0 = 0.99886 * b0 + white * 0.0555179; b1 = 0.99332 * b1 + white * 0.0750759; - b2 = 0.96900 * b2 + white * 0.1538520; - b3 = 0.86650 * b3 + white * 0.3104856; - b4 = 0.55000 * b4 + white * 0.5329522; - b5 = -0.7616 * b5 - white * 0.0168980; + b2 = 0.969 * b2 + white * 0.153852; + b3 = 0.8665 * b3 + white * 0.3104856; + b4 = 0.55 * b4 + white * 0.5329522; + b5 = -0.7616 * b5 - white * 0.016898; output[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362; output[i] *= 0.11; b6 = white * 0.115926; @@ -186,7 +192,7 @@ export function getNoiseOscillator({ t, ac, type = 'white' }) { return { node: o, - stop: (time) => o.stop(time) + stop: (time) => o.stop(time), }; } @@ -196,11 +202,11 @@ export function getOscillator({ s, freq, t, vib, vibmod, partials, noise }) { let o; if (['pink', 'white', 'brown'].includes(s)) { - let noiseOscillator = getNoiseOscillator({ t: t, ac: getAudioContext(), type: s }) + let noiseOscillator = getNoiseOscillator({ t: t, ac: getAudioContext(), type: s }); return { node: noiseOscillator.node, - stop: noiseOscillator.stop - } + stop: noiseOscillator.stop, + }; } else { if (!partials || s === 'sine') { o = getAudioContext().createOscillator(); @@ -238,7 +244,7 @@ export function getOscillator({ s, freq, t, vib, vibmod, partials, noise }) { // Connecting the main oscillator to the gain node o.connect(o_gain).connect(mix_gain); - // Instanciating a noise oscillator and connecting + // Instanciating a noise oscillator and connecting const noiseOscillator = getNoiseOscillator({ t: t, ac: ac, type: 'pink' }); noiseOscillator.node.connect(n_gain).connect(mix_gain); @@ -249,8 +255,8 @@ export function getOscillator({ s, freq, t, vib, vibmod, partials, noise }) { vibrato_oscillator?.stop(time); o.stop(time); noiseOscillator.stop(time); - } - } + }, + }; } return { @@ -262,4 +268,3 @@ export function getOscillator({ s, freq, t, vib, vibmod, partials, noise }) { }; } } - diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index 661ec860..83de3ca5 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -35,10 +35,7 @@ flavours of noise, here written from hard to soft. Some amount of pink noise can also be added to any oscillator by using the `noise` paremeter: -").scope()`} -/> +").scope()`} /> ### Additive Synthesis From a0884e2a038c654a722647237f5e760810ddcf63 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 3 Oct 2023 09:09:49 +0200 Subject: [PATCH 138/175] add noise heading + hihat example --- website/src/pages/learn/synths.mdx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index 83de3ca5..432276ef 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -23,14 +23,19 @@ The basic waveforms are `sine`, `sawtooth`, `square` and `triangle`, which can b If you don't set a `sound` but a `note` the default value for `sound` is `triangle`! +## Noise + You can also use noise as a source by setting the waveform to: `white`, `pink` or `brown`. These are different flavours of noise, here written from hard to soft. +/2").scope()`} /> + +Here's a more musical example of how to use noise for hihats: + >") -.sound("/2") -.scope()`} + tune={`sound("bd*2,*8") +.decay(.04).sustain(0).scope()`} /> Some amount of pink noise can also be added to any oscillator by using the `noise` paremeter: From 484bb6b11f7c79220cc9bd0c8f5056a88232d90a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 3 Oct 2023 10:03:09 +0200 Subject: [PATCH 139/175] refactor synth - separate waveform / noise oscillators - pull noise out of getOscillator - put fm into getOscillator - simplify overall value plumbing --- packages/superdough/synth.mjs | 280 ++++++++++++++++------------------ 1 file changed, 135 insertions(+), 145 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 51d56993..f12be9c8 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -20,85 +20,26 @@ const fm = (osc, harmonicityRatio, modulationIndex, wave = 'sine') => { return mod(modfreq, modgain, wave); }; +const waveforms = ['sine', 'square', 'triangle', 'sawtooth']; +const noises = ['pink', 'white', 'brown']; + export function registerSynthSounds() { - ['sine', 'square', 'triangle', 'sawtooth', 'pink', 'white', 'brown'].forEach((wave) => { + [...waveforms, ...noises].forEach((s) => { registerSound( - wave, + s, (t, value, onended) => { // destructure adsr here, because the default should be different for synths and samples - let { - attack = 0.001, - decay = 0.05, - sustain = 0.6, - release = 0.01, - fmh: fmHarmonicity = 1, - fmi: fmModulationIndex, - fmenv: fmEnvelopeType = 'lin', - fmattack: fmAttack, - fmdecay: fmDecay, - fmsustain: fmSustain, - fmrelease: fmRelease, - fmvelocity: fmVelocity, - fmwave: fmWaveform = 'sine', - vib = 0, - vibmod = 0.5, - noise = 0, - } = value; - let { n, note, freq } = value; - // with synths, n and note are the same thing - note = note || 36; - if (typeof note === 'string') { - note = noteToMidi(note); // e.g. c3 => 48 - } - // get frequency - if (!freq && typeof note === 'number') { - freq = midiToFreq(note); // + 48); - } - // maybe pull out the above frequency resolution?? (there is also getFrequency but it has no default) - // make oscillator - const { - node: o, - stop, - dry_node = null, - } = getOscillator({ - t, - s: wave, - freq, - vib, - vibmod, - partials: n, - noise: noise, - }); - // FM + FM envelope - let stopFm, fmEnvelope; - if (fmModulationIndex) { - const { node: modulator, stop } = fm( - dry_node !== null ? dry_node : o, - fmHarmonicity, - fmModulationIndex, - fmWaveform, - ); - if (![fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity].find((v) => v !== undefined)) { - // no envelope by default - modulator.connect(dry_node !== null ? dry_node.frequency : o.frequency); - } else { - fmAttack = fmAttack ?? 0.001; - fmDecay = fmDecay ?? 0.001; - fmSustain = fmSustain ?? 1; - fmRelease = fmRelease ?? 0.001; - fmVelocity = fmVelocity ?? 1; - fmEnvelope = getEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); - if (fmEnvelopeType === 'exp') { - fmEnvelope = getExpEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); - fmEnvelope.node.maxValue = fmModulationIndex * 2; - fmEnvelope.node.minValue = 0.00001; - } - modulator.connect(fmEnvelope.node); - fmEnvelope.node.connect(dry_node !== null ? dry_node.frequency : o.frequency); - } - stopFm = stop; + let { attack = 0.001, decay = 0.05, sustain = 0.6, release = 0.01 } = value; + + let sound; + if (waveforms.includes(s)) { + sound = getOscillator(s, t, value); + } else { + sound = getNoiseOscillator(t, s); } + let { node: o, stop, triggerRelease } = sound; + // turn down const g = gainNode(0.3); @@ -114,10 +55,9 @@ export function registerSynthSounds() { node: o.connect(g).connect(envelope), stop: (releaseTime) => { releaseEnvelope(releaseTime); - fmEnvelope?.stop(releaseTime); + triggerRelease?.(releaseTime); let end = releaseTime + release; stop(end); - stopFm?.(end); }, }; }, @@ -156,7 +96,9 @@ export function waveformN(partials, type) { return osc; } -export function getNoiseOscillator({ t, ac, type = 'white' }) { +// expects one of noises as type +export function getNoiseOscillator(t, type = 'white') { + const ac = getAudioContext(); const bufferSize = 2 * ac.sampleRate; const noiseBuffer = ac.createBuffer(1, bufferSize, ac.sampleRate); const output = noiseBuffer.getChannelData(0); @@ -189,82 +131,130 @@ export function getNoiseOscillator({ t, ac, type = 'white' }) { o.buffer = noiseBuffer; o.loop = true; o.start(t); - return { node: o, stop: (time) => o.stop(time), }; } -export function getOscillator({ s, freq, t, vib, vibmod, partials, noise }) { - // Make oscillator with partial count +// expects one of waveforms as s +export function getOscillator( + s, + t, + { + n: partials, + note, + freq, + vib = 0, + vibmod = 0.5, + noise = 0, + // fm + fmh: fmHarmonicity = 1, + fmi: fmModulationIndex, + fmenv: fmEnvelopeType = 'lin', + fmattack: fmAttack, + fmdecay: fmDecay, + fmsustain: fmSustain, + fmrelease: fmRelease, + fmvelocity: fmVelocity, + fmwave: fmWaveform = 'sine', + }, +) { let ac = getAudioContext(); let o; - - if (['pink', 'white', 'brown'].includes(s)) { - let noiseOscillator = getNoiseOscillator({ t: t, ac: getAudioContext(), type: s }); - return { - node: noiseOscillator.node, - stop: noiseOscillator.stop, - }; - } else { - if (!partials || s === 'sine') { - o = getAudioContext().createOscillator(); - o.type = s || 'triangle'; - } else { - o = waveformN(partials, s); - } - o.frequency.value = Number(freq); - o.start(t); - - // Additional oscillator for vibrato effect - let vibrato_oscillator; - if (vib > 0) { - vibrato_oscillator = getAudioContext().createOscillator(); - vibrato_oscillator.frequency.value = vib; - const gain = getAudioContext().createGain(); - // Vibmod is the amount of vibrato, in semitones - gain.gain.value = vibmod * 100; - vibrato_oscillator.connect(gain); - gain.connect(o.detune); - vibrato_oscillator.start(t); - } - - if (noise > 0) { - // Two gain nodes to set the oscillators to their respective levels - noise = noise > 1 ? 1 : noise; - let o_gain = ac.createGain(); - let n_gain = ac.createGain(); - o_gain.gain.setValueAtTime(1 - noise, ac.currentTime); - n_gain.gain.setValueAtTime(noise, ac.currentTime); - - // Instanciating a mixer to blend sources together - let mix_gain = ac.createGain(); - - // Connecting the main oscillator to the gain node - o.connect(o_gain).connect(mix_gain); - - // Instanciating a noise oscillator and connecting - const noiseOscillator = getNoiseOscillator({ t: t, ac: ac, type: 'pink' }); - noiseOscillator.node.connect(n_gain).connect(mix_gain); - - return { - node: mix_gain, - dry_node: o, - stop: (time) => { - vibrato_oscillator?.stop(time); - o.stop(time); - noiseOscillator.stop(time); - }, - }; - } - - return { - node: o, - stop: (time) => { - vibrato_oscillator?.stop(time); - o.stop(time); - }, - }; + // If no partials are given, use stock waveforms + if (!partials || s === 'sine') { + o = getAudioContext().createOscillator(); + o.type = s || 'triangle'; } + // generate custom waveform if partials are given + else { + o = waveformN(partials, s); + } + + // get frequency from note... + note = note || 36; + if (typeof note === 'string') { + note = noteToMidi(note); // e.g. c3 => 48 + } + // get frequency + if (!freq && typeof note === 'number') { + freq = midiToFreq(note); // + 48); + } + + // set frequency + o.frequency.value = Number(freq); + o.start(t); + + // FM + let stopFm, fmEnvelope; + if (fmModulationIndex) { + const { node: modulator, stop } = fm(o, fmHarmonicity, fmModulationIndex, fmWaveform); + if (![fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity].find((v) => v !== undefined)) { + // no envelope by default + modulator.connect(o.frequency); + } else { + fmAttack = fmAttack ?? 0.001; + fmDecay = fmDecay ?? 0.001; + fmSustain = fmSustain ?? 1; + fmRelease = fmRelease ?? 0.001; + fmVelocity = fmVelocity ?? 1; + fmEnvelope = getEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); + if (fmEnvelopeType === 'exp') { + fmEnvelope = getExpEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); + fmEnvelope.node.maxValue = fmModulationIndex * 2; + fmEnvelope.node.minValue = 0.00001; + } + modulator.connect(fmEnvelope.node); + fmEnvelope.node.connect(o.frequency); + } + stopFm = stop; + } + + // Additional oscillator for vibrato effect + let vibratoOscillator; + if (vib > 0) { + vibratoOscillator = getAudioContext().createOscillator(); + vibratoOscillator.frequency.value = vib; + const gain = getAudioContext().createGain(); + // Vibmod is the amount of vibrato, in semitones + gain.gain.value = vibmod * 100; + vibratoOscillator.connect(gain); + gain.connect(o.detune); + vibratoOscillator.start(t); + } + + let noiseOscillator, noiseMix; + // noise mix + if (noise > 0) { + // Two gain nodes to set the oscillators to their respective levels + noise = noise > 1 ? 1 : noise; + let o_gain = ac.createGain(); + let n_gain = ac.createGain(); + o_gain.gain.setValueAtTime(1 - noise, ac.currentTime); + n_gain.gain.setValueAtTime(noise, ac.currentTime); + + // Instanciating a mixer to blend sources together + noiseMix = ac.createGain(); + + // Connecting the main oscillator to the gain node + o.connect(o_gain).connect(noiseMix); + + // Instanciating a noise oscillator and connecting + noiseOscillator = getNoiseOscillator(t, 'pink'); + noiseOscillator.node.connect(n_gain).connect(noiseMix); + } + + return { + node: noiseMix || o, + stop: (time) => { + vibratoOscillator?.stop(time); + noiseOscillator?.stop(time); + stopFm?.(time); + o.stop(time); + }, + triggerRelease: (time) => { + fmEnvelope?.stop(time); + }, + }; } From 2bc6d0841049aaac6943cec2cdf217905aa1ac13 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 3 Oct 2023 12:19:30 +0200 Subject: [PATCH 140/175] proper dry wet + pull out noise to extra file --- packages/superdough/helpers.mjs | 22 +++++++++++ packages/superdough/noise.mjs | 51 ++++++++++++++++++++++++ packages/superdough/synth.mjs | 70 ++++----------------------------- 3 files changed, 80 insertions(+), 63 deletions(-) create mode 100644 packages/superdough/noise.mjs diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 32ca0bb2..576ec3f1 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -112,3 +112,25 @@ export function createFilter( return filter; } + +// stays 1 until .5, then fades out +let wetfade = (d) => (d < 0.5 ? 1 : 1 - (d - 0.5) / 0.5); + +// mix together dry and wet nodes. 0 = only dry 1 = only wet +// still not too sure about how this could be used more generally... +export function drywet(dry, wet, wetAmount = 0) { + const ac = getAudioContext(); + if (!wetAmount) { + return dry; + } + let dry_gain = ac.createGain(); + let wet_gain = ac.createGain(); + dry.connect(dry_gain); + wet.connect(wet_gain); + dry_gain.gain.value = wetfade(wetAmount); + wet_gain.gain.value = wetfade(1 - wetAmount); + let mix = ac.createGain(); + dry_gain.connect(mix); + wet_gain.connect(mix); + return mix; +} diff --git a/packages/superdough/noise.mjs b/packages/superdough/noise.mjs new file mode 100644 index 00000000..eeb2a9d0 --- /dev/null +++ b/packages/superdough/noise.mjs @@ -0,0 +1,51 @@ +import { drywet } from './helpers.mjs'; + +// expects one of noises as type +export function getNoiseOscillator(type = 'white', t) { + const ac = getAudioContext(); + const bufferSize = 2 * ac.sampleRate; + const noiseBuffer = ac.createBuffer(1, bufferSize, ac.sampleRate); + const output = noiseBuffer.getChannelData(0); + let lastOut = 0; + let b0, b1, b2, b3, b4, b5, b6; + b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0; + + for (let i = 0; i < bufferSize; i++) { + if (type === 'white') { + output[i] = Math.random() * 2 - 1; + } else if (type === 'brown') { + let white = Math.random() * 2 - 1; + output[i] = (lastOut + 0.02 * white) / 1.02; + lastOut = output[i]; + } else if (type === 'pink') { + let white = Math.random() * 2 - 1; + b0 = 0.99886 * b0 + white * 0.0555179; + b1 = 0.99332 * b1 + white * 0.0750759; + b2 = 0.969 * b2 + white * 0.153852; + b3 = 0.8665 * b3 + white * 0.3104856; + b4 = 0.55 * b4 + white * 0.5329522; + b5 = -0.7616 * b5 - white * 0.016898; + output[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362; + output[i] *= 0.11; + b6 = white * 0.115926; + } + } + + const o = ac.createBufferSource(); + o.buffer = noiseBuffer; + o.loop = true; + o.start(t); + return { + node: o, + stop: (time) => o.stop(time), + }; +} + +export function getNoiseMix(inputNode, wet, t) { + const noiseOscillator = getNoiseOscillator('pink', t); + const noiseMix = drywet(inputNode, noiseOscillator.node, wet); + return { + node: noiseMix, + stop: (time) => noiseOscillator?.stop(time), + }; +} diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index f12be9c8..8c07f34e 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -1,6 +1,7 @@ import { midiToFreq, noteToMidi } from './util.mjs'; import { registerSound, getAudioContext } from './superdough.mjs'; import { gainNode, getEnvelope, getExpEnvelope } from './helpers.mjs'; +import { getNoiseMix } from './noise.mjs'; const mod = (freq, range = 1, type = 'sine') => { const ctx = getAudioContext(); @@ -35,7 +36,7 @@ export function registerSynthSounds() { if (waveforms.includes(s)) { sound = getOscillator(s, t, value); } else { - sound = getNoiseOscillator(t, s); + sound = getNoiseOscillator(s, t); } let { node: o, stop, triggerRelease } = sound; @@ -96,47 +97,6 @@ export function waveformN(partials, type) { return osc; } -// expects one of noises as type -export function getNoiseOscillator(t, type = 'white') { - const ac = getAudioContext(); - const bufferSize = 2 * ac.sampleRate; - const noiseBuffer = ac.createBuffer(1, bufferSize, ac.sampleRate); - const output = noiseBuffer.getChannelData(0); - let lastOut = 0; - let b0, b1, b2, b3, b4, b5, b6; - b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0; - - for (let i = 0; i < bufferSize; i++) { - if (type === 'white') { - output[i] = Math.random() * 2 - 1; - } else if (type === 'brown') { - let white = Math.random() * 2 - 1; - output[i] = (lastOut + 0.02 * white) / 1.02; - lastOut = output[i]; - } else if (type === 'pink') { - let white = Math.random() * 2 - 1; - b0 = 0.99886 * b0 + white * 0.0555179; - b1 = 0.99332 * b1 + white * 0.0750759; - b2 = 0.969 * b2 + white * 0.153852; - b3 = 0.8665 * b3 + white * 0.3104856; - b4 = 0.55 * b4 + white * 0.5329522; - b5 = -0.7616 * b5 - white * 0.016898; - output[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362; - output[i] *= 0.11; - b6 = white * 0.115926; - } - } - - const o = ac.createBufferSource(); - o.buffer = noiseBuffer; - o.loop = true; - o.start(t); - return { - node: o, - stop: (time) => o.stop(time), - }; -} - // expects one of waveforms as s export function getOscillator( s, @@ -224,32 +184,16 @@ export function getOscillator( vibratoOscillator.start(t); } - let noiseOscillator, noiseMix; - // noise mix - if (noise > 0) { - // Two gain nodes to set the oscillators to their respective levels - noise = noise > 1 ? 1 : noise; - let o_gain = ac.createGain(); - let n_gain = ac.createGain(); - o_gain.gain.setValueAtTime(1 - noise, ac.currentTime); - n_gain.gain.setValueAtTime(noise, ac.currentTime); - - // Instanciating a mixer to blend sources together - noiseMix = ac.createGain(); - - // Connecting the main oscillator to the gain node - o.connect(o_gain).connect(noiseMix); - - // Instanciating a noise oscillator and connecting - noiseOscillator = getNoiseOscillator(t, 'pink'); - noiseOscillator.node.connect(n_gain).connect(noiseMix); + let noiseMix; + if (noise) { + noiseMix = getNoiseMix(o, noise, t); } return { - node: noiseMix || o, + node: noiseMix?.node || o, stop: (time) => { vibratoOscillator?.stop(time); - noiseOscillator?.stop(time); + noiseMix?.stop(time); stopFm?.(time); o.stop(time); }, From 4b64168faa0c95b70edac6c6ec17ca178c72278a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 3 Oct 2023 12:20:28 +0200 Subject: [PATCH 141/175] fix: imports --- packages/superdough/noise.mjs | 1 + packages/superdough/synth.mjs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/superdough/noise.mjs b/packages/superdough/noise.mjs index eeb2a9d0..0e6c436e 100644 --- a/packages/superdough/noise.mjs +++ b/packages/superdough/noise.mjs @@ -1,4 +1,5 @@ import { drywet } from './helpers.mjs'; +import { getAudioContext } from './superdough.mjs'; // expects one of noises as type export function getNoiseOscillator(type = 'white', t) { diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 8c07f34e..24d1d5ef 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -1,7 +1,7 @@ import { midiToFreq, noteToMidi } from './util.mjs'; import { registerSound, getAudioContext } from './superdough.mjs'; import { gainNode, getEnvelope, getExpEnvelope } from './helpers.mjs'; -import { getNoiseMix } from './noise.mjs'; +import { getNoiseMix, getNoiseOscillator } from './noise.mjs'; const mod = (freq, range = 1, type = 'sine') => { const ctx = getAudioContext(); From 047129223e62a0d161083853bcfe84a599e4ccc0 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 3 Oct 2023 12:25:47 +0200 Subject: [PATCH 142/175] cache noise --- packages/superdough/noise.mjs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/superdough/noise.mjs b/packages/superdough/noise.mjs index 0e6c436e..2c8c1d4a 100644 --- a/packages/superdough/noise.mjs +++ b/packages/superdough/noise.mjs @@ -1,9 +1,14 @@ import { drywet } from './helpers.mjs'; import { getAudioContext } from './superdough.mjs'; -// expects one of noises as type -export function getNoiseOscillator(type = 'white', t) { +let noiseCache = {}; + +// lazy generates noise buffers and keeps them forever +function getNoiseBuffer(type) { const ac = getAudioContext(); + if (noiseCache[type]) { + return noiseCache[type]; + } const bufferSize = 2 * ac.sampleRate; const noiseBuffer = ac.createBuffer(1, bufferSize, ac.sampleRate); const output = noiseBuffer.getChannelData(0); @@ -31,9 +36,15 @@ export function getNoiseOscillator(type = 'white', t) { b6 = white * 0.115926; } } + noiseCache[type] = noiseBuffer; + return noiseBuffer; +} +// expects one of noises as type +export function getNoiseOscillator(type = 'white', t) { + const ac = getAudioContext(); const o = ac.createBufferSource(); - o.buffer = noiseBuffer; + o.buffer = getNoiseBuffer(type); o.loop = true; o.start(t); return { From 376cf09565bb9c63a08c4eef43a6909186f00b29 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 3 Oct 2023 12:41:57 +0200 Subject: [PATCH 143/175] rename zzfx noise to znoise --- packages/core/controls.mjs | 11 ++++++++++- packages/superdough/zzfx.mjs | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 6cac6e54..39c2df2f 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -655,6 +655,15 @@ const generic_params = [ * .vib("<.5 1 2 4 8 16>:12") */ [['vib', 'vibmod'], 'vibrato', 'v'], + /** + * Adds pink noise to the mix + * + * @name noise + * @param {number | Pattern} wet wet amount + * @example + * sound("/2") + */ + ['noise'], /** * Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set * @@ -1153,7 +1162,7 @@ const generic_params = [ ['pitchJump'], ['pitchJumpTime'], ['lfo', 'repeatTime'], - ['noise'], + ['znoise'], // noise on the frequency or as bubo calls it "frequency fog" :) ['zmod'], ['zcrush'], // like crush but scaled differently ['zdelay'], diff --git a/packages/superdough/zzfx.mjs b/packages/superdough/zzfx.mjs index da505d74..a6af8260 100644 --- a/packages/superdough/zzfx.mjs +++ b/packages/superdough/zzfx.mjs @@ -20,7 +20,7 @@ export const getZZFX = (value, t) => { pitchJump = 0, pitchJumpTime = 0, lfo = 0, - noise = 0, + znoise = 0, zmod = 0, zcrush = 0, zdelay = 0, @@ -54,7 +54,7 @@ export const getZZFX = (value, t) => { pitchJump, pitchJumpTime, lfo, - noise, + znoise, zmod, zcrush, zdelay, From 9c9323e04099db415645d95a24e6969d3c21d113 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 3 Oct 2023 12:42:56 +0200 Subject: [PATCH 144/175] snapshot --- test/__snapshots__/examples.test.mjs.snap | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index e026f9c4..4a4c966d 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2959,6 +2959,15 @@ exports[`runs examples > example "never" example index 0 1`] = ` ] `; +exports[`runs examples > example "noise" example index 0 1`] = ` +[ + "[ (0/1 → 1/1) ⇝ 2/1 | s:white ]", + "[ 0/1 ⇜ (1/1 → 2/1) | s:white ]", + "[ (2/1 → 3/1) ⇝ 4/1 | s:pink ]", + "[ 2/1 ⇜ (3/1 → 4/1) | s:pink ]", +] +`; + exports[`runs examples > example "note" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:c ]", From 020e85906d9ca9bb304eaedd2ae7814319eaf94b Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 4 Oct 2023 09:42:10 +0200 Subject: [PATCH 145/175] fix: slider crash on some platforms --- packages/codemirror/slider.mjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/codemirror/slider.mjs b/packages/codemirror/slider.mjs index 62ec33c2..519e5610 100644 --- a/packages/codemirror/slider.mjs +++ b/packages/codemirror/slider.mjs @@ -91,8 +91,10 @@ export const sliderPlugin = ViewPlugin.fromClass( while (iterator.value) { // when the widgets are moved, we need to tell the dom node the current position // this is important because the updateSliderValue function has to work with the dom node - iterator.value.widget.slider.from = iterator.from; - iterator.value.widget.slider.to = iterator.to; + if (iterator.value?.widget?.slider) { + iterator.value.widget.slider.from = iterator.from; + iterator.value.widget.slider.to = iterator.to; + } iterator.next(); } } From 508af7eb72dfd2a56f3bad50355df987e0b75094 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 4 Oct 2023 23:48:53 +0200 Subject: [PATCH 146/175] update internal reverb param names --- packages/superdough/superdough.mjs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index e387ff6c..1e26cc9d 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -108,11 +108,11 @@ function getDelay(orbit, delaytime, delayfeedback, t) { let reverbs = {}; -function getReverb(orbit, duration = 2, fade, revlp, revdim) { +function getReverb(orbit, duration = 2, fade, lp, dim) { // If no reverb has been created for a given orbit, create one if (!reverbs[orbit]) { const ac = getAudioContext(); - const reverb = ac.createReverb(getAudioContext(), duration, fade, revlp, revdim); + const reverb = ac.createReverb(getAudioContext(), duration, fade, lp, dim); reverb.connect(getDestination()); reverbs[orbit] = reverb; } @@ -120,14 +120,14 @@ function getReverb(orbit, duration = 2, fade, revlp, revdim) { if ( reverbs[orbit].duration !== duration || reverbs[orbit].fade !== fade || - reverbs[orbit].revlp !== revlp || - reverbs[orbit].revdim !== revdim + reverbs[orbit].lp !== lp || + reverbs[orbit].dim !== dim ) { - reverbs[orbit].setDuration(duration, fade, revlp, revdim); + reverbs[orbit].setDuration(duration, fade, lp, dim); reverbs[orbit].duration = duration; reverbs[orbit].fade = fade; - reverbs[orbit].revlp = revlp; - reverbs[orbit].revdim = revdim; + reverbs[orbit].lp = lp; + reverbs[orbit].dim = dim; } return reverbs[orbit]; From ce842f75612202b916c838a26e1fa7dd58ab3c35 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 4 Oct 2023 23:56:00 +0200 Subject: [PATCH 147/175] simplify createReverb --- packages/superdough/reverb.mjs | 4 ++-- packages/superdough/superdough.mjs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index 7151e7fc..52d6983c 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -2,12 +2,12 @@ import reverbGen from './reverbGen.mjs'; if (typeof AudioContext !== 'undefined') { AudioContext.prototype.generateReverb = reverbGen.generateReverb; - AudioContext.prototype.createReverb = function (audioContext, duration, fade, revlp, revdim) { + AudioContext.prototype.createReverb = function (duration, fade, revlp, revdim) { const convolver = this.createConvolver(); convolver.setDuration = (d, fade, revlp, revdim) => { this.generateReverb( { - audioContext, + audioContext: this, sampleRate: 44100, numChannels: 2, decayTime: d, diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 1e26cc9d..0f2b3dd0 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -112,7 +112,7 @@ function getReverb(orbit, duration = 2, fade, lp, dim) { // If no reverb has been created for a given orbit, create one if (!reverbs[orbit]) { const ac = getAudioContext(); - const reverb = ac.createReverb(getAudioContext(), duration, fade, lp, dim); + const reverb = ac.createReverb(duration, fade, lp, dim); reverb.connect(getDestination()); reverbs[orbit] = reverb; } From 3c4f835d8b6fb8f520c7302bff4b83d5bd2dfe5d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 5 Oct 2023 00:00:47 +0200 Subject: [PATCH 148/175] consistent naming + simplify --- packages/superdough/reverb.mjs | 14 +++++++------- packages/superdough/superdough.mjs | 6 +----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index 52d6983c..de6c903e 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -2,9 +2,9 @@ import reverbGen from './reverbGen.mjs'; if (typeof AudioContext !== 'undefined') { AudioContext.prototype.generateReverb = reverbGen.generateReverb; - AudioContext.prototype.createReverb = function (duration, fade, revlp, revdim) { + AudioContext.prototype.createReverb = function (duration, fade, lp, dim) { const convolver = this.createConvolver(); - convolver.setDuration = (d, fade, revlp, revdim) => { + convolver.generate = (d, fade, lp, dim) => { this.generateReverb( { audioContext: this, @@ -12,8 +12,8 @@ if (typeof AudioContext !== 'undefined') { numChannels: 2, decayTime: d, fadeInTime: fade, - lpFreqStart: revlp, - lpFreqEnd: revdim, + lpFreqStart: lp, + lpFreqEnd: dim, }, (buffer) => { convolver.buffer = buffer; @@ -21,10 +21,10 @@ if (typeof AudioContext !== 'undefined') { ); convolver.duration = d; convolver.fade = fade; - convolver.revlp = revlp; - convolver.revdim = revdim; + convolver.lp = lp; + convolver.dim = dim; }; - convolver.setDuration(duration, fade, revlp, revdim); + convolver.generate(duration, fade, lp, dim); return convolver; }; } diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 0f2b3dd0..ea8afc58 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -123,11 +123,7 @@ function getReverb(orbit, duration = 2, fade, lp, dim) { reverbs[orbit].lp !== lp || reverbs[orbit].dim !== dim ) { - reverbs[orbit].setDuration(duration, fade, lp, dim); - reverbs[orbit].duration = duration; - reverbs[orbit].fade = fade; - reverbs[orbit].lp = lp; - reverbs[orbit].dim = dim; + reverbs[orbit].generate(duration, fade, lp, dim); } return reverbs[orbit]; From 75099abbc125908df97ee80a12ede3abda5e1ee3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 5 Oct 2023 00:03:02 +0200 Subject: [PATCH 149/175] remove unused reverb method --- packages/superdough/reverbGen.mjs | 76 ------------------------------- 1 file changed, 76 deletions(-) diff --git a/packages/superdough/reverbGen.mjs b/packages/superdough/reverbGen.mjs index cac5d24a..49429937 100644 --- a/packages/superdough/reverbGen.mjs +++ b/packages/superdough/reverbGen.mjs @@ -70,82 +70,6 @@ reverbGen.generateGraph = function (data, width, height, min, max) { return canvas; }; -/** Saves an AudioBuffer as a 16-bit WAV file on the client's host - file system. Normalizes it to peak at +-32767, and optionally - truncates it if there's a lot of "silence" at the end. - - @param {!AudioBuffer} buffer The buffer to save. - @param {string} name Name of file to create. - @param {number?} opt_minTail Defines what counts as "silence" for - auto-truncating the buffer. If there is a point past which every - value of every channel is less than opt_minTail, then the buffer - is truncated at that point. This is expressed as an integer, - applying to the post-normalized and integer-converted - buffer. The default is 0, meaning don't truncate. */ -reverbGen.saveWavFile = function (buffer, name, opt_minTail) { - var bitsPerSample = 16; - var bytesPerSample = 2; - var sampleRate = buffer.sampleRate; - var numChannels = buffer.numberOfChannels; - var channels = getAllChannelData(buffer); - var numSampleFrames = channels[0].length; - var scale = 32767; - // Find normalization constant. - var max = 0; - for (var i = 0; i < numChannels; i++) { - for (var j = 0; j < numSampleFrames; j++) { - max = Math.max(max, Math.abs(channels[i][j])); - } - } - if (max) { - scale = 32767 / max; - } - // Find truncation point. - if (opt_minTail) { - var truncateAt = 0; - for (var i = 0; i < numChannels; i++) { - for (var j = 0; j < numSampleFrames; j++) { - var absSample = Math.abs(Math.round(scale * channels[i][j])); - if (absSample > opt_minTail) { - truncateAt = j; - } - } - } - numSampleFrames = truncateAt + 1; - } - var sampleDataBytes = bytesPerSample * numChannels * numSampleFrames; - var fileBytes = sampleDataBytes + 44; - var arrayBuffer = new ArrayBuffer(fileBytes); - var dataView = new DataView(arrayBuffer); - dataView.setUint32(0, 1179011410, true); // "RIFF" - dataView.setUint32(4, fileBytes - 8, true); // file length - dataView.setUint32(8, 1163280727, true); // "WAVE" - dataView.setUint32(12, 544501094, true); // "fmt " - dataView.setUint32(16, 16, true); // fmt chunk length - dataView.setUint16(20, 1, true); // PCM format - dataView.setUint16(22, numChannels, true); // NumChannels - dataView.setUint32(24, sampleRate, true); // SampleRate - var bytesPerSampleFrame = numChannels * bytesPerSample; - dataView.setUint32(28, sampleRate * bytesPerSampleFrame, true); // ByteRate - dataView.setUint16(32, bytesPerSampleFrame, true); // BlockAlign - dataView.setUint16(34, bitsPerSample, true); // BitsPerSample - dataView.setUint32(36, 1635017060, true); // "data" - dataView.setUint32(40, sampleDataBytes, true); - for (var j = 0; j < numSampleFrames; j++) { - for (var i = 0; i < numChannels; i++) { - dataView.setInt16(44 + j * bytesPerSampleFrame + i * bytesPerSample, Math.round(scale * channels[i][j]), true); - } - } - var blob = new Blob([arrayBuffer], { type: 'audio/wav' }); - var url = window.URL.createObjectURL(blob); - var linkEl = document.createElement('a'); - linkEl.href = url; - linkEl.download = name; - linkEl.style.display = 'none'; - document.body.appendChild(linkEl); - linkEl.click(); -}; - /** Applies a constantly changing lowpass filter to the given sound. @private From d6c8838fe26db2bf3b5db75c59145952e544f1ad Mon Sep 17 00:00:00 2001 From: Vasilii Milovidov Date: Thu, 5 Oct 2023 03:49:50 +0400 Subject: [PATCH 150/175] Integrate with the new impulse generation functionality --- packages/core/controls.mjs | 71 +++++++++++++++-------------- packages/superdough/reverb.mjs | 34 ++++++-------- packages/superdough/superdough.mjs | 37 +++++++-------- website/src/pages/learn/effects.mdx | 28 +++++++----- 4 files changed, 86 insertions(+), 84 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index d909423f..e23114ca 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -655,6 +655,15 @@ const generic_params = [ * .vib("<.5 1 2 4 8 16>:12") */ [['vib', 'vibmod'], 'vibrato', 'v'], + /** + * Adds pink noise to the mix + * + * @name noise + * @param {number | Pattern} wet wet amount + * @example + * sound("/2") + */ + ['noise'], /** * Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set * @@ -970,56 +979,50 @@ const generic_params = [ * */ [['room', 'size']], - /** - * Sets the room size of the reverb, see {@link room}. - * - * @name roomsize - * @param {number | Pattern} size between 0 and 10 - * @synonyms size, sz - * @example - * s("bd sd").room(.8).roomsize("<0 1 2 4 8>") - * - */ /** * Reverb lowpass starting frequency (in hertz). + * When this property is changed, the reverb will be recaculated, so only change this sparsely.. * - * @name revlp - * @param {number} level between 0 and 20000hz + * @name roomlp + * @synonyms rlp + * @param {number} frequency between 0 and 20000hz * @example - * s("bd sd").room(0.5).revlp(10000) + * s("bd sd").room(0.5).rlp(10000) * @example - * s("bd sd").room(0.5).revlp(5000) + * s("bd sd").room(0.5).rlp(5000) */ - ['revlp'], + ['roomlp', 'rlp'], /** * Reverb lowpass frequency at -60dB (in hertz). + * When this property is changed, the reverb will be recaculated, so only change this sparsely.. * - * @name revdim - * @param {number} level between 0 and 20000hz + * @name roomdim + * @synonyms rdim + * @param {number} frequency between 0 and 20000hz * @example - * s("bd sd").room(0.5).revlp(10000).revdim(8000) + * s("bd sd").room(0.5).rlp(10000).rdim(8000) * @example - * s("bd sd").room(0.5).revlp(5000).revdim(400) + * s("bd sd").room(0.5).rlp(5000).rdim(400) * */ - ['revdim'], + ['roomdim', 'rdim'], /** * Reverb fade time (in seconds). + * When this property is changed, the reverb will be recaculated, so only change this sparsely.. * - * @name fade + * @name roomfade + * @synonyms rfade * @param {number} seconds for the reverb to fade * @example - * s("bd sd").room(0.5).revlp(10000).fade(0.5) + * s("bd sd").room(0.5).rlp(10000).rfade(0.5) * @example - * s("bd sd").room(0.5).revlp(5000).fade(4) + * s("bd sd").room(0.5).rlp(5000).rfade(4) * */ - ['fade'], + ['roomfade', 'rfade'], /** - * Sets the sample to use as an impulse response for the reverb. - * - * @name iresponse - * @param {string | Pattern} sample sample to pick as an impulse response + * Sets the sample to use as an impulse response for the reverb. * * @name iresponse + * @param {string | Pattern} sample to use as an impulse response * @synonyms ir * @example * s("bd sd").room(.8).ir("") @@ -1028,23 +1031,25 @@ const generic_params = [ [['ir', 'i'], 'iresponse'], /** * Sets the room size of the reverb, see {@link room}. + * When this property is changed, the reverb will be recaculated, so only change this sparsely.. * * @name roomsize * @param {number | Pattern} size between 0 and 10 - * @synonyms size, sz + * @synonyms rsize, sz, size * @example - * s("bd sd").room(.8).roomsize("<0 1 2 4 8>") + * s("bd sd").room(.8).rsize(1) + * @example + * s("bd sd").room(.8).rsize(4) * */ // TODO: find out why : // s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc() // .. does not work. Is it because room is only one effect? - ['size', 'sz', 'roomsize'], + ['roomsize', 'size', 'sz', 'rsize'], // ['sagogo'], // ['sclap'], // ['sclaves'], // ['scrash'], - /** * Wave shaping distortion. CAUTION: it might get loud * @@ -1210,7 +1215,7 @@ const generic_params = [ ['pitchJump'], ['pitchJumpTime'], ['lfo', 'repeatTime'], - ['noise'], + ['znoise'], // noise on the frequency or as bubo calls it "frequency fog" :) ['zmod'], ['zcrush'], // like crush but scaled differently ['zdelay'], diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index 5e4ce8f1..85be19ae 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -17,47 +17,43 @@ if (typeof AudioContext !== 'undefined') { return newBuffer; }; - AudioContext.prototype.createReverb = function (audioContext, duration, fade, revlp, revdim, imp) { + AudioContext.prototype.createReverb = function (duration, fade, lp, dim, ir) { const convolver = this.createConvolver(); - - convolver.setDuration = (d, fade, revlp, revdim, imp) => { - if (imp) { - convolver.buffer = this.adjustLength(d, imp); + convolver.generate = (d, fade, lp, dim, buf) => { + if (buf) { + convolver.buffer = this.adjustLength(d, buf); return convolver; } else { this.generateReverb( { - audioContext, + audioContext: this, sampleRate: 44100, numChannels: 2, decayTime: d, fadeInTime: fade, - lpFreqStart: revlp, - lpFreqEnd: revdim, + lpFreqStart: lp, + lpFreqEnd: dim, }, (buffer) => { convolver.buffer = buffer; }, ); - convolver.duration = duration; + convolver.duration = d; convolver.fade = fade; - convolver.revlp = revlp; - convolver.revdim = revdim; + convolver.lp = lp; + convolver.dim = dim; return convolver; } }; - convolver.setIR = (d, fade, revlp, revdim, imp) => { - if (imp) { - convolver.buffer = this.adjustLength(d, imp); + convolver.setIR = (d, fade, lp, dim, buf) => { + if (buf) { + convolver.buffer = this.adjustLength(d, buf); } else { - convolver.setDuration(d, fade, revlp, revdim, imp); + convolver.generate(d, fade, lp, dim, buf); } return convolver; }; - convolver.setDuration(duration, fade, revlp, revdim, imp); + convolver.generate(duration, fade, lp, dim, ir); return convolver; }; } - -// TODO: make the reverb more exciting -// check out https://blog.gskinner.com/archives/2019/02/reverb-web-audio-api.html diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index ec3b981e..d7f0b14b 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -114,32 +114,29 @@ function getDelay(orbit, delaytime, delayfeedback, t) { let reverbs = {}; -function getReverb(orbit, duration = 2, fade, revlp, revdim, imp) { +function getReverb(orbit, duration = 2, fade, lp, dim, ir) { if (!reverbs[orbit]) { const ac = getAudioContext(); - const reverb = ac.createReverb(getAudioContext(), duration, fade, revlp, revdim, imp); + const reverb = ac.createReverb(duration, fade, lp, dim, ir); reverb.connect(getDestination()); reverbs[orbit] = reverb; } - const reverbOrbit = reverbs[orbit]; - if ( reverbs[orbit].duration !== duration || reverbs[orbit].fade !== fade || - reverbs[orbit].revlp !== revlp || - reverbs[orbit].revdim !== revdim + reverbs[orbit].ir !== lp || + reverbs[orbit].dim !== dim || + reverbs[orbit].ir !== ir ) { - reverbs[orbit].setDuration(duration, fade, revlp, revdim); - reverbs[orbit].duration = duration; - reverbs[orbit].fade = fade; - reverbs[orbit].revlp = revlp; - reverbs[orbit].revdim = revdim; + reverbs[orbit].generate(duration, fade, lp, dim, ir); } - if (reverbs[orbit].ir !== imp) { - reverbs[orbit] = reverbs[orbit].setIR(duration, fade, revlp, revdim, imp); - reverbs[orbit].ir = imp; + + if (reverbs[orbit].ir !== ir) { + reverbs[orbit] = reverbs[orbit].setIR(duration, fade, lp, dim, ir); + reverbs[orbit].ir = ir; } + return reverbs[orbit]; } @@ -238,10 +235,10 @@ export const superdough = async (value, deadline, hapDuration) => { delaytime = 0.25, orbit = 1, room, - fade = 0.1, - revlp = 15000, - revdim = 1000, - size = 2, + roomfade = 0.1, + roomlp = 15000, + roomdim = 1000, + roomsize = 2, ir, i = 0, velocity = 1, @@ -393,8 +390,8 @@ export const superdough = async (value, deadline, hapDuration) => { buffer = await loadBuffer(url, ac, ir, 0); } let reverbSend; - if (room > 0 && size > 0) { - const reverbNode = getReverb(orbit, size, fade, revlp, revdim, buffer); + if (room > 0 && roomsize > 0) { + const reverbNode = getReverb(orbit, roomsize, roomfade, roomlp, roomdim, buffer); reverbSend = effectSend(post, reverbNode, room); } diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index 3ca43f69..35052788 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -183,39 +183,43 @@ global effects use the same chain for all events of the same orbit: -## delay +## Delay + +### delay -## delaytime +### delaytime -## delayfeedback +### delayfeedback -## room +## Reverb + +### room -## roomsize +### roomsize -## fade +### roomfade - + -## revlp +### roomlp - + -## revdim +### roomdim - + -## iresponse +### iresponse From 1d4eb59e942687313c5f14c03ac771618379c5ac Mon Sep 17 00:00:00 2001 From: Vasilii Milovidov Date: Thu, 5 Oct 2023 04:10:35 +0400 Subject: [PATCH 151/175] fix: reverbGen.mjs --- packages/superdough/reverbGen.mjs | 78 ------------------------------- 1 file changed, 78 deletions(-) diff --git a/packages/superdough/reverbGen.mjs b/packages/superdough/reverbGen.mjs index 9fb46173..d8024ccb 100644 --- a/packages/superdough/reverbGen.mjs +++ b/packages/superdough/reverbGen.mjs @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -'use strict'; - var reverbGen = {}; /** Generates a reverb impulse response. @@ -72,82 +70,6 @@ reverbGen.generateGraph = function (data, width, height, min, max) { return canvas; }; -/** Saves an AudioBuffer as a 16-bit WAV file on the client's host - file system. Normalizes it to peak at +-32767, and optionally - truncates it if there's a lot of "silence" at the end. - - @param {!AudioBuffer} buffer The buffer to save. - @param {string} name Name of file to create. - @param {number?} opt_minTail Defines what counts as "silence" for - auto-truncating the buffer. If there is a point past which every - value of every channel is less than opt_minTail, then the buffer - is truncated at that point. This is expressed as an integer, - applying to the post-normalized and integer-converted - buffer. The default is 0, meaning don't truncate. */ -reverbGen.saveWavFile = function (buffer, name, opt_minTail) { - var bitsPerSample = 16; - var bytesPerSample = 2; - var sampleRate = buffer.sampleRate; - var numChannels = buffer.numberOfChannels; - var channels = getAllChannelData(buffer); - var numSampleFrames = channels[0].length; - var scale = 32767; - // Find normalization constant. - var max = 0; - for (var i = 0; i < numChannels; i++) { - for (var j = 0; j < numSampleFrames; j++) { - max = Math.max(max, Math.abs(channels[i][j])); - } - } - if (max) { - scale = 32767 / max; - } - // Find truncation point. - if (opt_minTail) { - var truncateAt = 0; - for (var i = 0; i < numChannels; i++) { - for (var j = 0; j < numSampleFrames; j++) { - var absSample = Math.abs(Math.round(scale * channels[i][j])); - if (absSample > opt_minTail) { - truncateAt = j; - } - } - } - numSampleFrames = truncateAt + 1; - } - var sampleDataBytes = bytesPerSample * numChannels * numSampleFrames; - var fileBytes = sampleDataBytes + 44; - var arrayBuffer = new ArrayBuffer(fileBytes); - var dataView = new DataView(arrayBuffer); - dataView.setUint32(0, 1179011410, true); // "RIFF" - dataView.setUint32(4, fileBytes - 8, true); // file length - dataView.setUint32(8, 1163280727, true); // "WAVE" - dataView.setUint32(12, 544501094, true); // "fmt " - dataView.setUint32(16, 16, true); // fmt chunk length - dataView.setUint16(20, 1, true); // PCM format - dataView.setUint16(22, numChannels, true); // NumChannels - dataView.setUint32(24, sampleRate, true); // SampleRate - var bytesPerSampleFrame = numChannels * bytesPerSample; - dataView.setUint32(28, sampleRate * bytesPerSampleFrame, true); // ByteRate - dataView.setUint16(32, bytesPerSampleFrame, true); // BlockAlign - dataView.setUint16(34, bitsPerSample, true); // BitsPerSample - dataView.setUint32(36, 1635017060, true); // "data" - dataView.setUint32(40, sampleDataBytes, true); - for (var j = 0; j < numSampleFrames; j++) { - for (var i = 0; i < numChannels; i++) { - dataView.setInt16(44 + j * bytesPerSampleFrame + i * bytesPerSample, Math.round(scale * channels[i][j]), true); - } - } - var blob = new Blob([arrayBuffer], { type: 'audio/wav' }); - var url = window.URL.createObjectURL(blob); - var linkEl = document.createElement('a'); - linkEl.href = url; - linkEl.download = name; - linkEl.style.display = 'none'; - document.body.appendChild(linkEl); - linkEl.click(); -}; - /** Applies a constantly changing lowpass filter to the given sound. @private From 2f0798de3267556f275598d84c38a86d35d6cf7d Mon Sep 17 00:00:00 2001 From: Vasilii Milovidov Date: Thu, 5 Oct 2023 13:17:17 +0400 Subject: [PATCH 152/175] fix: formatting --- packages/superdough/superdough.mjs | 1 - website/src/pages/learn/effects.mdx | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index d74e3182..d7f0b14b 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -114,7 +114,6 @@ function getDelay(orbit, delaytime, delayfeedback, t) { let reverbs = {}; - function getReverb(orbit, duration = 2, fade, lp, dim, ir) { if (!reverbs[orbit]) { const ac = getAudioContext(); diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index e2a0de8b..35052788 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -219,7 +219,6 @@ global effects use the same chain for all events of the same orbit: - ### iresponse From 4718bfac25e323997eaa5bf8e5019563764520bb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 7 Oct 2023 00:22:55 +0200 Subject: [PATCH 153/175] fix: reverb regenerate loophole --- packages/superdough/reverb.mjs | 2 +- packages/superdough/superdough.mjs | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index de6c903e..3d54203c 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -4,7 +4,7 @@ if (typeof AudioContext !== 'undefined') { AudioContext.prototype.generateReverb = reverbGen.generateReverb; AudioContext.prototype.createReverb = function (duration, fade, lp, dim) { const convolver = this.createConvolver(); - convolver.generate = (d, fade, lp, dim) => { + convolver.generate = (d = 2, fade = 0.1, lp = 15000, dim = 1000) => { this.generateReverb( { audioContext: this, diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index ea8afc58..730e495d 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -108,7 +108,9 @@ function getDelay(orbit, delaytime, delayfeedback, t) { let reverbs = {}; -function getReverb(orbit, duration = 2, fade, lp, dim) { +let hasChanged = (now, before) => now !== undefined && now !== before; + +function getReverb(orbit, duration, fade, lp, dim) { // If no reverb has been created for a given orbit, create one if (!reverbs[orbit]) { const ac = getAudioContext(); @@ -118,11 +120,16 @@ function getReverb(orbit, duration = 2, fade, lp, dim) { } if ( - reverbs[orbit].duration !== duration || - reverbs[orbit].fade !== fade || - reverbs[orbit].lp !== lp || - reverbs[orbit].dim !== dim + hasChanged(duration, reverbs[orbit].duration) || + hasChanged(fade, reverbs[orbit].fade) || + hasChanged(lp, reverbs[orbit].lp) || + hasChanged(dim, reverbs[orbit].dim) ) { + // only regenerate when something has changed + // avoids endless regeneration on things like + // stack(s("a"), s("b").rsize(8)).room(.5) + // this only works when args may stay undefined until here + // setting default values breaks this reverbs[orbit].generate(duration, fade, lp, dim); } @@ -223,10 +230,10 @@ export const superdough = async (value, deadline, hapDuration) => { delaytime = 0.25, orbit = 1, room, - roomfade = 0.1, - roomlp = 15000, - roomdim = 1000, - roomsize = 2, + roomfade, + roomlp, + roomdim, + roomsize, velocity = 1, analyze, // analyser wet fft = 8, // fftSize 0 - 10 From b297888eb414c0be157191713cca7c47f443ecee Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 7 Oct 2023 15:40:08 +0200 Subject: [PATCH 154/175] consume n with scale --- packages/tonal/tonal.mjs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/tonal/tonal.mjs b/packages/tonal/tonal.mjs index 3fd8a5da..99a11c53 100644 --- a/packages/tonal/tonal.mjs +++ b/packages/tonal/tonal.mjs @@ -150,6 +150,9 @@ export const scale = register('scale', function (scale, pat) { return pat.withHap((hap) => { const isObject = typeof hap.value === 'object'; let note = isObject ? hap.value.n : hap.value; + if (isObject) { + delete hap.value.n; // remove n so it won't cause trouble + } const asNumber = Number(note); if (!isNaN(asNumber)) { // TODO: worth keeping for supporting ':' in (non-mininotation) strings? From 296cd83a556635181e021260c5160447901c992c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 7 Oct 2023 15:45:44 +0200 Subject: [PATCH 155/175] snapshot --- test/__snapshots__/examples.test.mjs.snap | 160 +- test/__snapshots__/tunes.test.mjs.snap | 3110 ++++++++++----------- 2 files changed, 1635 insertions(+), 1635 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index f2bc7039..18370903 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -3942,96 +3942,96 @@ exports[`runs examples > example "saw" example index 1 1`] = ` exports[`runs examples > example "scale" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | n:0 note:C3 ]", - "[ 1/6 → 1/3 | n:2 note:E3 ]", - "[ 1/3 → 1/2 | n:4 note:G3 ]", - "[ 1/2 → 2/3 | n:6 note:B3 ]", - "[ 2/3 → 5/6 | n:4 note:G3 ]", - "[ 5/6 → 1/1 | n:2 note:E3 ]", - "[ 1/1 → 7/6 | n:0 note:C3 ]", - "[ 7/6 → 4/3 | n:2 note:E3 ]", - "[ 4/3 → 3/2 | n:4 note:G3 ]", - "[ 3/2 → 5/3 | n:6 note:B3 ]", - "[ 5/3 → 11/6 | n:4 note:G3 ]", - "[ 11/6 → 2/1 | n:2 note:E3 ]", - "[ 2/1 → 13/6 | n:0 note:C3 ]", - "[ 13/6 → 7/3 | n:2 note:E3 ]", - "[ 7/3 → 5/2 | n:4 note:G3 ]", - "[ 5/2 → 8/3 | n:6 note:B3 ]", - "[ 8/3 → 17/6 | n:4 note:G3 ]", - "[ 17/6 → 3/1 | n:2 note:E3 ]", - "[ 3/1 → 19/6 | n:0 note:C3 ]", - "[ 19/6 → 10/3 | n:2 note:E3 ]", - "[ 10/3 → 7/2 | n:4 note:G3 ]", - "[ 7/2 → 11/3 | n:6 note:B3 ]", - "[ 11/3 → 23/6 | n:4 note:G3 ]", - "[ 23/6 → 4/1 | n:2 note:E3 ]", + "[ 0/1 → 1/6 | note:C3 ]", + "[ 1/6 → 1/3 | note:E3 ]", + "[ 1/3 → 1/2 | note:G3 ]", + "[ 1/2 → 2/3 | note:B3 ]", + "[ 2/3 → 5/6 | note:G3 ]", + "[ 5/6 → 1/1 | note:E3 ]", + "[ 1/1 → 7/6 | note:C3 ]", + "[ 7/6 → 4/3 | note:E3 ]", + "[ 4/3 → 3/2 | note:G3 ]", + "[ 3/2 → 5/3 | note:B3 ]", + "[ 5/3 → 11/6 | note:G3 ]", + "[ 11/6 → 2/1 | note:E3 ]", + "[ 2/1 → 13/6 | note:C3 ]", + "[ 13/6 → 7/3 | note:E3 ]", + "[ 7/3 → 5/2 | note:G3 ]", + "[ 5/2 → 8/3 | note:B3 ]", + "[ 8/3 → 17/6 | note:G3 ]", + "[ 17/6 → 3/1 | note:E3 ]", + "[ 3/1 → 19/6 | note:C3 ]", + "[ 19/6 → 10/3 | note:E3 ]", + "[ 10/3 → 7/2 | note:G3 ]", + "[ 7/2 → 11/3 | note:B3 ]", + "[ 11/3 → 23/6 | note:G3 ]", + "[ 23/6 → 4/1 | note:E3 ]", ] `; exports[`runs examples > example "scale" example index 1 1`] = ` [ - "[ 0/1 → 1/4 | n:0 note:C3 s:piano ]", - "[ 0/1 → 1/4 | n:7 note:C4 s:piano ]", - "[ 1/4 → 1/2 | n:4 note:G3 s:piano ]", - "[ 1/2 → 3/4 | n:2 note:E3 s:piano ]", - "[ 1/2 → 3/4 | n:7 note:C4 s:piano ]", - "[ 3/4 → 1/1 | n:4 note:G3 s:piano ]", - "[ 1/1 → 5/4 | n:0 note:C3 s:piano ]", - "[ 1/1 → 5/4 | n:7 note:C4 s:piano ]", - "[ 5/4 → 3/2 | n:4 note:G3 s:piano ]", - "[ 3/2 → 7/4 | n:2 note:E3 s:piano ]", - "[ 3/2 → 7/4 | n:7 note:C4 s:piano ]", - "[ 7/4 → 2/1 | n:4 note:G3 s:piano ]", - "[ 2/1 → 9/4 | n:0 note:C3 s:piano ]", - "[ 2/1 → 9/4 | n:7 note:C4 s:piano ]", - "[ 9/4 → 5/2 | n:4 note:G3 s:piano ]", - "[ 5/2 → 11/4 | n:2 note:Eb3 s:piano ]", - "[ 5/2 → 11/4 | n:7 note:C4 s:piano ]", - "[ 11/4 → 3/1 | n:4 note:G3 s:piano ]", - "[ 3/1 → 13/4 | n:0 note:C3 s:piano ]", - "[ 3/1 → 13/4 | n:7 note:C4 s:piano ]", - "[ 13/4 → 7/2 | n:4 note:G3 s:piano ]", - "[ 7/2 → 15/4 | n:2 note:Eb3 s:piano ]", - "[ 7/2 → 15/4 | n:7 note:C4 s:piano ]", - "[ 15/4 → 4/1 | n:4 note:G3 s:piano ]", + "[ 0/1 → 1/4 | note:C3 s:piano ]", + "[ 0/1 → 1/4 | note:C4 s:piano ]", + "[ 1/4 → 1/2 | note:G3 s:piano ]", + "[ 1/2 → 3/4 | note:E3 s:piano ]", + "[ 1/2 → 3/4 | note:C4 s:piano ]", + "[ 3/4 → 1/1 | note:G3 s:piano ]", + "[ 1/1 → 5/4 | note:C3 s:piano ]", + "[ 1/1 → 5/4 | note:C4 s:piano ]", + "[ 5/4 → 3/2 | note:G3 s:piano ]", + "[ 3/2 → 7/4 | note:E3 s:piano ]", + "[ 3/2 → 7/4 | note:C4 s:piano ]", + "[ 7/4 → 2/1 | note:G3 s:piano ]", + "[ 2/1 → 9/4 | note:C3 s:piano ]", + "[ 2/1 → 9/4 | note:C4 s:piano ]", + "[ 9/4 → 5/2 | note:G3 s:piano ]", + "[ 5/2 → 11/4 | note:Eb3 s:piano ]", + "[ 5/2 → 11/4 | note:C4 s:piano ]", + "[ 11/4 → 3/1 | note:G3 s:piano ]", + "[ 3/1 → 13/4 | note:C3 s:piano ]", + "[ 3/1 → 13/4 | note:C4 s:piano ]", + "[ 13/4 → 7/2 | note:G3 s:piano ]", + "[ 7/2 → 15/4 | note:Eb3 s:piano ]", + "[ 7/2 → 15/4 | note:C4 s:piano ]", + "[ 15/4 → 4/1 | note:G3 s:piano ]", ] `; exports[`runs examples > example "scale" example index 2 1`] = ` [ - "[ 0/1 → 1/8 | n:10 note:C5 s:folkharp ]", - "[ 1/8 → 1/4 | n:2 note:F3 s:folkharp ]", - "[ 1/4 → 3/8 | n:7 note:F4 s:folkharp ]", - "[ 3/8 → 1/2 | n:4 note:A3 s:folkharp ]", - "[ 1/2 → 5/8 | n:2 note:F3 s:folkharp ]", - "[ 5/8 → 3/4 | n:5 note:C4 s:folkharp ]", - "[ 3/4 → 7/8 | n:9 note:A4 s:folkharp ]", - "[ 7/8 → 1/1 | n:8 note:G4 s:folkharp ]", - "[ 1/1 → 9/8 | n:7 note:F4 s:folkharp ]", - "[ 9/8 → 5/4 | n:1 note:D3 s:folkharp ]", - "[ 5/4 → 11/8 | n:1 note:D3 s:folkharp ]", - "[ 11/8 → 3/2 | n:6 note:D4 s:folkharp ]", - "[ 3/2 → 13/8 | n:2 note:F3 s:folkharp ]", - "[ 13/8 → 7/4 | n:4 note:A3 s:folkharp ]", - "[ 7/4 → 15/8 | n:6 note:D4 s:folkharp ]", - "[ 15/8 → 2/1 | n:10 note:C5 s:folkharp ]", - "[ 2/1 → 17/8 | n:4 note:A3 s:folkharp ]", - "[ 17/8 → 9/4 | n:0 note:C3 s:folkharp ]", - "[ 9/4 → 19/8 | n:8 note:G4 s:folkharp ]", - "[ 19/8 → 5/2 | n:2 note:F3 s:folkharp ]", - "[ 5/2 → 21/8 | n:7 note:F4 s:folkharp ]", - "[ 21/8 → 11/4 | n:6 note:D4 s:folkharp ]", - "[ 11/4 → 23/8 | n:11 note:D5 s:folkharp ]", - "[ 23/8 → 3/1 | n:3 note:G3 s:folkharp ]", - "[ 3/1 → 25/8 | n:0 note:C3 s:folkharp ]", - "[ 25/8 → 13/4 | n:11 note:D5 s:folkharp ]", - "[ 13/4 → 27/8 | n:4 note:A3 s:folkharp ]", - "[ 27/8 → 7/2 | n:9 note:A4 s:folkharp ]", - "[ 7/2 → 29/8 | n:10 note:C5 s:folkharp ]", - "[ 29/8 → 15/4 | n:12 note:F5 s:folkharp ]", - "[ 15/4 → 31/8 | n:1 note:D3 s:folkharp ]", - "[ 31/8 → 4/1 | n:4 note:A3 s:folkharp ]", + "[ 0/1 → 1/8 | note:C5 s:folkharp ]", + "[ 1/8 → 1/4 | note:F3 s:folkharp ]", + "[ 1/4 → 3/8 | note:F4 s:folkharp ]", + "[ 3/8 → 1/2 | note:A3 s:folkharp ]", + "[ 1/2 → 5/8 | note:F3 s:folkharp ]", + "[ 5/8 → 3/4 | note:C4 s:folkharp ]", + "[ 3/4 → 7/8 | note:A4 s:folkharp ]", + "[ 7/8 → 1/1 | note:G4 s:folkharp ]", + "[ 1/1 → 9/8 | note:F4 s:folkharp ]", + "[ 9/8 → 5/4 | note:D3 s:folkharp ]", + "[ 5/4 → 11/8 | note:D3 s:folkharp ]", + "[ 11/8 → 3/2 | note:D4 s:folkharp ]", + "[ 3/2 → 13/8 | note:F3 s:folkharp ]", + "[ 13/8 → 7/4 | note:A3 s:folkharp ]", + "[ 7/4 → 15/8 | note:D4 s:folkharp ]", + "[ 15/8 → 2/1 | note:C5 s:folkharp ]", + "[ 2/1 → 17/8 | note:A3 s:folkharp ]", + "[ 17/8 → 9/4 | note:C3 s:folkharp ]", + "[ 9/4 → 19/8 | note:G4 s:folkharp ]", + "[ 19/8 → 5/2 | note:F3 s:folkharp ]", + "[ 5/2 → 21/8 | note:F4 s:folkharp ]", + "[ 21/8 → 11/4 | note:D4 s:folkharp ]", + "[ 11/4 → 23/8 | note:D5 s:folkharp ]", + "[ 23/8 → 3/1 | note:G3 s:folkharp ]", + "[ 3/1 → 25/8 | note:C3 s:folkharp ]", + "[ 25/8 → 13/4 | note:D5 s:folkharp ]", + "[ 13/4 → 27/8 | note:A3 s:folkharp ]", + "[ 27/8 → 7/2 | note:A4 s:folkharp ]", + "[ 7/2 → 29/8 | note:C5 s:folkharp ]", + "[ 29/8 → 15/4 | note:F5 s:folkharp ]", + "[ 15/4 → 31/8 | note:D3 s:folkharp ]", + "[ 31/8 → 4/1 | note:A3 s:folkharp ]", ] `; diff --git a/test/__snapshots__/tunes.test.mjs.snap b/test/__snapshots__/tunes.test.mjs.snap index cd89ee3f..8d696d75 100644 --- a/test/__snapshots__/tunes.test.mjs.snap +++ b/test/__snapshots__/tunes.test.mjs.snap @@ -341,396 +341,396 @@ exports[`renders tunes > tune: blippyRhodes 1`] = ` exports[`renders tunes > tune: bridgeIsOver 1`] = ` [ - "[ -155/52 ⇜ (0/1 → 5/52) | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ -75/26 ⇜ (0/1 → 5/26) | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ -145/52 ⇜ (0/1 → 15/52) | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ -35/13 ⇜ (0/1 → 5/13) | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ -35/13 ⇜ (0/1 → 5/13) | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ -135/52 ⇜ (0/1 → 5/13) ⇝ 25/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ -5/2 ⇜ (0/1 → 5/13) ⇝ 15/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ -125/52 ⇜ (0/1 → 5/13) ⇝ 35/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ -30/13 ⇜ (0/1 → 5/13) ⇝ 10/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ -115/52 ⇜ (0/1 → 5/13) ⇝ 45/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ -55/26 ⇜ (0/1 → 5/13) ⇝ 25/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ -105/52 ⇜ (0/1 → 5/13) ⇝ 55/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ -155/52 ⇜ (0/1 → 5/52) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ -75/26 ⇜ (0/1 → 5/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ -145/52 ⇜ (0/1 → 15/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ -35/13 ⇜ (0/1 → 5/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ -35/13 ⇜ (0/1 → 5/13) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ -135/52 ⇜ (0/1 → 5/13) ⇝ 25/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ -5/2 ⇜ (0/1 → 5/13) ⇝ 15/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ -125/52 ⇜ (0/1 → 5/13) ⇝ 35/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ -30/13 ⇜ (0/1 → 5/13) ⇝ 10/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ -115/52 ⇜ (0/1 → 5/13) ⇝ 45/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ -55/26 ⇜ (0/1 → 5/13) ⇝ 25/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ -105/52 ⇜ (0/1 → 5/13) ⇝ 55/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", "[ 0/1 → 5/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ -135/52 ⇜ (0/1 → 25/52) | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ -5/2 ⇜ (0/1 → 15/26) | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ -125/52 ⇜ (0/1 → 35/52) | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ -30/13 ⇜ (0/1 → 10/13) | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ -115/52 ⇜ (0/1 → 10/13) ⇝ 45/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ -55/26 ⇜ (0/1 → 10/13) ⇝ 25/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ -105/52 ⇜ (0/1 → 10/13) ⇝ 55/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ -25/13 ⇜ (0/1 → 10/13) ⇝ 15/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ -95/52 ⇜ (0/1 → 10/13) ⇝ 5/4 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ -45/26 ⇜ (0/1 → 10/13) ⇝ 35/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ -85/52 ⇜ (0/1 → 10/13) ⇝ 75/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (0/1 → 1/1) ⇝ 40/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ -135/52 ⇜ (0/1 → 25/52) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ -5/2 ⇜ (0/1 → 15/26) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ -125/52 ⇜ (0/1 → 35/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ -30/13 ⇜ (0/1 → 10/13) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ -115/52 ⇜ (0/1 → 10/13) ⇝ 45/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ -55/26 ⇜ (0/1 → 10/13) ⇝ 25/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ -105/52 ⇜ (0/1 → 10/13) ⇝ 55/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ -25/13 ⇜ (0/1 → 10/13) ⇝ 15/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ -95/52 ⇜ (0/1 → 10/13) ⇝ 5/4 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ -45/26 ⇜ (0/1 → 10/13) ⇝ 35/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ -85/52 ⇜ (0/1 → 10/13) ⇝ 75/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (0/1 → 1/1) ⇝ 40/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", "[ (0/1 → 1/1) ⇝ 80/13 | s:mad ]", - "[ (5/52 → 1/1) ⇝ 165/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ (5/26 → 1/1) ⇝ 85/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (15/52 → 1/1) ⇝ 175/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ -135/52 ⇜ (5/13 → 25/52) | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ -5/2 ⇜ (5/13 → 15/26) | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ -125/52 ⇜ (5/13 → 35/52) | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ -30/13 ⇜ (5/13 → 10/13) | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (5/52 → 1/1) ⇝ 165/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ (5/26 → 1/1) ⇝ 85/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (15/52 → 1/1) ⇝ 175/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ -135/52 ⇜ (5/13 → 25/52) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ -5/2 ⇜ (5/13 → 15/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ -125/52 ⇜ (5/13 → 35/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ -30/13 ⇜ (5/13 → 10/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", "[ 5/13 → 10/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ -115/52 ⇜ (5/13 → 45/52) | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ -55/26 ⇜ (5/13 → 25/26) | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ -105/52 ⇜ (5/13 → 1/1) ⇝ 55/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (5/13 → 1/1) ⇝ 45/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ (5/13 → 1/1) ⇝ 45/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (25/52 → 1/1) ⇝ 185/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ (25/52 → 1/1) ⇝ 185/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ (15/26 → 1/1) ⇝ 95/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (15/26 → 1/1) ⇝ 95/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (35/52 → 1/1) ⇝ 15/4 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (35/52 → 1/1) ⇝ 15/4 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ -115/52 ⇜ (10/13 → 45/52) | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ -55/26 ⇜ (10/13 → 25/26) | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ -115/52 ⇜ (5/13 → 45/52) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ -55/26 ⇜ (5/13 → 25/26) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ -105/52 ⇜ (5/13 → 1/1) ⇝ 55/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (5/13 → 1/1) ⇝ 45/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ (5/13 → 1/1) ⇝ 45/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (25/52 → 1/1) ⇝ 185/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (25/52 → 1/1) ⇝ 185/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ (15/26 → 1/1) ⇝ 95/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (15/26 → 1/1) ⇝ 95/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (35/52 → 1/1) ⇝ 15/4 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (35/52 → 1/1) ⇝ 15/4 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ -115/52 ⇜ (10/13 → 45/52) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ -55/26 ⇜ (10/13 → 25/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", "[ 10/13 → 155/156 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ -105/52 ⇜ (10/13 → 1/1) ⇝ 55/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ -25/13 ⇜ (10/13 → 1/1) ⇝ 15/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ -95/52 ⇜ (10/13 → 1/1) ⇝ 5/4 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ -45/26 ⇜ (10/13 → 1/1) ⇝ 35/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ -85/52 ⇜ (10/13 → 1/1) ⇝ 75/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (10/13 → 1/1) ⇝ 50/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ (10/13 → 1/1) ⇝ 50/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (45/52 → 1/1) ⇝ 205/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ (45/52 → 1/1) ⇝ 205/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ (25/26 → 1/1) ⇝ 105/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (25/26 → 1/1) ⇝ 105/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ -105/52 ⇜ (10/13 → 1/1) ⇝ 55/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ -25/13 ⇜ (10/13 → 1/1) ⇝ 15/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ -95/52 ⇜ (10/13 → 1/1) ⇝ 5/4 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ -45/26 ⇜ (10/13 → 1/1) ⇝ 35/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ -85/52 ⇜ (10/13 → 1/1) ⇝ 75/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (10/13 → 1/1) ⇝ 50/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ (10/13 → 1/1) ⇝ 50/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (45/52 → 1/1) ⇝ 205/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (45/52 → 1/1) ⇝ 205/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ (25/26 → 1/1) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (25/26 → 1/1) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", "[ (155/156 → 1/1) ⇝ 15/13 | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]", - "[ -105/52 ⇜ (1/1 → 55/52) | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ -105/52 ⇜ (1/1 → 55/52) | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ -25/13 ⇜ (1/1 → 15/13) | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ -105/52 ⇜ (1/1 → 55/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ -105/52 ⇜ (1/1 → 55/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ -25/13 ⇜ (1/1 → 15/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", "[ 155/156 ⇜ (1/1 → 15/13) | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]", - "[ -95/52 ⇜ (1/1 → 5/4) | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ -45/26 ⇜ (1/1 → 35/26) | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ -85/52 ⇜ (1/1 → 75/52) | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 0/1 ⇜ (1/1 → 2/1) ⇝ 40/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ -95/52 ⇜ (1/1 → 5/4) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ -45/26 ⇜ (1/1 → 35/26) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ -85/52 ⇜ (1/1 → 75/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 0/1 ⇜ (1/1 → 2/1) ⇝ 40/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", "[ 0/1 ⇜ (1/1 → 2/1) ⇝ 80/13 | s:mad ]", - "[ 5/52 ⇜ (1/1 → 2/1) ⇝ 165/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 5/26 ⇜ (1/1 → 2/1) ⇝ 85/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 15/52 ⇜ (1/1 → 2/1) ⇝ 175/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 5/13 ⇜ (1/1 → 2/1) ⇝ 45/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 5/13 ⇜ (1/1 → 2/1) ⇝ 45/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 25/52 ⇜ (1/1 → 2/1) ⇝ 185/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 25/52 ⇜ (1/1 → 2/1) ⇝ 185/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 15/26 ⇜ (1/1 → 2/1) ⇝ 95/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 15/26 ⇜ (1/1 → 2/1) ⇝ 95/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 35/52 ⇜ (1/1 → 2/1) ⇝ 15/4 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 35/52 ⇜ (1/1 → 2/1) ⇝ 15/4 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 10/13 ⇜ (1/1 → 2/1) ⇝ 50/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 10/13 ⇜ (1/1 → 2/1) ⇝ 50/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 45/52 ⇜ (1/1 → 2/1) ⇝ 205/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 45/52 ⇜ (1/1 → 2/1) ⇝ 205/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 25/26 ⇜ (1/1 → 2/1) ⇝ 105/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 25/26 ⇜ (1/1 → 2/1) ⇝ 105/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (55/52 → 2/1) ⇝ 215/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (55/52 → 2/1) ⇝ 215/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 5/52 ⇜ (1/1 → 2/1) ⇝ 165/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 5/26 ⇜ (1/1 → 2/1) ⇝ 85/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 15/52 ⇜ (1/1 → 2/1) ⇝ 175/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 5/13 ⇜ (1/1 → 2/1) ⇝ 45/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 5/13 ⇜ (1/1 → 2/1) ⇝ 45/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 25/52 ⇜ (1/1 → 2/1) ⇝ 185/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 25/52 ⇜ (1/1 → 2/1) ⇝ 185/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 15/26 ⇜ (1/1 → 2/1) ⇝ 95/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 15/26 ⇜ (1/1 → 2/1) ⇝ 95/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 35/52 ⇜ (1/1 → 2/1) ⇝ 15/4 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 35/52 ⇜ (1/1 → 2/1) ⇝ 15/4 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 10/13 ⇜ (1/1 → 2/1) ⇝ 50/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 10/13 ⇜ (1/1 → 2/1) ⇝ 50/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 45/52 ⇜ (1/1 → 2/1) ⇝ 205/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 45/52 ⇜ (1/1 → 2/1) ⇝ 205/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 25/26 ⇜ (1/1 → 2/1) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 25/26 ⇜ (1/1 → 2/1) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (55/52 → 2/1) ⇝ 215/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (55/52 → 2/1) ⇝ 215/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", "[ 15/13 → 20/13 | note:ab2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4537037037037037 ]", - "[ (15/13 → 2/1) ⇝ 55/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ (5/4 → 2/1) ⇝ 225/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ (35/26 → 2/1) ⇝ 115/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (75/52 → 2/1) ⇝ 235/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (15/13 → 2/1) ⇝ 55/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ (5/4 → 2/1) ⇝ 225/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (35/26 → 2/1) ⇝ 115/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (75/52 → 2/1) ⇝ 235/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", "[ 20/13 → 25/13 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]", "[ (25/13 → 2/1) ⇝ 30/13 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]", "[ 25/13 ⇜ (2/1 → 30/13) | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]", - "[ 0/1 ⇜ (2/1 → 3/1) ⇝ 40/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 0/1 ⇜ (2/1 → 3/1) ⇝ 40/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", "[ 0/1 ⇜ (2/1 → 3/1) ⇝ 80/13 | s:mad ]", - "[ 5/52 ⇜ (2/1 → 3/1) ⇝ 165/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 5/26 ⇜ (2/1 → 3/1) ⇝ 85/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 15/52 ⇜ (2/1 → 3/1) ⇝ 175/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 5/13 ⇜ (2/1 → 3/1) ⇝ 45/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 5/13 ⇜ (2/1 → 3/1) ⇝ 45/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 25/52 ⇜ (2/1 → 3/1) ⇝ 185/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 25/52 ⇜ (2/1 → 3/1) ⇝ 185/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 15/26 ⇜ (2/1 → 3/1) ⇝ 95/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 15/26 ⇜ (2/1 → 3/1) ⇝ 95/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 35/52 ⇜ (2/1 → 3/1) ⇝ 15/4 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 35/52 ⇜ (2/1 → 3/1) ⇝ 15/4 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 10/13 ⇜ (2/1 → 3/1) ⇝ 50/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 10/13 ⇜ (2/1 → 3/1) ⇝ 50/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 45/52 ⇜ (2/1 → 3/1) ⇝ 205/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 45/52 ⇜ (2/1 → 3/1) ⇝ 205/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 25/26 ⇜ (2/1 → 3/1) ⇝ 105/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 25/26 ⇜ (2/1 → 3/1) ⇝ 105/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 55/52 ⇜ (2/1 → 3/1) ⇝ 215/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 55/52 ⇜ (2/1 → 3/1) ⇝ 215/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 15/13 ⇜ (2/1 → 3/1) ⇝ 55/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 5/4 ⇜ (2/1 → 3/1) ⇝ 225/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 35/26 ⇜ (2/1 → 3/1) ⇝ 115/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 75/52 ⇜ (2/1 → 3/1) ⇝ 235/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 5/52 ⇜ (2/1 → 3/1) ⇝ 165/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 5/26 ⇜ (2/1 → 3/1) ⇝ 85/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 15/52 ⇜ (2/1 → 3/1) ⇝ 175/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 5/13 ⇜ (2/1 → 3/1) ⇝ 45/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 5/13 ⇜ (2/1 → 3/1) ⇝ 45/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 25/52 ⇜ (2/1 → 3/1) ⇝ 185/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 25/52 ⇜ (2/1 → 3/1) ⇝ 185/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 15/26 ⇜ (2/1 → 3/1) ⇝ 95/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 15/26 ⇜ (2/1 → 3/1) ⇝ 95/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 35/52 ⇜ (2/1 → 3/1) ⇝ 15/4 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 35/52 ⇜ (2/1 → 3/1) ⇝ 15/4 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 10/13 ⇜ (2/1 → 3/1) ⇝ 50/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 10/13 ⇜ (2/1 → 3/1) ⇝ 50/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 45/52 ⇜ (2/1 → 3/1) ⇝ 205/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 45/52 ⇜ (2/1 → 3/1) ⇝ 205/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 25/26 ⇜ (2/1 → 3/1) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 25/26 ⇜ (2/1 → 3/1) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 55/52 ⇜ (2/1 → 3/1) ⇝ 215/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 55/52 ⇜ (2/1 → 3/1) ⇝ 215/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 15/13 ⇜ (2/1 → 3/1) ⇝ 55/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 5/4 ⇜ (2/1 → 3/1) ⇝ 225/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 35/26 ⇜ (2/1 → 3/1) ⇝ 115/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 75/52 ⇜ (2/1 → 3/1) ⇝ 235/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", "[ 30/13 → 395/156 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]", "[ 395/156 → 35/13 | note:ab2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4537037037037037 ]", "[ (35/13 → 3/1) ⇝ 40/13 | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]", - "[ 0/1 ⇜ (3/1 → 40/13) | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 0/1 ⇜ (3/1 → 40/13) | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", "[ 0/1 ⇜ (3/1 → 40/13) ⇝ 80/13 | s:mad ]", - "[ 5/52 ⇜ (3/1 → 40/13) ⇝ 165/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 5/26 ⇜ (3/1 → 40/13) ⇝ 85/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 15/52 ⇜ (3/1 → 40/13) ⇝ 175/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 5/13 ⇜ (3/1 → 40/13) ⇝ 45/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 5/13 ⇜ (3/1 → 40/13) ⇝ 45/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 25/52 ⇜ (3/1 → 40/13) ⇝ 185/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 25/52 ⇜ (3/1 → 40/13) ⇝ 185/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 15/26 ⇜ (3/1 → 40/13) ⇝ 95/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 15/26 ⇜ (3/1 → 40/13) ⇝ 95/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 35/52 ⇜ (3/1 → 40/13) ⇝ 15/4 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 35/52 ⇜ (3/1 → 40/13) ⇝ 15/4 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 10/13 ⇜ (3/1 → 40/13) ⇝ 50/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 10/13 ⇜ (3/1 → 40/13) ⇝ 50/13 | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 45/52 ⇜ (3/1 → 40/13) ⇝ 205/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 45/52 ⇜ (3/1 → 40/13) ⇝ 205/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 25/26 ⇜ (3/1 → 40/13) ⇝ 105/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 25/26 ⇜ (3/1 → 40/13) ⇝ 105/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 55/52 ⇜ (3/1 → 40/13) ⇝ 215/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 55/52 ⇜ (3/1 → 40/13) ⇝ 215/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 15/13 ⇜ (3/1 → 40/13) ⇝ 55/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 5/4 ⇜ (3/1 → 40/13) ⇝ 225/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 35/26 ⇜ (3/1 → 40/13) ⇝ 115/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 75/52 ⇜ (3/1 → 40/13) ⇝ 235/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 5/52 ⇜ (3/1 → 40/13) ⇝ 165/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 5/26 ⇜ (3/1 → 40/13) ⇝ 85/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 15/52 ⇜ (3/1 → 40/13) ⇝ 175/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 5/13 ⇜ (3/1 → 40/13) ⇝ 45/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 5/13 ⇜ (3/1 → 40/13) ⇝ 45/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 25/52 ⇜ (3/1 → 40/13) ⇝ 185/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 25/52 ⇜ (3/1 → 40/13) ⇝ 185/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 15/26 ⇜ (3/1 → 40/13) ⇝ 95/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 15/26 ⇜ (3/1 → 40/13) ⇝ 95/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 35/52 ⇜ (3/1 → 40/13) ⇝ 15/4 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 35/52 ⇜ (3/1 → 40/13) ⇝ 15/4 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 10/13 ⇜ (3/1 → 40/13) ⇝ 50/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 10/13 ⇜ (3/1 → 40/13) ⇝ 50/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 45/52 ⇜ (3/1 → 40/13) ⇝ 205/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 45/52 ⇜ (3/1 → 40/13) ⇝ 205/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 25/26 ⇜ (3/1 → 40/13) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 25/26 ⇜ (3/1 → 40/13) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 55/52 ⇜ (3/1 → 40/13) ⇝ 215/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 55/52 ⇜ (3/1 → 40/13) ⇝ 215/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 15/13 ⇜ (3/1 → 40/13) ⇝ 55/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 5/4 ⇜ (3/1 → 40/13) ⇝ 225/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 35/26 ⇜ (3/1 → 40/13) ⇝ 115/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 75/52 ⇜ (3/1 → 40/13) ⇝ 235/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", "[ 35/13 ⇜ (3/1 → 40/13) | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]", - "[ 5/52 ⇜ (40/13 → 165/52) | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 5/26 ⇜ (40/13 → 85/26) | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 15/52 ⇜ (40/13 → 175/52) | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 5/13 ⇜ (40/13 → 45/13) | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 5/13 ⇜ (40/13 → 45/13) | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 25/52 ⇜ (40/13 → 45/13) ⇝ 185/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 15/26 ⇜ (40/13 → 45/13) ⇝ 95/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 35/52 ⇜ (40/13 → 45/13) ⇝ 15/4 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 10/13 ⇜ (40/13 → 45/13) ⇝ 50/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 45/52 ⇜ (40/13 → 45/13) ⇝ 205/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 25/26 ⇜ (40/13 → 45/13) ⇝ 105/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 55/52 ⇜ (40/13 → 45/13) ⇝ 215/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 5/52 ⇜ (40/13 → 165/52) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 5/26 ⇜ (40/13 → 85/26) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 15/52 ⇜ (40/13 → 175/52) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 5/13 ⇜ (40/13 → 45/13) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 5/13 ⇜ (40/13 → 45/13) | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 25/52 ⇜ (40/13 → 45/13) ⇝ 185/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 15/26 ⇜ (40/13 → 45/13) ⇝ 95/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 35/52 ⇜ (40/13 → 45/13) ⇝ 15/4 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 10/13 ⇜ (40/13 → 45/13) ⇝ 50/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 45/52 ⇜ (40/13 → 45/13) ⇝ 205/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 25/26 ⇜ (40/13 → 45/13) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 55/52 ⇜ (40/13 → 45/13) ⇝ 215/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", "[ 40/13 → 45/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 25/52 ⇜ (40/13 → 185/52) | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 15/26 ⇜ (40/13 → 95/26) | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 35/52 ⇜ (40/13 → 15/4) | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 10/13 ⇜ (40/13 → 50/13) | n:0 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 45/52 ⇜ (40/13 → 50/13) ⇝ 205/52 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 25/26 ⇜ (40/13 → 50/13) ⇝ 105/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 55/52 ⇜ (40/13 → 50/13) ⇝ 215/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 15/13 ⇜ (40/13 → 50/13) ⇝ 55/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 5/4 ⇜ (40/13 → 50/13) ⇝ 225/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 35/26 ⇜ (40/13 → 50/13) ⇝ 115/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 75/52 ⇜ (40/13 → 50/13) ⇝ 235/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 25/52 ⇜ (40/13 → 185/52) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 15/26 ⇜ (40/13 → 95/26) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 35/52 ⇜ (40/13 → 15/4) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 10/13 ⇜ (40/13 → 50/13) | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 45/52 ⇜ (40/13 → 50/13) ⇝ 205/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 25/26 ⇜ (40/13 → 50/13) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 55/52 ⇜ (40/13 → 50/13) ⇝ 215/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 15/13 ⇜ (40/13 → 50/13) ⇝ 55/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 5/4 ⇜ (40/13 → 50/13) ⇝ 225/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 35/26 ⇜ (40/13 → 50/13) ⇝ 115/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 75/52 ⇜ (40/13 → 50/13) ⇝ 235/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", "[ 0/1 ⇜ (40/13 → 4/1) ⇝ 80/13 | s:mad ]", - "[ (40/13 → 4/1) ⇝ 80/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ (165/52 → 4/1) ⇝ 25/4 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (85/26 → 4/1) ⇝ 165/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ (175/52 → 4/1) ⇝ 335/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 25/52 ⇜ (45/13 → 185/52) | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 15/26 ⇜ (45/13 → 95/26) | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 35/52 ⇜ (45/13 → 15/4) | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 10/13 ⇜ (45/13 → 50/13) | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ (40/13 → 4/1) ⇝ 80/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ (165/52 → 4/1) ⇝ 25/4 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (85/26 → 4/1) ⇝ 165/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ (175/52 → 4/1) ⇝ 335/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 25/52 ⇜ (45/13 → 185/52) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 15/26 ⇜ (45/13 → 95/26) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 35/52 ⇜ (45/13 → 15/4) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 10/13 ⇜ (45/13 → 50/13) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", "[ 45/13 → 50/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 45/52 ⇜ (45/13 → 205/52) | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 25/26 ⇜ (45/13 → 4/1) ⇝ 105/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 55/52 ⇜ (45/13 → 4/1) ⇝ 215/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (45/13 → 4/1) ⇝ 85/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ (45/13 → 4/1) ⇝ 85/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ (185/52 → 4/1) ⇝ 345/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (185/52 → 4/1) ⇝ 345/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (95/26 → 4/1) ⇝ 175/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (95/26 → 4/1) ⇝ 175/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ (15/4 → 4/1) ⇝ 355/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (15/4 → 4/1) ⇝ 355/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 45/52 ⇜ (50/13 → 205/52) | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 25/26 ⇜ (50/13 → 4/1) ⇝ 105/26 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 55/52 ⇜ (50/13 → 4/1) ⇝ 215/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 15/13 ⇜ (50/13 → 4/1) ⇝ 55/13 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 5/4 ⇜ (50/13 → 4/1) ⇝ 225/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 35/26 ⇜ (50/13 → 4/1) ⇝ 115/26 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 75/52 ⇜ (50/13 → 4/1) ⇝ 235/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 45/52 ⇜ (45/13 → 205/52) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 25/26 ⇜ (45/13 → 4/1) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 55/52 ⇜ (45/13 → 4/1) ⇝ 215/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (45/13 → 4/1) ⇝ 85/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (45/13 → 4/1) ⇝ 85/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ (185/52 → 4/1) ⇝ 345/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (185/52 → 4/1) ⇝ 345/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (95/26 → 4/1) ⇝ 175/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (95/26 → 4/1) ⇝ 175/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ (15/4 → 4/1) ⇝ 355/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (15/4 → 4/1) ⇝ 355/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 45/52 ⇜ (50/13 → 205/52) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 25/26 ⇜ (50/13 → 4/1) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 55/52 ⇜ (50/13 → 4/1) ⇝ 215/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 15/13 ⇜ (50/13 → 4/1) ⇝ 55/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 5/4 ⇜ (50/13 → 4/1) ⇝ 225/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 35/26 ⇜ (50/13 → 4/1) ⇝ 115/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 75/52 ⇜ (50/13 → 4/1) ⇝ 235/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", "[ (50/13 → 4/1) ⇝ 635/156 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ (50/13 → 4/1) ⇝ 90/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ (50/13 → 4/1) ⇝ 90/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ (205/52 → 4/1) ⇝ 365/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (205/52 → 4/1) ⇝ 365/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 25/26 ⇜ (4/1 → 105/26) | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 25/26 ⇜ (4/1 → 105/26) | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (50/13 → 4/1) ⇝ 90/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (50/13 → 4/1) ⇝ 90/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ (205/52 → 4/1) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (205/52 → 4/1) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 25/26 ⇜ (4/1 → 105/26) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 25/26 ⇜ (4/1 → 105/26) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", "[ 50/13 ⇜ (4/1 → 635/156) | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 55/52 ⇜ (4/1 → 215/52) | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 55/52 ⇜ (4/1 → 215/52) | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 15/13 ⇜ (4/1 → 55/13) | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 5/4 ⇜ (4/1 → 225/52) | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 35/26 ⇜ (4/1 → 115/26) | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 75/52 ⇜ (4/1 → 235/52) | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 55/52 ⇜ (4/1 → 215/52) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 55/52 ⇜ (4/1 → 215/52) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 15/13 ⇜ (4/1 → 55/13) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 5/4 ⇜ (4/1 → 225/52) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 35/26 ⇜ (4/1 → 115/26) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 75/52 ⇜ (4/1 → 235/52) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", "[ 0/1 ⇜ (4/1 → 5/1) ⇝ 80/13 | s:mad ]", - "[ 40/13 ⇜ (4/1 → 5/1) ⇝ 80/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 165/52 ⇜ (4/1 → 5/1) ⇝ 25/4 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 85/26 ⇜ (4/1 → 5/1) ⇝ 165/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 175/52 ⇜ (4/1 → 5/1) ⇝ 335/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 45/13 ⇜ (4/1 → 5/1) ⇝ 85/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 45/13 ⇜ (4/1 → 5/1) ⇝ 85/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 185/52 ⇜ (4/1 → 5/1) ⇝ 345/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 185/52 ⇜ (4/1 → 5/1) ⇝ 345/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 95/26 ⇜ (4/1 → 5/1) ⇝ 175/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 95/26 ⇜ (4/1 → 5/1) ⇝ 175/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 15/4 ⇜ (4/1 → 5/1) ⇝ 355/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 15/4 ⇜ (4/1 → 5/1) ⇝ 355/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 50/13 ⇜ (4/1 → 5/1) ⇝ 90/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 50/13 ⇜ (4/1 → 5/1) ⇝ 90/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 205/52 ⇜ (4/1 → 5/1) ⇝ 365/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 205/52 ⇜ (4/1 → 5/1) ⇝ 365/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (105/26 → 5/1) ⇝ 185/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (105/26 → 5/1) ⇝ 185/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 40/13 ⇜ (4/1 → 5/1) ⇝ 80/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 165/52 ⇜ (4/1 → 5/1) ⇝ 25/4 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 85/26 ⇜ (4/1 → 5/1) ⇝ 165/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 175/52 ⇜ (4/1 → 5/1) ⇝ 335/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 45/13 ⇜ (4/1 → 5/1) ⇝ 85/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 45/13 ⇜ (4/1 → 5/1) ⇝ 85/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 185/52 ⇜ (4/1 → 5/1) ⇝ 345/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 185/52 ⇜ (4/1 → 5/1) ⇝ 345/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 95/26 ⇜ (4/1 → 5/1) ⇝ 175/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 95/26 ⇜ (4/1 → 5/1) ⇝ 175/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 15/4 ⇜ (4/1 → 5/1) ⇝ 355/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 15/4 ⇜ (4/1 → 5/1) ⇝ 355/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 50/13 ⇜ (4/1 → 5/1) ⇝ 90/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 50/13 ⇜ (4/1 → 5/1) ⇝ 90/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 205/52 ⇜ (4/1 → 5/1) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 205/52 ⇜ (4/1 → 5/1) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (105/26 → 5/1) ⇝ 185/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (105/26 → 5/1) ⇝ 185/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", "[ 635/156 → 55/13 | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]", - "[ (215/52 → 5/1) ⇝ 375/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (215/52 → 5/1) ⇝ 375/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ (215/52 → 5/1) ⇝ 375/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (215/52 → 5/1) ⇝ 375/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", "[ 55/13 → 60/13 | note:ab2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4537037037037037 ]", - "[ (55/13 → 5/1) ⇝ 95/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ (225/52 → 5/1) ⇝ 385/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (115/26 → 5/1) ⇝ 15/2 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (235/52 → 5/1) ⇝ 395/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (55/13 → 5/1) ⇝ 95/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (225/52 → 5/1) ⇝ 385/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (115/26 → 5/1) ⇝ 15/2 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (235/52 → 5/1) ⇝ 395/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", "[ 60/13 → 5/1 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]", "[ 5/1 → 70/13 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]", "[ 0/1 ⇜ (5/1 → 6/1) ⇝ 80/13 | s:mad ]", - "[ 40/13 ⇜ (5/1 → 6/1) ⇝ 80/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 165/52 ⇜ (5/1 → 6/1) ⇝ 25/4 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 85/26 ⇜ (5/1 → 6/1) ⇝ 165/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 175/52 ⇜ (5/1 → 6/1) ⇝ 335/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 45/13 ⇜ (5/1 → 6/1) ⇝ 85/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 45/13 ⇜ (5/1 → 6/1) ⇝ 85/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 185/52 ⇜ (5/1 → 6/1) ⇝ 345/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 185/52 ⇜ (5/1 → 6/1) ⇝ 345/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 95/26 ⇜ (5/1 → 6/1) ⇝ 175/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 95/26 ⇜ (5/1 → 6/1) ⇝ 175/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 15/4 ⇜ (5/1 → 6/1) ⇝ 355/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 15/4 ⇜ (5/1 → 6/1) ⇝ 355/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 50/13 ⇜ (5/1 → 6/1) ⇝ 90/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 50/13 ⇜ (5/1 → 6/1) ⇝ 90/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 205/52 ⇜ (5/1 → 6/1) ⇝ 365/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 205/52 ⇜ (5/1 → 6/1) ⇝ 365/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 105/26 ⇜ (5/1 → 6/1) ⇝ 185/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 105/26 ⇜ (5/1 → 6/1) ⇝ 185/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 215/52 ⇜ (5/1 → 6/1) ⇝ 375/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 215/52 ⇜ (5/1 → 6/1) ⇝ 375/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 55/13 ⇜ (5/1 → 6/1) ⇝ 95/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 225/52 ⇜ (5/1 → 6/1) ⇝ 385/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 115/26 ⇜ (5/1 → 6/1) ⇝ 15/2 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 235/52 ⇜ (5/1 → 6/1) ⇝ 395/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 40/13 ⇜ (5/1 → 6/1) ⇝ 80/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 165/52 ⇜ (5/1 → 6/1) ⇝ 25/4 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 85/26 ⇜ (5/1 → 6/1) ⇝ 165/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 175/52 ⇜ (5/1 → 6/1) ⇝ 335/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 45/13 ⇜ (5/1 → 6/1) ⇝ 85/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 45/13 ⇜ (5/1 → 6/1) ⇝ 85/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 185/52 ⇜ (5/1 → 6/1) ⇝ 345/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 185/52 ⇜ (5/1 → 6/1) ⇝ 345/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 95/26 ⇜ (5/1 → 6/1) ⇝ 175/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 95/26 ⇜ (5/1 → 6/1) ⇝ 175/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 15/4 ⇜ (5/1 → 6/1) ⇝ 355/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 15/4 ⇜ (5/1 → 6/1) ⇝ 355/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 50/13 ⇜ (5/1 → 6/1) ⇝ 90/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 50/13 ⇜ (5/1 → 6/1) ⇝ 90/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 205/52 ⇜ (5/1 → 6/1) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 205/52 ⇜ (5/1 → 6/1) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 105/26 ⇜ (5/1 → 6/1) ⇝ 185/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 105/26 ⇜ (5/1 → 6/1) ⇝ 185/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 215/52 ⇜ (5/1 → 6/1) ⇝ 375/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 215/52 ⇜ (5/1 → 6/1) ⇝ 375/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 55/13 ⇜ (5/1 → 6/1) ⇝ 95/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 225/52 ⇜ (5/1 → 6/1) ⇝ 385/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 115/26 ⇜ (5/1 → 6/1) ⇝ 15/2 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 235/52 ⇜ (5/1 → 6/1) ⇝ 395/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", "[ (70/13 → 6/1) ⇝ 80/13 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]", "[ 0/1 ⇜ (6/1 → 80/13) | s:mad ]", - "[ 40/13 ⇜ (6/1 → 80/13) | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 165/52 ⇜ (6/1 → 80/13) ⇝ 25/4 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 85/26 ⇜ (6/1 → 80/13) ⇝ 165/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 175/52 ⇜ (6/1 → 80/13) ⇝ 335/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 45/13 ⇜ (6/1 → 80/13) ⇝ 85/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 45/13 ⇜ (6/1 → 80/13) ⇝ 85/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 185/52 ⇜ (6/1 → 80/13) ⇝ 345/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 185/52 ⇜ (6/1 → 80/13) ⇝ 345/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 95/26 ⇜ (6/1 → 80/13) ⇝ 175/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 95/26 ⇜ (6/1 → 80/13) ⇝ 175/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 15/4 ⇜ (6/1 → 80/13) ⇝ 355/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 15/4 ⇜ (6/1 → 80/13) ⇝ 355/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 50/13 ⇜ (6/1 → 80/13) ⇝ 90/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 50/13 ⇜ (6/1 → 80/13) ⇝ 90/13 | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 205/52 ⇜ (6/1 → 80/13) ⇝ 365/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 205/52 ⇜ (6/1 → 80/13) ⇝ 365/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 105/26 ⇜ (6/1 → 80/13) ⇝ 185/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 105/26 ⇜ (6/1 → 80/13) ⇝ 185/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 215/52 ⇜ (6/1 → 80/13) ⇝ 375/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 215/52 ⇜ (6/1 → 80/13) ⇝ 375/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 55/13 ⇜ (6/1 → 80/13) ⇝ 95/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 225/52 ⇜ (6/1 → 80/13) ⇝ 385/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 115/26 ⇜ (6/1 → 80/13) ⇝ 15/2 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 235/52 ⇜ (6/1 → 80/13) ⇝ 395/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 40/13 ⇜ (6/1 → 80/13) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 165/52 ⇜ (6/1 → 80/13) ⇝ 25/4 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 85/26 ⇜ (6/1 → 80/13) ⇝ 165/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 175/52 ⇜ (6/1 → 80/13) ⇝ 335/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 45/13 ⇜ (6/1 → 80/13) ⇝ 85/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 45/13 ⇜ (6/1 → 80/13) ⇝ 85/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 185/52 ⇜ (6/1 → 80/13) ⇝ 345/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 185/52 ⇜ (6/1 → 80/13) ⇝ 345/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 95/26 ⇜ (6/1 → 80/13) ⇝ 175/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 95/26 ⇜ (6/1 → 80/13) ⇝ 175/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 15/4 ⇜ (6/1 → 80/13) ⇝ 355/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 15/4 ⇜ (6/1 → 80/13) ⇝ 355/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 50/13 ⇜ (6/1 → 80/13) ⇝ 90/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 50/13 ⇜ (6/1 → 80/13) ⇝ 90/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 205/52 ⇜ (6/1 → 80/13) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 205/52 ⇜ (6/1 → 80/13) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 105/26 ⇜ (6/1 → 80/13) ⇝ 185/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 105/26 ⇜ (6/1 → 80/13) ⇝ 185/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 215/52 ⇜ (6/1 → 80/13) ⇝ 375/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 215/52 ⇜ (6/1 → 80/13) ⇝ 375/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 55/13 ⇜ (6/1 → 80/13) ⇝ 95/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 225/52 ⇜ (6/1 → 80/13) ⇝ 385/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 115/26 ⇜ (6/1 → 80/13) ⇝ 15/2 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 235/52 ⇜ (6/1 → 80/13) ⇝ 395/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", "[ 70/13 ⇜ (6/1 → 80/13) | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]", - "[ 165/52 ⇜ (80/13 → 25/4) | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 85/26 ⇜ (80/13 → 165/26) | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 175/52 ⇜ (80/13 → 335/52) | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 45/13 ⇜ (80/13 → 85/13) | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 45/13 ⇜ (80/13 → 85/13) | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 185/52 ⇜ (80/13 → 85/13) ⇝ 345/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 95/26 ⇜ (80/13 → 85/13) ⇝ 175/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 15/4 ⇜ (80/13 → 85/13) ⇝ 355/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 50/13 ⇜ (80/13 → 85/13) ⇝ 90/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 205/52 ⇜ (80/13 → 85/13) ⇝ 365/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 105/26 ⇜ (80/13 → 85/13) ⇝ 185/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 215/52 ⇜ (80/13 → 85/13) ⇝ 375/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 165/52 ⇜ (80/13 → 25/4) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 85/26 ⇜ (80/13 → 165/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 175/52 ⇜ (80/13 → 335/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 45/13 ⇜ (80/13 → 85/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 45/13 ⇜ (80/13 → 85/13) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 185/52 ⇜ (80/13 → 85/13) ⇝ 345/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 95/26 ⇜ (80/13 → 85/13) ⇝ 175/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 15/4 ⇜ (80/13 → 85/13) ⇝ 355/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 50/13 ⇜ (80/13 → 85/13) ⇝ 90/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 205/52 ⇜ (80/13 → 85/13) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 105/26 ⇜ (80/13 → 85/13) ⇝ 185/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 215/52 ⇜ (80/13 → 85/13) ⇝ 375/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", "[ 80/13 → 85/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 185/52 ⇜ (80/13 → 345/52) | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 95/26 ⇜ (80/13 → 175/26) | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 15/4 ⇜ (80/13 → 355/52) | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 50/13 ⇜ (80/13 → 90/13) | n:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 205/52 ⇜ (80/13 → 90/13) ⇝ 365/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 105/26 ⇜ (80/13 → 90/13) ⇝ 185/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 215/52 ⇜ (80/13 → 90/13) ⇝ 375/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 55/13 ⇜ (80/13 → 90/13) ⇝ 95/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 225/52 ⇜ (80/13 → 90/13) ⇝ 385/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 115/26 ⇜ (80/13 → 90/13) ⇝ 15/2 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 235/52 ⇜ (80/13 → 90/13) ⇝ 395/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (80/13 → 7/1) ⇝ 120/13 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 185/52 ⇜ (80/13 → 345/52) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 95/26 ⇜ (80/13 → 175/26) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 15/4 ⇜ (80/13 → 355/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 50/13 ⇜ (80/13 → 90/13) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 205/52 ⇜ (80/13 → 90/13) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 105/26 ⇜ (80/13 → 90/13) ⇝ 185/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 215/52 ⇜ (80/13 → 90/13) ⇝ 375/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 55/13 ⇜ (80/13 → 90/13) ⇝ 95/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 225/52 ⇜ (80/13 → 90/13) ⇝ 385/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 115/26 ⇜ (80/13 → 90/13) ⇝ 15/2 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 235/52 ⇜ (80/13 → 90/13) ⇝ 395/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (80/13 → 7/1) ⇝ 120/13 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", "[ (80/13 → 7/1) ⇝ 160/13 | s:mad ]", - "[ (25/4 → 7/1) ⇝ 485/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ (165/26 → 7/1) ⇝ 245/26 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ (335/52 → 7/1) ⇝ 495/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 185/52 ⇜ (85/13 → 345/52) | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 95/26 ⇜ (85/13 → 175/26) | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 15/4 ⇜ (85/13 → 355/52) | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 50/13 ⇜ (85/13 → 90/13) | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (25/4 → 7/1) ⇝ 485/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ (165/26 → 7/1) ⇝ 245/26 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ (335/52 → 7/1) ⇝ 495/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 185/52 ⇜ (85/13 → 345/52) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 95/26 ⇜ (85/13 → 175/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 15/4 ⇜ (85/13 → 355/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 50/13 ⇜ (85/13 → 90/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", "[ 85/13 → 90/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 205/52 ⇜ (85/13 → 7/1) ⇝ 365/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 105/26 ⇜ (85/13 → 7/1) ⇝ 185/26 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 215/52 ⇜ (85/13 → 7/1) ⇝ 375/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (85/13 → 7/1) ⇝ 125/13 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (85/13 → 7/1) ⇝ 125/13 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (345/52 → 7/1) ⇝ 505/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (345/52 → 7/1) ⇝ 505/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ (175/26 → 7/1) ⇝ 255/26 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (175/26 → 7/1) ⇝ 255/26 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ (355/52 → 7/1) ⇝ 515/52 | n:9 clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]", - "[ (355/52 → 7/1) ⇝ 515/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 205/52 ⇜ (90/13 → 7/1) ⇝ 365/52 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 105/26 ⇜ (90/13 → 7/1) ⇝ 185/26 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 215/52 ⇜ (90/13 → 7/1) ⇝ 375/52 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 55/13 ⇜ (90/13 → 7/1) ⇝ 95/13 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 225/52 ⇜ (90/13 → 7/1) ⇝ 385/52 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 115/26 ⇜ (90/13 → 7/1) ⇝ 15/2 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 235/52 ⇜ (90/13 → 7/1) ⇝ 395/52 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 205/52 ⇜ (85/13 → 7/1) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 105/26 ⇜ (85/13 → 7/1) ⇝ 185/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 215/52 ⇜ (85/13 → 7/1) ⇝ 375/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (85/13 → 7/1) ⇝ 125/13 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (85/13 → 7/1) ⇝ 125/13 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (345/52 → 7/1) ⇝ 505/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (345/52 → 7/1) ⇝ 505/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ (175/26 → 7/1) ⇝ 255/26 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (175/26 → 7/1) ⇝ 255/26 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ (355/52 → 7/1) ⇝ 515/52 | clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]", + "[ (355/52 → 7/1) ⇝ 515/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 205/52 ⇜ (90/13 → 7/1) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 105/26 ⇜ (90/13 → 7/1) ⇝ 185/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 215/52 ⇜ (90/13 → 7/1) ⇝ 375/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 55/13 ⇜ (90/13 → 7/1) ⇝ 95/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 225/52 ⇜ (90/13 → 7/1) ⇝ 385/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 115/26 ⇜ (90/13 → 7/1) ⇝ 15/2 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 235/52 ⇜ (90/13 → 7/1) ⇝ 395/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", "[ (90/13 → 7/1) ⇝ 1115/156 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ (90/13 → 7/1) ⇝ 10/1 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (90/13 → 7/1) ⇝ 10/1 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 205/52 ⇜ (7/1 → 365/52) | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 205/52 ⇜ (7/1 → 365/52) | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 105/26 ⇜ (7/1 → 185/26) | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 105/26 ⇜ (7/1 → 185/26) | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ (90/13 → 7/1) ⇝ 10/1 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (90/13 → 7/1) ⇝ 10/1 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 205/52 ⇜ (7/1 → 365/52) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 205/52 ⇜ (7/1 → 365/52) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 105/26 ⇜ (7/1 → 185/26) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 105/26 ⇜ (7/1 → 185/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", "[ 90/13 ⇜ (7/1 → 1115/156) | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 215/52 ⇜ (7/1 → 375/52) | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 215/52 ⇜ (7/1 → 375/52) | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 55/13 ⇜ (7/1 → 95/13) | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 225/52 ⇜ (7/1 → 385/52) | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 115/26 ⇜ (7/1 → 15/2) | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 235/52 ⇜ (7/1 → 395/52) | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 80/13 ⇜ (7/1 → 8/1) ⇝ 120/13 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 215/52 ⇜ (7/1 → 375/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 215/52 ⇜ (7/1 → 375/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 55/13 ⇜ (7/1 → 95/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 225/52 ⇜ (7/1 → 385/52) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 115/26 ⇜ (7/1 → 15/2) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 235/52 ⇜ (7/1 → 395/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 80/13 ⇜ (7/1 → 8/1) ⇝ 120/13 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", "[ 80/13 ⇜ (7/1 → 8/1) ⇝ 160/13 | s:mad ]", - "[ 25/4 ⇜ (7/1 → 8/1) ⇝ 485/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 165/26 ⇜ (7/1 → 8/1) ⇝ 245/26 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 335/52 ⇜ (7/1 → 8/1) ⇝ 495/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 85/13 ⇜ (7/1 → 8/1) ⇝ 125/13 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 85/13 ⇜ (7/1 → 8/1) ⇝ 125/13 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 345/52 ⇜ (7/1 → 8/1) ⇝ 505/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 345/52 ⇜ (7/1 → 8/1) ⇝ 505/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ 175/26 ⇜ (7/1 → 8/1) ⇝ 255/26 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 175/26 ⇜ (7/1 → 8/1) ⇝ 255/26 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", - "[ 355/52 ⇜ (7/1 → 8/1) ⇝ 515/52 | n:9 clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]", - "[ 355/52 ⇜ (7/1 → 8/1) ⇝ 515/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 90/13 ⇜ (7/1 → 8/1) ⇝ 10/1 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 90/13 ⇜ (7/1 → 8/1) ⇝ 10/1 | n:2 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (365/52 → 8/1) ⇝ 525/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (365/52 → 8/1) ⇝ 525/52 | n:3 clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", - "[ (185/26 → 8/1) ⇝ 265/26 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (185/26 → 8/1) ⇝ 265/26 | n:4 clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 25/4 ⇜ (7/1 → 8/1) ⇝ 485/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 165/26 ⇜ (7/1 → 8/1) ⇝ 245/26 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 335/52 ⇜ (7/1 → 8/1) ⇝ 495/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 85/13 ⇜ (7/1 → 8/1) ⇝ 125/13 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 85/13 ⇜ (7/1 → 8/1) ⇝ 125/13 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 345/52 ⇜ (7/1 → 8/1) ⇝ 505/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 345/52 ⇜ (7/1 → 8/1) ⇝ 505/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ 175/26 ⇜ (7/1 → 8/1) ⇝ 255/26 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 175/26 ⇜ (7/1 → 8/1) ⇝ 255/26 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", + "[ 355/52 ⇜ (7/1 → 8/1) ⇝ 515/52 | clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]", + "[ 355/52 ⇜ (7/1 → 8/1) ⇝ 515/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 90/13 ⇜ (7/1 → 8/1) ⇝ 10/1 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 90/13 ⇜ (7/1 → 8/1) ⇝ 10/1 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (365/52 → 8/1) ⇝ 525/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (365/52 → 8/1) ⇝ 525/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]", + "[ (185/26 → 8/1) ⇝ 265/26 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (185/26 → 8/1) ⇝ 265/26 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]", "[ 1115/156 → 95/13 | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]", - "[ (375/52 → 8/1) ⇝ 535/52 | n:9 clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]", - "[ (375/52 → 8/1) ⇝ 535/52 | n:5 clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (375/52 → 8/1) ⇝ 535/52 | clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]", + "[ (375/52 → 8/1) ⇝ 535/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]", "[ 95/13 → 100/13 | note:ab2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4537037037037037 ]", - "[ (95/13 → 8/1) ⇝ 135/13 | n:6 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (385/52 → 8/1) ⇝ 545/52 | n:7 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (15/2 → 8/1) ⇝ 275/26 | n:8 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (395/52 → 8/1) ⇝ 555/52 | n:9 clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]", + "[ (95/13 → 8/1) ⇝ 135/13 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (385/52 → 8/1) ⇝ 545/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (15/2 → 8/1) ⇝ 275/26 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (395/52 → 8/1) ⇝ 555/52 | clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]", "[ (100/13 → 8/1) ⇝ 105/13 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]", ] `; @@ -1563,394 +1563,394 @@ exports[`renders tunes > tune: dinofunk 1`] = ` exports[`renders tunes > tune: echoPiano 1`] = ` [ - "[ -3/8 ⇜ (0/1 → 1/8) | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ -3/8 ⇜ (0/1 → 1/8) | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ -3/8 ⇜ (0/1 → 1/8) | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ -1/8 ⇜ (0/1 → 1/8) | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ -1/8 ⇜ (0/1 → 1/8) ⇝ 3/8 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ -1/8 ⇜ (0/1 → 1/8) ⇝ 3/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ -1/4 ⇜ (0/1 → 1/4) | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ -1/4 ⇜ (0/1 → 1/4) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ -1/4 ⇜ (0/1 → 1/4) | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ -1/4 ⇜ (0/1 → 1/4) | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (0/1 → 1/4) ⇝ 1/2 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ (0/1 → 1/4) ⇝ 1/2 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ -1/8 ⇜ (0/1 → 3/8) | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ -1/8 ⇜ (0/1 → 3/8) | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 0/1 → 1/2 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 0/1 → 1/1 | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ -1/8 ⇜ (1/8 → 3/8) | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ -1/8 ⇜ (1/8 → 3/8) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (1/8 → 3/8) ⇝ 5/8 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ (1/8 → 3/8) ⇝ 5/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 1/8 → 5/8 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (1/8 → 1/1) ⇝ 9/8 | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 0/1 ⇜ (1/4 → 1/2) | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 0/1 ⇜ (1/4 → 1/2) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (1/4 → 1/2) ⇝ 3/4 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 1/4 → 3/4 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (1/4 → 1/1) ⇝ 5/4 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (1/4 → 1/1) ⇝ 5/4 | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 1/8 ⇜ (3/8 → 5/8) | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 1/8 ⇜ (3/8 → 5/8) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (3/8 → 5/8) ⇝ 7/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 3/8 → 7/8 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (3/8 → 1/1) ⇝ 11/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (3/8 → 1/1) ⇝ 11/8 | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 1/4 ⇜ (1/2 → 3/4) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (1/2 → 3/4) ⇝ 1/1 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (1/2 → 1/1) ⇝ 3/2 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (1/2 → 1/1) ⇝ 3/2 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 3/8 ⇜ (5/8 → 7/8) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (5/8 → 7/8) ⇝ 9/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (5/8 → 1/1) ⇝ 13/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (5/8 → 1/1) ⇝ 13/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 1/2 ⇜ (3/4 → 1/1) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (3/4 → 1/1) ⇝ 7/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (3/4 → 1/1) ⇝ 7/4 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 5/8 ⇜ (7/8 → 1/1) ⇝ 9/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (7/8 → 1/1) ⇝ 15/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (7/8 → 1/1) ⇝ 15/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 1/8 ⇜ (1/1 → 9/8) | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 3/8 ⇜ (1/1 → 9/8) ⇝ 11/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 5/8 ⇜ (1/1 → 9/8) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 5/8 ⇜ (1/1 → 9/8) ⇝ 13/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 7/8 ⇜ (1/1 → 9/8) ⇝ 15/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 1/4 ⇜ (1/1 → 5/4) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 1/4 ⇜ (1/1 → 5/4) | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 1/2 ⇜ (1/1 → 5/4) ⇝ 3/2 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 3/4 ⇜ (1/1 → 5/4) ⇝ 7/4 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (1/1 → 5/4) ⇝ 2/1 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 3/8 ⇜ (1/1 → 11/8) | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 5/8 ⇜ (1/1 → 11/8) ⇝ 13/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 7/8 ⇜ (1/1 → 11/8) ⇝ 15/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 1/2 ⇜ (1/1 → 3/2) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 3/4 ⇜ (1/1 → 3/2) ⇝ 7/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 1/1 → 2/1 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 3/8 ⇜ (9/8 → 11/8) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (9/8 → 11/8) ⇝ 17/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 5/8 ⇜ (9/8 → 13/8) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 7/8 ⇜ (9/8 → 13/8) ⇝ 15/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (9/8 → 2/1) ⇝ 17/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 1/2 ⇜ (5/4 → 3/2) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 3/4 ⇜ (5/4 → 7/4) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 1/1 ⇜ (5/4 → 7/4) ⇝ 2/1 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (5/4 → 2/1) ⇝ 9/4 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ (5/4 → 2/1) ⇝ 9/4 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 5/8 ⇜ (11/8 → 13/8) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 7/8 ⇜ (11/8 → 15/8) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 9/8 ⇜ (11/8 → 15/8) ⇝ 17/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (11/8 → 2/1) ⇝ 19/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ (11/8 → 2/1) ⇝ 19/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 3/4 ⇜ (3/2 → 7/4) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (3/2 → 2/1) ⇝ 5/2 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (3/2 → 2/1) ⇝ 5/2 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 7/8 ⇜ (13/8 → 15/8) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (13/8 → 2/1) ⇝ 21/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (13/8 → 2/1) ⇝ 21/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 1/1 ⇜ (7/4 → 2/1) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (7/4 → 2/1) ⇝ 11/4 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ (7/4 → 2/1) ⇝ 11/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 9/8 ⇜ (15/8 → 2/1) ⇝ 17/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (15/8 → 2/1) ⇝ 23/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ (15/8 → 2/1) ⇝ 23/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 9/8 ⇜ (2/1 → 17/8) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 9/8 ⇜ (2/1 → 17/8) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 11/8 ⇜ (2/1 → 17/8) ⇝ 19/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 13/8 ⇜ (2/1 → 17/8) ⇝ 21/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 15/8 ⇜ (2/1 → 17/8) ⇝ 23/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 5/4 ⇜ (2/1 → 9/4) | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 5/4 ⇜ (2/1 → 9/4) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 3/2 ⇜ (2/1 → 9/4) ⇝ 5/2 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 7/4 ⇜ (2/1 → 9/4) ⇝ 11/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 2/1 → 9/4 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ (2/1 → 9/4) ⇝ 3/1 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 11/8 ⇜ (2/1 → 19/8) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 13/8 ⇜ (2/1 → 19/8) ⇝ 21/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 15/8 ⇜ (2/1 → 19/8) ⇝ 23/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 3/2 ⇜ (2/1 → 5/2) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 7/4 ⇜ (2/1 → 5/2) ⇝ 11/4 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 11/8 ⇜ (17/8 → 19/8) | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 17/8 → 19/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ (17/8 → 19/8) ⇝ 25/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 13/8 ⇜ (17/8 → 21/8) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 15/8 ⇜ (17/8 → 21/8) ⇝ 23/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 3/2 ⇜ (9/4 → 5/2) | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 9/4 → 5/2 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 9/4 → 5/2 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 7/4 ⇜ (9/4 → 11/4) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 2/1 ⇜ (9/4 → 11/4) ⇝ 3/1 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 13/8 ⇜ (19/8 → 21/8) | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 19/8 → 21/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 19/8 → 21/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 15/8 ⇜ (19/8 → 23/8) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 17/8 ⇜ (19/8 → 23/8) ⇝ 25/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 7/4 ⇜ (5/2 → 11/4) | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 5/2 → 11/4 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 5/2 → 11/4 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 5/2 → 11/4 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 15/8 ⇜ (21/8 → 23/8) | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 21/8 → 23/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 21/8 → 23/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 21/8 → 23/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 2/1 ⇜ (11/4 → 3/1) | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 11/4 → 3/1 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 11/4 → 3/1 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 11/4 → 3/1 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 11/4 → 3/1 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 11/4 → 3/1 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 17/8 ⇜ (23/8 → 3/1) ⇝ 25/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ (23/8 → 3/1) ⇝ 25/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (23/8 → 3/1) ⇝ 25/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (23/8 → 3/1) ⇝ 25/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ (23/8 → 3/1) ⇝ 25/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (23/8 → 3/1) ⇝ 25/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 17/8 ⇜ (3/1 → 25/8) | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 23/8 ⇜ (3/1 → 25/8) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 23/8 ⇜ (3/1 → 25/8) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 23/8 ⇜ (3/1 → 25/8) | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 23/8 ⇜ (3/1 → 25/8) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 23/8 ⇜ (3/1 → 25/8) | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 3/1 → 13/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 3/1 → 13/4 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 3/1 → 13/4 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 3/1 → 13/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 3/1 → 13/4 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 3/1 → 7/2 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 25/8 → 27/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 25/8 → 27/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 25/8 → 27/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 25/8 → 27/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 25/8 → 27/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 25/8 → 29/8 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 13/4 → 7/2 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 13/4 → 7/2 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 13/4 → 7/2 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 13/4 → 7/2 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 13/4 → 15/4 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 13/4 → 15/4 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 27/8 → 29/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 27/8 → 29/8 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 27/8 → 29/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 27/8 → 29/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 27/8 → 31/8 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 27/8 → 31/8 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 7/2 → 15/4 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 7/2 → 15/4 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 7/2 → 15/4 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 7/2 → 4/1 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 7/2 → 4/1 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 7/2 → 4/1 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 29/8 → 31/8 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 29/8 → 31/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 29/8 → 31/8 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (29/8 → 4/1) ⇝ 33/8 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ (29/8 → 4/1) ⇝ 33/8 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (29/8 → 4/1) ⇝ 33/8 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 15/4 → 4/1 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (15/4 → 4/1) ⇝ 17/4 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ (15/4 → 4/1) ⇝ 17/4 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (15/4 → 4/1) ⇝ 17/4 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ (15/4 → 4/1) ⇝ 17/4 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (31/8 → 4/1) ⇝ 33/8 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (31/8 → 4/1) ⇝ 35/8 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ (31/8 → 4/1) ⇝ 35/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (31/8 → 4/1) ⇝ 35/8 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ (31/8 → 4/1) ⇝ 35/8 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 29/8 ⇜ (4/1 → 33/8) | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 29/8 ⇜ (4/1 → 33/8) | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 29/8 ⇜ (4/1 → 33/8) | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 31/8 ⇜ (4/1 → 33/8) | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 31/8 ⇜ (4/1 → 33/8) ⇝ 35/8 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 31/8 ⇜ (4/1 → 33/8) ⇝ 35/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 15/4 ⇜ (4/1 → 17/4) | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 15/4 ⇜ (4/1 → 17/4) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 15/4 ⇜ (4/1 → 17/4) | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 15/4 ⇜ (4/1 → 17/4) | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (4/1 → 17/4) ⇝ 9/2 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ (4/1 → 17/4) ⇝ 9/2 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 31/8 ⇜ (4/1 → 35/8) | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 31/8 ⇜ (4/1 → 35/8) | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 4/1 → 9/2 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 4/1 → 5/1 | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 31/8 ⇜ (33/8 → 35/8) | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 31/8 ⇜ (33/8 → 35/8) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (33/8 → 35/8) ⇝ 37/8 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ (33/8 → 35/8) ⇝ 37/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 33/8 → 37/8 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (33/8 → 5/1) ⇝ 41/8 | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 4/1 ⇜ (17/4 → 9/2) | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 4/1 ⇜ (17/4 → 9/2) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (17/4 → 9/2) ⇝ 19/4 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 17/4 → 19/4 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (17/4 → 5/1) ⇝ 21/4 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (17/4 → 5/1) ⇝ 21/4 | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 33/8 ⇜ (35/8 → 37/8) | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 33/8 ⇜ (35/8 → 37/8) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (35/8 → 37/8) ⇝ 39/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 35/8 → 39/8 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (35/8 → 5/1) ⇝ 43/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (35/8 → 5/1) ⇝ 43/8 | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 17/4 ⇜ (9/2 → 19/4) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (9/2 → 19/4) ⇝ 5/1 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (9/2 → 5/1) ⇝ 11/2 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (9/2 → 5/1) ⇝ 11/2 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 35/8 ⇜ (37/8 → 39/8) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (37/8 → 39/8) ⇝ 41/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (37/8 → 5/1) ⇝ 45/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (37/8 → 5/1) ⇝ 45/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 9/2 ⇜ (19/4 → 5/1) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (19/4 → 5/1) ⇝ 23/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (19/4 → 5/1) ⇝ 23/4 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 37/8 ⇜ (39/8 → 5/1) ⇝ 41/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (39/8 → 5/1) ⇝ 47/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (39/8 → 5/1) ⇝ 47/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 33/8 ⇜ (5/1 → 41/8) | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 35/8 ⇜ (5/1 → 41/8) ⇝ 43/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 37/8 ⇜ (5/1 → 41/8) | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 37/8 ⇜ (5/1 → 41/8) ⇝ 45/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 39/8 ⇜ (5/1 → 41/8) ⇝ 47/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 17/4 ⇜ (5/1 → 21/4) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 17/4 ⇜ (5/1 → 21/4) | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 9/2 ⇜ (5/1 → 21/4) ⇝ 11/2 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 19/4 ⇜ (5/1 → 21/4) ⇝ 23/4 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (5/1 → 21/4) ⇝ 6/1 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 35/8 ⇜ (5/1 → 43/8) | n:0 note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 37/8 ⇜ (5/1 → 43/8) ⇝ 45/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 39/8 ⇜ (5/1 → 43/8) ⇝ 47/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 9/2 ⇜ (5/1 → 11/2) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 19/4 ⇜ (5/1 → 11/2) ⇝ 23/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 5/1 → 6/1 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 35/8 ⇜ (41/8 → 43/8) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (41/8 → 43/8) ⇝ 49/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 37/8 ⇜ (41/8 → 45/8) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 39/8 ⇜ (41/8 → 45/8) ⇝ 47/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (41/8 → 6/1) ⇝ 49/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 9/2 ⇜ (21/4 → 11/2) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 19/4 ⇜ (21/4 → 23/4) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 5/1 ⇜ (21/4 → 23/4) ⇝ 6/1 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (21/4 → 6/1) ⇝ 25/4 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ (21/4 → 6/1) ⇝ 25/4 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 37/8 ⇜ (43/8 → 45/8) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 39/8 ⇜ (43/8 → 47/8) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 41/8 ⇜ (43/8 → 47/8) ⇝ 49/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (43/8 → 6/1) ⇝ 51/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ (43/8 → 6/1) ⇝ 51/8 | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 19/4 ⇜ (11/2 → 23/4) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (11/2 → 6/1) ⇝ 13/2 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (11/2 → 6/1) ⇝ 13/2 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 39/8 ⇜ (45/8 → 47/8) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (45/8 → 6/1) ⇝ 53/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (45/8 → 6/1) ⇝ 53/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 5/1 ⇜ (23/4 → 6/1) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (23/4 → 6/1) ⇝ 27/4 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ (23/4 → 6/1) ⇝ 27/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 41/8 ⇜ (47/8 → 6/1) ⇝ 49/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (47/8 → 6/1) ⇝ 55/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ (47/8 → 6/1) ⇝ 55/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 41/8 ⇜ (6/1 → 49/8) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 41/8 ⇜ (6/1 → 49/8) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 43/8 ⇜ (6/1 → 49/8) ⇝ 51/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 45/8 ⇜ (6/1 → 49/8) ⇝ 53/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 47/8 ⇜ (6/1 → 49/8) ⇝ 55/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 21/4 ⇜ (6/1 → 25/4) | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 21/4 ⇜ (6/1 → 25/4) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 11/2 ⇜ (6/1 → 25/4) ⇝ 13/2 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 23/4 ⇜ (6/1 → 25/4) ⇝ 27/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 6/1 → 25/4 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ (6/1 → 25/4) ⇝ 7/1 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 43/8 ⇜ (6/1 → 51/8) | n:2 note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 45/8 ⇜ (6/1 → 51/8) ⇝ 53/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 47/8 ⇜ (6/1 → 51/8) ⇝ 55/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 11/2 ⇜ (6/1 → 13/2) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 23/4 ⇜ (6/1 → 13/2) ⇝ 27/4 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 43/8 ⇜ (49/8 → 51/8) | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 49/8 → 51/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ (49/8 → 51/8) ⇝ 57/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 45/8 ⇜ (49/8 → 53/8) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 47/8 ⇜ (49/8 → 53/8) ⇝ 55/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 11/2 ⇜ (25/4 → 13/2) | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 25/4 → 13/2 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 25/4 → 13/2 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 23/4 ⇜ (25/4 → 27/4) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 6/1 ⇜ (25/4 → 27/4) ⇝ 7/1 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 45/8 ⇜ (51/8 → 53/8) | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 51/8 → 53/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 51/8 → 53/8 | n:4 note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 47/8 ⇜ (51/8 → 55/8) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 49/8 ⇜ (51/8 → 55/8) ⇝ 57/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 23/4 ⇜ (13/2 → 27/4) | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 13/2 → 27/4 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 13/2 → 27/4 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 13/2 → 27/4 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 47/8 ⇜ (53/8 → 55/8) | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 53/8 → 55/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 53/8 → 55/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 53/8 → 55/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 6/1 ⇜ (27/4 → 7/1) | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 27/4 → 7/1 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 27/4 → 7/1 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 27/4 → 7/1 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 27/4 → 7/1 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 27/4 → 7/1 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 49/8 ⇜ (55/8 → 7/1) ⇝ 57/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ (55/8 → 7/1) ⇝ 57/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (55/8 → 7/1) ⇝ 57/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ (55/8 → 7/1) ⇝ 57/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ (55/8 → 7/1) ⇝ 57/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (55/8 → 7/1) ⇝ 57/8 | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 49/8 ⇜ (7/1 → 57/8) | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 55/8 ⇜ (7/1 → 57/8) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 55/8 ⇜ (7/1 → 57/8) | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 55/8 ⇜ (7/1 → 57/8) | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 55/8 ⇜ (7/1 → 57/8) | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 55/8 ⇜ (7/1 → 57/8) | n:10 note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 7/1 → 29/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 7/1 → 29/4 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 7/1 → 29/4 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 7/1 → 29/4 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 7/1 → 29/4 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 7/1 → 15/2 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 57/8 → 59/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 57/8 → 59/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 57/8 → 59/8 | n:6 note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 57/8 → 59/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 57/8 → 59/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 57/8 → 61/8 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 29/4 → 15/2 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 29/4 → 15/2 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 29/4 → 15/2 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 29/4 → 15/2 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 29/4 → 31/4 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 29/4 → 31/4 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 59/8 → 61/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 59/8 → 61/8 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 59/8 → 61/8 | n:8 note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 59/8 → 61/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 59/8 → 63/8 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 59/8 → 63/8 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 15/2 → 31/4 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 15/2 → 31/4 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 15/2 → 31/4 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 15/2 → 8/1 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 15/2 → 8/1 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 15/2 → 8/1 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 61/8 → 63/8 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 61/8 → 63/8 | n:12 note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 61/8 → 63/8 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (61/8 → 8/1) ⇝ 65/8 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ (61/8 → 8/1) ⇝ 65/8 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (61/8 → 8/1) ⇝ 65/8 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 31/4 → 8/1 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (31/4 → 8/1) ⇝ 33/4 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ (31/4 → 8/1) ⇝ 33/4 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (31/4 → 8/1) ⇝ 33/4 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ (31/4 → 8/1) ⇝ 33/4 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (63/8 → 8/1) ⇝ 65/8 | n:14 note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (63/8 → 8/1) ⇝ 67/8 | n:5 note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ (63/8 → 8/1) ⇝ 67/8 | n:11 note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (63/8 → 8/1) ⇝ 67/8 | n:3 note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ (63/8 → 8/1) ⇝ 67/8 | n:9 note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ -3/8 ⇜ (0/1 → 1/8) | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ -3/8 ⇜ (0/1 → 1/8) | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ -3/8 ⇜ (0/1 → 1/8) | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ -1/8 ⇜ (0/1 → 1/8) | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ -1/8 ⇜ (0/1 → 1/8) ⇝ 3/8 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ -1/8 ⇜ (0/1 → 1/8) ⇝ 3/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ -1/4 ⇜ (0/1 → 1/4) | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ -1/4 ⇜ (0/1 → 1/4) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ -1/4 ⇜ (0/1 → 1/4) | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ -1/4 ⇜ (0/1 → 1/4) | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (0/1 → 1/4) ⇝ 1/2 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ (0/1 → 1/4) ⇝ 1/2 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ -1/8 ⇜ (0/1 → 3/8) | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ -1/8 ⇜ (0/1 → 3/8) | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 0/1 → 1/2 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 0/1 → 1/1 | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ -1/8 ⇜ (1/8 → 3/8) | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ -1/8 ⇜ (1/8 → 3/8) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (1/8 → 3/8) ⇝ 5/8 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ (1/8 → 3/8) ⇝ 5/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 1/8 → 5/8 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (1/8 → 1/1) ⇝ 9/8 | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 0/1 ⇜ (1/4 → 1/2) | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 0/1 ⇜ (1/4 → 1/2) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (1/4 → 1/2) ⇝ 3/4 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 1/4 → 3/4 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (1/4 → 1/1) ⇝ 5/4 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (1/4 → 1/1) ⇝ 5/4 | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 1/8 ⇜ (3/8 → 5/8) | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 1/8 ⇜ (3/8 → 5/8) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (3/8 → 5/8) ⇝ 7/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 3/8 → 7/8 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (3/8 → 1/1) ⇝ 11/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (3/8 → 1/1) ⇝ 11/8 | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 1/4 ⇜ (1/2 → 3/4) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (1/2 → 3/4) ⇝ 1/1 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (1/2 → 1/1) ⇝ 3/2 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (1/2 → 1/1) ⇝ 3/2 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 3/8 ⇜ (5/8 → 7/8) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (5/8 → 7/8) ⇝ 9/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (5/8 → 1/1) ⇝ 13/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (5/8 → 1/1) ⇝ 13/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 1/2 ⇜ (3/4 → 1/1) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (3/4 → 1/1) ⇝ 7/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (3/4 → 1/1) ⇝ 7/4 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 5/8 ⇜ (7/8 → 1/1) ⇝ 9/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (7/8 → 1/1) ⇝ 15/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (7/8 → 1/1) ⇝ 15/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 1/8 ⇜ (1/1 → 9/8) | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 3/8 ⇜ (1/1 → 9/8) ⇝ 11/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 5/8 ⇜ (1/1 → 9/8) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 5/8 ⇜ (1/1 → 9/8) ⇝ 13/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 7/8 ⇜ (1/1 → 9/8) ⇝ 15/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 1/4 ⇜ (1/1 → 5/4) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 1/4 ⇜ (1/1 → 5/4) | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 1/2 ⇜ (1/1 → 5/4) ⇝ 3/2 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 3/4 ⇜ (1/1 → 5/4) ⇝ 7/4 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (1/1 → 5/4) ⇝ 2/1 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 3/8 ⇜ (1/1 → 11/8) | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 5/8 ⇜ (1/1 → 11/8) ⇝ 13/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 7/8 ⇜ (1/1 → 11/8) ⇝ 15/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 1/2 ⇜ (1/1 → 3/2) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 3/4 ⇜ (1/1 → 3/2) ⇝ 7/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 1/1 → 2/1 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 3/8 ⇜ (9/8 → 11/8) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (9/8 → 11/8) ⇝ 17/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 5/8 ⇜ (9/8 → 13/8) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 7/8 ⇜ (9/8 → 13/8) ⇝ 15/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (9/8 → 2/1) ⇝ 17/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 1/2 ⇜ (5/4 → 3/2) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 3/4 ⇜ (5/4 → 7/4) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 1/1 ⇜ (5/4 → 7/4) ⇝ 2/1 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (5/4 → 2/1) ⇝ 9/4 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ (5/4 → 2/1) ⇝ 9/4 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 5/8 ⇜ (11/8 → 13/8) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 7/8 ⇜ (11/8 → 15/8) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 9/8 ⇜ (11/8 → 15/8) ⇝ 17/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (11/8 → 2/1) ⇝ 19/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ (11/8 → 2/1) ⇝ 19/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 3/4 ⇜ (3/2 → 7/4) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (3/2 → 2/1) ⇝ 5/2 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (3/2 → 2/1) ⇝ 5/2 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 7/8 ⇜ (13/8 → 15/8) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (13/8 → 2/1) ⇝ 21/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (13/8 → 2/1) ⇝ 21/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 1/1 ⇜ (7/4 → 2/1) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (7/4 → 2/1) ⇝ 11/4 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ (7/4 → 2/1) ⇝ 11/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 9/8 ⇜ (15/8 → 2/1) ⇝ 17/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (15/8 → 2/1) ⇝ 23/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ (15/8 → 2/1) ⇝ 23/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 9/8 ⇜ (2/1 → 17/8) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 9/8 ⇜ (2/1 → 17/8) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 11/8 ⇜ (2/1 → 17/8) ⇝ 19/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 13/8 ⇜ (2/1 → 17/8) ⇝ 21/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 15/8 ⇜ (2/1 → 17/8) ⇝ 23/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 5/4 ⇜ (2/1 → 9/4) | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 5/4 ⇜ (2/1 → 9/4) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 3/2 ⇜ (2/1 → 9/4) ⇝ 5/2 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 7/4 ⇜ (2/1 → 9/4) ⇝ 11/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 2/1 → 9/4 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ (2/1 → 9/4) ⇝ 3/1 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 11/8 ⇜ (2/1 → 19/8) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 13/8 ⇜ (2/1 → 19/8) ⇝ 21/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 15/8 ⇜ (2/1 → 19/8) ⇝ 23/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 3/2 ⇜ (2/1 → 5/2) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 7/4 ⇜ (2/1 → 5/2) ⇝ 11/4 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 11/8 ⇜ (17/8 → 19/8) | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 17/8 → 19/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ (17/8 → 19/8) ⇝ 25/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 13/8 ⇜ (17/8 → 21/8) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 15/8 ⇜ (17/8 → 21/8) ⇝ 23/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 3/2 ⇜ (9/4 → 5/2) | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 9/4 → 5/2 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 9/4 → 5/2 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 7/4 ⇜ (9/4 → 11/4) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 2/1 ⇜ (9/4 → 11/4) ⇝ 3/1 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 13/8 ⇜ (19/8 → 21/8) | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 19/8 → 21/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 19/8 → 21/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 15/8 ⇜ (19/8 → 23/8) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 17/8 ⇜ (19/8 → 23/8) ⇝ 25/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 7/4 ⇜ (5/2 → 11/4) | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 5/2 → 11/4 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 5/2 → 11/4 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 5/2 → 11/4 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 15/8 ⇜ (21/8 → 23/8) | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 21/8 → 23/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 21/8 → 23/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 21/8 → 23/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 2/1 ⇜ (11/4 → 3/1) | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 11/4 → 3/1 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 11/4 → 3/1 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 11/4 → 3/1 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 11/4 → 3/1 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 11/4 → 3/1 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 17/8 ⇜ (23/8 → 3/1) ⇝ 25/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ (23/8 → 3/1) ⇝ 25/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (23/8 → 3/1) ⇝ 25/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (23/8 → 3/1) ⇝ 25/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (23/8 → 3/1) ⇝ 25/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (23/8 → 3/1) ⇝ 25/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 17/8 ⇜ (3/1 → 25/8) | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 23/8 ⇜ (3/1 → 25/8) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 23/8 ⇜ (3/1 → 25/8) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 23/8 ⇜ (3/1 → 25/8) | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 23/8 ⇜ (3/1 → 25/8) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 23/8 ⇜ (3/1 → 25/8) | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 3/1 → 13/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 3/1 → 13/4 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 3/1 → 13/4 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 3/1 → 13/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 3/1 → 13/4 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 3/1 → 7/2 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 25/8 → 27/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 25/8 → 27/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 25/8 → 27/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 25/8 → 27/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 25/8 → 27/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 25/8 → 29/8 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 13/4 → 7/2 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 13/4 → 7/2 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 13/4 → 7/2 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 13/4 → 7/2 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 13/4 → 15/4 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 13/4 → 15/4 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 27/8 → 29/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 27/8 → 29/8 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 27/8 → 29/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 27/8 → 29/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 27/8 → 31/8 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 27/8 → 31/8 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 7/2 → 15/4 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 7/2 → 15/4 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 7/2 → 15/4 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 7/2 → 4/1 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 7/2 → 4/1 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 7/2 → 4/1 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 29/8 → 31/8 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 29/8 → 31/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 29/8 → 31/8 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (29/8 → 4/1) ⇝ 33/8 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ (29/8 → 4/1) ⇝ 33/8 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (29/8 → 4/1) ⇝ 33/8 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 15/4 → 4/1 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (15/4 → 4/1) ⇝ 17/4 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ (15/4 → 4/1) ⇝ 17/4 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (15/4 → 4/1) ⇝ 17/4 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ (15/4 → 4/1) ⇝ 17/4 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (31/8 → 4/1) ⇝ 33/8 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (31/8 → 4/1) ⇝ 35/8 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ (31/8 → 4/1) ⇝ 35/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (31/8 → 4/1) ⇝ 35/8 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ (31/8 → 4/1) ⇝ 35/8 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 29/8 ⇜ (4/1 → 33/8) | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 29/8 ⇜ (4/1 → 33/8) | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 29/8 ⇜ (4/1 → 33/8) | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 31/8 ⇜ (4/1 → 33/8) | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 31/8 ⇜ (4/1 → 33/8) ⇝ 35/8 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 31/8 ⇜ (4/1 → 33/8) ⇝ 35/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 15/4 ⇜ (4/1 → 17/4) | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 15/4 ⇜ (4/1 → 17/4) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 15/4 ⇜ (4/1 → 17/4) | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 15/4 ⇜ (4/1 → 17/4) | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (4/1 → 17/4) ⇝ 9/2 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ (4/1 → 17/4) ⇝ 9/2 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 31/8 ⇜ (4/1 → 35/8) | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 31/8 ⇜ (4/1 → 35/8) | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 4/1 → 9/2 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 4/1 → 5/1 | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 31/8 ⇜ (33/8 → 35/8) | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 31/8 ⇜ (33/8 → 35/8) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (33/8 → 35/8) ⇝ 37/8 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ (33/8 → 35/8) ⇝ 37/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 33/8 → 37/8 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (33/8 → 5/1) ⇝ 41/8 | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 4/1 ⇜ (17/4 → 9/2) | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 4/1 ⇜ (17/4 → 9/2) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (17/4 → 9/2) ⇝ 19/4 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 17/4 → 19/4 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (17/4 → 5/1) ⇝ 21/4 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (17/4 → 5/1) ⇝ 21/4 | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 33/8 ⇜ (35/8 → 37/8) | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 33/8 ⇜ (35/8 → 37/8) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (35/8 → 37/8) ⇝ 39/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 35/8 → 39/8 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (35/8 → 5/1) ⇝ 43/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (35/8 → 5/1) ⇝ 43/8 | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 17/4 ⇜ (9/2 → 19/4) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (9/2 → 19/4) ⇝ 5/1 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (9/2 → 5/1) ⇝ 11/2 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (9/2 → 5/1) ⇝ 11/2 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 35/8 ⇜ (37/8 → 39/8) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (37/8 → 39/8) ⇝ 41/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (37/8 → 5/1) ⇝ 45/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (37/8 → 5/1) ⇝ 45/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 9/2 ⇜ (19/4 → 5/1) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (19/4 → 5/1) ⇝ 23/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (19/4 → 5/1) ⇝ 23/4 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 37/8 ⇜ (39/8 → 5/1) ⇝ 41/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (39/8 → 5/1) ⇝ 47/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (39/8 → 5/1) ⇝ 47/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 33/8 ⇜ (5/1 → 41/8) | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 35/8 ⇜ (5/1 → 41/8) ⇝ 43/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 37/8 ⇜ (5/1 → 41/8) | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 37/8 ⇜ (5/1 → 41/8) ⇝ 45/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 39/8 ⇜ (5/1 → 41/8) ⇝ 47/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 17/4 ⇜ (5/1 → 21/4) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 17/4 ⇜ (5/1 → 21/4) | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 9/2 ⇜ (5/1 → 21/4) ⇝ 11/2 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 19/4 ⇜ (5/1 → 21/4) ⇝ 23/4 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (5/1 → 21/4) ⇝ 6/1 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 35/8 ⇜ (5/1 → 43/8) | note:D3 clip:1 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 37/8 ⇜ (5/1 → 43/8) ⇝ 45/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 39/8 ⇜ (5/1 → 43/8) ⇝ 47/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 9/2 ⇜ (5/1 → 11/2) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 19/4 ⇜ (5/1 → 11/2) ⇝ 23/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 5/1 → 6/1 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 35/8 ⇜ (41/8 → 43/8) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (41/8 → 43/8) ⇝ 49/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 37/8 ⇜ (41/8 → 45/8) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 39/8 ⇜ (41/8 → 45/8) ⇝ 47/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (41/8 → 6/1) ⇝ 49/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 9/2 ⇜ (21/4 → 11/2) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 19/4 ⇜ (21/4 → 23/4) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 5/1 ⇜ (21/4 → 23/4) ⇝ 6/1 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (21/4 → 6/1) ⇝ 25/4 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ (21/4 → 6/1) ⇝ 25/4 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 37/8 ⇜ (43/8 → 45/8) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 39/8 ⇜ (43/8 → 47/8) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 41/8 ⇜ (43/8 → 47/8) ⇝ 49/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (43/8 → 6/1) ⇝ 51/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ (43/8 → 6/1) ⇝ 51/8 | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 19/4 ⇜ (11/2 → 23/4) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (11/2 → 6/1) ⇝ 13/2 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (11/2 → 6/1) ⇝ 13/2 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 39/8 ⇜ (45/8 → 47/8) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (45/8 → 6/1) ⇝ 53/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (45/8 → 6/1) ⇝ 53/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 5/1 ⇜ (23/4 → 6/1) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (23/4 → 6/1) ⇝ 27/4 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ (23/4 → 6/1) ⇝ 27/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 41/8 ⇜ (47/8 → 6/1) ⇝ 49/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (47/8 → 6/1) ⇝ 55/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ (47/8 → 6/1) ⇝ 55/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 41/8 ⇜ (6/1 → 49/8) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 41/8 ⇜ (6/1 → 49/8) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 43/8 ⇜ (6/1 → 49/8) ⇝ 51/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 45/8 ⇜ (6/1 → 49/8) ⇝ 53/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 47/8 ⇜ (6/1 → 49/8) ⇝ 55/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 21/4 ⇜ (6/1 → 25/4) | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 21/4 ⇜ (6/1 → 25/4) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 11/2 ⇜ (6/1 → 25/4) ⇝ 13/2 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 23/4 ⇜ (6/1 → 25/4) ⇝ 27/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 6/1 → 25/4 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ (6/1 → 25/4) ⇝ 7/1 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 43/8 ⇜ (6/1 → 51/8) | note:F3 clip:1 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 45/8 ⇜ (6/1 → 51/8) ⇝ 53/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 47/8 ⇜ (6/1 → 51/8) ⇝ 55/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 11/2 ⇜ (6/1 → 13/2) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 23/4 ⇜ (6/1 → 13/2) ⇝ 27/4 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 43/8 ⇜ (49/8 → 51/8) | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 49/8 → 51/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ (49/8 → 51/8) ⇝ 57/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 45/8 ⇜ (49/8 → 53/8) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 47/8 ⇜ (49/8 → 53/8) ⇝ 55/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 11/2 ⇜ (25/4 → 13/2) | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 25/4 → 13/2 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 25/4 → 13/2 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 23/4 ⇜ (25/4 → 27/4) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 6/1 ⇜ (25/4 → 27/4) ⇝ 7/1 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 45/8 ⇜ (51/8 → 53/8) | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 51/8 → 53/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 51/8 → 53/8 | note:A3 clip:1 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 47/8 ⇜ (51/8 → 55/8) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 49/8 ⇜ (51/8 → 55/8) ⇝ 57/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 23/4 ⇜ (13/2 → 27/4) | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 13/2 → 27/4 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 13/2 → 27/4 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 13/2 → 27/4 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 47/8 ⇜ (53/8 → 55/8) | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 53/8 → 55/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 53/8 → 55/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 53/8 → 55/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 6/1 ⇜ (27/4 → 7/1) | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 27/4 → 7/1 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 27/4 → 7/1 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 27/4 → 7/1 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 27/4 → 7/1 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 27/4 → 7/1 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 49/8 ⇜ (55/8 → 7/1) ⇝ 57/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ (55/8 → 7/1) ⇝ 57/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (55/8 → 7/1) ⇝ 57/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ (55/8 → 7/1) ⇝ 57/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ (55/8 → 7/1) ⇝ 57/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (55/8 → 7/1) ⇝ 57/8 | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 49/8 ⇜ (7/1 → 57/8) | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 55/8 ⇜ (7/1 → 57/8) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 55/8 ⇜ (7/1 → 57/8) | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 55/8 ⇜ (7/1 → 57/8) | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 55/8 ⇜ (7/1 → 57/8) | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 55/8 ⇜ (7/1 → 57/8) | note:G4 clip:1 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 7/1 → 29/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 7/1 → 29/4 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 7/1 → 29/4 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 7/1 → 29/4 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 7/1 → 29/4 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 7/1 → 15/2 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 57/8 → 59/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 57/8 → 59/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 57/8 → 59/8 | note:C4 clip:1 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 57/8 → 59/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 57/8 → 59/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 57/8 → 61/8 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 29/4 → 15/2 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 29/4 → 15/2 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 29/4 → 15/2 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 29/4 → 15/2 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 29/4 → 31/4 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 29/4 → 31/4 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 59/8 → 61/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 59/8 → 61/8 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 59/8 → 61/8 | note:E4 clip:1 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 59/8 → 61/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 59/8 → 63/8 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 59/8 → 63/8 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 15/2 → 31/4 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 15/2 → 31/4 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 15/2 → 31/4 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 15/2 → 8/1 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 15/2 → 8/1 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 15/2 → 8/1 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 61/8 → 63/8 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 61/8 → 63/8 | note:Bb4 clip:1 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 61/8 → 63/8 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (61/8 → 8/1) ⇝ 65/8 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ (61/8 → 8/1) ⇝ 65/8 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (61/8 → 8/1) ⇝ 65/8 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 31/4 → 8/1 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (31/4 → 8/1) ⇝ 33/4 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ (31/4 → 8/1) ⇝ 33/4 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (31/4 → 8/1) ⇝ 33/4 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ (31/4 → 8/1) ⇝ 33/4 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (63/8 → 8/1) ⇝ 65/8 | note:D5 clip:1 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (63/8 → 8/1) ⇝ 67/8 | note:Bb3 clip:1 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ (63/8 → 8/1) ⇝ 67/8 | note:A4 clip:1 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (63/8 → 8/1) ⇝ 67/8 | note:G3 clip:1 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ (63/8 → 8/1) ⇝ 67/8 | note:F4 clip:1 s:piano release:0.1 pan:0.5509259259259259 ]", ] `; @@ -6601,710 +6601,710 @@ exports[`renders tunes > tune: festivalOfFingers 1`] = ` exports[`renders tunes > tune: festivalOfFingers3 1`] = ` [ - "[ -1/2 ⇜ (0/1 → 1/6) | n:14 gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ -1/6 ⇜ (0/1 → 1/6) | n:25 clip:1 gain:0.5790943073464694 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ -1/6 ⇜ (0/1 → 1/6) | n:22 clip:1 gain:0.5381966011250106 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ -1/3 ⇜ (0/1 → 1/3) | n:7 gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 0/1 → 1/3 | n:22 clip:1 gain:0.6209056926535308 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 0/1 → 1/3 | n:25 clip:1 gain:0.5790943073464694 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ -3/2 ⇜ (0/1 → 1/2) | n:7 gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ -3/2 ⇜ (0/1 → 1/2) | n:9 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ -3/2 ⇜ (0/1 → 1/2) | n:13 gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ -1/2 ⇜ (0/1 → 1/2) | n:14 gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ -1/2 ⇜ (0/1 → 1/2) | n:29 gain:0.25 clip:1 note:E7 s:piano release:0.1 pan:0.712962962962963 ]", - "[ -1/6 ⇜ (0/1 → 1/2) | n:0 gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 0/1 → 2/3 | n:-7 gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ -1/1 ⇜ (0/1 → 1/1) | n:14 gain:0.3333333333333333 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ -1/1 ⇜ (0/1 → 1/1) | n:16 gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ -1/1 ⇜ (0/1 → 1/1) | n:20 gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ -1/2 ⇜ (0/1 → 1/1) ⇝ 3/2 | n:21 gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ -1/2 ⇜ (0/1 → 1/1) ⇝ 3/2 | n:23 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ -1/2 ⇜ (0/1 → 1/1) ⇝ 3/2 | n:27 gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 0/1 → 1/1 | n:8 gain:1 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 0/1 → 1/1 | n:21 gain:0.3333333333333333 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (0/1 → 1/1) ⇝ 2/1 | n:0 gain:1 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ (0/1 → 1/1) ⇝ 2/1 | n:2 gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (0/1 → 1/1) ⇝ 2/1 | n:6 gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 1/6 → 1/2 | n:22 clip:1 gain:0.6209056926535308 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 1/6 → 1/2 | n:25 clip:1 gain:0.5790943073464694 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 1/6 → 5/6 | n:14 gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 1/3 → 2/3 | n:25 clip:1 gain:0.6618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 1/3 → 2/3 | n:22 clip:1 gain:0.6209056926535308 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 1/3 → 1/1 | n:7 gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 1/2 → 5/6 | n:25 clip:1 gain:0.6618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 1/2 → 5/6 | n:22 clip:1 gain:0.6209056926535308 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ (1/2 → 1/1) ⇝ 7/6 | n:0 gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ (1/2 → 1/1) ⇝ 3/2 | n:15 gain:0.5 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (1/2 → 1/1) ⇝ 3/2 | n:28 gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (1/2 → 1/1) ⇝ 5/2 | n:7 gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ (1/2 → 1/1) ⇝ 5/2 | n:9 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (1/2 → 1/1) ⇝ 5/2 | n:13 gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 2/3 → 1/1 | n:22 clip:1 gain:0.7000000000000001 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 2/3 → 1/1 | n:25 clip:1 gain:0.6618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (2/3 → 1/1) ⇝ 4/3 | n:-7 gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ (5/6 → 1/1) ⇝ 7/6 | n:22 clip:1 gain:0.7000000000000001 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ (5/6 → 1/1) ⇝ 7/6 | n:25 clip:1 gain:0.6618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (5/6 → 1/1) ⇝ 3/2 | n:14 gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 1/2 ⇜ (1/1 → 7/6) | n:0 gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 5/6 ⇜ (1/1 → 7/6) | n:22 clip:1 gain:0.7000000000000001 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 5/6 ⇜ (1/1 → 7/6) | n:25 clip:1 gain:0.6618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 2/3 ⇜ (1/1 → 4/3) | n:-7 gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 1/1 → 4/3 | n:25 clip:1 gain:0.7338261212717717 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 1/1 → 4/3 | n:22 clip:1 gain:0.7000000000000001 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ -1/2 ⇜ (1/1 → 3/2) | n:21 gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ -1/2 ⇜ (1/1 → 3/2) | n:23 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ -1/2 ⇜ (1/1 → 3/2) | n:27 gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 1/2 ⇜ (1/1 → 3/2) | n:15 gain:0.5 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 1/2 ⇜ (1/1 → 3/2) | n:28 gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 5/6 ⇜ (1/1 → 3/2) | n:14 gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 1/1 → 5/3 | n:7 gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 0/1 ⇜ (1/1 → 2/1) | n:0 gain:1 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 0/1 ⇜ (1/1 → 2/1) | n:2 gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 0/1 ⇜ (1/1 → 2/1) | n:6 gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 1/2 ⇜ (1/1 → 2/1) ⇝ 5/2 | n:7 gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 1/2 ⇜ (1/1 → 2/1) ⇝ 5/2 | n:9 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 1/2 ⇜ (1/1 → 2/1) ⇝ 5/2 | n:13 gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 1/1 → 2/1 | n:7 gain:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 1/1 → 2/1 | n:22 gain:0.3333333333333333 clip:1 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ (1/1 → 2/1) ⇝ 3/1 | n:14 gain:0.3333333333333333 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (1/1 → 2/1) ⇝ 3/1 | n:16 gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ (1/1 → 2/1) ⇝ 3/1 | n:20 gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ 7/6 → 3/2 | n:25 clip:1 gain:0.7338261212717717 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 7/6 → 3/2 | n:22 clip:1 gain:0.7000000000000001 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 7/6 → 11/6 | n:0 gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 4/3 → 5/3 | n:22 clip:1 gain:0.7618033988749895 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 4/3 → 5/3 | n:25 clip:1 gain:0.7338261212717717 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 4/3 → 2/1 | n:-7 gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 3/2 → 11/6 | n:22 clip:1 gain:0.7618033988749895 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 3/2 → 11/6 | n:25 clip:1 gain:0.7338261212717717 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (3/2 → 2/1) ⇝ 13/6 | n:14 gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (3/2 → 2/1) ⇝ 5/2 | n:14 gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (3/2 → 2/1) ⇝ 5/2 | n:29 gain:0.25 clip:1 note:E7 s:piano release:0.1 pan:0.712962962962963 ]", - "[ (3/2 → 2/1) ⇝ 7/2 | n:21 gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (3/2 → 2/1) ⇝ 7/2 | n:23 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ (3/2 → 2/1) ⇝ 7/2 | n:27 gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 5/3 → 2/1 | n:25 clip:1 gain:0.7827090915285202 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 5/3 → 2/1 | n:22 clip:1 gain:0.7618033988749895 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ (5/3 → 2/1) ⇝ 7/3 | n:7 gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ (11/6 → 2/1) ⇝ 13/6 | n:25 clip:1 gain:0.7827090915285202 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (11/6 → 2/1) ⇝ 13/6 | n:22 clip:1 gain:0.7618033988749895 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ (11/6 → 2/1) ⇝ 5/2 | n:0 gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 3/2 ⇜ (2/1 → 13/6) | n:14 gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 11/6 ⇜ (2/1 → 13/6) | n:25 clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 11/6 ⇜ (2/1 → 13/6) | n:22 clip:1 gain:0.7618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 5/3 ⇜ (2/1 → 7/3) | n:7 gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 2/1 → 7/3 | n:22 clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 2/1 → 7/3 | n:25 clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 1/2 ⇜ (2/1 → 5/2) | n:7 gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 1/2 ⇜ (2/1 → 5/2) | n:9 gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", - "[ 1/2 ⇜ (2/1 → 5/2) | n:13 gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 3/2 ⇜ (2/1 → 5/2) | n:14 gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 3/2 ⇜ (2/1 → 5/2) | n:29 gain:0.25 clip:1 note:A7 s:piano release:0.1 pan:0.7361111111111112 ]", - "[ 11/6 ⇜ (2/1 → 5/2) | n:0 gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 2/1 → 8/3 | n:-7 gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", - "[ 1/1 ⇜ (2/1 → 3/1) | n:14 gain:0.3333333333333333 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 1/1 ⇜ (2/1 → 3/1) | n:16 gain:0.3333333333333333 clip:1 note:B5 s:piano release:0.1 pan:0.6342592592592593 ]", - "[ 1/1 ⇜ (2/1 → 3/1) | n:20 gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ 3/2 ⇜ (2/1 → 3/1) ⇝ 7/2 | n:21 gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 3/2 ⇜ (2/1 → 3/1) ⇝ 7/2 | n:23 gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", - "[ 3/2 ⇜ (2/1 → 3/1) ⇝ 7/2 | n:27 gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", - "[ 2/1 → 3/1 | n:8 gain:1 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 2/1 → 3/1 | n:21 gain:0.3333333333333333 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (2/1 → 3/1) ⇝ 4/1 | n:0 gain:1 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ (2/1 → 3/1) ⇝ 4/1 | n:2 gain:1 clip:1 note:B3 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ (2/1 → 3/1) ⇝ 4/1 | n:6 gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 13/6 → 5/2 | n:22 clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 13/6 → 5/2 | n:25 clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 13/6 → 17/6 | n:14 gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 7/3 → 8/3 | n:25 clip:1 gain:0.8 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 7/3 → 8/3 | n:22 clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 7/3 → 3/1 | n:7 gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 5/2 → 17/6 | n:25 clip:1 gain:0.8 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 5/2 → 17/6 | n:22 clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (5/2 → 3/1) ⇝ 19/6 | n:0 gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ (5/2 → 3/1) ⇝ 7/2 | n:15 gain:0.5 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", - "[ (5/2 → 3/1) ⇝ 7/2 | n:28 gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", - "[ (5/2 → 3/1) ⇝ 9/2 | n:7 gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ (5/2 → 3/1) ⇝ 9/2 | n:9 gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", - "[ (5/2 → 3/1) ⇝ 9/2 | n:13 gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 8/3 → 3/1 | n:22 clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 8/3 → 3/1 | n:25 clip:1 gain:0.8 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (8/3 → 3/1) ⇝ 10/3 | n:-7 gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", - "[ (17/6 → 3/1) ⇝ 19/6 | n:22 clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (17/6 → 3/1) ⇝ 19/6 | n:25 clip:1 gain:0.8 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (17/6 → 3/1) ⇝ 7/2 | n:14 gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 5/2 ⇜ (3/1 → 19/6) | n:0 gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 17/6 ⇜ (3/1 → 19/6) | n:22 clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 17/6 ⇜ (3/1 → 19/6) | n:25 clip:1 gain:0.8 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 8/3 ⇜ (3/1 → 10/3) | n:-7 gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", - "[ 3/1 → 10/3 | n:25 clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 3/1 → 10/3 | n:22 clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 3/2 ⇜ (3/1 → 7/2) | n:21 gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 3/2 ⇜ (3/1 → 7/2) | n:23 gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", - "[ 3/2 ⇜ (3/1 → 7/2) | n:27 gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", - "[ 5/2 ⇜ (3/1 → 7/2) | n:15 gain:0.5 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", - "[ 5/2 ⇜ (3/1 → 7/2) | n:28 gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", - "[ 17/6 ⇜ (3/1 → 7/2) | n:14 gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 3/1 → 11/3 | n:7 gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 2/1 ⇜ (3/1 → 4/1) | n:0 gain:1 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 2/1 ⇜ (3/1 → 4/1) | n:2 gain:1 clip:1 note:B3 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 2/1 ⇜ (3/1 → 4/1) | n:6 gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 5/2 ⇜ (3/1 → 4/1) ⇝ 9/2 | n:7 gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 5/2 ⇜ (3/1 → 4/1) ⇝ 9/2 | n:9 gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", - "[ 5/2 ⇜ (3/1 → 4/1) ⇝ 9/2 | n:13 gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 3/1 → 4/1 | n:7 gain:1 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 3/1 → 4/1 | n:22 gain:0.3333333333333333 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (3/1 → 4/1) ⇝ 5/1 | n:14 gain:0.3333333333333333 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ (3/1 → 4/1) ⇝ 5/1 | n:16 gain:0.3333333333333333 clip:1 note:B5 s:piano release:0.1 pan:0.6342592592592593 ]", - "[ (3/1 → 4/1) ⇝ 5/1 | n:20 gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ 19/6 → 7/2 | n:25 clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 19/6 → 7/2 | n:22 clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 19/6 → 23/6 | n:0 gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 10/3 → 11/3 | n:22 clip:1 gain:0.7618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 10/3 → 11/3 | n:25 clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 10/3 → 4/1 | n:-7 gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", - "[ 7/2 → 23/6 | n:22 clip:1 gain:0.7618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 7/2 → 23/6 | n:25 clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (7/2 → 4/1) ⇝ 25/6 | n:14 gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ (7/2 → 4/1) ⇝ 9/2 | n:14 gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ (7/2 → 4/1) ⇝ 9/2 | n:29 gain:0.25 clip:1 note:A7 s:piano release:0.1 pan:0.7361111111111112 ]", - "[ (7/2 → 4/1) ⇝ 11/2 | n:21 gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (7/2 → 4/1) ⇝ 11/2 | n:23 gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", - "[ (7/2 → 4/1) ⇝ 11/2 | n:27 gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", - "[ 11/3 → 4/1 | n:25 clip:1 gain:0.7338261212717716 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 11/3 → 4/1 | n:22 clip:1 gain:0.7618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (11/3 → 4/1) ⇝ 13/3 | n:7 gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ (23/6 → 4/1) ⇝ 25/6 | n:25 clip:1 gain:0.7338261212717716 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (23/6 → 4/1) ⇝ 25/6 | n:22 clip:1 gain:0.7618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (23/6 → 4/1) ⇝ 9/2 | n:0 gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 7/2 ⇜ (4/1 → 25/6) | n:14 gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 23/6 ⇜ (4/1 → 25/6) | n:25 clip:1 gain:0.7338261212717716 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 23/6 ⇜ (4/1 → 25/6) | n:22 clip:1 gain:0.7618033988749895 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 11/3 ⇜ (4/1 → 13/3) | n:7 gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 4/1 → 13/3 | n:22 clip:1 gain:0.7000000000000001 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 4/1 → 13/3 | n:25 clip:1 gain:0.7338261212717716 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 5/2 ⇜ (4/1 → 9/2) | n:7 gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 5/2 ⇜ (4/1 → 9/2) | n:9 gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", - "[ 5/2 ⇜ (4/1 → 9/2) | n:13 gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 7/2 ⇜ (4/1 → 9/2) | n:14 gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 7/2 ⇜ (4/1 → 9/2) | n:29 gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 23/6 ⇜ (4/1 → 9/2) | n:0 gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 4/1 → 14/3 | n:-7 gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", - "[ 3/1 ⇜ (4/1 → 5/1) | n:14 gain:0.3333333333333333 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 3/1 ⇜ (4/1 → 5/1) | n:16 gain:0.3333333333333333 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", - "[ 3/1 ⇜ (4/1 → 5/1) | n:20 gain:0.3333333333333333 clip:1 note:Bb5 s:piano release:0.1 pan:0.6296296296296297 ]", - "[ 7/2 ⇜ (4/1 → 5/1) ⇝ 11/2 | n:21 gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ 7/2 ⇜ (4/1 → 5/1) ⇝ 11/2 | n:23 gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", - "[ 7/2 ⇜ (4/1 → 5/1) ⇝ 11/2 | n:27 gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", - "[ 4/1 → 5/1 | n:8 gain:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 4/1 → 5/1 | n:21 gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ (4/1 → 5/1) ⇝ 6/1 | n:0 gain:1 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ (4/1 → 5/1) ⇝ 6/1 | n:2 gain:1 clip:1 note:Eb3 s:piano release:0.1 pan:0.4861111111111111 ]", - "[ (4/1 → 5/1) ⇝ 6/1 | n:6 gain:1 clip:1 note:Bb3 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 25/6 → 9/2 | n:22 clip:1 gain:0.7000000000000001 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 25/6 → 9/2 | n:25 clip:1 gain:0.7338261212717716 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 25/6 → 29/6 | n:14 gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 13/3 → 14/3 | n:25 clip:1 gain:0.6618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 13/3 → 14/3 | n:22 clip:1 gain:0.7000000000000001 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 13/3 → 5/1 | n:7 gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 9/2 → 29/6 | n:25 clip:1 gain:0.6618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 9/2 → 29/6 | n:22 clip:1 gain:0.7000000000000001 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (9/2 → 5/1) ⇝ 31/6 | n:0 gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ (9/2 → 5/1) ⇝ 11/2 | n:15 gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (9/2 → 5/1) ⇝ 11/2 | n:28 gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ (9/2 → 5/1) ⇝ 13/2 | n:7 gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (9/2 → 5/1) ⇝ 13/2 | n:9 gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", - "[ (9/2 → 5/1) ⇝ 13/2 | n:13 gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 14/3 → 5/1 | n:22 clip:1 gain:0.6209056926535308 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 14/3 → 5/1 | n:25 clip:1 gain:0.6618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (14/3 → 5/1) ⇝ 16/3 | n:-7 gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", - "[ (29/6 → 5/1) ⇝ 31/6 | n:22 clip:1 gain:0.6209056926535308 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (29/6 → 5/1) ⇝ 31/6 | n:25 clip:1 gain:0.6618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (29/6 → 5/1) ⇝ 11/2 | n:14 gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 9/2 ⇜ (5/1 → 31/6) | n:0 gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 29/6 ⇜ (5/1 → 31/6) | n:22 clip:1 gain:0.6209056926535308 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 29/6 ⇜ (5/1 → 31/6) | n:25 clip:1 gain:0.6618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 14/3 ⇜ (5/1 → 16/3) | n:-7 gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", - "[ 5/1 → 16/3 | n:25 clip:1 gain:0.5790943073464694 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 5/1 → 16/3 | n:22 clip:1 gain:0.6209056926535308 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 7/2 ⇜ (5/1 → 11/2) | n:21 gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ 7/2 ⇜ (5/1 → 11/2) | n:23 gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", - "[ 7/2 ⇜ (5/1 → 11/2) | n:27 gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", - "[ 9/2 ⇜ (5/1 → 11/2) | n:15 gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 9/2 ⇜ (5/1 → 11/2) | n:28 gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 29/6 ⇜ (5/1 → 11/2) | n:14 gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 5/1 → 17/3 | n:7 gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 4/1 ⇜ (5/1 → 6/1) | n:0 gain:1 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 4/1 ⇜ (5/1 → 6/1) | n:2 gain:1 clip:1 note:Eb3 s:piano release:0.1 pan:0.4861111111111111 ]", - "[ 4/1 ⇜ (5/1 → 6/1) | n:6 gain:1 clip:1 note:Bb3 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 9/2 ⇜ (5/1 → 6/1) ⇝ 13/2 | n:7 gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 9/2 ⇜ (5/1 → 6/1) ⇝ 13/2 | n:9 gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", - "[ 9/2 ⇜ (5/1 → 6/1) ⇝ 13/2 | n:13 gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 5/1 → 6/1 | n:7 gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 5/1 → 6/1 | n:22 gain:0.3333333333333333 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (5/1 → 6/1) ⇝ 7/1 | n:14 gain:0.3333333333333333 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (5/1 → 6/1) ⇝ 7/1 | n:16 gain:0.3333333333333333 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", - "[ (5/1 → 6/1) ⇝ 7/1 | n:20 gain:0.3333333333333333 clip:1 note:Bb5 s:piano release:0.1 pan:0.6296296296296297 ]", - "[ 31/6 → 11/2 | n:25 clip:1 gain:0.5790943073464694 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 31/6 → 11/2 | n:22 clip:1 gain:0.6209056926535308 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 31/6 → 35/6 | n:0 gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 16/3 → 17/3 | n:22 clip:1 gain:0.5381966011250106 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 16/3 → 17/3 | n:25 clip:1 gain:0.5790943073464694 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 16/3 → 6/1 | n:-7 gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", - "[ 11/2 → 35/6 | n:22 clip:1 gain:0.5381966011250106 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 11/2 → 35/6 | n:25 clip:1 gain:0.5790943073464694 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (11/2 → 6/1) ⇝ 37/6 | n:14 gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (11/2 → 6/1) ⇝ 13/2 | n:14 gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (11/2 → 6/1) ⇝ 13/2 | n:29 gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (11/2 → 6/1) ⇝ 15/2 | n:21 gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ (11/2 → 6/1) ⇝ 15/2 | n:23 gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", - "[ (11/2 → 6/1) ⇝ 15/2 | n:27 gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", - "[ 17/3 → 6/1 | n:25 clip:1 gain:0.5 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 17/3 → 6/1 | n:22 clip:1 gain:0.5381966011250106 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (17/3 → 6/1) ⇝ 19/3 | n:7 gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (35/6 → 6/1) ⇝ 37/6 | n:25 clip:1 gain:0.5 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (35/6 → 6/1) ⇝ 37/6 | n:22 clip:1 gain:0.5381966011250106 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (35/6 → 6/1) ⇝ 13/2 | n:0 gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 11/2 ⇜ (6/1 → 37/6) | n:14 gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 35/6 ⇜ (6/1 → 37/6) | n:25 clip:1 gain:0.5 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 35/6 ⇜ (6/1 → 37/6) | n:22 clip:1 gain:0.5381966011250106 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 17/3 ⇜ (6/1 → 19/3) | n:7 gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 6/1 → 19/3 | n:22 clip:1 gain:0.46617387872822835 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 6/1 → 19/3 | n:25 clip:1 gain:0.5 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 9/2 ⇜ (6/1 → 13/2) | n:7 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 9/2 ⇜ (6/1 → 13/2) | n:9 gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 9/2 ⇜ (6/1 → 13/2) | n:13 gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", - "[ 11/2 ⇜ (6/1 → 13/2) | n:14 gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 11/2 ⇜ (6/1 → 13/2) | n:29 gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", - "[ 35/6 ⇜ (6/1 → 13/2) | n:0 gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 6/1 → 20/3 | n:-7 gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", - "[ 5/1 ⇜ (6/1 → 7/1) | n:14 gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 5/1 ⇜ (6/1 → 7/1) | n:16 gain:0.3333333333333333 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", - "[ 5/1 ⇜ (6/1 → 7/1) | n:20 gain:0.3333333333333333 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", - "[ 11/2 ⇜ (6/1 → 7/1) ⇝ 15/2 | n:21 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ 11/2 ⇜ (6/1 → 7/1) ⇝ 15/2 | n:23 gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 11/2 ⇜ (6/1 → 7/1) ⇝ 15/2 | n:27 gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", - "[ 6/1 → 7/1 | n:8 gain:1 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 6/1 → 7/1 | n:21 gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ (6/1 → 7/1) ⇝ 8/1 | n:0 gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (6/1 → 7/1) ⇝ 8/1 | n:2 gain:1 clip:1 note:A3 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ (6/1 → 7/1) ⇝ 8/1 | n:6 gain:1 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", - "[ 37/6 → 13/2 | n:22 clip:1 gain:0.46617387872822835 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 37/6 → 13/2 | n:25 clip:1 gain:0.5 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 37/6 → 41/6 | n:14 gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 19/3 → 20/3 | n:25 clip:1 gain:0.4381966011250106 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 19/3 → 20/3 | n:22 clip:1 gain:0.46617387872822835 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 19/3 → 7/1 | n:7 gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 13/2 → 41/6 | n:25 clip:1 gain:0.4381966011250106 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 13/2 → 41/6 | n:22 clip:1 gain:0.46617387872822835 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (13/2 → 7/1) ⇝ 43/6 | n:0 gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (13/2 → 7/1) ⇝ 15/2 | n:15 gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ (13/2 → 7/1) ⇝ 15/2 | n:28 gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", - "[ (13/2 → 7/1) ⇝ 17/2 | n:7 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (13/2 → 7/1) ⇝ 17/2 | n:9 gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (13/2 → 7/1) ⇝ 17/2 | n:13 gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", - "[ 20/3 → 7/1 | n:22 clip:1 gain:0.4172909084714798 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 20/3 → 7/1 | n:25 clip:1 gain:0.4381966011250106 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ (20/3 → 7/1) ⇝ 22/3 | n:-7 gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", - "[ (41/6 → 7/1) ⇝ 43/6 | n:22 clip:1 gain:0.4172909084714798 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (41/6 → 7/1) ⇝ 43/6 | n:25 clip:1 gain:0.4381966011250106 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ (41/6 → 7/1) ⇝ 15/2 | n:14 gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 13/2 ⇜ (7/1 → 43/6) | n:0 gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 41/6 ⇜ (7/1 → 43/6) | n:22 clip:1 gain:0.4172909084714798 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 41/6 ⇜ (7/1 → 43/6) | n:25 clip:1 gain:0.4381966011250106 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 20/3 ⇜ (7/1 → 22/3) | n:-7 gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", - "[ 7/1 → 22/3 | n:25 clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 7/1 → 22/3 | n:22 clip:1 gain:0.4172909084714798 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 11/2 ⇜ (7/1 → 15/2) | n:21 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ 11/2 ⇜ (7/1 → 15/2) | n:23 gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 11/2 ⇜ (7/1 → 15/2) | n:27 gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", - "[ 13/2 ⇜ (7/1 → 15/2) | n:15 gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 13/2 ⇜ (7/1 → 15/2) | n:28 gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", - "[ 41/6 ⇜ (7/1 → 15/2) | n:14 gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 7/1 → 23/3 | n:7 gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 6/1 ⇜ (7/1 → 8/1) | n:0 gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 6/1 ⇜ (7/1 → 8/1) | n:2 gain:1 clip:1 note:A3 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 6/1 ⇜ (7/1 → 8/1) | n:6 gain:1 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", - "[ 13/2 ⇜ (7/1 → 8/1) ⇝ 17/2 | n:7 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 13/2 ⇜ (7/1 → 8/1) ⇝ 17/2 | n:9 gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 13/2 ⇜ (7/1 → 8/1) ⇝ 17/2 | n:13 gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", - "[ 7/1 → 8/1 | n:7 gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 7/1 → 8/1 | n:22 gain:0.3333333333333333 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (7/1 → 8/1) ⇝ 9/1 | n:14 gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ (7/1 → 8/1) ⇝ 9/1 | n:16 gain:0.3333333333333333 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", - "[ (7/1 → 8/1) ⇝ 9/1 | n:20 gain:0.3333333333333333 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", - "[ 43/6 → 15/2 | n:25 clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 43/6 → 15/2 | n:22 clip:1 gain:0.4172909084714798 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 43/6 → 47/6 | n:0 gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 22/3 → 23/3 | n:22 clip:1 gain:0.4 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 22/3 → 23/3 | n:25 clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 22/3 → 8/1 | n:-7 gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", - "[ 15/2 → 47/6 | n:22 clip:1 gain:0.4 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 15/2 → 47/6 | n:25 clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ (15/2 → 8/1) ⇝ 49/6 | n:14 gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ (15/2 → 8/1) ⇝ 17/2 | n:14 gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ (15/2 → 8/1) ⇝ 17/2 | n:29 gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", - "[ (15/2 → 8/1) ⇝ 19/2 | n:21 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ (15/2 → 8/1) ⇝ 19/2 | n:23 gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (15/2 → 8/1) ⇝ 19/2 | n:27 gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", - "[ 23/3 → 8/1 | n:25 clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 23/3 → 8/1 | n:22 clip:1 gain:0.4 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (23/3 → 8/1) ⇝ 25/3 | n:7 gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (47/6 → 8/1) ⇝ 49/6 | n:25 clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ (47/6 → 8/1) ⇝ 49/6 | n:22 clip:1 gain:0.4 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (47/6 → 8/1) ⇝ 17/2 | n:0 gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 15/2 ⇜ (8/1 → 49/6) | n:14 gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 47/6 ⇜ (8/1 → 49/6) | n:25 clip:1 gain:0.40437047985323893 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 47/6 ⇜ (8/1 → 49/6) | n:22 clip:1 gain:0.4 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 23/3 ⇜ (8/1 → 25/3) | n:7 gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 8/1 → 25/3 | n:22 clip:1 gain:0.4172909084714798 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 8/1 → 25/3 | n:25 clip:1 gain:0.40437047985323893 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 13/2 ⇜ (8/1 → 17/2) | n:7 gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 13/2 ⇜ (8/1 → 17/2) | n:9 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 13/2 ⇜ (8/1 → 17/2) | n:13 gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 15/2 ⇜ (8/1 → 17/2) | n:14 gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 15/2 ⇜ (8/1 → 17/2) | n:29 gain:0.25 clip:1 note:E7 s:piano release:0.1 pan:0.712962962962963 ]", - "[ 47/6 ⇜ (8/1 → 17/2) | n:0 gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 8/1 → 26/3 | n:-7 gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 7/1 ⇜ (8/1 → 9/1) | n:14 gain:0.3333333333333333 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 7/1 ⇜ (8/1 → 9/1) | n:16 gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 7/1 ⇜ (8/1 → 9/1) | n:20 gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ 15/2 ⇜ (8/1 → 9/1) ⇝ 19/2 | n:21 gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 15/2 ⇜ (8/1 → 9/1) ⇝ 19/2 | n:23 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ 15/2 ⇜ (8/1 → 9/1) ⇝ 19/2 | n:27 gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 8/1 → 9/1 | n:8 gain:1 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 8/1 → 9/1 | n:21 gain:0.3333333333333333 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (8/1 → 9/1) ⇝ 10/1 | n:0 gain:1 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ (8/1 → 9/1) ⇝ 10/1 | n:2 gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (8/1 → 9/1) ⇝ 10/1 | n:6 gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 49/6 → 17/2 | n:22 clip:1 gain:0.4172909084714798 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 49/6 → 17/2 | n:25 clip:1 gain:0.40437047985323893 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 49/6 → 53/6 | n:14 gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 25/3 → 26/3 | n:25 clip:1 gain:0.4381966011250105 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 25/3 → 26/3 | n:22 clip:1 gain:0.4172909084714798 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 25/3 → 9/1 | n:7 gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 17/2 → 53/6 | n:25 clip:1 gain:0.4381966011250105 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 17/2 → 53/6 | n:22 clip:1 gain:0.4172909084714798 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ (17/2 → 9/1) ⇝ 55/6 | n:0 gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ (17/2 → 9/1) ⇝ 19/2 | n:15 gain:0.5 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ (17/2 → 9/1) ⇝ 19/2 | n:28 gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (17/2 → 9/1) ⇝ 21/2 | n:7 gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ (17/2 → 9/1) ⇝ 21/2 | n:9 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (17/2 → 9/1) ⇝ 21/2 | n:13 gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 26/3 → 9/1 | n:22 clip:1 gain:0.46617387872822824 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 26/3 → 9/1 | n:25 clip:1 gain:0.4381966011250105 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (26/3 → 9/1) ⇝ 28/3 | n:-7 gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ (53/6 → 9/1) ⇝ 55/6 | n:22 clip:1 gain:0.46617387872822824 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ (53/6 → 9/1) ⇝ 55/6 | n:25 clip:1 gain:0.4381966011250105 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (53/6 → 9/1) ⇝ 19/2 | n:14 gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 17/2 ⇜ (9/1 → 55/6) | n:0 gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 53/6 ⇜ (9/1 → 55/6) | n:22 clip:1 gain:0.46617387872822824 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 53/6 ⇜ (9/1 → 55/6) | n:25 clip:1 gain:0.4381966011250105 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 26/3 ⇜ (9/1 → 28/3) | n:-7 gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 9/1 → 28/3 | n:25 clip:1 gain:0.49999999999999994 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 9/1 → 28/3 | n:22 clip:1 gain:0.46617387872822824 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 15/2 ⇜ (9/1 → 19/2) | n:21 gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 15/2 ⇜ (9/1 → 19/2) | n:23 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ 15/2 ⇜ (9/1 → 19/2) | n:27 gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 17/2 ⇜ (9/1 → 19/2) | n:15 gain:0.5 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", - "[ 17/2 ⇜ (9/1 → 19/2) | n:28 gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 53/6 ⇜ (9/1 → 19/2) | n:14 gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 9/1 → 29/3 | n:7 gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 8/1 ⇜ (9/1 → 10/1) | n:0 gain:1 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 8/1 ⇜ (9/1 → 10/1) | n:2 gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 8/1 ⇜ (9/1 → 10/1) | n:6 gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 17/2 ⇜ (9/1 → 10/1) ⇝ 21/2 | n:7 gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 17/2 ⇜ (9/1 → 10/1) ⇝ 21/2 | n:9 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 17/2 ⇜ (9/1 → 10/1) ⇝ 21/2 | n:13 gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 9/1 → 10/1 | n:7 gain:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 9/1 → 10/1 | n:22 gain:0.3333333333333333 clip:1 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ (9/1 → 10/1) ⇝ 11/1 | n:14 gain:0.3333333333333333 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (9/1 → 10/1) ⇝ 11/1 | n:16 gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ (9/1 → 10/1) ⇝ 11/1 | n:20 gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ 55/6 → 19/2 | n:25 clip:1 gain:0.49999999999999994 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 55/6 → 19/2 | n:22 clip:1 gain:0.46617387872822824 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 55/6 → 59/6 | n:0 gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 28/3 → 29/3 | n:22 clip:1 gain:0.5381966011250106 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 28/3 → 29/3 | n:25 clip:1 gain:0.49999999999999994 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 28/3 → 10/1 | n:-7 gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 19/2 → 59/6 | n:22 clip:1 gain:0.5381966011250106 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ 19/2 → 59/6 | n:25 clip:1 gain:0.49999999999999994 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (19/2 → 10/1) ⇝ 61/6 | n:14 gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (19/2 → 10/1) ⇝ 21/2 | n:14 gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (19/2 → 10/1) ⇝ 21/2 | n:29 gain:0.25 clip:1 note:E7 s:piano release:0.1 pan:0.712962962962963 ]", - "[ (19/2 → 10/1) ⇝ 23/2 | n:21 gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (19/2 → 10/1) ⇝ 23/2 | n:23 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ (19/2 → 10/1) ⇝ 23/2 | n:27 gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 29/3 → 10/1 | n:25 clip:1 gain:0.5790943073464692 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 29/3 → 10/1 | n:22 clip:1 gain:0.5381966011250106 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ (29/3 → 10/1) ⇝ 31/3 | n:7 gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ (59/6 → 10/1) ⇝ 61/6 | n:25 clip:1 gain:0.5790943073464692 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (59/6 → 10/1) ⇝ 61/6 | n:22 clip:1 gain:0.5381966011250106 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", - "[ (59/6 → 10/1) ⇝ 21/2 | n:0 gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 19/2 ⇜ (10/1 → 61/6) | n:14 gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 59/6 ⇜ (10/1 → 61/6) | n:25 clip:1 gain:0.5790943073464692 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 59/6 ⇜ (10/1 → 61/6) | n:22 clip:1 gain:0.5381966011250106 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 29/3 ⇜ (10/1 → 31/3) | n:7 gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 10/1 → 31/3 | n:22 clip:1 gain:0.6209056926535306 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 10/1 → 31/3 | n:25 clip:1 gain:0.5790943073464692 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 17/2 ⇜ (10/1 → 21/2) | n:7 gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 17/2 ⇜ (10/1 → 21/2) | n:9 gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", - "[ 17/2 ⇜ (10/1 → 21/2) | n:13 gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 19/2 ⇜ (10/1 → 21/2) | n:14 gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 19/2 ⇜ (10/1 → 21/2) | n:29 gain:0.25 clip:1 note:A7 s:piano release:0.1 pan:0.7361111111111112 ]", - "[ 59/6 ⇜ (10/1 → 21/2) | n:0 gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 10/1 → 32/3 | n:-7 gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", - "[ 9/1 ⇜ (10/1 → 11/1) | n:14 gain:0.3333333333333333 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 9/1 ⇜ (10/1 → 11/1) | n:16 gain:0.3333333333333333 clip:1 note:B5 s:piano release:0.1 pan:0.6342592592592593 ]", - "[ 9/1 ⇜ (10/1 → 11/1) | n:20 gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ 19/2 ⇜ (10/1 → 11/1) ⇝ 23/2 | n:21 gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 19/2 ⇜ (10/1 → 11/1) ⇝ 23/2 | n:23 gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", - "[ 19/2 ⇜ (10/1 → 11/1) ⇝ 23/2 | n:27 gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", - "[ 10/1 → 11/1 | n:8 gain:1 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 10/1 → 11/1 | n:21 gain:0.3333333333333333 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (10/1 → 11/1) ⇝ 12/1 | n:0 gain:1 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ (10/1 → 11/1) ⇝ 12/1 | n:2 gain:1 clip:1 note:B3 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ (10/1 → 11/1) ⇝ 12/1 | n:6 gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 61/6 → 21/2 | n:22 clip:1 gain:0.6209056926535306 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 61/6 → 21/2 | n:25 clip:1 gain:0.5790943073464692 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 61/6 → 65/6 | n:14 gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 31/3 → 32/3 | n:25 clip:1 gain:0.6618033988749894 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 31/3 → 32/3 | n:22 clip:1 gain:0.6209056926535306 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 31/3 → 11/1 | n:7 gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 21/2 → 65/6 | n:25 clip:1 gain:0.6618033988749894 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 21/2 → 65/6 | n:22 clip:1 gain:0.6209056926535306 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (21/2 → 11/1) ⇝ 67/6 | n:0 gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ (21/2 → 11/1) ⇝ 23/2 | n:15 gain:0.5 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", - "[ (21/2 → 11/1) ⇝ 23/2 | n:28 gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", - "[ (21/2 → 11/1) ⇝ 25/2 | n:7 gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ (21/2 → 11/1) ⇝ 25/2 | n:9 gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", - "[ (21/2 → 11/1) ⇝ 25/2 | n:13 gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 32/3 → 11/1 | n:22 clip:1 gain:0.7 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 32/3 → 11/1 | n:25 clip:1 gain:0.6618033988749894 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (32/3 → 11/1) ⇝ 34/3 | n:-7 gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", - "[ (65/6 → 11/1) ⇝ 67/6 | n:22 clip:1 gain:0.7 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (65/6 → 11/1) ⇝ 67/6 | n:25 clip:1 gain:0.6618033988749894 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (65/6 → 11/1) ⇝ 23/2 | n:14 gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 21/2 ⇜ (11/1 → 67/6) | n:0 gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 65/6 ⇜ (11/1 → 67/6) | n:22 clip:1 gain:0.7 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 65/6 ⇜ (11/1 → 67/6) | n:25 clip:1 gain:0.6618033988749894 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 32/3 ⇜ (11/1 → 34/3) | n:-7 gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", - "[ 11/1 → 34/3 | n:25 clip:1 gain:0.7338261212717717 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 11/1 → 34/3 | n:22 clip:1 gain:0.7 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 19/2 ⇜ (11/1 → 23/2) | n:21 gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 19/2 ⇜ (11/1 → 23/2) | n:23 gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", - "[ 19/2 ⇜ (11/1 → 23/2) | n:27 gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", - "[ 21/2 ⇜ (11/1 → 23/2) | n:15 gain:0.5 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", - "[ 21/2 ⇜ (11/1 → 23/2) | n:28 gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", - "[ 65/6 ⇜ (11/1 → 23/2) | n:14 gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 11/1 → 35/3 | n:7 gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 10/1 ⇜ (11/1 → 12/1) | n:0 gain:1 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 10/1 ⇜ (11/1 → 12/1) | n:2 gain:1 clip:1 note:B3 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 10/1 ⇜ (11/1 → 12/1) | n:6 gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 21/2 ⇜ (11/1 → 12/1) ⇝ 25/2 | n:7 gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 21/2 ⇜ (11/1 → 12/1) ⇝ 25/2 | n:9 gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", - "[ 21/2 ⇜ (11/1 → 12/1) ⇝ 25/2 | n:13 gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 11/1 → 12/1 | n:7 gain:1 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 11/1 → 12/1 | n:22 gain:0.3333333333333333 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (11/1 → 12/1) ⇝ 13/1 | n:14 gain:0.3333333333333333 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ (11/1 → 12/1) ⇝ 13/1 | n:16 gain:0.3333333333333333 clip:1 note:B5 s:piano release:0.1 pan:0.6342592592592593 ]", - "[ (11/1 → 12/1) ⇝ 13/1 | n:20 gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ 67/6 → 23/2 | n:25 clip:1 gain:0.7338261212717717 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 67/6 → 23/2 | n:22 clip:1 gain:0.7 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 67/6 → 71/6 | n:0 gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 34/3 → 35/3 | n:22 clip:1 gain:0.7618033988749894 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 34/3 → 35/3 | n:25 clip:1 gain:0.7338261212717717 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 34/3 → 12/1 | n:-7 gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", - "[ 23/2 → 71/6 | n:22 clip:1 gain:0.7618033988749894 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 23/2 → 71/6 | n:25 clip:1 gain:0.7338261212717717 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (23/2 → 12/1) ⇝ 73/6 | n:14 gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ (23/2 → 12/1) ⇝ 25/2 | n:14 gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ (23/2 → 12/1) ⇝ 25/2 | n:29 gain:0.25 clip:1 note:A7 s:piano release:0.1 pan:0.7361111111111112 ]", - "[ (23/2 → 12/1) ⇝ 27/2 | n:21 gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (23/2 → 12/1) ⇝ 27/2 | n:23 gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", - "[ (23/2 → 12/1) ⇝ 27/2 | n:27 gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", - "[ 35/3 → 12/1 | n:25 clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 35/3 → 12/1 | n:22 clip:1 gain:0.7618033988749894 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (35/3 → 12/1) ⇝ 37/3 | n:7 gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ (71/6 → 12/1) ⇝ 73/6 | n:25 clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (71/6 → 12/1) ⇝ 73/6 | n:22 clip:1 gain:0.7618033988749894 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (71/6 → 12/1) ⇝ 25/2 | n:0 gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 23/2 ⇜ (12/1 → 73/6) | n:14 gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 71/6 ⇜ (12/1 → 73/6) | n:25 clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 71/6 ⇜ (12/1 → 73/6) | n:22 clip:1 gain:0.7618033988749894 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 35/3 ⇜ (12/1 → 37/3) | n:7 gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 12/1 → 37/3 | n:22 clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 12/1 → 37/3 | n:25 clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 21/2 ⇜ (12/1 → 25/2) | n:7 gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 21/2 ⇜ (12/1 → 25/2) | n:9 gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", - "[ 21/2 ⇜ (12/1 → 25/2) | n:13 gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 23/2 ⇜ (12/1 → 25/2) | n:14 gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 23/2 ⇜ (12/1 → 25/2) | n:29 gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ 71/6 ⇜ (12/1 → 25/2) | n:0 gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 12/1 → 38/3 | n:-7 gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", - "[ 11/1 ⇜ (12/1 → 13/1) | n:14 gain:0.3333333333333333 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 11/1 ⇜ (12/1 → 13/1) | n:16 gain:0.3333333333333333 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", - "[ 11/1 ⇜ (12/1 → 13/1) | n:20 gain:0.3333333333333333 clip:1 note:Bb5 s:piano release:0.1 pan:0.6296296296296297 ]", - "[ 23/2 ⇜ (12/1 → 13/1) ⇝ 27/2 | n:21 gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ 23/2 ⇜ (12/1 → 13/1) ⇝ 27/2 | n:23 gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", - "[ 23/2 ⇜ (12/1 → 13/1) ⇝ 27/2 | n:27 gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", - "[ 12/1 → 13/1 | n:8 gain:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 12/1 → 13/1 | n:21 gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ (12/1 → 13/1) ⇝ 14/1 | n:0 gain:1 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ (12/1 → 13/1) ⇝ 14/1 | n:2 gain:1 clip:1 note:Eb3 s:piano release:0.1 pan:0.4861111111111111 ]", - "[ (12/1 → 13/1) ⇝ 14/1 | n:6 gain:1 clip:1 note:Bb3 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 73/6 → 25/2 | n:22 clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 73/6 → 25/2 | n:25 clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 73/6 → 77/6 | n:14 gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 37/3 → 38/3 | n:25 clip:1 gain:0.8 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 37/3 → 38/3 | n:22 clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 37/3 → 13/1 | n:7 gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 25/2 → 77/6 | n:25 clip:1 gain:0.8 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 25/2 → 77/6 | n:22 clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (25/2 → 13/1) ⇝ 79/6 | n:0 gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ (25/2 → 13/1) ⇝ 27/2 | n:15 gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ (25/2 → 13/1) ⇝ 27/2 | n:28 gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ (25/2 → 13/1) ⇝ 29/2 | n:7 gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (25/2 → 13/1) ⇝ 29/2 | n:9 gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", - "[ (25/2 → 13/1) ⇝ 29/2 | n:13 gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 38/3 → 13/1 | n:22 clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 38/3 → 13/1 | n:25 clip:1 gain:0.8 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (38/3 → 13/1) ⇝ 40/3 | n:-7 gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", - "[ (77/6 → 13/1) ⇝ 79/6 | n:22 clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (77/6 → 13/1) ⇝ 79/6 | n:25 clip:1 gain:0.8 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (77/6 → 13/1) ⇝ 27/2 | n:14 gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 25/2 ⇜ (13/1 → 79/6) | n:0 gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 77/6 ⇜ (13/1 → 79/6) | n:22 clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 77/6 ⇜ (13/1 → 79/6) | n:25 clip:1 gain:0.8 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 38/3 ⇜ (13/1 → 40/3) | n:-7 gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", - "[ 13/1 → 40/3 | n:25 clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 13/1 → 40/3 | n:22 clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 23/2 ⇜ (13/1 → 27/2) | n:21 gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ 23/2 ⇜ (13/1 → 27/2) | n:23 gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", - "[ 23/2 ⇜ (13/1 → 27/2) | n:27 gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", - "[ 25/2 ⇜ (13/1 → 27/2) | n:15 gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", - "[ 25/2 ⇜ (13/1 → 27/2) | n:28 gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 77/6 ⇜ (13/1 → 27/2) | n:14 gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ 13/1 → 41/3 | n:7 gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 12/1 ⇜ (13/1 → 14/1) | n:0 gain:1 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 12/1 ⇜ (13/1 → 14/1) | n:2 gain:1 clip:1 note:Eb3 s:piano release:0.1 pan:0.4861111111111111 ]", - "[ 12/1 ⇜ (13/1 → 14/1) | n:6 gain:1 clip:1 note:Bb3 s:piano release:0.1 pan:0.5185185185185186 ]", - "[ 25/2 ⇜ (13/1 → 14/1) ⇝ 29/2 | n:7 gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 25/2 ⇜ (13/1 → 14/1) ⇝ 29/2 | n:9 gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", - "[ 25/2 ⇜ (13/1 → 14/1) ⇝ 29/2 | n:13 gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", - "[ 13/1 → 14/1 | n:7 gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ 13/1 → 14/1 | n:22 gain:0.3333333333333333 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (13/1 → 14/1) ⇝ 15/1 | n:14 gain:0.3333333333333333 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (13/1 → 14/1) ⇝ 15/1 | n:16 gain:0.3333333333333333 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", - "[ (13/1 → 14/1) ⇝ 15/1 | n:20 gain:0.3333333333333333 clip:1 note:Bb5 s:piano release:0.1 pan:0.6296296296296297 ]", - "[ 79/6 → 27/2 | n:25 clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 79/6 → 27/2 | n:22 clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 79/6 → 83/6 | n:0 gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 40/3 → 41/3 | n:22 clip:1 gain:0.7618033988749895 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 40/3 → 41/3 | n:25 clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 40/3 → 14/1 | n:-7 gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", - "[ 27/2 → 83/6 | n:22 clip:1 gain:0.7618033988749895 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ 27/2 → 83/6 | n:25 clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (27/2 → 14/1) ⇝ 85/6 | n:14 gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (27/2 → 14/1) ⇝ 29/2 | n:14 gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", - "[ (27/2 → 14/1) ⇝ 29/2 | n:29 gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", - "[ (27/2 → 14/1) ⇝ 31/2 | n:21 gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", - "[ (27/2 → 14/1) ⇝ 31/2 | n:23 gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", - "[ (27/2 → 14/1) ⇝ 31/2 | n:27 gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", - "[ 41/3 → 14/1 | n:25 clip:1 gain:0.7338261212717718 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 41/3 → 14/1 | n:22 clip:1 gain:0.7618033988749895 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (41/3 → 14/1) ⇝ 43/3 | n:7 gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", - "[ (83/6 → 14/1) ⇝ 85/6 | n:25 clip:1 gain:0.7338261212717718 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (83/6 → 14/1) ⇝ 85/6 | n:22 clip:1 gain:0.7618033988749895 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", - "[ (83/6 → 14/1) ⇝ 29/2 | n:0 gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", - "[ 27/2 ⇜ (14/1 → 85/6) | n:14 gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 83/6 ⇜ (14/1 → 85/6) | n:25 clip:1 gain:0.7338261212717718 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 83/6 ⇜ (14/1 → 85/6) | n:22 clip:1 gain:0.7618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 41/3 ⇜ (14/1 → 43/3) | n:7 gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 14/1 → 43/3 | n:22 clip:1 gain:0.7 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 14/1 → 43/3 | n:25 clip:1 gain:0.7338261212717718 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 25/2 ⇜ (14/1 → 29/2) | n:7 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 25/2 ⇜ (14/1 → 29/2) | n:9 gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 25/2 ⇜ (14/1 → 29/2) | n:13 gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", - "[ 27/2 ⇜ (14/1 → 29/2) | n:14 gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 27/2 ⇜ (14/1 → 29/2) | n:29 gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", - "[ 83/6 ⇜ (14/1 → 29/2) | n:0 gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 14/1 → 44/3 | n:-7 gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", - "[ 13/1 ⇜ (14/1 → 15/1) | n:14 gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 13/1 ⇜ (14/1 → 15/1) | n:16 gain:0.3333333333333333 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", - "[ 13/1 ⇜ (14/1 → 15/1) | n:20 gain:0.3333333333333333 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", - "[ 27/2 ⇜ (14/1 → 15/1) ⇝ 31/2 | n:21 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ 27/2 ⇜ (14/1 → 15/1) ⇝ 31/2 | n:23 gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 27/2 ⇜ (14/1 → 15/1) ⇝ 31/2 | n:27 gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", - "[ 14/1 → 15/1 | n:8 gain:1 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", - "[ 14/1 → 15/1 | n:21 gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ (14/1 → 15/1) ⇝ 16/1 | n:0 gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (14/1 → 15/1) ⇝ 16/1 | n:2 gain:1 clip:1 note:A3 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ (14/1 → 15/1) ⇝ 16/1 | n:6 gain:1 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", - "[ 85/6 → 29/2 | n:22 clip:1 gain:0.7 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 85/6 → 29/2 | n:25 clip:1 gain:0.7338261212717718 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 85/6 → 89/6 | n:14 gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 43/3 → 44/3 | n:25 clip:1 gain:0.6618033988749896 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 43/3 → 44/3 | n:22 clip:1 gain:0.7 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 43/3 → 15/1 | n:7 gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 29/2 → 89/6 | n:25 clip:1 gain:0.6618033988749896 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 29/2 → 89/6 | n:22 clip:1 gain:0.7 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (29/2 → 15/1) ⇝ 91/6 | n:0 gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ (29/2 → 15/1) ⇝ 31/2 | n:15 gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ (29/2 → 15/1) ⇝ 31/2 | n:28 gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", - "[ (29/2 → 15/1) ⇝ 33/2 | n:7 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (29/2 → 15/1) ⇝ 33/2 | n:9 gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ (29/2 → 15/1) ⇝ 33/2 | n:13 gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", - "[ 44/3 → 15/1 | n:22 clip:1 gain:0.6209056926535306 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 44/3 → 15/1 | n:25 clip:1 gain:0.6618033988749896 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ (44/3 → 15/1) ⇝ 46/3 | n:-7 gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", - "[ (89/6 → 15/1) ⇝ 91/6 | n:22 clip:1 gain:0.6209056926535306 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (89/6 → 15/1) ⇝ 91/6 | n:25 clip:1 gain:0.6618033988749896 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ (89/6 → 15/1) ⇝ 31/2 | n:14 gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 29/2 ⇜ (15/1 → 91/6) | n:0 gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 89/6 ⇜ (15/1 → 91/6) | n:22 clip:1 gain:0.6209056926535306 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 89/6 ⇜ (15/1 → 91/6) | n:25 clip:1 gain:0.6618033988749896 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 44/3 ⇜ (15/1 → 46/3) | n:-7 gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", - "[ 15/1 → 46/3 | n:25 clip:1 gain:0.5790943073464696 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 15/1 → 46/3 | n:22 clip:1 gain:0.6209056926535306 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 27/2 ⇜ (15/1 → 31/2) | n:21 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ 27/2 ⇜ (15/1 → 31/2) | n:23 gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ 27/2 ⇜ (15/1 → 31/2) | n:27 gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", - "[ 29/2 ⇜ (15/1 → 31/2) | n:15 gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", - "[ 29/2 ⇜ (15/1 → 31/2) | n:28 gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", - "[ 89/6 ⇜ (15/1 → 31/2) | n:14 gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ 15/1 → 47/3 | n:7 gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 14/1 ⇜ (15/1 → 16/1) | n:0 gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 14/1 ⇜ (15/1 → 16/1) | n:2 gain:1 clip:1 note:A3 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 14/1 ⇜ (15/1 → 16/1) | n:6 gain:1 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", - "[ 29/2 ⇜ (15/1 → 16/1) ⇝ 33/2 | n:7 gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 29/2 ⇜ (15/1 → 16/1) ⇝ 33/2 | n:9 gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", - "[ 29/2 ⇜ (15/1 → 16/1) ⇝ 33/2 | n:13 gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", - "[ 15/1 → 16/1 | n:7 gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ 15/1 → 16/1 | n:22 gain:0.3333333333333333 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (15/1 → 16/1) ⇝ 17/1 | n:14 gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ (15/1 → 16/1) ⇝ 17/1 | n:16 gain:0.3333333333333333 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", - "[ (15/1 → 16/1) ⇝ 17/1 | n:20 gain:0.3333333333333333 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", - "[ 91/6 → 31/2 | n:25 clip:1 gain:0.5790943073464696 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 91/6 → 31/2 | n:22 clip:1 gain:0.6209056926535306 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 91/6 → 95/6 | n:0 gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", - "[ 46/3 → 47/3 | n:22 clip:1 gain:0.5381966011250107 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 46/3 → 47/3 | n:25 clip:1 gain:0.5790943073464696 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 46/3 → 16/1 | n:-7 gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", - "[ 31/2 → 95/6 | n:22 clip:1 gain:0.5381966011250107 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ 31/2 → 95/6 | n:25 clip:1 gain:0.5790943073464696 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ (31/2 → 16/1) ⇝ 97/6 | n:14 gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ (31/2 → 16/1) ⇝ 33/2 | n:14 gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", - "[ (31/2 → 16/1) ⇝ 33/2 | n:29 gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", - "[ (31/2 → 16/1) ⇝ 35/2 | n:21 gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", - "[ (31/2 → 16/1) ⇝ 35/2 | n:23 gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", - "[ (31/2 → 16/1) ⇝ 35/2 | n:27 gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", - "[ 47/3 → 16/1 | n:25 clip:1 gain:0.5000000000000002 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ 47/3 → 16/1 | n:22 clip:1 gain:0.5381966011250107 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (47/3 → 16/1) ⇝ 49/3 | n:7 gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", - "[ (95/6 → 16/1) ⇝ 97/6 | n:25 clip:1 gain:0.5000000000000002 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", - "[ (95/6 → 16/1) ⇝ 97/6 | n:22 clip:1 gain:0.5381966011250107 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", - "[ (95/6 → 16/1) ⇝ 33/2 | n:0 gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ -1/2 ⇜ (0/1 → 1/6) | gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ -1/6 ⇜ (0/1 → 1/6) | clip:1 gain:0.5790943073464694 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ -1/6 ⇜ (0/1 → 1/6) | clip:1 gain:0.5381966011250106 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ -1/3 ⇜ (0/1 → 1/3) | gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 0/1 → 1/3 | clip:1 gain:0.6209056926535308 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 0/1 → 1/3 | clip:1 gain:0.5790943073464694 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ -3/2 ⇜ (0/1 → 1/2) | gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ -3/2 ⇜ (0/1 → 1/2) | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ -3/2 ⇜ (0/1 → 1/2) | gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ -1/2 ⇜ (0/1 → 1/2) | gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ -1/2 ⇜ (0/1 → 1/2) | gain:0.25 clip:1 note:E7 s:piano release:0.1 pan:0.712962962962963 ]", + "[ -1/6 ⇜ (0/1 → 1/2) | gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 0/1 → 2/3 | gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ -1/1 ⇜ (0/1 → 1/1) | gain:0.3333333333333333 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ -1/1 ⇜ (0/1 → 1/1) | gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ -1/1 ⇜ (0/1 → 1/1) | gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ -1/2 ⇜ (0/1 → 1/1) ⇝ 3/2 | gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ -1/2 ⇜ (0/1 → 1/1) ⇝ 3/2 | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ -1/2 ⇜ (0/1 → 1/1) ⇝ 3/2 | gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 0/1 → 1/1 | gain:1 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 0/1 → 1/1 | gain:0.3333333333333333 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (0/1 → 1/1) ⇝ 2/1 | gain:1 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ (0/1 → 1/1) ⇝ 2/1 | gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (0/1 → 1/1) ⇝ 2/1 | gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 1/6 → 1/2 | clip:1 gain:0.6209056926535308 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 1/6 → 1/2 | clip:1 gain:0.5790943073464694 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 1/6 → 5/6 | gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 1/3 → 2/3 | clip:1 gain:0.6618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 1/3 → 2/3 | clip:1 gain:0.6209056926535308 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 1/3 → 1/1 | gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 1/2 → 5/6 | clip:1 gain:0.6618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 1/2 → 5/6 | clip:1 gain:0.6209056926535308 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ (1/2 → 1/1) ⇝ 7/6 | gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ (1/2 → 1/1) ⇝ 3/2 | gain:0.5 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (1/2 → 1/1) ⇝ 3/2 | gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (1/2 → 1/1) ⇝ 5/2 | gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ (1/2 → 1/1) ⇝ 5/2 | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (1/2 → 1/1) ⇝ 5/2 | gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 2/3 → 1/1 | clip:1 gain:0.7000000000000001 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 2/3 → 1/1 | clip:1 gain:0.6618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (2/3 → 1/1) ⇝ 4/3 | gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ (5/6 → 1/1) ⇝ 7/6 | clip:1 gain:0.7000000000000001 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ (5/6 → 1/1) ⇝ 7/6 | clip:1 gain:0.6618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (5/6 → 1/1) ⇝ 3/2 | gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 1/2 ⇜ (1/1 → 7/6) | gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 5/6 ⇜ (1/1 → 7/6) | clip:1 gain:0.7000000000000001 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 5/6 ⇜ (1/1 → 7/6) | clip:1 gain:0.6618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 2/3 ⇜ (1/1 → 4/3) | gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 1/1 → 4/3 | clip:1 gain:0.7338261212717717 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 1/1 → 4/3 | clip:1 gain:0.7000000000000001 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ -1/2 ⇜ (1/1 → 3/2) | gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ -1/2 ⇜ (1/1 → 3/2) | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ -1/2 ⇜ (1/1 → 3/2) | gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 1/2 ⇜ (1/1 → 3/2) | gain:0.5 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 1/2 ⇜ (1/1 → 3/2) | gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 5/6 ⇜ (1/1 → 3/2) | gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 1/1 → 5/3 | gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 0/1 ⇜ (1/1 → 2/1) | gain:1 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 0/1 ⇜ (1/1 → 2/1) | gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 0/1 ⇜ (1/1 → 2/1) | gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 1/2 ⇜ (1/1 → 2/1) ⇝ 5/2 | gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 1/2 ⇜ (1/1 → 2/1) ⇝ 5/2 | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 1/2 ⇜ (1/1 → 2/1) ⇝ 5/2 | gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 1/1 → 2/1 | gain:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 1/1 → 2/1 | gain:0.3333333333333333 clip:1 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ (1/1 → 2/1) ⇝ 3/1 | gain:0.3333333333333333 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (1/1 → 2/1) ⇝ 3/1 | gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ (1/1 → 2/1) ⇝ 3/1 | gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ 7/6 → 3/2 | clip:1 gain:0.7338261212717717 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 7/6 → 3/2 | clip:1 gain:0.7000000000000001 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 7/6 → 11/6 | gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 4/3 → 5/3 | clip:1 gain:0.7618033988749895 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 4/3 → 5/3 | clip:1 gain:0.7338261212717717 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 4/3 → 2/1 | gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 3/2 → 11/6 | clip:1 gain:0.7618033988749895 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 3/2 → 11/6 | clip:1 gain:0.7338261212717717 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (3/2 → 2/1) ⇝ 13/6 | gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (3/2 → 2/1) ⇝ 5/2 | gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (3/2 → 2/1) ⇝ 5/2 | gain:0.25 clip:1 note:E7 s:piano release:0.1 pan:0.712962962962963 ]", + "[ (3/2 → 2/1) ⇝ 7/2 | gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (3/2 → 2/1) ⇝ 7/2 | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ (3/2 → 2/1) ⇝ 7/2 | gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 5/3 → 2/1 | clip:1 gain:0.7827090915285202 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 5/3 → 2/1 | clip:1 gain:0.7618033988749895 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ (5/3 → 2/1) ⇝ 7/3 | gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ (11/6 → 2/1) ⇝ 13/6 | clip:1 gain:0.7827090915285202 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (11/6 → 2/1) ⇝ 13/6 | clip:1 gain:0.7618033988749895 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ (11/6 → 2/1) ⇝ 5/2 | gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 3/2 ⇜ (2/1 → 13/6) | gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 11/6 ⇜ (2/1 → 13/6) | clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 11/6 ⇜ (2/1 → 13/6) | clip:1 gain:0.7618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 5/3 ⇜ (2/1 → 7/3) | gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 2/1 → 7/3 | clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 2/1 → 7/3 | clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 1/2 ⇜ (2/1 → 5/2) | gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 1/2 ⇜ (2/1 → 5/2) | gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", + "[ 1/2 ⇜ (2/1 → 5/2) | gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 3/2 ⇜ (2/1 → 5/2) | gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 3/2 ⇜ (2/1 → 5/2) | gain:0.25 clip:1 note:A7 s:piano release:0.1 pan:0.7361111111111112 ]", + "[ 11/6 ⇜ (2/1 → 5/2) | gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 2/1 → 8/3 | gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", + "[ 1/1 ⇜ (2/1 → 3/1) | gain:0.3333333333333333 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 1/1 ⇜ (2/1 → 3/1) | gain:0.3333333333333333 clip:1 note:B5 s:piano release:0.1 pan:0.6342592592592593 ]", + "[ 1/1 ⇜ (2/1 → 3/1) | gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ 3/2 ⇜ (2/1 → 3/1) ⇝ 7/2 | gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 3/2 ⇜ (2/1 → 3/1) ⇝ 7/2 | gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", + "[ 3/2 ⇜ (2/1 → 3/1) ⇝ 7/2 | gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", + "[ 2/1 → 3/1 | gain:1 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 2/1 → 3/1 | gain:0.3333333333333333 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (2/1 → 3/1) ⇝ 4/1 | gain:1 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ (2/1 → 3/1) ⇝ 4/1 | gain:1 clip:1 note:B3 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ (2/1 → 3/1) ⇝ 4/1 | gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 13/6 → 5/2 | clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 13/6 → 5/2 | clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 13/6 → 17/6 | gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 7/3 → 8/3 | clip:1 gain:0.8 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 7/3 → 8/3 | clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 7/3 → 3/1 | gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 5/2 → 17/6 | clip:1 gain:0.8 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 5/2 → 17/6 | clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (5/2 → 3/1) ⇝ 19/6 | gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ (5/2 → 3/1) ⇝ 7/2 | gain:0.5 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", + "[ (5/2 → 3/1) ⇝ 7/2 | gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", + "[ (5/2 → 3/1) ⇝ 9/2 | gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ (5/2 → 3/1) ⇝ 9/2 | gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", + "[ (5/2 → 3/1) ⇝ 9/2 | gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 8/3 → 3/1 | clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 8/3 → 3/1 | clip:1 gain:0.8 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (8/3 → 3/1) ⇝ 10/3 | gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", + "[ (17/6 → 3/1) ⇝ 19/6 | clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (17/6 → 3/1) ⇝ 19/6 | clip:1 gain:0.8 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (17/6 → 3/1) ⇝ 7/2 | gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 5/2 ⇜ (3/1 → 19/6) | gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 17/6 ⇜ (3/1 → 19/6) | clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 17/6 ⇜ (3/1 → 19/6) | clip:1 gain:0.8 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 8/3 ⇜ (3/1 → 10/3) | gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", + "[ 3/1 → 10/3 | clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 3/1 → 10/3 | clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 3/2 ⇜ (3/1 → 7/2) | gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 3/2 ⇜ (3/1 → 7/2) | gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", + "[ 3/2 ⇜ (3/1 → 7/2) | gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", + "[ 5/2 ⇜ (3/1 → 7/2) | gain:0.5 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", + "[ 5/2 ⇜ (3/1 → 7/2) | gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", + "[ 17/6 ⇜ (3/1 → 7/2) | gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 3/1 → 11/3 | gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 2/1 ⇜ (3/1 → 4/1) | gain:1 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 2/1 ⇜ (3/1 → 4/1) | gain:1 clip:1 note:B3 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 2/1 ⇜ (3/1 → 4/1) | gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 5/2 ⇜ (3/1 → 4/1) ⇝ 9/2 | gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 5/2 ⇜ (3/1 → 4/1) ⇝ 9/2 | gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", + "[ 5/2 ⇜ (3/1 → 4/1) ⇝ 9/2 | gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 3/1 → 4/1 | gain:1 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 3/1 → 4/1 | gain:0.3333333333333333 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (3/1 → 4/1) ⇝ 5/1 | gain:0.3333333333333333 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ (3/1 → 4/1) ⇝ 5/1 | gain:0.3333333333333333 clip:1 note:B5 s:piano release:0.1 pan:0.6342592592592593 ]", + "[ (3/1 → 4/1) ⇝ 5/1 | gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ 19/6 → 7/2 | clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 19/6 → 7/2 | clip:1 gain:0.7956295201467611 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 19/6 → 23/6 | gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 10/3 → 11/3 | clip:1 gain:0.7618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 10/3 → 11/3 | clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 10/3 → 4/1 | gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", + "[ 7/2 → 23/6 | clip:1 gain:0.7618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 7/2 → 23/6 | clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (7/2 → 4/1) ⇝ 25/6 | gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ (7/2 → 4/1) ⇝ 9/2 | gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ (7/2 → 4/1) ⇝ 9/2 | gain:0.25 clip:1 note:A7 s:piano release:0.1 pan:0.7361111111111112 ]", + "[ (7/2 → 4/1) ⇝ 11/2 | gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (7/2 → 4/1) ⇝ 11/2 | gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", + "[ (7/2 → 4/1) ⇝ 11/2 | gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", + "[ 11/3 → 4/1 | clip:1 gain:0.7338261212717716 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 11/3 → 4/1 | clip:1 gain:0.7618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (11/3 → 4/1) ⇝ 13/3 | gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ (23/6 → 4/1) ⇝ 25/6 | clip:1 gain:0.7338261212717716 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (23/6 → 4/1) ⇝ 25/6 | clip:1 gain:0.7618033988749895 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (23/6 → 4/1) ⇝ 9/2 | gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 7/2 ⇜ (4/1 → 25/6) | gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 23/6 ⇜ (4/1 → 25/6) | clip:1 gain:0.7338261212717716 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 23/6 ⇜ (4/1 → 25/6) | clip:1 gain:0.7618033988749895 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 11/3 ⇜ (4/1 → 13/3) | gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 4/1 → 13/3 | clip:1 gain:0.7000000000000001 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 4/1 → 13/3 | clip:1 gain:0.7338261212717716 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 5/2 ⇜ (4/1 → 9/2) | gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 5/2 ⇜ (4/1 → 9/2) | gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", + "[ 5/2 ⇜ (4/1 → 9/2) | gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 7/2 ⇜ (4/1 → 9/2) | gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 7/2 ⇜ (4/1 → 9/2) | gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 23/6 ⇜ (4/1 → 9/2) | gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ 4/1 → 14/3 | gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", + "[ 3/1 ⇜ (4/1 → 5/1) | gain:0.3333333333333333 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 3/1 ⇜ (4/1 → 5/1) | gain:0.3333333333333333 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", + "[ 3/1 ⇜ (4/1 → 5/1) | gain:0.3333333333333333 clip:1 note:Bb5 s:piano release:0.1 pan:0.6296296296296297 ]", + "[ 7/2 ⇜ (4/1 → 5/1) ⇝ 11/2 | gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ 7/2 ⇜ (4/1 → 5/1) ⇝ 11/2 | gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", + "[ 7/2 ⇜ (4/1 → 5/1) ⇝ 11/2 | gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", + "[ 4/1 → 5/1 | gain:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 4/1 → 5/1 | gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ (4/1 → 5/1) ⇝ 6/1 | gain:1 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ (4/1 → 5/1) ⇝ 6/1 | gain:1 clip:1 note:Eb3 s:piano release:0.1 pan:0.4861111111111111 ]", + "[ (4/1 → 5/1) ⇝ 6/1 | gain:1 clip:1 note:Bb3 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 25/6 → 9/2 | clip:1 gain:0.7000000000000001 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 25/6 → 9/2 | clip:1 gain:0.7338261212717716 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 25/6 → 29/6 | gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 13/3 → 14/3 | clip:1 gain:0.6618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 13/3 → 14/3 | clip:1 gain:0.7000000000000001 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 13/3 → 5/1 | gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 9/2 → 29/6 | clip:1 gain:0.6618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 9/2 → 29/6 | clip:1 gain:0.7000000000000001 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (9/2 → 5/1) ⇝ 31/6 | gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ (9/2 → 5/1) ⇝ 11/2 | gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (9/2 → 5/1) ⇝ 11/2 | gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ (9/2 → 5/1) ⇝ 13/2 | gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (9/2 → 5/1) ⇝ 13/2 | gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", + "[ (9/2 → 5/1) ⇝ 13/2 | gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 14/3 → 5/1 | clip:1 gain:0.6209056926535308 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 14/3 → 5/1 | clip:1 gain:0.6618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (14/3 → 5/1) ⇝ 16/3 | gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", + "[ (29/6 → 5/1) ⇝ 31/6 | clip:1 gain:0.6209056926535308 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (29/6 → 5/1) ⇝ 31/6 | clip:1 gain:0.6618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (29/6 → 5/1) ⇝ 11/2 | gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 9/2 ⇜ (5/1 → 31/6) | gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ 29/6 ⇜ (5/1 → 31/6) | clip:1 gain:0.6209056926535308 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 29/6 ⇜ (5/1 → 31/6) | clip:1 gain:0.6618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 14/3 ⇜ (5/1 → 16/3) | gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", + "[ 5/1 → 16/3 | clip:1 gain:0.5790943073464694 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 5/1 → 16/3 | clip:1 gain:0.6209056926535308 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 7/2 ⇜ (5/1 → 11/2) | gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ 7/2 ⇜ (5/1 → 11/2) | gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", + "[ 7/2 ⇜ (5/1 → 11/2) | gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", + "[ 9/2 ⇜ (5/1 → 11/2) | gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 9/2 ⇜ (5/1 → 11/2) | gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 29/6 ⇜ (5/1 → 11/2) | gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 5/1 → 17/3 | gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 4/1 ⇜ (5/1 → 6/1) | gain:1 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ 4/1 ⇜ (5/1 → 6/1) | gain:1 clip:1 note:Eb3 s:piano release:0.1 pan:0.4861111111111111 ]", + "[ 4/1 ⇜ (5/1 → 6/1) | gain:1 clip:1 note:Bb3 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 9/2 ⇜ (5/1 → 6/1) ⇝ 13/2 | gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 9/2 ⇜ (5/1 → 6/1) ⇝ 13/2 | gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", + "[ 9/2 ⇜ (5/1 → 6/1) ⇝ 13/2 | gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 5/1 → 6/1 | gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 5/1 → 6/1 | gain:0.3333333333333333 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (5/1 → 6/1) ⇝ 7/1 | gain:0.3333333333333333 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (5/1 → 6/1) ⇝ 7/1 | gain:0.3333333333333333 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", + "[ (5/1 → 6/1) ⇝ 7/1 | gain:0.3333333333333333 clip:1 note:Bb5 s:piano release:0.1 pan:0.6296296296296297 ]", + "[ 31/6 → 11/2 | clip:1 gain:0.5790943073464694 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 31/6 → 11/2 | clip:1 gain:0.6209056926535308 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 31/6 → 35/6 | gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ 16/3 → 17/3 | clip:1 gain:0.5381966011250106 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 16/3 → 17/3 | clip:1 gain:0.5790943073464694 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 16/3 → 6/1 | gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", + "[ 11/2 → 35/6 | clip:1 gain:0.5381966011250106 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 11/2 → 35/6 | clip:1 gain:0.5790943073464694 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (11/2 → 6/1) ⇝ 37/6 | gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (11/2 → 6/1) ⇝ 13/2 | gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (11/2 → 6/1) ⇝ 13/2 | gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (11/2 → 6/1) ⇝ 15/2 | gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ (11/2 → 6/1) ⇝ 15/2 | gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", + "[ (11/2 → 6/1) ⇝ 15/2 | gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", + "[ 17/3 → 6/1 | clip:1 gain:0.5 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 17/3 → 6/1 | clip:1 gain:0.5381966011250106 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (17/3 → 6/1) ⇝ 19/3 | gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (35/6 → 6/1) ⇝ 37/6 | clip:1 gain:0.5 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (35/6 → 6/1) ⇝ 37/6 | clip:1 gain:0.5381966011250106 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (35/6 → 6/1) ⇝ 13/2 | gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ 11/2 ⇜ (6/1 → 37/6) | gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 35/6 ⇜ (6/1 → 37/6) | clip:1 gain:0.5 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 35/6 ⇜ (6/1 → 37/6) | clip:1 gain:0.5381966011250106 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 17/3 ⇜ (6/1 → 19/3) | gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 6/1 → 19/3 | clip:1 gain:0.46617387872822835 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 6/1 → 19/3 | clip:1 gain:0.5 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 9/2 ⇜ (6/1 → 13/2) | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 9/2 ⇜ (6/1 → 13/2) | gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 9/2 ⇜ (6/1 → 13/2) | gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", + "[ 11/2 ⇜ (6/1 → 13/2) | gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 11/2 ⇜ (6/1 → 13/2) | gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", + "[ 35/6 ⇜ (6/1 → 13/2) | gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 6/1 → 20/3 | gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", + "[ 5/1 ⇜ (6/1 → 7/1) | gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 5/1 ⇜ (6/1 → 7/1) | gain:0.3333333333333333 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", + "[ 5/1 ⇜ (6/1 → 7/1) | gain:0.3333333333333333 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", + "[ 11/2 ⇜ (6/1 → 7/1) ⇝ 15/2 | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ 11/2 ⇜ (6/1 → 7/1) ⇝ 15/2 | gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 11/2 ⇜ (6/1 → 7/1) ⇝ 15/2 | gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", + "[ 6/1 → 7/1 | gain:1 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 6/1 → 7/1 | gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ (6/1 → 7/1) ⇝ 8/1 | gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (6/1 → 7/1) ⇝ 8/1 | gain:1 clip:1 note:A3 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ (6/1 → 7/1) ⇝ 8/1 | gain:1 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", + "[ 37/6 → 13/2 | clip:1 gain:0.46617387872822835 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 37/6 → 13/2 | clip:1 gain:0.5 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 37/6 → 41/6 | gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 19/3 → 20/3 | clip:1 gain:0.4381966011250106 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 19/3 → 20/3 | clip:1 gain:0.46617387872822835 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 19/3 → 7/1 | gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 13/2 → 41/6 | clip:1 gain:0.4381966011250106 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 13/2 → 41/6 | clip:1 gain:0.46617387872822835 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (13/2 → 7/1) ⇝ 43/6 | gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (13/2 → 7/1) ⇝ 15/2 | gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ (13/2 → 7/1) ⇝ 15/2 | gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", + "[ (13/2 → 7/1) ⇝ 17/2 | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (13/2 → 7/1) ⇝ 17/2 | gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (13/2 → 7/1) ⇝ 17/2 | gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", + "[ 20/3 → 7/1 | clip:1 gain:0.4172909084714798 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 20/3 → 7/1 | clip:1 gain:0.4381966011250106 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ (20/3 → 7/1) ⇝ 22/3 | gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", + "[ (41/6 → 7/1) ⇝ 43/6 | clip:1 gain:0.4172909084714798 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (41/6 → 7/1) ⇝ 43/6 | clip:1 gain:0.4381966011250106 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ (41/6 → 7/1) ⇝ 15/2 | gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 13/2 ⇜ (7/1 → 43/6) | gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 41/6 ⇜ (7/1 → 43/6) | clip:1 gain:0.4172909084714798 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 41/6 ⇜ (7/1 → 43/6) | clip:1 gain:0.4381966011250106 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 20/3 ⇜ (7/1 → 22/3) | gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", + "[ 7/1 → 22/3 | clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 7/1 → 22/3 | clip:1 gain:0.4172909084714798 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 11/2 ⇜ (7/1 → 15/2) | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ 11/2 ⇜ (7/1 → 15/2) | gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 11/2 ⇜ (7/1 → 15/2) | gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", + "[ 13/2 ⇜ (7/1 → 15/2) | gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 13/2 ⇜ (7/1 → 15/2) | gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", + "[ 41/6 ⇜ (7/1 → 15/2) | gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 7/1 → 23/3 | gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 6/1 ⇜ (7/1 → 8/1) | gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 6/1 ⇜ (7/1 → 8/1) | gain:1 clip:1 note:A3 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 6/1 ⇜ (7/1 → 8/1) | gain:1 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", + "[ 13/2 ⇜ (7/1 → 8/1) ⇝ 17/2 | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 13/2 ⇜ (7/1 → 8/1) ⇝ 17/2 | gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 13/2 ⇜ (7/1 → 8/1) ⇝ 17/2 | gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", + "[ 7/1 → 8/1 | gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 7/1 → 8/1 | gain:0.3333333333333333 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (7/1 → 8/1) ⇝ 9/1 | gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ (7/1 → 8/1) ⇝ 9/1 | gain:0.3333333333333333 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", + "[ (7/1 → 8/1) ⇝ 9/1 | gain:0.3333333333333333 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", + "[ 43/6 → 15/2 | clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 43/6 → 15/2 | clip:1 gain:0.4172909084714798 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 43/6 → 47/6 | gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 22/3 → 23/3 | clip:1 gain:0.4 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 22/3 → 23/3 | clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 22/3 → 8/1 | gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", + "[ 15/2 → 47/6 | clip:1 gain:0.4 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 15/2 → 47/6 | clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ (15/2 → 8/1) ⇝ 49/6 | gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ (15/2 → 8/1) ⇝ 17/2 | gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ (15/2 → 8/1) ⇝ 17/2 | gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", + "[ (15/2 → 8/1) ⇝ 19/2 | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ (15/2 → 8/1) ⇝ 19/2 | gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (15/2 → 8/1) ⇝ 19/2 | gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", + "[ 23/3 → 8/1 | clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 23/3 → 8/1 | clip:1 gain:0.4 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (23/3 → 8/1) ⇝ 25/3 | gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (47/6 → 8/1) ⇝ 49/6 | clip:1 gain:0.40437047985323893 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ (47/6 → 8/1) ⇝ 49/6 | clip:1 gain:0.4 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (47/6 → 8/1) ⇝ 17/2 | gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 15/2 ⇜ (8/1 → 49/6) | gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 47/6 ⇜ (8/1 → 49/6) | clip:1 gain:0.40437047985323893 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 47/6 ⇜ (8/1 → 49/6) | clip:1 gain:0.4 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 23/3 ⇜ (8/1 → 25/3) | gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 8/1 → 25/3 | clip:1 gain:0.4172909084714798 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 8/1 → 25/3 | clip:1 gain:0.40437047985323893 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 13/2 ⇜ (8/1 → 17/2) | gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 13/2 ⇜ (8/1 → 17/2) | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 13/2 ⇜ (8/1 → 17/2) | gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 15/2 ⇜ (8/1 → 17/2) | gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 15/2 ⇜ (8/1 → 17/2) | gain:0.25 clip:1 note:E7 s:piano release:0.1 pan:0.712962962962963 ]", + "[ 47/6 ⇜ (8/1 → 17/2) | gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 8/1 → 26/3 | gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 7/1 ⇜ (8/1 → 9/1) | gain:0.3333333333333333 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 7/1 ⇜ (8/1 → 9/1) | gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 7/1 ⇜ (8/1 → 9/1) | gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ 15/2 ⇜ (8/1 → 9/1) ⇝ 19/2 | gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 15/2 ⇜ (8/1 → 9/1) ⇝ 19/2 | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ 15/2 ⇜ (8/1 → 9/1) ⇝ 19/2 | gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 8/1 → 9/1 | gain:1 clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 8/1 → 9/1 | gain:0.3333333333333333 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (8/1 → 9/1) ⇝ 10/1 | gain:1 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ (8/1 → 9/1) ⇝ 10/1 | gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (8/1 → 9/1) ⇝ 10/1 | gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 49/6 → 17/2 | clip:1 gain:0.4172909084714798 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 49/6 → 17/2 | clip:1 gain:0.40437047985323893 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 49/6 → 53/6 | gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 25/3 → 26/3 | clip:1 gain:0.4381966011250105 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 25/3 → 26/3 | clip:1 gain:0.4172909084714798 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 25/3 → 9/1 | gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 17/2 → 53/6 | clip:1 gain:0.4381966011250105 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 17/2 → 53/6 | clip:1 gain:0.4172909084714798 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ (17/2 → 9/1) ⇝ 55/6 | gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ (17/2 → 9/1) ⇝ 19/2 | gain:0.5 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ (17/2 → 9/1) ⇝ 19/2 | gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (17/2 → 9/1) ⇝ 21/2 | gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ (17/2 → 9/1) ⇝ 21/2 | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (17/2 → 9/1) ⇝ 21/2 | gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 26/3 → 9/1 | clip:1 gain:0.46617387872822824 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 26/3 → 9/1 | clip:1 gain:0.4381966011250105 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (26/3 → 9/1) ⇝ 28/3 | gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ (53/6 → 9/1) ⇝ 55/6 | clip:1 gain:0.46617387872822824 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ (53/6 → 9/1) ⇝ 55/6 | clip:1 gain:0.4381966011250105 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (53/6 → 9/1) ⇝ 19/2 | gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 17/2 ⇜ (9/1 → 55/6) | gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 53/6 ⇜ (9/1 → 55/6) | clip:1 gain:0.46617387872822824 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 53/6 ⇜ (9/1 → 55/6) | clip:1 gain:0.4381966011250105 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 26/3 ⇜ (9/1 → 28/3) | gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 9/1 → 28/3 | clip:1 gain:0.49999999999999994 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 9/1 → 28/3 | clip:1 gain:0.46617387872822824 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 15/2 ⇜ (9/1 → 19/2) | gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 15/2 ⇜ (9/1 → 19/2) | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ 15/2 ⇜ (9/1 → 19/2) | gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 17/2 ⇜ (9/1 → 19/2) | gain:0.5 clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]", + "[ 17/2 ⇜ (9/1 → 19/2) | gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 53/6 ⇜ (9/1 → 19/2) | gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 9/1 → 29/3 | gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 8/1 ⇜ (9/1 → 10/1) | gain:1 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 8/1 ⇜ (9/1 → 10/1) | gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 8/1 ⇜ (9/1 → 10/1) | gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 17/2 ⇜ (9/1 → 10/1) ⇝ 21/2 | gain:0.5 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 17/2 ⇜ (9/1 → 10/1) ⇝ 21/2 | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 17/2 ⇜ (9/1 → 10/1) ⇝ 21/2 | gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 9/1 → 10/1 | gain:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 9/1 → 10/1 | gain:0.3333333333333333 clip:1 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ (9/1 → 10/1) ⇝ 11/1 | gain:0.3333333333333333 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (9/1 → 10/1) ⇝ 11/1 | gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ (9/1 → 10/1) ⇝ 11/1 | gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ 55/6 → 19/2 | clip:1 gain:0.49999999999999994 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 55/6 → 19/2 | clip:1 gain:0.46617387872822824 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 55/6 → 59/6 | gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 28/3 → 29/3 | clip:1 gain:0.5381966011250106 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 28/3 → 29/3 | clip:1 gain:0.49999999999999994 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 28/3 → 10/1 | gain:1 clip:1 note:D2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 19/2 → 59/6 | clip:1 gain:0.5381966011250106 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ 19/2 → 59/6 | clip:1 gain:0.49999999999999994 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (19/2 → 10/1) ⇝ 61/6 | gain:0.25 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (19/2 → 10/1) ⇝ 21/2 | gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (19/2 → 10/1) ⇝ 21/2 | gain:0.25 clip:1 note:E7 s:piano release:0.1 pan:0.712962962962963 ]", + "[ (19/2 → 10/1) ⇝ 23/2 | gain:0.25 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (19/2 → 10/1) ⇝ 23/2 | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ (19/2 → 10/1) ⇝ 23/2 | gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 29/3 → 10/1 | clip:1 gain:0.5790943073464692 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 29/3 → 10/1 | clip:1 gain:0.5381966011250106 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ (29/3 → 10/1) ⇝ 31/3 | gain:0.3333333333333333 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ (59/6 → 10/1) ⇝ 61/6 | clip:1 gain:0.5790943073464692 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (59/6 → 10/1) ⇝ 61/6 | clip:1 gain:0.5381966011250106 note:E6 s:piano release:0.1 pan:0.6574074074074074 ]", + "[ (59/6 → 10/1) ⇝ 21/2 | gain:0.5 clip:1 note:D3 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 19/2 ⇜ (10/1 → 61/6) | gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 59/6 ⇜ (10/1 → 61/6) | clip:1 gain:0.5790943073464692 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 59/6 ⇜ (10/1 → 61/6) | clip:1 gain:0.5381966011250106 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 29/3 ⇜ (10/1 → 31/3) | gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 10/1 → 31/3 | clip:1 gain:0.6209056926535306 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 10/1 → 31/3 | clip:1 gain:0.5790943073464692 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 17/2 ⇜ (10/1 → 21/2) | gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 17/2 ⇜ (10/1 → 21/2) | gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", + "[ 17/2 ⇜ (10/1 → 21/2) | gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 19/2 ⇜ (10/1 → 21/2) | gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 19/2 ⇜ (10/1 → 21/2) | gain:0.25 clip:1 note:A7 s:piano release:0.1 pan:0.7361111111111112 ]", + "[ 59/6 ⇜ (10/1 → 21/2) | gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 10/1 → 32/3 | gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", + "[ 9/1 ⇜ (10/1 → 11/1) | gain:0.3333333333333333 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 9/1 ⇜ (10/1 → 11/1) | gain:0.3333333333333333 clip:1 note:B5 s:piano release:0.1 pan:0.6342592592592593 ]", + "[ 9/1 ⇜ (10/1 → 11/1) | gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ 19/2 ⇜ (10/1 → 11/1) ⇝ 23/2 | gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 19/2 ⇜ (10/1 → 11/1) ⇝ 23/2 | gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", + "[ 19/2 ⇜ (10/1 → 11/1) ⇝ 23/2 | gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", + "[ 10/1 → 11/1 | gain:1 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 10/1 → 11/1 | gain:0.3333333333333333 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (10/1 → 11/1) ⇝ 12/1 | gain:1 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ (10/1 → 11/1) ⇝ 12/1 | gain:1 clip:1 note:B3 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ (10/1 → 11/1) ⇝ 12/1 | gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 61/6 → 21/2 | clip:1 gain:0.6209056926535306 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 61/6 → 21/2 | clip:1 gain:0.5790943073464692 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 61/6 → 65/6 | gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 31/3 → 32/3 | clip:1 gain:0.6618033988749894 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 31/3 → 32/3 | clip:1 gain:0.6209056926535306 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 31/3 → 11/1 | gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 21/2 → 65/6 | clip:1 gain:0.6618033988749894 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 21/2 → 65/6 | clip:1 gain:0.6209056926535306 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (21/2 → 11/1) ⇝ 67/6 | gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ (21/2 → 11/1) ⇝ 23/2 | gain:0.5 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", + "[ (21/2 → 11/1) ⇝ 23/2 | gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", + "[ (21/2 → 11/1) ⇝ 25/2 | gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ (21/2 → 11/1) ⇝ 25/2 | gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", + "[ (21/2 → 11/1) ⇝ 25/2 | gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 32/3 → 11/1 | clip:1 gain:0.7 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 32/3 → 11/1 | clip:1 gain:0.6618033988749894 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (32/3 → 11/1) ⇝ 34/3 | gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", + "[ (65/6 → 11/1) ⇝ 67/6 | clip:1 gain:0.7 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (65/6 → 11/1) ⇝ 67/6 | clip:1 gain:0.6618033988749894 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (65/6 → 11/1) ⇝ 23/2 | gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 21/2 ⇜ (11/1 → 67/6) | gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 65/6 ⇜ (11/1 → 67/6) | clip:1 gain:0.7 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 65/6 ⇜ (11/1 → 67/6) | clip:1 gain:0.6618033988749894 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 32/3 ⇜ (11/1 → 34/3) | gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", + "[ 11/1 → 34/3 | clip:1 gain:0.7338261212717717 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 11/1 → 34/3 | clip:1 gain:0.7 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 19/2 ⇜ (11/1 → 23/2) | gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 19/2 ⇜ (11/1 → 23/2) | gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", + "[ 19/2 ⇜ (11/1 → 23/2) | gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", + "[ 21/2 ⇜ (11/1 → 23/2) | gain:0.5 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", + "[ 21/2 ⇜ (11/1 → 23/2) | gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", + "[ 65/6 ⇜ (11/1 → 23/2) | gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 11/1 → 35/3 | gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 10/1 ⇜ (11/1 → 12/1) | gain:1 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 10/1 ⇜ (11/1 → 12/1) | gain:1 clip:1 note:B3 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 10/1 ⇜ (11/1 → 12/1) | gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 21/2 ⇜ (11/1 → 12/1) ⇝ 25/2 | gain:0.5 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 21/2 ⇜ (11/1 → 12/1) ⇝ 25/2 | gain:0.5 clip:1 note:B4 s:piano release:0.1 pan:0.5787037037037037 ]", + "[ 21/2 ⇜ (11/1 → 12/1) ⇝ 25/2 | gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 11/1 → 12/1 | gain:1 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 11/1 → 12/1 | gain:0.3333333333333333 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (11/1 → 12/1) ⇝ 13/1 | gain:0.3333333333333333 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ (11/1 → 12/1) ⇝ 13/1 | gain:0.3333333333333333 clip:1 note:B5 s:piano release:0.1 pan:0.6342592592592593 ]", + "[ (11/1 → 12/1) ⇝ 13/1 | gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ 67/6 → 23/2 | clip:1 gain:0.7338261212717717 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 67/6 → 23/2 | clip:1 gain:0.7 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 67/6 → 71/6 | gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 34/3 → 35/3 | clip:1 gain:0.7618033988749894 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 34/3 → 35/3 | clip:1 gain:0.7338261212717717 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 34/3 → 12/1 | gain:1 clip:1 note:G2 s:piano release:0.1 pan:0.44907407407407407 ]", + "[ 23/2 → 71/6 | clip:1 gain:0.7618033988749894 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 23/2 → 71/6 | clip:1 gain:0.7338261212717717 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (23/2 → 12/1) ⇝ 73/6 | gain:0.25 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ (23/2 → 12/1) ⇝ 25/2 | gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ (23/2 → 12/1) ⇝ 25/2 | gain:0.25 clip:1 note:A7 s:piano release:0.1 pan:0.7361111111111112 ]", + "[ (23/2 → 12/1) ⇝ 27/2 | gain:0.25 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (23/2 → 12/1) ⇝ 27/2 | gain:0.25 clip:1 note:B6 s:piano release:0.1 pan:0.6898148148148149 ]", + "[ (23/2 → 12/1) ⇝ 27/2 | gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", + "[ 35/3 → 12/1 | clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 35/3 → 12/1 | clip:1 gain:0.7618033988749894 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (35/3 → 12/1) ⇝ 37/3 | gain:0.3333333333333333 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ (71/6 → 12/1) ⇝ 73/6 | clip:1 gain:0.7827090915285202 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (71/6 → 12/1) ⇝ 73/6 | clip:1 gain:0.7618033988749894 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (71/6 → 12/1) ⇝ 25/2 | gain:0.5 clip:1 note:G3 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 23/2 ⇜ (12/1 → 73/6) | gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 71/6 ⇜ (12/1 → 73/6) | clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 71/6 ⇜ (12/1 → 73/6) | clip:1 gain:0.7618033988749894 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 35/3 ⇜ (12/1 → 37/3) | gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 12/1 → 37/3 | clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 12/1 → 37/3 | clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 21/2 ⇜ (12/1 → 25/2) | gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 21/2 ⇜ (12/1 → 25/2) | gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", + "[ 21/2 ⇜ (12/1 → 25/2) | gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 23/2 ⇜ (12/1 → 25/2) | gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 23/2 ⇜ (12/1 → 25/2) | gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ 71/6 ⇜ (12/1 → 25/2) | gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ 12/1 → 38/3 | gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", + "[ 11/1 ⇜ (12/1 → 13/1) | gain:0.3333333333333333 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 11/1 ⇜ (12/1 → 13/1) | gain:0.3333333333333333 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", + "[ 11/1 ⇜ (12/1 → 13/1) | gain:0.3333333333333333 clip:1 note:Bb5 s:piano release:0.1 pan:0.6296296296296297 ]", + "[ 23/2 ⇜ (12/1 → 13/1) ⇝ 27/2 | gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ 23/2 ⇜ (12/1 → 13/1) ⇝ 27/2 | gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", + "[ 23/2 ⇜ (12/1 → 13/1) ⇝ 27/2 | gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", + "[ 12/1 → 13/1 | gain:1 clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 12/1 → 13/1 | gain:0.3333333333333333 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ (12/1 → 13/1) ⇝ 14/1 | gain:1 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ (12/1 → 13/1) ⇝ 14/1 | gain:1 clip:1 note:Eb3 s:piano release:0.1 pan:0.4861111111111111 ]", + "[ (12/1 → 13/1) ⇝ 14/1 | gain:1 clip:1 note:Bb3 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 73/6 → 25/2 | clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 73/6 → 25/2 | clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 73/6 → 77/6 | gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 37/3 → 38/3 | clip:1 gain:0.8 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 37/3 → 38/3 | clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 37/3 → 13/1 | gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 25/2 → 77/6 | clip:1 gain:0.8 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 25/2 → 77/6 | clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (25/2 → 13/1) ⇝ 79/6 | gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ (25/2 → 13/1) ⇝ 27/2 | gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ (25/2 → 13/1) ⇝ 27/2 | gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ (25/2 → 13/1) ⇝ 29/2 | gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (25/2 → 13/1) ⇝ 29/2 | gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", + "[ (25/2 → 13/1) ⇝ 29/2 | gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 38/3 → 13/1 | clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 38/3 → 13/1 | clip:1 gain:0.8 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (38/3 → 13/1) ⇝ 40/3 | gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", + "[ (77/6 → 13/1) ⇝ 79/6 | clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (77/6 → 13/1) ⇝ 79/6 | clip:1 gain:0.8 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (77/6 → 13/1) ⇝ 27/2 | gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 25/2 ⇜ (13/1 → 79/6) | gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ 77/6 ⇜ (13/1 → 79/6) | clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 77/6 ⇜ (13/1 → 79/6) | clip:1 gain:0.8 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 38/3 ⇜ (13/1 → 40/3) | gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", + "[ 13/1 → 40/3 | clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 13/1 → 40/3 | clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 23/2 ⇜ (13/1 → 27/2) | gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ 23/2 ⇜ (13/1 → 27/2) | gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", + "[ 23/2 ⇜ (13/1 → 27/2) | gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", + "[ 25/2 ⇜ (13/1 → 27/2) | gain:0.5 clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]", + "[ 25/2 ⇜ (13/1 → 27/2) | gain:0.25 clip:1 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 77/6 ⇜ (13/1 → 27/2) | gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ 13/1 → 41/3 | gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 12/1 ⇜ (13/1 → 14/1) | gain:1 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ 12/1 ⇜ (13/1 → 14/1) | gain:1 clip:1 note:Eb3 s:piano release:0.1 pan:0.4861111111111111 ]", + "[ 12/1 ⇜ (13/1 → 14/1) | gain:1 clip:1 note:Bb3 s:piano release:0.1 pan:0.5185185185185186 ]", + "[ 25/2 ⇜ (13/1 → 14/1) ⇝ 29/2 | gain:0.5 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 25/2 ⇜ (13/1 → 14/1) ⇝ 29/2 | gain:0.5 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", + "[ 25/2 ⇜ (13/1 → 14/1) ⇝ 29/2 | gain:0.5 clip:1 note:Bb4 s:piano release:0.1 pan:0.5740740740740741 ]", + "[ 13/1 → 14/1 | gain:1 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ 13/1 → 14/1 | gain:0.3333333333333333 clip:1 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (13/1 → 14/1) ⇝ 15/1 | gain:0.3333333333333333 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (13/1 → 14/1) ⇝ 15/1 | gain:0.3333333333333333 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", + "[ (13/1 → 14/1) ⇝ 15/1 | gain:0.3333333333333333 clip:1 note:Bb5 s:piano release:0.1 pan:0.6296296296296297 ]", + "[ 79/6 → 27/2 | clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 79/6 → 27/2 | clip:1 gain:0.7956295201467611 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 79/6 → 83/6 | gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ 40/3 → 41/3 | clip:1 gain:0.7618033988749895 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 40/3 → 41/3 | clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 40/3 → 14/1 | gain:1 clip:1 note:C2 s:piano release:0.1 pan:0.41666666666666663 ]", + "[ 27/2 → 83/6 | clip:1 gain:0.7618033988749895 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ 27/2 → 83/6 | clip:1 gain:0.7827090915285202 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (27/2 → 14/1) ⇝ 85/6 | gain:0.25 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (27/2 → 14/1) ⇝ 29/2 | gain:0.5 clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]", + "[ (27/2 → 14/1) ⇝ 29/2 | gain:0.25 clip:1 note:D7 s:piano release:0.1 pan:0.7037037037037037 ]", + "[ (27/2 → 14/1) ⇝ 31/2 | gain:0.25 clip:1 note:C6 s:piano release:0.1 pan:0.6388888888888888 ]", + "[ (27/2 → 14/1) ⇝ 31/2 | gain:0.25 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", + "[ (27/2 → 14/1) ⇝ 31/2 | gain:0.25 clip:1 note:Bb6 s:piano release:0.1 pan:0.6851851851851851 ]", + "[ 41/3 → 14/1 | clip:1 gain:0.7338261212717718 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 41/3 → 14/1 | clip:1 gain:0.7618033988749895 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (41/3 → 14/1) ⇝ 43/3 | gain:0.3333333333333333 clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]", + "[ (83/6 → 14/1) ⇝ 85/6 | clip:1 gain:0.7338261212717718 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (83/6 → 14/1) ⇝ 85/6 | clip:1 gain:0.7618033988749895 note:D6 s:piano release:0.1 pan:0.6481481481481481 ]", + "[ (83/6 → 14/1) ⇝ 29/2 | gain:0.5 clip:1 note:C3 s:piano release:0.1 pan:0.4722222222222222 ]", + "[ 27/2 ⇜ (14/1 → 85/6) | gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 83/6 ⇜ (14/1 → 85/6) | clip:1 gain:0.7338261212717718 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 83/6 ⇜ (14/1 → 85/6) | clip:1 gain:0.7618033988749895 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 41/3 ⇜ (14/1 → 43/3) | gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 14/1 → 43/3 | clip:1 gain:0.7 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 14/1 → 43/3 | clip:1 gain:0.7338261212717718 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 25/2 ⇜ (14/1 → 29/2) | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 25/2 ⇜ (14/1 → 29/2) | gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 25/2 ⇜ (14/1 → 29/2) | gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", + "[ 27/2 ⇜ (14/1 → 29/2) | gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 27/2 ⇜ (14/1 → 29/2) | gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", + "[ 83/6 ⇜ (14/1 → 29/2) | gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 14/1 → 44/3 | gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", + "[ 13/1 ⇜ (14/1 → 15/1) | gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 13/1 ⇜ (14/1 → 15/1) | gain:0.3333333333333333 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", + "[ 13/1 ⇜ (14/1 → 15/1) | gain:0.3333333333333333 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", + "[ 27/2 ⇜ (14/1 → 15/1) ⇝ 31/2 | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ 27/2 ⇜ (14/1 → 15/1) ⇝ 31/2 | gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 27/2 ⇜ (14/1 → 15/1) ⇝ 31/2 | gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", + "[ 14/1 → 15/1 | gain:1 clip:1 note:G4 s:piano release:0.1 pan:0.5601851851851851 ]", + "[ 14/1 → 15/1 | gain:0.3333333333333333 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ (14/1 → 15/1) ⇝ 16/1 | gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (14/1 → 15/1) ⇝ 16/1 | gain:1 clip:1 note:A3 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ (14/1 → 15/1) ⇝ 16/1 | gain:1 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", + "[ 85/6 → 29/2 | clip:1 gain:0.7 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 85/6 → 29/2 | clip:1 gain:0.7338261212717718 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 85/6 → 89/6 | gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 43/3 → 44/3 | clip:1 gain:0.6618033988749896 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 43/3 → 44/3 | clip:1 gain:0.7 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 43/3 → 15/1 | gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 29/2 → 89/6 | clip:1 gain:0.6618033988749896 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 29/2 → 89/6 | clip:1 gain:0.7 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (29/2 → 15/1) ⇝ 91/6 | gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ (29/2 → 15/1) ⇝ 31/2 | gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ (29/2 → 15/1) ⇝ 31/2 | gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", + "[ (29/2 → 15/1) ⇝ 33/2 | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (29/2 → 15/1) ⇝ 33/2 | gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ (29/2 → 15/1) ⇝ 33/2 | gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", + "[ 44/3 → 15/1 | clip:1 gain:0.6209056926535306 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 44/3 → 15/1 | clip:1 gain:0.6618033988749896 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ (44/3 → 15/1) ⇝ 46/3 | gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", + "[ (89/6 → 15/1) ⇝ 91/6 | clip:1 gain:0.6209056926535306 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (89/6 → 15/1) ⇝ 91/6 | clip:1 gain:0.6618033988749896 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ (89/6 → 15/1) ⇝ 31/2 | gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 29/2 ⇜ (15/1 → 91/6) | gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 89/6 ⇜ (15/1 → 91/6) | clip:1 gain:0.6209056926535306 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 89/6 ⇜ (15/1 → 91/6) | clip:1 gain:0.6618033988749896 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 44/3 ⇜ (15/1 → 46/3) | gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", + "[ 15/1 → 46/3 | clip:1 gain:0.5790943073464696 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 15/1 → 46/3 | clip:1 gain:0.6209056926535306 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 27/2 ⇜ (15/1 → 31/2) | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ 27/2 ⇜ (15/1 → 31/2) | gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ 27/2 ⇜ (15/1 → 31/2) | gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", + "[ 29/2 ⇜ (15/1 → 31/2) | gain:0.5 clip:1 note:G5 s:piano release:0.1 pan:0.6157407407407407 ]", + "[ 29/2 ⇜ (15/1 → 31/2) | gain:0.25 clip:1 note:F7 s:piano release:0.1 pan:0.7175925925925926 ]", + "[ 89/6 ⇜ (15/1 → 31/2) | gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ 15/1 → 47/3 | gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 14/1 ⇜ (15/1 → 16/1) | gain:1 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 14/1 ⇜ (15/1 → 16/1) | gain:1 clip:1 note:A3 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 14/1 ⇜ (15/1 → 16/1) | gain:1 clip:1 note:Eb4 s:piano release:0.1 pan:0.5416666666666667 ]", + "[ 29/2 ⇜ (15/1 → 16/1) ⇝ 33/2 | gain:0.5 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 29/2 ⇜ (15/1 → 16/1) ⇝ 33/2 | gain:0.5 clip:1 note:A4 s:piano release:0.1 pan:0.5694444444444444 ]", + "[ 29/2 ⇜ (15/1 → 16/1) ⇝ 33/2 | gain:0.5 clip:1 note:Eb5 s:piano release:0.1 pan:0.5972222222222222 ]", + "[ 15/1 → 16/1 | gain:1 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ 15/1 → 16/1 | gain:0.3333333333333333 clip:1 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (15/1 → 16/1) ⇝ 17/1 | gain:0.3333333333333333 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ (15/1 → 16/1) ⇝ 17/1 | gain:0.3333333333333333 clip:1 note:A5 s:piano release:0.1 pan:0.625 ]", + "[ (15/1 → 16/1) ⇝ 17/1 | gain:0.3333333333333333 clip:1 note:Eb6 s:piano release:0.1 pan:0.6527777777777778 ]", + "[ 91/6 → 31/2 | clip:1 gain:0.5790943073464696 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 91/6 → 31/2 | clip:1 gain:0.6209056926535306 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 91/6 → 95/6 | gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", + "[ 46/3 → 47/3 | clip:1 gain:0.5381966011250107 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 46/3 → 47/3 | clip:1 gain:0.5790943073464696 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 46/3 → 16/1 | gain:1 clip:1 note:F2 s:piano release:0.1 pan:0.4398148148148148 ]", + "[ 31/2 → 95/6 | clip:1 gain:0.5381966011250107 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ 31/2 → 95/6 | clip:1 gain:0.5790943073464696 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ (31/2 → 16/1) ⇝ 97/6 | gain:0.25 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ (31/2 → 16/1) ⇝ 33/2 | gain:0.5 clip:1 note:F5 s:piano release:0.1 pan:0.6064814814814814 ]", + "[ (31/2 → 16/1) ⇝ 33/2 | gain:0.25 clip:1 note:G7 s:piano release:0.1 pan:0.7268518518518519 ]", + "[ (31/2 → 16/1) ⇝ 35/2 | gain:0.25 clip:1 note:F6 s:piano release:0.1 pan:0.662037037037037 ]", + "[ (31/2 → 16/1) ⇝ 35/2 | gain:0.25 clip:1 note:A6 s:piano release:0.1 pan:0.6805555555555556 ]", + "[ (31/2 → 16/1) ⇝ 35/2 | gain:0.25 clip:1 note:Eb7 s:piano release:0.1 pan:0.7083333333333333 ]", + "[ 47/3 → 16/1 | clip:1 gain:0.5000000000000002 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ 47/3 → 16/1 | clip:1 gain:0.5381966011250107 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (47/3 → 16/1) ⇝ 49/3 | gain:0.3333333333333333 clip:1 note:F4 s:piano release:0.1 pan:0.5509259259259259 ]", + "[ (95/6 → 16/1) ⇝ 97/6 | clip:1 gain:0.5000000000000002 note:C7 s:piano release:0.1 pan:0.6944444444444444 ]", + "[ (95/6 → 16/1) ⇝ 97/6 | clip:1 gain:0.5381966011250107 note:G6 s:piano release:0.1 pan:0.6712962962962963 ]", + "[ (95/6 → 16/1) ⇝ 33/2 | gain:0.5 clip:1 note:F3 s:piano release:0.1 pan:0.49537037037037035 ]", ] `; @@ -7571,118 +7571,118 @@ exports[`renders tunes > tune: giantSteps 1`] = ` exports[`renders tunes > tune: goodTimes 1`] = ` [ - "[ 0/1 → 1/4 | n:0 note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", - "[ 1/4 → 1/2 | n:0 note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", - "[ 1/2 → 3/4 | n:0 note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", - "[ 1/2 → 3/4 | n:2 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 1/2 → 3/4 | n:4 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 1/2 → 3/4 | n:0 note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", - "[ 1/1 → 5/4 | n:2 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 1/1 → 5/4 | n:4 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 1/1 → 5/4 | n:0 note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", - "[ 5/4 → 3/2 | n:0 note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", - "[ 5/4 → 3/2 | n:0 note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", - "[ 7/4 → 2/1 | n:2 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 7/4 → 2/1 | n:4 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 7/4 → 2/1 | n:0 note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", - "[ 2/1 → 9/4 | n:1 note:54 clip:2 s:piano release:0.1 pan:0.5 ]", - "[ 9/4 → 5/2 | n:4 note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", - "[ 5/2 → 11/4 | n:1 note:54 clip:2 s:piano release:0.1 pan:0.5 ]", - "[ 5/2 → 11/4 | n:3 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 5/2 → 11/4 | n:5 note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", - "[ 5/2 → 11/4 | n:4 note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", - "[ 3/1 → 13/4 | n:3 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 3/1 → 13/4 | n:5 note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", - "[ 3/1 → 13/4 | n:4 note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", - "[ 13/4 → 7/2 | n:1 note:54 clip:2 s:piano release:0.1 pan:0.5 ]", - "[ 13/4 → 7/2 | n:4 note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", - "[ 15/4 → 4/1 | n:3 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 15/4 → 4/1 | n:5 note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", - "[ 15/4 → 4/1 | n:4 note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", - "[ 4/1 → 17/4 | n:2 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 17/4 → 9/2 | n:0 note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", - "[ 9/2 → 19/4 | n:2 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 9/2 → 19/4 | n:4 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 9/2 → 19/4 | n:6 note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 9/2 → 19/4 | n:0 note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", - "[ 5/1 → 21/4 | n:4 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 5/1 → 21/4 | n:6 note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 5/1 → 21/4 | n:0 note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", - "[ 21/4 → 11/2 | n:2 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 21/4 → 11/2 | n:0 note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", - "[ 23/4 → 6/1 | n:4 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 23/4 → 6/1 | n:6 note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 23/4 → 6/1 | n:0 note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", - "[ 6/1 → 25/4 | n:3 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 25/4 → 13/2 | n:4 note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", - "[ 13/2 → 27/4 | n:3 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 13/2 → 27/4 | n:5 note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", - "[ 13/2 → 27/4 | n:7 note:64 clip:2 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 13/2 → 27/4 | n:4 note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", - "[ 7/1 → 29/4 | n:5 note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", - "[ 7/1 → 29/4 | n:7 note:64 clip:2 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 7/1 → 29/4 | n:4 note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", - "[ 29/4 → 15/2 | n:3 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 29/4 → 15/2 | n:4 note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", - "[ 31/4 → 8/1 | n:5 note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", - "[ 31/4 → 8/1 | n:7 note:64 clip:2 s:piano release:0.1 pan:0.5462962962962963 ]", - "[ 31/4 → 8/1 | n:4 note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", - "[ 8/1 → 33/4 | n:0 note:50 clip:2 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 33/4 → 17/2 | n:0 note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 17/2 → 35/4 | n:0 note:50 clip:2 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 17/2 → 35/4 | n:2 note:54 clip:2 s:piano release:0.1 pan:0.5 ]", - "[ 17/2 → 35/4 | n:4 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 17/2 → 35/4 | n:0 note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 9/1 → 37/4 | n:2 note:54 clip:2 s:piano release:0.1 pan:0.5 ]", - "[ 9/1 → 37/4 | n:4 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 9/1 → 37/4 | n:0 note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 37/4 → 19/2 | n:0 note:50 clip:2 s:piano release:0.1 pan:0.4814814814814815 ]", - "[ 37/4 → 19/2 | n:0 note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 39/4 → 10/1 | n:2 note:54 clip:2 s:piano release:0.1 pan:0.5 ]", - "[ 39/4 → 10/1 | n:4 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 39/4 → 10/1 | n:0 note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 10/1 → 41/4 | n:1 note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", - "[ 41/4 → 21/2 | n:4 note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", - "[ 21/2 → 43/4 | n:1 note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", - "[ 21/2 → 43/4 | n:3 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 21/2 → 43/4 | n:5 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 21/2 → 43/4 | n:4 note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", - "[ 11/1 → 45/4 | n:3 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 11/1 → 45/4 | n:5 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 11/1 → 45/4 | n:4 note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", - "[ 45/4 → 23/2 | n:1 note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", - "[ 45/4 → 23/2 | n:4 note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", - "[ 47/4 → 12/1 | n:3 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 47/4 → 12/1 | n:5 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 47/4 → 12/1 | n:4 note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", - "[ 12/1 → 49/4 | n:2 note:54 clip:2 s:piano release:0.1 pan:0.5 ]", - "[ 49/4 → 25/2 | n:0 note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 25/2 → 51/4 | n:2 note:54 clip:2 s:piano release:0.1 pan:0.5 ]", - "[ 25/2 → 51/4 | n:4 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 25/2 → 51/4 | n:6 note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", - "[ 25/2 → 51/4 | n:0 note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 13/1 → 53/4 | n:4 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 13/1 → 53/4 | n:6 note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", - "[ 13/1 → 53/4 | n:0 note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 53/4 → 27/2 | n:2 note:54 clip:2 s:piano release:0.1 pan:0.5 ]", - "[ 53/4 → 27/2 | n:0 note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 55/4 → 14/1 | n:4 note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", - "[ 55/4 → 14/1 | n:6 note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", - "[ 55/4 → 14/1 | n:0 note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", - "[ 14/1 → 57/4 | n:3 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 57/4 → 29/2 | n:4 note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", - "[ 29/2 → 59/4 | n:3 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 29/2 → 59/4 | n:5 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 29/2 → 59/4 | n:7 note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 29/2 → 59/4 | n:4 note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", - "[ 15/1 → 61/4 | n:5 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 15/1 → 61/4 | n:7 note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 15/1 → 61/4 | n:4 note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", - "[ 61/4 → 31/2 | n:3 note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", - "[ 61/4 → 31/2 | n:4 note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", - "[ 63/4 → 16/1 | n:5 note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", - "[ 63/4 → 16/1 | n:7 note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", - "[ 63/4 → 16/1 | n:4 note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", + "[ 0/1 → 1/4 | note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", + "[ 1/4 → 1/2 | note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", + "[ 1/2 → 3/4 | note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", + "[ 1/2 → 3/4 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 1/2 → 3/4 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 1/2 → 3/4 | note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", + "[ 1/1 → 5/4 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 1/1 → 5/4 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 1/1 → 5/4 | note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", + "[ 5/4 → 3/2 | note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", + "[ 5/4 → 3/2 | note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", + "[ 7/4 → 2/1 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 7/4 → 2/1 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 7/4 → 2/1 | note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", + "[ 2/1 → 9/4 | note:54 clip:2 s:piano release:0.1 pan:0.5 ]", + "[ 9/4 → 5/2 | note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", + "[ 5/2 → 11/4 | note:54 clip:2 s:piano release:0.1 pan:0.5 ]", + "[ 5/2 → 11/4 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 5/2 → 11/4 | note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", + "[ 5/2 → 11/4 | note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", + "[ 3/1 → 13/4 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 3/1 → 13/4 | note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", + "[ 3/1 → 13/4 | note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", + "[ 13/4 → 7/2 | note:54 clip:2 s:piano release:0.1 pan:0.5 ]", + "[ 13/4 → 7/2 | note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", + "[ 15/4 → 4/1 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 15/4 → 4/1 | note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", + "[ 15/4 → 4/1 | note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", + "[ 4/1 → 17/4 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 17/4 → 9/2 | note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", + "[ 9/2 → 19/4 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 9/2 → 19/4 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 9/2 → 19/4 | note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 9/2 → 19/4 | note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", + "[ 5/1 → 21/4 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 5/1 → 21/4 | note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 5/1 → 21/4 | note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", + "[ 21/4 → 11/2 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 21/4 → 11/2 | note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", + "[ 23/4 → 6/1 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 23/4 → 6/1 | note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 23/4 → 6/1 | note:40 clip:2 s:piano release:0.1 pan:0.4351851851851852 ]", + "[ 6/1 → 25/4 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 25/4 → 13/2 | note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", + "[ 13/2 → 27/4 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 13/2 → 27/4 | note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", + "[ 13/2 → 27/4 | note:64 clip:2 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 13/2 → 27/4 | note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", + "[ 7/1 → 29/4 | note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", + "[ 7/1 → 29/4 | note:64 clip:2 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 7/1 → 29/4 | note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", + "[ 29/4 → 15/2 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 29/4 → 15/2 | note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", + "[ 31/4 → 8/1 | note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", + "[ 31/4 → 8/1 | note:64 clip:2 s:piano release:0.1 pan:0.5462962962962963 ]", + "[ 31/4 → 8/1 | note:47 clip:2 s:piano release:0.1 pan:0.46759259259259256 ]", + "[ 8/1 → 33/4 | note:50 clip:2 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 33/4 → 17/2 | note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 17/2 → 35/4 | note:50 clip:2 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 17/2 → 35/4 | note:54 clip:2 s:piano release:0.1 pan:0.5 ]", + "[ 17/2 → 35/4 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 17/2 → 35/4 | note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 9/1 → 37/4 | note:54 clip:2 s:piano release:0.1 pan:0.5 ]", + "[ 9/1 → 37/4 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 9/1 → 37/4 | note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 37/4 → 19/2 | note:50 clip:2 s:piano release:0.1 pan:0.4814814814814815 ]", + "[ 37/4 → 19/2 | note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 39/4 → 10/1 | note:54 clip:2 s:piano release:0.1 pan:0.5 ]", + "[ 39/4 → 10/1 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 39/4 → 10/1 | note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 10/1 → 41/4 | note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", + "[ 41/4 → 21/2 | note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", + "[ 21/2 → 43/4 | note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", + "[ 21/2 → 43/4 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 21/2 → 43/4 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 21/2 → 43/4 | note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", + "[ 11/1 → 45/4 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 11/1 → 45/4 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 11/1 → 45/4 | note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", + "[ 45/4 → 23/2 | note:52 clip:2 s:piano release:0.1 pan:0.4907407407407407 ]", + "[ 45/4 → 23/2 | note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", + "[ 47/4 → 12/1 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 47/4 → 12/1 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 47/4 → 12/1 | note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", + "[ 12/1 → 49/4 | note:54 clip:2 s:piano release:0.1 pan:0.5 ]", + "[ 49/4 → 25/2 | note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 25/2 → 51/4 | note:54 clip:2 s:piano release:0.1 pan:0.5 ]", + "[ 25/2 → 51/4 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 25/2 → 51/4 | note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", + "[ 25/2 → 51/4 | note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 13/1 → 53/4 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 13/1 → 53/4 | note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", + "[ 13/1 → 53/4 | note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 53/4 → 27/2 | note:54 clip:2 s:piano release:0.1 pan:0.5 ]", + "[ 53/4 → 27/2 | note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 55/4 → 14/1 | note:57 clip:2 s:piano release:0.1 pan:0.5138888888888888 ]", + "[ 55/4 → 14/1 | note:61 clip:2 s:piano release:0.1 pan:0.5324074074074074 ]", + "[ 55/4 → 14/1 | note:38 clip:2 s:piano release:0.1 pan:0.42592592592592593 ]", + "[ 14/1 → 57/4 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 57/4 → 29/2 | note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", + "[ 29/2 → 59/4 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 29/2 → 59/4 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 29/2 → 59/4 | note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 29/2 → 59/4 | note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", + "[ 15/1 → 61/4 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 15/1 → 61/4 | note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 15/1 → 61/4 | note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", + "[ 61/4 → 31/2 | note:55 clip:2 s:piano release:0.1 pan:0.5046296296296297 ]", + "[ 61/4 → 31/2 | note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", + "[ 63/4 → 16/1 | note:59 clip:2 s:piano release:0.1 pan:0.5231481481481481 ]", + "[ 63/4 → 16/1 | note:62 clip:2 s:piano release:0.1 pan:0.537037037037037 ]", + "[ 63/4 → 16/1 | note:45 clip:2 s:piano release:0.1 pan:0.45833333333333337 ]", ] `; From b25b9d815b87461a107da22f0b662a4c12fc6af2 Mon Sep 17 00:00:00 2001 From: Vasilii Milovidov Date: Sat, 7 Oct 2023 19:30:07 +0400 Subject: [PATCH 156/175] fix: conflicts --- packages/superdough/reverb.mjs | 4 +--- packages/superdough/superdough.mjs | 26 ++++++++++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index 85be19ae..f853d3fb 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -19,10 +19,9 @@ if (typeof AudioContext !== 'undefined') { AudioContext.prototype.createReverb = function (duration, fade, lp, dim, ir) { const convolver = this.createConvolver(); - convolver.generate = (d, fade, lp, dim, buf) => { + convolver.generate = (d = 2, fade = 0.1, lp = 15000, dim = 1000, buf) => { if (buf) { convolver.buffer = this.adjustLength(d, buf); - return convolver; } else { this.generateReverb( { @@ -42,7 +41,6 @@ if (typeof AudioContext !== 'undefined') { convolver.fade = fade; convolver.lp = lp; convolver.dim = dim; - return convolver; } }; convolver.setIR = (d, fade, lp, dim, buf) => { diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index d7f0b14b..20edbe33 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -114,6 +114,8 @@ function getDelay(orbit, delaytime, delayfeedback, t) { let reverbs = {}; +let hasChanged = (now, before) => now !== undefined && now !== before; + function getReverb(orbit, duration = 2, fade, lp, dim, ir) { if (!reverbs[orbit]) { const ac = getAudioContext(); @@ -123,13 +125,17 @@ function getReverb(orbit, duration = 2, fade, lp, dim, ir) { } if ( - reverbs[orbit].duration !== duration || - reverbs[orbit].fade !== fade || - reverbs[orbit].ir !== lp || - reverbs[orbit].dim !== dim || - reverbs[orbit].ir !== ir + hasChanged(duration, reverbs[orbit].duration) || + hasChanged(fade, reverbs[orbit].fade) || + hasChanged(lp, reverbs[orbit].lp) || + hasChanged(dim, reverbs[orbit].dim) ) { - reverbs[orbit].generate(duration, fade, lp, dim, ir); + // only regenerate when something has changed + // avoids endless regeneration on things like + // stack(s("a"), s("b").rsize(8)).room(.5) + // this only works when args may stay undefined until here + // setting default values breaks this + reverbs[orbit].generate(duration, fade, lp, dim); } if (reverbs[orbit].ir !== ir) { @@ -235,10 +241,10 @@ export const superdough = async (value, deadline, hapDuration) => { delaytime = 0.25, orbit = 1, room, - roomfade = 0.1, - roomlp = 15000, - roomdim = 1000, - roomsize = 2, + roomfade, + roomlp, + roomdim, + roomsize, ir, i = 0, velocity = 1, From 2d750a14b9bd5da47a86aada47b0f5d5836aca8c Mon Sep 17 00:00:00 2001 From: Vasilii Milovidov Date: Sat, 7 Oct 2023 19:48:07 +0400 Subject: [PATCH 157/175] fix: conflicts --- packages/superdough/superdough.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 20edbe33..d2507672 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -116,7 +116,8 @@ let reverbs = {}; let hasChanged = (now, before) => now !== undefined && now !== before; -function getReverb(orbit, duration = 2, fade, lp, dim, ir) { +function getReverb(orbit, duration, fade, lp, dim, ir) { + // If no reverb has been created for a given orbit, create one if (!reverbs[orbit]) { const ac = getAudioContext(); const reverb = ac.createReverb(duration, fade, lp, dim, ir); From 130ad4451b7af054371992220342a0658b9543d7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 8 Oct 2023 00:30:12 +0200 Subject: [PATCH 158/175] add compressor + postgain --- packages/core/controls.mjs | 6 ++++++ packages/superdough/helpers.mjs | 11 +++++++++++ packages/superdough/superdough.mjs | 15 +++++++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 88c2c072..832b09dc 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -86,6 +86,7 @@ const generic_params = [ * */ ['gain'], + ['postgain'], /** * Like {@link gain}, but linear. * @@ -1051,6 +1052,11 @@ const generic_params = [ * */ ['shape'], + [['compressor', 'compressorRatio', 'compressorKnee', 'compressorAttack', 'compressorRelease']], + ['compressorKnee'], + ['compressorRatio'], + ['compressorAttack'], + ['compressorRelease'], /** * Changes the speed of sample playback, i.e. a cheap way of changing pitch. * diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 576ec3f1..d87ea94d 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -78,6 +78,17 @@ export const getParamADSR = (param, attack, decay, sustain, release, min, max, b param.linearRampToValueAtTime(min, end + Math.max(release, 0.1)); }; +export function getCompressor(ac, threshold, ratio, knee, attack, release) { + const options = { + threshold: threshold ?? -3, + ratio: ratio ?? 10, + knee: knee ?? 10, + attack: attack ?? 0.005, + release: release ?? 0.05, + }; + return new DynamicsCompressorNode(ac, options); +} + export function createFilter( context, type, diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 730e495d..410b7b96 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -9,7 +9,7 @@ import './reverb.mjs'; import './vowel.mjs'; import { clamp } from './util.mjs'; import workletsUrl from './worklets.mjs?url'; -import { createFilter, gainNode } from './helpers.mjs'; +import { createFilter, gainNode, getCompressor } from './helpers.mjs'; import { map } from 'nanostores'; import { logger } from './logger.mjs'; @@ -192,6 +192,7 @@ export const superdough = async (value, deadline, hapDuration) => { bank, source, gain = 0.8, + postgain = 1, // filters ftype = '12db', fanchor = 0.5, @@ -237,6 +238,11 @@ export const superdough = async (value, deadline, hapDuration) => { velocity = 1, analyze, // analyser wet fft = 8, // fftSize 0 - 10 + compressor: compressorThreshold, + compressorRatio, + compressorKnee, + compressorAttack, + compressorRelease, } = value; gain *= velocity; // legacy fix for velocity let toDisconnect = []; // audio nodes that will be disconnected when the source has ended @@ -351,6 +357,11 @@ export const superdough = async (value, deadline, hapDuration) => { crush !== undefined && chain.push(getWorklet(ac, 'crush-processor', { crush })); shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', { shape })); + compressorThreshold !== undefined && + chain.push( + getCompressor(ac, compressorThreshold, compressorRatio, compressorKnee, compressorAttack, compressorRelease), + ); + // panning if (pan !== undefined) { const panner = ac.createStereoPanner(); @@ -359,7 +370,7 @@ export const superdough = async (value, deadline, hapDuration) => { } // last gain - const post = gainNode(1); + const post = gainNode(postgain); chain.push(post); post.connect(getDestination()); From 444d583a49065648af5d4c2cc6b1c2bf82532d26 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 8 Oct 2023 13:23:13 +0200 Subject: [PATCH 159/175] fix: hashes in urls --- packages/superdough/sampler.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 76b6a542..a7e9c3a3 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -64,6 +64,7 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol export const loadBuffer = (url, ac, s, n = 0) => { const label = s ? `sound "${s}:${n}"` : 'sample'; + url = url.replace('#', '%23'); if (!loadCache[url]) { logger(`[sampler] load ${label}..`, 'load-sample', { url }); const timestamp = Date.now(); From 0a3692e459ca2eb807b71f55ee6698d36dfd2aa3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 8 Oct 2023 13:37:39 +0200 Subject: [PATCH 160/175] compressor docs --- packages/core/controls.mjs | 19 +++++++++++++++++++ website/src/pages/learn/effects.mdx | 9 +++++++++ 2 files changed, 28 insertions(+) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 832b09dc..3abeb504 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -86,6 +86,15 @@ const generic_params = [ * */ ['gain'], + /** + * Gain applied after all effects have been processed. + * + * @name postgain + * @example + * s("bd sd,hh*4") + * .compressor("-20:20:10:.002:.02").postgain(1.5) + * + */ ['postgain'], /** * Like {@link gain}, but linear. @@ -1052,6 +1061,16 @@ const generic_params = [ * */ ['shape'], + /** + * Dynamics Compressor. The params are `compressor("threshold:ratio:knee:attack:release")` + * More info [here](https://developer.mozilla.org/en-US/docs/Web/API/DynamicsCompressorNode?retiredLocale=de#instance_properties) + * + * @name compressor + * @example + * s("bd sd,hh*4") + * .compressor("-20:20:10:.002:.02") + * + */ [['compressor', 'compressorRatio', 'compressorKnee', 'compressorAttack', 'compressorRelease']], ['compressorKnee'], ['compressorRatio'], diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index 2ee6c44a..11b74646 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -144,6 +144,15 @@ There is one filter envelope for each filter type and thus one set of envelope f +## compressor + + + +## postgain + + + + # Panning ## jux From 08ce8213fcb09eb2dd709650b1f5339138a774bc Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 8 Oct 2023 13:37:56 +0200 Subject: [PATCH 161/175] format --- website/src/pages/learn/effects.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index 11b74646..0bb9da9e 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -152,7 +152,6 @@ There is one filter envelope for each filter type and thus one set of envelope f - # Panning ## jux From 56c14414946796436db34f4f565a9c9ec437674d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 8 Oct 2023 13:38:18 +0200 Subject: [PATCH 162/175] snapshot --- test/__snapshots__/examples.test.mjs.snap | 58 +++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 18370903..f351a5a0 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1185,6 +1185,35 @@ exports[`runs examples > example "compress" example index 0 1`] = ` ] `; +exports[`runs examples > example "compressor" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 0/1 → 1/2 | s:bd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 1/4 → 1/2 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 1/2 → 3/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 1/2 → 1/1 | s:sd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 3/4 → 1/1 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 1/1 → 5/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 1/1 → 3/2 | s:bd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 5/4 → 3/2 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 3/2 → 7/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 3/2 → 2/1 | s:sd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 7/4 → 2/1 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 2/1 → 9/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 2/1 → 5/2 | s:bd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 9/4 → 5/2 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 5/2 → 11/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 5/2 → 3/1 | s:sd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 11/4 → 3/1 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 3/1 → 13/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 3/1 → 7/2 | s:bd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 13/4 → 7/2 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 7/2 → 15/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 7/2 → 4/1 | s:sd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", + "[ 15/4 → 4/1 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 ]", +] +`; + exports[`runs examples > example "cosine" example index 0 1`] = ` [ "[ 0/1 → 1/8 | note:Eb4 ]", @@ -3293,6 +3322,35 @@ exports[`runs examples > example "polymeterSteps" example index 0 1`] = ` ] `; +exports[`runs examples > example "postgain" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 0/1 → 1/2 | s:bd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 1/4 → 1/2 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 1/2 → 3/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 1/2 → 1/1 | s:sd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 3/4 → 1/1 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 1/1 → 5/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 1/1 → 3/2 | s:bd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 5/4 → 3/2 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 3/2 → 7/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 3/2 → 2/1 | s:sd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 7/4 → 2/1 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 2/1 → 9/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 2/1 → 5/2 | s:bd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 9/4 → 5/2 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 5/2 → 11/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 5/2 → 3/1 | s:sd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 11/4 → 3/1 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 3/1 → 13/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 3/1 → 7/2 | s:bd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 13/4 → 7/2 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 7/2 → 15/4 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 7/2 → 4/1 | s:sd compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", + "[ 15/4 → 4/1 | s:hh compressor:-20 compressorRatio:20 compressorKnee:10 compressorAttack:0.002 compressorRelease:0.02 postgain:1.5 ]", +] +`; + exports[`runs examples > example "press" example index 0 1`] = ` [ "[ 0/1 → 1/2 | s:hh ]", From f34937d4aef4a89497f5cffdb5ba1bcaaa288130 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 9 Oct 2023 21:31:49 +0200 Subject: [PATCH 163/175] fix: roomsize not required --- packages/superdough/superdough.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 410b7b96..9f11b983 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -382,7 +382,7 @@ export const superdough = async (value, deadline, hapDuration) => { } // reverb let reverbSend; - if (room > 0 && roomsize > 0) { + if (room > 0) { const reverbNode = getReverb(orbit, roomsize, roomfade, roomlp, roomdim); reverbSend = effectSend(post, reverbNode, room); } From 6544e8135cf8b40eaa751cd13fdabeb5baa489a1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 9 Oct 2023 21:40:38 +0200 Subject: [PATCH 164/175] fix: reverb sampleRate --- packages/superdough/reverb.mjs | 4 +--- packages/superdough/reverbGen.mjs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs index 3d54203c..ff4cb78a 100644 --- a/packages/superdough/reverb.mjs +++ b/packages/superdough/reverb.mjs @@ -1,14 +1,12 @@ import reverbGen from './reverbGen.mjs'; if (typeof AudioContext !== 'undefined') { - AudioContext.prototype.generateReverb = reverbGen.generateReverb; AudioContext.prototype.createReverb = function (duration, fade, lp, dim) { const convolver = this.createConvolver(); convolver.generate = (d = 2, fade = 0.1, lp = 15000, dim = 1000) => { - this.generateReverb( + reverbGen.generateReverb( { audioContext: this, - sampleRate: 44100, numChannels: 2, decayTime: d, fadeInTime: fade, diff --git a/packages/superdough/reverbGen.mjs b/packages/superdough/reverbGen.mjs index 49429937..eed63792 100644 --- a/packages/superdough/reverbGen.mjs +++ b/packages/superdough/reverbGen.mjs @@ -23,7 +23,7 @@ var reverbGen = {}; immediately within the current execution context, or later. */ reverbGen.generateReverb = function (params, callback) { var audioContext = params.audioContext || new AudioContext(); - var sampleRate = params.sampleRate || 44100; + var sampleRate = audioContext.sampleRate; var numChannels = params.numChannels || 2; // params.decayTime is the -60dB fade time. We let it go 50% longer to get to -90dB. var totalTime = params.decayTime * 1.5; From 5c76f2b9a28a7456e8fd02a0ea7b7f9f09fde34a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 9 Oct 2023 22:30:34 +0200 Subject: [PATCH 165/175] bump superdough to 0.9.10 --- packages/superdough/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/package.json b/packages/superdough/package.json index 387749c8..0f862c03 100644 --- a/packages/superdough/package.json +++ b/packages/superdough/package.json @@ -1,6 +1,6 @@ { "name": "superdough", - "version": "0.9.9", + "version": "0.9.10", "description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.", "main": "index.mjs", "type": "module", From 57b166d13a9523350d42c5e682b0233678365816 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 9 Oct 2023 22:49:38 +0200 Subject: [PATCH 166/175] fix: pitched sample as ir --- packages/superdough/superdough.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 1d615548..e3033afe 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -399,7 +399,7 @@ export const superdough = async (value, deadline, hapDuration) => { if (Array.isArray(sample)) { url = sample.data.samples[i % sample.data.samples.length]; } else if (typeof sample === 'object') { - url = Object.values(sample.data.samples)[i & Object.values(sample.data.samples).length]; + url = Object.values(sample.data.samples).flat()[i % Object.values(sample.data.samples).length]; } roomIR = await loadBuffer(url, ac, ir, 0); } From d7028252c2210939b1435d1aee5c9df84f4046ae Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 13 Oct 2023 12:55:31 +0200 Subject: [PATCH 167/175] vite-vanilla-repl readme fix --- packages/core/examples/vite-vanilla-repl-cm6/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/examples/vite-vanilla-repl-cm6/README.md b/packages/core/examples/vite-vanilla-repl-cm6/README.md index 70d18e09..4d99d4e6 100644 --- a/packages/core/examples/vite-vanilla-repl-cm6/README.md +++ b/packages/core/examples/vite-vanilla-repl-cm6/README.md @@ -3,6 +3,6 @@ This folder demonstrates how to set up a strudel repl using vite and vanilla JS + codemirror. Run it using: ```sh -npm i -npm run dev +pnpm i +pnpm dev ``` From 6b5de5fec85f5995c4387e6ad9480fcb2b07c1ec Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 17 Oct 2023 01:33:51 -0400 Subject: [PATCH 168/175] fixed --- packages/core/signal.mjs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index d0db0be9..f404f000 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -160,7 +160,12 @@ export const __chooseWith = (pat, xs) => { if (xs.length == 0) { return silence; } - return pat.range(0, xs.length).fmap((i) => xs[Math.floor(i)]); + + return pat.range(0, xs.length).fmap((i) => { + const key = Math.min(Math.max(Math.floor(i), 0), xs.length - 1); + console.log({ key }); + return xs[key]; + }); }; /** * Choose from the list of values (or patterns of values) using the given @@ -179,6 +184,8 @@ export const chooseWith = (pat, xs) => { * @param {Pattern} pat * @param {*} xs * @returns {Pattern} + * @example + * note("c g g d f").s(chooseInWith(slider(1, 0, 1), ["sawtooth", "triangle", "bd hh sd hh"])) */ export const chooseInWith = (pat, xs) => { return __chooseWith(pat, xs).innerJoin(); From d3edc62fc7178eef9f22a116d05244ef368c3d88 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 17 Oct 2023 21:31:11 -0400 Subject: [PATCH 169/175] document function --- packages/core/signal.mjs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index f404f000..8bf3c911 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -163,7 +163,6 @@ export const __chooseWith = (pat, xs) => { return pat.range(0, xs.length).fmap((i) => { const key = Math.min(Math.max(Math.floor(i), 0), xs.length - 1); - console.log({ key }); return xs[key]; }); }; @@ -173,6 +172,8 @@ export const __chooseWith = (pat, xs) => { * @param {Pattern} pat * @param {*} xs * @returns {Pattern} + * @example + * note("c g g d f").s(chooseWith(slider(0, 0, 1), ["sawtooth", "triangle", "bd hh sd hh"])) */ export const chooseWith = (pat, xs) => { return __chooseWith(pat, xs).outerJoin(); @@ -184,8 +185,6 @@ export const chooseWith = (pat, xs) => { * @param {Pattern} pat * @param {*} xs * @returns {Pattern} - * @example - * note("c g g d f").s(chooseInWith(slider(1, 0, 1), ["sawtooth", "triangle", "bd hh sd hh"])) */ export const chooseInWith = (pat, xs) => { return __chooseWith(pat, xs).innerJoin(); From 912a661c042bf620995adea21ab6e9cf882e4f3c Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 17 Oct 2023 23:03:14 -0400 Subject: [PATCH 170/175] fixed example test failure --- packages/core/signal.mjs | 2 +- test/__snapshots__/examples.test.mjs.snap | 25 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 8bf3c911..d1408809 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -173,7 +173,7 @@ export const __chooseWith = (pat, xs) => { * @param {*} xs * @returns {Pattern} * @example - * note("c g g d f").s(chooseWith(slider(0, 0, 1), ["sawtooth", "triangle", "bd hh sd hh"])) + * note("c2 g2!2 d2 f1").s(chooseWith(sine.fast(2), ["sawtooth", "triangle", "bd:6"])) */ export const chooseWith = (pat, xs) => { return __chooseWith(pat, xs).outerJoin(); diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index f351a5a0..ed0249f3 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1071,6 +1071,31 @@ exports[`runs examples > example "chooseCycles" example index 1 1`] = ` ] `; +exports[`runs examples > example "chooseWith" example index 0 1`] = ` +[ + "[ 0/1 → 1/5 | note:c2 s:bd n:6 ]", + "[ 1/5 → 2/5 | note:g2 s:sawtooth ]", + "[ 2/5 → 3/5 | note:g2 s:triangle ]", + "[ 3/5 → 4/5 | note:d2 s:bd n:6 ]", + "[ 4/5 → 1/1 | note:f1 s:sawtooth ]", + "[ 1/1 → 6/5 | note:c2 s:bd n:6 ]", + "[ 6/5 → 7/5 | note:g2 s:sawtooth ]", + "[ 7/5 → 8/5 | note:g2 s:triangle ]", + "[ 8/5 → 9/5 | note:d2 s:bd n:6 ]", + "[ 9/5 → 2/1 | note:f1 s:sawtooth ]", + "[ 2/1 → 11/5 | note:c2 s:bd n:6 ]", + "[ 11/5 → 12/5 | note:g2 s:sawtooth ]", + "[ 12/5 → 13/5 | note:g2 s:triangle ]", + "[ 13/5 → 14/5 | note:d2 s:bd n:6 ]", + "[ 14/5 → 3/1 | note:f1 s:sawtooth ]", + "[ 3/1 → 16/5 | note:c2 s:bd n:6 ]", + "[ 16/5 → 17/5 | note:g2 s:sawtooth ]", + "[ 17/5 → 18/5 | note:g2 s:triangle ]", + "[ 18/5 → 19/5 | note:d2 s:bd n:6 ]", + "[ 19/5 → 4/1 | note:f1 s:sawtooth ]", +] +`; + exports[`runs examples > example "chop" example index 0 1`] = ` [ "[ 0/1 → 1/1 | s:rhodes begin:0.75 end:1 speed:0.25 unit:c ]", From d9db5263e8c665ed62da4b0ef544cd2c46d517f6 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 20 Oct 2023 11:18:40 +0200 Subject: [PATCH 171/175] add recipes --- website/src/pages/recipes/recipes.mdx | 313 ++++++++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 website/src/pages/recipes/recipes.mdx diff --git a/website/src/pages/recipes/recipes.mdx b/website/src/pages/recipes/recipes.mdx new file mode 100644 index 00000000..5e5ae9bf --- /dev/null +++ b/website/src/pages/recipes/recipes.mdx @@ -0,0 +1,313 @@ +--- +title: Recipes +layout: ../../layouts/MainLayout.astro +--- + +import { MiniRepl } from '../../docs/MiniRepl'; + +# Recipes + +This page shows possible ways to achieve common (or not so common) musical goals. +There are often many ways to do a thing and there is no right or wrong. +The fun part is that each representation will give you different impulses when improvising. + +## Arpeggios + +An arpeggio is when the notes of a chord are played in sequence. +We can either write the notes by hand: + + + +...or use scales: + + + +...or chord symbols: + + + +...using off: + + + +## Chopping Breaks + +A sample can be looped and chopped like this: + + + +This fits the break into 8 cycles + chops it in 16 pieces. +The chops are not audible yet, because we're not doing any manipulation. +Let's add randmized doubling + reversing: + + + +If we want to specify the order of samples, we can replace `chop` with `slice`: + +") + .cut(1).rarely(ply(2))`} + punchcard +/> + +If we use `splice` instead of `slice`, the speed adjusts to the duration of the event: + +") + .cut(1).rarely(ply(2))`} + punchcard +/> + +Note that we don't need `fit`, because `splice` will do that by itself. + +## Filter Envelopes + +A minimal filter envelope looks like this: + + d2") + .s("sawtooth") + .lpf(400).lpa(.2).lpenv(4) + .scope()`} +/> + +We can flip the envelope by setting `lpenv` negative + add some resonance `lpq`: + + d2") + .s("sawtooth").lpq(8) + .lpf(400).lpa(.2).lpenv(-4) + .scope()`} +/> + +## Layering Sounds + +We can layer sounds by separating them with ",": + +") +.s("sawtooth, square") // <------ +.scope()`} +/> + +We can control the gain of individual sounds like this: + +") +.s("sawtooth, square:0:.5") // <--- "name:number:gain" +.scope()`} +/> + +For more control over each voice, we can use `layer`: + +").layer( + x=>x.s("sawtooth").vib(4), + x=>x.s("square").add(note(12)) +).scope()`} +/> + +Here, we give the sawtooth a vibrato and the square is moved an octave up. +With `layer`, you can use any pattern method available on each voice, so sky is the limit.. + +## Oscillator Detune + +We can fatten a sound by adding a detuned version to itself: + +") +.add(note("0,.1")) // <------ chorus +.s("sawtooth").scope()`} + punchcard +/> + +Try out different values, or add another voice! + +## Polyrhythms + +Here is a simple example of a polyrhythm: + + + +A polyrhythm is when 2 different tempos happen at the same time. + +## Polymeter + +This is a polymeter: + +,").fast(2)`} punchcard /> + +A polymeter is when 2 different bar lengths play at the same tempo. + +## Phasing + +This is a phasing: + +*[6,6.1]").piano()`} punchcard /> + +Phasing happens when the same sequence plays at slightly different tempos. + +## Running through samples + +Using `run` with `n`, we can rush through a sample bank: + + + +This works great with sample banks that contain similar sounds, like in this case different recordings of a tabla. +Often times, you'll hear the beginning of the phrase not where the pattern begins. +In this case, I hear the beginning at the third sample, which can be accounted for with `early`. + + + +Let's add some randomness: + + + +## Tape Warble + +We can emulate a pitch warbling effect like this: + + + +## Sound Duration + +There are a number of ways to change the sound duration. Using clip: + +/2")`} +/> + +The value of clip is relative to the duration of each event. +We can also create overlaps using release: + +/2")`} +/> + +This will smoothly fade out each sound for the given number of seconds. +We could also make the notes shorter with decay / sustain: + +/2").sustain(0)`} +/> + +For now, there is a limitation where decay values that exceed the event duration may cause little cracks, so use higher numbers with caution.. + +When using samples, we also have `.end` to cut relative to the sample length: + +")`} /> + +Compare that to clip: + +")`} /> + +or decay / sustain + +").sustain(0)`} /> + +## Wavetable Synthesis + +You can loop a sample with `loop` / `loopEnd`: + +").s("bd").loop(1).loopEnd(.05)`} /> + +This allows us to play the first 5% of the bass drum as a synth! +To simplify loading wavetables, any sample that starts with `wt_` will be looped automatically: + + + +Running through different wavetables can also give interesting variations: + + + +...adding a filter envelope + reverb: + + + \ No newline at end of file From 7b8a35a311e490170ac2912a943f50646bfdf808 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 20 Oct 2023 11:18:47 +0200 Subject: [PATCH 172/175] add understand cycles --- website/src/pages/understand/cycles.mdx | 130 ++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 website/src/pages/understand/cycles.mdx diff --git a/website/src/pages/understand/cycles.mdx b/website/src/pages/understand/cycles.mdx new file mode 100644 index 00000000..a66794be --- /dev/null +++ b/website/src/pages/understand/cycles.mdx @@ -0,0 +1,130 @@ +--- +title: Understanding Cycles +layout: ../../layouts/MainLayout.astro +--- + +import { MiniRepl } from '../../docs/MiniRepl'; +import { PitchSlider } from '../../components/PitchSlider'; +import Box from '@components/Box.astro'; + +# Understanding Cycles + +The concept of cycles is very central to be able to understand how Strudel works. +Strudel's mother language, TidalCycles, even has it in its name. + +## Cycles and BPM + +In most music software, the unit BPM (beats per minute) is used to set the tempo. +Strudel expresses tempo as CPS (cycles per second), with a default of 1CPS: + + + +Here we can hear the 1CPS in action: The kick repeats once per second like a clock. +We could say 1CPS = 1BPS (beats per second) = 60BPM. Let's add another kick: + + + +Now we have 2 kicks per second, but the whole pattern still plays at 1CPS. +In terms of BPM, most musicians would tell you this is playing at 120bpm. +What about this one: + + + +Because the second sound is now a hihat, the tempo feels slower again. +This brings us to an important realization: + + + +Tempo is based on perception. +The choice of sounds also has an impact on the tempo feel. +This is why the same CPS can produce different perceived tempos. + + + +## Setting CPM + +If you're familiar with BPM, you can use the `cpm` method to set the tempo in cycles per minute: + + + +If you want to add more beats per cycle, you might want to divide the cpm: + + + +Or using 2 beats per cycle: + + + + + +To set a specific bpm, use `.cpm(bpm/bpc)` + +- bpm: the target beats per minute +- bpc: the number of perceived beats per cycle + + + +## Cycles and Bars + +Also in most music software, multiple beats form a bar (or measure). +The so called time signature specifies how many beats are in each bar. +In many types of music, it is common to use 4 beats per bar, also known as 4/4 time. +Many music programs use it as a default. + +Strudel does not a have concept of bars or measures, there are only cycles. +How you use them is up to you. Above, we've had this example: + + + +This could be interpreted as 4/4 time with a tempo of 110bpm. +We could write out multiple bars like this: + +\`).cpm(110/4)`} +/> + +Instead of writing out each bar separately, we could express this much shorter: + +>,hh*4").cpm(110/2)`} /> + +Here we can see that thinking in cycles rather than bars simplifies things a lot! +These types of simplifications work because of the repetitive nature of rhythm. +In computational terms, you could say the former notation has a lot of redundancy. + +## Time Signatures + +To get a time signature, just change the number of elements per bar. Here is a rhythm with 7 beats: + + + +or with 5: + +*5")`} /> + +We could also write multiple bars with different time signatures: + +\`).cpm(110*2)`} +/> + +Here we switch between 3/4 and 4/4, keeping the same tempo. + +If we don't specify the length, we get what's called a metric modulation: + +\`).cpm(110/2)`} +/> + +Now the 3 elements get the same time as the 4 elements, which is why the tempo changes. From f51c01dc88fed3d419958b2cbd2349b37f6b8598 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 20 Oct 2023 11:18:54 +0200 Subject: [PATCH 173/175] move stuff around --- website/src/config.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/website/src/config.ts b/website/src/config.ts index ba9b0666..0d774a5a 100644 --- a/website/src/config.ts +++ b/website/src/config.ts @@ -70,12 +70,10 @@ export const SIDEBAR: Sidebar = { { text: 'MIDI & OSC', link: 'learn/input-output' }, ], More: [ + { text: 'Recipes', link: 'recipes/recipes' }, { text: 'Mini-Notation', link: 'learn/mini-notation' }, - { text: 'Coding syntax', link: 'learn/code' }, { text: 'Offline', link: 'learn/pwa' }, { text: 'Patterns', link: 'technical-manual/patterns' }, - { text: 'Pattern Alignment', link: 'technical-manual/alignment' }, - { text: 'Strudel vs Tidal', link: 'learn/strudel-vs-tidal' }, { text: 'Music metadata', link: 'learn/metadata' }, { text: 'CSound', link: 'learn/csound' }, ], @@ -89,7 +87,13 @@ export const SIDEBAR: Sidebar = { { text: 'Accumulation', link: 'learn/accumulation' }, { text: 'Tonal Functions', link: 'learn/tonal' }, ], - Understand: [{ text: 'Pitch', link: 'understand/pitch' }], + Understand: [ + { text: 'Coding syntax', link: 'learn/code' }, + { text: 'Pitch', link: 'understand/pitch' }, + { text: 'Cycles', link: 'understand/cycles' }, + { text: 'Pattern Alignment', link: 'technical-manual/alignment' }, + { text: 'Strudel vs Tidal', link: 'learn/strudel-vs-tidal' }, + ], Development: [ { text: 'REPL', link: 'technical-manual/repl' }, { text: 'Sounds', link: 'technical-manual/sounds' }, From 80c98b6a35f94a4041ade36cbe345d35612109e5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 20 Oct 2023 11:23:38 +0200 Subject: [PATCH 174/175] fix: loud example --- website/src/pages/recipes/recipes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/recipes/recipes.mdx b/website/src/pages/recipes/recipes.mdx index 5e5ae9bf..2e4765a8 100644 --- a/website/src/pages/recipes/recipes.mdx +++ b/website/src/pages/recipes/recipes.mdx @@ -282,7 +282,7 @@ or decay / sustain You can loop a sample with `loop` / `loopEnd`: -").s("bd").loop(1).loopEnd(.05)`} /> +").s("bd").loop(1).loopEnd(.05).gain(.2)`} /> This allows us to play the first 5% of the bass drum as a synth! To simplify loading wavetables, any sample that starts with `wt_` will be looped automatically: From 2cc60c6ee2b97e66444aa430ac5cc33b9ea58b11 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 20 Oct 2023 11:28:35 +0200 Subject: [PATCH 175/175] format --- website/src/pages/recipes/recipes.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/src/pages/recipes/recipes.mdx b/website/src/pages/recipes/recipes.mdx index 2e4765a8..22617e4b 100644 --- a/website/src/pages/recipes/recipes.mdx +++ b/website/src/pages/recipes/recipes.mdx @@ -303,11 +303,10 @@ note("c2*8").s("wt_dbass").n(run(8))`} ...adding a filter envelope + reverb: - \ No newline at end of file +/>