From 7da75544933d9f5c4b5a20ae7fad611171955e37 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Fri, 15 Dec 2023 11:32:23 -0700 Subject: [PATCH 01/93] it works --- packages/superdough/helpers.mjs | 16 ++++++++++++++++ packages/superdough/sampler.mjs | 5 +++-- packages/superdough/synth.mjs | 11 +++++++++-- src-tauri/src/oscbridge.rs | 4 ++-- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index d87ea94dc..91bc17bca 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -89,6 +89,22 @@ export function getCompressor(ac, threshold, ratio, knee, attack, release) { return new DynamicsCompressorNode(ac, options); } +const adsrmin = 0.001; +export const getADSRDefaults = ( + a, + d, + s, + r, + def = { attack: adsrmin, decay: adsrmin, sustain: 1, release: adsrmin }, +) => { + console.log(a, d, s, r); + if (a == null && d == null && s == null && r == null) { + return def; + } + const sustain = s ?? ((a != null && d == null) || (a == null && d == null)) ? def.sustain : adsrmin; + return { attack: a ?? adsrmin, decay: d ?? adsrmin, sustain, release: r ?? adsrmin }; +}; + export function createFilter( context, type, diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 6df5a6b68..e4ead52ea 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -1,6 +1,6 @@ import { noteToMidi, valueToMidi, nanFallback } from './util.mjs'; import { getAudioContext, registerSound } from './index.mjs'; -import { getEnvelope } from './helpers.mjs'; +import { getADSRDefaults, getEnvelope } from './helpers.mjs'; import { logger } from './logger.mjs'; const bufferCache = {}; // string: Promise @@ -251,7 +251,8 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { 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; + + const { attack, decay, sustain, release } = getADSRDefaults(value.attack, value.decay, value.sustain, value.release); //const soundfont = getSoundfontKey(s); const time = t + nudge; diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index edc3c01e1..a715947ec 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -1,6 +1,6 @@ import { midiToFreq, noteToMidi } from './util.mjs'; import { registerSound, getAudioContext } from './superdough.mjs'; -import { gainNode, getEnvelope, getExpEnvelope } from './helpers.mjs'; +import { gainNode, getADSRDefaults, getEnvelope, getExpEnvelope } from './helpers.mjs'; import { getNoiseMix, getNoiseOscillator } from './noise.mjs'; const mod = (freq, range = 1, type = 'sine') => { @@ -30,7 +30,14 @@ export function registerSynthSounds() { 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 } = value; + const { attack, decay, sustain, release } = getADSRDefaults( + value.attack, + value.decay, + value.sustain, + value.release, + { attack: 0.001, decay: 0.05, sustain: 0.6, release: 0.01 }, + ); + console.log({ attack, decay, sustain, release }); let sound; if (waveforms.includes(s)) { diff --git a/src-tauri/src/oscbridge.rs b/src-tauri/src/oscbridge.rs index 6060cd9dc..8148622e1 100644 --- a/src-tauri/src/oscbridge.rs +++ b/src-tauri/src/oscbridge.rs @@ -53,8 +53,8 @@ pub fn init( /* ........................................................... Open OSC Ports ............................................................*/ - let sock = UdpSocket::bind("127.0.0.1:57122").unwrap(); - let to_addr = String::from("127.0.0.1:57120"); + let sock = UdpSocket::bind("169.254.248.82:57122").unwrap(); + let to_addr = String::from("169.254.180.239:57120"); sock.set_nonblocking(true).unwrap(); sock.connect(to_addr).expect("could not connect to OSC address"); From 9663c2ec858cc37ede5211d59297b8b849761d84 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Fri, 15 Dec 2023 12:16:28 -0700 Subject: [PATCH 02/93] fileter envelopes --- packages/superdough/helpers.mjs | 19 +++++++---------- packages/superdough/sampler.mjs | 4 ++-- packages/superdough/superdough.mjs | 33 ++++++++++++++++++------------ packages/superdough/synth.mjs | 14 +++++-------- 4 files changed, 34 insertions(+), 36 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 91bc17bca..94bdc11f0 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -88,21 +88,16 @@ export function getCompressor(ac, threshold, ratio, knee, attack, release) { }; return new DynamicsCompressorNode(ac, options); } - -const adsrmin = 0.001; -export const getADSRDefaults = ( - a, - d, - s, - r, - def = { attack: adsrmin, decay: adsrmin, sustain: 1, release: adsrmin }, -) => { +const envmin = 0.001; +export const getADSRValues = (params, defaultValues = [envmin, envmin, 1, envmin]) => { + const [a, d, s, r] = params; + const [defA, defD, defS, defR] = defaultValues; console.log(a, d, s, r); if (a == null && d == null && s == null && r == null) { - return def; + return defaultValues; } - const sustain = s ?? ((a != null && d == null) || (a == null && d == null)) ? def.sustain : adsrmin; - return { attack: a ?? adsrmin, decay: d ?? adsrmin, sustain, release: r ?? adsrmin }; + const sustain = s != null ? s : (a != null && d == null) || (a == null && d == null) ? defS : envmin; + return [a ?? envmin, d ?? envmin, sustain, r ?? envmin]; }; export function createFilter( diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index e4ead52ea..fb1dfda98 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -1,6 +1,6 @@ import { noteToMidi, valueToMidi, nanFallback } from './util.mjs'; import { getAudioContext, registerSound } from './index.mjs'; -import { getADSRDefaults, getEnvelope } from './helpers.mjs'; +import { getADSRValues, getEnvelope } from './helpers.mjs'; import { logger } from './logger.mjs'; const bufferCache = {}; // string: Promise @@ -252,7 +252,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { const ac = getAudioContext(); // destructure adsr here, because the default should be different for synths and samples - const { attack, decay, sustain, release } = getADSRDefaults(value.attack, value.decay, value.sustain, value.release); + const [attack, decay, sustain, release] = getADSRValues([value.attack, value.decay, value.sustain, value.release]); //const soundfont = getSoundfontKey(s); const time = t + nudge; diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 3be97615f..036e63ba8 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -9,7 +9,7 @@ import './reverb.mjs'; import './vowel.mjs'; import { clamp, nanFallback } from './util.mjs'; import workletsUrl from './worklets.mjs?url'; -import { createFilter, gainNode, getCompressor } from './helpers.mjs'; +import { createFilter, gainNode, getADSRValues, getCompressor } from './helpers.mjs'; import { map } from 'nanostores'; import { logger } from './logger.mjs'; import { loadBuffer } from './sampler.mjs'; @@ -269,26 +269,16 @@ export const superdough = async (value, deadline, hapDuration) => { // low pass cutoff, lpenv, - lpattack = 0.01, - lpdecay = 0.01, - lpsustain = 1, - lprelease = 0.01, resonance = 1, // high pass hpenv, hcutoff, - hpattack = 0.01, - hpdecay = 0.01, - hpsustain = 1, - hprelease = 0.01, + hresonance = 1, // band pass bpenv, bandf, - bpattack = 0.01, - bpdecay = 0.01, - bpsustain = 1, - bprelease = 0.01, + bandq = 1, channels = [1, 2], //phaser @@ -322,6 +312,7 @@ export const superdough = async (value, deadline, hapDuration) => { compressorAttack, compressorRelease, } = value; + gain = nanFallback(gain, 1); //music programs/audio gear usually increments inputs/outputs from 1, so imitate that behavior @@ -366,7 +357,15 @@ export const superdough = async (value, deadline, hapDuration) => { // gain stage chain.push(gainNode(gain)); + const filterEnvDefaults = [0.01, 0.01, 1, 0.01]; + if (cutoff !== undefined) { + const [lpattack, lpdecay, lpsustain, lprelease] = getADSRValues( + [value.lpattack, value.lpdecay, value.lpsustain, value.lprelease], + filterEnvDefaults, + ); + console.log(lpattack, 'atta'); + let lp = () => createFilter( ac, @@ -389,6 +388,10 @@ export const superdough = async (value, deadline, hapDuration) => { } if (hcutoff !== undefined) { + const [hpattack, hpdecay, hpsustain, hprelease] = getADSRValues( + [value.hpattack, value.hpdecay, value.hpsustain, value.hprelease], + filterEnvDefaults, + ); let hp = () => createFilter( ac, @@ -411,6 +414,10 @@ export const superdough = async (value, deadline, hapDuration) => { } if (bandf !== undefined) { + const [bpattack, bpdecay, bpsustain, bprelease] = getADSRValues( + [value.bpattack, value.bpdecay, value.bpsustain, value.bprelease], + filterEnvDefaults, + ); let bp = () => createFilter( ac, diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index a715947ec..5977e9acf 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -1,6 +1,6 @@ import { midiToFreq, noteToMidi } from './util.mjs'; import { registerSound, getAudioContext } from './superdough.mjs'; -import { gainNode, getADSRDefaults, getEnvelope, getExpEnvelope } from './helpers.mjs'; +import { gainNode, getADSRValues, getEnvelope, getExpEnvelope } from './helpers.mjs'; import { getNoiseMix, getNoiseOscillator } from './noise.mjs'; const mod = (freq, range = 1, type = 'sine') => { @@ -29,15 +29,11 @@ export function registerSynthSounds() { registerSound( s, (t, value, onended) => { - // destructure adsr here, because the default should be different for synths and samples - const { attack, decay, sustain, release } = getADSRDefaults( - value.attack, - value.decay, - value.sustain, - value.release, - { attack: 0.001, decay: 0.05, sustain: 0.6, release: 0.01 }, + const defaultADSRValues = [0.001, 0.05, 0.6, 0.01]; + const [attack, decay, sustain, release] = getADSRValues( + [value.attack, value.decay, value.sustain, value.release], + defaultADSRValues, ); - console.log({ attack, decay, sustain, release }); let sound; if (waveforms.includes(s)) { From 88f677e9100276597406793a07e271895b6ca3f5 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Fri, 15 Dec 2023 18:54:04 -0500 Subject: [PATCH 03/93] fix envelope behavior --- packages/superdough/helpers.mjs | 2 +- packages/superdough/superdough.mjs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index d75f5b14d..d628d8513 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -77,7 +77,7 @@ export const getParamADSR = (param, attack, decay, sustain, release, min, max, b param.setValueAtTime(min, begin); param.linearRampToValueAtTime(peak, begin + attack); param.linearRampToValueAtTime(sustainLevel, begin + attack + decay); - param.setValueAtTime(sustainLevel, end); + // param.setValueAtTime(sustainLevel, end); param.linearRampToValueAtTime(min, end + Math.max(release, 0.1)); }; diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 036e63ba8..9a35c2771 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -364,7 +364,6 @@ export const superdough = async (value, deadline, hapDuration) => { [value.lpattack, value.lpdecay, value.lpsustain, value.lprelease], filterEnvDefaults, ); - console.log(lpattack, 'atta'); let lp = () => createFilter( From 96e0cce2d267d797e10f68d9d254d7325de0ed46 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Sat, 16 Dec 2023 00:30:35 -0500 Subject: [PATCH 04/93] improve response --- packages/superdough/helpers.mjs | 34 ++++++++++++------------------ packages/superdough/superdough.mjs | 31 ++++++++++++--------------- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index d628d8513..1bc1a8783 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -71,14 +71,17 @@ export const getADSR = (attack, decay, sustain, release, velocity, begin, end) = }; export const getParamADSR = (param, attack, decay, sustain, release, min, max, begin, end) => { + // let phase = begin; const range = max - min; const peak = min + range; const sustainLevel = min + sustain * range; param.setValueAtTime(min, begin); - param.linearRampToValueAtTime(peak, begin + attack); - param.linearRampToValueAtTime(sustainLevel, begin + attack + decay); - // param.setValueAtTime(sustainLevel, end); - param.linearRampToValueAtTime(min, end + Math.max(release, 0.1)); + param.exponentialRampToValueAtTime(peak, begin + attack); + param.exponentialRampToValueAtTime(sustainLevel, begin + attack + decay); + //stop current envelope ramp at event end, and begin release ramp + console.log(param); + param.cancelAndHoldAtTime(end); + param.exponentialRampToValueAtTime(min, end + Math.max(release, 0.1)); }; export function getCompressor(ac, threshold, ratio, knee, attack, release) { @@ -91,11 +94,14 @@ export function getCompressor(ac, threshold, ratio, knee, attack, release) { }; return new DynamicsCompressorNode(ac, options); } + +// changes the default values of the envelope based on what parameters the user has defined +// so it behaves more like you would expect/familiar as other synthesis tools +// ex: sound(val).decay(val) will behave as a decay only envelope. sound(val).attack(val).decay(val) will behave like an "ad" env, etc. const envmin = 0.001; export const getADSRValues = (params, defaultValues = [envmin, envmin, 1, envmin]) => { const [a, d, s, r] = params; const [defA, defD, defS, defR] = defaultValues; - console.log(a, d, s, r); if (a == null && d == null && s == null && r == null) { return defaultValues; } @@ -103,20 +109,8 @@ export const getADSRValues = (params, defaultValues = [envmin, envmin, 1, envmin return [a ?? envmin, d ?? envmin, sustain, r ?? envmin]; }; -export function createFilter( - context, - type, - frequency, - Q, - attack, - decay, - sustain, - release, - fenv, - start, - end, - fanchor = 0.5, -) { +export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fenv, start, end, fanchor = 0.5) { + const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], [0.01, 0.01, 1, 0.01]); const filter = context.createBiquadFilter(); filter.type = type; filter.Q.value = Q; @@ -129,8 +123,6 @@ export function createFilter( const min = clamp(2 ** -offset * frequency, 0, 20000); const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000); - // console.log('min', min, 'max', max); - getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end); return filter; } diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 9a35c2771..b4c16a532 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -9,7 +9,7 @@ import './reverb.mjs'; import './vowel.mjs'; import { clamp, nanFallback } from './util.mjs'; import workletsUrl from './worklets.mjs?url'; -import { createFilter, gainNode, getADSRValues, getCompressor } from './helpers.mjs'; +import { createFilter, gainNode, getCompressor } from './helpers.mjs'; import { map } from 'nanostores'; import { logger } from './logger.mjs'; import { loadBuffer } from './sampler.mjs'; @@ -269,16 +269,26 @@ export const superdough = async (value, deadline, hapDuration) => { // low pass cutoff, lpenv, + lpattack, + lpdecay, + lpsustain, + lprelease, resonance = 1, // high pass hpenv, hcutoff, - + hpattack, + hpdecay, + hpsustain, + hprelease, hresonance = 1, // band pass bpenv, bandf, - + bpattack, + bpdecay, + bpsustain, + bprelease, bandq = 1, channels = [1, 2], //phaser @@ -357,14 +367,7 @@ export const superdough = async (value, deadline, hapDuration) => { // gain stage chain.push(gainNode(gain)); - const filterEnvDefaults = [0.01, 0.01, 1, 0.01]; - if (cutoff !== undefined) { - const [lpattack, lpdecay, lpsustain, lprelease] = getADSRValues( - [value.lpattack, value.lpdecay, value.lpsustain, value.lprelease], - filterEnvDefaults, - ); - let lp = () => createFilter( ac, @@ -387,10 +390,6 @@ export const superdough = async (value, deadline, hapDuration) => { } if (hcutoff !== undefined) { - const [hpattack, hpdecay, hpsustain, hprelease] = getADSRValues( - [value.hpattack, value.hpdecay, value.hpsustain, value.hprelease], - filterEnvDefaults, - ); let hp = () => createFilter( ac, @@ -413,10 +412,6 @@ export const superdough = async (value, deadline, hapDuration) => { } if (bandf !== undefined) { - const [bpattack, bpdecay, bpsustain, bprelease] = getADSRValues( - [value.bpattack, value.bpdecay, value.bpsustain, value.bprelease], - filterEnvDefaults, - ); let bp = () => createFilter( ac, From 93a4efcf6d0ac943298d118de56a0203928c3003 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Sat, 16 Dec 2023 13:21:23 -0500 Subject: [PATCH 05/93] updated fontloader --- packages/soundfonts/fontloader.mjs | 12 +++++++-- packages/superdough/helpers.mjs | 43 +++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/packages/soundfonts/fontloader.mjs b/packages/soundfonts/fontloader.mjs index 017ba763c..b6c8c8b4b 100644 --- a/packages/soundfonts/fontloader.mjs +++ b/packages/soundfonts/fontloader.mjs @@ -1,5 +1,5 @@ import { noteToMidi, freqToMidi } from '@strudel.cycles/core'; -import { getAudioContext, registerSound, getEnvelope } from '@strudel.cycles/webaudio'; +import { getAudioContext, registerSound, getEnvelope, getADSRValues } from '@strudel.cycles/webaudio'; import gm from './gm.mjs'; let loadCache = {}; @@ -131,7 +131,15 @@ export function registerSoundfonts() { name, async (time, value, onended) => { const { n = 0 } = value; - const { attack = 0.001, decay = 0.001, sustain = 1, release = 0.001 } = value; + const [attack, decay, sustain, release] = getADSRValues([ + value.attack, + value.decay, + value.sustain, + value.release, + ]); + + console.log(attack, decay, sustain, release); + const font = fonts[n % fonts.length]; const ctx = getAudioContext(); const bufferSource = await getFontBufferSource(font, value, ctx); diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 1bc1a8783..e8c695b82 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -70,18 +70,41 @@ export const getADSR = (attack, decay, sustain, release, velocity, begin, end) = return gainNode; }; -export const getParamADSR = (param, attack, decay, sustain, release, min, max, begin, end) => { - // let phase = begin; +export const getParamADSR = ( + context, + param, + attack, + decay, + sustain, + release, + min, + max, + begin, + end, + //exponential works better for frequency modulations (such as filter cutoff) due to human ear perception + curve = 'exponential', +) => { + const ramp = curve === 'exponential' ? 'exponentialRampToValueAtTime' : 'linearRampToValueAtTime'; + let phase = begin; const range = max - min; const peak = min + range; - const sustainLevel = min + sustain * range; + param.setValueAtTime(min, begin); - param.exponentialRampToValueAtTime(peak, begin + attack); - param.exponentialRampToValueAtTime(sustainLevel, begin + attack + decay); - //stop current envelope ramp at event end, and begin release ramp - console.log(param); - param.cancelAndHoldAtTime(end); - param.exponentialRampToValueAtTime(min, end + Math.max(release, 0.1)); + phase += attack; + //attack + param[ramp](peak, phase); + phase += decay; + const sustainLevel = min + sustain * range; + //decay + param[ramp](sustainLevel, phase); + //this timeout can be replaced with cancelAndHoldAtTime once it is implemented in Firefox + setTimeout(() => { + //sustain at current value + param.cancelScheduledValues(0); + phase += Math.max(release, 0.1); + //release + param[ramp](min, phase); + }, (end - context.currentTime) * 1000); }; export function getCompressor(ac, threshold, ratio, knee, attack, release) { @@ -123,7 +146,7 @@ export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fe const min = clamp(2 ** -offset * frequency, 0, 20000); const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000); - getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end); + getParamADSR(context, filter.frequency, attack, decay, sustain, release, min, max, start, end); return filter; } From b5dc65d52a1a2550011beb5cb84419aff38135d1 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Sat, 16 Dec 2023 13:36:05 -0500 Subject: [PATCH 06/93] format --- packages/soundfonts/fontloader.mjs | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/soundfonts/fontloader.mjs b/packages/soundfonts/fontloader.mjs index b6c8c8b4b..f8b10d384 100644 --- a/packages/soundfonts/fontloader.mjs +++ b/packages/soundfonts/fontloader.mjs @@ -137,9 +137,6 @@ export function registerSoundfonts() { value.sustain, value.release, ]); - - console.log(attack, decay, sustain, release); - const font = fonts[n % fonts.length]; const ctx = getAudioContext(); const bufferSource = await getFontBufferSource(font, value, ctx); From fe60f3401510fa7a51cfcd424989448d7e4bafed Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Sun, 17 Dec 2023 12:13:05 -0500 Subject: [PATCH 07/93] removed accidental file commit --- src-tauri/src/oscbridge.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/oscbridge.rs b/src-tauri/src/oscbridge.rs index 8148622e1..6060cd9dc 100644 --- a/src-tauri/src/oscbridge.rs +++ b/src-tauri/src/oscbridge.rs @@ -53,8 +53,8 @@ pub fn init( /* ........................................................... Open OSC Ports ............................................................*/ - let sock = UdpSocket::bind("169.254.248.82:57122").unwrap(); - let to_addr = String::from("169.254.180.239:57120"); + let sock = UdpSocket::bind("127.0.0.1:57122").unwrap(); + let to_addr = String::from("127.0.0.1:57120"); sock.set_nonblocking(true).unwrap(); sock.connect(to_addr).expect("could not connect to OSC address"); From d7fae2620e2ce87b01079537bc45a195e4f0a3c5 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 00:21:14 -0500 Subject: [PATCH 08/93] create release audio param method, make volume envelopes consistant --- packages/superdough/helpers.mjs | 42 +++++++++++++++++++++------------ packages/superdough/synth.mjs | 2 +- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index e8c695b82..011feb256 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -1,6 +1,27 @@ import { getAudioContext } from './superdough.mjs'; import { clamp } from './util.mjs'; +AudioParam.prototype.setRelease = function (startTime, endTime, endValue, curve = 'linear') { + const ctx = getAudioContext(); + const ramp = curve === 'exponential' ? 'exponentialRampToValueAtTime' : 'linearRampToValueAtTime'; + const param = this; + if (AudioParam.prototype.cancelAndHoldAtTime == null) { + //this replicates cancelAndHoldAtTime behavior for Firefox + setTimeout(() => { + //sustain at current value + const currValue = param.value; + param.cancelScheduledValues(0); + param.setValueAtTime(currValue, 0); + //release + param[ramp](endValue, endTime); + }, (startTime - ctx.currentTime) * 1000); + } else { + param.cancelAndHoldAtTime(startTime); + //release + param[ramp](endValue, endTime); + } +}; + export function gainNode(value) { const node = getAudioContext().createGain(); node.gain.value = value; @@ -21,13 +42,10 @@ export const getEnvelope = (attack, decay, sustain, release, velocity, begin) => return { node: gainNode, stop: (t) => { - // to make sure the release won't begin before sustain is reached - phase = Math.max(t, phase); - // see https://github.com/tidalcycles/strudel/issues/522 - gainNode.gain.setValueAtTime(sustainLevel, phase); - phase += release; - gainNode.gain.linearRampToValueAtTime(0, phase); // release - return phase; + const endTime = t + release; + gainNode.gain.setRelease(t, endTime, 0); + // helps prevent pops from overlapping sounds + return endTime - 0.01; }, }; }; @@ -97,14 +115,8 @@ export const getParamADSR = ( const sustainLevel = min + sustain * range; //decay param[ramp](sustainLevel, phase); - //this timeout can be replaced with cancelAndHoldAtTime once it is implemented in Firefox - setTimeout(() => { - //sustain at current value - param.cancelScheduledValues(0); - phase += Math.max(release, 0.1); - //release - param[ramp](min, phase); - }, (end - context.currentTime) * 1000); + phase += Math.max(release, 0.1); + param.setRelease(end, phase, min, curve); }; export function getCompressor(ac, threshold, ratio, knee, attack, release) { diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 74255dbf9..3d93b8cd4 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -42,7 +42,7 @@ export function registerSynthSounds() { let { density } = value; sound = getNoiseOscillator(s, t, density); } - + console.log(sound); let { node: o, stop, triggerRelease } = sound; // turn down From 34ba81a84119b557f5b8e8eeb6ece9da7ef277a4 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 00:25:56 -0500 Subject: [PATCH 09/93] fixed test complaint --- packages/superdough/helpers.mjs | 38 +++++++++++++++++---------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 011feb256..a9d5a05a6 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -1,26 +1,28 @@ import { getAudioContext } from './superdough.mjs'; import { clamp } from './util.mjs'; -AudioParam.prototype.setRelease = function (startTime, endTime, endValue, curve = 'linear') { - const ctx = getAudioContext(); - const ramp = curve === 'exponential' ? 'exponentialRampToValueAtTime' : 'linearRampToValueAtTime'; - const param = this; - if (AudioParam.prototype.cancelAndHoldAtTime == null) { - //this replicates cancelAndHoldAtTime behavior for Firefox - setTimeout(() => { - //sustain at current value - const currValue = param.value; - param.cancelScheduledValues(0); - param.setValueAtTime(currValue, 0); +if (AudioParam != null) { + AudioParam.prototype.setRelease = function (startTime, endTime, endValue, curve = 'linear') { + const ctx = getAudioContext(); + const ramp = curve === 'exponential' ? 'exponentialRampToValueAtTime' : 'linearRampToValueAtTime'; + const param = this; + if (AudioParam.prototype.cancelAndHoldAtTime == null) { + //this replicates cancelAndHoldAtTime behavior for Firefox + setTimeout(() => { + //sustain at current value + const currValue = param.value; + param.cancelScheduledValues(0); + param.setValueAtTime(currValue, 0); + //release + param[ramp](endValue, endTime); + }, (startTime - ctx.currentTime) * 1000); + } else { + param.cancelAndHoldAtTime(startTime); //release param[ramp](endValue, endTime); - }, (startTime - ctx.currentTime) * 1000); - } else { - param.cancelAndHoldAtTime(startTime); - //release - param[ramp](endValue, endTime); - } -}; + } + }; +} export function gainNode(value) { const node = getAudioContext().createGain(); From f6d9ad51c62bc478bc2947509afcc0e064e8a489 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 01:44:34 -0500 Subject: [PATCH 10/93] trying to fix divergent firefox behavior --- packages/superdough/helpers.mjs | 56 ++++++++++++++++----------------- packages/superdough/synth.mjs | 5 +-- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index a9d5a05a6..bcc92cddc 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -1,28 +1,25 @@ import { getAudioContext } from './superdough.mjs'; import { clamp } from './util.mjs'; -if (AudioParam != null) { - AudioParam.prototype.setRelease = function (startTime, endTime, endValue, curve = 'linear') { - const ctx = getAudioContext(); - const ramp = curve === 'exponential' ? 'exponentialRampToValueAtTime' : 'linearRampToValueAtTime'; - const param = this; - if (AudioParam.prototype.cancelAndHoldAtTime == null) { - //this replicates cancelAndHoldAtTime behavior for Firefox - setTimeout(() => { - //sustain at current value - const currValue = param.value; - param.cancelScheduledValues(0); - param.setValueAtTime(currValue, 0); - //release - param[ramp](endValue, endTime); - }, (startTime - ctx.currentTime) * 1000); - } else { - param.cancelAndHoldAtTime(startTime); +const setRelease = (param, startTime, endTime, endValue, curve = 'linear') => { + const ctx = getAudioContext(); + const ramp = curve === 'exponential' ? 'exponentialRampToValueAtTime' : 'linearRampToValueAtTime'; + if (param.cancelAndHoldAtTime == null) { + //this replicates cancelAndHoldAtTime behavior for Firefox + setTimeout(() => { + //sustain at current value + const currValue = param.value; + param.cancelScheduledValues(0); + param.setValueAtTime(currValue, 0); //release param[ramp](endValue, endTime); - } - }; -} + }, (startTime - ctx.currentTime) * 1000); + } else { + param.cancelAndHoldAtTime(startTime); + //release + param[ramp](endValue, endTime); + } +}; export function gainNode(value) { const node = getAudioContext().createGain(); @@ -45,9 +42,9 @@ export const getEnvelope = (attack, decay, sustain, release, velocity, begin) => node: gainNode, stop: (t) => { const endTime = t + release; - gainNode.gain.setRelease(t, endTime, 0); + setRelease(gainNode.gain, t, endTime, 0); // helps prevent pops from overlapping sounds - return endTime - 0.01; + return endTime; }, }; }; @@ -117,8 +114,8 @@ export const getParamADSR = ( const sustainLevel = min + sustain * range; //decay param[ramp](sustainLevel, phase); - phase += Math.max(release, 0.1); - param.setRelease(end, phase, min, curve); + phase += release; + setRelease(param, end, phase, min, curve); }; export function getCompressor(ac, threshold, ratio, knee, attack, release) { @@ -135,19 +132,20 @@ export function getCompressor(ac, threshold, ratio, knee, attack, release) { // changes the default values of the envelope based on what parameters the user has defined // so it behaves more like you would expect/familiar as other synthesis tools // ex: sound(val).decay(val) will behave as a decay only envelope. sound(val).attack(val).decay(val) will behave like an "ad" env, etc. -const envmin = 0.001; -export const getADSRValues = (params, defaultValues = [envmin, envmin, 1, envmin]) => { + +export const getADSRValues = (params, defaultValues, min = 0, max = 1) => { + defaultValues = defaultValues ?? [min, min, max, min]; const [a, d, s, r] = params; const [defA, defD, defS, defR] = defaultValues; if (a == null && d == null && s == null && r == null) { return defaultValues; } - const sustain = s != null ? s : (a != null && d == null) || (a == null && d == null) ? defS : envmin; - return [a ?? envmin, d ?? envmin, sustain, r ?? envmin]; + const sustain = s != null ? s : (a != null && d == null) || (a == null && d == null) ? max : min; + return [a ?? min, d ?? min, sustain, r ?? min]; }; export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fenv, start, end, fanchor = 0.5) { - const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], [0.01, 0.01, 1, 0.01]); + const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], [0.001, 0.1, 1, 0.01], 0.001, 1); const filter = context.createBiquadFilter(); filter.type = type; filter.Q.value = Q; diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 3d93b8cd4..fcf63893c 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -29,10 +29,12 @@ export function registerSynthSounds() { registerSound( s, (t, value, onended) => { - const defaultADSRValues = [0.001, 0.05, 0.6, 0.01]; + const defaultADSRValues = [0.001, 0.1, 0.6, 0.01]; const [attack, decay, sustain, release] = getADSRValues( [value.attack, value.decay, value.sustain, value.release], defaultADSRValues, + 0, + 0.6, ); let sound; @@ -42,7 +44,6 @@ export function registerSynthSounds() { let { density } = value; sound = getNoiseOscillator(s, t, density); } - console.log(sound); let { node: o, stop, triggerRelease } = sound; // turn down From 30e402b9f14c47324d2ce80d09174e6be39ffb91 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 01:52:43 -0500 Subject: [PATCH 11/93] fixed release bug --- packages/superdough/helpers.mjs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index bcc92cddc..179995292 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -114,8 +114,8 @@ export const getParamADSR = ( const sustainLevel = min + sustain * range; //decay param[ramp](sustainLevel, phase); - phase += release; - setRelease(param, end, phase, min, curve); + + setRelease(param, end, end + release, min, curve); }; export function getCompressor(ac, threshold, ratio, knee, attack, release) { @@ -132,20 +132,19 @@ export function getCompressor(ac, threshold, ratio, knee, attack, release) { // changes the default values of the envelope based on what parameters the user has defined // so it behaves more like you would expect/familiar as other synthesis tools // ex: sound(val).decay(val) will behave as a decay only envelope. sound(val).attack(val).decay(val) will behave like an "ad" env, etc. - -export const getADSRValues = (params, defaultValues, min = 0, max = 1) => { - defaultValues = defaultValues ?? [min, min, max, min]; +const envmin = 0.001; +export const getADSRValues = (params, defaultValues = [envmin, envmin, 1, envmin]) => { const [a, d, s, r] = params; const [defA, defD, defS, defR] = defaultValues; if (a == null && d == null && s == null && r == null) { return defaultValues; } - const sustain = s != null ? s : (a != null && d == null) || (a == null && d == null) ? max : min; - return [a ?? min, d ?? min, sustain, r ?? min]; + const sustain = s != null ? s : (a != null && d == null) || (a == null && d == null) ? defS : envmin; + return [a ?? envmin, d ?? envmin, sustain, r ?? envmin]; }; export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fenv, start, end, fanchor = 0.5) { - const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], [0.001, 0.1, 1, 0.01], 0.001, 1); + const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], [0.01, 0.01, 1, 0.01]); const filter = context.createBiquadFilter(); filter.type = type; filter.Q.value = Q; From e0a7fb8290fe31000895006f464137f7ea3939ce Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 09:28:40 -0500 Subject: [PATCH 12/93] filter should decay to set frequency --- 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 179995292..451412d5d 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -157,7 +157,7 @@ export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fe const min = clamp(2 ** -offset * frequency, 0, 20000); const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000); - getParamADSR(context, filter.frequency, attack, decay, sustain, release, min, max, start, end); + getParamADSR(context, filter.frequency, attack, decay, sustain, release, frequency, max, start, end); return filter; } From 2dea3911ba18256043db39868e87d29767905344 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 09:29:07 -0500 Subject: [PATCH 13/93] remove unused variable --- packages/superdough/helpers.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 451412d5d..a2329cda9 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -154,7 +154,6 @@ export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fe if (!isNaN(fenv) && fenv !== 0) { const offset = fenv * fanchor; - const min = clamp(2 ** -offset * frequency, 0, 20000); const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000); getParamADSR(context, filter.frequency, attack, decay, sustain, release, frequency, max, start, end); From deb973afa5dfd85d7d3ec935903c1bd7b5a073f2 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 10:17:12 -0500 Subject: [PATCH 14/93] fixed hold behavior --- packages/superdough/helpers.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index a2329cda9..9ef0a1135 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -16,6 +16,7 @@ const setRelease = (param, startTime, endTime, endValue, curve = 'linear') => { }, (startTime - ctx.currentTime) * 1000); } else { param.cancelAndHoldAtTime(startTime); + param.setValueAtTime(param.value, startTime); //release param[ramp](endValue, endTime); } @@ -146,6 +147,7 @@ export const getADSRValues = (params, defaultValues = [envmin, envmin, 1, envmin export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fenv, start, end, fanchor = 0.5) { const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], [0.01, 0.01, 1, 0.01]); const filter = context.createBiquadFilter(); + filter.type = type; filter.Q.value = Q; filter.frequency.value = frequency; From fb81f6f268debc3374dfead211ef3cae5c45ed95 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 10:50:06 -0500 Subject: [PATCH 15/93] still working on popping issue with firefox --- packages/superdough/helpers.mjs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 9ef0a1135..d6e397c6e 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -1,7 +1,7 @@ import { getAudioContext } from './superdough.mjs'; import { clamp } from './util.mjs'; -const setRelease = (param, startTime, endTime, endValue, curve = 'linear') => { +const setRelease = (param, phase, sustain, startTime, endTime, endValue, curve = 'linear') => { const ctx = getAudioContext(); const ramp = curve === 'exponential' ? 'exponentialRampToValueAtTime' : 'linearRampToValueAtTime'; if (param.cancelAndHoldAtTime == null) { @@ -15,9 +15,10 @@ const setRelease = (param, startTime, endTime, endValue, curve = 'linear') => { param[ramp](endValue, endTime); }, (startTime - ctx.currentTime) * 1000); } else { + if (phase < startTime) { + param.setValueAtTime(sustain, startTime); + } param.cancelAndHoldAtTime(startTime); - param.setValueAtTime(param.value, startTime); - //release param[ramp](endValue, endTime); } }; @@ -43,7 +44,7 @@ export const getEnvelope = (attack, decay, sustain, release, velocity, begin) => node: gainNode, stop: (t) => { const endTime = t + release; - setRelease(gainNode.gain, t, endTime, 0); + setRelease(gainNode.gain, phase, sustain, t, endTime, 0); // helps prevent pops from overlapping sounds return endTime; }, @@ -113,10 +114,11 @@ export const getParamADSR = ( param[ramp](peak, phase); phase += decay; const sustainLevel = min + sustain * range; + //decay param[ramp](sustainLevel, phase); - setRelease(param, end, end + release, min, curve); + setRelease(param, phase, sustain, end, end + release, min, curve); }; export function getCompressor(ac, threshold, ratio, knee, attack, release) { From dec039ead3dccd68f343418ac81891798d728160 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 13:09:04 -0500 Subject: [PATCH 16/93] fixed filter envelope popping... --- packages/superdough/helpers.mjs | 44 +++++++++------------------------ packages/superdough/synth.mjs | 13 +++++----- 2 files changed, 18 insertions(+), 39 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index d6e397c6e..51361e79b 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -67,30 +67,7 @@ export const getExpEnvelope = (attack, decay, sustain, release, velocity, begin) }; }; -export const getADSR = (attack, decay, sustain, release, velocity, begin, end) => { - const gainNode = getAudioContext().createGain(); - gainNode.gain.setValueAtTime(0, begin); - gainNode.gain.linearRampToValueAtTime(velocity, begin + attack); // attack - gainNode.gain.linearRampToValueAtTime(sustain * velocity, begin + attack + decay); // sustain start - gainNode.gain.setValueAtTime(sustain * velocity, end); // sustain end - gainNode.gain.linearRampToValueAtTime(0, end + release); // release - // for some reason, using exponential ramping creates little cracklings - /* let t = begin; - gainNode.gain.setValueAtTime(0, t); - gainNode.gain.exponentialRampToValueAtTime(velocity, (t += attack)); - const sustainGain = Math.max(sustain * velocity, 0.001); - gainNode.gain.exponentialRampToValueAtTime(sustainGain, (t += decay)); - if (end - begin < attack + decay) { - gainNode.gain.cancelAndHoldAtTime(end); - } else { - gainNode.gain.setValueAtTime(sustainGain, end); - } - gainNode.gain.exponentialRampToValueAtTime(0.001, end + release); // release */ - return gainNode; -}; - export const getParamADSR = ( - context, param, attack, decay, @@ -118,7 +95,7 @@ export const getParamADSR = ( //decay param[ramp](sustainLevel, phase); - setRelease(param, phase, sustain, end, end + release, min, curve); + setRelease(param, phase, sustainLevel, end, end + release, min, curve); }; export function getCompressor(ac, threshold, ratio, knee, attack, release) { @@ -135,19 +112,22 @@ export function getCompressor(ac, threshold, ratio, knee, attack, release) { // changes the default values of the envelope based on what parameters the user has defined // so it behaves more like you would expect/familiar as other synthesis tools // ex: sound(val).decay(val) will behave as a decay only envelope. sound(val).attack(val).decay(val) will behave like an "ad" env, etc. -const envmin = 0.001; -export const getADSRValues = (params, defaultValues = [envmin, envmin, 1, envmin]) => { + +export const getADSRValues = (params, curve = 'linear', defaultValues) => { + const envmin = curve === 'exponential' ? 0.001 : 0; + const releaseMin = 0.01; + const envmax = 1; const [a, d, s, r] = params; - const [defA, defD, defS, defR] = defaultValues; if (a == null && d == null && s == null && r == null) { - return defaultValues; + return defaultValues ?? [envmin, envmin, envmax, releaseMin]; } - const sustain = s != null ? s : (a != null && d == null) || (a == null && d == null) ? defS : envmin; - return [a ?? envmin, d ?? envmin, sustain, r ?? envmin]; + const sustain = s != null ? s : (a != null && d == null) || (a == null && d == null) ? envmax : envmin; + return [Math.max(a ?? 0, envmin), Math.max(d ?? 0, envmin), Math.min(sustain, envmax), Math.max(r ?? 0, releaseMin)]; }; export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fenv, start, end, fanchor = 0.5) { - const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], [0.01, 0.01, 1, 0.01]); + const curve = 'exponential'; + const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], curve, [0.005, 0.14, 0, 0.1]); const filter = context.createBiquadFilter(); filter.type = type; @@ -160,7 +140,7 @@ export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fe const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000); - getParamADSR(context, filter.frequency, attack, decay, sustain, release, frequency, max, start, end); + getParamADSR(filter.frequency, attack, decay, sustain, release, frequency, max, start, end, curve); return filter; } diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index fcf63893c..09c8163ba 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -29,13 +29,12 @@ export function registerSynthSounds() { registerSound( s, (t, value, onended) => { - const defaultADSRValues = [0.001, 0.1, 0.6, 0.01]; - const [attack, decay, sustain, release] = getADSRValues( - [value.attack, value.decay, value.sustain, value.release], - defaultADSRValues, - 0, - 0.6, - ); + const [attack, decay, sustain, release] = getADSRValues([ + value.attack, + value.decay, + value.sustain, + value.release, + ]); let sound; if (waveforms.includes(s)) { From 5671b40707b86f9e9be5d0eb319a2bcbe2e0e4de Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 15:24:14 -0500 Subject: [PATCH 17/93] account for phase complete --- packages/superdough/helpers.mjs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 51361e79b..b5c01b08f 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -4,7 +4,11 @@ import { clamp } from './util.mjs'; const setRelease = (param, phase, sustain, startTime, endTime, endValue, curve = 'linear') => { const ctx = getAudioContext(); const ramp = curve === 'exponential' ? 'exponentialRampToValueAtTime' : 'linearRampToValueAtTime'; - if (param.cancelAndHoldAtTime == null) { + // if the decay stage is complete before the note event is done, we don't need to do anything special + if (phase < startTime) { + param.setValueAtTime(sustain, startTime); + param[ramp](endValue, endTime); + } else if (param.cancelAndHoldAtTime == null) { //this replicates cancelAndHoldAtTime behavior for Firefox setTimeout(() => { //sustain at current value @@ -15,9 +19,7 @@ const setRelease = (param, phase, sustain, startTime, endTime, endValue, curve = param[ramp](endValue, endTime); }, (startTime - ctx.currentTime) * 1000); } else { - if (phase < startTime) { - param.setValueAtTime(sustain, startTime); - } + //stop the envelope, hold the value, and then set the release stage param.cancelAndHoldAtTime(startTime); param[ramp](endValue, endTime); } From 77fee0b8661dfbee9565ed35d6aa9002d02115be Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Wed, 20 Dec 2023 17:39:11 -0500 Subject: [PATCH 18/93] fixed popping on font envelope --- 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 b5c01b08f..8b7d96317 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -46,7 +46,7 @@ export const getEnvelope = (attack, decay, sustain, release, velocity, begin) => node: gainNode, stop: (t) => { const endTime = t + release; - setRelease(gainNode.gain, phase, sustain, t, endTime, 0); + setRelease(gainNode.gain, phase, sustainLevel, t, endTime, 0); // helps prevent pops from overlapping sounds return endTime; }, From 9756d63cf114742c5cf51f2817dc363c89e15cc5 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sun, 31 Dec 2023 11:58:06 -0500 Subject: [PATCH 19/93] prettier --- packages/soundfonts/fontloader.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/soundfonts/fontloader.mjs b/packages/soundfonts/fontloader.mjs index a986481fd..683c249b7 100644 --- a/packages/soundfonts/fontloader.mjs +++ b/packages/soundfonts/fontloader.mjs @@ -1,4 +1,3 @@ - import { noteToMidi, freqToMidi, getSoundIndex } from '@strudel.cycles/core'; import { getAudioContext, registerSound, getEnvelope, getADSRValues } from '@strudel.cycles/webaudio'; import gm from './gm.mjs'; From 83c820a18c92b4dbc430ed978c4876584b57d348 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Mon, 1 Jan 2024 18:50:23 -0500 Subject: [PATCH 20/93] prettier again --- packages/superdough/helpers.mjs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 8b7d96317..68e88e87c 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -15,6 +15,7 @@ const setRelease = (param, phase, sustain, startTime, endTime, endValue, curve = const currValue = param.value; param.cancelScheduledValues(0); param.setValueAtTime(currValue, 0); + //release param[ramp](endValue, endTime); }, (startTime - ctx.currentTime) * 1000); @@ -89,6 +90,7 @@ export const getParamADSR = ( param.setValueAtTime(min, begin); phase += attack; + //attack param[ramp](peak, phase); phase += decay; @@ -139,13 +141,10 @@ export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fe // Apply ADSR to filter frequency if (!isNaN(fenv) && fenv !== 0) { const offset = fenv * fanchor; - const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000); - getParamADSR(filter.frequency, attack, decay, sustain, release, frequency, max, start, end, curve); return filter; } - return filter; } From ca3eda8fc739794148489cb252aabf36ed6fcb7d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 3 Jan 2024 21:54:10 +0100 Subject: [PATCH 21/93] support , in < > --- packages/mini/krill-parser.js | 4 ++-- packages/mini/krill.pegjs | 4 ++-- packages/mini/mini.mjs | 10 ++++------ 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/mini/krill-parser.js b/packages/mini/krill-parser.js index 66dff038f..ac9e83096 100644 --- a/packages/mini/krill-parser.js +++ b/packages/mini/krill-parser.js @@ -292,7 +292,7 @@ function peg$parse(input, options) { 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$f6 = function(s) { s.arguments_.alignment = 'polymeter_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 }}) }; @@ -1073,7 +1073,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { s3 = peg$parsews(); - s4 = peg$parsesequence(); + s4 = peg$parsepolymeter_stack(); if (s4 !== peg$FAILED) { s5 = peg$parsews(); if (input.charCodeAt(peg$currPos) === 62) { diff --git a/packages/mini/krill.pegjs b/packages/mini/krill.pegjs index 62b2f1a1b..da941049c 100644 --- a/packages/mini/krill.pegjs +++ b/packages/mini/krill.pegjs @@ -119,8 +119,8 @@ polymeter_steps = "%"a:slice // define a step-per-cycle timeline e.g <1 3 [3 5]>. We simply defer to a sequence and // change the alignment to slowcat -slow_sequence = ws "<" ws s:sequence ws ">" ws - { s.arguments_.alignment = 'slowcat'; return s; } +slow_sequence = ws "<" ws s:polymeter_stack ws ">" ws + { s.arguments_.alignment = 'polymeter_slowcat'; return s; } // a slice is either a single step or a sub cycle slice = step / sub_cycle / polymeter / slow_sequence diff --git a/packages/mini/mini.mjs b/packages/mini/mini.mjs index c2faf29b1..5272a094d 100644 --- a/packages/mini/mini.mjs +++ b/packages/mini/mini.mjs @@ -91,6 +91,10 @@ export function patternifyAST(ast, code, onEnter, offset = 0) { if (alignment === 'stack') { return strudel.stack(...children); } + if (alignment === 'polymeter_slowcat') { + const aligned = children.map((child) => child._slow(strudel.Fraction(child.__weight ?? 1))); + return strudel.stack(...aligned); + } if (alignment === 'polymeter') { // polymeter const stepsPerCycle = ast.arguments_.stepsPerCycle @@ -104,15 +108,9 @@ export function patternifyAST(ast, code, onEnter, offset = 0) { return strudel.chooseInWith(strudel.rand.early(randOffset * ast.arguments_.seed).segment(1), children); } const weightedChildren = ast.source_.some((child) => !!child.options_?.weight); - if (!weightedChildren && alignment === 'slowcat') { - return strudel.slowcat(...children); - } if (weightedChildren) { const weightSum = ast.source_.reduce((sum, child) => sum + (child.options_?.weight || 1), 0); const pat = strudel.timeCat(...ast.source_.map((child, i) => [child.options_?.weight || 1, children[i]])); - if (alignment === 'slowcat') { - return pat._slow(weightSum); // timecat + slow - } pat.__weight = weightSum; return pat; } From d582bbbb601c4b7e4fe0ecc8969be634504d64da Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 3 Jan 2024 22:17:11 +0100 Subject: [PATCH 22/93] fix: format --- packages/superdough/helpers.mjs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 68e88e87c..7544ab7f4 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -10,15 +10,18 @@ const setRelease = (param, phase, sustain, startTime, endTime, endValue, curve = param[ramp](endValue, endTime); } else if (param.cancelAndHoldAtTime == null) { //this replicates cancelAndHoldAtTime behavior for Firefox - setTimeout(() => { - //sustain at current value - const currValue = param.value; - param.cancelScheduledValues(0); - param.setValueAtTime(currValue, 0); - - //release - param[ramp](endValue, endTime); - }, (startTime - ctx.currentTime) * 1000); + setTimeout( + () => { + //sustain at current value + const currValue = param.value; + param.cancelScheduledValues(0); + param.setValueAtTime(currValue, 0); + + //release + param[ramp](endValue, endTime); + }, + (startTime - ctx.currentTime) * 1000, + ); } else { //stop the envelope, hold the value, and then set the release stage param.cancelAndHoldAtTime(startTime); From 2ecc6b30aa3829c73660f9ae4a3d0500489685fc Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 3 Jan 2024 22:37:35 +0100 Subject: [PATCH 23/93] add ad function --- packages/core/controls.mjs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index d979ff23e..5bb0a37f0 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1394,6 +1394,11 @@ controls.adsr = register('adsr', (adsr, pat) => { const [attack, decay, sustain, release] = adsr; return pat.set({ attack, decay, sustain, release }); }); +controls.ad = register('ad', (t, pat) => { + t = !Array.isArray(t) ? [t] : t; + const [attack, decay = attack] = t; + return pat.attack(attack).decay(decay); +}); controls.ds = register('ds', (ds, pat) => { ds = !Array.isArray(ds) ? [ds] : ds; const [decay, sustain] = ds; From 041a809b07106765edf83cbd9e3223bc0af0b325 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 3 Jan 2024 22:41:03 +0100 Subject: [PATCH 24/93] add ar function --- packages/core/controls.mjs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 5bb0a37f0..993f1c1da 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1399,10 +1399,15 @@ controls.ad = register('ad', (t, pat) => { const [attack, decay = attack] = t; return pat.attack(attack).decay(decay); }); -controls.ds = register('ds', (ds, pat) => { - ds = !Array.isArray(ds) ? [ds] : ds; - const [decay, sustain] = ds; +controls.ds = register('ds', (t, pat) => { + t = !Array.isArray(t) ? [t] : t; + const [decay, sustain = 0] = t; return pat.set({ decay, sustain }); }); +controls.ds = register('ar', (t, pat) => { + t = !Array.isArray(t) ? [t] : t; + const [attack, release = attack] = t; + return pat.set({ attack, release }); +}); export default controls; From a2974099c1932961cac391ae2341fe7ef2ed2776 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 3 Jan 2024 23:06:23 +0100 Subject: [PATCH 25/93] add dec synonym for decay --- packages/core/controls.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 993f1c1da..603725225 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -234,7 +234,7 @@ const generic_params = [ * note("c3 e3").decay("<.1 .2 .3 .4>").sustain(0) * */ - ['decay'], + ['decay', 'dec'], /** * Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset. * From 2ee392be9b28ccdc9f65d5ffd18f9e90536aba0f Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Fri, 5 Jan 2024 01:00:22 -0500 Subject: [PATCH 26/93] fixed all the things --- packages/core/util.mjs | 2 +- packages/soundfonts/fontloader.mjs | 22 +++-- packages/superdough/helpers.mjs | 121 ++++++++++----------------- packages/superdough/sampler.mjs | 31 ++++--- packages/superdough/synth.mjs | 61 +++++++++----- packages/superdough/util.mjs | 2 +- website/src/repl/panel/SoundsTab.jsx | 56 +++++++------ 7 files changed, 145 insertions(+), 150 deletions(-) diff --git a/packages/core/util.mjs b/packages/core/util.mjs index 6c0439b65..ef55de95d 100644 --- a/packages/core/util.mjs +++ b/packages/core/util.mjs @@ -86,7 +86,7 @@ export const midi2note = (n) => { // modulo that works with negative numbers e.g. _mod(-1, 3) = 2. Works on numbers (rather than patterns of numbers, as @mod@ from pattern.mjs does) export const _mod = (n, m) => ((n % m) + m) % m; -export function nanFallback(value, fallback) { +export function nanFallback(value, fallback = 0) { if (isNaN(Number(value))) { logger(`"${value}" is not a number, falling back to ${fallback}`, 'warning'); return fallback; diff --git a/packages/soundfonts/fontloader.mjs b/packages/soundfonts/fontloader.mjs index 683c249b7..8d8fb02bf 100644 --- a/packages/soundfonts/fontloader.mjs +++ b/packages/soundfonts/fontloader.mjs @@ -1,5 +1,5 @@ import { noteToMidi, freqToMidi, getSoundIndex } from '@strudel.cycles/core'; -import { getAudioContext, registerSound, getEnvelope, getADSRValues } from '@strudel.cycles/webaudio'; +import { getAudioContext, registerSound, getParamADSR, getADSRValues } from '@strudel.cycles/webaudio'; import gm from './gm.mjs'; let loadCache = {}; @@ -136,23 +136,27 @@ export function registerSoundfonts() { value.sustain, value.release, ]); + + const { duration } = value; const n = getSoundIndex(value.n, fonts.length); const font = fonts[n]; const ctx = getAudioContext(); const bufferSource = await getFontBufferSource(font, value, ctx); bufferSource.start(time); - const { node: envelope, stop: releaseEnvelope } = getEnvelope(attack, decay, sustain, release, 0.3, time); - bufferSource.connect(envelope); - const stop = (releaseTime) => { - const silentAt = releaseEnvelope(releaseTime); - bufferSource.stop(silentAt); - }; + const envGain = ctx.createGain(); + const node = bufferSource.connect(envGain); + const holdEnd = time + duration; + getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, time, holdEnd, 'linear'); + let envEnd = holdEnd + release + 0.01; + + bufferSource.stop(envEnd); + const stop = (releaseTime) => {}; bufferSource.onended = () => { bufferSource.disconnect(); - envelope.disconnect(); + node.disconnect(); onended(); }; - return { node: envelope, stop }; + return { node, stop }; }, { type: 'soundfont', prebake: true, fonts }, ); diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 7544ab7f4..ac22fc7c0 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -1,33 +1,5 @@ import { getAudioContext } from './superdough.mjs'; -import { clamp } from './util.mjs'; - -const setRelease = (param, phase, sustain, startTime, endTime, endValue, curve = 'linear') => { - const ctx = getAudioContext(); - const ramp = curve === 'exponential' ? 'exponentialRampToValueAtTime' : 'linearRampToValueAtTime'; - // if the decay stage is complete before the note event is done, we don't need to do anything special - if (phase < startTime) { - param.setValueAtTime(sustain, startTime); - param[ramp](endValue, endTime); - } else if (param.cancelAndHoldAtTime == null) { - //this replicates cancelAndHoldAtTime behavior for Firefox - setTimeout( - () => { - //sustain at current value - const currValue = param.value; - param.cancelScheduledValues(0); - param.setValueAtTime(currValue, 0); - - //release - param[ramp](endValue, endTime); - }, - (startTime - ctx.currentTime) * 1000, - ); - } else { - //stop the envelope, hold the value, and then set the release stage - param.cancelAndHoldAtTime(startTime); - param[ramp](endValue, endTime); - } -}; +import { clamp, nanFallback } from './util.mjs'; export function gainNode(value) { const node = getAudioContext().createGain(); @@ -35,44 +7,13 @@ export function gainNode(value) { return node; } -// alternative to getADSR returning the gain node and a stop handle to trigger the release anytime in the future -export const getEnvelope = (attack, decay, sustain, release, velocity, begin) => { - const gainNode = getAudioContext().createGain(); - let phase = begin; - gainNode.gain.setValueAtTime(0, begin); - phase += attack; - gainNode.gain.linearRampToValueAtTime(velocity, phase); // attack - phase += decay; - let sustainLevel = sustain * velocity; - gainNode.gain.linearRampToValueAtTime(sustainLevel, phase); // decay / sustain - // sustain end - return { - node: gainNode, - stop: (t) => { - const endTime = t + release; - setRelease(gainNode.gain, phase, sustainLevel, t, endTime, 0); - // helps prevent pops from overlapping sounds - return endTime; - }, - }; -}; - -export const getExpEnvelope = (attack, decay, sustain, release, velocity, begin) => { - sustain = Math.max(0.001, sustain); - velocity = Math.max(0.001, velocity); - const gainNode = getAudioContext().createGain(); - gainNode.gain.setValueAtTime(0.0001, begin); - gainNode.gain.exponentialRampToValueAtTime(velocity, begin + attack); - gainNode.gain.exponentialRampToValueAtTime(sustain * velocity, begin + attack + decay); - return { - node: gainNode, - stop: (t) => { - // similar to getEnvelope, this will glitch if sustain level has not been reached - gainNode.gain.exponentialRampToValueAtTime(0.0001, t + release); - }, - }; +const getSlope = (y1, y2, x1, x2) => { + const denom = x2 - x1; + if (denom === 0) { + return 0; + } + return (y2 - y1) / (x2 - x1); }; - export const getParamADSR = ( param, attack, @@ -86,23 +27,47 @@ export const getParamADSR = ( //exponential works better for frequency modulations (such as filter cutoff) due to human ear perception curve = 'exponential', ) => { + attack = nanFallback(attack); + decay = nanFallback(decay); + sustain = nanFallback(sustain); + release = nanFallback(release); + const ramp = curve === 'exponential' ? 'exponentialRampToValueAtTime' : 'linearRampToValueAtTime'; - let phase = begin; + if (curve === 'exponential') { + min = Math.max(0.0001, min); + } const range = max - min; const peak = min + range; + const sustainVal = min + sustain * range; + const duration = end - begin; + + const envValAtTime = (time) => { + if (attack > time) { + return time * getSlope(min, peak, 0, attack) + 0; + } else { + return (time - attack) * getSlope(peak, sustainVal, 0, decay) + peak; + } + }; param.setValueAtTime(min, begin); - phase += attack; - - //attack - param[ramp](peak, phase); - phase += decay; - const sustainLevel = min + sustain * range; - - //decay - param[ramp](sustainLevel, phase); - - setRelease(param, phase, sustainLevel, end, end + release, min, curve); + if (attack > duration) { + //attack + param[ramp](envValAtTime(duration), end); + } else if (attack + decay > duration) { + //attack + param[ramp](envValAtTime(attack), begin + attack); + //decay + param[ramp](envValAtTime(duration), end); + } else { + //attack + param[ramp](envValAtTime(attack), begin + attack); + //decay + param[ramp](envValAtTime(attack + decay), begin + attack + decay); + //sustain + param.setValueAtTime(sustainVal, end); + } + //release + param[ramp](min, end + release); }; export function getCompressor(ac, threshold, ratio, knee, attack, release) { diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index ac39da66a..f0e46221a 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -1,6 +1,6 @@ import { noteToMidi, valueToMidi, getSoundIndex } from './util.mjs'; import { getAudioContext, registerSound } from './index.mjs'; -import { getADSRValues, getEnvelope } from './helpers.mjs'; +import { getADSRValues, getParamADSR } from './helpers.mjs'; import { logger } from './logger.mjs'; const bufferCache = {}; // string: Promise @@ -243,6 +243,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { begin = 0, loopEnd = 1, end = 1, + duration, vib, vibmod = 0.5, } = value; @@ -255,7 +256,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { const ac = getAudioContext(); // destructure adsr here, because the default should be different for synths and samples - const [attack, decay, sustain, release] = getADSRValues([value.attack, value.decay, value.sustain, value.release]); + let [attack, decay, sustain, release] = getADSRValues([value.attack, value.decay, value.sustain, value.release]); //const soundfont = getSoundfontKey(s); const time = t + nudge; @@ -299,25 +300,29 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { bufferSource.loopEnd = loopEnd * bufferSource.buffer.duration - offset; } bufferSource.start(time, offset); - const { node: envelope, stop: releaseEnvelope } = getEnvelope(attack, decay, sustain, release, 1, t); - bufferSource.connect(envelope); + const envGain = ac.createGain(); + const node = bufferSource.connect(envGain); + const holdEnd = t + duration; + getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, t, holdEnd, 'linear'); + const out = ac.createGain(); // we need a separate gain for the cutgroups because firefox... - envelope.connect(out); + node.connect(out); bufferSource.onended = function () { bufferSource.disconnect(); vibratoOscillator?.stop(); - envelope.disconnect(); + node.disconnect(); out.disconnect(); onended(); }; + let envEnd = holdEnd + release + 0.01; + bufferSource.stop(envEnd); 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; - } - const silentAt = releaseEnvelope(releaseTime); - bufferSource.stop(silentAt); + // did not reimplement this behavior, because it mostly seems to confuse people... + // if (playWholeBuffer) { + // const bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value; + // envEnd = t + (end - begin) * bufferDuration; + // } + // bufferSource.stop(envEnd); }; const handle = { node: out, bufferSource, stop }; diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 09c8163ba..cfe3567ce 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -1,6 +1,6 @@ import { midiToFreq, noteToMidi } from './util.mjs'; import { registerSound, getAudioContext } from './superdough.mjs'; -import { gainNode, getADSRValues, getEnvelope, getExpEnvelope } from './helpers.mjs'; +import { gainNode, getADSRValues, getParamADSR } from './helpers.mjs'; import { getNoiseMix, getNoiseOscillator } from './noise.mjs'; const mod = (freq, range = 1, type = 'sine') => { @@ -43,26 +43,30 @@ export function registerSynthSounds() { let { density } = value; sound = getNoiseOscillator(s, t, density); } + let { node: o, stop, triggerRelease } = sound; // turn down const g = gainNode(0.3); - // gain envelope - const { node: envelope, stop: releaseEnvelope } = getEnvelope(attack, decay, sustain, release, 1, t); + const { duration } = value; o.onended = () => { o.disconnect(); g.disconnect(); onended(); }; + + const envGain = gainNode(1); + let node = o.connect(g).connect(envGain); + const holdEnd = t + duration; + getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, t, holdEnd, 'linear'); + const envEnd = holdEnd + release + 0.01; + triggerRelease?.(envEnd); + stop(envEnd); return { - node: o.connect(g).connect(envelope), - stop: (releaseTime) => { - const silentAt = releaseEnvelope(releaseTime); - triggerRelease?.(releaseTime); - stop(silentAt); - }, + node, + stop: (releaseTime) => {}, }; }, { type: 'synth', prebake: true }, @@ -122,6 +126,7 @@ export function getOscillator( fmrelease: fmRelease, fmvelocity: fmVelocity, fmwave: fmWaveform = 'sine', + duration, }, ) { let ac = getAudioContext(); @@ -151,26 +156,38 @@ export function getOscillator( o.start(t); // FM - let stopFm, fmEnvelope; + let stopFm; + let envGain = ac.createGain(); 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); + const [attack, decay, sustain, release] = getADSRValues([fmAttack, fmDecay, fmSustain, fmRelease]); + + const holdEnd = t + duration; + // let envEnd = holdEnd + release + 0.01; + + getParamADSR( + envGain.gain, + attack, + decay, + sustain, + release, + 0, + 1, + t, + holdEnd, + fmEnvelopeType === 'exp' ? 'exponential' : 'linear', + ); + if (fmEnvelopeType === 'exp') { - fmEnvelope = getExpEnvelope(fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity, t); - fmEnvelope.node.maxValue = fmModulationIndex * 2; - fmEnvelope.node.minValue = 0.00001; + envGain.maxValue = fmModulationIndex * 2; + envGain.minValue = 0.00001; } - modulator.connect(fmEnvelope.node); - fmEnvelope.node.connect(o.frequency); + modulator.connect(envGain); + envGain.connect(o.frequency); } stopFm = stop; } @@ -202,7 +219,7 @@ export function getOscillator( o.stop(time); }, triggerRelease: (time) => { - fmEnvelope?.stop(time); + // envGain?.stop(time); }, }; } diff --git a/packages/superdough/util.mjs b/packages/superdough/util.mjs index 29eaa7bc5..cebabfdaf 100644 --- a/packages/superdough/util.mjs +++ b/packages/superdough/util.mjs @@ -54,7 +54,7 @@ export const valueToMidi = (value, fallbackValue) => { return fallbackValue; }; -export function nanFallback(value, fallback) { +export function nanFallback(value, fallback = 0) { if (isNaN(Number(value))) { logger(`"${value}" is not a number, falling back to ${fallback}`, 'warning'); return fallback; diff --git a/website/src/repl/panel/SoundsTab.jsx b/website/src/repl/panel/SoundsTab.jsx index a3639dfb2..7c16b2664 100644 --- a/website/src/repl/panel/SoundsTab.jsx +++ b/website/src/repl/panel/SoundsTab.jsx @@ -57,32 +57,36 @@ export function SoundsTab() { settingsMap.setKey('soundsFilter', 'user')} />
- {soundEntries.map(([name, { data, onTrigger }]) => ( - { - const ctx = getAudioContext(); - const params = { - note: ['synth', 'soundfont'].includes(data.type) ? 'a3' : undefined, - s: name, - clip: 1, - release: 0.5, - }; - const time = ctx.currentTime + 0.05; - const onended = () => trigRef.current?.node?.disconnect(); - trigRef.current = Promise.resolve(onTrigger(time, params, onended)); - trigRef.current.then((ref) => { - connectToDestination(ref?.node); - }); - }} - > - {' '} - {name} - {data?.type === 'sample' ? `(${getSamples(data.samples)})` : ''} - {data?.type === 'soundfont' ? `(${data.fonts.length})` : ''} - - ))} + {soundEntries.map(([name, { data, onTrigger }]) => { + return ( + { + const ctx = getAudioContext(); + const params = { + note: ['synth', 'soundfont'].includes(data.type) ? 'a3' : undefined, + s: name, + clip: 1, + release: 0.5, + sustain: 1, + duration: 0.5, + }; + const time = ctx.currentTime + 0.05; + const onended = () => trigRef.current?.node?.disconnect(); + trigRef.current = Promise.resolve(onTrigger(time, params, onended)); + trigRef.current.then((ref) => { + connectToDestination(ref?.node); + }); + }} + > + {' '} + {name} + {data?.type === 'sample' ? `(${getSamples(data.samples)})` : ''} + {data?.type === 'soundfont' ? `(${data.fonts.length})` : ''} + + ); + })} {!soundEntries.length ? 'No custom sounds loaded in this pattern (yet).' : ''}
From b2f63897f9644a2c1e25d576b3b6a82f1b21a638 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Fri, 5 Jan 2024 01:07:54 -0500 Subject: [PATCH 27/93] change default FM env to exp because it modulates frequency and sounds way better :) --- packages/superdough/synth.mjs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index cfe3567ce..c4586e92e 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -119,7 +119,7 @@ export function getOscillator( // fm fmh: fmHarmonicity = 1, fmi: fmModulationIndex, - fmenv: fmEnvelopeType = 'lin', + fmenv: fmEnvelopeType = 'exp', fmattack: fmAttack, fmdecay: fmDecay, fmsustain: fmSustain, @@ -165,10 +165,7 @@ export function getOscillator( modulator.connect(o.frequency); } else { const [attack, decay, sustain, release] = getADSRValues([fmAttack, fmDecay, fmSustain, fmRelease]); - const holdEnd = t + duration; - // let envEnd = holdEnd + release + 0.01; - getParamADSR( envGain.gain, attack, @@ -181,11 +178,6 @@ export function getOscillator( holdEnd, fmEnvelopeType === 'exp' ? 'exponential' : 'linear', ); - - if (fmEnvelopeType === 'exp') { - envGain.maxValue = fmModulationIndex * 2; - envGain.minValue = 0.00001; - } modulator.connect(envGain); envGain.connect(o.frequency); } From 150a1b8eed86f39136a638788d91595478d1fe4e Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Fri, 5 Jan 2024 17:45:09 -0500 Subject: [PATCH 28/93] restore buffer hold behavior --- packages/superdough/sampler.mjs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index f0e46221a..36f712772 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -302,7 +302,12 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { bufferSource.start(time, offset); const envGain = ac.createGain(); const node = bufferSource.connect(envGain); - const holdEnd = t + duration; + let holdEnd = t + duration; + if (clip == null && loop == null && value.release == null) { + const bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value; + holdEnd = t + bufferDuration; + } + getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, t, holdEnd, 'linear'); const out = ac.createGain(); // we need a separate gain for the cutgroups because firefox... @@ -316,14 +321,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { }; let envEnd = holdEnd + release + 0.01; bufferSource.stop(envEnd); - const stop = (endTime, playWholeBuffer = clip === undefined && loop === undefined) => { - // did not reimplement this behavior, because it mostly seems to confuse people... - // if (playWholeBuffer) { - // const bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value; - // envEnd = t + (end - begin) * bufferDuration; - // } - // bufferSource.stop(envEnd); - }; + const stop = (endTime, playWholeBuffer) => {}; const handle = { node: out, bufferSource, stop }; // cut groups From bcee6632af4792da03ee0cd154c08c4dd5a41e2e Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 6 Jan 2024 15:21:58 +0100 Subject: [PATCH 29/93] fix: invisible selection on vim + emacs mode --- packages/codemirror/codemirror.mjs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index 8a887036c..0d095a4ed 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -4,7 +4,14 @@ import { history } from '@codemirror/commands'; import { javascript } from '@codemirror/lang-javascript'; import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language'; import { Compartment, EditorState, Prec } from '@codemirror/state'; -import { EditorView, highlightActiveLineGutter, highlightActiveLine, keymap, lineNumbers } from '@codemirror/view'; +import { + EditorView, + highlightActiveLineGutter, + highlightActiveLine, + keymap, + lineNumbers, + drawSelection, +} from '@codemirror/view'; import { Pattern, Drawer, repl, cleanupDraw } from '@strudel.cycles/core'; import { isAutoCompletionEnabled } from './autocomplete.mjs'; import { isTooltipEnabled } from './tooltip.mjs'; @@ -68,6 +75,7 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, roo syntaxHighlighting(defaultHighlightStyle), history(), EditorView.updateListener.of((v) => onChange(v)), + drawSelection({ cursorBlinkRate: 0 }), Prec.highest( keymap.of([ { From 8d325b96ead0769ad047f038d1a210b2773ca1a4 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sat, 6 Jan 2024 14:49:52 -0500 Subject: [PATCH 30/93] init --- website/src/repl/Repl.jsx | 8 ++-- .../src/repl/panel/AudioDeviceSelector.jsx | 36 +---------------- website/src/repl/util.mjs | 39 ++++++++++++++++++- website/src/settings.mjs | 6 ++- 4 files changed, 47 insertions(+), 42 deletions(-) diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index d53e7e5bd..7f8bd06ab 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -8,9 +8,10 @@ import { code2hash, getDrawContext, logger, silence } from '@strudel.cycles/core import cx from '@src/cx.mjs'; import { transpiler } from '@strudel.cycles/transpiler'; import { getAudioContext, initAudioOnFirstClick, webaudioOutput } from '@strudel.cycles/webaudio'; -import { defaultAudioDeviceName, getAudioDevices, setAudioDevice } from './panel/AudioDeviceSelector'; +import { defaultAudioDeviceName } from '../settings.mjs'; +import { getAudioDevices, setAudioDevice } from './util.mjs'; import { StrudelMirror, defaultSettings } from '@strudel/codemirror'; -import { createContext, useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { initUserCode, setActivePattern, @@ -24,12 +25,11 @@ import Loader from './Loader'; import { Panel } from './panel/Panel'; import { useStore } from '@nanostores/react'; import { prebake } from './prebake.mjs'; -import { getRandomTune, initCode, loadModules, shareCode } from './util.mjs'; +import { getRandomTune, initCode, loadModules, shareCode, ReplContext } from './util.mjs'; import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon'; import './Repl.css'; const { code: randomTune, name } = getRandomTune(); -export const ReplContext = createContext(null); const { latestCode } = settingsMap.get(); diff --git a/website/src/repl/panel/AudioDeviceSelector.jsx b/website/src/repl/panel/AudioDeviceSelector.jsx index 98e3e0687..969bf3873 100644 --- a/website/src/repl/panel/AudioDeviceSelector.jsx +++ b/website/src/repl/panel/AudioDeviceSelector.jsx @@ -1,42 +1,8 @@ import React, { useState } from 'react'; -import { getAudioContext, initializeAudioOutput, setDefaultAudioContext } from '@strudel.cycles/webaudio'; +import { getAudioDevices, setAudioDevice } from '../util.mjs'; import { SelectInput } from './SelectInput'; -import { logger } from '@strudel.cycles/core'; const initdevices = new Map(); -export const defaultAudioDeviceName = 'System Standard'; - -export const getAudioDevices = async () => { - await navigator.mediaDevices.getUserMedia({ audio: true }); - let mediaDevices = await navigator.mediaDevices.enumerateDevices(); - mediaDevices = mediaDevices.filter((device) => device.kind === 'audiooutput' && device.deviceId !== 'default'); - const devicesMap = new Map(); - devicesMap.set(defaultAudioDeviceName, ''); - mediaDevices.forEach((device) => { - devicesMap.set(device.label, device.deviceId); - }); - return devicesMap; -}; - -export const setAudioDevice = async (id) => { - let audioCtx = getAudioContext(); - if (audioCtx.sinkId === id) { - return; - } - await audioCtx.suspend(); - await audioCtx.close(); - audioCtx = setDefaultAudioContext(); - await audioCtx.resume(); - const isValidID = (id ?? '').length > 0; - if (isValidID) { - try { - await audioCtx.setSinkId(id); - } catch { - logger('failed to set audio interface', 'warning'); - } - } - initializeAudioOutput(); -}; // Allows the user to select an audio interface for Strudel to play through export function AudioDeviceSelector({ audioDeviceName, onChange, isDisabled }) { diff --git a/website/src/repl/util.mjs b/website/src/repl/util.mjs index 2b93b619f..27745eec0 100644 --- a/website/src/repl/util.mjs +++ b/website/src/repl/util.mjs @@ -1,11 +1,14 @@ import { controls, evalScope, hash2code, logger } from '@strudel.cycles/core'; -import { settingPatterns } from '../settings.mjs'; +import { settingPatterns, defaultAudioDeviceName } from '../settings.mjs'; +import { getAudioContext, initializeAudioOutput, setDefaultAudioContext } from '@strudel.cycles/webaudio'; + import { isTauri } from '../tauri.mjs'; import './Repl.css'; import * as tunes from './tunes.mjs'; import { createClient } from '@supabase/supabase-js'; import { nanoid } from 'nanoid'; import { writeText } from '@tauri-apps/api/clipboard'; +import { createContext } from 'react'; // Create a single supabase client for interacting with your database const supabase = createClient( @@ -110,3 +113,37 @@ export async function shareCode(codeToShare) { logger(message); } } + +export const ReplContext = createContext(null); + +export const getAudioDevices = async () => { + await navigator.mediaDevices.getUserMedia({ audio: true }); + let mediaDevices = await navigator.mediaDevices.enumerateDevices(); + mediaDevices = mediaDevices.filter((device) => device.kind === 'audiooutput' && device.deviceId !== 'default'); + const devicesMap = new Map(); + devicesMap.set(defaultAudioDeviceName, ''); + mediaDevices.forEach((device) => { + devicesMap.set(device.label, device.deviceId); + }); + return devicesMap; +}; + +export const setAudioDevice = async (id) => { + let audioCtx = getAudioContext(); + if (audioCtx.sinkId === id) { + return; + } + await audioCtx.suspend(); + await audioCtx.close(); + audioCtx = setDefaultAudioContext(); + await audioCtx.resume(); + const isValidID = (id ?? '').length > 0; + if (isValidID) { + try { + await audioCtx.setSinkId(id); + } catch { + logger('failed to set audio interface', 'warning'); + } + } + initializeAudioOutput(); +}; \ No newline at end of file diff --git a/website/src/settings.mjs b/website/src/settings.mjs index c74136363..5ede6c033 100644 --- a/website/src/settings.mjs +++ b/website/src/settings.mjs @@ -2,9 +2,10 @@ import { persistentMap, persistentAtom } from '@nanostores/persistent'; import { useStore } from '@nanostores/react'; import { register } from '@strudel.cycles/core'; import * as tunes from './repl/tunes.mjs'; -import { defaultAudioDeviceName } from './repl/panel/AudioDeviceSelector'; import { logger } from '@strudel.cycles/core'; +export const defaultAudioDeviceName = 'System Standard'; + export const defaultSettings = { activeFooter: 'intro', keybindings: 'codemirror', @@ -171,6 +172,7 @@ export function updateUserCode(code) { setActivePattern(example); return; } + if (!activePattern) { // create new user pattern activePattern = newUserPattern(); @@ -241,4 +243,4 @@ export async function exportPatterns() { document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); -} +} \ No newline at end of file From 46510664725b1c65d84fe7390e1f9827e5976dc9 Mon Sep 17 00:00:00 2001 From: Richard Julian Date: Sat, 6 Jan 2024 11:55:00 -0800 Subject: [PATCH 31/93] Remove hideHeader for better mobile UI and consistency --- .../src/pages/de/workshop/first-effects.mdx | 39 ++++------ website/src/pages/de/workshop/first-notes.mdx | 42 ++++------- .../src/pages/de/workshop/first-sounds.mdx | 72 +++++++++---------- .../src/pages/de/workshop/pattern-effects.mdx | 29 +++----- website/src/pages/de/workshop/recap.mdx | 66 ++++++++--------- website/src/pages/workshop/first-effects.mdx | 39 ++++------ website/src/pages/workshop/first-notes.mdx | 41 ++++------- website/src/pages/workshop/first-sounds.mdx | 72 +++++++++---------- .../src/pages/workshop/pattern-effects.mdx | 29 +++----- website/src/pages/workshop/recap.mdx | 66 ++++++++--------- 10 files changed, 203 insertions(+), 292 deletions(-) diff --git a/website/src/pages/de/workshop/first-effects.mdx b/website/src/pages/de/workshop/first-effects.mdx index b408a343e..aa89de9cc 100644 --- a/website/src/pages/de/workshop/first-effects.mdx +++ b/website/src/pages/de/workshop/first-effects.mdx @@ -15,7 +15,6 @@ import Box from '@components/Box.astro'; **low-pass filter** /2") .sound("sawtooth").lpf(800)`} @@ -33,7 +32,6 @@ lpf = **l**ow **p**ass **f**ilter **filter automatisieren** /2") .sound("sawtooth").lpf("200 1000")`} @@ -51,7 +49,6 @@ Später sehen wir, wie man mit Wellenformen Dinge automatisieren kann. **vowel = Vokal** /2") .sound("sawtooth").vowel("/2")`} @@ -60,7 +57,6 @@ Später sehen wir, wie man mit Wellenformen Dinge automatisieren kann. **gain = Verstärkung** ") .sound("sawtooth").lpf(600) @@ -145,7 +139,6 @@ Kannst du erraten, was die einzelnen Werte machen? **adsr-Kurznotation** ") .sound("sawtooth").lpf(600) @@ -156,7 +149,6 @@ Kannst du erraten, was die einzelnen Werte machen? **delay = Verzögerung** ~]") @@ -188,7 +180,6 @@ Was passiert, wenn du `.delay(".8:.06:.8")` schreibst? Kannst du erraten, was di **room aka reverb = Hall** ~@16] ~>/2") .scale("D4:minor").sound("gm_accordion:2") @@ -206,7 +197,6 @@ Füg auch ein Delay hinzu! **kleiner Dub-Tune** ~]") @@ -221,7 +211,6 @@ Füg auch ein Delay hinzu! Für echten Dub fehlt noch der Bass: ~]") @@ -245,7 +234,6 @@ Füg `.hush()` ans Ende eines Patterns im stack... **pan = Panorama** ").room(.2)`} /> +").room(.2)`} /> **fast and slow = schnell und langsam** Mit `fast` und `slow` kann man das Tempo eines Patterns außerhalb der Mini-Notation ändern: - + @@ -272,13 +260,13 @@ Was passiert, wenn du den Wert automatisierst? z.b. `.fast("<1 [2 4]>")` ? Übrigens, innerhalb der Mini-Notation: `fast` ist `*` und `slow` ist `/`. -")`} /> +")`} /> ## Automation mit Signalen Anstatt Werte schrittweise zu automatisieren, können wir auch sogenannte Signale benutzen: - + @@ -294,7 +282,7 @@ Der `gain`-Wert (Verstärkung) wird in der Visualisierung als Transparenz darges Signale bewegen sich standardmäßig zwischen 0 und 1. Wir können das mit `range` ändern: - + `range` ist nützlich wenn wir Funktionen mit einem anderen Wertebereich als 0 und 1 automatisieren wollen (z.b. `lpf`) @@ -307,7 +295,6 @@ Was passiert wenn du die beiden Werte vertauschst? Wir können die Geschwindigkeit der Automation mit slow / fast ändern: /2") .sound("sawtooth") @@ -324,13 +311,13 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt. | Name | Beispiel | | ----- | -------------------------------------------------------------------------------------------------- | -| lpf | ")`} /> | -| vowel | ")`} /> | -| gain | | -| delay | | -| room | | -| pan | | -| speed | ")`} /> | -| range | | +| lpf | ")`} /> | +| vowel | ")`} /> | +| gain | | +| delay | | +| room | | +| pan | | +| speed | ")`} /> | +| range | | Lass uns nun die für Tidal typischen [Pattern-Effekte anschauen](/de/workshop/pattern-effects). diff --git a/website/src/pages/de/workshop/first-notes.mdx b/website/src/pages/de/workshop/first-notes.mdx index c44969dfb..e80495a12 100644 --- a/website/src/pages/de/workshop/first-notes.mdx +++ b/website/src/pages/de/workshop/first-notes.mdx @@ -17,7 +17,6 @@ Jetzt schauen wir uns an wie man mit Tönen mit der `note` Funktion spielt. **Töne mit Zahlen** + @@ -126,7 +121,6 @@ Probier ein paar sounds aus: **Zwischen Sounds hin und her wechseln** + @@ -171,7 +164,7 @@ Wenn eine Sequenz unabhängig von ihrem Inhalt immer gleich schnell bleiben soll **Eins pro Cycle per \< \>** -").sound("gm_acoustic_bass")`} punchcard /> +").sound("gm_acoustic_bass")`} punchcard /> @@ -190,7 +183,6 @@ usw.. **Eine Sequenz pro Cycle** ") .sound("gm_acoustic_bass")`} @@ -200,7 +192,6 @@ usw.. oder auch... /2") .sound("gm_acoustic_bass")`} @@ -212,7 +203,6 @@ oder auch... Ähnlich wie Unter-Sequenzen, kann auch `<...>` innerhalb einer Sequenz verwendet werden: ") .sound("gm_xylophone")`} @@ -222,7 +212,6 @@ oder auch... Das ist auch praktisch für atonale Sounds: , [~ hh]*2") .bank("RolandTR909")`} @@ -235,7 +224,6 @@ Es kann mühsam sein die richtigen Noten zu finden wenn man alle zur Verfügung Mit Skalen ist das einfacher: ") .scale("C:minor").sound("piano")`} @@ -262,7 +250,6 @@ Probier verschiedene Skalen: Wie alle Funktionen können auch Skalen mit einem Pattern automatisiert werden: , 2 4 <[6,8] [7,9]>") .scale("/4") @@ -283,7 +270,7 @@ Nimm dir Zeit um herauszufinden welche Skalen du magst. **Verlängern mit @** - + @@ -296,7 +283,6 @@ Spiel mit der Länge! **Unter-Sequenzen verlängern** *2") .scale("/4") @@ -314,7 +300,7 @@ Das nennt man auch manchmal `triolen swing`. Es ist ein typischer Rhythmus im Bl **Wiederholen** -]").sound("piano")`} punchcard /> +]").sound("piano")`} punchcard /> @@ -330,25 +316,24 @@ Das haben wir in diesem Kapitel gelernt: | Concept | Syntax | Example | | ------------ | ------ | ------------------------------------------------------------------- | -| Verlangsamen | \/ | | -| Alternativen | \<\> | ")`} /> | -| Verlängern | @ | | -| Wiederholen | ! | | +| Verlangsamen | \/ | | +| Alternativen | \<\> | ")`} /> | +| Verlängern | @ | | +| Wiederholen | ! | | Neue Funktionen: | Name | Description | Example | | ----- | --------------------------------------- | -------------------------------------------------------------------------------------------- | -| note | Tonhöhe als Buchstabe oder Zahl | | -| scale | Interpretiert `n` als Skalenstufe | | -| stack | Spiele mehrere Patterns parallel (s.u.) | | +| note | Tonhöhe als Buchstabe oder Zahl | | +| scale | Interpretiert `n` als Skalenstufe | | +| stack | Spiele mehrere Patterns parallel (s.u.) | | ## Beispiele **Bassline** /2") .sound("gm_synth_bass_1") @@ -358,7 +343,6 @@ Neue Funktionen: **Melodie** , [~ hh]*2") .bank("RolandTR909")`} @@ -387,7 +370,6 @@ Das geht mit `stack` 😙 /2") diff --git a/website/src/pages/de/workshop/first-sounds.mdx b/website/src/pages/de/workshop/first-sounds.mdx index a689add80..cfb27f835 100644 --- a/website/src/pages/de/workshop/first-sounds.mdx +++ b/website/src/pages/de/workshop/first-sounds.mdx @@ -15,7 +15,7 @@ Dies ist das erste Kapitel im Strudel Workshop, schön dich an Bord zu haben! Der Workshop ist voller interaktiver Textfelder. Lass uns lernen wie sie funktionieren. Hier ist eins: - + @@ -35,7 +35,7 @@ Glückwunsch, du kannst jetzt live coden! Gerade haben wir schon den ersten sound mit `sound` abgespielt: - + @@ -57,7 +57,7 @@ Ein Sound kann mehrere Samples (Audio Dateien) enthalten. Du kannst ein anderes Sample wählen, indem du `:` und eine Zahl an den Sound-Namen anhängst: - + @@ -74,7 +74,7 @@ Vorerst bleiben wir bei den voreingestellten Sounds, später erfahren wir noch w Strudel kommt von Haus aus mit einer breiten Auswahl an Drum Sounds: - + @@ -92,7 +92,7 @@ Probier verschiedene Sounds aus! Wir können den Charakter des Drum Sounds verändern, indem wir mit `bank` die Drum Machine auswählen: - + In diesem Beispiel ist `RolandTR909` der Name der Drum Machine, die eine prägende Rolle für House und Techno Musik spielte. @@ -117,7 +117,7 @@ Dann kannst du ihn mit `Strg`+`C` kopieren und mit `Strg`+`V` einfügen. Im letzten Beispiel haben wir schon gesehen dass man mehrere Sounds hintereinander abspielen kann wenn man sie durch Leerzeichen trennt: - + Beachte wie der aktuell gespielte Sound im Code markiert und auch darunter visualisiert wird. @@ -129,13 +129,13 @@ Versuch noch mehr Sounds hinzuzfügen! **Je länger die Sequence, desto schneller** - + Der Inhalt einer Sequence wird in einen sogenannten Cycle (=Zyklus) zusammengequetscht. **Tempo ändern mit `cpm`** - + @@ -151,7 +151,7 @@ Wir werden später noch mehr Möglichkeiten kennen lernen das Tempo zu veränder **Pausen mit '~'** - + @@ -164,7 +164,7 @@ Tilde tippen: **Unter-Sequenzen mit [Klammern]** - + @@ -178,11 +178,11 @@ Genau wie bei der ganzen Sequence wird eine Unter-Sequence schneller je mehr dri **Multiplikation: Dinge schneller machen** - + **Multiplikation: Vieeeeeeel schneller** - + @@ -192,12 +192,11 @@ Tonhöhe = sehr schneller Rhythmus **Multiplikation: Ganze Unter-Sequences schneller machen** - + Bolero: + @@ -216,15 +215,15 @@ Du kannst so tief verschachteln wie du willst! **Parallele Sequenzen mit Komma** - + Du kannst so viele Kommas benutzen wie du möchtest: - + Kommas können auch in Unter-Sequenzen verwendet werden: - + @@ -237,7 +236,6 @@ Es kommt öfter vor, dass man die gleiche Idee auf verschiedene Arten ausdrücke **Mehrere Zeilen schreiben mit \` (backtick)** + Das gleiche kann man auch so schreiben: - + ## Rückblick @@ -269,33 +267,33 @@ Das haben wir bisher gelernt: | Concept | Syntax | Example | | --------------------- | ----------- | -------------------------------------------------------------------------------- | -| Sequenz | Leerzeichen | | -| Sound Nummer | :x | | -| Pausen | ~ | | -| Unter-Sequenzen | \[\] | | -| Unter-Unter-Sequenzen | \[\[\]\] | | -| Schneller | \* | | -| Parallel | , | | +| Sequenz | Leerzeichen | | +| Sound Nummer | :x | | +| Pausen | ~ | | +| Unter-Sequenzen | \[\] | | +| Unter-Unter-Sequenzen | \[\[\]\] | | +| Schneller | \* | | +| Parallel | , | | Die mit Apostrophen umgebene Mini-Notation benutzt man normalerweise in einer sogenannten Funktion. Die folgenden Funktionen haben wir bereits gesehen: | Name | Description | Example | | ----- | -------------------------------------- | ---------------------------------------------------------------------------------- | -| sound | Spielt den Sound mit dem Namen | | -| bank | Wählt die Soundbank / Drum Machine | | -| cpm | Tempo in **C**ycles **p**ro **M**inute | | -| n | Sample Nummer | | +| sound | Spielt den Sound mit dem Namen | | +| bank | Wählt die Soundbank / Drum Machine | | +| cpm | Tempo in **C**ycles **p**ro **M**inute | | +| n | Sample Nummer | | ## Beispiele **Einfacher Rock Beat** - + **Klassischer House** - + @@ -306,12 +304,11 @@ Bestimmte Drum Patterns werden oft genreübergreifend wiederverwendet. We Will Rock you - + **Yellow Magic Orchestra - Firecracker** + **jux = einen stereo kanal modifizieren** - + So würde man das ohne `jux` schreiben: + Das hat den gleichen Effekt, wie: >")) .color(">").adsr("[.1 0]:.2:[1 0]") @@ -95,7 +91,6 @@ z.B. c4 = 60, also ist c4 + 2 = 62 Man kann auch mehrmals addieren: >").add("0,7")) .color(">").adsr("[.1 0]:.2:[1 0]") @@ -106,7 +101,6 @@ Man kann auch mehrmals addieren: **add + scale** [~ <4 1>]>*2".add("<0 [0,2,4]>/4")) .scale("C5:minor").release(.5) @@ -117,7 +111,6 @@ Man kann auch mehrmals addieren: **Alles zusammen** [~ <4 1>]>*2".add("<0 [0,2,4]>/4")) @@ -134,11 +127,11 @@ Man kann auch mehrmals addieren: **ply** - + das ist wie: - + @@ -149,7 +142,6 @@ Probier `ply` mit einem pattern zu automatisieren, z.b. `"<1 2 1 3>"` **off** ] <2 3> [~ 1]>" .off(1/8, x=>x.add(4)) @@ -168,7 +160,6 @@ In der Notation `x=>x.`, ist `x` das Pattern, das wir bearbeiten. `off` ist auch nützlich für Sounds: x.speed(1.5).gain(.25))`} @@ -176,8 +167,8 @@ In der Notation `x=>x.`, ist `x` das Pattern, das wir bearbeiten. | Name | Beschreibung | Beispiel | | ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- | -| rev | rückwärts | | -| jux | einen Stereo-Kanal modifizieren | | -| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | -| ply | multipliziert jedes Element x mal | ")`} /> | -| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | +| rev | rückwärts | | +| jux | einen Stereo-Kanal modifizieren | | +| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | +| ply | multipliziert jedes Element x mal | ")`} /> | +| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | diff --git a/website/src/pages/de/workshop/recap.mdx b/website/src/pages/de/workshop/recap.mdx index c0d577d16..eb1f64f03 100644 --- a/website/src/pages/de/workshop/recap.mdx +++ b/website/src/pages/de/workshop/recap.mdx @@ -13,56 +13,56 @@ Diese Seite ist eine Auflistung aller im Workshop vorgestellten Funktionen. | Konzept | Syntax | Beispiel | | --------------------- | -------- | -------------------------------------------------------------------------------- | -| Sequenz | space | | -| Sample-Nummer | :x | | -| Pausen | ~ | | -| Unter-Sequenzen | \[\] | | -| Unter-Unter-Sequenzen | \[\[\]\] | | -| Schneller | \* | | -| Verlangsamen | \/ | | -| Parallel | , | | -| Alternieren | \<\> | ")`} /> | -| Verlängern | @ | | -| Wiederholen | ! | | +| Sequenz | space | | +| Sample-Nummer | :x | | +| Pausen | ~ | | +| Unter-Sequenzen | \[\] | | +| Unter-Unter-Sequenzen | \[\[\]\] | | +| Schneller | \* | | +| Verlangsamen | \/ | | +| Parallel | , | | +| Alternieren | \<\> | ")`} /> | +| Verlängern | @ | | +| Wiederholen | ! | | ## Sounds | Name | Beschreibung | Beispiel | | ----- | -------------------------- | ---------------------------------------------------------------------------------- | -| sound | spielt den Sound mit Namen | | -| bank | wählt die Soundbank | | -| n | wählt Sample mit Nummer | | +| sound | spielt den Sound mit Namen | | +| bank | wählt die Soundbank | | +| n | wählt Sample mit Nummer | | ## Noten | Name | Beschreibung | Beispiel | | --------- | ---------------------------------- | -------------------------------------------------------------------------------------------- | -| note | wählt Note per Zahl oder Buchstabe | | -| n + scale | wählt Note n in Skala | | -| stack | spielt mehrere Patterns parallel | | +| note | wählt Note per Zahl oder Buchstabe | | +| n + scale | wählt Note n in Skala | | +| stack | spielt mehrere Patterns parallel | | ## Audio-Effekte | Name | Beispiele | | ----- | -------------------------------------------------------------------------------------------------- | -| lpf | ")`} /> | -| vowel | ")`} /> | -| gain | | -| delay | | -| room | | -| pan | | -| speed | ")`} /> | -| range | | +| lpf | ")`} /> | +| vowel | ")`} /> | +| gain | | +| delay | | +| room | | +| pan | | +| speed | ")`} /> | +| range | | ## Pattern-Effekte | Name | Beschreibung | Beispiel | | ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- | -| cpm | Tempo in Cycles pro Minute | | -| fast | schneller | | -| slow | langsamer | | -| rev | rückwärts | | -| jux | einen Stereo-Kanal modifizieren | | -| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | -| ply | jedes Element schneller machen | ")`} /> | -| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | +| cpm | Tempo in Cycles pro Minute | | +| fast | schneller | | +| slow | langsamer | | +| rev | rückwärts | | +| jux | einen Stereo-Kanal modifizieren | | +| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | +| ply | jedes Element schneller machen | ")`} /> | +| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | diff --git a/website/src/pages/workshop/first-effects.mdx b/website/src/pages/workshop/first-effects.mdx index e3ce54874..de3d62011 100644 --- a/website/src/pages/workshop/first-effects.mdx +++ b/website/src/pages/workshop/first-effects.mdx @@ -17,7 +17,6 @@ We have sounds, we have notes, now let's look at effects! **low-pass filter** /2") .sound("sawtooth").lpf(800)`} @@ -35,7 +34,6 @@ lpf = **l**ow **p**ass **f**ilter **pattern the filter** /2") .sound("sawtooth").lpf("200 1000")`} @@ -53,7 +51,6 @@ We will learn how to automate with waves later... **vowel** /2") .sound("sawtooth").vowel("/2")`} @@ -62,7 +59,6 @@ We will learn how to automate with waves later... **gain** ") .sound("sawtooth").lpf(600) @@ -146,7 +140,6 @@ Can you guess what they do? **adsr short notation** ") .sound("sawtooth").lpf(600) @@ -157,7 +150,6 @@ Can you guess what they do? **delay** ~]") @@ -189,7 +181,6 @@ What happens if you use `.delay(".8:.06:.8")` ? Can you guess what the third num **room aka reverb** ~@16] ~>/2") .scale("D4:minor").sound("gm_accordion:2") @@ -207,7 +198,6 @@ Add a delay too! **little dub tune** ~]") @@ -222,7 +212,6 @@ Add a delay too! Let's add a bass to make this complete: ~]") @@ -246,7 +235,6 @@ Try adding `.hush()` at the end of one of the patterns in the stack... **pan** ").room(.2)`} /> +").room(.2)`} /> **fast and slow** We can use `fast` and `slow` to change the tempo of a pattern outside of Mini-Notation: - + @@ -273,13 +261,13 @@ What happens if you use a pattern like `.fast("<1 [2 4]>")`? By the way, inside Mini-Notation, `fast` is `*` and `slow` is `/`. -")`} /> +")`} /> ## automation with signals Instead of changing values stepwise, we can also control them with signals: - + @@ -295,7 +283,7 @@ The gain is visualized as transparency in the pianoroll. By default, waves oscillate between 0 to 1. We can change that with `range`: - + @@ -306,7 +294,6 @@ What happens if you flip the range values? We can change the automation speed with slow / fast: /2") .sound("sawtooth") @@ -323,13 +310,13 @@ The whole automation will now take 8 cycles to repeat. | name | example | | ----- | -------------------------------------------------------------------------------------------------- | -| lpf | ")`} /> | -| vowel | ")`} /> | -| gain | | -| delay | | -| room | | -| pan | | -| speed | ")`} /> | -| range | | +| lpf | ")`} /> | +| vowel | ")`} /> | +| gain | | +| delay | | +| room | | +| pan | | +| speed | ")`} /> | +| range | | Let us now take a look at some of Tidal's typical [pattern effects](/workshop/pattern-effects). diff --git a/website/src/pages/workshop/first-notes.mdx b/website/src/pages/workshop/first-notes.mdx index ab11ed903..d525cf819 100644 --- a/website/src/pages/workshop/first-notes.mdx +++ b/website/src/pages/workshop/first-notes.mdx @@ -17,7 +17,6 @@ Let's look at how we can play notes **play notes with numbers** + {/* c2 g2, e3 b3 d4 e4 */} @@ -127,7 +122,6 @@ Try out different sounds: **switch between sounds** + @@ -172,7 +165,7 @@ Because it is so common to just play one thing per cycle, you can.. **Play one per cycle with \< \>** -").sound("gm_acoustic_bass")`} punchcard /> +").sound("gm_acoustic_bass")`} punchcard /> @@ -185,7 +178,6 @@ Try adding more notes inside the brackets and notice how it does **not** get fas {/* <[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2 */} /2") .sound("gm_acoustic_bass")`} @@ -195,7 +187,6 @@ Try adding more notes inside the brackets and notice how it does **not** get fas **Alternate between multiple things** ") .sound("gm_xylophone")`} @@ -205,7 +196,6 @@ Try adding more notes inside the brackets and notice how it does **not** get fas This is also useful for unpitched sounds: , [~ hh]*2") .bank("RolandTR909")`} @@ -217,7 +207,6 @@ This is also useful for unpitched sounds: Finding the right notes can be difficult.. Scales are here to help: ") .scale("C:minor").sound("piano")`} @@ -244,7 +233,6 @@ Try out different scales: Just like anything, we can automate the scale with a pattern: , 2 4 <[6,8] [7,9]>") .scale("/4") @@ -265,7 +253,7 @@ Take your time and you'll find scales you like! **Elongate with @** - + @@ -278,7 +266,6 @@ Try changing that number! **Elongate within sub-sequences** *2") .scale("/4") @@ -296,7 +283,7 @@ This is also sometimes called triplet swing. You'll often find it in blues and j **Replicate** -]").sound("piano")`} punchcard /> +]").sound("piano")`} punchcard /> @@ -312,25 +299,24 @@ Let's recap what we've learned in this chapter: | Concept | Syntax | Example | | --------- | ------ | ------------------------------------------------------------------- | -| Slow down | \/ | | -| Alternate | \<\> | ")`} /> | -| Elongate | @ | | -| Replicate | ! | | +| Slow down | \/ | | +| Alternate | \<\> | ")`} /> | +| Elongate | @ | | +| Replicate | ! | | New functions: | Name | Description | Example | | ----- | ----------------------------------- | -------------------------------------------------------------------------------------------- | -| note | set pitch as number or letter | | -| scale | interpret `n` as scale degree | | -| stack | play patterns in parallel (read on) | | +| note | set pitch as number or letter | | +| scale | interpret `n` as scale degree | | +| stack | play patterns in parallel (read on) | | ## Examples **Classy Bassline** /2") .sound("gm_synth_bass_1") @@ -340,7 +326,6 @@ New functions: **Classy Melody** , [~ hh]*2") .bank("RolandTR909")`} @@ -369,7 +353,6 @@ It's called `stack` 😙 /2") diff --git a/website/src/pages/workshop/first-sounds.mdx b/website/src/pages/workshop/first-sounds.mdx index 5897f0292..5b0f45f2d 100644 --- a/website/src/pages/workshop/first-sounds.mdx +++ b/website/src/pages/workshop/first-sounds.mdx @@ -15,7 +15,7 @@ This is the first chapter of the Strudel Workshop, nice to have you on board! The workshop is full of interactive code fields. Let's learn how to use those. Here is one: - + @@ -33,7 +33,7 @@ Congratulations, you are now live coding! We have just played a sound with `sound` like this: - + @@ -55,7 +55,7 @@ One Sound can contain multiple samples (audio files). You can select the sample by appending `:` followed by a number to the name: - + @@ -72,7 +72,7 @@ For now we'll stick to this little selection of sounds, but we'll find out how t By default, Strudel comes with a wide selection of drum sounds: - + @@ -90,7 +90,7 @@ Try out different drum sounds! To change the sound character of our drums, we can use `bank` to change the drum machine: - + In this example `RolandTR909` is the name of the drum machine that we're using. It is a famous drum machine for house and techno beats. @@ -115,7 +115,7 @@ There are a lot more, but let's keep it simple for now In the last example, we already saw that you can play multiple sounds in a sequence by separating them with a space: - + Notice how the currently playing sound is highlighted in the code and also visualized below. @@ -127,13 +127,13 @@ Try adding more sounds to the sequence! **The longer the sequence, the faster it runs** - + The content of a sequence will be squished into what's called a cycle. **One way to change the tempo is using `cpm`** - + @@ -147,11 +147,11 @@ We will look at other ways to change the tempo later! **Add a rests in a sequence with '~'** - + **Sub-Sequences with [brackets]** - + @@ -163,15 +163,15 @@ Similar to the whole sequence, the content of a sub-sequence will be squished to **Multiplication: Speed things up** - + **Multiplication: Speed up sequences** - + **Multiplication: Speeeeeeeeed things up** - + @@ -181,7 +181,7 @@ Pitch = really fast rhythm **Sub-Sub-Sequences with [[brackets]]** - + @@ -191,15 +191,15 @@ You can go as deep as you want! **Play sequences in parallel with comma** - + You can use as many commas as you want: - + Commas can also be used inside sub-sequences: - + @@ -212,7 +212,6 @@ It is quite common that there are many ways to express the same idea. **Multiple Lines with backticks** + This is shorter and more readable than: - + ## Recap @@ -237,32 +236,32 @@ This is what we've leared so far: | Concept | Syntax | Example | | ----------------- | -------- | -------------------------------------------------------------------------------- | -| Sequence | space | | -| Sample Number | :x | | -| Rests | ~ | | -| Sub-Sequences | \[\] | | -| Sub-Sub-Sequences | \[\[\]\] | | -| Speed up | \* | | -| Parallel | , | | +| Sequence | space | | +| Sample Number | :x | | +| Rests | ~ | | +| Sub-Sequences | \[\] | | +| Sub-Sub-Sequences | \[\[\]\] | | +| Speed up | \* | | +| Parallel | , | | The Mini-Notation is usually used inside some function. These are the functions we've seen so far: | Name | Description | Example | | ----- | ----------------------------------- | ---------------------------------------------------------------------------------- | -| sound | plays the sound of the given name | | -| bank | selects the sound bank | | -| cpm | sets the tempo in cycles per minute | | -| n | select sample number | | +| sound | plays the sound of the given name | | +| bank | selects the sound bank | | +| cpm | sets the tempo in cycles per minute | | +| n | select sample number | | ## Examples **Basic rock beat** - + **Classic house** - + @@ -273,12 +272,12 @@ Certain drum patterns are reused across genres. We Will Rock you - + **Yellow Magic Orchestra - Firecracker** + **play pattern left and modify it right with jux** - + This is the same as: + This is like doing >")) .color(">").adsr("[.1 0]:.2:[1 0]") @@ -93,7 +89,6 @@ If you add a number to a note, the note will be treated as if it was a number We can add as often as we like: >").add("0,7")) .color(">").adsr("[.1 0]:.2:[1 0]") @@ -104,7 +99,6 @@ We can add as often as we like: **add with scale** [~ <4 1>]>*2".add("<0 [0,2,4]>/4")) .scale("C5:minor").release(.5) @@ -115,7 +109,6 @@ We can add as often as we like: **time to stack** [~ <4 1>]>*2".add("<0 [0,2,4]>/4")) @@ -132,11 +125,11 @@ We can add as often as we like: **ply** - + this is like writing: - + @@ -147,7 +140,6 @@ Try patterning the `ply` function, for example using `"<1 2 1 3>"` **off** ] <2 3> [~ 1]>" .off(1/8, x=>x.add(4)) @@ -166,7 +158,6 @@ In the notation `x=>x.`, the `x` is the shifted pattern, which where modifying. off is also useful for sounds: x.speed(1.5).gain(.25))`} @@ -174,8 +165,8 @@ off is also useful for sounds: | name | description | example | | ---- | ------------------------------ | ---------------------------------------------------------------------------------------------- | -| rev | reverse | | -| jux | split left/right, modify right | | -| add | add numbers / notes | ")).scale("C:minor")`} /> | -| ply | speed up each event n times | ")`} /> | -| off | copy, shift time & modify | x.speed(2))`} /> | +| rev | reverse | | +| jux | split left/right, modify right | | +| add | add numbers / notes | ")).scale("C:minor")`} /> | +| ply | speed up each event n times | ")`} /> | +| off | copy, shift time & modify | x.speed(2))`} /> | diff --git a/website/src/pages/workshop/recap.mdx b/website/src/pages/workshop/recap.mdx index fad14fb4f..17377e970 100644 --- a/website/src/pages/workshop/recap.mdx +++ b/website/src/pages/workshop/recap.mdx @@ -13,56 +13,56 @@ This page is just a listing of all functions covered in the workshop! | Concept | Syntax | Example | | ----------------- | -------- | -------------------------------------------------------------------------------- | -| Sequence | space | | -| Sample Number | :x | | -| Rests | ~ | | -| Sub-Sequences | \[\] | | -| Sub-Sub-Sequences | \[\[\]\] | | -| Speed up | \* | | -| Parallel | , | | -| Slow down | \/ | | -| Alternate | \<\> | ")`} /> | -| Elongate | @ | | -| Replicate | ! | | +| Sequence | space | | +| Sample Number | :x | | +| Rests | ~ | | +| Sub-Sequences | \[\] | | +| Sub-Sub-Sequences | \[\[\]\] | | +| Speed up | \* | | +| Parallel | , | | +| Slow down | \/ | | +| Alternate | \<\> | ")`} /> | +| Elongate | @ | | +| Replicate | ! | | ## Sounds | Name | Description | Example | | ----- | --------------------------------- | ---------------------------------------------------------------------------------- | -| sound | plays the sound of the given name | | -| bank | selects the sound bank | | -| n | select sample number | | +| sound | plays the sound of the given name | | +| bank | selects the sound bank | | +| n | select sample number | | ## Notes | Name | Description | Example | | --------- | ----------------------------- | -------------------------------------------------------------------------------------------- | -| note | set pitch as number or letter | | -| n + scale | set note in scale | | -| stack | play patterns in parallel | | +| note | set pitch as number or letter | | +| n + scale | set note in scale | | +| stack | play patterns in parallel | | ## Audio Effects | name | example | | ----- | -------------------------------------------------------------------------------------------------- | -| lpf | ")`} /> | -| vowel | ")`} /> | -| gain | | -| delay | | -| room | | -| pan | | -| speed | ")`} /> | -| range | | +| lpf | ")`} /> | +| vowel | ")`} /> | +| gain | | +| delay | | +| room | | +| pan | | +| speed | ")`} /> | +| range | | ## Pattern Effects | name | description | example | | ---- | ----------------------------------- | ---------------------------------------------------------------------------------------------- | -| cpm | sets the tempo in cycles per minute | | -| fast | speed up | | -| slow | slow down | | -| rev | reverse | | -| jux | split left/right, modify right | | -| add | add numbers / notes | ")).scale("C:minor")`} /> | -| ply | speed up each event n times | ")`} /> | -| off | copy, shift time & modify | x.speed(2))`} /> | +| cpm | sets the tempo in cycles per minute | | +| fast | speed up | | +| slow | slow down | | +| rev | reverse | | +| jux | split left/right, modify right | | +| add | add numbers / notes | ")).scale("C:minor")`} /> | +| ply | speed up each event n times | ")`} /> | +| off | copy, shift time & modify | x.speed(2))`} /> | From 5e3a37c9e8cc00f9eb89e90e16ad46a610338669 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sat, 6 Jan 2024 14:55:45 -0500 Subject: [PATCH 32/93] init --- pnpm-lock.yaml | 949 ++++++++++++++++++++++++++++--------------------- 1 file changed, 548 insertions(+), 401 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4e136397..b8b6e007b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -177,7 +177,7 @@ importers: version: 6.1.0(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0) '@replit/codemirror-vscode-keymap': specifier: ^6.0.2 - version: 6.0.2(@codemirror/autocomplete@6.11.1)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/lint@6.1.0)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0) + version: 6.0.2(@codemirror/autocomplete@6.11.1)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0) '@strudel.cycles/core': specifier: workspace:* version: link:../core @@ -489,7 +489,7 @@ importers: version: 2.0.3(astro@4.0.8) '@astrojs/react': specifier: ^3.0.9 - version: 3.0.9(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)(vite@5.0.10) + version: 3.0.9(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)(vite@5.0.11) '@astrojs/tailwind': specifier: ^5.1.0 version: 5.1.0(astro@4.0.8)(tailwindcss@3.4.0) @@ -631,7 +631,7 @@ importers: version: 0.33.1 vite-plugin-pwa: specifier: ^0.17.4 - version: 0.17.4(vite@5.0.10)(workbox-build@7.0.0)(workbox-window@7.0.0) + version: 0.17.4(vite@5.0.11)(workbox-build@7.0.0)(workbox-window@7.0.0) workbox-window: specifier: ^7.0.0 version: 7.0.0 @@ -867,7 +867,7 @@ packages: dependencies: prismjs: 1.29.0 - /@astrojs/react@3.0.9(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)(vite@5.0.10): + /@astrojs/react@3.0.9(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)(vite@5.0.11): resolution: {integrity: sha512-31J5yF5p9yBFV1axBooLA9PB4B2+MYm7swWhtlezSsJiUNXRFo5Is9qI3teJ7cKgmaCv+ZA593Smskko0NGaDQ==} engines: {node: '>=18.14.1'} peerDependencies: @@ -878,7 +878,7 @@ packages: dependencies: '@types/react': 18.2.46 '@types/react-dom': 18.2.18 - '@vitejs/plugin-react': 4.2.1(vite@5.0.10) + '@vitejs/plugin-react': 4.2.1(vite@5.0.11) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ultrahtml: 1.5.2 @@ -973,11 +973,10 @@ packages: dependencies: '@babel/types': 7.23.6 - /@babel/helper-builder-binary-assignment-operator-visitor@7.18.9: - resolution: {integrity: sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==} + /@babel/helper-builder-binary-assignment-operator-visitor@7.22.15: + resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-explode-assignable-expression': 7.18.6 '@babel/types': 7.23.6 dev: true @@ -991,8 +990,8 @@ packages: lru-cache: 5.1.1 semver: 6.3.1 - /@babel/helper-create-class-features-plugin@7.20.12(@babel/core@7.23.7): - resolution: {integrity: sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==} + /@babel/helper-create-class-features-plugin@7.23.7(@babel/core@7.23.7): + resolution: {integrity: sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1001,30 +1000,30 @@ packages: '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 - '@babel/helper-member-expression-to-functions': 7.20.7 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-replace-supers': 7.20.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - transitivePeerDependencies: - - supports-color + semver: 6.3.1 dev: true - /@babel/helper-create-regexp-features-plugin@7.20.5(@babel/core@7.23.7): - resolution: {integrity: sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==} + /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.7): + resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.23.7 '@babel/helper-annotate-as-pure': 7.22.5 - regexpu-core: 5.2.2 + regexpu-core: 5.3.2 + semver: 6.3.1 dev: true - /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.23.7): - resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==} + /@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.23.7): + resolution: {integrity: sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==} peerDependencies: - '@babel/core': ^7.4.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: '@babel/core': 7.23.7 '@babel/helper-compilation-targets': 7.23.6 @@ -1032,7 +1031,6 @@ packages: debug: 4.3.4 lodash.debounce: 4.0.8 resolve: 1.22.8 - semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true @@ -1041,13 +1039,6 @@ packages: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} - /@babel/helper-explode-assignable-expression@7.18.6: - resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.6 - dev: true - /@babel/helper-function-name@7.23.0: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} engines: {node: '>=6.9.0'} @@ -1061,8 +1052,8 @@ packages: dependencies: '@babel/types': 7.23.6 - /@babel/helper-member-expression-to-functions@7.20.7: - resolution: {integrity: sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==} + /@babel/helper-member-expression-to-functions@7.23.0: + resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.6 @@ -1087,8 +1078,8 @@ packages: '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 - /@babel/helper-optimise-call-expression@7.18.6: - resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} + /@babel/helper-optimise-call-expression@7.22.5: + resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.6 @@ -1098,8 +1089,8 @@ packages: resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} engines: {node: '>=6.9.0'} - /@babel/helper-remap-async-to-generator@7.18.9(@babel/core@7.23.7): - resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==} + /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.7): + resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1107,24 +1098,19 @@ packages: '@babel/core': 7.23.7 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-wrap-function': 7.20.5 - '@babel/types': 7.23.6 - transitivePeerDependencies: - - supports-color + '@babel/helper-wrap-function': 7.22.20 dev: true - /@babel/helper-replace-supers@7.20.7: - resolution: {integrity: sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==} + /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.7): + resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: + '@babel/core': 7.23.7 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-member-expression-to-functions': 7.20.7 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 - '@babel/types': 7.23.6 - transitivePeerDependencies: - - supports-color + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 dev: true /@babel/helper-simple-access@7.22.5: @@ -1133,8 +1119,8 @@ packages: dependencies: '@babel/types': 7.23.6 - /@babel/helper-skip-transparent-expression-wrappers@7.20.0: - resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==} + /@babel/helper-skip-transparent-expression-wrappers@7.22.5: + resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.6 @@ -1173,16 +1159,13 @@ packages: resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} - /@babel/helper-wrap-function@7.20.5: - resolution: {integrity: sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==} + /@babel/helper-wrap-function@7.22.20: + resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-function-name': 7.23.0 '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 '@babel/types': 7.23.6 - transitivePeerDependencies: - - supports-color dev: true /@babel/helpers@7.23.7: @@ -1226,8 +1209,8 @@ packages: dependencies: '@babel/types': 7.23.6 - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1236,219 +1219,169 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.20.7(@babel/core@7.23.7): - resolution: {integrity: sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==} + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/plugin-proposal-optional-chaining': 7.20.7(@babel/core@7.23.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) dev: true - /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.23.7): - resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.23.7): + resolution: {integrity: sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==} 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 + '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.23.7 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.23.7) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) - transitivePeerDependencies: - - supports-color dev: true - /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7): + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} 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: '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.22.5 - transitivePeerDependencies: - - supports-color dev: true - /@babel/plugin-proposal-class-static-block@7.20.7(@babel/core@7.23.7): - 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. + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: - '@babel/core': ^7.12.0 + '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) - transitivePeerDependencies: - - supports-color dev: true - /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.23.7): - 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. + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) dev: true - /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.23.7): - resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.7): + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} 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: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) dev: true - /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.23.7): - 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. + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.7): + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) dev: true - /@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.23.7): - 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. + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.7): + resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) dev: true - /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} + /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==} 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: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) dev: true - /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} + /@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==} 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: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) dev: true - /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.23.7): - 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. + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.7): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.23.5 '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-parameters': 7.20.7(@babel/core@7.23.7) dev: true - /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.23.7): - 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. + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) dev: true - /@babel/plugin-proposal-optional-chaining@7.20.7(@babel/core@7.23.7): - resolution: {integrity: sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==} + /@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.23.7): + resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} 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: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.23.7): - 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. + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 - transitivePeerDependencies: - - supports-color dev: true - /@babel/plugin-proposal-private-property-in-object@7.20.5(@babel/core@7.23.7): - 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. + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) - transitivePeerDependencies: - - supports-color dev: true - /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.23.7): - 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. + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.20.5(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1456,8 +1389,8 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1465,8 +1398,8 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.7): - resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.7): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1475,8 +1408,9 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1484,17 +1418,19 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.7): + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-import-assertions@7.20.0(@babel/core@7.23.7): - resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==} + /@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1503,26 +1439,34 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + /@babel/plugin-transform-async-generator-functions@7.23.7(@babel/core@7.23.7): + resolution: {integrity: sha512-PdxEpL71bJp1byMG0va5gwQcXHxuEYC/BgI/e88mGTtohbZN28O5Yit0Plkkm/dBzCF/BxmbNcses1RH1T+urA==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) dev: true - /@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.23.7): - resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} + /@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + /@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1530,8 +1474,9 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + /@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1539,35 +1484,61 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + /@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.7(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + /@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.7(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) + dev: true + + /@babel/plugin-transform-classes@7.23.5(@babel/core@7.23.7): + resolution: {integrity: sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + /@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 + '@babel/template': 7.22.15 dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + /@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1575,18 +1546,19 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.7): - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + /@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + /@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1595,147 +1567,164 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-arrow-functions@7.20.7(@babel/core@7.23.7): - resolution: {integrity: sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==} + /@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) dev: true - /@babel/plugin-transform-async-to-generator@7.20.7(@babel/core@7.23.7): - resolution: {integrity: sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==} + /@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-module-imports': 7.22.15 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.23.7) - transitivePeerDependencies: - - supports-color dev: true - /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==} + /@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) dev: true - /@babel/plugin-transform-block-scoping@7.20.15(@babel/core@7.23.7): - resolution: {integrity: sha512-Vv4DMZ6MiNOhu/LdaZsT/bsLRxgL94d269Mv4R/9sp6+Mp++X/JqypZYypJXLlM4mlL352/Egzbzr98iABH1CA==} + /@babel/plugin-transform-for-of@7.23.6(@babel/core@7.23.7): + resolution: {integrity: sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 dev: true - /@babel/plugin-transform-classes@7.20.7(@babel/core@7.23.7): - resolution: {integrity: sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==} + /@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 - '@babel/helper-optimise-call-expression': 7.18.6 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.20.7 - '@babel/helper-split-export-declaration': 7.22.6 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color dev: true - /@babel/plugin-transform-computed-properties@7.20.7(@babel/core@7.23.7): - resolution: {integrity: sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==} + /@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) + dev: true + + /@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/template': 7.22.15 dev: true - /@babel/plugin-transform-destructuring@7.20.7(@babel/core@7.23.7): - resolution: {integrity: sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==} + /@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) dev: true - /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==} + /@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.20.5(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.23.7): - resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==} + /@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==} + /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 dev: true - /@babel/plugin-transform-for-of@7.18.8(@babel/core@7.23.7): - resolution: {integrity: sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==} + /@babel/plugin-transform-modules-systemjs@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 dev: true - /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.23.7): - resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==} + /@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-function-name': 7.23.0 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.7): + resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-literals@7.18.9(@babel/core@7.23.7): - resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==} + /@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1744,76 +1733,78 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==} + /@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) dev: true - /@babel/plugin-transform-modules-amd@7.20.11(@babel/core@7.23.7): - resolution: {integrity: sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==} + /@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) dev: true - /@babel/plugin-transform-modules-commonjs@7.20.11(@babel/core@7.23.7): - resolution: {integrity: sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==} + /@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: + '@babel/compat-data': 7.23.5 '@babel/core': 7.23.7 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) + '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-simple-access': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) dev: true - /@babel/plugin-transform-modules-systemjs@7.20.11(@babel/core@7.23.7): - resolution: {integrity: sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==} + /@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) dev: true - /@babel/plugin-transform-modules-umd@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==} + /@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) dev: true - /@babel/plugin-transform-named-capturing-groups-regex@7.20.5(@babel/core@7.23.7): - resolution: {integrity: sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==} + /@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.20.5(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) dev: true - /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==} + /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1822,31 +1813,32 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==} + /@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.7(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.20.7 - transitivePeerDependencies: - - supports-color dev: true - /@babel/plugin-transform-parameters@7.20.7(@babel/core@7.23.7): - resolution: {integrity: sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==} + /@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.7): + resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.7(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) dev: true - /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==} + /@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1888,19 +1880,19 @@ packages: '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.23.7) '@babel/types': 7.23.6 - /@babel/plugin-transform-regenerator@7.20.5(@babel/core@7.23.7): - resolution: {integrity: sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==} + /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - regenerator-transform: 0.15.1 + regenerator-transform: 0.15.2 dev: true - /@babel/plugin-transform-reserved-words@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==} + /@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1909,8 +1901,8 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-shorthand-properties@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==} + /@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1919,19 +1911,19 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-spread@7.20.7(@babel/core@7.23.7): - resolution: {integrity: sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==} + /@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 dev: true - /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==} + /@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1940,8 +1932,8 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.23.7): - resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==} + /@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1950,8 +1942,8 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.23.7): - resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==} + /@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1960,8 +1952,8 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-unicode-escapes@7.18.10(@babel/core@7.23.7): - resolution: {integrity: sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==} + /@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1970,19 +1962,41 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-unicode-regex@7.18.6(@babel/core@7.23.7): - resolution: {integrity: sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==} + /@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.20.5(@babel/core@7.23.7) + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/preset-env@7.20.2(@babel/core@7.23.7): - resolution: {integrity: sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==} + /@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/preset-env@7.23.7(@babel/core@7.23.7): + resolution: {integrity: sha512-SY27X/GtTz/L4UryMNJ6p4fH4nsgWbz84y9FE0bQeWJP6O5BhgVCt53CotQKHCOeXJel8VyhlhujhlltKms/CA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1992,29 +2006,18 @@ packages: '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-class-static-block': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-proposal-dynamic-import': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.23.7) - '@babel/plugin-proposal-json-strings': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-optional-chaining': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-private-property-in-object': 7.20.5(@babel/core@7.23.7) - '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.7(@babel/core@7.23.7) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.7) '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-import-assertions': 7.20.0(@babel/core@7.23.7) + '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.7) '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) @@ -2024,67 +2027,93 @@ packages: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-transform-arrow-functions': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-transform-async-to-generator': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-transform-block-scoped-functions': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-block-scoping': 7.20.15(@babel/core@7.23.7) - '@babel/plugin-transform-classes': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-transform-computed-properties': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-transform-destructuring': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-duplicate-keys': 7.18.9(@babel/core@7.23.7) - '@babel/plugin-transform-exponentiation-operator': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-for-of': 7.18.8(@babel/core@7.23.7) - '@babel/plugin-transform-function-name': 7.18.9(@babel/core@7.23.7) - '@babel/plugin-transform-literals': 7.18.9(@babel/core@7.23.7) - '@babel/plugin-transform-member-expression-literals': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-modules-amd': 7.20.11(@babel/core@7.23.7) - '@babel/plugin-transform-modules-commonjs': 7.20.11(@babel/core@7.23.7) - '@babel/plugin-transform-modules-systemjs': 7.20.11(@babel/core@7.23.7) - '@babel/plugin-transform-modules-umd': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-named-capturing-groups-regex': 7.20.5(@babel/core@7.23.7) - '@babel/plugin-transform-new-target': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-object-super': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-parameters': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-transform-property-literals': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-regenerator': 7.20.5(@babel/core@7.23.7) - '@babel/plugin-transform-reserved-words': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-shorthand-properties': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-spread': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-transform-sticky-regex': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.23.7) - '@babel/plugin-transform-typeof-symbol': 7.18.9(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.23.7) - '@babel/preset-modules': 0.1.5(@babel/core@7.23.7) - '@babel/types': 7.23.6 - babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.23.7) - babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.23.7) - babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.23.7) - core-js-compat: 3.27.2 + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-async-generator-functions': 7.23.7(@babel/core@7.23.7) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-classes': 7.23.5(@babel/core@7.23.7) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.23.7) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-systemjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) + '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.23.7) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.7) + babel-plugin-polyfill-corejs2: 0.4.7(@babel/core@7.23.7) + babel-plugin-polyfill-corejs3: 0.8.7(@babel/core@7.23.7) + babel-plugin-polyfill-regenerator: 0.5.4(@babel/core@7.23.7) + core-js-compat: 3.35.0 semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /@babel/preset-modules@0.1.5(@babel/core@7.23.7): - resolution: {integrity: sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==} + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.7): + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 dependencies: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.23.7) '@babel/types': 7.23.6 esutils: 2.0.3 dev: true + /@babel/regjsgen@0.8.0: + resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} + dev: true + /@babel/runtime@7.20.13: resolution: {integrity: sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.11 + dev: false + + /@babel/runtime@7.23.7: + resolution: {integrity: sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: true /@babel/template@7.22.15: resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} @@ -2214,6 +2243,14 @@ packages: crelt: 1.0.5 dev: false + /@codemirror/lint@6.4.2: + resolution: {integrity: sha512-wzRkluWb1ptPKdzlsrbwwjYCPLgzU6N88YBAmlZi8WFyuiEduSd05MnJYNogzyc8rPK7pj6m95ptUApc8sHKVA==} + dependencies: + '@codemirror/state': 6.4.0 + '@codemirror/view': 6.23.0 + crelt: 1.0.6 + dev: false + /@codemirror/search@6.5.5: resolution: {integrity: sha512-PIEN3Ke1buPod2EHbJsoQwlbpkz30qGZKcnmH1eihq9+bPQx8gelauUwLYaY4vBOuBAuEhmpDLii4rj/uO0yMA==} dependencies: @@ -2298,7 +2335,7 @@ packages: resolution: {integrity: sha512-ZX/etZEZw8DR7zAB1eVQT40lNo0jeqpb6dCgOvctB6FIQ5PoXfMuNY8+ayQfu8tNQbAB8gQWSSJupR8NxeiZXw==} requiresBuild: true dependencies: - tslib: 2.5.0 + tslib: 2.6.2 optional: true /@esbuild/aix-ppc64@0.19.11: @@ -2939,19 +2976,33 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.17 + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + /@jridgewell/resolve-uri@3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - /@jridgewell/source-map@0.3.2: - resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==} + /@jridgewell/source-map@0.3.5: + resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} dependencies: - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.17 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 dev: true /@jridgewell/sourcemap-codec@1.4.14: @@ -2966,6 +3017,13 @@ packages: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 + /@jridgewell/trace-mapping@0.3.20: + resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + /@jsdoc/salty@0.2.3: resolution: {integrity: sha512-bbtCxCkxcnWhi50I+4Lj6mdz9w3pOXOgEQrID8TCZ/DF51fW7M9GCQW2y45SpBDdHd1Eirm1X/Cf6CkAAe8HPg==} engines: {node: '>=v12.0.0'} @@ -3541,7 +3599,7 @@ packages: '@codemirror/view': 6.23.0 dev: false - /@replit/codemirror-vscode-keymap@6.0.2(@codemirror/autocomplete@6.11.1)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/lint@6.1.0)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0): + /@replit/codemirror-vscode-keymap@6.0.2(@codemirror/autocomplete@6.11.1)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0): resolution: {integrity: sha512-j45qTwGxzpsv82lMD/NreGDORFKSctMDVkGRopaP+OrzSzv+pXDQuU3LnFvKpasyjVT0lf+PKG1v2DSCn/vxxg==} peerDependencies: '@codemirror/autocomplete': ^6.0.0 @@ -3555,7 +3613,7 @@ packages: '@codemirror/autocomplete': 6.11.1(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0) '@codemirror/commands': 6.3.3 '@codemirror/language': 6.10.0 - '@codemirror/lint': 6.1.0 + '@codemirror/lint': 6.4.2 '@codemirror/search': 6.5.5 '@codemirror/state': 6.4.0 '@codemirror/view': 6.23.0 @@ -3587,7 +3645,7 @@ packages: '@rollup/pluginutils': 3.1.0(rollup@2.79.1) '@types/resolve': 1.17.1 builtin-modules: 3.3.0 - deepmerge: 4.2.2 + deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.8 rollup: 2.79.1 @@ -3834,10 +3892,10 @@ packages: /@surma/rollup-plugin-off-main-thread@2.2.3: resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} dependencies: - ejs: 3.1.8 + ejs: 3.1.9 json5: 2.2.3 magic-string: 0.25.9 - string.prototype.matchall: 4.0.8 + string.prototype.matchall: 4.0.10 dev: true /@tailwindcss/forms@0.5.7(tailwindcss@3.4.0): @@ -4318,6 +4376,12 @@ packages: /@types/unist@3.0.1: resolution: {integrity: sha512-ue/hDUpPjC85m+PM9OQDMZr3LywT+CT6mPsQq8OJtCLiERkGRcQUFvu9XASF5XWqyZFXbf15lvb3JFJ4dRLWPg==} + /@types/webmidi@2.0.10: + resolution: {integrity: sha512-4RmTFMB6mN2h8XbJa1x3cOs9IOkXvFyHGcPUpUvWfmATuKg/J+dsFiMVgCE2EkpS+/8a8AP2tE3rQT1mLG7vEg==} + requiresBuild: true + dev: false + optional: true + /@types/webmidi@2.0.6: resolution: {integrity: sha512-sfS0A5IryqmBrUpcGPipEPeFdpqmZzP6b6lZFxHKgz5n2Vhzh4yJ5P2TvoDUhDjqJyv0Y25ng0Qodgo2Vu08ug==} dev: false @@ -4762,10 +4826,10 @@ packages: vite-plugin-pwa: '>=0.17.3 <1' dependencies: astro: 4.0.8(@types/node@20.10.6)(typescript@5.3.3) - vite-plugin-pwa: 0.17.4(vite@5.0.10)(workbox-build@7.0.0)(workbox-window@7.0.0) + vite-plugin-pwa: 0.17.4(vite@5.0.11)(workbox-build@7.0.0)(workbox-window@7.0.0) dev: true - /@vitejs/plugin-react@4.2.1(vite@5.0.10): + /@vitejs/plugin-react@4.2.1(vite@5.0.11): resolution: {integrity: sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -4776,7 +4840,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.23.7) '@types/babel__core': 7.20.5 react-refresh: 0.14.0 - vite: 5.0.10(@types/node@20.10.6) + vite: 5.0.11(@types/node@20.10.6) transitivePeerDependencies: - supports-color dev: false @@ -5284,6 +5348,10 @@ packages: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} dev: true + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: true + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: true @@ -5336,38 +5404,38 @@ packages: resolution: {integrity: sha512-3AN/9V/rKuv90NG65m4tTHsI04XrCKsWbztIcW7a8H5iIN7WlvWucRtVV0V/rT4QvtA11n5Vmp20fLwfMWqp6g==} dev: false - /babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.23.7): - resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==} + /babel-plugin-polyfill-corejs2@0.4.7(@babel/core@7.23.7): + resolution: {integrity: sha512-LidDk/tEGDfuHW2DWh/Hgo4rmnw3cduK6ZkOI1NPFceSK3n/yAGeOsNT7FLnSGHkXj3RHGSEVkN3FsCTY6w2CQ==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: '@babel/compat-data': 7.23.5 '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.23.7) + '@babel/helper-define-polyfill-provider': 0.4.4(@babel/core@7.23.7) semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-corejs3@0.6.0(@babel/core@7.23.7): - resolution: {integrity: sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==} + /babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.23.7): + resolution: {integrity: sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.23.7) - core-js-compat: 3.27.2 + '@babel/helper-define-polyfill-provider': 0.4.4(@babel/core@7.23.7) + core-js-compat: 3.35.0 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-regenerator@0.4.1(@babel/core@7.23.7): - resolution: {integrity: sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==} + /babel-plugin-polyfill-regenerator@0.5.4(@babel/core@7.23.7): + resolution: {integrity: sha512-S/x2iOCvDaCASLYsOOgWOq4bCfKYVqvO/uxjkaYyZ3rVsVE3CeAI/c84NpyuBBymEgNvHgjEot3a9/Z/kXvqsg==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.23.7) + '@babel/helper-define-polyfill-provider': 0.4.4(@babel/core@7.23.7) transitivePeerDependencies: - supports-color dev: true @@ -6086,8 +6154,8 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} - /core-js-compat@3.27.2: - resolution: {integrity: sha512-welaYuF7ZtbYKGrIy7y3eb40d37rG1FvzEOfe7hSLd2iD6duMDqUhRfSvCGyC46HhR6Y8JXXdZ2lnRUMkPBpvg==} + /core-js-compat@3.35.0: + resolution: {integrity: sha512-5blwFAddknKeNgsjBzilkdQ0+YK8L1PfqPYq40NOYMYFSS38qj+hpTcLLWwpIwA2A5bje/x5jmVn2tzUMg9IVw==} dependencies: browserslist: 4.22.2 dev: true @@ -6115,6 +6183,10 @@ packages: resolution: {integrity: sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==} dev: false + /crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + dev: false + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -6238,8 +6310,8 @@ packages: /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - /deepmerge@4.2.2: - resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} dev: true @@ -6498,6 +6570,14 @@ packages: jake: 10.8.5 dev: true + /ejs@3.1.9: + resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + jake: 10.8.7 + dev: true + /electron-to-chromium@1.4.574: resolution: {integrity: sha512-bg1m8L0n02xRzx4LsTTMbBPiUd9yIR+74iPtS/Ao65CuXvhVZHP0ym1kSdDG3yHFDXqHQQBKujlN1AQ8qZnyFg==} dev: false @@ -8541,6 +8621,17 @@ packages: minimatch: 3.1.2 dev: true + /jake@10.8.7: + resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==} + engines: {node: '>=10'} + hasBin: true + dependencies: + async: 3.2.5 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + dev: true + /jazz-midi@1.7.9: resolution: {integrity: sha512-c8c4BBgwxdsIr1iVm53nadCrtH7BUlnX3V95ciK/gbvXN/ndE5+POskBalXgqlc/r9p2XUbdLTrgrC6fou5p9w==} engines: {node: '>=10.0.0'} @@ -8747,6 +8838,15 @@ packages: jazz-midi: 1.7.9 dev: false + /jzz@1.7.7: + resolution: {integrity: sha512-fh7Qxb7G4q+7XqmayINHtGj2WpXtQTm+crFK0kg/s7JDhXLKg97MV0MXpADWNFJrNNVb9mkwNzW9sQlkRlfyug==} + requiresBuild: true + dependencies: + '@types/webmidi': 2.0.10 + jazz-midi: 1.7.9 + dev: false + optional: true + /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -11235,6 +11335,11 @@ packages: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -11481,8 +11586,8 @@ packages: test-value: 2.1.0 dev: true - /regenerate-unicode-properties@10.1.0: - resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} + /regenerate-unicode-properties@10.1.1: + resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} engines: {node: '>=4'} dependencies: regenerate: 1.4.2 @@ -11494,11 +11599,16 @@ packages: /regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: false - /regenerator-transform@0.15.1: - resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==} + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + dev: true + + /regenerator-transform@0.15.2: + resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} dependencies: - '@babel/runtime': 7.20.13 + '@babel/runtime': 7.23.7 dev: true /regexp.prototype.flags@1.5.1: @@ -11515,22 +11625,18 @@ packages: engines: {node: '>=8'} dev: false - /regexpu-core@5.2.2: - resolution: {integrity: sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==} + /regexpu-core@5.3.2: + resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} engines: {node: '>=4'} dependencies: + '@babel/regjsgen': 0.8.0 regenerate: 1.4.2 - regenerate-unicode-properties: 10.1.0 - regjsgen: 0.7.1 + regenerate-unicode-properties: 10.1.1 regjsparser: 0.9.1 unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.1.0 dev: true - /regjsgen@0.7.1: - resolution: {integrity: sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==} - dev: true - /regjsparser@0.9.1: resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} hasBin: true @@ -11821,7 +11927,7 @@ packages: jest-worker: 26.6.2 rollup: 2.79.1 serialize-javascript: 4.0.0 - terser: 5.16.3 + terser: 5.26.0 dev: true /rollup-plugin-visualizer@5.12.0: @@ -12389,8 +12495,8 @@ packages: get-east-asian-width: 1.2.0 strip-ansi: 7.1.0 - /string.prototype.matchall@4.0.8: - resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} + /string.prototype.matchall@4.0.10: + resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} dependencies: call-bind: 1.0.5 define-properties: 1.2.1 @@ -12399,6 +12505,7 @@ packages: has-symbols: 1.0.3 internal-slot: 1.0.6 regexp.prototype.flags: 1.5.1 + set-function-name: 2.0.1 side-channel: 1.0.4 dev: true @@ -12705,12 +12812,12 @@ packages: unique-string: 2.0.0 dev: true - /terser@5.16.3: - resolution: {integrity: sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==} + /terser@5.26.0: + resolution: {integrity: sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==} engines: {node: '>=10'} hasBin: true dependencies: - '@jridgewell/source-map': 0.3.2 + '@jridgewell/source-map': 0.3.5 acorn: 8.11.3 commander: 2.20.3 source-map-support: 0.5.21 @@ -12825,7 +12932,7 @@ packages: /tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} dependencies: - punycode: 2.3.0 + punycode: 2.3.1 dev: true /trim-lines@3.0.1: @@ -12880,6 +12987,11 @@ packages: /tslib@2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + requiresBuild: true + optional: true + /tsutils@3.21.0(typescript@5.3.3): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -13363,7 +13475,7 @@ packages: debug: 4.3.4 pathe: 1.1.1 picocolors: 1.0.0 - vite: 5.0.10(@types/node@20.10.6) + vite: 5.0.11(@types/node@20.10.6) transitivePeerDependencies: - '@types/node' - less @@ -13375,7 +13487,7 @@ packages: - terser dev: true - /vite-plugin-pwa@0.17.4(vite@5.0.10)(workbox-build@7.0.0)(workbox-window@7.0.0): + /vite-plugin-pwa@0.17.4(vite@5.0.11)(workbox-build@7.0.0)(workbox-window@7.0.0): resolution: {integrity: sha512-j9iiyinFOYyof4Zk3Q+DtmYyDVBDAi6PuMGNGq6uGI0pw7E+LNm9e+nQ2ep9obMP/kjdWwzilqUrlfVRj9OobA==} engines: {node: '>=16.0.0'} peerDependencies: @@ -13386,7 +13498,7 @@ packages: debug: 4.3.4 fast-glob: 3.3.2 pretty-bytes: 6.1.1 - vite: 5.0.10(@types/node@20.10.6) + vite: 5.0.11(@types/node@20.10.6) workbox-build: 7.0.0 workbox-window: 7.0.0 transitivePeerDependencies: @@ -13428,6 +13540,41 @@ packages: optionalDependencies: fsevents: 2.3.3 + /vite@5.0.11(@types/node@20.10.6): + resolution: {integrity: sha512-XBMnDjZcNAw/G1gEiskiM1v6yzM4GE5aMGvhWTlHAYYhxb7S3/V1s3m2LDHa8Vh6yIWYYB0iJwsEaS523c4oYA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.10.6 + esbuild: 0.19.5 + postcss: 8.4.32 + rollup: 4.9.2 + optionalDependencies: + fsevents: 2.3.3 + /vitefu@0.2.5(vite@5.0.10): resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} peerDependencies: @@ -13482,7 +13629,7 @@ packages: strip-literal: 1.3.0 tinybench: 2.5.1 tinypool: 0.8.1 - vite: 5.0.10(@types/node@20.10.6) + vite: 5.0.11(@types/node@20.10.6) vite-node: 1.1.0 why-is-node-running: 2.2.2 transitivePeerDependencies: @@ -13554,7 +13701,7 @@ packages: dependencies: djipevents: 2.0.7 optionalDependencies: - jzz: 1.5.9 + jzz: 1.7.7 dev: false /whatwg-url@5.0.0: @@ -13676,8 +13823,8 @@ packages: dependencies: '@apideck/better-ajv-errors': 0.3.6(ajv@8.12.0) '@babel/core': 7.23.7 - '@babel/preset-env': 7.20.2(@babel/core@7.23.7) - '@babel/runtime': 7.20.13 + '@babel/preset-env': 7.23.7(@babel/core@7.23.7) + '@babel/runtime': 7.23.7 '@rollup/plugin-babel': 5.3.1(@babel/core@7.23.7)(rollup@2.79.1) '@rollup/plugin-node-resolve': 11.2.1(rollup@2.79.1) '@rollup/plugin-replace': 2.4.2(rollup@2.79.1) From 569137eb22b31792c48fdbe92799c61477110eb7 Mon Sep 17 00:00:00 2001 From: Richard Julian Date: Sat, 6 Jan 2024 12:05:39 -0800 Subject: [PATCH 33/93] Formatting for passing CI --- .../src/pages/de/workshop/first-effects.mdx | 4 +- website/src/pages/de/workshop/first-notes.mdx | 8 ++-- .../src/pages/de/workshop/first-sounds.mdx | 8 ++-- .../src/pages/de/workshop/pattern-effects.mdx | 4 +- website/src/pages/de/workshop/recap.mdx | 20 +++++----- website/src/pages/workshop/first-effects.mdx | 4 +- website/src/pages/workshop/first-notes.mdx | 8 ++-- website/src/pages/workshop/first-sounds.mdx | 37 +++++++++---------- .../src/pages/workshop/pattern-effects.mdx | 4 +- website/src/pages/workshop/recap.mdx | 20 +++++----- 10 files changed, 58 insertions(+), 59 deletions(-) diff --git a/website/src/pages/de/workshop/first-effects.mdx b/website/src/pages/de/workshop/first-effects.mdx index aa89de9cc..a790120ab 100644 --- a/website/src/pages/de/workshop/first-effects.mdx +++ b/website/src/pages/de/workshop/first-effects.mdx @@ -309,8 +309,8 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt. ## Rückblick -| Name | Beispiel | -| ----- | -------------------------------------------------------------------------------------------------- | +| Name | Beispiel | +| ----- | --------------------------------------------------------------------------------------- | | lpf | ")`} /> | | vowel | ")`} /> | | gain | | diff --git a/website/src/pages/de/workshop/first-notes.mdx b/website/src/pages/de/workshop/first-notes.mdx index e80495a12..0f5efc55b 100644 --- a/website/src/pages/de/workshop/first-notes.mdx +++ b/website/src/pages/de/workshop/first-notes.mdx @@ -314,8 +314,8 @@ Was ist der Unterschied? Das haben wir in diesem Kapitel gelernt: -| Concept | Syntax | Example | -| ------------ | ------ | ------------------------------------------------------------------- | +| Concept | Syntax | Example | +| ------------ | ------ | -------------------------------------------------------- | | Verlangsamen | \/ | | | Alternativen | \<\> | ")`} /> | | Verlängern | @ | | @@ -323,8 +323,8 @@ Das haben wir in diesem Kapitel gelernt: Neue Funktionen: -| Name | Description | Example | -| ----- | --------------------------------------- | -------------------------------------------------------------------------------------------- | +| Name | Description | Example | +| ----- | --------------------------------------- | --------------------------------------------------------------------------------- | | note | Tonhöhe als Buchstabe oder Zahl | | | scale | Interpretiert `n` als Skalenstufe | | | stack | Spiele mehrere Patterns parallel (s.u.) | | diff --git a/website/src/pages/de/workshop/first-sounds.mdx b/website/src/pages/de/workshop/first-sounds.mdx index cfb27f835..743a53125 100644 --- a/website/src/pages/de/workshop/first-sounds.mdx +++ b/website/src/pages/de/workshop/first-sounds.mdx @@ -265,8 +265,8 @@ Wir haben jetzt die Grundlagen der sogenannten Mini-Notation gelernt, der Rhythm Das haben wir bisher gelernt: -| Concept | Syntax | Example | -| --------------------- | ----------- | -------------------------------------------------------------------------------- | +| Concept | Syntax | Example | +| --------------------- | ----------- | --------------------------------------------------------------------- | | Sequenz | Leerzeichen | | | Sound Nummer | :x | | | Pausen | ~ | | @@ -278,8 +278,8 @@ Das haben wir bisher gelernt: Die mit Apostrophen umgebene Mini-Notation benutzt man normalerweise in einer sogenannten Funktion. Die folgenden Funktionen haben wir bereits gesehen: -| Name | Description | Example | -| ----- | -------------------------------------- | ---------------------------------------------------------------------------------- | +| Name | Description | Example | +| ----- | -------------------------------------- | ----------------------------------------------------------------------- | | sound | Spielt den Sound mit dem Namen | | | bank | Wählt die Soundbank / Drum Machine | | | cpm | Tempo in **C**ycles **p**ro **M**inute | | diff --git a/website/src/pages/de/workshop/pattern-effects.mdx b/website/src/pages/de/workshop/pattern-effects.mdx index f710f41df..c76c831df 100644 --- a/website/src/pages/de/workshop/pattern-effects.mdx +++ b/website/src/pages/de/workshop/pattern-effects.mdx @@ -165,8 +165,8 @@ In der Notation `x=>x.`, ist `x` das Pattern, das wir bearbeiten. .off(1/8, x=>x.speed(1.5).gain(.25))`} /> -| Name | Beschreibung | Beispiel | -| ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- | +| Name | Beschreibung | Beispiel | +| ---- | --------------------------------- | ----------------------------------------------------------------------------------- | | rev | rückwärts | | | jux | einen Stereo-Kanal modifizieren | | | add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | diff --git a/website/src/pages/de/workshop/recap.mdx b/website/src/pages/de/workshop/recap.mdx index eb1f64f03..14ef6b252 100644 --- a/website/src/pages/de/workshop/recap.mdx +++ b/website/src/pages/de/workshop/recap.mdx @@ -11,8 +11,8 @@ Diese Seite ist eine Auflistung aller im Workshop vorgestellten Funktionen. ## Mini Notation -| Konzept | Syntax | Beispiel | -| --------------------- | -------- | -------------------------------------------------------------------------------- | +| Konzept | Syntax | Beispiel | +| --------------------- | -------- | --------------------------------------------------------------------- | | Sequenz | space | | | Sample-Nummer | :x | | | Pausen | ~ | | @@ -27,24 +27,24 @@ Diese Seite ist eine Auflistung aller im Workshop vorgestellten Funktionen. ## Sounds -| Name | Beschreibung | Beispiel | -| ----- | -------------------------- | ---------------------------------------------------------------------------------- | +| Name | Beschreibung | Beispiel | +| ----- | -------------------------- | ----------------------------------------------------------------------- | | sound | spielt den Sound mit Namen | | | bank | wählt die Soundbank | | | n | wählt Sample mit Nummer | | ## Noten -| Name | Beschreibung | Beispiel | -| --------- | ---------------------------------- | -------------------------------------------------------------------------------------------- | +| Name | Beschreibung | Beispiel | +| --------- | ---------------------------------- | --------------------------------------------------------------------------------- | | note | wählt Note per Zahl oder Buchstabe | | | n + scale | wählt Note n in Skala | | | stack | spielt mehrere Patterns parallel | | ## Audio-Effekte -| Name | Beispiele | -| ----- | -------------------------------------------------------------------------------------------------- | +| Name | Beispiele | +| ----- | --------------------------------------------------------------------------------------- | | lpf | ")`} /> | | vowel | ")`} /> | | gain | | @@ -56,8 +56,8 @@ Diese Seite ist eine Auflistung aller im Workshop vorgestellten Funktionen. ## Pattern-Effekte -| Name | Beschreibung | Beispiel | -| ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- | +| Name | Beschreibung | Beispiel | +| ---- | --------------------------------- | ----------------------------------------------------------------------------------- | | cpm | Tempo in Cycles pro Minute | | | fast | schneller | | | slow | langsamer | | diff --git a/website/src/pages/workshop/first-effects.mdx b/website/src/pages/workshop/first-effects.mdx index de3d62011..48764bce3 100644 --- a/website/src/pages/workshop/first-effects.mdx +++ b/website/src/pages/workshop/first-effects.mdx @@ -308,8 +308,8 @@ The whole automation will now take 8 cycles to repeat. ## Recap -| name | example | -| ----- | -------------------------------------------------------------------------------------------------- | +| name | example | +| ----- | --------------------------------------------------------------------------------------- | | lpf | ")`} /> | | vowel | ")`} /> | | gain | | diff --git a/website/src/pages/workshop/first-notes.mdx b/website/src/pages/workshop/first-notes.mdx index d525cf819..335cffe7c 100644 --- a/website/src/pages/workshop/first-notes.mdx +++ b/website/src/pages/workshop/first-notes.mdx @@ -297,8 +297,8 @@ What's the difference? Let's recap what we've learned in this chapter: -| Concept | Syntax | Example | -| --------- | ------ | ------------------------------------------------------------------- | +| Concept | Syntax | Example | +| --------- | ------ | -------------------------------------------------------- | | Slow down | \/ | | | Alternate | \<\> | ")`} /> | | Elongate | @ | | @@ -306,8 +306,8 @@ Let's recap what we've learned in this chapter: New functions: -| Name | Description | Example | -| ----- | ----------------------------------- | -------------------------------------------------------------------------------------------- | +| Name | Description | Example | +| ----- | ----------------------------------- | --------------------------------------------------------------------------------- | | note | set pitch as number or letter | | | scale | interpret `n` as scale degree | | | stack | play patterns in parallel (read on) | | diff --git a/website/src/pages/workshop/first-sounds.mdx b/website/src/pages/workshop/first-sounds.mdx index 5b0f45f2d..91ae1e5a0 100644 --- a/website/src/pages/workshop/first-sounds.mdx +++ b/website/src/pages/workshop/first-sounds.mdx @@ -55,7 +55,7 @@ One Sound can contain multiple samples (audio files). You can select the sample by appending `:` followed by a number to the name: - + @@ -72,7 +72,7 @@ For now we'll stick to this little selection of sounds, but we'll find out how t By default, Strudel comes with a wide selection of drum sounds: - + @@ -90,7 +90,7 @@ Try out different drum sounds! To change the sound character of our drums, we can use `bank` to change the drum machine: - + In this example `RolandTR909` is the name of the drum machine that we're using. It is a famous drum machine for house and techno beats. @@ -234,24 +234,24 @@ This is shorter and more readable than: Now we've learned the basics of the so called Mini-Notation, the rhythm language of Tidal. This is what we've leared so far: -| Concept | Syntax | Example | -| ----------------- | -------- | -------------------------------------------------------------------------------- | -| Sequence | space | | -| Sample Number | :x | | -| Rests | ~ | | -| Sub-Sequences | \[\] | | -| Sub-Sub-Sequences | \[\[\]\] | | -| Speed up | \* | | -| Parallel | , | | +| Concept | Syntax | Example | +| ----------------- | -------- | --------------------------------------------------------------------- | +| Sequence | space | | +| Sample Number | :x | | +| Rests | ~ | | +| Sub-Sequences | \[\] | | +| Sub-Sub-Sequences | \[\[\]\] | | +| Speed up | \* | | +| Parallel | , | | The Mini-Notation is usually used inside some function. These are the functions we've seen so far: -| Name | Description | Example | -| ----- | ----------------------------------- | ---------------------------------------------------------------------------------- | -| sound | plays the sound of the given name | | -| bank | selects the sound bank | | -| cpm | sets the tempo in cycles per minute | | -| n | select sample number | | +| Name | Description | Example | +| ----- | ----------------------------------- | ----------------------------------------------------------------------- | +| sound | plays the sound of the given name | | +| bank | selects the sound bank | | +| cpm | sets the tempo in cycles per minute | | +| n | select sample number | | ## Examples @@ -277,7 +277,6 @@ We Will Rock you **Yellow Magic Orchestra - Firecracker** x.speed(1.5).gain(.25))`} /> -| name | description | example | -| ---- | ------------------------------ | ---------------------------------------------------------------------------------------------- | +| name | description | example | +| ---- | ------------------------------ | ----------------------------------------------------------------------------------- | | rev | reverse | | | jux | split left/right, modify right | | | add | add numbers / notes | ")).scale("C:minor")`} /> | diff --git a/website/src/pages/workshop/recap.mdx b/website/src/pages/workshop/recap.mdx index 17377e970..9260a8f6a 100644 --- a/website/src/pages/workshop/recap.mdx +++ b/website/src/pages/workshop/recap.mdx @@ -11,8 +11,8 @@ This page is just a listing of all functions covered in the workshop! ## Mini Notation -| Concept | Syntax | Example | -| ----------------- | -------- | -------------------------------------------------------------------------------- | +| Concept | Syntax | Example | +| ----------------- | -------- | --------------------------------------------------------------------- | | Sequence | space | | | Sample Number | :x | | | Rests | ~ | | @@ -27,24 +27,24 @@ This page is just a listing of all functions covered in the workshop! ## Sounds -| Name | Description | Example | -| ----- | --------------------------------- | ---------------------------------------------------------------------------------- | +| Name | Description | Example | +| ----- | --------------------------------- | ----------------------------------------------------------------------- | | sound | plays the sound of the given name | | | bank | selects the sound bank | | | n | select sample number | | ## Notes -| Name | Description | Example | -| --------- | ----------------------------- | -------------------------------------------------------------------------------------------- | +| Name | Description | Example | +| --------- | ----------------------------- | --------------------------------------------------------------------------------- | | note | set pitch as number or letter | | | n + scale | set note in scale | | | stack | play patterns in parallel | | ## Audio Effects -| name | example | -| ----- | -------------------------------------------------------------------------------------------------- | +| name | example | +| ----- | --------------------------------------------------------------------------------------- | | lpf | ")`} /> | | vowel | ")`} /> | | gain | | @@ -56,8 +56,8 @@ This page is just a listing of all functions covered in the workshop! ## Pattern Effects -| name | description | example | -| ---- | ----------------------------------- | ---------------------------------------------------------------------------------------------- | +| name | description | example | +| ---- | ----------------------------------- | ----------------------------------------------------------------------------------- | | cpm | sets the tempo in cycles per minute | | | fast | speed up | | | slow | slow down | | From 86442adb20c9f513106f93b0d1e6082f16d71be6 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sat, 6 Jan 2024 15:09:09 -0500 Subject: [PATCH 34/93] prettier --- website/src/repl/util.mjs | 2 +- website/src/settings.mjs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/repl/util.mjs b/website/src/repl/util.mjs index 27745eec0..81c41e9d0 100644 --- a/website/src/repl/util.mjs +++ b/website/src/repl/util.mjs @@ -146,4 +146,4 @@ export const setAudioDevice = async (id) => { } } initializeAudioOutput(); -}; \ No newline at end of file +}; diff --git a/website/src/settings.mjs b/website/src/settings.mjs index 5ede6c033..0e4338062 100644 --- a/website/src/settings.mjs +++ b/website/src/settings.mjs @@ -172,7 +172,7 @@ export function updateUserCode(code) { setActivePattern(example); return; } - + if (!activePattern) { // create new user pattern activePattern = newUserPattern(); @@ -243,4 +243,4 @@ export async function exportPatterns() { document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); -} \ No newline at end of file +} From 7157634db03db7b673a059b494e8ebcfd26e6e5d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 9 Jan 2024 22:34:16 +0100 Subject: [PATCH 35/93] fix: autocomplete / tooltip code example bug --- packages/codemirror/autocomplete.mjs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/codemirror/autocomplete.mjs b/packages/codemirror/autocomplete.mjs index c9ec3d7aa..203ab8556 100644 --- a/packages/codemirror/autocomplete.mjs +++ b/packages/codemirror/autocomplete.mjs @@ -3,6 +3,12 @@ import jsdoc from '../../doc.json'; import { autocompletion } from '@codemirror/autocomplete'; import { h } from './html'; +function plaintext(str) { + const div = document.createElement('div'); + div.innerText = str; + return div.innerHTML; +} + const getDocLabel = (doc) => doc.name || doc.longname; const getInnerText = (html) => { var div = document.createElement('div'); @@ -21,7 +27,7 @@ ${doc.description} )}
- ${doc.examples?.map((example) => `
${example}
`)} + ${doc.examples?.map((example) => `
${plaintext(example)}
`)}
`[0]; /* From 62cd2263c2048ec53f8bd92350a532b1a491108f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 10 Jan 2024 00:03:18 +0100 Subject: [PATCH 36/93] add silent flag to nanFallback --- packages/superdough/util.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/superdough/util.mjs b/packages/superdough/util.mjs index cebabfdaf..4e3c7e41e 100644 --- a/packages/superdough/util.mjs +++ b/packages/superdough/util.mjs @@ -54,9 +54,9 @@ export const valueToMidi = (value, fallbackValue) => { return fallbackValue; }; -export function nanFallback(value, fallback = 0) { +export function nanFallback(value, fallback = 0, silent) { if (isNaN(Number(value))) { - logger(`"${value}" is not a number, falling back to ${fallback}`, 'warning'); + !silent && logger(`"${value}" is not a number, falling back to ${fallback}`, 'warning'); return fallback; } return value; From f785823e0051c3951ea868816a5cbd12fc79f725 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 10 Jan 2024 00:08:13 +0100 Subject: [PATCH 37/93] add fenv to filter cutoff controls --- packages/core/controls.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 603725225..971297797 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -270,7 +270,7 @@ const generic_params = [ * s("bd sd,hh*3").bpf("<1000 2000 4000 8000>") * */ - [['bandf', 'bandq'], 'bpf', 'bp'], + [['bandf', 'bandq', 'bpenv'], 'bpf', 'bp'], // TODO: in tidal, it seems to be normalized /** * Sets the **b**and-**p**ass **q**-factor (resonance). @@ -481,7 +481,7 @@ const generic_params = [ * s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30") * */ - [['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'], + [['cutoff', 'resonance', 'lpenv'], 'ctf', 'lpf', 'lp'], /** * Sets the lowpass filter envelope modulation depth. @@ -758,7 +758,7 @@ const generic_params = [ * .vibmod("<.25 .5 1 2 12>:8") */ [['vibmod', 'vib'], 'vmod'], - [['hcutoff', 'hresonance'], 'hpf', 'hp'], + [['hcutoff', 'hresonance', 'hpenv'], 'hpf', 'hp'], /** * Controls the **h**igh-**p**ass **q**-value. * From f99557cc0567dba6f1c3ef74e559631f73c59b56 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 10 Jan 2024 00:08:49 +0100 Subject: [PATCH 38/93] fix: fanchor + default fanchor to 0 (breaking change) --- packages/superdough/helpers.mjs | 12 ++++++++---- packages/superdough/superdough.mjs | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index ac22fc7c0..99531eff0 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -97,7 +97,7 @@ export const getADSRValues = (params, curve = 'linear', defaultValues) => { return [Math.max(a ?? 0, envmin), Math.max(d ?? 0, envmin), Math.min(sustain, envmax), Math.max(r ?? 0, releaseMin)]; }; -export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fenv, start, end, fanchor = 0.5) { +export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fenv, start, end, fanchor) { const curve = 'exponential'; const [attack, decay, sustain, release] = getADSRValues([att, dec, sus, rel], curve, [0.005, 0.14, 0, 0.1]); const filter = context.createBiquadFilter(); @@ -105,12 +105,16 @@ export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fe filter.type = type; filter.Q.value = Q; filter.frequency.value = frequency; - + // envelope is active when any of these values is set + const hasEnvelope = att ?? dec ?? sus ?? rel ?? fenv; // Apply ADSR to filter frequency - if (!isNaN(fenv) && fenv !== 0) { + if (hasEnvelope !== undefined) { + fenv = nanFallback(fenv, 1, true); + fanchor = nanFallback(fanchor, 0, true); const offset = fenv * fanchor; + const min = clamp(2 ** -offset * frequency, 0, 20000); const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000); - getParamADSR(filter.frequency, attack, decay, sustain, release, frequency, max, start, end, curve); + getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end, curve); return filter; } return filter; diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index f5674f2cf..d03007f17 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -276,7 +276,7 @@ export const superdough = async (value, deadline, hapDuration) => { density = 0.03, // filters ftype = '12db', - fanchor = 0.5, + fanchor = 0, // low pass cutoff, lpenv, From c68dba8c21f429cf0a0a14cd911a660648d740ab Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 10 Jan 2024 14:28:38 +0100 Subject: [PATCH 39/93] fix: use end --- packages/superdough/sampler.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 36f712772..932be9958 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -302,11 +302,11 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { bufferSource.start(time, offset); const envGain = ac.createGain(); const node = bufferSource.connect(envGain); - let holdEnd = t + duration; if (clip == null && loop == null && value.release == null) { const bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value; - holdEnd = t + bufferDuration; + duration = (end - begin) * bufferDuration; } + let holdEnd = t + duration; getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, t, holdEnd, 'linear'); From f26fd18c7a8b2537d25c40f32dcf4b317d7cec9d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 10 Jan 2024 15:02:10 +0100 Subject: [PATCH 40/93] use 0.001 as linear mintime as well (to prevent cracks) --- 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 99531eff0..43e435b86 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -86,7 +86,7 @@ export function getCompressor(ac, threshold, ratio, knee, attack, release) { // ex: sound(val).decay(val) will behave as a decay only envelope. sound(val).attack(val).decay(val) will behave like an "ad" env, etc. export const getADSRValues = (params, curve = 'linear', defaultValues) => { - const envmin = curve === 'exponential' ? 0.001 : 0; + const envmin = curve === 'exponential' ? 0.001 : 0.001; const releaseMin = 0.01; const envmax = 1; const [a, d, s, r] = params; From 86bc28dfb3fcfa1b1fa8b3821e5e8455c63b4da8 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 11 Jan 2024 20:46:22 +0100 Subject: [PATCH 41/93] add deprecation notes --- packages/core/README.md | 2 ++ packages/csound/README.md | 3 +++ packages/embed/README.md | 2 ++ packages/midi/README.md | 2 ++ packages/mini/README.md | 2 ++ packages/osc/README.md | 2 ++ packages/serial/README.md | 2 ++ packages/soundfonts/README.md | 3 +++ packages/tonal/README.md | 2 ++ packages/transpiler/README.md | 2 ++ packages/webaudio/README.md | 2 ++ packages/xen/README.md | 2 ++ 12 files changed, 26 insertions(+) create mode 100644 packages/csound/README.md create mode 100644 packages/soundfonts/README.md diff --git a/packages/core/README.md b/packages/core/README.md index 8e42800ef..5b01edcbd 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -1,5 +1,7 @@ # @strudel.cycles/core +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/core](https://www.npmjs.com/package/@strudel/core). + This package contains the bare essence of strudel. ## Install diff --git a/packages/csound/README.md b/packages/csound/README.md new file mode 100644 index 000000000..3961bd950 --- /dev/null +++ b/packages/csound/README.md @@ -0,0 +1,3 @@ +# @strudel.cycles/csound + +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/csound](https://www.npmjs.com/package/@strudel/csound). diff --git a/packages/embed/README.md b/packages/embed/README.md index f293c9312..d6ff83d73 100644 --- a/packages/embed/README.md +++ b/packages/embed/README.md @@ -1,5 +1,7 @@ # @strudel.cycles/embed +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/embed](https://www.npmjs.com/package/@strudel/embed). + This package contains a embeddable web component for the Strudel REPL. ## Usage diff --git a/packages/midi/README.md b/packages/midi/README.md index bf8a85eb2..29444cba0 100644 --- a/packages/midi/README.md +++ b/packages/midi/README.md @@ -1,5 +1,7 @@ # @strudel.cycles/midi +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/midi](https://www.npmjs.com/package/@strudel/midi). + This package adds midi functionality to strudel Patterns. ## Install diff --git a/packages/mini/README.md b/packages/mini/README.md index fce7a0451..a82323040 100644 --- a/packages/mini/README.md +++ b/packages/mini/README.md @@ -1,5 +1,7 @@ # @strudel.cycles/mini +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/mini](https://www.npmjs.com/package/@strudel/mini). + This package contains the mini notation parser and pattern generator. ## Install diff --git a/packages/osc/README.md b/packages/osc/README.md index 824d79a42..828dcb9d6 100644 --- a/packages/osc/README.md +++ b/packages/osc/README.md @@ -1,5 +1,7 @@ # @strudel.cycles/osc +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/osc](https://www.npmjs.com/package/@strudel/osc). + OSC output for strudel patterns! Currently only tested with super collider / super dirt. ## Usage diff --git a/packages/serial/README.md b/packages/serial/README.md index 5246c2f83..3eaae91e6 100644 --- a/packages/serial/README.md +++ b/packages/serial/README.md @@ -1,3 +1,5 @@ # @strudel.cycles/serial +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/serial](https://www.npmjs.com/package/@strudel/serial). + This package adds webserial functionality to strudel Patterns, for e.g. sending messages to arduino microcontrollers. diff --git a/packages/soundfonts/README.md b/packages/soundfonts/README.md new file mode 100644 index 000000000..e1423952f --- /dev/null +++ b/packages/soundfonts/README.md @@ -0,0 +1,3 @@ +# @strudel.cycles/soundfonts + +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/soundfonts](https://www.npmjs.com/package/@strudel/soundfonts). diff --git a/packages/tonal/README.md b/packages/tonal/README.md index 0bb344fd4..b95c2e1a9 100644 --- a/packages/tonal/README.md +++ b/packages/tonal/README.md @@ -1,5 +1,7 @@ # @strudel.cycles/tonal +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/tonal](https://www.npmjs.com/package/@strudel/tonal). + This package adds tonal / harmonic functions to strudel Patterns. ## Install diff --git a/packages/transpiler/README.md b/packages/transpiler/README.md index 1b0ed3654..8c5ef50f0 100644 --- a/packages/transpiler/README.md +++ b/packages/transpiler/README.md @@ -1,5 +1,7 @@ # @strudel.cycles/transpiler +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/transpiler](https://www.npmjs.com/package/@strudel/transpiler). + This package contains a JS code transpiler with the following features: - add locations of mini notation strings (double quoted or backticked) for highlighting diff --git a/packages/webaudio/README.md b/packages/webaudio/README.md index 8f974a25e..36ac0cc8e 100644 --- a/packages/webaudio/README.md +++ b/packages/webaudio/README.md @@ -1,5 +1,7 @@ # @strudel.cycles/webaudio +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/webaudio](https://www.npmjs.com/package/@strudel/webaudio). + This package contains helpers to make music with strudel and the Web Audio API. It is a thin binding to [superdough](https://www.npmjs.com/package/superdough). diff --git a/packages/xen/README.md b/packages/xen/README.md index aed60e4dd..cfb75358e 100644 --- a/packages/xen/README.md +++ b/packages/xen/README.md @@ -1,5 +1,7 @@ # @strudel.cycles/xen +**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/xen](https://www.npmjs.com/package/@strudel/xen). + This package adds xenharmonic / microtonal functions to strudel Patterns. Further documentation + examples will follow. ## Install From 9a0459fdd3fb375a6ac37bd4ed7580288b1edb48 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 12 Jan 2024 18:16:57 +0100 Subject: [PATCH 42/93] move non pages out of pages dir --- test/metadata.test.mjs | 2 +- website/src/{pages => }/metadata_parser.js | 0 website/src/my_patterns.js | 10 ++++++++++ website/src/pages/examples/index.astro | 3 ++- website/src/pages/swatch/[name].png.js | 4 ++-- website/src/pages/swatch/index.astro | 3 ++- website/src/pages/swatch/list.json.js | 17 ----------------- 7 files changed, 17 insertions(+), 22 deletions(-) rename website/src/{pages => }/metadata_parser.js (100%) create mode 100644 website/src/my_patterns.js delete mode 100644 website/src/pages/swatch/list.json.js diff --git a/test/metadata.test.mjs b/test/metadata.test.mjs index cbd0f8a36..947b045d6 100644 --- a/test/metadata.test.mjs +++ b/test/metadata.test.mjs @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { getMetadata } from '../website/src/pages/metadata_parser'; +import { getMetadata } from '../website/src/metadata_parser'; describe.concurrent('Metadata parser', () => { it('loads a tag from inline comment', async () => { diff --git a/website/src/pages/metadata_parser.js b/website/src/metadata_parser.js similarity index 100% rename from website/src/pages/metadata_parser.js rename to website/src/metadata_parser.js diff --git a/website/src/my_patterns.js b/website/src/my_patterns.js new file mode 100644 index 000000000..5779cc427 --- /dev/null +++ b/website/src/my_patterns.js @@ -0,0 +1,10 @@ +import { getMetadata } from './metadata_parser'; + +export function getMyPatterns() { + const my = import.meta.glob('../../my-patterns/**', { as: 'raw', eager: true }); + return Object.fromEntries( + Object.entries(my) + .filter(([name]) => name.endsWith('.txt')) + .map(([name, raw]) => [getMetadata(raw)['title'] || name.split('/').slice(-1), raw]), + ); +} diff --git a/website/src/pages/examples/index.astro b/website/src/pages/examples/index.astro index d44406898..6b24d9ff8 100644 --- a/website/src/pages/examples/index.astro +++ b/website/src/pages/examples/index.astro @@ -2,7 +2,7 @@ import * as tunes from '../../../src/repl/tunes.mjs'; import HeadCommon from '../../components/HeadCommon.astro'; -import { getMetadata } from '../metadata_parser'; +import { getMetadata } from '../../metadata_parser'; const { BASE_URL } = import.meta.env; const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL; @@ -25,3 +25,4 @@ const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL } +../../metadata_parser \ No newline at end of file diff --git a/website/src/pages/swatch/[name].png.js b/website/src/pages/swatch/[name].png.js index aa8aabf3c..117b75a69 100644 --- a/website/src/pages/swatch/[name].png.js +++ b/website/src/pages/swatch/[name].png.js @@ -2,9 +2,9 @@ import { createCanvas } from 'canvas'; import { pianoroll } from '@strudel.cycles/core'; import { evaluate } from '@strudel.cycles/transpiler'; import '../../../../test/runtime.mjs'; -import { getMyPatterns } from './list.json'; +import { getMyPatterns } from '../../my_patterns'; -export async function get({ params, request }) { +export async function GET({ params, request }) { const patterns = await getMyPatterns(); const { name } = params; const tune = patterns[name]; diff --git a/website/src/pages/swatch/index.astro b/website/src/pages/swatch/index.astro index 65484856c..5f5754494 100644 --- a/website/src/pages/swatch/index.astro +++ b/website/src/pages/swatch/index.astro @@ -1,5 +1,5 @@ --- -import { getMyPatterns } from './list.json'; +import { getMyPatterns } from '../../my_patterns.js'; import { Content } from '../../../../my-patterns/README.md'; import HeadCommon from '../../components/HeadCommon.astro'; @@ -37,3 +37,4 @@ const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL } +../../list.json diff --git a/website/src/pages/swatch/list.json.js b/website/src/pages/swatch/list.json.js deleted file mode 100644 index 4bf6bb4ae..000000000 --- a/website/src/pages/swatch/list.json.js +++ /dev/null @@ -1,17 +0,0 @@ -import { getMetadata } from '../metadata_parser'; - -export function getMyPatterns() { - const my = import.meta.glob('../../../../my-patterns/**', { as: 'raw', eager: true }); - return Object.fromEntries( - Object.entries(my) - .filter(([name]) => name.endsWith('.txt')) - .map(([name, raw]) => [getMetadata(raw)['title'] || name.split('/').slice(-1), raw]), - ); -} - -export async function get() { - const all = await getMyPatterns(); - return { - body: JSON.stringify(all), - }; -} From 6f3b2fa66b238fda198db544626a6687e58fe9d1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 13 Jan 2024 00:26:16 +0100 Subject: [PATCH 43/93] negative fenv values now stay in the same range as positives --- packages/superdough/helpers.mjs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 43e435b86..846130e81 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -111,9 +111,11 @@ export function createFilter(context, type, frequency, Q, att, dec, sus, rel, fe if (hasEnvelope !== undefined) { fenv = nanFallback(fenv, 1, true); fanchor = nanFallback(fanchor, 0, true); - const offset = fenv * fanchor; - const min = clamp(2 ** -offset * frequency, 0, 20000); - const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000); + const fenvAbs = Math.abs(fenv); + const offset = fenvAbs * fanchor; + let min = clamp(2 ** -offset * frequency, 0, 20000); + let max = clamp(2 ** (fenvAbs - offset) * frequency, 0, 20000); + if (fenv < 0) [min, max] = [max, min]; getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end, curve); return filter; } From 4fb5c1828d5310cd4be9c47ca4299fb9f3b0c557 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 13 Jan 2024 01:16:26 +0100 Subject: [PATCH 44/93] i have no clue why this works --- 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 846130e81..bee26f38b 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -37,13 +37,14 @@ export const getParamADSR = ( min = Math.max(0.0001, min); } const range = max - min; - const peak = min + range; + const peak = max; const sustainVal = min + sustain * range; const duration = end - begin; const envValAtTime = (time) => { if (attack > time) { - return time * getSlope(min, peak, 0, attack) + 0; + let slope = getSlope(min, peak, 0, attack); + return time * slope + (min > peak ? min : 0); } else { return (time - attack) * getSlope(peak, sustainVal, 0, decay) + peak; } From e051d383a07f54a7064e8cb67ce84e05f1de7ca9 Mon Sep 17 00:00:00 2001 From: fnordomat <46D46D1246803312401472B5A7427E237B7908CA> Date: Sat, 13 Jan 2024 11:07:59 +0100 Subject: [PATCH 45/93] add 10 new vowel qualities to formant table --- packages/superdough/vowel.mjs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/superdough/vowel.mjs b/packages/superdough/vowel.mjs index 25357642f..dd2fd52da 100644 --- a/packages/superdough/vowel.mjs +++ b/packages/superdough/vowel.mjs @@ -5,6 +5,16 @@ export var vowelFormant = { i: { freqs: [270, 1850, 2900, 3350, 3590], gains: [1, 0.0631, 0.0631, 0.0158, 0.0158], qs: [40, 90, 100, 120, 120] }, o: { freqs: [430, 820, 2700, 3000, 3300], gains: [1, 0.3162, 0.0501, 0.0794, 0.01995], qs: [40, 80, 100, 120, 120] }, u: { freqs: [370, 630, 2750, 3000, 3400], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, + ae: { freqs: [650, 1515, 2400, 3000, 3350], gains: [1, 0.5, 0.1008, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, + aa: { freqs: [560, 900, 2570, 3000, 3300], gains: [1, 0.5, 0.0708, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, + oe: { freqs: [500, 1430, 2300, 3000, 3300], gains: [1, 0.2, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, + ue: { freqs: [250, 1750, 2150, 3200, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, + y: { freqs: [400, 1460, 2400, 3000, 3300], gains: [1, 0.2, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, + uh: { freqs: [600, 1250, 2100, 3100, 3500], gains: [1, 0.3, 0.0608, 0.0316, 0.01995], qs: [40, 70, 100, 120, 130] }, + un: { freqs: [500, 1240, 2280, 3000, 3500], gains: [1, 0.1, 0.1708, 0.0216, 0.02995], qs: [40, 60, 100, 120, 120] }, + en: { freqs: [600, 1480, 2450, 3200, 3300], gains: [1, 0.15, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, + an: { freqs: [700, 1050, 2500, 3000, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, + on: { freqs: [500, 1080, 2350, 3000, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, }; if (typeof GainNode !== 'undefined') { class VowelNode extends GainNode { From 6232560273e5bafbb65854f02d7d5914470cd887 Mon Sep 17 00:00:00 2001 From: fnordomat <46D46D1246803312401472B5A7427E237B7908CA> Date: Sat, 13 Jan 2024 11:07:59 +0100 Subject: [PATCH 46/93] document extra vowels in quick reference --- packages/core/controls.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index d979ff23e..f449f85fc 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1209,7 +1209,7 @@ const generic_params = [ * Formant filter to make things sound like vowels. * * @name vowel - * @param {string | Pattern} vowel You can use a e i o u. + * @param {string | Pattern} vowel You can use a e i o u ae aa oe ue y uh un en an on, corresponding to [a] [e] [i] [o] [u] [æ] [ɑ] [ø] [y] [ɯ] [ʌ] [œ̃] [ɛ̃] [ɑ̃] [ɔ̃]. * @example * note("c2 >").s('sawtooth') * .vowel("
>") From efa0737660b9d13ba127ed6eaea6db8d35053afa Mon Sep 17 00:00:00 2001 From: fnordomat <46D46D1246803312401472B5A7427E237B7908CA> Date: Sat, 13 Jan 2024 15:11:30 +0100 Subject: [PATCH 47/93] added some aliases for the vowels (cosmetics) --- packages/core/controls.mjs | 2 +- packages/superdough/vowel.mjs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index f449f85fc..8605d7bec 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1209,7 +1209,7 @@ const generic_params = [ * Formant filter to make things sound like vowels. * * @name vowel - * @param {string | Pattern} vowel You can use a e i o u ae aa oe ue y uh un en an on, corresponding to [a] [e] [i] [o] [u] [æ] [ɑ] [ø] [y] [ɯ] [ʌ] [œ̃] [ɛ̃] [ɑ̃] [ɔ̃]. + * @param {string | Pattern} vowel You can use a e i o u ae aa oe ue y uh un en an on, corresponding to [a] [e] [i] [o] [u] [æ] [ɑ] [ø] [y] [ɯ] [ʌ] [œ̃] [ɛ̃] [ɑ̃] [ɔ̃]. Aliases: aa = å = ɑ, oe = ø = ö, y = ı, ae = æ. * @example * note("c2 >").s('sawtooth') * .vowel(">") diff --git a/packages/superdough/vowel.mjs b/packages/superdough/vowel.mjs index dd2fd52da..7d5dac4a4 100644 --- a/packages/superdough/vowel.mjs +++ b/packages/superdough/vowel.mjs @@ -15,6 +15,14 @@ export var vowelFormant = { en: { freqs: [600, 1480, 2450, 3200, 3300], gains: [1, 0.15, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, an: { freqs: [700, 1050, 2500, 3000, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, on: { freqs: [500, 1080, 2350, 3000, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, + get æ() { return this.ae; }, + get ø() { return this.oe; }, + get ɑ() { return this.aa; }, + get å() { return this.aa; }, + get ö() { return this.oe; }, + get ü() { return this.ue; }, + get ı() { return this.y; }, + }; if (typeof GainNode !== 'undefined') { class VowelNode extends GainNode { From eefa90a2bc7416ba38bfbd9b803f36dfd0ccaaeb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 13 Jan 2024 22:24:59 +0100 Subject: [PATCH 48/93] fix: synth default envelope --- packages/superdough/synth.mjs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index c4586e92e..6a3e381ab 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -29,12 +29,11 @@ export function registerSynthSounds() { registerSound( s, (t, value, onended) => { - const [attack, decay, sustain, release] = getADSRValues([ - value.attack, - value.decay, - value.sustain, - value.release, - ]); + const [attack, decay, sustain, release] = getADSRValues( + [value.attack, value.decay, value.sustain, value.release], + 'linear', + [0.001, 0.05, 0.6, 0.01], + ); let sound; if (waveforms.includes(s)) { From 3c1844046a4ca677891cec3a5df9db65618efb7d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 13 Jan 2024 23:01:16 +0100 Subject: [PATCH 49/93] basic browse page --- website/database.types.ts | 120 ++++++++++++++++++++++ website/src/components/SharedPatterns.tsx | 54 ++++++++++ website/src/pages/browse.astro | 14 +++ 3 files changed, 188 insertions(+) create mode 100644 website/database.types.ts create mode 100644 website/src/components/SharedPatterns.tsx create mode 100644 website/src/pages/browse.astro diff --git a/website/database.types.ts b/website/database.types.ts new file mode 100644 index 000000000..152742b4b --- /dev/null +++ b/website/database.types.ts @@ -0,0 +1,120 @@ +// generated with https://supabase.com/docs/reference/javascript/typescript-support#generating-typescript-types +export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]; + +export interface Database { + public: { + Tables: { + code: { + Row: { + code: string | null; + created_at: string | null; + featured: boolean | null; + hash: string | null; + id: number; + public: boolean | null; + }; + Insert: { + code?: string | null; + created_at?: string | null; + featured?: boolean | null; + hash?: string | null; + id?: number; + public?: boolean | null; + }; + Update: { + code?: string | null; + created_at?: string | null; + featured?: boolean | null; + hash?: string | null; + id?: number; + public?: boolean | null; + }; + Relationships: []; + }; + }; + Views: { + [_ in never]: never; + }; + Functions: { + [_ in never]: never; + }; + Enums: { + [_ in never]: never; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; +} + +export type Tables< + PublicTableNameOrOptions extends + | keyof (Database['public']['Tables'] & Database['public']['Views']) + | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof (Database[PublicTableNameOrOptions['schema']]['Tables'] & + Database[PublicTableNameOrOptions['schema']]['Views']) + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? (Database[PublicTableNameOrOptions['schema']]['Tables'] & + Database[PublicTableNameOrOptions['schema']]['Views'])[TableName] extends { + Row: infer R; + } + ? R + : never + : PublicTableNameOrOptions extends keyof (Database['public']['Tables'] & Database['public']['Views']) + ? (Database['public']['Tables'] & Database['public']['Views'])[PublicTableNameOrOptions] extends { + Row: infer R; + } + ? R + : never + : never; + +export type TablesInsert< + PublicTableNameOrOptions extends keyof Database['public']['Tables'] | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { + Insert: infer I; + } + ? I + : never + : PublicTableNameOrOptions extends keyof Database['public']['Tables'] + ? Database['public']['Tables'][PublicTableNameOrOptions] extends { + Insert: infer I; + } + ? I + : never + : never; + +export type TablesUpdate< + PublicTableNameOrOptions extends keyof Database['public']['Tables'] | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { + Update: infer U; + } + ? U + : never + : PublicTableNameOrOptions extends keyof Database['public']['Tables'] + ? Database['public']['Tables'][PublicTableNameOrOptions] extends { + Update: infer U; + } + ? U + : never + : never; + +export type Enums< + PublicEnumNameOrOptions extends keyof Database['public']['Enums'] | { schema: keyof Database }, + EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicEnumNameOrOptions['schema']]['Enums'] + : never = never, +> = PublicEnumNameOrOptions extends { schema: keyof Database } + ? Database[PublicEnumNameOrOptions['schema']]['Enums'][EnumName] + : PublicEnumNameOrOptions extends keyof Database['public']['Enums'] + ? Database['public']['Enums'][PublicEnumNameOrOptions] + : never; diff --git a/website/src/components/SharedPatterns.tsx b/website/src/components/SharedPatterns.tsx new file mode 100644 index 000000000..4deab67e7 --- /dev/null +++ b/website/src/components/SharedPatterns.tsx @@ -0,0 +1,54 @@ +import { createClient } from '@supabase/supabase-js'; +import { useCallback, useEffect, useMemo, useState } from 'react'; +import type { Database, Tables } from '../../database.types'; +import { getMetadata } from '../metadata_parser'; + +function PatternLink({ pattern }: { pattern: Tables<'code'> }) { + const meta = useMemo(() => getMetadata(pattern.code), [pattern]); + // console.log('meta', meta); + return ( + + {meta.title || pattern.hash} by {meta.by.join(',') || 'Anonymous'} + + ); +} + +export function SharedPatterns() { + const [publicPatterns, setPublicPatterns] = useState[] | null>([]); + const [featuredPatterns, setFeaturedPatterns] = useState[] | null>([]); + const init = useCallback(async () => { + const supabase = createClient( + 'https://pidxdsxphlhzjnzmifth.supabase.co', + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM', + ); + const { data: _publicPatterns } = await supabase.from('code').select().eq('public', true).limit(20); + const { data: _featuredPatterns } = await supabase.from('code').select().eq('featured', true).limit(20); + setPublicPatterns(_publicPatterns); + setFeaturedPatterns(_featuredPatterns); + /* console.log('public', publicPatterns); + console.log('featured', featuredPatterns); */ + }, []); + useEffect(() => { + init(); + }, [useCallback]); + return ( +
+

Featured

+
+ {featuredPatterns?.map((pattern, i) => ( +
+ +
+ ))} +
+

Last Creations

+
+ {publicPatterns?.map((pattern, i) => ( +
+ +
+ ))} +
+
+ ); +} diff --git a/website/src/pages/browse.astro b/website/src/pages/browse.astro new file mode 100644 index 000000000..3e63bf87a --- /dev/null +++ b/website/src/pages/browse.astro @@ -0,0 +1,14 @@ +--- +import HeadCommon from '../components/HeadCommon.astro'; +import { SharedPatterns } from '../components/SharedPatterns'; +--- + + + + + +
+

Browse

+ +
+ From 1ede99f71e93ab105925408b090330b90ffd97bb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 13 Jan 2024 23:12:22 +0100 Subject: [PATCH 50/93] ask for public sharing (very cheap) + order browse list --- website/src/components/SharedPatterns.tsx | 16 +++++++++++++--- website/src/repl/util.mjs | 5 ++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/website/src/components/SharedPatterns.tsx b/website/src/components/SharedPatterns.tsx index 4deab67e7..bbd5cc8d0 100644 --- a/website/src/components/SharedPatterns.tsx +++ b/website/src/components/SharedPatterns.tsx @@ -8,7 +8,7 @@ function PatternLink({ pattern }: { pattern: Tables<'code'> }) { // console.log('meta', meta); return ( - {meta.title || pattern.hash} by {meta.by.join(',') || 'Anonymous'} + {pattern.id}. {meta.title || pattern.hash} by {meta.by.join(',') || 'Anonymous'} ); } @@ -21,8 +21,18 @@ export function SharedPatterns() { 'https://pidxdsxphlhzjnzmifth.supabase.co', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM', ); - const { data: _publicPatterns } = await supabase.from('code').select().eq('public', true).limit(20); - const { data: _featuredPatterns } = await supabase.from('code').select().eq('featured', true).limit(20); + const { data: _publicPatterns } = await supabase + .from('code') + .select() + .eq('public', true) + .limit(20) + .order('id', { ascending: false }); + const { data: _featuredPatterns } = await supabase + .from('code') + .select() + .eq('featured', true) + .limit(20) + .order('id', { ascending: false }); setPublicPatterns(_publicPatterns); setFeaturedPatterns(_featuredPatterns); /* console.log('public', publicPatterns); diff --git a/website/src/repl/util.mjs b/website/src/repl/util.mjs index 81c41e9d0..325417d70 100644 --- a/website/src/repl/util.mjs +++ b/website/src/repl/util.mjs @@ -90,10 +90,13 @@ export async function shareCode(codeToShare) { logger(`Link already generated!`, 'error'); return; } + const isPublic = confirm( + 'Do you want your pattern to be public? If no, press cancel and you will get just a private link.', + ); // generate uuid in the browser const hash = nanoid(12); const shareUrl = window.location.origin + window.location.pathname + '?' + hash; - const { data, error } = await supabase.from('code').insert([{ code: codeToShare, hash }]); + const { error } = await supabase.from('code').insert([{ code: codeToShare, hash, ['public']: isPublic }]); if (!error) { lastShared = codeToShare; // copy shareUrl to clipboard From 204c9640503b9691fe0f7c2e736af7060ab96e0c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 13 Jan 2024 23:53:46 +0100 Subject: [PATCH 51/93] integrate public patterns into patterns tab --- website/src/components/SharedPatterns.tsx | 46 +++++++++----------- website/src/repl/panel/PatternsTab.jsx | 52 ++++++++++++++++++++++- website/src/repl/util.mjs | 10 ++++- website/src/settings.mjs | 31 +++++++++++++- 4 files changed, 108 insertions(+), 31 deletions(-) diff --git a/website/src/components/SharedPatterns.tsx b/website/src/components/SharedPatterns.tsx index bbd5cc8d0..1cdca7923 100644 --- a/website/src/components/SharedPatterns.tsx +++ b/website/src/components/SharedPatterns.tsx @@ -1,53 +1,43 @@ -import { createClient } from '@supabase/supabase-js'; import { useCallback, useEffect, useMemo, useState } from 'react'; -import type { Database, Tables } from '../../database.types'; +import type { Tables } from '../../database.types'; import { getMetadata } from '../metadata_parser'; +import { loadFeaturedPatterns, loadPublicPatterns } from '../repl/util.mjs'; -function PatternLink({ pattern }: { pattern: Tables<'code'> }) { +export function PatternLabel({ pattern }: { pattern: Tables<'code'> }) { const meta = useMemo(() => getMetadata(pattern.code), [pattern]); - // console.log('meta', meta); return ( - + <> {pattern.id}. {meta.title || pattern.hash} by {meta.by.join(',') || 'Anonymous'} - + ); } -export function SharedPatterns() { +export const usePublicPatterns = () => { const [publicPatterns, setPublicPatterns] = useState[] | null>([]); const [featuredPatterns, setFeaturedPatterns] = useState[] | null>([]); const init = useCallback(async () => { - const supabase = createClient( - 'https://pidxdsxphlhzjnzmifth.supabase.co', - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM', - ); - const { data: _publicPatterns } = await supabase - .from('code') - .select() - .eq('public', true) - .limit(20) - .order('id', { ascending: false }); - const { data: _featuredPatterns } = await supabase - .from('code') - .select() - .eq('featured', true) - .limit(20) - .order('id', { ascending: false }); + const { data: _publicPatterns } = await loadPublicPatterns(); + const { data: _featuredPatterns } = await loadFeaturedPatterns(); setPublicPatterns(_publicPatterns); setFeaturedPatterns(_featuredPatterns); - /* console.log('public', publicPatterns); - console.log('featured', featuredPatterns); */ }, []); useEffect(() => { init(); }, [useCallback]); + return { publicPatterns, featuredPatterns }; +}; + +export function SharedPatterns() { + const { publicPatterns, featuredPatterns } = usePublicPatterns(); return (

Featured

{featuredPatterns?.map((pattern, i) => (
- + + +
))}
@@ -55,7 +45,9 @@ export function SharedPatterns() {
{publicPatterns?.map((pattern, i) => (
- + + +
))}
diff --git a/website/src/repl/panel/PatternsTab.jsx b/website/src/repl/panel/PatternsTab.jsx index 4466b5999..a3d674606 100644 --- a/website/src/repl/panel/PatternsTab.jsx +++ b/website/src/repl/panel/PatternsTab.jsx @@ -1,6 +1,8 @@ import { DocumentDuplicateIcon, PencilSquareIcon, TrashIcon } from '@heroicons/react/20/solid'; import { useMemo } from 'react'; import { + $featuredPatterns, + $publicPatterns, clearUserPatterns, deleteActivePattern, duplicateActivePattern, @@ -14,6 +16,8 @@ import { useSettings, } from '../../settings.mjs'; import * as tunes from '../tunes.mjs'; +import { PatternLabel } from '../../components/SharedPatterns'; +import { useStore } from '@nanostores/react'; function classNames(...classes) { return classes.filter(Boolean).join(' '); @@ -22,6 +26,8 @@ function classNames(...classes) { export function PatternsTab({ context }) { const { userPatterns } = useSettings(); const activePattern = useActivePattern(); + const featuredPatterns = useStore($featuredPatterns); + const publicPatterns = useStore($publicPatterns); const isExample = useMemo(() => activePattern && !!tunes[activePattern], [activePattern]); return (
@@ -94,8 +100,52 @@ export function PatternsTab({ context }) {
+ {featuredPatterns && ( +
+

Featured Patterns

+ +
+ )} + {publicPatterns && ( +
+

Last Creations

+ +
+ )}
-

Examples

+

Stock Examples

{Object.entries(tunes).map(([key, tune]) => ( { } initializeAudioOutput(); }; + +export function loadPublicPatterns() { + return supabase.from('code').select().eq('public', true).limit(20).order('id', { ascending: false }); +} + +export function loadFeaturedPatterns() { + return supabase.from('code').select().eq('featured', true).limit(20).order('id', { ascending: false }); +} diff --git a/website/src/settings.mjs b/website/src/settings.mjs index 0e4338062..2f973a2f7 100644 --- a/website/src/settings.mjs +++ b/website/src/settings.mjs @@ -1,8 +1,22 @@ +import { atom } from 'nanostores'; import { persistentMap, persistentAtom } from '@nanostores/persistent'; import { useStore } from '@nanostores/react'; import { register } from '@strudel.cycles/core'; import * as tunes from './repl/tunes.mjs'; import { logger } from '@strudel.cycles/core'; +import { loadPublicPatterns, loadFeaturedPatterns } from './repl/util.mjs'; + +export let $publicPatterns = atom([]); +export let $featuredPatterns = atom([]); + +async function loadDBPatterns() { + const { data: publicPatterns } = await loadPublicPatterns(); + $publicPatterns.set(publicPatterns); + const { data: featuredPatterns } = await loadFeaturedPatterns(); + $featuredPatterns.set(featuredPatterns); +} + +loadDBPatterns(); export const defaultAudioDeviceName = 'System Standard'; @@ -172,12 +186,25 @@ export function updateUserCode(code) { setActivePattern(example); return; } - + const publicPattern = $publicPatterns.get().find((pat) => pat.code === code); + if (publicPattern) { + setActivePattern(publicPattern.hash); + return; + } + const featuredPattern = $featuredPatterns.get().find((pat) => pat.code === code); + if (featuredPattern) { + setActivePattern(featuredPattern.hash); + return; + } if (!activePattern) { // create new user pattern activePattern = newUserPattern(); setActivePattern(activePattern); - } else if (!!tunes[activePattern] && code !== tunes[activePattern]) { + } else if ( + (!!tunes[activePattern] && code !== tunes[activePattern]) || // fork example tune? + $publicPatterns.get().find((p) => p.hash === activePattern) || // fork public pattern? + $featuredPatterns.get().find((p) => p.hash === activePattern) // fork featured pattern? + ) { // fork example activePattern = getNextCloneName(activePattern); setActivePattern(activePattern); From 5314c83534db1d28d158c274417a08eb15bec4b7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 00:02:27 +0100 Subject: [PATCH 52/93] delete browse page for now --- website/src/components/SharedPatterns.tsx | 56 ----------------------- website/src/pages/browse.astro | 14 ------ website/src/repl/panel/PatternsTab.jsx | 11 ++++- 3 files changed, 10 insertions(+), 71 deletions(-) delete mode 100644 website/src/components/SharedPatterns.tsx delete mode 100644 website/src/pages/browse.astro diff --git a/website/src/components/SharedPatterns.tsx b/website/src/components/SharedPatterns.tsx deleted file mode 100644 index 1cdca7923..000000000 --- a/website/src/components/SharedPatterns.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { useCallback, useEffect, useMemo, useState } from 'react'; -import type { Tables } from '../../database.types'; -import { getMetadata } from '../metadata_parser'; -import { loadFeaturedPatterns, loadPublicPatterns } from '../repl/util.mjs'; - -export function PatternLabel({ pattern }: { pattern: Tables<'code'> }) { - const meta = useMemo(() => getMetadata(pattern.code), [pattern]); - return ( - <> - {pattern.id}. {meta.title || pattern.hash} by {meta.by.join(',') || 'Anonymous'} - - ); -} - -export const usePublicPatterns = () => { - const [publicPatterns, setPublicPatterns] = useState[] | null>([]); - const [featuredPatterns, setFeaturedPatterns] = useState[] | null>([]); - const init = useCallback(async () => { - const { data: _publicPatterns } = await loadPublicPatterns(); - const { data: _featuredPatterns } = await loadFeaturedPatterns(); - setPublicPatterns(_publicPatterns); - setFeaturedPatterns(_featuredPatterns); - }, []); - useEffect(() => { - init(); - }, [useCallback]); - return { publicPatterns, featuredPatterns }; -}; - -export function SharedPatterns() { - const { publicPatterns, featuredPatterns } = usePublicPatterns(); - return ( -
-

Featured

-
- {featuredPatterns?.map((pattern, i) => ( - - ))} -
-

Last Creations

-
- {publicPatterns?.map((pattern, i) => ( -
- - - -
- ))} -
-
- ); -} diff --git a/website/src/pages/browse.astro b/website/src/pages/browse.astro deleted file mode 100644 index 3e63bf87a..000000000 --- a/website/src/pages/browse.astro +++ /dev/null @@ -1,14 +0,0 @@ ---- -import HeadCommon from '../components/HeadCommon.astro'; -import { SharedPatterns } from '../components/SharedPatterns'; ---- - - - - - -
-

Browse

- -
- diff --git a/website/src/repl/panel/PatternsTab.jsx b/website/src/repl/panel/PatternsTab.jsx index a3d674606..1b5ecef65 100644 --- a/website/src/repl/panel/PatternsTab.jsx +++ b/website/src/repl/panel/PatternsTab.jsx @@ -16,8 +16,8 @@ import { useSettings, } from '../../settings.mjs'; import * as tunes from '../tunes.mjs'; -import { PatternLabel } from '../../components/SharedPatterns'; import { useStore } from '@nanostores/react'; +import { getMetadata } from '../../metadata_parser'; function classNames(...classes) { return classes.filter(Boolean).join(' '); @@ -167,3 +167,12 @@ export function PatternsTab({ context }) {
); } + +export function PatternLabel({ pattern } /* : { pattern: Tables<'code'> } */) { + const meta = useMemo(() => getMetadata(pattern.code), [pattern]); + return ( + <> + {pattern.id}. {meta.title || pattern.hash} by {meta.by.join(',') || 'Anonymous'} + + ); +} From f38758934234ba38028e05820d47c5cf3c93128d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 00:53:43 +0100 Subject: [PATCH 53/93] hotfix: fix build error --- website/src/settings.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/src/settings.mjs b/website/src/settings.mjs index 2f973a2f7..286eb52d8 100644 --- a/website/src/settings.mjs +++ b/website/src/settings.mjs @@ -16,7 +16,9 @@ async function loadDBPatterns() { $featuredPatterns.set(featuredPatterns); } -loadDBPatterns(); +if (typeof window !== 'undefined') { + loadDBPatterns(); +} export const defaultAudioDeviceName = 'System Standard'; From 6d32d4024d9ffce0f8c484966bbc1a366786a646 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 01:08:01 +0100 Subject: [PATCH 54/93] hotfix: fix built version loading at runtime.. --- website/src/repl/util.mjs | 32 ++++++++++++++++++++++++-------- website/src/settings.mjs | 12 ------------ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/website/src/repl/util.mjs b/website/src/repl/util.mjs index adb99b3db..3405e93d9 100644 --- a/website/src/repl/util.mjs +++ b/website/src/repl/util.mjs @@ -9,6 +9,7 @@ import { createClient } from '@supabase/supabase-js'; import { nanoid } from 'nanoid'; import { writeText } from '@tauri-apps/api/clipboard'; import { createContext } from 'react'; +import { $publicPatterns, $featuredPatterns } from '../settings.mjs'; // Create a single supabase client for interacting with your database export const supabase = createClient( @@ -16,6 +17,29 @@ export const supabase = createClient( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM', ); +export function loadPublicPatterns() { + return supabase.from('code').select().eq('public', true).limit(20).order('id', { ascending: false }); +} + +export function loadFeaturedPatterns() { + return supabase.from('code').select().eq('featured', true).limit(20).order('id', { ascending: false }); +} + +async function loadDBPatterns() { + try { + const { data: publicPatterns } = await loadPublicPatterns(); + const { data: featuredPatterns } = await loadFeaturedPatterns(); + $publicPatterns.set(publicPatterns); + $featuredPatterns.set(featuredPatterns); + } catch (err) { + console.error('error loading patterns'); + } +} + +if (typeof window !== 'undefined') { + loadDBPatterns(); +} + export async function initCode() { // load code from url hash (either short hash from database or decode long hash) try { @@ -150,11 +174,3 @@ export const setAudioDevice = async (id) => { } initializeAudioOutput(); }; - -export function loadPublicPatterns() { - return supabase.from('code').select().eq('public', true).limit(20).order('id', { ascending: false }); -} - -export function loadFeaturedPatterns() { - return supabase.from('code').select().eq('featured', true).limit(20).order('id', { ascending: false }); -} diff --git a/website/src/settings.mjs b/website/src/settings.mjs index 286eb52d8..00237022f 100644 --- a/website/src/settings.mjs +++ b/website/src/settings.mjs @@ -4,22 +4,10 @@ import { useStore } from '@nanostores/react'; import { register } from '@strudel.cycles/core'; import * as tunes from './repl/tunes.mjs'; import { logger } from '@strudel.cycles/core'; -import { loadPublicPatterns, loadFeaturedPatterns } from './repl/util.mjs'; export let $publicPatterns = atom([]); export let $featuredPatterns = atom([]); -async function loadDBPatterns() { - const { data: publicPatterns } = await loadPublicPatterns(); - $publicPatterns.set(publicPatterns); - const { data: featuredPatterns } = await loadFeaturedPatterns(); - $featuredPatterns.set(featuredPatterns); -} - -if (typeof window !== 'undefined') { - loadDBPatterns(); -} - export const defaultAudioDeviceName = 'System Standard'; export const defaultSettings = { From 53771d7f95d3dee532a5f6799b26cf98ae4676b7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 01:50:48 +0100 Subject: [PATCH 55/93] hotfix: avoid crash for anonymous patterns --- website/src/repl/panel/PatternsTab.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/repl/panel/PatternsTab.jsx b/website/src/repl/panel/PatternsTab.jsx index 1b5ecef65..cec165c1f 100644 --- a/website/src/repl/panel/PatternsTab.jsx +++ b/website/src/repl/panel/PatternsTab.jsx @@ -172,7 +172,7 @@ export function PatternLabel({ pattern } /* : { pattern: Tables<'code'> } */) { const meta = useMemo(() => getMetadata(pattern.code), [pattern]); return ( <> - {pattern.id}. {meta.title || pattern.hash} by {meta.by.join(',') || 'Anonymous'} + {pattern.id}. {meta.title || pattern.hash} by {Array.isArray(meta.by) ? meta.by.join(',') : 'Anonymous'} ); } From 70712bdab653825507e5334c9dcb99cf0f2430c3 Mon Sep 17 00:00:00 2001 From: fnordomat <46D46D1246803312401472B5A7427E237B7908CA> Date: Sun, 14 Jan 2024 10:19:49 +0100 Subject: [PATCH 56/93] fix codeformat --- packages/superdough/vowel.mjs | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/superdough/vowel.mjs b/packages/superdough/vowel.mjs index 7d5dac4a4..3f30aef1e 100644 --- a/packages/superdough/vowel.mjs +++ b/packages/superdough/vowel.mjs @@ -15,14 +15,27 @@ export var vowelFormant = { en: { freqs: [600, 1480, 2450, 3200, 3300], gains: [1, 0.15, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, an: { freqs: [700, 1050, 2500, 3000, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, on: { freqs: [500, 1080, 2350, 3000, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, - get æ() { return this.ae; }, - get ø() { return this.oe; }, - get ɑ() { return this.aa; }, - get å() { return this.aa; }, - get ö() { return this.oe; }, - get ü() { return this.ue; }, - get ı() { return this.y; }, - + get æ() { + return this.ae; + }, + get ø() { + return this.oe; + }, + get ɑ() { + return this.aa; + }, + get å() { + return this.aa; + }, + get ö() { + return this.oe; + }, + get ü() { + return this.ue; + }, + get ı() { + return this.y; + }, }; if (typeof GainNode !== 'undefined') { class VowelNode extends GainNode { From 0d6bdfb514368d952344d313b72d9c63536a9973 Mon Sep 17 00:00:00 2001 From: Alex McLean Date: Sun, 14 Jan 2024 10:14:43 +0000 Subject: [PATCH 57/93] Link to creative commons chooser --- website/src/pages/learn/metadata.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/learn/metadata.mdx b/website/src/pages/learn/metadata.mdx index 9ade4447c..a5d173625 100644 --- a/website/src/pages/learn/metadata.mdx +++ b/website/src/pages/learn/metadata.mdx @@ -50,7 +50,7 @@ Available tags are: - `@title`: music title - `@by`: music author(s), separated by comma, eventually followed with a link in `<>` (ex: `@by John Doe `) -- `@license`: music license(s) +- `@license`: music license(s), e.g. CC BY-NC-SA. Unsure? [Choose yours here](https://creativecommons.org/choose/) - `@details`: some additional information about the music - `@url`: web page(s) related to the music (git repo, soundcloud link, etc.) - `@genre`: music genre(s) (pop, jazz, etc) From 945e7082cdaad80057e3b6f2d83f77eb5da265c5 Mon Sep 17 00:00:00 2001 From: Alex McLean Date: Sun, 14 Jan 2024 10:15:40 +0000 Subject: [PATCH 58/93] Update metadata.mdx --- website/src/pages/learn/metadata.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/learn/metadata.mdx b/website/src/pages/learn/metadata.mdx index a5d173625..e8bb86dfc 100644 --- a/website/src/pages/learn/metadata.mdx +++ b/website/src/pages/learn/metadata.mdx @@ -50,7 +50,7 @@ Available tags are: - `@title`: music title - `@by`: music author(s), separated by comma, eventually followed with a link in `<>` (ex: `@by John Doe `) -- `@license`: music license(s), e.g. CC BY-NC-SA. Unsure? [Choose yours here](https://creativecommons.org/choose/) +- `@license`: music license(s), e.g. CC BY-NC-SA. Unsure? [Choose a creative commons license here](https://creativecommons.org/choose/) - `@details`: some additional information about the music - `@url`: web page(s) related to the music (git repo, soundcloud link, etc.) - `@genre`: music genre(s) (pop, jazz, etc) From e6d028fd6b0771de26d1fd88c97c52ed3af847e7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 16:27:11 +0100 Subject: [PATCH 59/93] soundfont mixing --- packages/soundfonts/fontloader.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/soundfonts/fontloader.mjs b/packages/soundfonts/fontloader.mjs index 8d8fb02bf..dc3f4b610 100644 --- a/packages/soundfonts/fontloader.mjs +++ b/packages/soundfonts/fontloader.mjs @@ -146,7 +146,7 @@ export function registerSoundfonts() { const envGain = ctx.createGain(); const node = bufferSource.connect(envGain); const holdEnd = time + duration; - getParamADSR(node.gain, attack, decay, sustain, release, 0, 1, time, holdEnd, 'linear'); + getParamADSR(node.gain, attack, decay, sustain, release, 0, 0.3, time, holdEnd, 'linear'); let envEnd = holdEnd + release + 0.01; bufferSource.stop(envEnd); From 090194856413b3dcf4d7a6a9dd67aedc7b742ab1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 21:32:38 +0100 Subject: [PATCH 60/93] fanchor default to 0.5 for now --- 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 d03007f17..f5674f2cf 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -276,7 +276,7 @@ export const superdough = async (value, deadline, hapDuration) => { density = 0.03, // filters ftype = '12db', - fanchor = 0, + fanchor = 0.5, // low pass cutoff, lpenv, From 0566b7bcb373fe20fe6316afabc96b68897780b9 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 23:16:09 +0100 Subject: [PATCH 61/93] basic blog with release notes --- pnpm-lock.yaml | 7 + website/.astro/types.d.ts | 206 ++++++++++++++++++ website/package.json | 1 + website/src/components/BlogPost.astro | 21 ++ website/src/components/Header/Header.astro | 2 +- .../components/PageContent/PageContent.astro | 11 +- .../components/RightSidebar/MoreMenu.astro | 2 +- .../RightSidebar/RightSidebar.astro | 2 +- website/src/config.ts | 1 + .../content/blog/release-0.0.2-schwindlig.mdx | 42 ++++ .../blog/release-0.0.2.1-stuermisch.mdx | 55 +++++ .../content/blog/release-0.0.3-maelstrom.mdx | 68 ++++++ .../src/content/blog/release-0.0.4-gischt.mdx | 47 ++++ .../content/blog/release-0.3.0-donauwelle.mdx | 67 ++++++ .../content/blog/release-0.4.0-brandung.mdx | 17 ++ .../src/content/blog/release-0.5.0-wirbel.mdx | 61 ++++++ .../blog/release-0.6.0-zimtschnecke.mdx | 86 ++++++++ .../content/blog/release-0.7.0-zuckerguss.mdx | 90 ++++++++ .../blog/release-0.8.0-himbeermuffin.mdx | 130 +++++++++++ .../blog/release-0.9.0-bananenbrot.mdx | 114 ++++++++++ website/src/content/config.ts | 24 ++ website/src/env.d.ts | 2 + website/src/pages/blog.astro | 45 ++++ 23 files changed, 1089 insertions(+), 12 deletions(-) create mode 100644 website/.astro/types.d.ts create mode 100644 website/src/components/BlogPost.astro create mode 100644 website/src/content/blog/release-0.0.2-schwindlig.mdx create mode 100644 website/src/content/blog/release-0.0.2.1-stuermisch.mdx create mode 100644 website/src/content/blog/release-0.0.3-maelstrom.mdx create mode 100644 website/src/content/blog/release-0.0.4-gischt.mdx create mode 100644 website/src/content/blog/release-0.3.0-donauwelle.mdx create mode 100644 website/src/content/blog/release-0.4.0-brandung.mdx create mode 100644 website/src/content/blog/release-0.5.0-wirbel.mdx create mode 100644 website/src/content/blog/release-0.6.0-zimtschnecke.mdx create mode 100644 website/src/content/blog/release-0.7.0-zuckerguss.mdx create mode 100644 website/src/content/blog/release-0.8.0-himbeermuffin.mdx create mode 100644 website/src/content/blog/release-0.9.0-bananenbrot.mdx create mode 100644 website/src/content/config.ts create mode 100644 website/src/pages/blog.astro diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8b6e007b..1fb74b485 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -586,6 +586,9 @@ importers: claviature: specifier: ^0.1.0 version: 0.1.0 + date-fns: + specifier: ^3.2.0 + version: 3.2.0 nanoid: specifier: ^5.0.4 version: 5.0.4 @@ -6220,6 +6223,10 @@ packages: engines: {node: '>= 12'} dev: true + /date-fns@3.2.0: + resolution: {integrity: sha512-E4KWKavANzeuusPi0jUjpuI22SURAznGkx7eZV+4i6x2A+IZxAMcajgkvuDAU1bg40+xuhW1zRdVIIM/4khuIg==} + dev: false + /dateformat@3.0.3: resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} dev: true diff --git a/website/.astro/types.d.ts b/website/.astro/types.d.ts new file mode 100644 index 000000000..ea8fd38be --- /dev/null +++ b/website/.astro/types.d.ts @@ -0,0 +1,206 @@ +declare module 'astro:content' { + interface Render { + '.mdx': Promise<{ + Content: import('astro').MarkdownInstance<{}>['Content']; + headings: import('astro').MarkdownHeading[]; + remarkPluginFrontmatter: Record; + }>; + } +} + +declare module 'astro:content' { + interface Render { + '.md': Promise<{ + Content: import('astro').MarkdownInstance<{}>['Content']; + headings: import('astro').MarkdownHeading[]; + remarkPluginFrontmatter: Record; + }>; + } +} + +declare module 'astro:content' { + export { z } from 'astro/zod'; + + type Flatten = T extends { [K: string]: infer U } ? U : never; + + export type CollectionKey = keyof AnyEntryMap; + export type CollectionEntry = Flatten; + + export type ContentCollectionKey = keyof ContentEntryMap; + export type DataCollectionKey = keyof DataEntryMap; + + // This needs to be in sync with ImageMetadata + export type ImageFunction = () => import('astro/zod').ZodObject<{ + src: import('astro/zod').ZodString; + width: import('astro/zod').ZodNumber; + height: import('astro/zod').ZodNumber; + format: import('astro/zod').ZodUnion< + [ + import('astro/zod').ZodLiteral<'png'>, + import('astro/zod').ZodLiteral<'jpg'>, + import('astro/zod').ZodLiteral<'jpeg'>, + import('astro/zod').ZodLiteral<'tiff'>, + import('astro/zod').ZodLiteral<'webp'>, + import('astro/zod').ZodLiteral<'gif'>, + import('astro/zod').ZodLiteral<'svg'>, + import('astro/zod').ZodLiteral<'avif'>, + ] + >; + }>; + + type BaseSchemaWithoutEffects = + | import('astro/zod').AnyZodObject + | import('astro/zod').ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]> + | import('astro/zod').ZodDiscriminatedUnion + | import('astro/zod').ZodIntersection; + + type BaseSchema = + | BaseSchemaWithoutEffects + | import('astro/zod').ZodEffects; + + export type SchemaContext = { image: ImageFunction }; + + type DataCollectionConfig = { + type: 'data'; + schema?: S | ((context: SchemaContext) => S); + }; + + type ContentCollectionConfig = { + type?: 'content'; + schema?: S | ((context: SchemaContext) => S); + }; + + type CollectionConfig = ContentCollectionConfig | DataCollectionConfig; + + export function defineCollection( + input: CollectionConfig + ): CollectionConfig; + + type AllValuesOf = T extends any ? T[keyof T] : never; + type ValidContentEntrySlug = AllValuesOf< + ContentEntryMap[C] + >['slug']; + + export function getEntryBySlug< + C extends keyof ContentEntryMap, + E extends ValidContentEntrySlug | (string & {}), + >( + collection: C, + // Note that this has to accept a regular string too, for SSR + entrySlug: E + ): E extends ValidContentEntrySlug + ? Promise> + : Promise | undefined>; + + export function getDataEntryById( + collection: C, + entryId: E + ): Promise>; + + export function getCollection>( + collection: C, + filter?: (entry: CollectionEntry) => entry is E + ): Promise; + export function getCollection( + collection: C, + filter?: (entry: CollectionEntry) => unknown + ): Promise[]>; + + export function getEntry< + C extends keyof ContentEntryMap, + E extends ValidContentEntrySlug | (string & {}), + >(entry: { + collection: C; + slug: E; + }): E extends ValidContentEntrySlug + ? Promise> + : Promise | undefined>; + export function getEntry< + C extends keyof DataEntryMap, + E extends keyof DataEntryMap[C] | (string & {}), + >(entry: { + collection: C; + id: E; + }): E extends keyof DataEntryMap[C] + ? Promise + : Promise | undefined>; + export function getEntry< + C extends keyof ContentEntryMap, + E extends ValidContentEntrySlug | (string & {}), + >( + collection: C, + slug: E + ): E extends ValidContentEntrySlug + ? Promise> + : Promise | undefined>; + export function getEntry< + C extends keyof DataEntryMap, + E extends keyof DataEntryMap[C] | (string & {}), + >( + collection: C, + id: E + ): E extends keyof DataEntryMap[C] + ? Promise + : Promise | undefined>; + + /** Resolve an array of entry references from the same collection */ + export function getEntries( + entries: { + collection: C; + slug: ValidContentEntrySlug; + }[] + ): Promise[]>; + export function getEntries( + entries: { + collection: C; + id: keyof DataEntryMap[C]; + }[] + ): Promise[]>; + + export function reference( + collection: C + ): import('astro/zod').ZodEffects< + import('astro/zod').ZodString, + C extends keyof ContentEntryMap + ? { + collection: C; + slug: ValidContentEntrySlug; + } + : { + collection: C; + id: keyof DataEntryMap[C]; + } + >; + // Allow generic `string` to avoid excessive type errors in the config + // if `dev` is not running to update as you edit. + // Invalid collection names will be caught at build time. + export function reference( + collection: C + ): import('astro/zod').ZodEffects; + + type ReturnTypeOrOriginal = T extends (...args: any[]) => infer R ? R : T; + type InferEntrySchema = import('astro/zod').infer< + ReturnTypeOrOriginal['schema']> + >; + + type ContentEntryMap = { + "blog": { +"hello.mdx": { + id: "hello.mdx"; + slug: "hello"; + body: string; + collection: "blog"; + data: any +} & { render(): Render[".mdx"] }; +}; + + }; + + type DataEntryMap = { + + }; + + type AnyEntryMap = ContentEntryMap & DataEntryMap; + + type ContentConfig = never; +} diff --git a/website/package.json b/website/package.json index a324821bc..0f1e1e8ae 100644 --- a/website/package.json +++ b/website/package.json @@ -48,6 +48,7 @@ "astro": "^4.0.8", "canvas": "^2.11.2", "claviature": "^0.1.0", + "date-fns": "^3.2.0", "nanoid": "^5.0.4", "nanostores": "^0.9.5", "react": "^18.2.0", diff --git a/website/src/components/BlogPost.astro b/website/src/components/BlogPost.astro new file mode 100644 index 000000000..1fdb5a1a4 --- /dev/null +++ b/website/src/components/BlogPost.astro @@ -0,0 +1,21 @@ +--- +import type { CollectionEntry } from 'astro:content'; + +type Props = CollectionEntry<'blog'>['data']; + +const { post } = Astro.props; +const { Content } = await post.render(); +--- + +
+
+
+

{post.title}

+
+
+
+ +
+
diff --git a/website/src/components/Header/Header.astro b/website/src/components/Header/Header.astro index 6447d9d63..cbc91ca0a 100644 --- a/website/src/components/Header/Header.astro +++ b/website/src/components/Header/Header.astro @@ -9,7 +9,7 @@ import MobileNav from '../../docs/MobileNav'; import { SIDEBAR } from '../../config'; type Props = { - currentPage: string; + currentPage?: string; }; const { currentPage } = Astro.props as Props; diff --git a/website/src/components/PageContent/PageContent.astro b/website/src/components/PageContent/PageContent.astro index 9c433945f..c53053aff 100644 --- a/website/src/components/PageContent/PageContent.astro +++ b/website/src/components/PageContent/PageContent.astro @@ -1,18 +1,11 @@ --- -import type { Frontmatter } from '../../config'; import MoreMenu from '../RightSidebar/MoreMenu.astro'; -import TableOfContents from '../RightSidebar/TableOfContents'; -import type { MarkdownHeading } from 'astro'; type Props = { - frontmatter: Frontmatter; - headings: MarkdownHeading[]; - githubEditUrl: string; + githubEditUrl?: string; }; -const { frontmatter, headings, githubEditUrl } = Astro.props as Props; -const title = frontmatter.title; -const currentPage = Astro.url.pathname; +const { githubEditUrl } = Astro.props as Props; ---
diff --git a/website/src/components/RightSidebar/MoreMenu.astro b/website/src/components/RightSidebar/MoreMenu.astro index 1cf1c4e5a..5205c9c57 100644 --- a/website/src/components/RightSidebar/MoreMenu.astro +++ b/website/src/components/RightSidebar/MoreMenu.astro @@ -2,7 +2,7 @@ import * as CONFIG from '../../config'; type Props = { - editHref: string; + editHref?: string; }; const { editHref } = Astro.props as Props; diff --git a/website/src/components/RightSidebar/RightSidebar.astro b/website/src/components/RightSidebar/RightSidebar.astro index ba193d240..cd501b1a2 100644 --- a/website/src/components/RightSidebar/RightSidebar.astro +++ b/website/src/components/RightSidebar/RightSidebar.astro @@ -6,7 +6,7 @@ import AvatarList from '../Footer/AvatarList.astro'; type Props = { headings: MarkdownHeading[]; - githubEditUrl: string; + githubEditUrl?: string; }; const { headings, githubEditUrl } = Astro.props as Props; diff --git a/website/src/config.ts b/website/src/config.ts index fc904bfa6..effc593c1 100644 --- a/website/src/config.ts +++ b/website/src/config.ts @@ -57,6 +57,7 @@ export const SIDEBAR: Sidebar = { Presentation: [ { text: 'What is Strudel?', link: 'workshop/getting-started' }, { text: 'Showcase', link: 'intro/showcase' }, + { text: 'Blog', link: 'blog' }, ], Workshop: [ // { text: 'Getting Started', link: 'workshop/getting-started' }, diff --git a/website/src/content/blog/release-0.0.2-schwindlig.mdx b/website/src/content/blog/release-0.0.2-schwindlig.mdx new file mode 100644 index 000000000..3cb9b50be --- /dev/null +++ b/website/src/content/blog/release-0.0.2-schwindlig.mdx @@ -0,0 +1,42 @@ +--- +title: 'Release Notes v0.0.2 Schwindlig' +description: '' +date: '2022-03-28' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.0.2 Schwindlig + +## What's Changed + +- Most work done as [commits to main](https://github.com/tidalcycles/strudel/commits/2a0d8c3f77ff7b34e82602e2d02400707f367316) +- repl + reify functions by @felixroos in https://github.com/tidalcycles/strudel/pull/2 +- Fix path by @yaxu in https://github.com/tidalcycles/strudel/pull/3 +- update readme for local dev by @kindohm in https://github.com/tidalcycles/strudel/pull/4 +- Patternify all the things by @yaxu in https://github.com/tidalcycles/strudel/pull/5 +- krill parser + improved repl by @felixroos in https://github.com/tidalcycles/strudel/pull/6 +- fixed editor crash by @felixroos in https://github.com/tidalcycles/strudel/pull/7 +- timeCat by @yaxu in https://github.com/tidalcycles/strudel/pull/8 +- Bugfix every, and create more top level functions by @yaxu in https://github.com/tidalcycles/strudel/pull/9 +- Failing test for `when` WIP by @yaxu in https://github.com/tidalcycles/strudel/pull/10 +- Added mask() and struct() by @yaxu in https://github.com/tidalcycles/strudel/pull/11 +- Add continuous signals (sine, cosine, saw, etc) by @yaxu in https://github.com/tidalcycles/strudel/pull/13 +- add apply and layer, and missing div/mul methods by @yaxu in https://github.com/tidalcycles/strudel/pull/15 +- higher latencyHint by @felixroos in https://github.com/tidalcycles/strudel/pull/16 +- test: 📦 Add missing dependency and a CI check, to prevent oversights ;p by @puria in https://github.com/tidalcycles/strudel/pull/17 +- fix: 💄 Enhance visualisation of the Tutorial on mobile by @puria in https://github.com/tidalcycles/strudel/pull/19 +- Stateful queries and events (WIP) by @yaxu in https://github.com/tidalcycles/strudel/pull/14 +- Fix resolveState by @yaxu in https://github.com/tidalcycles/strudel/pull/22 +- added \_asNumber + interprete numbers as midi by @felixroos in https://github.com/tidalcycles/strudel/pull/21 +- Update package.json by @ChiakiUehira in https://github.com/tidalcycles/strudel/pull/23 +- packaging by @felixroos in https://github.com/tidalcycles/strudel/pull/24 + +## New Contributors + +- @felixroos made their first contribution in https://github.com/tidalcycles/strudel/pull/2 +- @kindohm made their first contribution in https://github.com/tidalcycles/strudel/pull/4 +- @puria made their first contribution in https://github.com/tidalcycles/strudel/pull/17 +- @ChiakiUehira made their first contribution in https://github.com/tidalcycles/strudel/pull/23 + +**Full Changelog**: https://github.com/tidalcycles/strudel/commits/2a0d8c3f77ff7b34e82602e2d02400707f367316 diff --git a/website/src/content/blog/release-0.0.2.1-stuermisch.mdx b/website/src/content/blog/release-0.0.2.1-stuermisch.mdx new file mode 100644 index 000000000..28da1a8ff --- /dev/null +++ b/website/src/content/blog/release-0.0.2.1-stuermisch.mdx @@ -0,0 +1,55 @@ +--- +title: 'Release Notes v0.0.3 Stürmisch' +date: '2022-05-20' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.0.2.1 Stürmisch + +## What's Changed + +- Add chunk, chunkBack and iterBack by @yaxu in https://github.com/tidalcycles/strudel/pull/25 +- Update tutorial.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/37 +- Update tutorial.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/38 +- Compose by @felixroos in https://github.com/tidalcycles/strudel/pull/40 +- Fix polymeter by @yaxu in https://github.com/tidalcycles/strudel/pull/44 +- First run at squeezeBind, ref #32 by @yaxu in https://github.com/tidalcycles/strudel/pull/48 +- Implement `chop()` by @yaxu in https://github.com/tidalcycles/strudel/pull/50 +- OSC and SuperDirt support by @yaxu in https://github.com/tidalcycles/strudel/pull/27 +- More functions by @yaxu in https://github.com/tidalcycles/strudel/pull/56 +- More functions by @yaxu in https://github.com/tidalcycles/strudel/pull/61 +- Separate out strudel.mjs, make index.mjs aggregate module by @yaxu in https://github.com/tidalcycles/strudel/pull/62 +- Speech output by @felixroos in https://github.com/tidalcycles/strudel/pull/67 +- use new fixed version of osc-js package by @felixroos in https://github.com/tidalcycles/strudel/pull/68 +- First effort at rand() by @yaxu in https://github.com/tidalcycles/strudel/pull/69 +- More randomness, fix `rand`, and add `brand`, `irand` and `choose` by @yaxu in https://github.com/tidalcycles/strudel/pull/70 +- webaudio package by @felixroos in https://github.com/tidalcycles/strudel/pull/26 +- Port `perlin` noise, `rangex`, and `palindrome` by @yaxu in https://github.com/tidalcycles/strudel/pull/73 +- More random functions by @yaxu in https://github.com/tidalcycles/strudel/pull/74 +- Try to fix appLeft / appRight by @yaxu in https://github.com/tidalcycles/strudel/pull/75 +- Basic webserial support by @yaxu in https://github.com/tidalcycles/strudel/pull/80 +- Webaudio in REPL by @felixroos in https://github.com/tidalcycles/strudel/pull/77 +- add `striate()` by @yaxu in https://github.com/tidalcycles/strudel/pull/76 +- Tidy up a couple of old files by @mindofmatthew in https://github.com/tidalcycles/strudel/pull/84 +- Add pattern composers, implements #82 by @yaxu in https://github.com/tidalcycles/strudel/pull/83 +- Fiddles with cat/stack by @yaxu in https://github.com/tidalcycles/strudel/pull/90 +- Paper by @felixroos in https://github.com/tidalcycles/strudel/pull/98 +- Change to Affero GPL by @yaxu in https://github.com/tidalcycles/strudel/pull/101 +- Work on Codemirror 6 highlighting by @mindofmatthew in https://github.com/tidalcycles/strudel/pull/102 +- Codemirror 6 by @felixroos in https://github.com/tidalcycles/strudel/pull/97 +- Tune tests by @felixroos in https://github.com/tidalcycles/strudel/pull/104 +- /embed package: web component for repl by @felixroos in https://github.com/tidalcycles/strudel/pull/106 +- Reset, Restart and other composers by @felixroos in https://github.com/tidalcycles/strudel/pull/88 +- Embed style by @felixroos in https://github.com/tidalcycles/strudel/pull/109 +- In source doc by @yaxu in https://github.com/tidalcycles/strudel/pull/105 +- `.brak()`, `.inside()` and `.outside()` by @yaxu in https://github.com/tidalcycles/strudel/pull/112 +- loopAt by @yaxu in https://github.com/tidalcycles/strudel/pull/114 +- Osc timing improvements by @yaxu in https://github.com/tidalcycles/strudel/pull/113 + +## New Contributors + +- @bwagner made their first contribution in https://github.com/tidalcycles/strudel/pull/37 +- @mindofmatthew made their first contribution in https://github.com/tidalcycles/strudel/pull/84 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.0.2...@strudel.cycles/core@0.1.0 diff --git a/website/src/content/blog/release-0.0.3-maelstrom.mdx b/website/src/content/blog/release-0.0.3-maelstrom.mdx new file mode 100644 index 000000000..ee8d5143b --- /dev/null +++ b/website/src/content/blog/release-0.0.3-maelstrom.mdx @@ -0,0 +1,68 @@ +--- +title: 'Release Notes v0.0.3 Maelstrom' +description: '' +date: '2022-06-18' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.0.3 Maelstrom + +## What's Changed + +- Add chunk, chunkBack and iterBack by @yaxu in https://github.com/tidalcycles/strudel/pull/25 +- Update tutorial.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/37 +- Update tutorial.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/38 +- Compose by @felixroos in https://github.com/tidalcycles/strudel/pull/40 +- Fix polymeter by @yaxu in https://github.com/tidalcycles/strudel/pull/44 +- First run at squeezeBind, ref #32 by @yaxu in https://github.com/tidalcycles/strudel/pull/48 +- Implement `chop()` by @yaxu in https://github.com/tidalcycles/strudel/pull/50 +- OSC and SuperDirt support by @yaxu in https://github.com/tidalcycles/strudel/pull/27 +- More functions by @yaxu in https://github.com/tidalcycles/strudel/pull/56 +- More functions by @yaxu in https://github.com/tidalcycles/strudel/pull/61 +- Separate out strudel.mjs, make index.mjs aggregate module by @yaxu in https://github.com/tidalcycles/strudel/pull/62 +- Speech output by @felixroos in https://github.com/tidalcycles/strudel/pull/67 +- use new fixed version of osc-js package by @felixroos in https://github.com/tidalcycles/strudel/pull/68 +- First effort at rand() by @yaxu in https://github.com/tidalcycles/strudel/pull/69 +- More randomness, fix `rand`, and add `brand`, `irand` and `choose` by @yaxu in https://github.com/tidalcycles/strudel/pull/70 +- webaudio package by @felixroos in https://github.com/tidalcycles/strudel/pull/26 +- Port `perlin` noise, `rangex`, and `palindrome` by @yaxu in https://github.com/tidalcycles/strudel/pull/73 +- More random functions by @yaxu in https://github.com/tidalcycles/strudel/pull/74 +- Try to fix appLeft / appRight by @yaxu in https://github.com/tidalcycles/strudel/pull/75 +- Basic webserial support by @yaxu in https://github.com/tidalcycles/strudel/pull/80 +- Webaudio in REPL by @felixroos in https://github.com/tidalcycles/strudel/pull/77 +- add `striate()` by @yaxu in https://github.com/tidalcycles/strudel/pull/76 +- Tidy up a couple of old files by @mindofmatthew in https://github.com/tidalcycles/strudel/pull/84 +- Add pattern composers, implements #82 by @yaxu in https://github.com/tidalcycles/strudel/pull/83 +- Fiddles with cat/stack by @yaxu in https://github.com/tidalcycles/strudel/pull/90 +- Paper by @felixroos in https://github.com/tidalcycles/strudel/pull/98 +- Change to Affero GPL by @yaxu in https://github.com/tidalcycles/strudel/pull/101 +- Work on Codemirror 6 highlighting by @mindofmatthew in https://github.com/tidalcycles/strudel/pull/102 +- Codemirror 6 by @felixroos in https://github.com/tidalcycles/strudel/pull/97 +- Tune tests by @felixroos in https://github.com/tidalcycles/strudel/pull/104 +- /embed package: web component for repl by @felixroos in https://github.com/tidalcycles/strudel/pull/106 +- Reset, Restart and other composers by @felixroos in https://github.com/tidalcycles/strudel/pull/88 +- Embed style by @felixroos in https://github.com/tidalcycles/strudel/pull/109 +- In source doc by @yaxu in https://github.com/tidalcycles/strudel/pull/105 +- `.brak()`, `.inside()` and `.outside()` by @yaxu in https://github.com/tidalcycles/strudel/pull/112 +- loopAt by @yaxu in https://github.com/tidalcycles/strudel/pull/114 +- Osc timing improvements by @yaxu in https://github.com/tidalcycles/strudel/pull/113 +- react package + vite build by @felixroos in https://github.com/tidalcycles/strudel/pull/116 +- In source doc by @felixroos in https://github.com/tidalcycles/strudel/pull/117 +- fix: #108 by @felixroos in https://github.com/tidalcycles/strudel/pull/123 +- fix: #122 ctrl enter would add newline by @felixroos in https://github.com/tidalcycles/strudel/pull/124 +- Webdirt by @felixroos in https://github.com/tidalcycles/strudel/pull/121 +- Fix link to contributing to tutorial docs by @stephendwolff in https://github.com/tidalcycles/strudel/pull/129 +- Pianoroll enhancements by @felixroos in https://github.com/tidalcycles/strudel/pull/131 +- add createParam + createParams by @felixroos in https://github.com/tidalcycles/strudel/pull/110 +- remove cycle + delta from onTrigger by @felixroos in https://github.com/tidalcycles/strudel/pull/135 +- Scheduler improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/134 +- add onTrigger helper by @felixroos in https://github.com/tidalcycles/strudel/pull/136 + +## New Contributors + +- @bwagner made their first contribution in https://github.com/tidalcycles/strudel/pull/37 +- @mindofmatthew made their first contribution in https://github.com/tidalcycles/strudel/pull/84 +- @stephendwolff made their first contribution in https://github.com/tidalcycles/strudel/pull/129 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.0.2...v0.0.3 diff --git a/website/src/content/blog/release-0.0.4-gischt.mdx b/website/src/content/blog/release-0.0.4-gischt.mdx new file mode 100644 index 000000000..93db48766 --- /dev/null +++ b/website/src/content/blog/release-0.0.4-gischt.mdx @@ -0,0 +1,47 @@ +--- +title: 'Release Notes v0.0.4 Gischt' +description: '' +date: '2022-08-14' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.0.4 Gischt + +## What's Changed + +- Webaudio rewrite by @felixroos in https://github.com/tidalcycles/strudel/pull/138 +- Fix createParam() by @yaxu in https://github.com/tidalcycles/strudel/pull/140 +- Soundfont Support by @felixroos in https://github.com/tidalcycles/strudel/pull/139 +- Serial twiddles by @yaxu in https://github.com/tidalcycles/strudel/pull/141 +- Pianoroll Object Support by @felixroos in https://github.com/tidalcycles/strudel/pull/142 +- flash effect on ctrl enter by @felixroos in https://github.com/tidalcycles/strudel/pull/144 +- can now generate short link for sharing by @felixroos in https://github.com/tidalcycles/strudel/pull/146 +- Sampler optimizations and more by @felixroos in https://github.com/tidalcycles/strudel/pull/148 +- Final update to demo.pdf by @yaxu in https://github.com/tidalcycles/strudel/pull/151 +- add webdirt drum samples to prebake for general availability by @larkob in https://github.com/tidalcycles/strudel/pull/150 +- update to tutorial documentation by @larkob in https://github.com/tidalcycles/strudel/pull/162 +- add chooseInWith/chooseCycles by @yaxu in https://github.com/tidalcycles/strudel/pull/166 +- fix: jsdoc comments by @felixroos in https://github.com/tidalcycles/strudel/pull/169 +- Pianoroll fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/163 +- Talk fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/164 +- Amend shapeshifter to allow use of dynamic import by @debrisapron in https://github.com/tidalcycles/strudel/pull/171 +- add more shapeshifter flags by @felixroos in https://github.com/tidalcycles/strudel/pull/99 +- Replace react-codemirror6 with @uiw/react-codemirror by @felixroos in https://github.com/tidalcycles/strudel/pull/173 +- fix some annoying bugs by @felixroos in https://github.com/tidalcycles/strudel/pull/177 +- incorporate elements of randomness to the mini notation by @bpow in https://github.com/tidalcycles/strudel/pull/165 +- replace mocha with vitest by @felixroos in https://github.com/tidalcycles/strudel/pull/175 +- scheduler improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/181 +- Fix codemirror bug by @felixroos in https://github.com/tidalcycles/strudel/pull/186 +- wait for prebake to finish before evaluating by @felixroos in https://github.com/tidalcycles/strudel/pull/189 +- fix regression: old way of setting frequencies was broken by @felixroos in https://github.com/tidalcycles/strudel/pull/190 +- Soundfont file support by @felixroos in https://github.com/tidalcycles/strudel/pull/183 +- change "stride"/"offset" of successive degradeBy/chooseIn by @bpow in https://github.com/tidalcycles/strudel/pull/185 + +## New Contributors + +- @larkob made their first contribution in https://github.com/tidalcycles/strudel/pull/150 +- @debrisapron made their first contribution in https://github.com/tidalcycles/strudel/pull/171 +- @bpow made their first contribution in https://github.com/tidalcycles/strudel/pull/165 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.0.3...v0.0.4 diff --git a/website/src/content/blog/release-0.3.0-donauwelle.mdx b/website/src/content/blog/release-0.3.0-donauwelle.mdx new file mode 100644 index 000000000..ce086dbc7 --- /dev/null +++ b/website/src/content/blog/release-0.3.0-donauwelle.mdx @@ -0,0 +1,67 @@ +--- +title: 'Release Notes v0.3.0 Donauwelle' +description: '' +date: '2022-11-06' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.3.0 Donauwelle + +## Package Versions + +- @strudel.cycles/core@0.3.1 +- @strudel.cycles/eval@0.3.1 +- @strudel.cycles/midi@0.3.1 +- @strudel.cycles/mini@0.3.1 +- @strudel.cycles/react@0.3.1 +- @strudel.cycles/soundfonts@0.3.1 +- @strudel.cycles/tonal@0.3.1 +- @strudel.cycles/tone@0.3.1 +- @strudel.cycles/webaudio@0.3.1 +- @strudel.cycles/webdirt@0.3.1 +- @strudel.cycles/xen@0.3.1 + +## What's Changed + +- Fix numbers in sampler by @felixroos in https://github.com/tidalcycles/strudel/pull/196 +- document random functions by @felixroos in https://github.com/tidalcycles/strudel/pull/199 +- add rollup-plugin-visualizer to build by @felixroos in https://github.com/tidalcycles/strudel/pull/200 +- add vowel to .out by @felixroos in https://github.com/tidalcycles/strudel/pull/201 +- Coarse crush shape by @felixroos in https://github.com/tidalcycles/strudel/pull/205 +- Webaudio guide by @felixroos in https://github.com/tidalcycles/strudel/pull/207 +- Even more docs by @felixroos in https://github.com/tidalcycles/strudel/pull/212 +- Just another docs PR by @felixroos in https://github.com/tidalcycles/strudel/pull/215 +- sampler features + fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/217 +- samples now have envelopes by @felixroos in https://github.com/tidalcycles/strudel/pull/218 +- encapsulate webaudio output by @felixroos in https://github.com/tidalcycles/strudel/pull/219 +- Fix squeeze join by @yaxu in https://github.com/tidalcycles/strudel/pull/220 +- Feedback Delay by @felixroos in https://github.com/tidalcycles/strudel/pull/213 +- support negative speeds by @felixroos in https://github.com/tidalcycles/strudel/pull/222 +- focus tweak for squeezeJoin - another go at fixing #216 by @yaxu in https://github.com/tidalcycles/strudel/pull/221 +- Reverb by @felixroos in https://github.com/tidalcycles/strudel/pull/224 +- fix fastgap for events that go across cycle boundaries by @yaxu in https://github.com/tidalcycles/strudel/pull/225 +- Core util tests by @mystery-house in https://github.com/tidalcycles/strudel/pull/226 +- Refactor tunes away from tone by @felixroos in https://github.com/tidalcycles/strudel/pull/230 +- Just another docs branch by @felixroos in https://github.com/tidalcycles/strudel/pull/228 +- Patternify range by @yaxu in https://github.com/tidalcycles/strudel/pull/231 +- Out by default by @felixroos in https://github.com/tidalcycles/strudel/pull/232 +- Fix zero length queries WIP by @yaxu in https://github.com/tidalcycles/strudel/pull/234 +- add vcsl sample library by @felixroos in https://github.com/tidalcycles/strudel/pull/235 +- fx on stereo speakers by @felixroos in https://github.com/tidalcycles/strudel/pull/236 +- Tidal drum machines by @felixroos in https://github.com/tidalcycles/strudel/pull/237 +- Object arithmetic by @felixroos in https://github.com/tidalcycles/strudel/pull/238 +- Load samples from url by @felixroos in https://github.com/tidalcycles/strudel/pull/239 +- feat: support github: links by @felixroos in https://github.com/tidalcycles/strudel/pull/240 +- in source example tests by @felixroos in https://github.com/tidalcycles/strudel/pull/242 +- Readme + TLC by @felixroos in https://github.com/tidalcycles/strudel/pull/244 +- patchday by @felixroos in https://github.com/tidalcycles/strudel/pull/246 +- Some tunes by @felixroos in https://github.com/tidalcycles/strudel/pull/247 +- snapshot tests on shared snippets by @felixroos in https://github.com/tidalcycles/strudel/pull/243 +- General purpose scheduler by @felixroos in https://github.com/tidalcycles/strudel/pull/248 + +## New Contributors + +- @mystery-house made their first contribution in https://github.com/tidalcycles/strudel/pull/226 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.0.4...v0.3.0 diff --git a/website/src/content/blog/release-0.4.0-brandung.mdx b/website/src/content/blog/release-0.4.0-brandung.mdx new file mode 100644 index 000000000..67e61ece2 --- /dev/null +++ b/website/src/content/blog/release-0.4.0-brandung.mdx @@ -0,0 +1,17 @@ +--- +title: 'Release Notes v0.4.0 Brandung' +description: '' +date: '2022-11-13' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.4.0 Brandung + +## What's Changed + +- new transpiler based on acorn by @felixroos in https://github.com/tidalcycles/strudel/pull/249 +- Webaudio build by @felixroos in https://github.com/tidalcycles/strudel/pull/250 +- Repl refactoring by @felixroos in https://github.com/tidalcycles/strudel/pull/255 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.3.0...v0.4.0 diff --git a/website/src/content/blog/release-0.5.0-wirbel.mdx b/website/src/content/blog/release-0.5.0-wirbel.mdx new file mode 100644 index 000000000..8912627c4 --- /dev/null +++ b/website/src/content/blog/release-0.5.0-wirbel.mdx @@ -0,0 +1,61 @@ +--- +title: 'Release Notes v0.5.0 Wirbel' +description: '' +date: '2022-12-13' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.5.0 Wirbel + +## Package Versions + +- @strudel.cycles/core@0.5.0 +- @strudel.cycles/osc@0.4.0 +- @strudel.cycles/serial@0.3.0 +- @strudel.cycles/csound@0.5.1 +- @strudel.cycles/eval@0.5.0 +- @strudel.cycles/midi@0.5.0 +- @strudel.cycles/mini@0.5.0 +- @strudel.cycles/react@0.5.0 +- @strudel.cycles/soundfonts@0.5.0 +- @strudel.cycles/tonal@0.5.0 +- @strudel.cycles/tone@0.5.0 +- @strudel.cycles/transpiler@0.5.0 +- @strudel.cycles/webaudio@0.5.0 +- @strudel.cycles/webdirt@0.5.0 +- @strudel.cycles/xen@0.5.0 + +## What's Changed + +- Binaries by @felixroos in https://github.com/tidalcycles/strudel/pull/254 +- fix tutorial bugs by @felixroos in https://github.com/tidalcycles/strudel/pull/263 +- fix performance bottleneck by @felixroos in https://github.com/tidalcycles/strudel/pull/266 +- Tidying up core by @yaxu in https://github.com/tidalcycles/strudel/pull/256 +- tonal update with fixed memory leak by @felixroos in https://github.com/tidalcycles/strudel/pull/272 +- add eslint by @felixroos in https://github.com/tidalcycles/strudel/pull/271 +- release version bumps by @felixroos in https://github.com/tidalcycles/strudel/pull/273 +- Support sending CRC16 bytes with serial messages by @yaxu in https://github.com/tidalcycles/strudel/pull/276 +- add licenses / credits to all tunes + remove some by @felixroos in https://github.com/tidalcycles/strudel/pull/277 +- add basic csound output by @felixroos in https://github.com/tidalcycles/strudel/pull/275 +- do not recompile orc by @felixroos in https://github.com/tidalcycles/strudel/pull/278 +- implement collect + arp function by @felixroos in https://github.com/tidalcycles/strudel/pull/281 +- Switch 'operators' from .whatHow to .what.how by @yaxu in https://github.com/tidalcycles/strudel/pull/285 +- Fancy hap show, include part in snapshots by @yaxu in https://github.com/tidalcycles/strudel/pull/291 +- Reorganise pattern.mjs with a 'toplevel first' regime by @yaxu in https://github.com/tidalcycles/strudel/pull/286 +- add prettier task by @felixroos in https://github.com/tidalcycles/strudel/pull/296 +- Move stuff to new register function by @felixroos in https://github.com/tidalcycles/strudel/pull/295 +- can now add bare numbers to numeral object props by @felixroos in https://github.com/tidalcycles/strudel/pull/287 +- update vitest by @felixroos in https://github.com/tidalcycles/strudel/pull/297 +- remove whitespace from highlighted region by @felixroos in https://github.com/tidalcycles/strudel/pull/298 +- .defragmentHaps() for merging touching haps that share a whole and value by @yaxu in https://github.com/tidalcycles/strudel/pull/299 +- fix whitespace trimming by @felixroos in https://github.com/tidalcycles/strudel/pull/300 +- add freq support to sampler by @felixroos in https://github.com/tidalcycles/strudel/pull/301 +- add lint + prettier check before test by @felixroos in https://github.com/tidalcycles/strudel/pull/305 +- Updated csoundm to use the register facility . by @gogins in https://github.com/tidalcycles/strudel/pull/303 + +## New Contributors + +- @gogins made their first contribution in https://github.com/tidalcycles/strudel/pull/303 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.4.0...v0.5.0 diff --git a/website/src/content/blog/release-0.6.0-zimtschnecke.mdx b/website/src/content/blog/release-0.6.0-zimtschnecke.mdx new file mode 100644 index 000000000..9e5f2f356 --- /dev/null +++ b/website/src/content/blog/release-0.6.0-zimtschnecke.mdx @@ -0,0 +1,86 @@ +--- +title: 'Release Notes v0.6.0 Zimtschnecke' +description: '' +date: '2023-02-01' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.6.0 Zimtschnecke + +## Package Versions + +- @strudel.cycles/core@0.6.8 +- @strudel.cycles/eval@0.6.2 +- @strudel.cycles/transpiler@0.6.0 +- @strudel.cycles/mini@0.6.0 +- @strudel.cycles/tonal@0.6.0 +- @strudel.cycles/tone@0.6.0 +- @strudel.cycles/xen@0.6.0 +- @strudel.cycles/webaudio@0.6.1 +- @strudel.cycles/react@0.6.0 +- @strudel.cycles/osc@0.6.0 +- @strudel.cycles/midi@0.6.0 +- @strudel.cycles/webdirt@0.6.0 +- @strudel.cycles/serial@0.6.0 +- @strudel.cycles/soundfonts@0.6.0 +- @strudel.cycles/csound@0.6.0 + +## What's Changed + +- support freq in pianoroll by @felixroos in https://github.com/tidalcycles/strudel/pull/308 +- ICLC2023 paper WIP by @yaxu in https://github.com/tidalcycles/strudel/pull/306 +- fix: copy share link to clipboard was broken for some browers by @felixroos in https://github.com/tidalcycles/strudel/pull/311 +- Jsdoc component by @felixroos in https://github.com/tidalcycles/strudel/pull/312 +- object support for .scale by @felixroos in https://github.com/tidalcycles/strudel/pull/307 +- Astro build by @felixroos in https://github.com/tidalcycles/strudel/pull/315 +- Reference tab sort by @felixroos in https://github.com/tidalcycles/strudel/pull/318 +- tutorial updates by @jarmitage in https://github.com/tidalcycles/strudel/pull/320 +- support notes without octave by @felixroos in https://github.com/tidalcycles/strudel/pull/323 +- mini repl improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/324 +- fix: workaround Object.assign globalThis by @felixroos in https://github.com/tidalcycles/strudel/pull/326 +- add examples route by @felixroos in https://github.com/tidalcycles/strudel/pull/327 +- add my-patterns by @felixroos in https://github.com/tidalcycles/strudel/pull/328 +- my-patterns build + deploy by @felixroos in https://github.com/tidalcycles/strudel/pull/329 +- my-patterns: fix paths + update readme by @felixroos in https://github.com/tidalcycles/strudel/pull/330 +- improve displaying 's' in pianoroll by @felixroos in https://github.com/tidalcycles/strudel/pull/331 +- fix: can now multiply floats in mini notation by @felixroos in https://github.com/tidalcycles/strudel/pull/332 +- Embed mode improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/333 +- testing + docs docs by @felixroos in https://github.com/tidalcycles/strudel/pull/334 +- animate mvp by @felixroos in https://github.com/tidalcycles/strudel/pull/335 +- Tidy parser, implement polymeters by @yaxu in https://github.com/tidalcycles/strudel/pull/336 +- animation options by @felixroos in https://github.com/tidalcycles/strudel/pull/337 +- move /my-patterns to /swatch by @yaxu in https://github.com/tidalcycles/strudel/pull/338 +- more animate functions + mini repl fix by @felixroos in https://github.com/tidalcycles/strudel/pull/340 +- Patternify euclid, fast, slow and polymeter step parameters in mininotation by @yaxu in https://github.com/tidalcycles/strudel/pull/341 +- fixes #346 by @felixroos in https://github.com/tidalcycles/strudel/pull/347 +- Fix prebake base path by @felixroos in https://github.com/tidalcycles/strudel/pull/345 +- Fix Bjorklund by @yaxu in https://github.com/tidalcycles/strudel/pull/343 +- docs: tidal comparison + add global fx + add missing sampler fx by @felixroos in https://github.com/tidalcycles/strudel/pull/356 +- Fix .out(), renaming webaudio's out() to webaudio() by @yaxu in https://github.com/tidalcycles/strudel/pull/361 +- Support for multiple mininotation operators by @yaxu in https://github.com/tidalcycles/strudel/pull/350 +- doc structuring by @felixroos in https://github.com/tidalcycles/strudel/pull/360 +- add https to url by @urswilke in https://github.com/tidalcycles/strudel/pull/364 +- document more functions + change arp join by @felixroos in https://github.com/tidalcycles/strudel/pull/369 +- improve new draw logic by @felixroos in https://github.com/tidalcycles/strudel/pull/372 +- Draw fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/377 +- update my-patterns instructions by @felixroos in https://github.com/tidalcycles/strudel/pull/384 +- docs: use note instead of n to mitigate confusion by @felixroos in https://github.com/tidalcycles/strudel/pull/385 +- add run + test + docs by @felixroos in https://github.com/tidalcycles/strudel/pull/386 +- Rename a to angle by @felixroos in https://github.com/tidalcycles/strudel/pull/387 +- document csound by @felixroos in https://github.com/tidalcycles/strudel/pull/391 +- Notes are not essential :) by @yaxu in https://github.com/tidalcycles/strudel/pull/393 +- add ribbon + test + docs by @felixroos in https://github.com/tidalcycles/strudel/pull/388 +- Add tidal-drum-patterns to examples by @urswilke in https://github.com/tidalcycles/strudel/pull/379 +- add pattern methods hurry, press and pressBy by @yaxu in https://github.com/tidalcycles/strudel/pull/397 +- proper builds + use pnpm workspaces by @felixroos in https://github.com/tidalcycles/strudel/pull/396 +- fix: minirepl styles by @felixroos in https://github.com/tidalcycles/strudel/pull/398 +- can now await initAudio + initAudioOnFirstClick by @felixroos in https://github.com/tidalcycles/strudel/pull/399 +- release webaudio by @felixroos in https://github.com/tidalcycles/strudel/pull/400 + +## New Contributors + +- @jarmitage made their first contribution in https://github.com/tidalcycles/strudel/pull/320 +- @urswilke made their first contribution in https://github.com/tidalcycles/strudel/pull/364 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.5.0...v0.6.0 diff --git a/website/src/content/blog/release-0.7.0-zuckerguss.mdx b/website/src/content/blog/release-0.7.0-zuckerguss.mdx new file mode 100644 index 000000000..55315a9cd --- /dev/null +++ b/website/src/content/blog/release-0.7.0-zuckerguss.mdx @@ -0,0 +1,90 @@ +--- +title: 'Release Notes v0.7.0 Zimtschnecke' +description: '' +date: '2023-03-23' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.7.0 Zimtschnecke + +## Package Versions + +- @strudel.cycles/core@0.7.2 +- @strudel.cycles/transpiler@0.7.1 +- @strudel.cycles/mini@0.7.2 +- @strudel.cycles/tonal@0.7.1 +- @strudel.cycles/xen@0.7.1 +- @strudel.cycles/tone@0.7.1 +- @strudel.cycles/webaudio@0.7.1 +- @strudel.cycles/react@0.7.1 +- @strudel.cycles/osc@0.7.1 +- @strudel.cycles/serial@0.7.1 +- @strudel.cycles/midi@0.7.1 +- @strudel.cycles/csound@0.7.1 + +## What's Changed + +- pin @csound/browser to 6.18.3 + bump by @felixroos in https://github.com/tidalcycles/strudel/pull/403 +- update csound + fix sound output by @felixroos in https://github.com/tidalcycles/strudel/pull/404 +- fix: share url on subpath by @felixroos in https://github.com/tidalcycles/strudel/pull/405 +- add shabda doc by @felixroos in https://github.com/tidalcycles/strudel/pull/407 +- Update effects.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/410 +- improve effects doc by @felixroos in https://github.com/tidalcycles/strudel/pull/409 +- google gtfo by @felixroos in https://github.com/tidalcycles/strudel/pull/413 +- improve samples doc by @felixroos in https://github.com/tidalcycles/strudel/pull/411 +- PWA with offline support by @felixroos in https://github.com/tidalcycles/strudel/pull/417 +- add caching strategy for missing file types + cache all samples loaded from github by @felixroos in https://github.com/tidalcycles/strudel/pull/419 +- add more offline caching by @felixroos in https://github.com/tidalcycles/strudel/pull/421 +- add cdn.freesound to cache list by @felixroos in https://github.com/tidalcycles/strudel/pull/425 +- minirepl: add keyboard shortcuts by @felixroos in https://github.com/tidalcycles/strudel/pull/429 +- Themes by @felixroos in https://github.com/tidalcycles/strudel/pull/431 +- autocomplete preparations by @felixroos in https://github.com/tidalcycles/strudel/pull/427 +- Fix anchors by @felixroos in https://github.com/tidalcycles/strudel/pull/433 +- Update code.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/436 +- Update mini-notation.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/437 +- Update synths.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/438 +- FIXES: Warning about jsxBracketSameLine deprecation by @bwagner in https://github.com/tidalcycles/strudel/pull/461 +- Composable functions by @yaxu in https://github.com/tidalcycles/strudel/pull/390 +- weave and weaveWith by @yaxu in https://github.com/tidalcycles/strudel/pull/465 +- slice and splice by @yaxu in https://github.com/tidalcycles/strudel/pull/466 +- fix: osc should not return a promise by @felixroos in https://github.com/tidalcycles/strudel/pull/472 +- FIXES: freqs instead of pitches by @bwagner in https://github.com/tidalcycles/strudel/pull/464 +- Update input-output.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/471 +- settings tab with vim / emacs modes + additional themes and fonts by @felixroos in https://github.com/tidalcycles/strudel/pull/467 +- fix: hash links by @felixroos in https://github.com/tidalcycles/strudel/pull/473 +- midi cc support by @felixroos in https://github.com/tidalcycles/strudel/pull/478 +- Fix array args by @felixroos in https://github.com/tidalcycles/strudel/pull/480 +- docs: packages + offline by @felixroos in https://github.com/tidalcycles/strudel/pull/482 +- Update mini-notation.mdx by @yaxu in https://github.com/tidalcycles/strudel/pull/365 +- Revert "Another attempt at composable functions - WIP (#390)" by @felixroos in https://github.com/tidalcycles/strudel/pull/484 +- fix app height by @felixroos in https://github.com/tidalcycles/strudel/pull/485 +- add algolia creds + optimize sidebar for crawling by @felixroos in https://github.com/tidalcycles/strudel/pull/488 +- refactor react package by @felixroos in https://github.com/tidalcycles/strudel/pull/490 +- react style fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/491 +- implement cps in scheduler by @felixroos in https://github.com/tidalcycles/strudel/pull/493 +- Add control aliases by @yaxu in https://github.com/tidalcycles/strudel/pull/497 +- fix: nano-repl highlighting by @felixroos in https://github.com/tidalcycles/strudel/pull/501 +- Reinstate slice and splice by @yaxu in https://github.com/tidalcycles/strudel/pull/500 +- can now use : as a replacement for space in scales by @felixroos in https://github.com/tidalcycles/strudel/pull/502 +- Support list syntax in mininotation by @yaxu in https://github.com/tidalcycles/strudel/pull/512 +- update react to 18 by @felixroos in https://github.com/tidalcycles/strudel/pull/514 +- add arrange function by @felixroos in https://github.com/tidalcycles/strudel/pull/508 +- Update README.md by @bwagner in https://github.com/tidalcycles/strudel/pull/474 +- add 2 illegible fonts by @felixroos in https://github.com/tidalcycles/strudel/pull/518 +- registerSound API + improved sounds tab + regroup soundfonts by @felixroos in https://github.com/tidalcycles/strudel/pull/516 +- fix: envelopes in chrome by @felixroos in https://github.com/tidalcycles/strudel/pull/521 +- Update samples.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/524 +- Update intro.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/525 +- fix(footer): fix link to tidalcycles by @revolunet in https://github.com/tidalcycles/strudel/pull/529 +- FIXES: alias pm for polymeter by @bwagner in https://github.com/tidalcycles/strudel/pull/527 +- Maintain random seed state in parser, not globally by @ijc8 in https://github.com/tidalcycles/strudel/pull/531 +- feat: add freq support to gm soundfonts by @felixroos in https://github.com/tidalcycles/strudel/pull/534 +- Update lerna by @felixroos in https://github.com/tidalcycles/strudel/pull/535 + +## New Contributors + +- @revolunet made their first contribution in https://github.com/tidalcycles/strudel/pull/529 +- @ijc8 made their first contribution in https://github.com/tidalcycles/strudel/pull/531 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.6.0...v0.7.0 diff --git a/website/src/content/blog/release-0.8.0-himbeermuffin.mdx b/website/src/content/blog/release-0.8.0-himbeermuffin.mdx new file mode 100644 index 000000000..d2ae211ae --- /dev/null +++ b/website/src/content/blog/release-0.8.0-himbeermuffin.mdx @@ -0,0 +1,130 @@ +--- +title: 'Release Notes v0.8.0 Himbeermuffin' +description: '' +date: '2023-06-30' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.8.0 Himbeermuffin + +These are the release notes for Strudel 0.8.0 aka "Himbeermuffin"! + +[Go to Tidal Club Forum for this Release](https://club.tidalcycles.org/t/strudel-0-8-0-released/4769) + +Let me write up some of the highlights: + +## Desktop App + +Besides the REPL (https://strudel.tidalcycles.org/), Strudel is now also distributed as a Desktop App via https://tauri.app/! Thanks to [vasilymilovidov](https://github.com/vasilymilovidov)! + +- [Linux: Debian based](https://github.com/tidalcycles/strudel/releases/download/v0.8.0/strudel_0.1.0_amd64.deb) +- [Linux: AppImage](https://github.com/tidalcycles/strudel/releases/download/v0.8.0/strudel_0.1.0_amd64.AppImage) +- [MacOS](https://github.com/tidalcycles/strudel/releases/download/v0.8.0/Strudel_0.1.0_x64.dmg) +- [Windows .exe](https://github.com/tidalcycles/strudel/releases/download/v0.8.0/Strudel_0.1.0_x64-setup.exe) +- [Windows .msi](https://github.com/tidalcycles/strudel/releases/download/v0.8.0/Strudel_0.1.0_x64_en-US.msi) + +edit: the desktop app performance on linux is currently not that great.. the web REPL runs much smoother (using firefox or chromium) + +The desktop App has the same features as the webapp, with the additional ability to load samples from disk. It is currently not documented yet, but you can do something like + +```js +await samples('~/music/xxx'); + +s('my_sound'); +``` + +You have to start with `~/music/`, followed by an arbitrary folder path that is expected to be present in the systems [audio directory](https://tauri.app/v1/api/js/path/#audiodir). +When you first run it, the app will create a strudel.json file in that directory to map out the available samples. + +I would be very happy to collect some feedback on how it works across different platforms & systems! + +## Spiral Visualization + +Also still undocumented, but you can now visualize patterns as a spiral via `.spiral()`: + +https://github.com/tidalcycles/strudel/assets/12023032/05bc2dba-b304-4298-9465-a1a6fafe5ded + +This is especially nice because strudel is not only the name of a dessert but also the german word for vortex! The spiral is very fitting to visualize cycles because you can align cycles vertically, while surfing along an infinite twisted timeline. + +## More settings + +In the settings tab, you can now toggle: + +- line numbers +- auto-complete +- line wrapping + +Thanks to [roipoussiere](https://github.com/roipoussiere)! + +## More + +Scroll down to see the full list of Changes! + +A big thanks to all the contributors! + +## Package Versions + +- @strudel.cycles/core: 0.8.2 +- @strudel.cycles/mini: 0.8.2 +- @strudel.cycles/transpiler: 0.8.2 +- @strudel.cycles/webaudio: 0.8.2 +- @strudel.cycles/soundfonts: 0.8.2 +- @strudel.cycles/react: 0.8.0 +- @strudel.cycles/midi: 0.8.0 +- @strudel.cycles/osc: 0.8.0 +- @strudel.cycles/csound: 0.8.0 +- @strudel.cycles/serial: 0.8.0 +- @strudel.cycles/tonal: 0.8.2 +- @strudel.cycles/xen: 0.8.0 +- @strudel/codemirror: 0.8.4 +- @strudel/web: 0.8.3 + +## What's Changed + +- fix period key for dvorak + remove duplicated code by @felixroos in https://github.com/tidalcycles/strudel/pull/537 +- improve initial loading + wait before eval by @felixroos in https://github.com/tidalcycles/strudel/pull/538 +- do not reset cps before eval #517 by @felixroos in https://github.com/tidalcycles/strudel/pull/539 +- feat: add loader bar to animate loading state by @felixroos in https://github.com/tidalcycles/strudel/pull/542 +- add firacode font by @felixroos in https://github.com/tidalcycles/strudel/pull/544 +- fix: allow whitespace at the end of a mini pattern by @felixroos in https://github.com/tidalcycles/strudel/pull/547 +- fix: reset time on stop by @felixroos in https://github.com/tidalcycles/strudel/pull/548 +- fix: load soundfonts in prebake by @felixroos in https://github.com/tidalcycles/strudel/pull/550 +- fix: colorable highlighting by @felixroos in https://github.com/tidalcycles/strudel/pull/553 +- fix: make soundfonts import dynamic by @felixroos in https://github.com/tidalcycles/strudel/pull/556 +- add basic triads and guidetone voicings by @felixroos in https://github.com/tidalcycles/strudel/pull/557 +- Patchday by @felixroos in https://github.com/tidalcycles/strudel/pull/559 +- Vanilla JS Refactoring by @felixroos in https://github.com/tidalcycles/strudel/pull/563 +- repl: add option to display line numbers by @roipoussiere in https://github.com/tidalcycles/strudel/pull/582 +- learn/tonal: fix typo in "scaleTran[s]pose" by @srenatus in https://github.com/tidalcycles/strudel/pull/585 +- Music metadata by @roipoussiere in https://github.com/tidalcycles/strudel/pull/580 +- New Workshop by @felixroos in https://github.com/tidalcycles/strudel/pull/587 +- Fix option dot by @felixroos in https://github.com/tidalcycles/strudel/pull/596 +- fix: allow f for flat notes like tidal by @felixroos in https://github.com/tidalcycles/strudel/pull/593 +- fix: division by zero by @felixroos in https://github.com/tidalcycles/strudel/pull/591 +- Solmization added by @dariacotocu in https://github.com/tidalcycles/strudel/pull/570 +- improve cursor by @felixroos in https://github.com/tidalcycles/strudel/pull/597 +- enable auto-completion by @roipoussiere in https://github.com/tidalcycles/strudel/pull/588 +- add ratio function by @felixroos in https://github.com/tidalcycles/strudel/pull/602 +- editor: enable line wrapping by @roipoussiere in https://github.com/tidalcycles/strudel/pull/581 +- tonal fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/607 +- fix: flatten scale lists by @felixroos in https://github.com/tidalcycles/strudel/pull/605 +- clip now works like legato in tidal by @felixroos in https://github.com/tidalcycles/strudel/pull/598 +- fix: doc links by @felixroos in https://github.com/tidalcycles/strudel/pull/612 +- tauri desktop app by @vasilymilovidov in https://github.com/tidalcycles/strudel/pull/613 +- add spiral viz by @felixroos in https://github.com/tidalcycles/strudel/pull/614 +- patterning ui settings by @felixroos in https://github.com/tidalcycles/strudel/pull/606 +- Fix typo on packages.mdx by @paikwiki in https://github.com/tidalcycles/strudel/pull/520 +- cps dependent functions by @felixroos in https://github.com/tidalcycles/strudel/pull/620 +- desktop: play samples from disk by @felixroos in https://github.com/tidalcycles/strudel/pull/621 +- fix: midi clock drift by @felixroos in https://github.com/tidalcycles/strudel/pull/627 + +## New Contributors + +- @roipoussiere made their first contribution in https://github.com/tidalcycles/strudel/pull/582 +- @srenatus made their first contribution in https://github.com/tidalcycles/strudel/pull/585 +- @dariacotocu made their first contribution in https://github.com/tidalcycles/strudel/pull/570 +- @vasilymilovidov made their first contribution in https://github.com/tidalcycles/strudel/pull/613 +- @paikwiki made their first contribution in https://github.com/tidalcycles/strudel/pull/520 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.7.0...v0.8.0 diff --git a/website/src/content/blog/release-0.9.0-bananenbrot.mdx b/website/src/content/blog/release-0.9.0-bananenbrot.mdx new file mode 100644 index 000000000..1322362eb --- /dev/null +++ b/website/src/content/blog/release-0.9.0-bananenbrot.mdx @@ -0,0 +1,114 @@ +--- +title: 'Release Notes v0.9.0 Bananenbrot' +description: '' +date: '2023-09-17' +tags: ['meta'] +author: froos +--- + +# Release Notes v0.9.0 Bananenbrot + +These are the release notes for Strudel 0.9.0 aka "Bananenbrot"! + +The last release was over 11 weeks ago, so a lot of things have happened! + +Let me write up some of the highlights: + +## Improved Synth Engine + +The synth engine has gotten a lot of love + a name: [superdough](https://www.npmjs.com/package/superdough) encapsulates the web audio based synth / sampler / fx engine into a reusable package, which is already used by [Topos](https://topos.raphaelforment.fr/). +Main new features include: + +- [filter envelopes](https://strudel.tidalcycles.org/learn/effects#filter-envelope) +- [FM Synthesis](https://strudel.tidalcycles.org/learn/synths#fm-synthesis) +- [looping samples](https://strudel.tidalcycles.org/learn/samples#loop), allowing [wavetable synthesis](https://strudel.tidalcycles.org/?I9myTNQoKKaP) +- [vibrato](https://strudel.tidalcycles.org/learn/synths#vibrato) +- an integration of [ZZFX](https://strudel.tidalcycles.org/learn/synths#zzfx) + +https://github.com/tidalcycles/strudel/assets/12023032/652e7042-f296-496b-95cd-b2a4987fe238 + +Related PRs: + +- superdough: encapsulates web audio output by @felixroos in https://github.com/tidalcycles/strudel/pull/664 +- basic fm by @felixroos in https://github.com/tidalcycles/strudel/pull/669 +- Wave Selection and Global Envelope on the FM Synth Modulator by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/683 +- control osc partial count with n by @felixroos in https://github.com/tidalcycles/strudel/pull/674 +- ZZFX Synth support by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/684 +- Adding filter envelopes and filter order selection by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/692 +- Adding loop points and thus wavetable synthesis by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/698 +- Adding vibrato to base oscillators by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/693 + +## Desktop App Improvements + +Thanks to @daslyfe and @vasilymilovidov , the desktop app now has its own rust based MIDI and OSC integrations, +which do not depend on browser APIs! + +You can see superdough, superdirt via OSC + hardware synths via MIDI all together playing in harmony in this [awesome video](https://www.youtube.com/watch?v=lxQgBeLQBgk). These are the related PRs: + +- Create Midi Integration for Tauri Desktop app by @daslyfe in https://github.com/tidalcycles/strudel/pull/685 +- add sleep timer + improve message iterating by @daslyfe in https://github.com/tidalcycles/strudel/pull/688 +- fix MIDI CC messages by @vasilymilovidov in https://github.com/tidalcycles/strudel/pull/690 +- Direct OSC Support in Tauri by @daslyfe in https://github.com/tidalcycles/strudel/pull/694 +- Add logging from tauri by @daslyfe in https://github.com/tidalcycles/strudel/pull/697 +- fix osc bundle timestamp glitches caused by drifting clock by @daslyfe in https://github.com/tidalcycles/strudel/pull/666 +- Midi time fixes by @daslyfe in https://github.com/tidalcycles/strudel/pull/668 +- [Bug Fix] Account for numeral notation when converting to midi by @daslyfe in https://github.com/tidalcycles/strudel/pull/656 +- [Bug Fix] Midi: Don't treat note 0 as false by @daslyfe in https://github.com/tidalcycles/strudel/pull/657 + +## Visuals + +- 2 new FFT based vizualisations have now landed: [scope and fscope](https://github.com/tidalcycles/strudel/pull/677) (featured in the video at the top). +- pianoroll has new options, see [PR](https://github.com/tidalcycles/strudel/pull/679) + +Related PRs: + +- Scope by @felixroos in https://github.com/tidalcycles/strudel/pull/677 ([demo](https://strudel.tidalcycles.org/?hXVQF-KxMI8p)) +- Pianoroll improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/679 ([demo](https://strudel.tidalcycles.org/?aPMKqXGVMgSM)) + +## Voicings + +There is now a new way to play chord voicings + a huge selection of chord voicings available. Find out more in these PRs: + +- stateless voicings + tonleiter lib by @felixroos in https://github.com/tidalcycles/strudel/pull/647 ([demo](https://strudel.tidalcycles.org/?FoILM0Hs9y9f)) +- ireal voicings by @felixroos in https://github.com/tidalcycles/strudel/pull/653 ([demo](https://strudel.tidalcycles.org/?bv_TjY9hOC28)) + +## Adaptive Highlighting + +Thanks to @mindofmatthew , the highlighting will adapt to edits instantly! Related PRs: + +- More work on highlight IDs by @mindofmatthew in https://github.com/tidalcycles/strudel/pull/636 +- Adaptive Highlighting by @felixroos in https://github.com/tidalcycles/strudel/pull/634 + +## UI Changes + +- teletext theme + fonts by @felixroos in https://github.com/tidalcycles/strudel/pull/681 (featured in video at the top) +- togglable panel position by @felixroos in https://github.com/tidalcycles/strudel/pull/667 + +## Other New Features + +- slice: list mode by @felixroos in https://github.com/tidalcycles/strudel/pull/645 ([demo](https://strudel.tidalcycles.org/?bAYIqz5NLjRr)) +- add emoji support by @felixroos in https://github.com/tidalcycles/strudel/pull/680 ([demo](https://strudel.tidalcycles.org/?a6FgLz475gN9)) + +## Articles + +- Understand pitch by @felixroos in https://github.com/tidalcycles/strudel/pull/652 + +## Other Fixes & Enhancements + +- fix: out of range error by @felixroos in https://github.com/tidalcycles/strudel/pull/630 +- fix: update canvas size on window resize by @felixroos in https://github.com/tidalcycles/strudel/pull/631 +- FIXES: TODO in rotateChroma by @bwagner in https://github.com/tidalcycles/strudel/pull/650 +- snapshot tests: sort haps by part by @felixroos in https://github.com/tidalcycles/strudel/pull/637 +- Delete old packages by @felixroos in https://github.com/tidalcycles/strudel/pull/639 +- update vitest by @felixroos in https://github.com/tidalcycles/strudel/pull/651 +- fix: welcome message for latestCode by @felixroos in https://github.com/tidalcycles/strudel/pull/659 +- fix: always run previous trigger by @felixroos in https://github.com/tidalcycles/strudel/pull/660 + +## New Contributors + +- @daslyfe made their first contribution in https://github.com/tidalcycles/strudel/pull/656 +- @Bubobubobubobubo made their first contribution in https://github.com/tidalcycles/strudel/pull/683 + +**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.8.0...v0.9.0 + +A big thanks to all the contributors! diff --git a/website/src/content/config.ts b/website/src/content/config.ts new file mode 100644 index 000000000..bc5d1dd37 --- /dev/null +++ b/website/src/content/config.ts @@ -0,0 +1,24 @@ +import { defineCollection, z } from 'astro:content'; + +const blog = defineCollection({ + // Type-check frontmatter using a schema + schema: z.object({ + title: z.string(), + author: z.string(), + description: z.string().optional(), + // Transform string to Date object + date: z + .string() + .or(z.date()) + .transform((val) => new Date(val)), + updatedDate: z + .string() + .optional() + .transform((str) => (str ? new Date(str) : undefined)), + image: z.string().optional(), + tags: z.array(z.string()).optional(), + draft: z.boolean().optional(), + }), +}); + +export const collections = { blog }; diff --git a/website/src/env.d.ts b/website/src/env.d.ts index 5263bd6a3..bd7aa94b7 100644 --- a/website/src/env.d.ts +++ b/website/src/env.d.ts @@ -2,3 +2,5 @@ /// /// /// + +declare module 'date-fns'; diff --git a/website/src/pages/blog.astro b/website/src/pages/blog.astro new file mode 100644 index 000000000..431244c64 --- /dev/null +++ b/website/src/pages/blog.astro @@ -0,0 +1,45 @@ +--- +import BlogPost from '../components/BlogPost.astro'; +import HeadCommon from '../components/HeadCommon.astro'; +import HeadSEO from '../components/HeadSEO.astro'; +import Header from '../components/Header/Header.astro'; +import LeftSidebar from '../components/LeftSidebar/LeftSidebar.astro'; +import PageContent from '../components/PageContent/PageContent.astro'; +import RightSidebar from '../components/RightSidebar/RightSidebar.astro'; +import { getCollection } from 'astro:content'; +import { compareDesc } from 'date-fns'; + +const currentPage = Astro.url.pathname; + +const posts = (await getCollection('blog')).sort((a, b) => compareDesc(a.data.date, b.data.date)); +--- + + + + + + 🌀 Strudel Blog + + + +
+
+
+
+
+
+ + +

Strudel Blog

+ {posts.map((post) => )} +
+ +
+
+
+ + From ceb4376eb8336eda96ba24ac14306906f6122299 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 23:16:44 +0100 Subject: [PATCH 62/93] format autogenerated types --- website/.astro/types.d.ts | 362 +++++++++++++++++--------------------- 1 file changed, 164 insertions(+), 198 deletions(-) diff --git a/website/.astro/types.d.ts b/website/.astro/types.d.ts index ea8fd38be..64bd0ddf1 100644 --- a/website/.astro/types.d.ts +++ b/website/.astro/types.d.ts @@ -1,206 +1,172 @@ declare module 'astro:content' { - interface Render { - '.mdx': Promise<{ - Content: import('astro').MarkdownInstance<{}>['Content']; - headings: import('astro').MarkdownHeading[]; - remarkPluginFrontmatter: Record; - }>; - } + interface Render { + '.mdx': Promise<{ + Content: import('astro').MarkdownInstance<{}>['Content']; + headings: import('astro').MarkdownHeading[]; + remarkPluginFrontmatter: Record; + }>; + } } declare module 'astro:content' { - interface Render { - '.md': Promise<{ - Content: import('astro').MarkdownInstance<{}>['Content']; - headings: import('astro').MarkdownHeading[]; - remarkPluginFrontmatter: Record; - }>; - } + interface Render { + '.md': Promise<{ + Content: import('astro').MarkdownInstance<{}>['Content']; + headings: import('astro').MarkdownHeading[]; + remarkPluginFrontmatter: Record; + }>; + } } declare module 'astro:content' { - export { z } from 'astro/zod'; - - type Flatten = T extends { [K: string]: infer U } ? U : never; - - export type CollectionKey = keyof AnyEntryMap; - export type CollectionEntry = Flatten; - - export type ContentCollectionKey = keyof ContentEntryMap; - export type DataCollectionKey = keyof DataEntryMap; - - // This needs to be in sync with ImageMetadata - export type ImageFunction = () => import('astro/zod').ZodObject<{ - src: import('astro/zod').ZodString; - width: import('astro/zod').ZodNumber; - height: import('astro/zod').ZodNumber; - format: import('astro/zod').ZodUnion< - [ - import('astro/zod').ZodLiteral<'png'>, - import('astro/zod').ZodLiteral<'jpg'>, - import('astro/zod').ZodLiteral<'jpeg'>, - import('astro/zod').ZodLiteral<'tiff'>, - import('astro/zod').ZodLiteral<'webp'>, - import('astro/zod').ZodLiteral<'gif'>, - import('astro/zod').ZodLiteral<'svg'>, - import('astro/zod').ZodLiteral<'avif'>, - ] - >; - }>; - - type BaseSchemaWithoutEffects = - | import('astro/zod').AnyZodObject - | import('astro/zod').ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]> - | import('astro/zod').ZodDiscriminatedUnion - | import('astro/zod').ZodIntersection; - - type BaseSchema = - | BaseSchemaWithoutEffects - | import('astro/zod').ZodEffects; - - export type SchemaContext = { image: ImageFunction }; - - type DataCollectionConfig = { - type: 'data'; - schema?: S | ((context: SchemaContext) => S); - }; - - type ContentCollectionConfig = { - type?: 'content'; - schema?: S | ((context: SchemaContext) => S); - }; - - type CollectionConfig = ContentCollectionConfig | DataCollectionConfig; - - export function defineCollection( - input: CollectionConfig - ): CollectionConfig; - - type AllValuesOf = T extends any ? T[keyof T] : never; - type ValidContentEntrySlug = AllValuesOf< - ContentEntryMap[C] - >['slug']; - - export function getEntryBySlug< - C extends keyof ContentEntryMap, - E extends ValidContentEntrySlug | (string & {}), - >( - collection: C, - // Note that this has to accept a regular string too, for SSR - entrySlug: E - ): E extends ValidContentEntrySlug - ? Promise> - : Promise | undefined>; - - export function getDataEntryById( - collection: C, - entryId: E - ): Promise>; - - export function getCollection>( - collection: C, - filter?: (entry: CollectionEntry) => entry is E - ): Promise; - export function getCollection( - collection: C, - filter?: (entry: CollectionEntry) => unknown - ): Promise[]>; - - export function getEntry< - C extends keyof ContentEntryMap, - E extends ValidContentEntrySlug | (string & {}), - >(entry: { - collection: C; - slug: E; - }): E extends ValidContentEntrySlug - ? Promise> - : Promise | undefined>; - export function getEntry< - C extends keyof DataEntryMap, - E extends keyof DataEntryMap[C] | (string & {}), - >(entry: { - collection: C; - id: E; - }): E extends keyof DataEntryMap[C] - ? Promise - : Promise | undefined>; - export function getEntry< - C extends keyof ContentEntryMap, - E extends ValidContentEntrySlug | (string & {}), - >( - collection: C, - slug: E - ): E extends ValidContentEntrySlug - ? Promise> - : Promise | undefined>; - export function getEntry< - C extends keyof DataEntryMap, - E extends keyof DataEntryMap[C] | (string & {}), - >( - collection: C, - id: E - ): E extends keyof DataEntryMap[C] - ? Promise - : Promise | undefined>; - - /** Resolve an array of entry references from the same collection */ - export function getEntries( - entries: { - collection: C; - slug: ValidContentEntrySlug; - }[] - ): Promise[]>; - export function getEntries( - entries: { - collection: C; - id: keyof DataEntryMap[C]; - }[] - ): Promise[]>; - - export function reference( - collection: C - ): import('astro/zod').ZodEffects< - import('astro/zod').ZodString, - C extends keyof ContentEntryMap - ? { - collection: C; - slug: ValidContentEntrySlug; - } - : { - collection: C; - id: keyof DataEntryMap[C]; - } - >; - // Allow generic `string` to avoid excessive type errors in the config - // if `dev` is not running to update as you edit. - // Invalid collection names will be caught at build time. - export function reference( - collection: C - ): import('astro/zod').ZodEffects; - - type ReturnTypeOrOriginal = T extends (...args: any[]) => infer R ? R : T; - type InferEntrySchema = import('astro/zod').infer< - ReturnTypeOrOriginal['schema']> - >; - - type ContentEntryMap = { - "blog": { -"hello.mdx": { - id: "hello.mdx"; - slug: "hello"; - body: string; - collection: "blog"; - data: any -} & { render(): Render[".mdx"] }; -}; - - }; - - type DataEntryMap = { - - }; - - type AnyEntryMap = ContentEntryMap & DataEntryMap; - - type ContentConfig = never; + export { z } from 'astro/zod'; + + type Flatten = T extends { [K: string]: infer U } ? U : never; + + export type CollectionKey = keyof AnyEntryMap; + export type CollectionEntry = Flatten; + + export type ContentCollectionKey = keyof ContentEntryMap; + export type DataCollectionKey = keyof DataEntryMap; + + // This needs to be in sync with ImageMetadata + export type ImageFunction = () => import('astro/zod').ZodObject<{ + src: import('astro/zod').ZodString; + width: import('astro/zod').ZodNumber; + height: import('astro/zod').ZodNumber; + format: import('astro/zod').ZodUnion< + [ + import('astro/zod').ZodLiteral<'png'>, + import('astro/zod').ZodLiteral<'jpg'>, + import('astro/zod').ZodLiteral<'jpeg'>, + import('astro/zod').ZodLiteral<'tiff'>, + import('astro/zod').ZodLiteral<'webp'>, + import('astro/zod').ZodLiteral<'gif'>, + import('astro/zod').ZodLiteral<'svg'>, + import('astro/zod').ZodLiteral<'avif'>, + ] + >; + }>; + + type BaseSchemaWithoutEffects = + | import('astro/zod').AnyZodObject + | import('astro/zod').ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]> + | import('astro/zod').ZodDiscriminatedUnion + | import('astro/zod').ZodIntersection; + + type BaseSchema = BaseSchemaWithoutEffects | import('astro/zod').ZodEffects; + + export type SchemaContext = { image: ImageFunction }; + + type DataCollectionConfig = { + type: 'data'; + schema?: S | ((context: SchemaContext) => S); + }; + + type ContentCollectionConfig = { + type?: 'content'; + schema?: S | ((context: SchemaContext) => S); + }; + + type CollectionConfig = ContentCollectionConfig | DataCollectionConfig; + + export function defineCollection(input: CollectionConfig): CollectionConfig; + + type AllValuesOf = T extends any ? T[keyof T] : never; + type ValidContentEntrySlug = AllValuesOf['slug']; + + export function getEntryBySlug | (string & {})>( + collection: C, + // Note that this has to accept a regular string too, for SSR + entrySlug: E, + ): E extends ValidContentEntrySlug ? Promise> : Promise | undefined>; + + export function getDataEntryById( + collection: C, + entryId: E, + ): Promise>; + + export function getCollection>( + collection: C, + filter?: (entry: CollectionEntry) => entry is E, + ): Promise; + export function getCollection( + collection: C, + filter?: (entry: CollectionEntry) => unknown, + ): Promise[]>; + + export function getEntry | (string & {})>(entry: { + collection: C; + slug: E; + }): E extends ValidContentEntrySlug ? Promise> : Promise | undefined>; + export function getEntry(entry: { + collection: C; + id: E; + }): E extends keyof DataEntryMap[C] ? Promise : Promise | undefined>; + export function getEntry | (string & {})>( + collection: C, + slug: E, + ): E extends ValidContentEntrySlug ? Promise> : Promise | undefined>; + export function getEntry( + collection: C, + id: E, + ): E extends keyof DataEntryMap[C] ? Promise : Promise | undefined>; + + /** Resolve an array of entry references from the same collection */ + export function getEntries( + entries: { + collection: C; + slug: ValidContentEntrySlug; + }[], + ): Promise[]>; + export function getEntries( + entries: { + collection: C; + id: keyof DataEntryMap[C]; + }[], + ): Promise[]>; + + export function reference( + collection: C, + ): import('astro/zod').ZodEffects< + import('astro/zod').ZodString, + C extends keyof ContentEntryMap + ? { + collection: C; + slug: ValidContentEntrySlug; + } + : { + collection: C; + id: keyof DataEntryMap[C]; + } + >; + // Allow generic `string` to avoid excessive type errors in the config + // if `dev` is not running to update as you edit. + // Invalid collection names will be caught at build time. + export function reference( + collection: C, + ): import('astro/zod').ZodEffects; + + type ReturnTypeOrOriginal = T extends (...args: any[]) => infer R ? R : T; + type InferEntrySchema = import('astro/zod').infer< + ReturnTypeOrOriginal['schema']> + >; + + type ContentEntryMap = { + blog: { + 'hello.mdx': { + id: 'hello.mdx'; + slug: 'hello'; + body: string; + collection: 'blog'; + data: any; + } & { render(): Render['.mdx'] }; + }; + }; + + type DataEntryMap = {}; + + type AnyEntryMap = ContentEntryMap & DataEntryMap; + + type ContentConfig = never; } From c02976782bf83f42d3061c923e0cb923088f7fdc Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 23:22:10 +0100 Subject: [PATCH 63/93] add video component --- website/src/components/BlogVideo.astro | 5 +++++ website/src/content/blog/release-0.8.0-himbeermuffin.mdx | 4 +++- website/src/content/blog/release-0.9.0-bananenbrot.mdx | 4 +++- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 website/src/components/BlogVideo.astro diff --git a/website/src/components/BlogVideo.astro b/website/src/components/BlogVideo.astro new file mode 100644 index 000000000..e9112fdaf --- /dev/null +++ b/website/src/components/BlogVideo.astro @@ -0,0 +1,5 @@ +--- +const { src } = Astro.props; +--- + + diff --git a/website/src/content/blog/release-0.8.0-himbeermuffin.mdx b/website/src/content/blog/release-0.8.0-himbeermuffin.mdx index d2ae211ae..491166665 100644 --- a/website/src/content/blog/release-0.8.0-himbeermuffin.mdx +++ b/website/src/content/blog/release-0.8.0-himbeermuffin.mdx @@ -6,6 +6,8 @@ tags: ['meta'] author: froos --- +import BlogVideo from '../../components/BlogVideo.astro'; + # Release Notes v0.8.0 Himbeermuffin These are the release notes for Strudel 0.8.0 aka "Himbeermuffin"! @@ -43,7 +45,7 @@ I would be very happy to collect some feedback on how it works across different Also still undocumented, but you can now visualize patterns as a spiral via `.spiral()`: -https://github.com/tidalcycles/strudel/assets/12023032/05bc2dba-b304-4298-9465-a1a6fafe5ded + This is especially nice because strudel is not only the name of a dessert but also the german word for vortex! The spiral is very fitting to visualize cycles because you can align cycles vertically, while surfing along an infinite twisted timeline. diff --git a/website/src/content/blog/release-0.9.0-bananenbrot.mdx b/website/src/content/blog/release-0.9.0-bananenbrot.mdx index 1322362eb..c18bc60e3 100644 --- a/website/src/content/blog/release-0.9.0-bananenbrot.mdx +++ b/website/src/content/blog/release-0.9.0-bananenbrot.mdx @@ -6,6 +6,8 @@ tags: ['meta'] author: froos --- +import BlogVideo from '../../components/BlogVideo.astro'; + # Release Notes v0.9.0 Bananenbrot These are the release notes for Strudel 0.9.0 aka "Bananenbrot"! @@ -25,7 +27,7 @@ Main new features include: - [vibrato](https://strudel.tidalcycles.org/learn/synths#vibrato) - an integration of [ZZFX](https://strudel.tidalcycles.org/learn/synths#zzfx) -https://github.com/tidalcycles/strudel/assets/12023032/652e7042-f296-496b-95cd-b2a4987fe238 + Related PRs: From 98db3d37efda3a851161e943f019766e8243ef68 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 23:30:26 +0100 Subject: [PATCH 64/93] add anchor links --- website/src/components/BlogPost.astro | 2 +- website/src/pages/blog.astro | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/website/src/components/BlogPost.astro b/website/src/components/BlogPost.astro index 1fdb5a1a4..0b3fc6a57 100644 --- a/website/src/components/BlogPost.astro +++ b/website/src/components/BlogPost.astro @@ -12,7 +12,7 @@ const { Content } = await post.render(); >
-

{post.title}

+

{post.title}

diff --git a/website/src/pages/blog.astro b/website/src/pages/blog.astro index 431244c64..d01eb6b8e 100644 --- a/website/src/pages/blog.astro +++ b/website/src/pages/blog.astro @@ -36,7 +36,13 @@ const posts = (await getCollection('blog')).sort((a, b) => compareDesc(a.data.da {posts.map((post) => )}
From 79f1a863b6451eb1dee37036524c7df8a8f40fce Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 14 Jan 2024 23:39:03 +0100 Subject: [PATCH 65/93] add date + author to posts + dedupe headings --- website/src/components/BlogPost.astro | 8 +++++++- website/src/content/blog/release-0.0.2-schwindlig.mdx | 2 -- website/src/content/blog/release-0.0.2.1-stuermisch.mdx | 2 -- website/src/content/blog/release-0.0.3-maelstrom.mdx | 2 -- website/src/content/blog/release-0.0.4-gischt.mdx | 2 -- website/src/content/blog/release-0.3.0-donauwelle.mdx | 2 -- website/src/content/blog/release-0.4.0-brandung.mdx | 2 -- website/src/content/blog/release-0.5.0-wirbel.mdx | 2 -- website/src/content/blog/release-0.6.0-zimtschnecke.mdx | 2 -- website/src/content/blog/release-0.7.0-zuckerguss.mdx | 2 -- website/src/content/blog/release-0.8.0-himbeermuffin.mdx | 2 -- website/src/content/blog/release-0.9.0-bananenbrot.mdx | 2 -- website/src/pages/blog.astro | 1 - 13 files changed, 7 insertions(+), 24 deletions(-) diff --git a/website/src/components/BlogPost.astro b/website/src/components/BlogPost.astro index 0b3fc6a57..b5b826806 100644 --- a/website/src/components/BlogPost.astro +++ b/website/src/components/BlogPost.astro @@ -5,6 +5,7 @@ type Props = CollectionEntry<'blog'>['data']; const { post } = Astro.props; const { Content } = await post.render(); +import { format } from 'date-fns'; ---
-

{post.title}

+

{post.data.title}

+

+ +

diff --git a/website/src/content/blog/release-0.0.2-schwindlig.mdx b/website/src/content/blog/release-0.0.2-schwindlig.mdx index 3cb9b50be..b65ff98f5 100644 --- a/website/src/content/blog/release-0.0.2-schwindlig.mdx +++ b/website/src/content/blog/release-0.0.2-schwindlig.mdx @@ -6,8 +6,6 @@ tags: ['meta'] author: froos --- -# Release Notes v0.0.2 Schwindlig - ## What's Changed - Most work done as [commits to main](https://github.com/tidalcycles/strudel/commits/2a0d8c3f77ff7b34e82602e2d02400707f367316) diff --git a/website/src/content/blog/release-0.0.2.1-stuermisch.mdx b/website/src/content/blog/release-0.0.2.1-stuermisch.mdx index 28da1a8ff..3824bd6b1 100644 --- a/website/src/content/blog/release-0.0.2.1-stuermisch.mdx +++ b/website/src/content/blog/release-0.0.2.1-stuermisch.mdx @@ -5,8 +5,6 @@ tags: ['meta'] author: froos --- -# Release Notes v0.0.2.1 Stürmisch - ## What's Changed - Add chunk, chunkBack and iterBack by @yaxu in https://github.com/tidalcycles/strudel/pull/25 diff --git a/website/src/content/blog/release-0.0.3-maelstrom.mdx b/website/src/content/blog/release-0.0.3-maelstrom.mdx index ee8d5143b..542412d82 100644 --- a/website/src/content/blog/release-0.0.3-maelstrom.mdx +++ b/website/src/content/blog/release-0.0.3-maelstrom.mdx @@ -6,8 +6,6 @@ tags: ['meta'] author: froos --- -# Release Notes v0.0.3 Maelstrom - ## What's Changed - Add chunk, chunkBack and iterBack by @yaxu in https://github.com/tidalcycles/strudel/pull/25 diff --git a/website/src/content/blog/release-0.0.4-gischt.mdx b/website/src/content/blog/release-0.0.4-gischt.mdx index 93db48766..83b831a75 100644 --- a/website/src/content/blog/release-0.0.4-gischt.mdx +++ b/website/src/content/blog/release-0.0.4-gischt.mdx @@ -6,8 +6,6 @@ tags: ['meta'] author: froos --- -# Release Notes v0.0.4 Gischt - ## What's Changed - Webaudio rewrite by @felixroos in https://github.com/tidalcycles/strudel/pull/138 diff --git a/website/src/content/blog/release-0.3.0-donauwelle.mdx b/website/src/content/blog/release-0.3.0-donauwelle.mdx index ce086dbc7..70dba0e68 100644 --- a/website/src/content/blog/release-0.3.0-donauwelle.mdx +++ b/website/src/content/blog/release-0.3.0-donauwelle.mdx @@ -6,8 +6,6 @@ tags: ['meta'] author: froos --- -# Release Notes v0.3.0 Donauwelle - ## Package Versions - @strudel.cycles/core@0.3.1 diff --git a/website/src/content/blog/release-0.4.0-brandung.mdx b/website/src/content/blog/release-0.4.0-brandung.mdx index 67e61ece2..56a1d2e29 100644 --- a/website/src/content/blog/release-0.4.0-brandung.mdx +++ b/website/src/content/blog/release-0.4.0-brandung.mdx @@ -6,8 +6,6 @@ tags: ['meta'] author: froos --- -# Release Notes v0.4.0 Brandung - ## What's Changed - new transpiler based on acorn by @felixroos in https://github.com/tidalcycles/strudel/pull/249 diff --git a/website/src/content/blog/release-0.5.0-wirbel.mdx b/website/src/content/blog/release-0.5.0-wirbel.mdx index 8912627c4..7d04f0d27 100644 --- a/website/src/content/blog/release-0.5.0-wirbel.mdx +++ b/website/src/content/blog/release-0.5.0-wirbel.mdx @@ -6,8 +6,6 @@ tags: ['meta'] author: froos --- -# Release Notes v0.5.0 Wirbel - ## Package Versions - @strudel.cycles/core@0.5.0 diff --git a/website/src/content/blog/release-0.6.0-zimtschnecke.mdx b/website/src/content/blog/release-0.6.0-zimtschnecke.mdx index 9e5f2f356..ee6353d36 100644 --- a/website/src/content/blog/release-0.6.0-zimtschnecke.mdx +++ b/website/src/content/blog/release-0.6.0-zimtschnecke.mdx @@ -6,8 +6,6 @@ tags: ['meta'] author: froos --- -# Release Notes v0.6.0 Zimtschnecke - ## Package Versions - @strudel.cycles/core@0.6.8 diff --git a/website/src/content/blog/release-0.7.0-zuckerguss.mdx b/website/src/content/blog/release-0.7.0-zuckerguss.mdx index 55315a9cd..1d810cb29 100644 --- a/website/src/content/blog/release-0.7.0-zuckerguss.mdx +++ b/website/src/content/blog/release-0.7.0-zuckerguss.mdx @@ -6,8 +6,6 @@ tags: ['meta'] author: froos --- -# Release Notes v0.7.0 Zimtschnecke - ## Package Versions - @strudel.cycles/core@0.7.2 diff --git a/website/src/content/blog/release-0.8.0-himbeermuffin.mdx b/website/src/content/blog/release-0.8.0-himbeermuffin.mdx index 491166665..7baea4c1b 100644 --- a/website/src/content/blog/release-0.8.0-himbeermuffin.mdx +++ b/website/src/content/blog/release-0.8.0-himbeermuffin.mdx @@ -8,8 +8,6 @@ author: froos import BlogVideo from '../../components/BlogVideo.astro'; -# Release Notes v0.8.0 Himbeermuffin - These are the release notes for Strudel 0.8.0 aka "Himbeermuffin"! [Go to Tidal Club Forum for this Release](https://club.tidalcycles.org/t/strudel-0-8-0-released/4769) diff --git a/website/src/content/blog/release-0.9.0-bananenbrot.mdx b/website/src/content/blog/release-0.9.0-bananenbrot.mdx index c18bc60e3..eed5bf553 100644 --- a/website/src/content/blog/release-0.9.0-bananenbrot.mdx +++ b/website/src/content/blog/release-0.9.0-bananenbrot.mdx @@ -8,8 +8,6 @@ author: froos import BlogVideo from '../../components/BlogVideo.astro'; -# Release Notes v0.9.0 Bananenbrot - These are the release notes for Strudel 0.9.0 aka "Bananenbrot"! The last release was over 11 weeks ago, so a lot of things have happened! diff --git a/website/src/pages/blog.astro b/website/src/pages/blog.astro index d01eb6b8e..802703534 100644 --- a/website/src/pages/blog.astro +++ b/website/src/pages/blog.astro @@ -32,7 +32,6 @@ const posts = (await getCollection('blog')).sort((a, b) => compareDesc(a.data.da -

Strudel Blog

{posts.map((post) => )}
- {posts.map((post) => )} +
+

Strudel Blog

+

+ Welcome to the Strudel Blog, where you we will keep you updated with the latest changes and things + happening in the strudelsphere. +

+
+
+ {posts.map((post) => )} +
-
+

Strudel Blog

- Welcome to the Strudel Blog, where you we will keep you updated with the latest changes and things - happening in the strudelsphere. + Welcome to the Strudel Blog, where we will keep you updated with the latest changes and things happening + in the strudelsphere. You can subscribe to this blog using this rss link

From f85fb35c669bc52ad8fa79d10e4a38157242042e Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 18 Jan 2024 13:46:35 +0100 Subject: [PATCH 88/93] minirepl multi tune support + add other getting-started examples (more to come) --- website/src/docs/Icon.jsx | 15 ++++ website/src/docs/MiniRepl.jsx | 43 ++++++++-- website/src/examples.mjs | 81 +++++++++++++++++++ .../src/pages/workshop/getting-started.mdx | 36 ++------- 4 files changed, 139 insertions(+), 36 deletions(-) create mode 100644 website/src/examples.mjs diff --git a/website/src/docs/Icon.jsx b/website/src/docs/Icon.jsx index 64d5f88ac..91583e505 100644 --- a/website/src/docs/Icon.jsx +++ b/website/src/docs/Icon.jsx @@ -1,4 +1,12 @@ export function Icon({ type }) { + if (type === 'skip') { + // !Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc. + return ( + + + + ); + } return ( { @@ -31,6 +39,13 @@ export function Icon({ type }) { clipRule="evenodd" /> ), + skip: ( + + ), }[type] } diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index 33dadedf6..10eff4832 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -1,8 +1,8 @@ import { useState, useRef, useCallback, useMemo, useEffect } from 'react'; import { Icon } from './Icon'; -import { silence, getPunchcardPainter, noteToMidi } from '@strudel/core'; +import { silence, getPunchcardPainter, noteToMidi, _mod } from '@strudel/core'; import { transpiler } from '@strudel/transpiler'; -import { getAudioContext, webaudioOutput } from '@strudel/webaudio'; +import { getAudioContext, webaudioOutput, initAudioOnFirstClick } from '@strudel/webaudio'; import { StrudelMirror } from '@strudel/codemirror'; // import { prebake } from '@strudel/repl'; import { prebake } from '../repl/prebake.mjs'; @@ -10,14 +10,16 @@ import { loadModules } from '../repl/util.mjs'; import Claviature from '@components/Claviature'; import useClient from '@src/useClient.mjs'; -let prebaked, modulesLoading; +let prebaked, modulesLoading, audioLoading; if (typeof window !== 'undefined') { prebaked = prebake(); modulesLoading = loadModules(); + audioLoading = initAudioOnFirstClick(); } export function MiniRepl({ - tune: code, + tune, + tunes, hideHeader = false, canvasHeight = 100, onTrigger, @@ -26,6 +28,7 @@ export function MiniRepl({ claviature, claviatureLabels, }) { + const code = tunes ? tunes[0] : tune; const id = useMemo(() => s4(), []); const canvasId = useMemo(() => `canvas-${id}`, [id]); const shouldDraw = !!punchcard || !!claviature; @@ -75,7 +78,7 @@ export function MiniRepl({ } return pat; }, - prebake: async () => Promise.all([modulesLoading, prebaked]), + prebake: async () => Promise.all([modulesLoading, prebaked, audioLoading]), onUpdateState: (state) => { setReplState({ ...state }); }, @@ -91,6 +94,14 @@ export function MiniRepl({ const containerRef = useRef(); const client = useClient(); + const [tuneIndex, setTuneIndex] = useState(0); + const changeTune = (index) => { + index = _mod(index, tunes.length); + setTuneIndex(index); + editorRef.current?.setCode(tunes[index]); + editorRef.current?.evaluate(); + }; + if (!client) { return
{code}
; } @@ -119,6 +130,28 @@ export function MiniRepl({
+ {tunes && ( +
+ + +
+ )}
)}
diff --git a/website/src/examples.mjs b/website/src/examples.mjs new file mode 100644 index 000000000..d752e711d --- /dev/null +++ b/website/src/examples.mjs @@ -0,0 +1,81 @@ +export const examples = [ + `// "coastline" @by eddyflux +await samples('github:eddyflux/crate') +setcps(.75) +let chords = chord("/4").dict('ireal') +stack( + stack( // DRUMS + s("bd").struct("<[x*<1 2> [~@3 x]] x>"), + s("~ [rim, sd:<2 3>]").room("<0 .2>"), + n("[0 <1 3>]*<2!3 4>").s("hh"), + s("rd:<1!3 2>*2").mask("<0 0 1 1>/16").gain(.5) + ).bank('crate') + .mask("<[0 1] 1 1 1>/16".early(.5)) + , // CHORDS + chords.offset(-1).voicing().s("gm_epiano1:1") + .phaser(4).room(.5) + , // MELODY + n("<0!3 1*2>").set(chords).mode("root:g2") + .voicing().s("gm_acoustic_bass"), + chords.n("[0 <4 3 <2 5>>*2](<3 5>,8)") + .set(x).anchor("D5").voicing() + .segment(4).clip(rand.range(.4,.8)) + .room(.75).shape(.3).delay(.25) + .fm(sine.range(3,8).slow(8)) + .lpf(sine.range(500,1000).slow(8)).lpq(5) + .rarely(ply("2")).chunk(4, fast(2)) + .gain(perlin.range(.6, .9)) + .mask("<0 1 1 0>/16") +) +.late("[0 .01]*4").late("[0 .01]*2").size(4)`, + `// "broken cut 1" @by froos + +await samples('github:tidalcycles/Dirt-Samples/master') +samples({ + 'slap': 'https://cdn.freesound.org/previews/495/495416_10350281-lq.mp3', + 'whirl': 'https://cdn.freesound.org/previews/495/495313_10350281-lq.mp3', + 'attack': 'https://cdn.freesound.org/previews/494/494947_10350281-lq.mp3' +}) + +setcps(1.25) + +note("[c2 ~](3,8)*2,eb,g,bb,d").s("sawtooth") + .noise(0.3) + .lpf(perlin.range(800,2000).mul(0.6)) + .lpenv(perlin.range(1,5)).lpa(.25).lpd(.1).lps(0) + .add.mix(note("<0!3 [1 <4!3 12>]>")).late(.5) + .vib("4:.2") + .room(1).roomsize(4).slow(4) + .stack( + s("bd").late("<0.01 .251>"), + s("breaks165:1/2").fit() + .chop(4).sometimesBy(.4, ply("2")) + .sometimesBy(.1, ply("4")).release(.01) + .gain(1.5).sometimes(mul(speed("1.05"))).cut(1) + , + s("?").delay(".8:.1:.8").room(2).slow(8).cut(2), + ).reset("".late(2))`, + `// "acidic tooth" @by eddyflux + setcps(1) + stack( + note("[/8](<3 5>,8)") + .clip(perlin.range(.15,1.5)) + .release(.1) + .s("sawtooth") + .lpf(sine.range(400,800).slow(16)) + .lpq(cosine.range(6,14).slow(3)) + .lpenv(sine.mul(4).slow(4)) + .lpd(.2).lpa(.02) + .ftype('24db') + .rarely(add(note(12))) + .room(.2).shape(.3).postgain(.5) + .superimpose(x=>x.add(note(12)).delay(.5).bpf(1000)) + .gain("[.2 1@3]*2") // fake sidechain + , + stack( + s("bd*2").mask("<0@4 1@16>"), + s("hh*8").gain(saw.mul(saw.fast(2))).clip(sine) + .mask("<0@8 1@16>") + ).bank('RolandTR909') + )`, +]; diff --git a/website/src/pages/workshop/getting-started.mdx b/website/src/pages/workshop/getting-started.mdx index 3d37a5cf7..83dc8894d 100644 --- a/website/src/pages/workshop/getting-started.mdx +++ b/website/src/pages/workshop/getting-started.mdx @@ -4,6 +4,7 @@ layout: ../../layouts/MainLayout.astro --- import { MiniRepl } from '../../docs/MiniRepl'; +import { examples } from '../../examples.mjs'; # Welcome @@ -29,40 +30,13 @@ The best place to actually make music with Strudel is the [Strudel REPL](https:/ - teaching: focussing on a low barrier of entry, Strudel is a good fit for teaching music and code at the same time. - integrate into your existing music setup: either via MIDI or OSC, you can use Strudel as a really flexible sequencer -## Example +## Examples -Here is an example of how strudel can sound: +Here are some examples of how strudel can sound: -],hh*8") - .speed(perlin.range(.8,.9)), // random sample speed variation - // bassline - "" - .off(1/8,x=>x.add(12).degradeBy(.5)) // random octave jumps - .add(perlin.range(0,.5)) // random pitch variation - .superimpose(add(.05)) // add second, slightly detuned voice - .note() // wrap in "note" - .decay(.15).sustain(0) // make each note of equal length - .s('sawtooth') // waveform - .gain(.4) // turn down - .cutoff(sine.slow(7).range(300,5000)), // automate cutoff - // chords - ">".voicings('lefthand') - .superimpose(x=>x.add(.04)) // add second, slightly detuned voice - .add(perlin.range(0,.5)) // random pitch variation - .note() // wrap in "note" - .s('sawtooth') // waveform - .gain(.16) // turn down - .cutoff(500) // fixed cutoff - .attack(1) // slowly fade in -) -.slow(3/2)`} -/> + -To hear more, go to the [Strudel REPL](https://strudel.cc/) and press shuffle to hear a random example pattern. +These examples cannot fully encompass the variety of things you can do, so [check out the showcase](/intro/showcase/) for some videos of how people use Strudel. ## Getting Started From 0778b4809e104b99a377d283123325dcdec13987 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 18 Jan 2024 13:47:34 +0100 Subject: [PATCH 89/93] format --- website/src/docs/Icon.jsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/website/src/docs/Icon.jsx b/website/src/docs/Icon.jsx index 91583e505..48b05d87f 100644 --- a/website/src/docs/Icon.jsx +++ b/website/src/docs/Icon.jsx @@ -2,7 +2,14 @@ export function Icon({ type }) { if (type === 'skip') { // !Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc. return ( - + ); From 873a4121791f83c64ddbe829075f4c1173ba441b Mon Sep 17 00:00:00 2001 From: Alex McLean Date: Thu, 18 Jan 2024 16:45:39 +0000 Subject: [PATCH 90/93] `pick` now accepts lookup tables, with alternate cycle squeezing behaviour as new `inhabit` function (#918) - the args for `pick` are now reversed (breaking change!) - `pick` is also now a method on the inhabited pattern - `pick` now also accepts a lookup table - `inhabit` added with same behaviour as `pick`, except cycles from source patterns are squeezed into events of inhabited patterns - Also some general doc tidying, sorry for the noise.. - There is now also `pickmod` and `inhabitmod`, for wrapping indexes around rather than clamping them --- packages/core/controls.mjs | 10 +-- packages/core/pattern.mjs | 36 ++++----- packages/core/signal.mjs | 97 ++++++++++++++++++----- packages/core/test/pattern.test.mjs | 51 ++++++++++++ packages/core/util.mjs | 7 ++ test/__snapshots__/examples.test.mjs.snap | 93 +++++++++++++++++++++- 6 files changed, 247 insertions(+), 47 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 444b4ea17..42212dd3b 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -97,7 +97,7 @@ const generic_params = [ */ ['postgain'], /** - * Like {@link gain}, but linear. + * Like `gain`, but linear. * * @name amp * @param {number | Pattern} amount gain. @@ -856,7 +856,7 @@ const generic_params = [ */ ['detune', 'det'], /** - * Set dryness of reverb. See {@link room} and {@link size} for more information about reverb. + * Set dryness of reverb. See `room` and `size` for more information about reverb. * * @name dry * @param {number | Pattern} dry 0 = wet, 1 = dry @@ -868,7 +868,7 @@ const generic_params = [ ['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. + * Used when using `begin`/`end` or `chop`/`striate` and friends, to change the fade out time of the 'grain' envelope. * * @name fadeTime * @param {number | Pattern} time between 0 and 1 @@ -1191,7 +1191,7 @@ const generic_params = [ */ [['ir', 'i'], 'iresponse'], /** - * Sets the room size of the reverb, see {@link room}. + * Sets the room size of the reverb, see `room`. * When this property is changed, the reverb will be recaculated, so only change this sparsely.. * * @name roomsize @@ -1249,7 +1249,7 @@ const generic_params = [ */ ['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`. + * Used in conjunction with `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 diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 9e804b236..6a7b210be 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -26,7 +26,7 @@ export class Pattern { /** * Create a pattern. As an end user, you will most likely not create a Pattern directly. * - * @param {function} query - The function that maps a {@link State} to an array of {@link Hap}. + * @param {function} query - The function that maps a `State` to an array of `Hap`. * @noAutocomplete */ constructor(query) { @@ -39,7 +39,7 @@ export class Pattern { /** * Returns a new pattern, with the function applied to the value of - * each hap. It has the alias {@link Pattern#fmap}. + * each hap. It has the alias `fmap`. * @synonyms fmap * @param {Function} func to to apply to the value * @returns Pattern @@ -51,7 +51,7 @@ export class Pattern { } /** - * see {@link Pattern#withValue} + * see `withValue` * @noAutocomplete */ fmap(func) { @@ -115,7 +115,7 @@ export class Pattern { } /** - * As with {@link Pattern#appBoth}, but the `whole` timespan is not the intersection, + * As with `appBoth`, but the `whole` timespan is not the intersection, * but the timespan from the function of patterns that this method is called * on. In practice, this means that the pattern structure, including onsets, * are preserved from the pattern of functions (often referred to as the left @@ -148,7 +148,7 @@ export class Pattern { } /** - * As with {@link Pattern#appLeft}, but `whole` timespans are instead taken from the + * As with `appLeft`, but `whole` timespans are instead taken from the * pattern of values, i.e. structure is preserved from the right hand/outer * pattern. * @param {Pattern} pat_val @@ -387,7 +387,7 @@ export class Pattern { } /** - * As with {@link Pattern#withQuerySpan}, but the function is applied to both the + * As with `withQuerySpan`, but the function is applied to both the * begin and end time of the query timespan. * @param {Function} func the function to apply * @returns Pattern @@ -398,7 +398,7 @@ export class Pattern { } /** - * Similar to {@link Pattern#withQuerySpan}, but the function is applied to the timespans + * Similar to `withQuerySpan`, but the function is applied to the timespans * of all haps returned by pattern queries (both `part` timespans, and where * present, `whole` timespans). * @param {Function} func @@ -410,7 +410,7 @@ export class Pattern { } /** - * As with {@link Pattern#withHapSpan}, but the function is applied to both the + * As with `withHapSpan`, but the function is applied to both the * begin and end time of the hap timespans. * @param {Function} func the function to apply * @returns Pattern @@ -431,7 +431,7 @@ export class Pattern { } /** - * As with {@link Pattern#withHaps}, but applies the function to every hap, rather than every list of haps. + * As with `withHaps`, but applies the function to every hap, rather than every list of haps. * @param {Function} func * @returns Pattern * @noAutocomplete @@ -499,7 +499,7 @@ export class Pattern { } /** - * As with {@link Pattern#filterHaps}, but the function is applied to values + * As with `filterHaps`, but the function is applied to values * inside haps. * @param {Function} value_test * @returns Pattern @@ -621,7 +621,7 @@ export class Pattern { } /** - * More human-readable version of the {@link Pattern#firstCycleValues} accessor. + * More human-readable version of the `firstCycleValues` accessor. * @noAutocomplete */ get showFirstCycle() { @@ -691,7 +691,7 @@ export class Pattern { // Methods without corresponding toplevel functions /** - * Layers the result of the given function(s). Like {@link Pattern.superimpose}, but without the original pattern: + * Layers the result of the given function(s). Like `superimpose`, but without the original pattern: * @name layer * @memberof Pattern * @synonyms apply @@ -1189,7 +1189,7 @@ export function stack(...pats) { /** Concatenation: combines a list of patterns, switching between them successively, one per cycle: * - * synonyms: {@link cat} + * synonyms: `cat` * * @return {Pattern} * @example @@ -1244,7 +1244,7 @@ export function cat(...pats) { return slowcat(...pats); } -/** Like {@link Pattern.seq}, but each step has a length, relative to the whole. +/** Like `seq`, but each step has a length, relative to the whole. * @return {Pattern} * @example * timeCat([3,"e3"],[1, "g3"]).note() // "e3@3 g3".note() @@ -1279,7 +1279,7 @@ export function fastcat(...pats) { return slowcat(...pats)._fast(pats.length); } -/** See {@link fastcat} */ +/** See `fastcat` */ export function sequence(...pats) { return fastcat(...pats); } @@ -1636,7 +1636,7 @@ export const { fastGap, fastgap } = register(['fastGap', 'fastgap'], function (f }); /** - * Similar to compress, but doesn't leave gaps, and the 'focus' can be bigger than a cycle + * Similar to `compress`, but doesn't leave gaps, and the 'focus' can be bigger than a cycle * @example * s("bd hh sd hh").focus(1/4, 3/4) */ @@ -1753,7 +1753,7 @@ export const lastOf = register('lastOf', function (n, func, pat) { */ /** - * An alias for {@link firstOf} + * An alias for `firstOf` * @name every * @memberof Pattern * @param {number} n how many cycles @@ -2365,7 +2365,7 @@ export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (facto // 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. + * Similar to `loopAt`. * @name fit * @example * samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' }) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 1446beebd..9e8db9a01 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th import { Hap } from './hap.mjs'; import { Pattern, fastcat, reify, silence, stack, register } from './pattern.mjs'; import Fraction from './fraction.mjs'; -import { id, _mod, clamp } from './util.mjs'; +import { id, _mod, clamp, objectMap } from './util.mjs'; export function steady(value) { // A continuous value @@ -156,31 +156,88 @@ export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i)); */ export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin(); +const _pick = function (lookup, pat, modulo = true) { + const array = Array.isArray(lookup); + const len = Object.keys(lookup).length; + + lookup = objectMap(lookup, reify); + + if (len === 0) { + return silence; + } + return pat.fmap((i) => { + let key = i; + if (array) { + key = modulo ? Math.round(key) % len : clamp(Math.round(key), 0, lookup.length - 1); + } + return lookup[key]; + }); +}; + +/** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name). + * Similar to `inhabit`, but maintains the structure of the original patterns. + * @param {Pattern} pat + * @param {*} xs + * @returns {Pattern} + * @example + * note("<0 1 2!2 3>".pick(["g a", "e f", "f g f g" , "g c d"])) + * @example + * sound("<0 1 [2,0]>".pick(["bd sd", "cp cp", "hh hh"])) + * @example + * sound("<0!2 [0,1] 1>".pick(["bd(3,8)", "sd sd"])) + * @example + * s("".pick({a: "bd(3,8)", b: "sd sd"})) + */ + +export const pick = register('pick', function (lookup, pat) { + return _pick(lookup, pat, false).innerJoin(); +}); + +/** * The same as `pick`, but if you pick a number greater than the size of the list, + * it wraps around, rather than sticking at the maximum value. + * For example, if you pick the fifth pattern of a list of three, you'll get the + * second one. + * @param {Pattern} pat + * @param {*} xs + * @returns {Pattern} + */ + +export const pickmod = register('pickmod', function (lookup, pat) { + return _pick(lookup, pat, true).innerJoin(); +}); + /** - * pick from the list of values (or patterns of values) via the index using the given - * pattern of integers +/** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name). + * Similar to `pick`, but cycles are squeezed into the target ('inhabited') pattern. * @param {Pattern} pat * @param {*} xs * @returns {Pattern} * @example - * note(pick("<0 1 [2!2] 3>", ["g a", "e f", "f g f g" , "g a c d"])) + * "".inhabit({a: s("bd(3,8)"), + b: s("cp sd") + }) + * @example + * s("a@2 [a b] a".inhabit({a: "bd(3,8)", b: "sd sd"})).slow(4) */ +export const inhabit = register('inhabit', function (lookup, pat) { + return _pick(lookup, pat, true).squeezeJoin(); +}); -export const pick = (pat, xs) => { - xs = xs.map(reify); - if (xs.length == 0) { - return silence; - } - return pat - .fmap((i) => { - const key = clamp(Math.round(i), 0, xs.length - 1); - return xs[key]; - }) - .innerJoin(); -}; +/** * The same as `inhabit`, but if you pick a number greater than the size of the list, + * it wraps around, rather than sticking at the maximum value. + * For example, if you pick the fifth pattern of a list of three, you'll get the + * second one. + * @param {Pattern} pat + * @param {*} xs + * @returns {Pattern} + */ + +export const inhabitmod = register('inhabit', function (lookup, pat) { + return _pick(lookup, pat, false).squeezeJoin(); +}); /** - * pick from the list of values (or patterns of values) via the index using the given + * Pick from the list of values (or patterns of values) via the index using the given * pattern of integers. The selected pattern will be compressed to fit the duration of the selecting event * @param {Pattern} pat * @param {*} xs @@ -356,7 +413,7 @@ export const degradeBy = register('degradeBy', function (x, pat) { export const degrade = register('degrade', (pat) => pat._degradeBy(0.5)); /** - * Inverse of {@link Pattern#degradeBy}: Randomly removes events from the pattern by a given amount. + * Inverse of `degradeBy`: Randomly removes events from the pattern by a given amount. * 0 = 100% chance of removal * 1 = 0% chance of removal * Events that would be removed by degradeBy are let through by undegradeBy and vice versa (see second example). @@ -380,7 +437,7 @@ export const undegrade = register('undegrade', (pat) => pat._undegradeBy(0.5)); /** * * Randomly applies the given function by the given probability. - * Similar to {@link Pattern#someCyclesBy} + * Similar to `someCyclesBy` * * @name sometimesBy * @memberof Pattern @@ -415,7 +472,7 @@ export const sometimes = register('sometimes', function (func, pat) { /** * * Randomly applies the given function by the given probability on a cycle by cycle basis. - * Similar to {@link Pattern#sometimesBy} + * Similar to `sometimesBy` * * @name someCyclesBy * @memberof Pattern diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index 928bfcef3..d9da114d5 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -1057,4 +1057,55 @@ describe('Pattern', () => { expect(slowcat(0, 1).repeatCycles(2).fast(6).firstCycleValues).toStrictEqual([0, 0, 1, 1, 0, 0]); }); }); + describe('inhabit', () => { + it('Can pattern named patterns', () => { + expect( + sameFirst( + sequence('a', 'b', stack('a', 'b')).inhabit({ a: sequence(1, 2), b: sequence(10, 20, 30) }), + sequence([1, 2], [10, 20, 30], stack([1, 2], [10, 20, 30])), + ), + ); + }); + it('Can pattern indexed patterns', () => { + expect( + sameFirst( + sequence('0', '1', stack('0', '1')).inhabit([sequence(1, 2), sequence(10, 20, 30)]), + sequence([1, 2], [10, 20, 30], stack([1, 2], [10, 20, 30])), + ), + ); + }); + }); + describe('pick', () => { + it('Can pattern named patterns', () => { + expect( + sameFirst( + sequence('a', 'b', 'a', stack('a', 'b')).pick({ a: sequence(1, 2, 3, 4), b: sequence(10, 20, 30, 40) }), + sequence(1, 20, 3, stack(4, 40)), + ), + ); + }); + it('Can pattern indexed patterns', () => { + expect( + sameFirst( + sequence(0, 1, 0, stack(0, 1)).pick([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]), + sequence(1, 20, 3, stack(4, 40)), + ), + ); + }); + it('Clamps indexes', () => { + expect( + sameFirst(sequence(0, 1, 2, 3).pick([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]), sequence(1, 20, 30, 40)), + ); + }); + }); + describe('pickmod', () => { + it('Wraps indexes', () => { + expect( + sameFirst( + sequence(0, 1, 2, 3).pickmod([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]), + sequence(1, 20, 3, 40), + ), + ); + }); + }); }); diff --git a/packages/core/util.mjs b/packages/core/util.mjs index ef55de95d..ca3cfc123 100644 --- a/packages/core/util.mjs +++ b/packages/core/util.mjs @@ -316,3 +316,10 @@ export function hash2code(hash) { return base64ToUnicode(decodeURIComponent(hash)); //return atob(decodeURIComponent(codeParam || '')); } + +export function objectMap(obj, fn) { + if (Array.isArray(obj)) { + return obj.map(fn); + } + return Object.fromEntries(Object.entries(obj).map(([k, v], i) => [k, fn(v, k, i)])); +} diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 002ccb5fc..b3114ed5f 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2408,6 +2408,40 @@ exports[`runs examples > example "hush" example index 0 1`] = ` ] `; +exports[`runs examples > example "inhabit" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | s:bd ]", + "[ 3/8 → 1/2 | s:bd ]", + "[ 3/4 → 7/8 | s:bd ]", + "[ 1/1 → 3/2 | s:cp ]", + "[ 3/2 → 2/1 | s:sd ]", + "[ 2/1 → 17/8 | s:bd ]", + "[ 2/1 → 5/2 | s:cp ]", + "[ 19/8 → 5/2 | s:bd ]", + "[ 5/2 → 3/1 | s:sd ]", + "[ 11/4 → 23/8 | s:bd ]", + "[ 3/1 → 25/8 | s:bd ]", + "[ 27/8 → 7/2 | s:bd ]", + "[ 15/4 → 31/8 | s:bd ]", +] +`; + +exports[`runs examples > example "inhabit" example index 1 1`] = ` +[ + "[ 0/1 → 1/4 | s:bd ]", + "[ 3/4 → 1/1 | s:bd ]", + "[ 3/2 → 7/4 | s:bd ]", + "[ 2/1 → 33/16 | s:bd ]", + "[ 35/16 → 9/4 | s:bd ]", + "[ 19/8 → 39/16 | s:bd ]", + "[ 5/2 → 11/4 | s:sd ]", + "[ 11/4 → 3/1 | s:sd ]", + "[ 3/1 → 25/8 | s:bd ]", + "[ 27/8 → 7/2 | s:bd ]", + "[ 15/4 → 31/8 | s:bd ]", +] +`; + exports[`runs examples > example "inside" example index 0 1`] = ` [ "[ 0/1 → 1/8 | note:D3 ]", @@ -3601,10 +3635,61 @@ exports[`runs examples > example "pick" example index 0 1`] = ` "[ 9/4 → 5/2 | note:g ]", "[ 5/2 → 11/4 | note:f ]", "[ 11/4 → 3/1 | note:g ]", - "[ 3/1 → 13/4 | note:g ]", - "[ 13/4 → 7/2 | note:a ]", - "[ 7/2 → 15/4 | note:c ]", - "[ 15/4 → 4/1 | note:d ]", + "[ 3/1 → 13/4 | note:f ]", + "[ 13/4 → 7/2 | note:g ]", + "[ 7/2 → 15/4 | note:f ]", + "[ 15/4 → 4/1 | note:g ]", +] +`; + +exports[`runs examples > example "pick" example index 1 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd ]", + "[ 1/2 → 1/1 | s:sd ]", + "[ 1/1 → 3/2 | s:cp ]", + "[ 3/2 → 2/1 | s:cp ]", + "[ 2/1 → 5/2 | s:hh ]", + "[ 2/1 → 5/2 | s:bd ]", + "[ 5/2 → 3/1 | s:hh ]", + "[ 5/2 → 3/1 | s:sd ]", + "[ 3/1 → 7/2 | s:bd ]", + "[ 7/2 → 4/1 | s:sd ]", +] +`; + +exports[`runs examples > example "pick" example index 2 1`] = ` +[ + "[ 0/1 → 1/8 | s:bd ]", + "[ 3/8 → 1/2 | s:bd ]", + "[ 3/4 → 7/8 | s:bd ]", + "[ 1/1 → 9/8 | s:bd ]", + "[ 11/8 → 3/2 | s:bd ]", + "[ 7/4 → 15/8 | s:bd ]", + "[ 2/1 → 17/8 | s:bd ]", + "[ 2/1 → 5/2 | s:sd ]", + "[ 19/8 → 5/2 | s:bd ]", + "[ 5/2 → 3/1 | s:sd ]", + "[ 11/4 → 23/8 | s:bd ]", + "[ 3/1 → 7/2 | s:sd ]", + "[ 7/2 → 4/1 | s:sd ]", +] +`; + +exports[`runs examples > example "pick" example index 3 1`] = ` +[ + "[ 0/1 → 1/8 | s:bd ]", + "[ 3/8 → 1/2 | s:bd ]", + "[ 3/4 → 7/8 | s:bd ]", + "[ 1/1 → 9/8 | s:bd ]", + "[ 11/8 → 3/2 | s:bd ]", + "[ 7/4 → 15/8 | s:bd ]", + "[ 2/1 → 17/8 | s:bd ]", + "[ 2/1 → 5/2 | s:sd ]", + "[ 19/8 → 5/2 | s:bd ]", + "[ 5/2 → 3/1 | s:sd ]", + "[ 11/4 → 23/8 | s:bd ]", + "[ 3/1 → 7/2 | s:sd ]", + "[ 7/2 → 4/1 | s:sd ]", ] `; From a8db70744053264274fedc6663bad15d440432d3 Mon Sep 17 00:00:00 2001 From: Alex McLean Date: Thu, 18 Jan 2024 17:04:26 +0000 Subject: [PATCH 91/93] Revert "`pick` now accepts lookup tables, with alternate cycle squeezing behaviour as new `inhabit` function" (#920) --- packages/core/controls.mjs | 10 +-- packages/core/pattern.mjs | 36 ++++----- packages/core/signal.mjs | 97 +++++------------------ packages/core/test/pattern.test.mjs | 51 ------------ packages/core/util.mjs | 7 -- test/__snapshots__/examples.test.mjs.snap | 93 +--------------------- 6 files changed, 47 insertions(+), 247 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 42212dd3b..444b4ea17 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -97,7 +97,7 @@ const generic_params = [ */ ['postgain'], /** - * Like `gain`, but linear. + * Like {@link gain}, but linear. * * @name amp * @param {number | Pattern} amount gain. @@ -856,7 +856,7 @@ const generic_params = [ */ ['detune', 'det'], /** - * Set dryness of reverb. See `room` and `size` for more information about reverb. + * 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 @@ -868,7 +868,7 @@ const generic_params = [ ['dry'], // TODO: does not seem to do anything /* - * Used when using `begin`/`end` or `chop`/`striate` and friends, to change the fade out time of the 'grain' envelope. + * 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 @@ -1191,7 +1191,7 @@ const generic_params = [ */ [['ir', 'i'], 'iresponse'], /** - * Sets the room size of the reverb, see `room`. + * 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 @@ -1249,7 +1249,7 @@ const generic_params = [ */ ['speed'], /** - * Used in conjunction with `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`. + * 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 diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 6a7b210be..9e804b236 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -26,7 +26,7 @@ export class Pattern { /** * Create a pattern. As an end user, you will most likely not create a Pattern directly. * - * @param {function} query - The function that maps a `State` to an array of `Hap`. + * @param {function} query - The function that maps a {@link State} to an array of {@link Hap}. * @noAutocomplete */ constructor(query) { @@ -39,7 +39,7 @@ export class Pattern { /** * Returns a new pattern, with the function applied to the value of - * each hap. It has the alias `fmap`. + * each hap. It has the alias {@link Pattern#fmap}. * @synonyms fmap * @param {Function} func to to apply to the value * @returns Pattern @@ -51,7 +51,7 @@ export class Pattern { } /** - * see `withValue` + * see {@link Pattern#withValue} * @noAutocomplete */ fmap(func) { @@ -115,7 +115,7 @@ export class Pattern { } /** - * As with `appBoth`, but the `whole` timespan is not the intersection, + * As with {@link Pattern#appBoth}, but the `whole` timespan is not the intersection, * but the timespan from the function of patterns that this method is called * on. In practice, this means that the pattern structure, including onsets, * are preserved from the pattern of functions (often referred to as the left @@ -148,7 +148,7 @@ export class Pattern { } /** - * As with `appLeft`, but `whole` timespans are instead taken from the + * As with {@link Pattern#appLeft}, but `whole` timespans are instead taken from the * pattern of values, i.e. structure is preserved from the right hand/outer * pattern. * @param {Pattern} pat_val @@ -387,7 +387,7 @@ export class Pattern { } /** - * As with `withQuerySpan`, but the function is applied to both the + * As with {@link Pattern#withQuerySpan}, but the function is applied to both the * begin and end time of the query timespan. * @param {Function} func the function to apply * @returns Pattern @@ -398,7 +398,7 @@ export class Pattern { } /** - * Similar to `withQuerySpan`, but the function is applied to the timespans + * Similar to {@link Pattern#withQuerySpan}, but the function is applied to the timespans * of all haps returned by pattern queries (both `part` timespans, and where * present, `whole` timespans). * @param {Function} func @@ -410,7 +410,7 @@ export class Pattern { } /** - * As with `withHapSpan`, but the function is applied to both the + * As with {@link Pattern#withHapSpan}, but the function is applied to both the * begin and end time of the hap timespans. * @param {Function} func the function to apply * @returns Pattern @@ -431,7 +431,7 @@ export class Pattern { } /** - * As with `withHaps`, but applies the function to every hap, rather than every list of haps. + * As with {@link Pattern#withHaps}, but applies the function to every hap, rather than every list of haps. * @param {Function} func * @returns Pattern * @noAutocomplete @@ -499,7 +499,7 @@ export class Pattern { } /** - * As with `filterHaps`, but the function is applied to values + * As with {@link Pattern#filterHaps}, but the function is applied to values * inside haps. * @param {Function} value_test * @returns Pattern @@ -621,7 +621,7 @@ export class Pattern { } /** - * More human-readable version of the `firstCycleValues` accessor. + * More human-readable version of the {@link Pattern#firstCycleValues} accessor. * @noAutocomplete */ get showFirstCycle() { @@ -691,7 +691,7 @@ export class Pattern { // Methods without corresponding toplevel functions /** - * Layers the result of the given function(s). Like `superimpose`, but without the original pattern: + * Layers the result of the given function(s). Like {@link Pattern.superimpose}, but without the original pattern: * @name layer * @memberof Pattern * @synonyms apply @@ -1189,7 +1189,7 @@ export function stack(...pats) { /** Concatenation: combines a list of patterns, switching between them successively, one per cycle: * - * synonyms: `cat` + * synonyms: {@link cat} * * @return {Pattern} * @example @@ -1244,7 +1244,7 @@ export function cat(...pats) { return slowcat(...pats); } -/** Like `seq`, but each step has a length, relative to the whole. +/** Like {@link Pattern.seq}, but each step has a length, relative to the whole. * @return {Pattern} * @example * timeCat([3,"e3"],[1, "g3"]).note() // "e3@3 g3".note() @@ -1279,7 +1279,7 @@ export function fastcat(...pats) { return slowcat(...pats)._fast(pats.length); } -/** See `fastcat` */ +/** See {@link fastcat} */ export function sequence(...pats) { return fastcat(...pats); } @@ -1636,7 +1636,7 @@ export const { fastGap, fastgap } = register(['fastGap', 'fastgap'], function (f }); /** - * Similar to `compress`, but doesn't leave gaps, and the 'focus' can be bigger than a cycle + * Similar to compress, but doesn't leave gaps, and the 'focus' can be bigger than a cycle * @example * s("bd hh sd hh").focus(1/4, 3/4) */ @@ -1753,7 +1753,7 @@ export const lastOf = register('lastOf', function (n, func, pat) { */ /** - * An alias for `firstOf` + * An alias for {@link firstOf} * @name every * @memberof Pattern * @param {number} n how many cycles @@ -2365,7 +2365,7 @@ export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (facto // 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`. + * Similar to loopAt. * @name fit * @example * samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' }) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 9e8db9a01..1446beebd 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th import { Hap } from './hap.mjs'; import { Pattern, fastcat, reify, silence, stack, register } from './pattern.mjs'; import Fraction from './fraction.mjs'; -import { id, _mod, clamp, objectMap } from './util.mjs'; +import { id, _mod, clamp } from './util.mjs'; export function steady(value) { // A continuous value @@ -156,88 +156,31 @@ export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i)); */ export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin(); -const _pick = function (lookup, pat, modulo = true) { - const array = Array.isArray(lookup); - const len = Object.keys(lookup).length; - - lookup = objectMap(lookup, reify); - - if (len === 0) { - return silence; - } - return pat.fmap((i) => { - let key = i; - if (array) { - key = modulo ? Math.round(key) % len : clamp(Math.round(key), 0, lookup.length - 1); - } - return lookup[key]; - }); -}; - -/** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name). - * Similar to `inhabit`, but maintains the structure of the original patterns. - * @param {Pattern} pat - * @param {*} xs - * @returns {Pattern} - * @example - * note("<0 1 2!2 3>".pick(["g a", "e f", "f g f g" , "g c d"])) - * @example - * sound("<0 1 [2,0]>".pick(["bd sd", "cp cp", "hh hh"])) - * @example - * sound("<0!2 [0,1] 1>".pick(["bd(3,8)", "sd sd"])) - * @example - * s("".pick({a: "bd(3,8)", b: "sd sd"})) - */ - -export const pick = register('pick', function (lookup, pat) { - return _pick(lookup, pat, false).innerJoin(); -}); - -/** * The same as `pick`, but if you pick a number greater than the size of the list, - * it wraps around, rather than sticking at the maximum value. - * For example, if you pick the fifth pattern of a list of three, you'll get the - * second one. - * @param {Pattern} pat - * @param {*} xs - * @returns {Pattern} - */ - -export const pickmod = register('pickmod', function (lookup, pat) { - return _pick(lookup, pat, true).innerJoin(); -}); - /** -/** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name). - * Similar to `pick`, but cycles are squeezed into the target ('inhabited') pattern. + * pick from the list of values (or patterns of values) via the index using the given + * pattern of integers * @param {Pattern} pat * @param {*} xs * @returns {Pattern} * @example - * "".inhabit({a: s("bd(3,8)"), - b: s("cp sd") - }) - * @example - * s("a@2 [a b] a".inhabit({a: "bd(3,8)", b: "sd sd"})).slow(4) + * note(pick("<0 1 [2!2] 3>", ["g a", "e f", "f g f g" , "g a c d"])) */ -export const inhabit = register('inhabit', function (lookup, pat) { - return _pick(lookup, pat, true).squeezeJoin(); -}); -/** * The same as `inhabit`, but if you pick a number greater than the size of the list, - * it wraps around, rather than sticking at the maximum value. - * For example, if you pick the fifth pattern of a list of three, you'll get the - * second one. - * @param {Pattern} pat - * @param {*} xs - * @returns {Pattern} - */ - -export const inhabitmod = register('inhabit', function (lookup, pat) { - return _pick(lookup, pat, false).squeezeJoin(); -}); +export const pick = (pat, xs) => { + xs = xs.map(reify); + if (xs.length == 0) { + return silence; + } + return pat + .fmap((i) => { + const key = clamp(Math.round(i), 0, xs.length - 1); + return xs[key]; + }) + .innerJoin(); +}; /** - * Pick from the list of values (or patterns of values) via the index using the given + * pick from the list of values (or patterns of values) via the index using the given * pattern of integers. The selected pattern will be compressed to fit the duration of the selecting event * @param {Pattern} pat * @param {*} xs @@ -413,7 +356,7 @@ export const degradeBy = register('degradeBy', function (x, pat) { export const degrade = register('degrade', (pat) => pat._degradeBy(0.5)); /** - * Inverse of `degradeBy`: Randomly removes events from the pattern by a given amount. + * Inverse of {@link Pattern#degradeBy}: Randomly removes events from the pattern by a given amount. * 0 = 100% chance of removal * 1 = 0% chance of removal * Events that would be removed by degradeBy are let through by undegradeBy and vice versa (see second example). @@ -437,7 +380,7 @@ export const undegrade = register('undegrade', (pat) => pat._undegradeBy(0.5)); /** * * Randomly applies the given function by the given probability. - * Similar to `someCyclesBy` + * Similar to {@link Pattern#someCyclesBy} * * @name sometimesBy * @memberof Pattern @@ -472,7 +415,7 @@ export const sometimes = register('sometimes', function (func, pat) { /** * * Randomly applies the given function by the given probability on a cycle by cycle basis. - * Similar to `sometimesBy` + * Similar to {@link Pattern#sometimesBy} * * @name someCyclesBy * @memberof Pattern diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index d9da114d5..928bfcef3 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -1057,55 +1057,4 @@ describe('Pattern', () => { expect(slowcat(0, 1).repeatCycles(2).fast(6).firstCycleValues).toStrictEqual([0, 0, 1, 1, 0, 0]); }); }); - describe('inhabit', () => { - it('Can pattern named patterns', () => { - expect( - sameFirst( - sequence('a', 'b', stack('a', 'b')).inhabit({ a: sequence(1, 2), b: sequence(10, 20, 30) }), - sequence([1, 2], [10, 20, 30], stack([1, 2], [10, 20, 30])), - ), - ); - }); - it('Can pattern indexed patterns', () => { - expect( - sameFirst( - sequence('0', '1', stack('0', '1')).inhabit([sequence(1, 2), sequence(10, 20, 30)]), - sequence([1, 2], [10, 20, 30], stack([1, 2], [10, 20, 30])), - ), - ); - }); - }); - describe('pick', () => { - it('Can pattern named patterns', () => { - expect( - sameFirst( - sequence('a', 'b', 'a', stack('a', 'b')).pick({ a: sequence(1, 2, 3, 4), b: sequence(10, 20, 30, 40) }), - sequence(1, 20, 3, stack(4, 40)), - ), - ); - }); - it('Can pattern indexed patterns', () => { - expect( - sameFirst( - sequence(0, 1, 0, stack(0, 1)).pick([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]), - sequence(1, 20, 3, stack(4, 40)), - ), - ); - }); - it('Clamps indexes', () => { - expect( - sameFirst(sequence(0, 1, 2, 3).pick([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]), sequence(1, 20, 30, 40)), - ); - }); - }); - describe('pickmod', () => { - it('Wraps indexes', () => { - expect( - sameFirst( - sequence(0, 1, 2, 3).pickmod([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]), - sequence(1, 20, 3, 40), - ), - ); - }); - }); }); diff --git a/packages/core/util.mjs b/packages/core/util.mjs index ca3cfc123..ef55de95d 100644 --- a/packages/core/util.mjs +++ b/packages/core/util.mjs @@ -316,10 +316,3 @@ export function hash2code(hash) { return base64ToUnicode(decodeURIComponent(hash)); //return atob(decodeURIComponent(codeParam || '')); } - -export function objectMap(obj, fn) { - if (Array.isArray(obj)) { - return obj.map(fn); - } - return Object.fromEntries(Object.entries(obj).map(([k, v], i) => [k, fn(v, k, i)])); -} diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index b3114ed5f..002ccb5fc 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2408,40 +2408,6 @@ exports[`runs examples > example "hush" example index 0 1`] = ` ] `; -exports[`runs examples > example "inhabit" example index 0 1`] = ` -[ - "[ 0/1 → 1/8 | s:bd ]", - "[ 3/8 → 1/2 | s:bd ]", - "[ 3/4 → 7/8 | s:bd ]", - "[ 1/1 → 3/2 | s:cp ]", - "[ 3/2 → 2/1 | s:sd ]", - "[ 2/1 → 17/8 | s:bd ]", - "[ 2/1 → 5/2 | s:cp ]", - "[ 19/8 → 5/2 | s:bd ]", - "[ 5/2 → 3/1 | s:sd ]", - "[ 11/4 → 23/8 | s:bd ]", - "[ 3/1 → 25/8 | s:bd ]", - "[ 27/8 → 7/2 | s:bd ]", - "[ 15/4 → 31/8 | s:bd ]", -] -`; - -exports[`runs examples > example "inhabit" example index 1 1`] = ` -[ - "[ 0/1 → 1/4 | s:bd ]", - "[ 3/4 → 1/1 | s:bd ]", - "[ 3/2 → 7/4 | s:bd ]", - "[ 2/1 → 33/16 | s:bd ]", - "[ 35/16 → 9/4 | s:bd ]", - "[ 19/8 → 39/16 | s:bd ]", - "[ 5/2 → 11/4 | s:sd ]", - "[ 11/4 → 3/1 | s:sd ]", - "[ 3/1 → 25/8 | s:bd ]", - "[ 27/8 → 7/2 | s:bd ]", - "[ 15/4 → 31/8 | s:bd ]", -] -`; - exports[`runs examples > example "inside" example index 0 1`] = ` [ "[ 0/1 → 1/8 | note:D3 ]", @@ -3635,61 +3601,10 @@ exports[`runs examples > example "pick" example index 0 1`] = ` "[ 9/4 → 5/2 | note:g ]", "[ 5/2 → 11/4 | note:f ]", "[ 11/4 → 3/1 | note:g ]", - "[ 3/1 → 13/4 | note:f ]", - "[ 13/4 → 7/2 | note:g ]", - "[ 7/2 → 15/4 | note:f ]", - "[ 15/4 → 4/1 | note:g ]", -] -`; - -exports[`runs examples > example "pick" example index 1 1`] = ` -[ - "[ 0/1 → 1/2 | s:bd ]", - "[ 1/2 → 1/1 | s:sd ]", - "[ 1/1 → 3/2 | s:cp ]", - "[ 3/2 → 2/1 | s:cp ]", - "[ 2/1 → 5/2 | s:hh ]", - "[ 2/1 → 5/2 | s:bd ]", - "[ 5/2 → 3/1 | s:hh ]", - "[ 5/2 → 3/1 | s:sd ]", - "[ 3/1 → 7/2 | s:bd ]", - "[ 7/2 → 4/1 | s:sd ]", -] -`; - -exports[`runs examples > example "pick" example index 2 1`] = ` -[ - "[ 0/1 → 1/8 | s:bd ]", - "[ 3/8 → 1/2 | s:bd ]", - "[ 3/4 → 7/8 | s:bd ]", - "[ 1/1 → 9/8 | s:bd ]", - "[ 11/8 → 3/2 | s:bd ]", - "[ 7/4 → 15/8 | s:bd ]", - "[ 2/1 → 17/8 | s:bd ]", - "[ 2/1 → 5/2 | s:sd ]", - "[ 19/8 → 5/2 | s:bd ]", - "[ 5/2 → 3/1 | s:sd ]", - "[ 11/4 → 23/8 | s:bd ]", - "[ 3/1 → 7/2 | s:sd ]", - "[ 7/2 → 4/1 | s:sd ]", -] -`; - -exports[`runs examples > example "pick" example index 3 1`] = ` -[ - "[ 0/1 → 1/8 | s:bd ]", - "[ 3/8 → 1/2 | s:bd ]", - "[ 3/4 → 7/8 | s:bd ]", - "[ 1/1 → 9/8 | s:bd ]", - "[ 11/8 → 3/2 | s:bd ]", - "[ 7/4 → 15/8 | s:bd ]", - "[ 2/1 → 17/8 | s:bd ]", - "[ 2/1 → 5/2 | s:sd ]", - "[ 19/8 → 5/2 | s:bd ]", - "[ 5/2 → 3/1 | s:sd ]", - "[ 11/4 → 23/8 | s:bd ]", - "[ 3/1 → 7/2 | s:sd ]", - "[ 7/2 → 4/1 | s:sd ]", + "[ 3/1 → 13/4 | note:g ]", + "[ 13/4 → 7/2 | note:a ]", + "[ 7/2 → 15/4 | note:c ]", + "[ 15/4 → 4/1 | note:d ]", ] `; From 98b785960544b4695905d6472a5fb6d7cefdfdf4 Mon Sep 17 00:00:00 2001 From: Alex McLean Date: Thu, 18 Jan 2024 17:08:29 +0000 Subject: [PATCH 92/93] pick, pickmod, inhabit, inhabitmod (#921) * the args for `pick` are now reversed as standard (old behaviour still supported to avoid breaking change) * `pick` is also now a pattern method * `pick` now also accepts a lookup table for pick-by-name as an alternative to pick-by-index from a list * `inhabit` added with same behaviour as `pick`, except cycles from source patterns are squeezed into events of inhabited patterns * Also some general doc tidying, sorry for the noise.. * There is also `pickmod` and `inhabitmod`, for wrapping indexes around rather than clamping them --- packages/core/controls.mjs | 10 +-- packages/core/pattern.mjs | 36 ++++---- packages/core/signal.mjs | 103 ++++++++++++++++++---- packages/core/test/pattern.test.mjs | 60 +++++++++++++ packages/core/util.mjs | 7 ++ test/__snapshots__/examples.test.mjs.snap | 93 ++++++++++++++++++- 6 files changed, 263 insertions(+), 46 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 444b4ea17..42212dd3b 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -97,7 +97,7 @@ const generic_params = [ */ ['postgain'], /** - * Like {@link gain}, but linear. + * Like `gain`, but linear. * * @name amp * @param {number | Pattern} amount gain. @@ -856,7 +856,7 @@ const generic_params = [ */ ['detune', 'det'], /** - * Set dryness of reverb. See {@link room} and {@link size} for more information about reverb. + * Set dryness of reverb. See `room` and `size` for more information about reverb. * * @name dry * @param {number | Pattern} dry 0 = wet, 1 = dry @@ -868,7 +868,7 @@ const generic_params = [ ['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. + * Used when using `begin`/`end` or `chop`/`striate` and friends, to change the fade out time of the 'grain' envelope. * * @name fadeTime * @param {number | Pattern} time between 0 and 1 @@ -1191,7 +1191,7 @@ const generic_params = [ */ [['ir', 'i'], 'iresponse'], /** - * Sets the room size of the reverb, see {@link room}. + * Sets the room size of the reverb, see `room`. * When this property is changed, the reverb will be recaculated, so only change this sparsely.. * * @name roomsize @@ -1249,7 +1249,7 @@ const generic_params = [ */ ['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`. + * Used in conjunction with `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 diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 9e804b236..6a7b210be 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -26,7 +26,7 @@ export class Pattern { /** * Create a pattern. As an end user, you will most likely not create a Pattern directly. * - * @param {function} query - The function that maps a {@link State} to an array of {@link Hap}. + * @param {function} query - The function that maps a `State` to an array of `Hap`. * @noAutocomplete */ constructor(query) { @@ -39,7 +39,7 @@ export class Pattern { /** * Returns a new pattern, with the function applied to the value of - * each hap. It has the alias {@link Pattern#fmap}. + * each hap. It has the alias `fmap`. * @synonyms fmap * @param {Function} func to to apply to the value * @returns Pattern @@ -51,7 +51,7 @@ export class Pattern { } /** - * see {@link Pattern#withValue} + * see `withValue` * @noAutocomplete */ fmap(func) { @@ -115,7 +115,7 @@ export class Pattern { } /** - * As with {@link Pattern#appBoth}, but the `whole` timespan is not the intersection, + * As with `appBoth`, but the `whole` timespan is not the intersection, * but the timespan from the function of patterns that this method is called * on. In practice, this means that the pattern structure, including onsets, * are preserved from the pattern of functions (often referred to as the left @@ -148,7 +148,7 @@ export class Pattern { } /** - * As with {@link Pattern#appLeft}, but `whole` timespans are instead taken from the + * As with `appLeft`, but `whole` timespans are instead taken from the * pattern of values, i.e. structure is preserved from the right hand/outer * pattern. * @param {Pattern} pat_val @@ -387,7 +387,7 @@ export class Pattern { } /** - * As with {@link Pattern#withQuerySpan}, but the function is applied to both the + * As with `withQuerySpan`, but the function is applied to both the * begin and end time of the query timespan. * @param {Function} func the function to apply * @returns Pattern @@ -398,7 +398,7 @@ export class Pattern { } /** - * Similar to {@link Pattern#withQuerySpan}, but the function is applied to the timespans + * Similar to `withQuerySpan`, but the function is applied to the timespans * of all haps returned by pattern queries (both `part` timespans, and where * present, `whole` timespans). * @param {Function} func @@ -410,7 +410,7 @@ export class Pattern { } /** - * As with {@link Pattern#withHapSpan}, but the function is applied to both the + * As with `withHapSpan`, but the function is applied to both the * begin and end time of the hap timespans. * @param {Function} func the function to apply * @returns Pattern @@ -431,7 +431,7 @@ export class Pattern { } /** - * As with {@link Pattern#withHaps}, but applies the function to every hap, rather than every list of haps. + * As with `withHaps`, but applies the function to every hap, rather than every list of haps. * @param {Function} func * @returns Pattern * @noAutocomplete @@ -499,7 +499,7 @@ export class Pattern { } /** - * As with {@link Pattern#filterHaps}, but the function is applied to values + * As with `filterHaps`, but the function is applied to values * inside haps. * @param {Function} value_test * @returns Pattern @@ -621,7 +621,7 @@ export class Pattern { } /** - * More human-readable version of the {@link Pattern#firstCycleValues} accessor. + * More human-readable version of the `firstCycleValues` accessor. * @noAutocomplete */ get showFirstCycle() { @@ -691,7 +691,7 @@ export class Pattern { // Methods without corresponding toplevel functions /** - * Layers the result of the given function(s). Like {@link Pattern.superimpose}, but without the original pattern: + * Layers the result of the given function(s). Like `superimpose`, but without the original pattern: * @name layer * @memberof Pattern * @synonyms apply @@ -1189,7 +1189,7 @@ export function stack(...pats) { /** Concatenation: combines a list of patterns, switching between them successively, one per cycle: * - * synonyms: {@link cat} + * synonyms: `cat` * * @return {Pattern} * @example @@ -1244,7 +1244,7 @@ export function cat(...pats) { return slowcat(...pats); } -/** Like {@link Pattern.seq}, but each step has a length, relative to the whole. +/** Like `seq`, but each step has a length, relative to the whole. * @return {Pattern} * @example * timeCat([3,"e3"],[1, "g3"]).note() // "e3@3 g3".note() @@ -1279,7 +1279,7 @@ export function fastcat(...pats) { return slowcat(...pats)._fast(pats.length); } -/** See {@link fastcat} */ +/** See `fastcat` */ export function sequence(...pats) { return fastcat(...pats); } @@ -1636,7 +1636,7 @@ export const { fastGap, fastgap } = register(['fastGap', 'fastgap'], function (f }); /** - * Similar to compress, but doesn't leave gaps, and the 'focus' can be bigger than a cycle + * Similar to `compress`, but doesn't leave gaps, and the 'focus' can be bigger than a cycle * @example * s("bd hh sd hh").focus(1/4, 3/4) */ @@ -1753,7 +1753,7 @@ export const lastOf = register('lastOf', function (n, func, pat) { */ /** - * An alias for {@link firstOf} + * An alias for `firstOf` * @name every * @memberof Pattern * @param {number} n how many cycles @@ -2365,7 +2365,7 @@ export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (facto // 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. + * Similar to `loopAt`. * @name fit * @example * samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' }) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 1446beebd..253458ceb 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th import { Hap } from './hap.mjs'; import { Pattern, fastcat, reify, silence, stack, register } from './pattern.mjs'; import Fraction from './fraction.mjs'; -import { id, _mod, clamp } from './util.mjs'; +import { id, _mod, clamp, objectMap } from './util.mjs'; export function steady(value) { // A continuous value @@ -156,31 +156,96 @@ export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i)); */ export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin(); -/** - * pick from the list of values (or patterns of values) via the index using the given - * pattern of integers +const _pick = function (lookup, pat, modulo = true) { + const array = Array.isArray(lookup); + const len = Object.keys(lookup).length; + + lookup = objectMap(lookup, reify); + + if (len === 0) { + return silence; + } + return pat.fmap((i) => { + let key = i; + if (array) { + key = modulo ? Math.round(key) % len : clamp(Math.round(key), 0, lookup.length - 1); + } + return lookup[key]; + }); +}; + +/** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name). + * Similar to `inhabit`, but maintains the structure of the original patterns. * @param {Pattern} pat * @param {*} xs * @returns {Pattern} * @example - * note(pick("<0 1 [2!2] 3>", ["g a", "e f", "f g f g" , "g a c d"])) + * note("<0 1 2!2 3>".pick(["g a", "e f", "f g f g" , "g c d"])) + * @example + * sound("<0 1 [2,0]>".pick(["bd sd", "cp cp", "hh hh"])) + * @example + * sound("<0!2 [0,1] 1>".pick(["bd(3,8)", "sd sd"])) + * @example + * s("".pick({a: "bd(3,8)", b: "sd sd"})) */ -export const pick = (pat, xs) => { - xs = xs.map(reify); - if (xs.length == 0) { - return silence; +export const pick = function (lookup, pat) { + // backward compatibility - the args used to be flipped + if (Array.isArray(pat)) { + [pat, lookup] = [lookup, pat]; } - return pat - .fmap((i) => { - const key = clamp(Math.round(i), 0, xs.length - 1); - return xs[key]; - }) - .innerJoin(); + return __pick(lookup, pat); }; +const __pick = register('pick', function (lookup, pat) { + return _pick(lookup, pat, false).innerJoin(); +}); + +/** * The same as `pick`, but if you pick a number greater than the size of the list, + * it wraps around, rather than sticking at the maximum value. + * For example, if you pick the fifth pattern of a list of three, you'll get the + * second one. + * @param {Pattern} pat + * @param {*} xs + * @returns {Pattern} + */ + +export const pickmod = register('pickmod', function (lookup, pat) { + return _pick(lookup, pat, true).innerJoin(); +}); + +/** +/** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name). + * Similar to `pick`, but cycles are squeezed into the target ('inhabited') pattern. + * @param {Pattern} pat + * @param {*} xs + * @returns {Pattern} + * @example + * "".inhabit({a: s("bd(3,8)"), + b: s("cp sd") + }) + * @example + * s("a@2 [a b] a".inhabit({a: "bd(3,8)", b: "sd sd"})).slow(4) + */ +export const inhabit = register('inhabit', function (lookup, pat) { + return _pick(lookup, pat, true).squeezeJoin(); +}); + +/** * The same as `inhabit`, but if you pick a number greater than the size of the list, + * it wraps around, rather than sticking at the maximum value. + * For example, if you pick the fifth pattern of a list of three, you'll get the + * second one. + * @param {Pattern} pat + * @param {*} xs + * @returns {Pattern} + */ + +export const inhabitmod = register('inhabit', function (lookup, pat) { + return _pick(lookup, pat, false).squeezeJoin(); +}); + /** - * pick from the list of values (or patterns of values) via the index using the given + * Pick from the list of values (or patterns of values) via the index using the given * pattern of integers. The selected pattern will be compressed to fit the duration of the selecting event * @param {Pattern} pat * @param {*} xs @@ -356,7 +421,7 @@ export const degradeBy = register('degradeBy', function (x, pat) { export const degrade = register('degrade', (pat) => pat._degradeBy(0.5)); /** - * Inverse of {@link Pattern#degradeBy}: Randomly removes events from the pattern by a given amount. + * Inverse of `degradeBy`: Randomly removes events from the pattern by a given amount. * 0 = 100% chance of removal * 1 = 0% chance of removal * Events that would be removed by degradeBy are let through by undegradeBy and vice versa (see second example). @@ -380,7 +445,7 @@ export const undegrade = register('undegrade', (pat) => pat._undegradeBy(0.5)); /** * * Randomly applies the given function by the given probability. - * Similar to {@link Pattern#someCyclesBy} + * Similar to `someCyclesBy` * * @name sometimesBy * @memberof Pattern @@ -415,7 +480,7 @@ export const sometimes = register('sometimes', function (func, pat) { /** * * Randomly applies the given function by the given probability on a cycle by cycle basis. - * Similar to {@link Pattern#sometimesBy} + * Similar to `sometimesBy` * * @name someCyclesBy * @memberof Pattern diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index 928bfcef3..bd0aa52b0 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -46,6 +46,7 @@ import { rev, time, run, + pick, } from '../index.mjs'; import { steady } from '../signal.mjs'; @@ -1057,4 +1058,63 @@ describe('Pattern', () => { expect(slowcat(0, 1).repeatCycles(2).fast(6).firstCycleValues).toStrictEqual([0, 0, 1, 1, 0, 0]); }); }); + describe('inhabit', () => { + it('Can pattern named patterns', () => { + expect( + sameFirst( + sequence('a', 'b', stack('a', 'b')).inhabit({ a: sequence(1, 2), b: sequence(10, 20, 30) }), + sequence([1, 2], [10, 20, 30], stack([1, 2], [10, 20, 30])), + ), + ); + }); + it('Can pattern indexed patterns', () => { + expect( + sameFirst( + sequence('0', '1', stack('0', '1')).inhabit([sequence(1, 2), sequence(10, 20, 30)]), + sequence([1, 2], [10, 20, 30], stack([1, 2], [10, 20, 30])), + ), + ); + }); + }); + describe('pick', () => { + it('Can pattern named patterns', () => { + expect( + sameFirst( + sequence('a', 'b', 'a', stack('a', 'b')).pick({ a: sequence(1, 2, 3, 4), b: sequence(10, 20, 30, 40) }), + sequence(1, 20, 3, stack(4, 40)), + ), + ); + }); + it('Can pattern indexed patterns', () => { + expect( + sameFirst( + sequence(0, 1, 0, stack(0, 1)).pick([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]), + sequence(1, 20, 3, stack(4, 40)), + ), + ); + }); + it('Clamps indexes', () => { + expect( + sameFirst(sequence(0, 1, 2, 3).pick([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]), sequence(1, 20, 30, 40)), + ); + }); + it('Is backwards compatible', () => { + expect( + sameFirst( + pick([sequence('a', 'b'), sequence('c', 'd')], sequence(0, 1)), + pick(sequence(0, 1), [sequence('a', 'b'), sequence('c', 'd')]), + ), + ); + }); + }); + describe('pickmod', () => { + it('Wraps indexes', () => { + expect( + sameFirst( + sequence(0, 1, 2, 3).pickmod([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]), + sequence(1, 20, 3, 40), + ), + ); + }); + }); }); diff --git a/packages/core/util.mjs b/packages/core/util.mjs index ef55de95d..ca3cfc123 100644 --- a/packages/core/util.mjs +++ b/packages/core/util.mjs @@ -316,3 +316,10 @@ export function hash2code(hash) { return base64ToUnicode(decodeURIComponent(hash)); //return atob(decodeURIComponent(codeParam || '')); } + +export function objectMap(obj, fn) { + if (Array.isArray(obj)) { + return obj.map(fn); + } + return Object.fromEntries(Object.entries(obj).map(([k, v], i) => [k, fn(v, k, i)])); +} diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 002ccb5fc..b3114ed5f 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2408,6 +2408,40 @@ exports[`runs examples > example "hush" example index 0 1`] = ` ] `; +exports[`runs examples > example "inhabit" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | s:bd ]", + "[ 3/8 → 1/2 | s:bd ]", + "[ 3/4 → 7/8 | s:bd ]", + "[ 1/1 → 3/2 | s:cp ]", + "[ 3/2 → 2/1 | s:sd ]", + "[ 2/1 → 17/8 | s:bd ]", + "[ 2/1 → 5/2 | s:cp ]", + "[ 19/8 → 5/2 | s:bd ]", + "[ 5/2 → 3/1 | s:sd ]", + "[ 11/4 → 23/8 | s:bd ]", + "[ 3/1 → 25/8 | s:bd ]", + "[ 27/8 → 7/2 | s:bd ]", + "[ 15/4 → 31/8 | s:bd ]", +] +`; + +exports[`runs examples > example "inhabit" example index 1 1`] = ` +[ + "[ 0/1 → 1/4 | s:bd ]", + "[ 3/4 → 1/1 | s:bd ]", + "[ 3/2 → 7/4 | s:bd ]", + "[ 2/1 → 33/16 | s:bd ]", + "[ 35/16 → 9/4 | s:bd ]", + "[ 19/8 → 39/16 | s:bd ]", + "[ 5/2 → 11/4 | s:sd ]", + "[ 11/4 → 3/1 | s:sd ]", + "[ 3/1 → 25/8 | s:bd ]", + "[ 27/8 → 7/2 | s:bd ]", + "[ 15/4 → 31/8 | s:bd ]", +] +`; + exports[`runs examples > example "inside" example index 0 1`] = ` [ "[ 0/1 → 1/8 | note:D3 ]", @@ -3601,10 +3635,61 @@ exports[`runs examples > example "pick" example index 0 1`] = ` "[ 9/4 → 5/2 | note:g ]", "[ 5/2 → 11/4 | note:f ]", "[ 11/4 → 3/1 | note:g ]", - "[ 3/1 → 13/4 | note:g ]", - "[ 13/4 → 7/2 | note:a ]", - "[ 7/2 → 15/4 | note:c ]", - "[ 15/4 → 4/1 | note:d ]", + "[ 3/1 → 13/4 | note:f ]", + "[ 13/4 → 7/2 | note:g ]", + "[ 7/2 → 15/4 | note:f ]", + "[ 15/4 → 4/1 | note:g ]", +] +`; + +exports[`runs examples > example "pick" example index 1 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd ]", + "[ 1/2 → 1/1 | s:sd ]", + "[ 1/1 → 3/2 | s:cp ]", + "[ 3/2 → 2/1 | s:cp ]", + "[ 2/1 → 5/2 | s:hh ]", + "[ 2/1 → 5/2 | s:bd ]", + "[ 5/2 → 3/1 | s:hh ]", + "[ 5/2 → 3/1 | s:sd ]", + "[ 3/1 → 7/2 | s:bd ]", + "[ 7/2 → 4/1 | s:sd ]", +] +`; + +exports[`runs examples > example "pick" example index 2 1`] = ` +[ + "[ 0/1 → 1/8 | s:bd ]", + "[ 3/8 → 1/2 | s:bd ]", + "[ 3/4 → 7/8 | s:bd ]", + "[ 1/1 → 9/8 | s:bd ]", + "[ 11/8 → 3/2 | s:bd ]", + "[ 7/4 → 15/8 | s:bd ]", + "[ 2/1 → 17/8 | s:bd ]", + "[ 2/1 → 5/2 | s:sd ]", + "[ 19/8 → 5/2 | s:bd ]", + "[ 5/2 → 3/1 | s:sd ]", + "[ 11/4 → 23/8 | s:bd ]", + "[ 3/1 → 7/2 | s:sd ]", + "[ 7/2 → 4/1 | s:sd ]", +] +`; + +exports[`runs examples > example "pick" example index 3 1`] = ` +[ + "[ 0/1 → 1/8 | s:bd ]", + "[ 3/8 → 1/2 | s:bd ]", + "[ 3/4 → 7/8 | s:bd ]", + "[ 1/1 → 9/8 | s:bd ]", + "[ 11/8 → 3/2 | s:bd ]", + "[ 7/4 → 15/8 | s:bd ]", + "[ 2/1 → 17/8 | s:bd ]", + "[ 2/1 → 5/2 | s:sd ]", + "[ 19/8 → 5/2 | s:bd ]", + "[ 5/2 → 3/1 | s:sd ]", + "[ 11/4 → 23/8 | s:bd ]", + "[ 3/1 → 7/2 | s:sd ]", + "[ 7/2 → 4/1 | s:sd ]", ] `; From d8677c6261c33a7a0d2a05fbda96ea9a0b30ad57 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 18 Jan 2024 23:40:22 +0100 Subject: [PATCH 93/93] hotfix: rss links --- website/src/pages/rss.xml.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/rss.xml.js b/website/src/pages/rss.xml.js index 0aeb7bf4e..02ecd7618 100644 --- a/website/src/pages/rss.xml.js +++ b/website/src/pages/rss.xml.js @@ -9,7 +9,7 @@ export async function GET(context) { 'The Strudel Blog will keep you updated with the latest changes and things happening in the strudelsphere.', site: context.site, items: posts.map((post) => ({ - link: `/${post.slug}/`, + link: `/blog/#${post.slug}`, title: post.data.title, pubDate: post.data.date, description: post.data.description,