From 375c68775c99c9b50a4bb3e100a923c46f5fa166 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 1 Jun 2024 15:41:55 +0200 Subject: [PATCH 01/18] make sure draw logic works with multiple repls --- packages/codemirror/codemirror.mjs | 6 +++--- packages/core/evaluate.mjs | 4 ++-- packages/core/repl.mjs | 8 +++++++- packages/draw/draw.mjs | 11 ++++------- packages/draw/pianoroll.mjs | 2 +- packages/transpiler/transpiler.mjs | 3 ++- website/src/docs/MiniRepl.jsx | 2 +- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index 0a722e1d6..99c537f5b 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -154,9 +154,9 @@ export class StrudelMirror { this.prebaked = prebake(); autodraw && this.drawFirstFrame(); - this.repl = repl({ ...replOptions, + id, onToggle: (started) => { replOptions?.onToggle?.(started); if (started) { @@ -171,11 +171,11 @@ export class StrudelMirror { } else { this.drawer.stop(); updateMiniLocations(this.editor, []); - cleanupDraw(false); + cleanupDraw(false, id); } }, beforeEval: async () => { - cleanupDraw(); + cleanupDraw(true, id); this.painters = []; const self = this; // this is similar to repl.mjs > injectPatternMethods diff --git a/packages/core/evaluate.mjs b/packages/core/evaluate.mjs index ea63d8dff..23cd44c13 100644 --- a/packages/core/evaluate.mjs +++ b/packages/core/evaluate.mjs @@ -37,11 +37,11 @@ function safeEval(str, options = {}) { return Function(body)(); } -export const evaluate = async (code, transpiler) => { +export const evaluate = async (code, transpiler, transpilerOptions) => { let meta = {}; if (transpiler) { // transform syntactically correct js code to semantically usable code - const transpiled = transpiler(code); + const transpiled = transpiler(code, transpilerOptions); code = transpiled.output; meta = transpiled; } diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 5b7bcd71b..3f3f5f24e 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -19,6 +19,7 @@ export function repl({ sync = false, setInterval, clearInterval, + id, }) { const state = { schedulerError: undefined, @@ -32,6 +33,10 @@ export function repl({ started: false, }; + const transpilerOptions = { + id, + }; + const updateState = (update) => { Object.assign(state, update); state.isDirty = state.code !== state.activeCode; @@ -139,9 +144,10 @@ export function repl({ try { updateState({ code, pending: true }); await injectPatternMethods(); + setTime(() => scheduler.now()); // TODO: refactor? await beforeEval?.({ code }); shouldHush && hush(); - let { pattern, meta } = await _evaluate(code, transpiler); + let { pattern, meta } = await _evaluate(code, transpiler, transpilerOptions); if (Object.keys(pPatterns).length) { pattern = stack(...Object.values(pPatterns)); } diff --git a/packages/draw/draw.mjs b/packages/draw/draw.mjs index 81123f469..7fe6441ed 100644 --- a/packages/draw/draw.mjs +++ b/packages/draw/draw.mjs @@ -36,8 +36,8 @@ function stopAnimationFrame(id) { delete animationFrames[id]; } } -function stopAllAnimations() { - Object.keys(animationFrames).forEach((id) => stopAnimationFrame(id)); +function stopAllAnimations(replID) { + Object.keys(animationFrames).forEach((id) => (!replID || id.startsWith(replID)) && stopAnimationFrame(id)); } let memory = {}; @@ -72,13 +72,10 @@ Pattern.prototype.draw = function (fn, options) { return this; }; -export const cleanupDraw = (clearScreen = true) => { +export const cleanupDraw = (clearScreen = true, id) => { const ctx = getDrawContext(); clearScreen && ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.width); - stopAllAnimations(); - if (window.strudelScheduler) { - clearInterval(window.strudelScheduler); - } + stopAllAnimations(id); }; Pattern.prototype.onPaint = function () { diff --git a/packages/draw/pianoroll.mjs b/packages/draw/pianoroll.mjs index 247213b4c..d0480ef54 100644 --- a/packages/draw/pianoroll.mjs +++ b/packages/draw/pianoroll.mjs @@ -266,7 +266,7 @@ export function getDrawOptions(drawTime, options = {}) { let [lookbehind, lookahead] = drawTime; lookbehind = Math.abs(lookbehind); const cycles = lookahead + lookbehind; - const playhead = lookbehind / cycles; + const playhead = cycles !== 0 ? lookbehind / cycles : 0; return { fold: 1, ...options, cycles, playhead }; } diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 6cd01499a..2e566305f 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -69,6 +69,7 @@ export function transpiler(input, options = {}) { to: node.end, index, type, + id: options.id, }; emitWidgets && widgets.push(widgetConfig); return this.replace(widgetWithLocation(node, widgetConfig)); @@ -162,7 +163,7 @@ export function getWidgetID(widgetConfig) { // that means, if we use the index index of line position as id, less garbage is generated // return `widget_${widgetConfig.to}`; // more gargabe //return `widget_${widgetConfig.index}_${widgetConfig.to}`; // also more garbage - return `widget_${widgetConfig.type}_${widgetConfig.index}`; // less garbage + return `${widgetConfig.id || ''}_widget_${widgetConfig.type}_${widgetConfig.index}`; // less garbage } function widgetWithLocation(node, widgetConfig) { diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index 03e3d6d3c..f8e79a0d8 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -34,7 +34,7 @@ export function MiniRepl({ const canvasId = useMemo(() => `canvas-${id}`, [id]); const shouldDraw = !!punchcard || !!claviature; const shouldShowCanvas = !!punchcard; - const drawTime = punchcard ? [0, 4] : [0, 0]; + const drawTime = punchcard ? [0, 4] : [-2, 2]; const [activeNotes, setActiveNotes] = useState([]); const init = useCallback(({ code, shouldDraw }) => { From 0e6a17fc77a004a1a0c6038613ab097c690b1310 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 1 Jun 2024 15:42:09 +0200 Subject: [PATCH 02/18] start visual feedback article --- website/src/config.ts | 1 + website/src/pages/learn/visual-feedback.mdx | 63 +++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 website/src/pages/learn/visual-feedback.mdx diff --git a/website/src/config.ts b/website/src/config.ts index 9dee2aac2..dd003c185 100644 --- a/website/src/config.ts +++ b/website/src/config.ts @@ -78,6 +78,7 @@ export const SIDEBAR: Sidebar = { More: [ { text: 'Recipes', link: 'recipes/recipes' }, { text: 'Mini-Notation', link: 'learn/mini-notation' }, + { text: 'Visual Feedback', link: 'learn/visual-feedback' }, { text: 'Offline', link: 'learn/pwa' }, { text: 'Patterns', link: 'technical-manual/patterns' }, { text: 'Music metadata', link: 'learn/metadata' }, diff --git a/website/src/pages/learn/visual-feedback.mdx b/website/src/pages/learn/visual-feedback.mdx new file mode 100644 index 000000000..b854cd0bc --- /dev/null +++ b/website/src/pages/learn/visual-feedback.mdx @@ -0,0 +1,63 @@ +--- +title: Visual Feedback +layout: ../../layouts/MainLayout.astro +--- + +import { MiniRepl } from '../../docs/MiniRepl'; +import { JsDoc } from '../../docs/JsDoc'; + +# Visual Feedback + +There are several function that add visual feedback to your patterns. + +## Mini Notation Highlighting + +When you write mini notation with "double quotes" or \`backticks\`, the active parts of the mini notation will be highlighted: + +*8") +.scale("/4:minor:pentatonic") +.s("supersaw").lpf(300).lpenv("<4 3 2>*4")`} +/> + +You can change the color as well, even pattern it: + +*8") +.scale("/4:minor:pentatonic") +.s("supersaw").lpf(300).lpenv("<4 3 2>*4") +.color("cyan magenta")`} +/> + +## Pianoroll and Punchcard + +*8") +.scale("/4:minor:pentatonic") +.s("supersaw").lpf(300).lpenv("<4 3 2>*4") +._punchcard() +`} +/> + +*8") +.scale("/4:minor:pentatonic") +.s("supersaw").lpf(300).lpenv("<4 3 2>*4") +._pianoroll() +`} +/> + +*8") +.scale("/4:minor:pentatonic") +.s("supersaw").lpf(300).lpenv("<4 3 2>*4") +._spiral() +`} +/> + +{/* */} From 94e411aa7aadb025c64ca8d057b7b9da08a50e8c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 02:34:33 +0200 Subject: [PATCH 03/18] add beforeStart callback --- packages/core/cyclist.mjs | 20 ++++++++++++++++---- packages/core/repl.mjs | 8 +++++--- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/core/cyclist.mjs b/packages/core/cyclist.mjs index 08b893752..472e83a8b 100644 --- a/packages/core/cyclist.mjs +++ b/packages/core/cyclist.mjs @@ -8,8 +8,19 @@ import createClock from './zyklus.mjs'; import { logger } from './logger.mjs'; export class Cyclist { - constructor({ interval, onTrigger, onToggle, onError, getTime, latency = 0.1, setInterval, clearInterval }) { + constructor({ + interval, + onTrigger, + onToggle, + onError, + getTime, + latency = 0.1, + setInterval, + clearInterval, + beforeStart, + }) { this.started = false; + this.beforeStart = beforeStart; this.cps = 0.5; this.num_ticks_since_cps_change = 0; this.lastTick = 0; // absolute time when last tick (clock callback) happened @@ -82,7 +93,8 @@ export class Cyclist { this.started = v; this.onToggle?.(v); } - start() { + async start() { + await this.beforeStart?.(); this.num_ticks_since_cps_change = 0; this.num_cycles_at_cps_change = 0; if (!this.pattern) { @@ -103,10 +115,10 @@ export class Cyclist { this.lastEnd = 0; this.setStarted(false); } - setPattern(pat, autostart = false) { + async setPattern(pat, autostart = false) { this.pattern = pat; if (autostart && !this.started) { - this.start(); + await this.start(); } } setCps(cps = 0.5) { diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 3f3f5f24e..f21ab8477 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -10,6 +10,7 @@ export function repl({ defaultOutput, onEvalError, beforeEval, + beforeStart, afterEval, getTime, transpiler, @@ -53,6 +54,7 @@ export function repl({ }, setInterval, clearInterval, + beforeStart, }; // NeoCyclist uses a shared worker to communicate between instances, which is not supported on mobile chrome @@ -69,9 +71,9 @@ export function repl({ return silence; }; - const setPattern = (pattern, autostart = true) => { + const setPattern = async (pattern, autostart = true) => { pattern = editPattern?.(pattern) || pattern; - scheduler.setPattern(pattern, autostart); + await scheduler.setPattern(pattern, autostart); }; setTime(() => scheduler.now()); // TODO: refactor? @@ -159,7 +161,7 @@ export function repl({ throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.')); } logger(`[eval] code updated`); - setPattern(pattern, autostart); + await setPattern(pattern, autostart); updateState({ miniLocations: meta?.miniLocations || [], widgets: meta?.widgets || [], From faba4a4e4ec05b6303dbea1eb4f7770899637d86 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 03:00:57 +0200 Subject: [PATCH 04/18] implement onPaint with pattern state --- packages/core/pattern.mjs | 8 ++++++++ packages/draw/draw.mjs | 25 +++++++++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 03ce2e2d9..918a924b2 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -94,6 +94,14 @@ export class Pattern { return result; } + // runs func on query state + withState(func) { + return this.withHaps((haps, state) => { + func(state); + return haps; + }); + } + /** * see `withValue` * @noAutocomplete diff --git a/packages/draw/draw.mjs b/packages/draw/draw.mjs index 7fe6441ed..e37376003 100644 --- a/packages/draw/draw.mjs +++ b/packages/draw/draw.mjs @@ -74,13 +74,23 @@ Pattern.prototype.draw = function (fn, options) { export const cleanupDraw = (clearScreen = true, id) => { const ctx = getDrawContext(); - clearScreen && ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.width); + clearScreen && ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); stopAllAnimations(id); }; -Pattern.prototype.onPaint = function () { - console.warn('[draw] onPaint was not overloaded. Some drawings might not work'); - return this; +Pattern.prototype.onPaint = function (painter) { + return this.withState((state) => { + if (!state.controls.painters) { + state.controls.painters = []; + } + state.controls.painters.push(painter); + }); +}; + +Pattern.prototype.getPainters = function () { + let painters = []; + this.queryArc(0, 0, { painters }); + return painters; }; // const round = (x) => Math.round(x * 1000) / 1000; @@ -119,6 +129,7 @@ export class Drawer { this.visibleHaps = []; this.lastFrame = null; this.drawTime = drawTime; + this.painters = []; this.framer = new Framer( () => { if (!this.scheduler) { @@ -143,7 +154,7 @@ export class Drawer { // add new haps with onset (think right edge bars scrolling in) .concat(haps.filter((h) => h.hasOnset())); const time = phase - lookahead; - onDraw(this.visibleHaps, time, this); + onDraw(this.visibleHaps, time, this, this.painters); }, (err) => { console.warn('draw error', err); @@ -161,11 +172,13 @@ export class Drawer { t = t ?? scheduler.now(); this.scheduler = scheduler; let [_, lookahead] = this.drawTime; + // +0.1 = workaround for weird holes in query.. const [begin, end] = [Math.max(t, 0), t + lookahead + 0.1]; // remove all future haps this.visibleHaps = this.visibleHaps.filter((h) => h.whole.begin < t); + this.painters = []; // will get populated by .onPaint calls attached to the pattern // query future haps - const futureHaps = scheduler.pattern.queryArc(begin, end); // +0.1 = workaround for weird holes in query.. + const futureHaps = scheduler.pattern.queryArc(begin, end, { painters: this.painters }); // append future haps this.visibleHaps = this.visibleHaps.concat(futureHaps); } From bf391ad6ce4352432dd7090a3247cdc175b98114 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 03:03:36 +0200 Subject: [PATCH 05/18] simplify: painters are now handled by Drawer --- packages/codemirror/codemirror.mjs | 35 ++++++++++-------------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index 99c537f5b..9bb1df096 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -140,16 +140,15 @@ export class StrudelMirror { this.root = root; this.miniLocations = []; this.widgets = []; - this.painters = []; this.drawTime = drawTime; this.drawContext = drawContext; this.onDraw = onDraw || this.draw; this.id = id || s4(); - this.drawer = new Drawer((haps, time) => { + this.drawer = new Drawer((haps, time, _, painters) => { const currentFrame = haps.filter((hap) => hap.isActive(time)); this.highlight(currentFrame, time); - this.onDraw(haps, time, this.painters); + this.onDraw(haps, time, painters); }, drawTime); this.prebaked = prebake(); @@ -160,7 +159,6 @@ export class StrudelMirror { onToggle: (started) => { replOptions?.onToggle?.(started); if (started) { - this.adjustDrawTime(); this.drawer.start(this.repl.scheduler); // stop other repls when this one is started document.dispatchEvent( @@ -171,20 +169,11 @@ export class StrudelMirror { } else { this.drawer.stop(); updateMiniLocations(this.editor, []); - cleanupDraw(false, id); + cleanupDraw(true, id); } }, beforeEval: async () => { cleanupDraw(true, id); - this.painters = []; - const self = this; - // this is similar to repl.mjs > injectPatternMethods - // maybe there is a solution without prototype hacking, but hey, it works - // we need to do this befor every eval to make sure it works with multiple StrudelMirror's side by side - Pattern.prototype.onPaint = function (onPaint) { - self.painters.push(onPaint); - return this; - }; await this.prebaked; await replOptions?.beforeEval?.(); }, @@ -198,8 +187,11 @@ export class StrudelMirror { updateWidgets(this.editor, widgets); updateMiniLocations(this.editor, this.miniLocations); replOptions?.afterEval?.(options); - this.adjustDrawTime(); - this.drawer.invalidate(); + // if no painters are set (.onPaint was not called), then we only need the present moment (for highlighting) + const drawTime = options.pattern.getPainters().length ? this.drawTime : [0, 0]; + this.drawer.setDrawTime(drawTime); + // invalidate drawer after we've set the appropriate drawTime + this.drawer.invalidate(this.repl.scheduler); }, }); this.editor = initEditor({ @@ -234,13 +226,8 @@ export class StrudelMirror { }; document.addEventListener('start-repl', this.onStartRepl); } - // adjusts draw time depending on if there are painters - adjustDrawTime() { - // when no painters are set, [0,0] is enough (just highlighting) - this.drawer.setDrawTime(this.painters.length ? this.drawTime : [0, 0]); - } - draw(haps, time) { - this.painters?.forEach((painter) => painter(this.drawContext, time, haps, this.drawTime)); + draw(haps, time, painters) { + painters?.forEach((painter) => painter(this.drawContext, time, haps, this.drawTime)); } async drawFirstFrame() { if (!this.onDraw) { @@ -252,7 +239,7 @@ export class StrudelMirror { await this.repl.evaluate(this.code, false); this.drawer.invalidate(this.repl.scheduler, -0.001); // draw at -0.001 to avoid haps at 0 to be visualized as active - this.onDraw?.(this.drawer.visibleHaps, -0.001, this.painters); + this.onDraw?.(this.drawer.visibleHaps, -0.001, this.drawer.painters); } catch (err) { console.warn('first frame could not be painted'); } From aadb2fee84035a13aa9f566ee8a4a744bf8fbdd0 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 03:05:26 +0200 Subject: [PATCH 06/18] support onload inline viz with autodraw --- website/src/docs/MiniRepl.jsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index f8e79a0d8..37ace3d6f 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -1,7 +1,7 @@ import { useState, useRef, useCallback, useMemo, useEffect } from 'react'; import { Icon } from './Icon'; import { silence, noteToMidi, _mod } from '@strudel/core'; -import { getPunchcardPainter } from '@strudel/draw'; +import { getDrawContext, getPunchcardPainter } from '@strudel/draw'; import { transpiler } from '@strudel/transpiler'; import { getAudioContext, webaudioOutput, initAudioOnFirstClick } from '@strudel/webaudio'; import { StrudelMirror } from '@strudel/codemirror'; @@ -28,24 +28,25 @@ export function MiniRepl({ claviature, claviatureLabels, maxHeight, + autodraw, }) { const code = tunes ? tunes[0] : tune; const id = useMemo(() => s4(), []); const canvasId = useMemo(() => `canvas-${id}`, [id]); - const shouldDraw = !!punchcard || !!claviature; + autodraw = !!punchcard || !!claviature || !!autodraw; const shouldShowCanvas = !!punchcard; const drawTime = punchcard ? [0, 4] : [-2, 2]; const [activeNotes, setActiveNotes] = useState([]); - const init = useCallback(({ code, shouldDraw }) => { - const drawContext = shouldDraw ? document.querySelector('#' + canvasId)?.getContext('2d') : null; + const init = useCallback(({ code, autodraw }) => { + const drawContext = canvasId ? document.querySelector('#' + canvasId)?.getContext('2d') : getDrawContext(); const editor = new StrudelMirror({ id, defaultOutput: webaudioOutput, getTime: () => getAudioContext().currentTime, transpiler, - autodraw: !!shouldDraw, + autodraw, root: containerRef.current, initialCode: '// LOADING', pattern: silence, @@ -73,7 +74,7 @@ export function MiniRepl({ onUpdateState: (state) => { setReplState({ ...state }); }, - beforeEval: () => audioReady, // not doing this in prebake to make sure viz is drawn + beforeStart: () => audioReady, afterEval: ({ code }) => setVersionDefaultsFrom(code), }); // init settings @@ -152,7 +153,7 @@ export function MiniRepl({ ref={(el) => { if (!editorRef.current) { containerRef.current = el; - init({ code, shouldDraw }); + init({ code, autodraw }); } }} > From a7650f1af355b19f5057f051cc71f14400df121d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 03:08:16 +0200 Subject: [PATCH 07/18] add autodraw flag + scope --- website/src/pages/learn/visual-feedback.mdx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/website/src/pages/learn/visual-feedback.mdx b/website/src/pages/learn/visual-feedback.mdx index b854cd0bc..cd76ca79e 100644 --- a/website/src/pages/learn/visual-feedback.mdx +++ b/website/src/pages/learn/visual-feedback.mdx @@ -18,7 +18,7 @@ When you write mini notation with "double quotes" or \`backticks\`, the active p client:idle tune={`n("<0 2 1 3 2>*8") .scale("/4:minor:pentatonic") -.s("supersaw").lpf(300).lpenv("<4 3 2>*4")`} +.s("supersaw").lpf(300).lpenv("<4 3 2>\*4")`} /> You can change the color as well, even pattern it: @@ -40,17 +40,21 @@ You can change the color as well, even pattern it: .s("supersaw").lpf(300).lpenv("<4 3 2>*4") ._punchcard() `} + autodraw /> *8") .scale("/4:minor:pentatonic") -.s("supersaw").lpf(300).lpenv("<4 3 2>*4") -._pianoroll() +.s("supersaw").lpf(300).lpenv("<4 3 2>\*4") +.\_pianoroll() `} + autodraw /> +## Spiral + *8") @@ -60,4 +64,15 @@ You can change the color as well, even pattern it: `} /> +## Scope + +*8") +.scale("/4:minor:pentatonic") +.s("supersaw").lpf(300).lpenv("<4 3 2>*4") +._scope() +`} +/> + {/* */} From 3dc5fd0e7e328a44f79656f8d8ed99c5ade51493 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 10:48:20 +0200 Subject: [PATCH 08/18] fix: editPattern bug --- packages/core/repl.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index f21ab8477..016eca3ee 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -74,6 +74,7 @@ export function repl({ const setPattern = async (pattern, autostart = true) => { pattern = editPattern?.(pattern) || pattern; await scheduler.setPattern(pattern, autostart); + return pattern; }; setTime(() => scheduler.now()); // TODO: refactor? @@ -161,7 +162,7 @@ export function repl({ throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.')); } logger(`[eval] code updated`); - await setPattern(pattern, autostart); + pattern = await setPattern(pattern, autostart); updateState({ miniLocations: meta?.miniLocations || [], widgets: meta?.widgets || [], From bf9086768517d5fba18eedae7d633a9ce0cdd69f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 10:49:07 +0200 Subject: [PATCH 09/18] fix: mini repl punchcard + claviature flags --- website/src/docs/MiniRepl.jsx | 10 ++++++--- website/src/pages/learn/visual-feedback.mdx | 23 ++++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index 37ace3d6f..dd856d266 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -29,13 +29,17 @@ export function MiniRepl({ claviatureLabels, maxHeight, autodraw, + drawTime, }) { const code = tunes ? tunes[0] : tune; const id = useMemo(() => s4(), []); const canvasId = useMemo(() => `canvas-${id}`, [id]); autodraw = !!punchcard || !!claviature || !!autodraw; const shouldShowCanvas = !!punchcard; - const drawTime = punchcard ? [0, 4] : [-2, 2]; + drawTime = drawTime ?? punchcard ? [0, 4] : [-2, 2]; + if (claviature) { + drawTime = [0, 0]; + } const [activeNotes, setActiveNotes] = useState([]); const init = useCallback(({ code, autodraw }) => { @@ -57,7 +61,7 @@ export function MiniRepl({ pat = pat.onTrigger(onTrigger, false); } if (claviature) { - editor?.painters.push((ctx, time, haps, drawTime) => { + pat = pat.onPaint((ctx, time, haps, drawTime) => { const active = haps .map((hap) => hap.value.note) .filter(Boolean) @@ -66,7 +70,7 @@ export function MiniRepl({ }); } if (punchcard) { - editor?.painters.push(getPunchcardPainter({ labels: !!punchcardLabels })); + pat = pat.punchcard({ labels: !!punchcardLabels }); } return pat; }, diff --git a/website/src/pages/learn/visual-feedback.mdx b/website/src/pages/learn/visual-feedback.mdx index cd76ca79e..ed5b16c20 100644 --- a/website/src/pages/learn/visual-feedback.mdx +++ b/website/src/pages/learn/visual-feedback.mdx @@ -38,8 +38,7 @@ You can change the color as well, even pattern it: tune={`n("<0 2 1 3 2>*8") .scale("/4:minor:pentatonic") .s("supersaw").lpf(300).lpenv("<4 3 2>*4") -._punchcard() -`} +._punchcard()`} autodraw /> @@ -48,8 +47,7 @@ You can change the color as well, even pattern it: tune={`n("<0 2 1 3 2>*8") .scale("/4:minor:pentatonic") .s("supersaw").lpf(300).lpenv("<4 3 2>\*4") -.\_pianoroll() -`} +.\_pianoroll()`} autodraw /> @@ -60,8 +58,8 @@ You can change the color as well, even pattern it: tune={`n("<0 2 1 3 2>*8") .scale("/4:minor:pentatonic") .s("supersaw").lpf(300).lpenv("<4 3 2>*4") -._spiral() -`} +._spiral()`} + autodraw /> ## Scope @@ -71,8 +69,17 @@ You can change the color as well, even pattern it: tune={`n("<0 2 1 3 2>*8") .scale("/4:minor:pentatonic") .s("supersaw").lpf(300).lpenv("<4 3 2>*4") -._scope() -`} +._scope()`} +/> + +## Pitchwheel + +*8") +.scale("/4:minor:pentatonic") +.s("supersaw").lpf(300).lpenv("<4 3 2>*4") +._pitchwheel()`} /> {/* */} From 4a87df642685889927777d478b90063616d89fe4 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 14:00:47 +0200 Subject: [PATCH 10/18] small example tweaks --- website/src/pages/workshop/first-effects.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/src/pages/workshop/first-effects.mdx b/website/src/pages/workshop/first-effects.mdx index 4a1522244..220a7cbca 100644 --- a/website/src/pages/workshop/first-effects.mdx +++ b/website/src/pages/workshop/first-effects.mdx @@ -154,7 +154,7 @@ Can you guess what they do? tune={`stack( note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2") .sound("gm_electric_guitar_muted"), -sound("").bank("RolandTR707") +sound("bd rim").bank("RolandTR707") ).delay(".5")`} /> @@ -202,7 +202,7 @@ Add a delay too! tune={`stack( note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2") .sound("gm_electric_guitar_muted").delay(.5), -sound("").bank("RolandTR707").delay(.5), +sound("bd rim").bank("RolandTR707").delay(.5), n("<4 [3@3 4] [<2 0> ~@16] ~>") .scale("D4:minor").sound("gm_accordion:2") .room(2).gain(.5) @@ -216,7 +216,7 @@ Let's add a bass to make this complete: tune={`stack( note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2") .sound("gm_electric_guitar_muted").delay(.5), -sound("").bank("RolandTR707").delay(.5), +sound("bd rim").bank("RolandTR707").delay(.5), n("<4 [3@3 4] [<2 0> ~@16] ~>") .scale("D4:minor").sound("gm_accordion:2") .room(2).gain(.4), @@ -266,7 +266,7 @@ By the way, inside Mini-Notation, `fast` is `*` and `slow` is `/`. Instead of changing values stepwise, we can also control them with signals: - + From d0510f862a022b86d0881e814e1ab73f1e235c25 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 14:02:39 +0200 Subject: [PATCH 11/18] clear hydra in mini repl --- website/src/docs/MiniRepl.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index dd856d266..3559b3412 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -1,6 +1,7 @@ import { useState, useRef, useCallback, useMemo, useEffect } from 'react'; import { Icon } from './Icon'; import { silence, noteToMidi, _mod } from '@strudel/core'; +import { clearHydra } from '@strudel/hydra'; import { getDrawContext, getPunchcardPainter } from '@strudel/draw'; import { transpiler } from '@strudel/transpiler'; import { getAudioContext, webaudioOutput, initAudioOnFirstClick } from '@strudel/webaudio'; @@ -78,6 +79,11 @@ export function MiniRepl({ onUpdateState: (state) => { setReplState({ ...state }); }, + onToggle: (playing) => { + if (!playing) { + clearHydra(); + } + }, beforeStart: () => audioReady, afterEval: ({ code }) => setVersionDefaultsFrom(code), }); From b6e277f1ea76eaea8ccfa67d73776eb4e92a2e65 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 14:03:05 +0200 Subject: [PATCH 12/18] use inline scope in examples --- packages/core/controls.mjs | 16 ++++++++++------ test/runtime.mjs | 4 ++++ website/src/pages/learn/synths.mdx | 23 ++++++++++++----------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 2e8d40f75..82f943949 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -191,7 +191,7 @@ export const { attack, att } = registerControl('attack', 'att'); * note("c e g b g e") * .fm(4) * .fmh("<1 2 1.5 1.61>") - * .scope() + * ._scope() * */ export const { fmh } = registerControl(['fmh', 'fmi'], 'fmh'); @@ -205,7 +205,7 @@ export const { fmh } = registerControl(['fmh', 'fmi'], 'fmh'); * @example * note("c e g b g e") * .fm("<0 1 2 8 32>") - * .scope() + * ._scope() * */ export const { fmi, fm } = registerControl(['fmi', 'fmh'], 'fm'); @@ -221,7 +221,7 @@ export const { fmi, fm } = registerControl(['fmi', 'fmh'], 'fm'); * .fmdecay(.2) * .fmsustain(0) * .fmenv("") - * .scope() + * ._scope() * */ export const { fmenv } = registerControl('fmenv'); @@ -234,7 +234,7 @@ export const { fmenv } = registerControl('fmenv'); * note("c e g b g e") * .fm(4) * .fmattack("<0 .05 .1 .2>") - * .scope() + * ._scope() * */ export const { fmattack } = registerControl('fmattack'); @@ -248,7 +248,7 @@ export const { fmattack } = registerControl('fmattack'); * .fm(4) * .fmdecay("<.01 .05 .1 .2>") * .fmsustain(.4) - * .scope() + * ._scope() * */ export const { fmdecay } = registerControl('fmdecay'); @@ -262,7 +262,7 @@ export const { fmdecay } = registerControl('fmdecay'); * .fm(4) * .fmdecay(.1) * .fmsustain("<1 .75 .5 0>") - * .scope() + * ._scope() * */ export const { fmsustain } = registerControl('fmsustain'); @@ -800,10 +800,12 @@ export const { fanchor } = registerControl('fanchor'); * @example * note("a e") * .vib("<.5 1 2 4 8 16>") + * ._scope() * @example * // change the modulation depth with ":" * note("a e") * .vib("<.5 1 2 4 8 16>:12") + * ._scope() */ export const { vib, vibrato, v } = registerControl(['vib', 'vibmod'], 'vibrato', 'v'); /** @@ -824,10 +826,12 @@ export const { noise } = registerControl('noise'); * @example * note("a e").vib(4) * .vibmod("<.25 .5 1 2 12>") + * ._scope() * @example * // change the vibrato frequency with ":" * note("a e") * .vibmod("<.25 .5 1 2 12>:8") + * ._scope() */ export const { vibmod, vmod } = registerControl(['vibmod', 'vib'], 'vmod'); export const { hcutoff, hpf, hp } = registerControl(['hcutoff', 'hresonance', 'hpenv'], 'hpf', 'hp'); diff --git a/test/runtime.mjs b/test/runtime.mjs index f14e18e23..7b9350ebd 100644 --- a/test/runtime.mjs +++ b/test/runtime.mjs @@ -122,6 +122,10 @@ strudel.Pattern.prototype.midi = function () { return this; }; +strudel.Pattern.prototype._scope = function () { + return this; +}; + const uiHelpersMocked = { backgroundImage: id, }; diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index 36385d54d..21a9b917e 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -18,7 +18,7 @@ The basic waveforms are `sine`, `sawtooth`, `square` and `triangle`, which can b client:idle tune={`note("c2 >".fast(2)) .sound("") -.scope()`} +._scope()`} /> If you don't set a `sound` but a `note` the default value for `sound` is `triangle`! @@ -28,23 +28,23 @@ If you don't set a `sound` but a `note` the default value for `sound` is `triang You can also use noise as a source by setting the waveform to: `white`, `pink` or `brown`. These are different flavours of noise, here written from hard to soft. -").scope()`} /> +")._scope()`} /> Here's a more musical example of how to use noise for hihats: *8") -.decay(.04).sustain(0).scope()`} +.decay(.04).sustain(0)._scope()`} /> Some amount of pink noise can also be added to any oscillator by using the `noise` paremeter: -").scope()`} /> +")._scope()`} /> You can also use the `crackle` type to play some subtle noise crackles. You can control noise amount by using the `density` parameter: -".slow(2)).scope()`} /> +".slow(2))._scope()`} /> ### Additive Synthesis @@ -55,7 +55,7 @@ To tame the harsh sound of the basic waveforms, we can set the `n` control to li tune={`note("c2 >".fast(2)) .sound("sawtooth") .n("<32 16 8 4>") -.scope()`} +._scope()`} /> When the `n` control is used on a basic waveform, it defines the number of harmonic partials the sound is getting. @@ -65,7 +65,7 @@ You can also set `n` directly in mini notation with `sound`: client:idle tune={`note("c2 >".fast(2)) .sound("sawtooth:<32 16 8 4>") -.scope()`} +._scope()`} /> Note for tidal users: `n` in tidal is synonymous to `note` for synths only. @@ -119,13 +119,14 @@ Any sample preceded by the `wt_` prefix will be loaded as a wavetable. This mean ") .n("<1 2 3 4 5 6 7 8 9 10>/2").room(0.5).size(0.9) .s('wt_flute').velocity(0.25).often(n => n.ply(2)) .release(0.125).decay("<0.1 0.25 0.3 0.4>").sustain(0) -.cutoff(2000).scope({}).cutoff("<1000 2000 4000>").fast(4)`} +.cutoff(2000).cutoff("<1000 2000 4000>").fast(4) +._scope() +`} /> ## ZZFX @@ -159,7 +160,7 @@ It has 20 parameters in total, here is a snippet that uses all: .tremolo(0) // 0-1 lfo volume modulation amount //.duration(.2) // overwrite strudel event duration //.gain(1) // change volume - .scope() // vizualise waveform (not zzfx related) + ._scope() // vizualise waveform (not zzfx related) `} /> From 6adf1ff9770230d75a60984a3fc70bd1d45a8ada Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 14:03:30 +0200 Subject: [PATCH 13/18] snapshot --- test/__snapshots__/examples.test.mjs.snap | 288 +++++++++++----------- 1 file changed, 144 insertions(+), 144 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 3ff7eae2a..dc76c13a1 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2717,175 +2717,175 @@ exports[`runs examples > example "floor" example index 0 1`] = ` exports[`runs examples > example "fm" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c fmi:0 analyze:1 ]", - "[ 1/6 → 1/3 | note:e fmi:0 analyze:1 ]", - "[ 1/3 → 1/2 | note:g fmi:0 analyze:1 ]", - "[ 1/2 → 2/3 | note:b fmi:0 analyze:1 ]", - "[ 2/3 → 5/6 | note:g fmi:0 analyze:1 ]", - "[ 5/6 → 1/1 | note:e fmi:0 analyze:1 ]", - "[ 1/1 → 7/6 | note:c fmi:1 analyze:1 ]", - "[ 7/6 → 4/3 | note:e fmi:1 analyze:1 ]", - "[ 4/3 → 3/2 | note:g fmi:1 analyze:1 ]", - "[ 3/2 → 5/3 | note:b fmi:1 analyze:1 ]", - "[ 5/3 → 11/6 | note:g fmi:1 analyze:1 ]", - "[ 11/6 → 2/1 | note:e fmi:1 analyze:1 ]", - "[ 2/1 → 13/6 | note:c fmi:2 analyze:1 ]", - "[ 13/6 → 7/3 | note:e fmi:2 analyze:1 ]", - "[ 7/3 → 5/2 | note:g fmi:2 analyze:1 ]", - "[ 5/2 → 8/3 | note:b fmi:2 analyze:1 ]", - "[ 8/3 → 17/6 | note:g fmi:2 analyze:1 ]", - "[ 17/6 → 3/1 | note:e fmi:2 analyze:1 ]", - "[ 3/1 → 19/6 | note:c fmi:8 analyze:1 ]", - "[ 19/6 → 10/3 | note:e fmi:8 analyze:1 ]", - "[ 10/3 → 7/2 | note:g fmi:8 analyze:1 ]", - "[ 7/2 → 11/3 | note:b fmi:8 analyze:1 ]", - "[ 11/3 → 23/6 | note:g fmi:8 analyze:1 ]", - "[ 23/6 → 4/1 | note:e fmi:8 analyze:1 ]", + "[ 0/1 → 1/6 | note:c fmi:0 ]", + "[ 1/6 → 1/3 | note:e fmi:0 ]", + "[ 1/3 → 1/2 | note:g fmi:0 ]", + "[ 1/2 → 2/3 | note:b fmi:0 ]", + "[ 2/3 → 5/6 | note:g fmi:0 ]", + "[ 5/6 → 1/1 | note:e fmi:0 ]", + "[ 1/1 → 7/6 | note:c fmi:1 ]", + "[ 7/6 → 4/3 | note:e fmi:1 ]", + "[ 4/3 → 3/2 | note:g fmi:1 ]", + "[ 3/2 → 5/3 | note:b fmi:1 ]", + "[ 5/3 → 11/6 | note:g fmi:1 ]", + "[ 11/6 → 2/1 | note:e fmi:1 ]", + "[ 2/1 → 13/6 | note:c fmi:2 ]", + "[ 13/6 → 7/3 | note:e fmi:2 ]", + "[ 7/3 → 5/2 | note:g fmi:2 ]", + "[ 5/2 → 8/3 | note:b fmi:2 ]", + "[ 8/3 → 17/6 | note:g fmi:2 ]", + "[ 17/6 → 3/1 | note:e fmi:2 ]", + "[ 3/1 → 19/6 | note:c fmi:8 ]", + "[ 19/6 → 10/3 | note:e fmi:8 ]", + "[ 10/3 → 7/2 | note:g fmi:8 ]", + "[ 7/2 → 11/3 | note:b fmi:8 ]", + "[ 11/3 → 23/6 | note:g fmi:8 ]", + "[ 23/6 → 4/1 | note:e fmi:8 ]", ] `; exports[`runs examples > example "fmattack" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c fmi:4 fmattack:0 analyze:1 ]", - "[ 1/6 → 1/3 | note:e fmi:4 fmattack:0 analyze:1 ]", - "[ 1/3 → 1/2 | note:g fmi:4 fmattack:0 analyze:1 ]", - "[ 1/2 → 2/3 | note:b fmi:4 fmattack:0 analyze:1 ]", - "[ 2/3 → 5/6 | note:g fmi:4 fmattack:0 analyze:1 ]", - "[ 5/6 → 1/1 | note:e fmi:4 fmattack:0 analyze:1 ]", - "[ 1/1 → 7/6 | note:c fmi:4 fmattack:0.05 analyze:1 ]", - "[ 7/6 → 4/3 | note:e fmi:4 fmattack:0.05 analyze:1 ]", - "[ 4/3 → 3/2 | note:g fmi:4 fmattack:0.05 analyze:1 ]", - "[ 3/2 → 5/3 | note:b fmi:4 fmattack:0.05 analyze:1 ]", - "[ 5/3 → 11/6 | note:g fmi:4 fmattack:0.05 analyze:1 ]", - "[ 11/6 → 2/1 | note:e fmi:4 fmattack:0.05 analyze:1 ]", - "[ 2/1 → 13/6 | note:c fmi:4 fmattack:0.1 analyze:1 ]", - "[ 13/6 → 7/3 | note:e fmi:4 fmattack:0.1 analyze:1 ]", - "[ 7/3 → 5/2 | note:g fmi:4 fmattack:0.1 analyze:1 ]", - "[ 5/2 → 8/3 | note:b fmi:4 fmattack:0.1 analyze:1 ]", - "[ 8/3 → 17/6 | note:g fmi:4 fmattack:0.1 analyze:1 ]", - "[ 17/6 → 3/1 | note:e fmi:4 fmattack:0.1 analyze:1 ]", - "[ 3/1 → 19/6 | note:c fmi:4 fmattack:0.2 analyze:1 ]", - "[ 19/6 → 10/3 | note:e fmi:4 fmattack:0.2 analyze:1 ]", - "[ 10/3 → 7/2 | note:g fmi:4 fmattack:0.2 analyze:1 ]", - "[ 7/2 → 11/3 | note:b fmi:4 fmattack:0.2 analyze:1 ]", - "[ 11/3 → 23/6 | note:g fmi:4 fmattack:0.2 analyze:1 ]", - "[ 23/6 → 4/1 | note:e fmi:4 fmattack:0.2 analyze:1 ]", + "[ 0/1 → 1/6 | note:c fmi:4 fmattack:0 ]", + "[ 1/6 → 1/3 | note:e fmi:4 fmattack:0 ]", + "[ 1/3 → 1/2 | note:g fmi:4 fmattack:0 ]", + "[ 1/2 → 2/3 | note:b fmi:4 fmattack:0 ]", + "[ 2/3 → 5/6 | note:g fmi:4 fmattack:0 ]", + "[ 5/6 → 1/1 | note:e fmi:4 fmattack:0 ]", + "[ 1/1 → 7/6 | note:c fmi:4 fmattack:0.05 ]", + "[ 7/6 → 4/3 | note:e fmi:4 fmattack:0.05 ]", + "[ 4/3 → 3/2 | note:g fmi:4 fmattack:0.05 ]", + "[ 3/2 → 5/3 | note:b fmi:4 fmattack:0.05 ]", + "[ 5/3 → 11/6 | note:g fmi:4 fmattack:0.05 ]", + "[ 11/6 → 2/1 | note:e fmi:4 fmattack:0.05 ]", + "[ 2/1 → 13/6 | note:c fmi:4 fmattack:0.1 ]", + "[ 13/6 → 7/3 | note:e fmi:4 fmattack:0.1 ]", + "[ 7/3 → 5/2 | note:g fmi:4 fmattack:0.1 ]", + "[ 5/2 → 8/3 | note:b fmi:4 fmattack:0.1 ]", + "[ 8/3 → 17/6 | note:g fmi:4 fmattack:0.1 ]", + "[ 17/6 → 3/1 | note:e fmi:4 fmattack:0.1 ]", + "[ 3/1 → 19/6 | note:c fmi:4 fmattack:0.2 ]", + "[ 19/6 → 10/3 | note:e fmi:4 fmattack:0.2 ]", + "[ 10/3 → 7/2 | note:g fmi:4 fmattack:0.2 ]", + "[ 7/2 → 11/3 | note:b fmi:4 fmattack:0.2 ]", + "[ 11/3 → 23/6 | note:g fmi:4 fmattack:0.2 ]", + "[ 23/6 → 4/1 | note:e fmi:4 fmattack:0.2 ]", ] `; exports[`runs examples > example "fmdecay" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c fmi:4 fmdecay:0.01 fmsustain:0.4 analyze:1 ]", - "[ 1/6 → 1/3 | note:e fmi:4 fmdecay:0.01 fmsustain:0.4 analyze:1 ]", - "[ 1/3 → 1/2 | note:g fmi:4 fmdecay:0.01 fmsustain:0.4 analyze:1 ]", - "[ 1/2 → 2/3 | note:b fmi:4 fmdecay:0.01 fmsustain:0.4 analyze:1 ]", - "[ 2/3 → 5/6 | note:g fmi:4 fmdecay:0.01 fmsustain:0.4 analyze:1 ]", - "[ 5/6 → 1/1 | note:e fmi:4 fmdecay:0.01 fmsustain:0.4 analyze:1 ]", - "[ 1/1 → 7/6 | note:c fmi:4 fmdecay:0.05 fmsustain:0.4 analyze:1 ]", - "[ 7/6 → 4/3 | note:e fmi:4 fmdecay:0.05 fmsustain:0.4 analyze:1 ]", - "[ 4/3 → 3/2 | note:g fmi:4 fmdecay:0.05 fmsustain:0.4 analyze:1 ]", - "[ 3/2 → 5/3 | note:b fmi:4 fmdecay:0.05 fmsustain:0.4 analyze:1 ]", - "[ 5/3 → 11/6 | note:g fmi:4 fmdecay:0.05 fmsustain:0.4 analyze:1 ]", - "[ 11/6 → 2/1 | note:e fmi:4 fmdecay:0.05 fmsustain:0.4 analyze:1 ]", - "[ 2/1 → 13/6 | note:c fmi:4 fmdecay:0.1 fmsustain:0.4 analyze:1 ]", - "[ 13/6 → 7/3 | note:e fmi:4 fmdecay:0.1 fmsustain:0.4 analyze:1 ]", - "[ 7/3 → 5/2 | note:g fmi:4 fmdecay:0.1 fmsustain:0.4 analyze:1 ]", - "[ 5/2 → 8/3 | note:b fmi:4 fmdecay:0.1 fmsustain:0.4 analyze:1 ]", - "[ 8/3 → 17/6 | note:g fmi:4 fmdecay:0.1 fmsustain:0.4 analyze:1 ]", - "[ 17/6 → 3/1 | note:e fmi:4 fmdecay:0.1 fmsustain:0.4 analyze:1 ]", - "[ 3/1 → 19/6 | note:c fmi:4 fmdecay:0.2 fmsustain:0.4 analyze:1 ]", - "[ 19/6 → 10/3 | note:e fmi:4 fmdecay:0.2 fmsustain:0.4 analyze:1 ]", - "[ 10/3 → 7/2 | note:g fmi:4 fmdecay:0.2 fmsustain:0.4 analyze:1 ]", - "[ 7/2 → 11/3 | note:b fmi:4 fmdecay:0.2 fmsustain:0.4 analyze:1 ]", - "[ 11/3 → 23/6 | note:g fmi:4 fmdecay:0.2 fmsustain:0.4 analyze:1 ]", - "[ 23/6 → 4/1 | note:e fmi:4 fmdecay:0.2 fmsustain:0.4 analyze:1 ]", + "[ 0/1 → 1/6 | note:c fmi:4 fmdecay:0.01 fmsustain:0.4 ]", + "[ 1/6 → 1/3 | note:e fmi:4 fmdecay:0.01 fmsustain:0.4 ]", + "[ 1/3 → 1/2 | note:g fmi:4 fmdecay:0.01 fmsustain:0.4 ]", + "[ 1/2 → 2/3 | note:b fmi:4 fmdecay:0.01 fmsustain:0.4 ]", + "[ 2/3 → 5/6 | note:g fmi:4 fmdecay:0.01 fmsustain:0.4 ]", + "[ 5/6 → 1/1 | note:e fmi:4 fmdecay:0.01 fmsustain:0.4 ]", + "[ 1/1 → 7/6 | note:c fmi:4 fmdecay:0.05 fmsustain:0.4 ]", + "[ 7/6 → 4/3 | note:e fmi:4 fmdecay:0.05 fmsustain:0.4 ]", + "[ 4/3 → 3/2 | note:g fmi:4 fmdecay:0.05 fmsustain:0.4 ]", + "[ 3/2 → 5/3 | note:b fmi:4 fmdecay:0.05 fmsustain:0.4 ]", + "[ 5/3 → 11/6 | note:g fmi:4 fmdecay:0.05 fmsustain:0.4 ]", + "[ 11/6 → 2/1 | note:e fmi:4 fmdecay:0.05 fmsustain:0.4 ]", + "[ 2/1 → 13/6 | note:c fmi:4 fmdecay:0.1 fmsustain:0.4 ]", + "[ 13/6 → 7/3 | note:e fmi:4 fmdecay:0.1 fmsustain:0.4 ]", + "[ 7/3 → 5/2 | note:g fmi:4 fmdecay:0.1 fmsustain:0.4 ]", + "[ 5/2 → 8/3 | note:b fmi:4 fmdecay:0.1 fmsustain:0.4 ]", + "[ 8/3 → 17/6 | note:g fmi:4 fmdecay:0.1 fmsustain:0.4 ]", + "[ 17/6 → 3/1 | note:e fmi:4 fmdecay:0.1 fmsustain:0.4 ]", + "[ 3/1 → 19/6 | note:c fmi:4 fmdecay:0.2 fmsustain:0.4 ]", + "[ 19/6 → 10/3 | note:e fmi:4 fmdecay:0.2 fmsustain:0.4 ]", + "[ 10/3 → 7/2 | note:g fmi:4 fmdecay:0.2 fmsustain:0.4 ]", + "[ 7/2 → 11/3 | note:b fmi:4 fmdecay:0.2 fmsustain:0.4 ]", + "[ 11/3 → 23/6 | note:g fmi:4 fmdecay:0.2 fmsustain:0.4 ]", + "[ 23/6 → 4/1 | note:e fmi:4 fmdecay:0.2 fmsustain:0.4 ]", ] `; exports[`runs examples > example "fmenv" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 1/6 → 1/3 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 1/3 → 1/2 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 1/2 → 2/3 | note:b fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 2/3 → 5/6 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 5/6 → 1/1 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 1/1 → 7/6 | note:c fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 7/6 → 4/3 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 4/3 → 3/2 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 3/2 → 5/3 | note:b fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 5/3 → 11/6 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 11/6 → 2/1 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 2/1 → 13/6 | note:c fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 13/6 → 7/3 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 7/3 → 5/2 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 5/2 → 8/3 | note:b fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 8/3 → 17/6 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 17/6 → 3/1 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp analyze:1 ]", - "[ 3/1 → 19/6 | note:c fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 19/6 → 10/3 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 10/3 → 7/2 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 7/2 → 11/3 | note:b fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 11/3 → 23/6 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", - "[ 23/6 → 4/1 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin analyze:1 ]", + "[ 0/1 → 1/6 | note:c fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 1/6 → 1/3 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 1/3 → 1/2 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 1/2 → 2/3 | note:b fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 2/3 → 5/6 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 5/6 → 1/1 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 1/1 → 7/6 | note:c fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 7/6 → 4/3 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 4/3 → 3/2 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 3/2 → 5/3 | note:b fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 5/3 → 11/6 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 11/6 → 2/1 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 2/1 → 13/6 | note:c fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 13/6 → 7/3 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 7/3 → 5/2 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 5/2 → 8/3 | note:b fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 8/3 → 17/6 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 17/6 → 3/1 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:exp ]", + "[ 3/1 → 19/6 | note:c fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 19/6 → 10/3 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 10/3 → 7/2 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 7/2 → 11/3 | note:b fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 11/3 → 23/6 | note:g fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", + "[ 23/6 → 4/1 | note:e fmi:4 fmdecay:0.2 fmsustain:0 fmenv:lin ]", ] `; exports[`runs examples > example "fmh" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c fmi:4 fmh:1 analyze:1 ]", - "[ 1/6 → 1/3 | note:e fmi:4 fmh:1 analyze:1 ]", - "[ 1/3 → 1/2 | note:g fmi:4 fmh:1 analyze:1 ]", - "[ 1/2 → 2/3 | note:b fmi:4 fmh:1 analyze:1 ]", - "[ 2/3 → 5/6 | note:g fmi:4 fmh:1 analyze:1 ]", - "[ 5/6 → 1/1 | note:e fmi:4 fmh:1 analyze:1 ]", - "[ 1/1 → 7/6 | note:c fmi:4 fmh:2 analyze:1 ]", - "[ 7/6 → 4/3 | note:e fmi:4 fmh:2 analyze:1 ]", - "[ 4/3 → 3/2 | note:g fmi:4 fmh:2 analyze:1 ]", - "[ 3/2 → 5/3 | note:b fmi:4 fmh:2 analyze:1 ]", - "[ 5/3 → 11/6 | note:g fmi:4 fmh:2 analyze:1 ]", - "[ 11/6 → 2/1 | note:e fmi:4 fmh:2 analyze:1 ]", - "[ 2/1 → 13/6 | note:c fmi:4 fmh:1.5 analyze:1 ]", - "[ 13/6 → 7/3 | note:e fmi:4 fmh:1.5 analyze:1 ]", - "[ 7/3 → 5/2 | note:g fmi:4 fmh:1.5 analyze:1 ]", - "[ 5/2 → 8/3 | note:b fmi:4 fmh:1.5 analyze:1 ]", - "[ 8/3 → 17/6 | note:g fmi:4 fmh:1.5 analyze:1 ]", - "[ 17/6 → 3/1 | note:e fmi:4 fmh:1.5 analyze:1 ]", - "[ 3/1 → 19/6 | note:c fmi:4 fmh:1.61 analyze:1 ]", - "[ 19/6 → 10/3 | note:e fmi:4 fmh:1.61 analyze:1 ]", - "[ 10/3 → 7/2 | note:g fmi:4 fmh:1.61 analyze:1 ]", - "[ 7/2 → 11/3 | note:b fmi:4 fmh:1.61 analyze:1 ]", - "[ 11/3 → 23/6 | note:g fmi:4 fmh:1.61 analyze:1 ]", - "[ 23/6 → 4/1 | note:e fmi:4 fmh:1.61 analyze:1 ]", + "[ 0/1 → 1/6 | note:c fmi:4 fmh:1 ]", + "[ 1/6 → 1/3 | note:e fmi:4 fmh:1 ]", + "[ 1/3 → 1/2 | note:g fmi:4 fmh:1 ]", + "[ 1/2 → 2/3 | note:b fmi:4 fmh:1 ]", + "[ 2/3 → 5/6 | note:g fmi:4 fmh:1 ]", + "[ 5/6 → 1/1 | note:e fmi:4 fmh:1 ]", + "[ 1/1 → 7/6 | note:c fmi:4 fmh:2 ]", + "[ 7/6 → 4/3 | note:e fmi:4 fmh:2 ]", + "[ 4/3 → 3/2 | note:g fmi:4 fmh:2 ]", + "[ 3/2 → 5/3 | note:b fmi:4 fmh:2 ]", + "[ 5/3 → 11/6 | note:g fmi:4 fmh:2 ]", + "[ 11/6 → 2/1 | note:e fmi:4 fmh:2 ]", + "[ 2/1 → 13/6 | note:c fmi:4 fmh:1.5 ]", + "[ 13/6 → 7/3 | note:e fmi:4 fmh:1.5 ]", + "[ 7/3 → 5/2 | note:g fmi:4 fmh:1.5 ]", + "[ 5/2 → 8/3 | note:b fmi:4 fmh:1.5 ]", + "[ 8/3 → 17/6 | note:g fmi:4 fmh:1.5 ]", + "[ 17/6 → 3/1 | note:e fmi:4 fmh:1.5 ]", + "[ 3/1 → 19/6 | note:c fmi:4 fmh:1.61 ]", + "[ 19/6 → 10/3 | note:e fmi:4 fmh:1.61 ]", + "[ 10/3 → 7/2 | note:g fmi:4 fmh:1.61 ]", + "[ 7/2 → 11/3 | note:b fmi:4 fmh:1.61 ]", + "[ 11/3 → 23/6 | note:g fmi:4 fmh:1.61 ]", + "[ 23/6 → 4/1 | note:e fmi:4 fmh:1.61 ]", ] `; exports[`runs examples > example "fmsustain" example index 0 1`] = ` [ - "[ 0/1 → 1/6 | note:c fmi:4 fmdecay:0.1 fmsustain:1 analyze:1 ]", - "[ 1/6 → 1/3 | note:e fmi:4 fmdecay:0.1 fmsustain:1 analyze:1 ]", - "[ 1/3 → 1/2 | note:g fmi:4 fmdecay:0.1 fmsustain:1 analyze:1 ]", - "[ 1/2 → 2/3 | note:b fmi:4 fmdecay:0.1 fmsustain:1 analyze:1 ]", - "[ 2/3 → 5/6 | note:g fmi:4 fmdecay:0.1 fmsustain:1 analyze:1 ]", - "[ 5/6 → 1/1 | note:e fmi:4 fmdecay:0.1 fmsustain:1 analyze:1 ]", - "[ 1/1 → 7/6 | note:c fmi:4 fmdecay:0.1 fmsustain:0.75 analyze:1 ]", - "[ 7/6 → 4/3 | note:e fmi:4 fmdecay:0.1 fmsustain:0.75 analyze:1 ]", - "[ 4/3 → 3/2 | note:g fmi:4 fmdecay:0.1 fmsustain:0.75 analyze:1 ]", - "[ 3/2 → 5/3 | note:b fmi:4 fmdecay:0.1 fmsustain:0.75 analyze:1 ]", - "[ 5/3 → 11/6 | note:g fmi:4 fmdecay:0.1 fmsustain:0.75 analyze:1 ]", - "[ 11/6 → 2/1 | note:e fmi:4 fmdecay:0.1 fmsustain:0.75 analyze:1 ]", - "[ 2/1 → 13/6 | note:c fmi:4 fmdecay:0.1 fmsustain:0.5 analyze:1 ]", - "[ 13/6 → 7/3 | note:e fmi:4 fmdecay:0.1 fmsustain:0.5 analyze:1 ]", - "[ 7/3 → 5/2 | note:g fmi:4 fmdecay:0.1 fmsustain:0.5 analyze:1 ]", - "[ 5/2 → 8/3 | note:b fmi:4 fmdecay:0.1 fmsustain:0.5 analyze:1 ]", - "[ 8/3 → 17/6 | note:g fmi:4 fmdecay:0.1 fmsustain:0.5 analyze:1 ]", - "[ 17/6 → 3/1 | note:e fmi:4 fmdecay:0.1 fmsustain:0.5 analyze:1 ]", - "[ 3/1 → 19/6 | note:c fmi:4 fmdecay:0.1 fmsustain:0 analyze:1 ]", - "[ 19/6 → 10/3 | note:e fmi:4 fmdecay:0.1 fmsustain:0 analyze:1 ]", - "[ 10/3 → 7/2 | note:g fmi:4 fmdecay:0.1 fmsustain:0 analyze:1 ]", - "[ 7/2 → 11/3 | note:b fmi:4 fmdecay:0.1 fmsustain:0 analyze:1 ]", - "[ 11/3 → 23/6 | note:g fmi:4 fmdecay:0.1 fmsustain:0 analyze:1 ]", - "[ 23/6 → 4/1 | note:e fmi:4 fmdecay:0.1 fmsustain:0 analyze:1 ]", + "[ 0/1 → 1/6 | note:c fmi:4 fmdecay:0.1 fmsustain:1 ]", + "[ 1/6 → 1/3 | note:e fmi:4 fmdecay:0.1 fmsustain:1 ]", + "[ 1/3 → 1/2 | note:g fmi:4 fmdecay:0.1 fmsustain:1 ]", + "[ 1/2 → 2/3 | note:b fmi:4 fmdecay:0.1 fmsustain:1 ]", + "[ 2/3 → 5/6 | note:g fmi:4 fmdecay:0.1 fmsustain:1 ]", + "[ 5/6 → 1/1 | note:e fmi:4 fmdecay:0.1 fmsustain:1 ]", + "[ 1/1 → 7/6 | note:c fmi:4 fmdecay:0.1 fmsustain:0.75 ]", + "[ 7/6 → 4/3 | note:e fmi:4 fmdecay:0.1 fmsustain:0.75 ]", + "[ 4/3 → 3/2 | note:g fmi:4 fmdecay:0.1 fmsustain:0.75 ]", + "[ 3/2 → 5/3 | note:b fmi:4 fmdecay:0.1 fmsustain:0.75 ]", + "[ 5/3 → 11/6 | note:g fmi:4 fmdecay:0.1 fmsustain:0.75 ]", + "[ 11/6 → 2/1 | note:e fmi:4 fmdecay:0.1 fmsustain:0.75 ]", + "[ 2/1 → 13/6 | note:c fmi:4 fmdecay:0.1 fmsustain:0.5 ]", + "[ 13/6 → 7/3 | note:e fmi:4 fmdecay:0.1 fmsustain:0.5 ]", + "[ 7/3 → 5/2 | note:g fmi:4 fmdecay:0.1 fmsustain:0.5 ]", + "[ 5/2 → 8/3 | note:b fmi:4 fmdecay:0.1 fmsustain:0.5 ]", + "[ 8/3 → 17/6 | note:g fmi:4 fmdecay:0.1 fmsustain:0.5 ]", + "[ 17/6 → 3/1 | note:e fmi:4 fmdecay:0.1 fmsustain:0.5 ]", + "[ 3/1 → 19/6 | note:c fmi:4 fmdecay:0.1 fmsustain:0 ]", + "[ 19/6 → 10/3 | note:e fmi:4 fmdecay:0.1 fmsustain:0 ]", + "[ 10/3 → 7/2 | note:g fmi:4 fmdecay:0.1 fmsustain:0 ]", + "[ 7/2 → 11/3 | note:b fmi:4 fmdecay:0.1 fmsustain:0 ]", + "[ 11/3 → 23/6 | note:g fmi:4 fmdecay:0.1 fmsustain:0 ]", + "[ 23/6 → 4/1 | note:e fmi:4 fmdecay:0.1 fmsustain:0 ]", ] `; From e6b55baed0714e9a454036d69daf6650b9e06d61 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 14:08:56 +0200 Subject: [PATCH 14/18] fix: step based naming --- packages/core/pattern.mjs | 8 ++++--- website/src/pages/learn/factories.mdx | 30 +++++++++++++-------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 918a924b2..a8a4f7da6 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2531,7 +2531,7 @@ export function _polymeterListSteps(steps, ...args) { * @param {any[]} patterns one or more patterns * @example * // the same as "{c d, e f g}%4" - * s_polymeterSteps(4, "c d", "e f g") + * s_polymeterSteps(4, "c d", "e f g").note() */ export function s_polymeterSteps(steps, ...args) { if (args.length == 0) { @@ -2549,8 +2549,8 @@ export function s_polymeterSteps(steps, ...args) { * *EXPERIMENTAL* - Combines the given lists of patterns with the same pulse, creating polymeters when different sized sequences are used. * @synonyms pm * @example - * // The same as "{c eb g, c2 g2}" - * s_polymeter("c eb g", "c2 g2") + * // The same as note("{c eb g, c2 g2}") + * s_polymeter("c eb g", "c2 g2").note() * */ export function s_polymeter(...args) { @@ -2579,6 +2579,8 @@ export function s_polymeter(...args) { /** Sequences patterns like `seq`, but each pattern has a length, relative to the whole. * This length can either be provided as a [length, pattern] pair, or inferred from * the pattern's 'tactus', generally inferred by the mininotation. Has the alias `timecat`. + * @name s_cat + * @synonyms timeCat, timecat * @return {Pattern} * @example * s_cat([3,"e3"],[1, "g3"]).note() diff --git a/website/src/pages/learn/factories.mdx b/website/src/pages/learn/factories.mdx index 0d93fb21a..a823bfedd 100644 --- a/website/src/pages/learn/factories.mdx +++ b/website/src/pages/learn/factories.mdx @@ -11,15 +11,15 @@ import { JsDoc } from '../../docs/JsDoc'; The following functions will return a pattern. These are the equivalents used by the Mini Notation: -| function | mini | -| ------------------------------ | ---------------- | -| `cat(x, y)` | `""` | -| `seq(x, y)` | `"x y"` | -| `stack(x, y)` | `"x,y"` | -| `timeCat([3,x],[2,y])` | `"x@3 y@2"` | -| `polymeter([a, b, c], [x, y])` | `"{a b c, x y}"` | -| `polymeterSteps(2, x, y, z)` | `"{x y z}%2"` | -| `silence` | `"~"` | +| function | mini | +| -------------------------------- | ---------------- | +| `cat(x, y)` | `""` | +| `seq(x, y)` | `"x y"` | +| `stack(x, y)` | `"x,y"` | +| `s_cat([3,x],[2,y])` | `"x@3 y@2"` | +| `s_polymeter([a, b, c], [x, y])` | `"{a b c, x y}"` | +| `s_polymeterSteps(2, x, y, z)` | `"{x y z}%2"` | +| `silence` | `"~"` | ## cat @@ -45,21 +45,21 @@ As a chained function: -## timeCat +## s_cat - + ## arrange -## polymeter +## s_polymeter - + -## polymeterSteps +## s_polymeterSteps - + ## silence From 25981092b184688ca0e3c45931d29af227c87ad6 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 14:11:52 +0200 Subject: [PATCH 15/18] snapshot --- test/__snapshots__/examples.test.mjs.snap | 112 +++++++++++----------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index dc76c13a1..0cd653e3a 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -6196,67 +6196,67 @@ exports[`runs examples > example "s_cat" example index 1 1`] = ` exports[`runs examples > example "s_polymeter" example index 0 1`] = ` [ - "[ 0/1 → 1/3 | c ]", - "[ 0/1 → 1/3 | c2 ]", - "[ 1/3 → 2/3 | eb ]", - "[ 1/3 → 2/3 | g2 ]", - "[ 2/3 → 1/1 | g ]", - "[ 2/3 → 1/1 | c2 ]", - "[ 1/1 → 4/3 | c ]", - "[ 1/1 → 4/3 | g2 ]", - "[ 4/3 → 5/3 | eb ]", - "[ 4/3 → 5/3 | c2 ]", - "[ 5/3 → 2/1 | g ]", - "[ 5/3 → 2/1 | g2 ]", - "[ 2/1 → 7/3 | c ]", - "[ 2/1 → 7/3 | c2 ]", - "[ 7/3 → 8/3 | eb ]", - "[ 7/3 → 8/3 | g2 ]", - "[ 8/3 → 3/1 | g ]", - "[ 8/3 → 3/1 | c2 ]", - "[ 3/1 → 10/3 | c ]", - "[ 3/1 → 10/3 | g2 ]", - "[ 10/3 → 11/3 | eb ]", - "[ 10/3 → 11/3 | c2 ]", - "[ 11/3 → 4/1 | g ]", - "[ 11/3 → 4/1 | g2 ]", + "[ 0/1 → 1/3 | note:c ]", + "[ 0/1 → 1/3 | note:c2 ]", + "[ 1/3 → 2/3 | note:eb ]", + "[ 1/3 → 2/3 | note:g2 ]", + "[ 2/3 → 1/1 | note:g ]", + "[ 2/3 → 1/1 | note:c2 ]", + "[ 1/1 → 4/3 | note:c ]", + "[ 1/1 → 4/3 | note:g2 ]", + "[ 4/3 → 5/3 | note:eb ]", + "[ 4/3 → 5/3 | note:c2 ]", + "[ 5/3 → 2/1 | note:g ]", + "[ 5/3 → 2/1 | note:g2 ]", + "[ 2/1 → 7/3 | note:c ]", + "[ 2/1 → 7/3 | note:c2 ]", + "[ 7/3 → 8/3 | note:eb ]", + "[ 7/3 → 8/3 | note:g2 ]", + "[ 8/3 → 3/1 | note:g ]", + "[ 8/3 → 3/1 | note:c2 ]", + "[ 3/1 → 10/3 | note:c ]", + "[ 3/1 → 10/3 | note:g2 ]", + "[ 10/3 → 11/3 | note:eb ]", + "[ 10/3 → 11/3 | note:c2 ]", + "[ 11/3 → 4/1 | note:g ]", + "[ 11/3 → 4/1 | note:g2 ]", ] `; exports[`runs examples > example "s_polymeterSteps" example index 0 1`] = ` [ - "[ 0/1 → 1/4 | c ]", - "[ 0/1 → 1/4 | e ]", - "[ 1/4 → 1/2 | d ]", - "[ 1/4 → 1/2 | f ]", - "[ 1/2 → 3/4 | c ]", - "[ 1/2 → 3/4 | g ]", - "[ 3/4 → 1/1 | d ]", - "[ 3/4 → 1/1 | e ]", - "[ 1/1 → 5/4 | c ]", - "[ 1/1 → 5/4 | f ]", - "[ 5/4 → 3/2 | d ]", - "[ 5/4 → 3/2 | g ]", - "[ 3/2 → 7/4 | c ]", - "[ 3/2 → 7/4 | e ]", - "[ 7/4 → 2/1 | d ]", - "[ 7/4 → 2/1 | f ]", - "[ 2/1 → 9/4 | c ]", - "[ 2/1 → 9/4 | g ]", - "[ 9/4 → 5/2 | d ]", - "[ 9/4 → 5/2 | e ]", - "[ 5/2 → 11/4 | c ]", - "[ 5/2 → 11/4 | f ]", - "[ 11/4 → 3/1 | d ]", - "[ 11/4 → 3/1 | g ]", - "[ 3/1 → 13/4 | c ]", - "[ 3/1 → 13/4 | e ]", - "[ 13/4 → 7/2 | d ]", - "[ 13/4 → 7/2 | f ]", - "[ 7/2 → 15/4 | c ]", - "[ 7/2 → 15/4 | g ]", - "[ 15/4 → 4/1 | d ]", - "[ 15/4 → 4/1 | e ]", + "[ 0/1 → 1/4 | note:c ]", + "[ 0/1 → 1/4 | note:e ]", + "[ 1/4 → 1/2 | note:d ]", + "[ 1/4 → 1/2 | note:f ]", + "[ 1/2 → 3/4 | note:c ]", + "[ 1/2 → 3/4 | note:g ]", + "[ 3/4 → 1/1 | note:d ]", + "[ 3/4 → 1/1 | note:e ]", + "[ 1/1 → 5/4 | note:c ]", + "[ 1/1 → 5/4 | note:f ]", + "[ 5/4 → 3/2 | note:d ]", + "[ 5/4 → 3/2 | note:g ]", + "[ 3/2 → 7/4 | note:c ]", + "[ 3/2 → 7/4 | note:e ]", + "[ 7/4 → 2/1 | note:d ]", + "[ 7/4 → 2/1 | note:f ]", + "[ 2/1 → 9/4 | note:c ]", + "[ 2/1 → 9/4 | note:g ]", + "[ 9/4 → 5/2 | note:d ]", + "[ 9/4 → 5/2 | note:e ]", + "[ 5/2 → 11/4 | note:c ]", + "[ 5/2 → 11/4 | note:f ]", + "[ 11/4 → 3/1 | note:d ]", + "[ 11/4 → 3/1 | note:g ]", + "[ 3/1 → 13/4 | note:c ]", + "[ 3/1 → 13/4 | note:e ]", + "[ 13/4 → 7/2 | note:d ]", + "[ 13/4 → 7/2 | note:f ]", + "[ 7/2 → 15/4 | note:c ]", + "[ 7/2 → 15/4 | note:g ]", + "[ 15/4 → 4/1 | note:d ]", + "[ 15/4 → 4/1 | note:e ]", ] `; From 1acb675f5ab7709c3f8b06007aa374ff3936c8a0 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 23:12:31 +0200 Subject: [PATCH 16/18] doc: visual functions --- packages/core/controls.mjs | 4 +- packages/draw/pianoroll.mjs | 9 ++- packages/draw/pitchwheel.mjs | 17 +++++ packages/draw/spiral.mjs | 27 +++++++ packages/webaudio/scope.mjs | 2 +- website/src/docs/MiniRepl.jsx | 4 +- website/src/pages/learn/visual-feedback.mdx | 81 ++++++++++++--------- 7 files changed, 104 insertions(+), 40 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 82f943949..94f46f44a 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -392,7 +392,7 @@ export const { loop } = registerControl('loop'); * @synonyms loopb * @example * s("space").loop(1) - * .loopBegin("<0 .125 .25>").scope() + * .loopBegin("<0 .125 .25>")._scope() */ export const { loopBegin, loopb } = registerControl('loopBegin', 'loopb'); /** @@ -405,7 +405,7 @@ export const { loopBegin, loopb } = registerControl('loopBegin', 'loopb'); * @synonyms loope * @example * s("space").loop(1) - * .loopEnd("<1 .75 .5 .25>").scope() + * .loopEnd("<1 .75 .5 .25>")._scope() */ export const { loopEnd, loope } = registerControl('loopEnd', 'loope'); /** diff --git a/packages/draw/pianoroll.mjs b/packages/draw/pianoroll.mjs index d0480ef54..2c6742cdf 100644 --- a/packages/draw/pianoroll.mjs +++ b/packages/draw/pianoroll.mjs @@ -67,6 +67,7 @@ Pattern.prototype.pianoroll = function (options = {}) { * Displays a midi-style piano roll * * @name pianoroll + * @synonyms punchcard * @param {Object} options Object containing all the optional following parameters as key value pairs: * @param {integer} cycles number of cycles to be displayed at the same time - defaults to 4 * @param {number} playhead location of the active notes on the time axis - 0 to 1, defaults to 0.5 @@ -94,7 +95,11 @@ Pattern.prototype.pianoroll = function (options = {}) { * @param {boolean} autorange automatically calculate the minMidi and maxMidi parameters - 0 by default * * @example - * note("C2 A2 G2").euclid(5,8).s('piano').clip(1).color('salmon').pianoroll({vertical:1, labels:1}) + * note("c2 a2 eb2") + * .euclid(5,8) + * .s('sawtooth') + * .lpenv(4).lpf(300) + * ._pianoroll({ labels: 1 }) */ export function pianoroll({ time, @@ -113,7 +118,7 @@ export function pianoroll({ maxMidi = 90, autorange = 0, timeframe: timeframeProp, - fold = 0, + fold = 1, vertical = 0, labels = false, fill = 1, diff --git a/packages/draw/pitchwheel.mjs b/packages/draw/pitchwheel.mjs index 8d3cfe61c..ba76df079 100644 --- a/packages/draw/pitchwheel.mjs +++ b/packages/draw/pitchwheel.mjs @@ -113,6 +113,23 @@ export function pitchwheel({ return; } +/** + * Renders a pitch circle to visualize frequencies within one octave + * @name pitchwheel + * @param {number} hapcircles + * @param {number} circle + * @param {number} edo + * @param {string} root + * @param {number} thickness + * @param {number} hapRadius + * @param {string} mode + * @param {number} margin + * @example + * n("0 .. 12").scale("C:chromatic") + * .s("sawtooth") + * .lpf(500) + * ._pitchwheel() + */ Pattern.prototype.pitchwheel = function (options = {}) { let { ctx = getDrawContext(), id = 1 } = options; return this.tag(id).onPaint((_, time, haps) => diff --git a/packages/draw/spiral.mjs b/packages/draw/spiral.mjs index 22f93f5d2..cebf3d374 100644 --- a/packages/draw/spiral.mjs +++ b/packages/draw/spiral.mjs @@ -125,6 +125,33 @@ function drawSpiral(options) { }); } +/** + * Displays a spiral visual. + * + * @name spiral + * @param {Object} options Object containing all the optional following parameters as key value pairs: + * @param {number} stretch controls the rotations per cycle ratio, where 1 = 1 cycle / 360 degrees + * @param {number} size the diameter of the spiral + * @param {number} thickness line thickness + * @param {string} cap style of line ends: butt (default), round, square + * @param {string} inset number of rotations before spiral starts (default 3) + * @param {string} playheadColor color of playhead, defaults to white + * @param {number} playheadLength length of playhead in rotations, defaults to 0.02 + * @param {number} playheadThickness thickness of playheadrotations, defaults to thickness + * @param {number} padding space around spiral + * @param {number} steady steadyness of spiral vs playhead. 1 = spiral doesn't move, playhead does. + * @param {number} activeColor color of active segment. defaults to foreground of theme + * @param {number} inactiveColor color of inactive segments. defaults to gutterForeground of theme + * @param {boolean} colorizeInactive wether or not to colorize inactive segments, defaults to 0 + * @param {boolean} fade wether or not past and future should fade out. defaults to 1 + * @param {boolean} logSpiral wether or not the spiral should be logarithmic. defaults to 0 + * @example + * note("c2 a2 eb2") + * .euclid(5,8) + * .s('sawtooth') + * .lpenv(4).lpf(300) + * ._spiral({ steady: .96 }) + */ Pattern.prototype.spiral = function (options = {}) { return this.onPaint((ctx, time, haps, drawTime) => drawSpiral({ ctx, time, haps, drawTime, ...options })); }; diff --git a/packages/webaudio/scope.mjs b/packages/webaudio/scope.mjs index fbf4c8fc2..e423b20fc 100644 --- a/packages/webaudio/scope.mjs +++ b/packages/webaudio/scope.mjs @@ -130,7 +130,7 @@ Pattern.prototype.fscope = function (config = {}) { * @param {number} pos y-position relative to screen height. 0 = top, 1 = bottom of screen * @param {number} trigger amplitude value that is used to align the scope. defaults to 0. * @example - * s("sawtooth").scope() + * s("sawtooth")._scope() */ let latestColor = {}; Pattern.prototype.tscope = function (config = {}) { diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index 3559b3412..565484715 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -34,9 +34,9 @@ export function MiniRepl({ }) { const code = tunes ? tunes[0] : tune; const id = useMemo(() => s4(), []); - const canvasId = useMemo(() => `canvas-${id}`, [id]); - autodraw = !!punchcard || !!claviature || !!autodraw; const shouldShowCanvas = !!punchcard; + const canvasId = shouldShowCanvas ? useMemo(() => `canvas-${id}`, [id]) : null; + autodraw = !!punchcard || !!claviature || !!autodraw; drawTime = drawTime ?? punchcard ? [0, 4] : [-2, 2]; if (claviature) { drawTime = [0, 0]; diff --git a/website/src/pages/learn/visual-feedback.mdx b/website/src/pages/learn/visual-feedback.mdx index ed5b16c20..25eae30ce 100644 --- a/website/src/pages/learn/visual-feedback.mdx +++ b/website/src/pages/learn/visual-feedback.mdx @@ -31,55 +31,70 @@ You can change the color as well, even pattern it: .color("cyan magenta")`} /> -## Pianoroll and Punchcard +## Global vs Inline Visuals + +The following functions all come with in 2 variants. + +**Without prefix**: renders the visual to the background of the page: + + + +**With `_` prefix**: renders the visual inside the code. Allows for multiple visuals + + + +Here we see the 2 variants for `punchcard`. The same goes for all others below. +To improve readability the following demos will all use the inline variant. + +## Punchcard / Pianoroll + +These 2 functions render a pianoroll style visual. +The only difference between the 2 is that `pianoroll` will render the pattern directly, +while `punchcard` will also take the transformations into account that occur afterwards: *8") -.scale("/4:minor:pentatonic") -.s("supersaw").lpf(300).lpenv("<4 3 2>*4") -._punchcard()`} + tune={`note("c a f e").color("white") +._punchcard() +.color("cyan")`} autodraw /> +Here, the `color` is still visible in the visual, even if it is applied after `_punchcard`. +On the contrary, the color is not visible when using `_pianoroll`: + *8") -.scale("/4:minor:pentatonic") -.s("supersaw").lpf(300).lpenv("<4 3 2>\*4") -.\_pianoroll()`} + tune={`note("c a f e").color("white") +._pianoroll() +.color("cyan")`} autodraw /> +import Box from '@components/Box.astro'; + +
+ + + +`punchcard` is less resource intensive because it uses the same data as used for the mini notation highlighting. + + + +The visual can be customized by passing options. Those options are the same for both functions. + +What follows is the API doc of all the options you can pass: + + + ## Spiral -*8") -.scale("/4:minor:pentatonic") -.s("supersaw").lpf(300).lpenv("<4 3 2>*4") -._spiral()`} - autodraw -/> + ## Scope -*8") -.scale("/4:minor:pentatonic") -.s("supersaw").lpf(300).lpenv("<4 3 2>*4") -._scope()`} -/> + ## Pitchwheel -*8") -.scale("/4:minor:pentatonic") -.s("supersaw").lpf(300).lpenv("<4 3 2>*4") -._pitchwheel()`} -/> - -{/* */} + From 357fbf8c825076e8eb508536abe22db1e46576e0 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jun 2024 23:14:32 +0200 Subject: [PATCH 17/18] snapshot --- test/__snapshots__/examples.test.mjs.snap | 170 +++++++++++++++++----- test/runtime.mjs | 9 ++ 2 files changed, 139 insertions(+), 40 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 0cd653e3a..3c1e39f8e 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -4042,19 +4042,19 @@ exports[`runs examples > example "loopAtCps" example index 0 1`] = ` exports[`runs examples > example "loopBegin" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | s:space loop:1 loopBegin:0 analyze:1 ]", - "[ 1/1 → 2/1 | s:space loop:1 loopBegin:0.125 analyze:1 ]", - "[ 2/1 → 3/1 | s:space loop:1 loopBegin:0.25 analyze:1 ]", - "[ 3/1 → 4/1 | s:space loop:1 loopBegin:0 analyze:1 ]", + "[ 0/1 → 1/1 | s:space loop:1 loopBegin:0 ]", + "[ 1/1 → 2/1 | s:space loop:1 loopBegin:0.125 ]", + "[ 2/1 → 3/1 | s:space loop:1 loopBegin:0.25 ]", + "[ 3/1 → 4/1 | s:space loop:1 loopBegin:0 ]", ] `; exports[`runs examples > example "loopEnd" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | s:space loop:1 loopEnd:1 analyze:1 ]", - "[ 1/1 → 2/1 | s:space loop:1 loopEnd:0.75 analyze:1 ]", - "[ 2/1 → 3/1 | s:space loop:1 loopEnd:0.5 analyze:1 ]", - "[ 3/1 → 4/1 | s:space loop:1 loopEnd:0.25 analyze:1 ]", + "[ 0/1 → 1/1 | s:space loop:1 loopEnd:1 ]", + "[ 1/1 → 2/1 | s:space loop:1 loopEnd:0.75 ]", + "[ 2/1 → 3/1 | s:space loop:1 loopEnd:0.5 ]", + "[ 3/1 → 4/1 | s:space loop:1 loopEnd:0.25 ]", ] `; @@ -5085,34 +5085,34 @@ exports[`runs examples > example "phasersweep" example index 0 1`] = ` exports[`runs examples > example "pianoroll" example index 0 1`] = ` [ - "[ 0/1 → 1/8 | note:C2 s:piano clip:1 color:salmon ]", - "[ (1/4 → 1/3) ⇝ 3/8 | note:C2 s:piano clip:1 color:salmon ]", - "[ 1/4 ⇜ (1/3 → 3/8) | note:A2 s:piano clip:1 color:salmon ]", - "[ 3/8 → 1/2 | note:A2 s:piano clip:1 color:salmon ]", - "[ (5/8 → 2/3) ⇝ 3/4 | note:A2 s:piano clip:1 color:salmon ]", - "[ 5/8 ⇜ (2/3 → 3/4) | note:G2 s:piano clip:1 color:salmon ]", - "[ 3/4 → 7/8 | note:G2 s:piano clip:1 color:salmon ]", - "[ 1/1 → 9/8 | note:C2 s:piano clip:1 color:salmon ]", - "[ (5/4 → 4/3) ⇝ 11/8 | note:C2 s:piano clip:1 color:salmon ]", - "[ 5/4 ⇜ (4/3 → 11/8) | note:A2 s:piano clip:1 color:salmon ]", - "[ 11/8 → 3/2 | note:A2 s:piano clip:1 color:salmon ]", - "[ (13/8 → 5/3) ⇝ 7/4 | note:A2 s:piano clip:1 color:salmon ]", - "[ 13/8 ⇜ (5/3 → 7/4) | note:G2 s:piano clip:1 color:salmon ]", - "[ 7/4 → 15/8 | note:G2 s:piano clip:1 color:salmon ]", - "[ 2/1 → 17/8 | note:C2 s:piano clip:1 color:salmon ]", - "[ (9/4 → 7/3) ⇝ 19/8 | note:C2 s:piano clip:1 color:salmon ]", - "[ 9/4 ⇜ (7/3 → 19/8) | note:A2 s:piano clip:1 color:salmon ]", - "[ 19/8 → 5/2 | note:A2 s:piano clip:1 color:salmon ]", - "[ (21/8 → 8/3) ⇝ 11/4 | note:A2 s:piano clip:1 color:salmon ]", - "[ 21/8 ⇜ (8/3 → 11/4) | note:G2 s:piano clip:1 color:salmon ]", - "[ 11/4 → 23/8 | note:G2 s:piano clip:1 color:salmon ]", - "[ 3/1 → 25/8 | note:C2 s:piano clip:1 color:salmon ]", - "[ (13/4 → 10/3) ⇝ 27/8 | note:C2 s:piano clip:1 color:salmon ]", - "[ 13/4 ⇜ (10/3 → 27/8) | note:A2 s:piano clip:1 color:salmon ]", - "[ 27/8 → 7/2 | note:A2 s:piano clip:1 color:salmon ]", - "[ (29/8 → 11/3) ⇝ 15/4 | note:A2 s:piano clip:1 color:salmon ]", - "[ 29/8 ⇜ (11/3 → 15/4) | note:G2 s:piano clip:1 color:salmon ]", - "[ 15/4 → 31/8 | note:G2 s:piano clip:1 color:salmon ]", + "[ 0/1 → 1/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (1/4 → 1/3) ⇝ 3/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 1/4 ⇜ (1/3 → 3/8) | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 3/8 → 1/2 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (5/8 → 2/3) ⇝ 3/4 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 5/8 ⇜ (2/3 → 3/4) | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 3/4 → 7/8 | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 1/1 → 9/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (5/4 → 4/3) ⇝ 11/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 5/4 ⇜ (4/3 → 11/8) | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 11/8 → 3/2 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (13/8 → 5/3) ⇝ 7/4 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 13/8 ⇜ (5/3 → 7/4) | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 7/4 → 15/8 | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 2/1 → 17/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (9/4 → 7/3) ⇝ 19/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 9/4 ⇜ (7/3 → 19/8) | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 19/8 → 5/2 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (21/8 → 8/3) ⇝ 11/4 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 21/8 ⇜ (8/3 → 11/4) | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 11/4 → 23/8 | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 3/1 → 25/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (13/4 → 10/3) ⇝ 27/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 13/4 ⇜ (10/3 → 27/8) | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 27/8 → 7/2 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (29/8 → 11/3) ⇝ 15/4 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 29/8 ⇜ (11/3 → 15/4) | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 15/4 → 31/8 | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", ] `; @@ -5234,6 +5234,63 @@ exports[`runs examples > example "pickF" example index 1 1`] = ` ] `; +exports[`runs examples > example "pitchwheel" example index 0 1`] = ` +[ + "[ 0/1 → 1/13 | note:C3 s:sawtooth cutoff:500 ]", + "[ 1/13 → 2/13 | note:Db3 s:sawtooth cutoff:500 ]", + "[ 2/13 → 3/13 | note:D3 s:sawtooth cutoff:500 ]", + "[ 3/13 → 4/13 | note:Eb3 s:sawtooth cutoff:500 ]", + "[ 4/13 → 5/13 | note:E3 s:sawtooth cutoff:500 ]", + "[ 5/13 → 6/13 | note:F3 s:sawtooth cutoff:500 ]", + "[ 6/13 → 7/13 | note:Gb3 s:sawtooth cutoff:500 ]", + "[ 7/13 → 8/13 | note:G3 s:sawtooth cutoff:500 ]", + "[ 8/13 → 9/13 | note:Ab3 s:sawtooth cutoff:500 ]", + "[ 9/13 → 10/13 | note:A3 s:sawtooth cutoff:500 ]", + "[ 10/13 → 11/13 | note:Bb3 s:sawtooth cutoff:500 ]", + "[ 11/13 → 12/13 | note:B3 s:sawtooth cutoff:500 ]", + "[ 12/13 → 1/1 | note:C4 s:sawtooth cutoff:500 ]", + "[ 1/1 → 14/13 | note:C3 s:sawtooth cutoff:500 ]", + "[ 14/13 → 15/13 | note:Db3 s:sawtooth cutoff:500 ]", + "[ 15/13 → 16/13 | note:D3 s:sawtooth cutoff:500 ]", + "[ 16/13 → 17/13 | note:Eb3 s:sawtooth cutoff:500 ]", + "[ 17/13 → 18/13 | note:E3 s:sawtooth cutoff:500 ]", + "[ 18/13 → 19/13 | note:F3 s:sawtooth cutoff:500 ]", + "[ 19/13 → 20/13 | note:Gb3 s:sawtooth cutoff:500 ]", + "[ 20/13 → 21/13 | note:G3 s:sawtooth cutoff:500 ]", + "[ 21/13 → 22/13 | note:Ab3 s:sawtooth cutoff:500 ]", + "[ 22/13 → 23/13 | note:A3 s:sawtooth cutoff:500 ]", + "[ 23/13 → 24/13 | note:Bb3 s:sawtooth cutoff:500 ]", + "[ 24/13 → 25/13 | note:B3 s:sawtooth cutoff:500 ]", + "[ 25/13 → 2/1 | note:C4 s:sawtooth cutoff:500 ]", + "[ 2/1 → 27/13 | note:C3 s:sawtooth cutoff:500 ]", + "[ 27/13 → 28/13 | note:Db3 s:sawtooth cutoff:500 ]", + "[ 28/13 → 29/13 | note:D3 s:sawtooth cutoff:500 ]", + "[ 29/13 → 30/13 | note:Eb3 s:sawtooth cutoff:500 ]", + "[ 30/13 → 31/13 | note:E3 s:sawtooth cutoff:500 ]", + "[ 31/13 → 32/13 | note:F3 s:sawtooth cutoff:500 ]", + "[ 32/13 → 33/13 | note:Gb3 s:sawtooth cutoff:500 ]", + "[ 33/13 → 34/13 | note:G3 s:sawtooth cutoff:500 ]", + "[ 34/13 → 35/13 | note:Ab3 s:sawtooth cutoff:500 ]", + "[ 35/13 → 36/13 | note:A3 s:sawtooth cutoff:500 ]", + "[ 36/13 → 37/13 | note:Bb3 s:sawtooth cutoff:500 ]", + "[ 37/13 → 38/13 | note:B3 s:sawtooth cutoff:500 ]", + "[ 38/13 → 3/1 | note:C4 s:sawtooth cutoff:500 ]", + "[ 3/1 → 40/13 | note:C3 s:sawtooth cutoff:500 ]", + "[ 40/13 → 41/13 | note:Db3 s:sawtooth cutoff:500 ]", + "[ 41/13 → 42/13 | note:D3 s:sawtooth cutoff:500 ]", + "[ 42/13 → 43/13 | note:Eb3 s:sawtooth cutoff:500 ]", + "[ 43/13 → 44/13 | note:E3 s:sawtooth cutoff:500 ]", + "[ 44/13 → 45/13 | note:F3 s:sawtooth cutoff:500 ]", + "[ 45/13 → 46/13 | note:Gb3 s:sawtooth cutoff:500 ]", + "[ 46/13 → 47/13 | note:G3 s:sawtooth cutoff:500 ]", + "[ 47/13 → 48/13 | note:Ab3 s:sawtooth cutoff:500 ]", + "[ 48/13 → 49/13 | note:A3 s:sawtooth cutoff:500 ]", + "[ 49/13 → 50/13 | note:Bb3 s:sawtooth cutoff:500 ]", + "[ 50/13 → 51/13 | note:B3 s:sawtooth cutoff:500 ]", + "[ 51/13 → 4/1 | note:C4 s:sawtooth cutoff:500 ]", +] +`; + exports[`runs examples > example "ply" example index 0 1`] = ` [ "[ 0/1 → 1/4 | s:bd ]", @@ -6554,10 +6611,10 @@ exports[`runs examples > example "scaleTranspose" example index 0 1`] = ` exports[`runs examples > example "scope" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | s:sawtooth analyze:1 ]", - "[ 1/1 → 2/1 | s:sawtooth analyze:1 ]", - "[ 2/1 → 3/1 | s:sawtooth analyze:1 ]", - "[ 3/1 → 4/1 | s:sawtooth analyze:1 ]", + "[ 0/1 → 1/1 | s:sawtooth ]", + "[ 1/1 → 2/1 | s:sawtooth ]", + "[ 2/1 → 3/1 | s:sawtooth ]", + "[ 3/1 → 4/1 | s:sawtooth ]", ] `; @@ -7158,6 +7215,39 @@ exports[`runs examples > example "speed" example index 1 1`] = ` ] `; +exports[`runs examples > example "spiral" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (1/4 → 1/3) ⇝ 3/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 1/4 ⇜ (1/3 → 3/8) | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 3/8 → 1/2 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (5/8 → 2/3) ⇝ 3/4 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 5/8 ⇜ (2/3 → 3/4) | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 3/4 → 7/8 | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 1/1 → 9/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (5/4 → 4/3) ⇝ 11/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 5/4 ⇜ (4/3 → 11/8) | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 11/8 → 3/2 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (13/8 → 5/3) ⇝ 7/4 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 13/8 ⇜ (5/3 → 7/4) | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 7/4 → 15/8 | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 2/1 → 17/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (9/4 → 7/3) ⇝ 19/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 9/4 ⇜ (7/3 → 19/8) | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 19/8 → 5/2 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (21/8 → 8/3) ⇝ 11/4 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 21/8 ⇜ (8/3 → 11/4) | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 11/4 → 23/8 | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 3/1 → 25/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (13/4 → 10/3) ⇝ 27/8 | note:c2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 13/4 ⇜ (10/3 → 27/8) | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 27/8 → 7/2 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ (29/8 → 11/3) ⇝ 15/4 | note:a2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 29/8 ⇜ (11/3 → 15/4) | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", + "[ 15/4 → 31/8 | note:eb2 s:sawtooth lpenv:4 cutoff:300 ]", +] +`; + exports[`runs examples > example "splice" example index 0 1`] = ` [ "[ 0/1 → 1/8 | speed:1 unit:c begin:0 end:0.125 _slices:8 s:breaks165 ]", diff --git a/test/runtime.mjs b/test/runtime.mjs index 7b9350ebd..ca92b1968 100644 --- a/test/runtime.mjs +++ b/test/runtime.mjs @@ -125,6 +125,15 @@ strudel.Pattern.prototype.midi = function () { strudel.Pattern.prototype._scope = function () { return this; }; +strudel.Pattern.prototype._spiral = function () { + return this; +}; +strudel.Pattern.prototype._pitchwheel = function () { + return this; +}; +strudel.Pattern.prototype._pianoroll = function () { + return this; +}; const uiHelpersMocked = { backgroundImage: id, From 300022d8ac2b1ed6dfd55f47fe5b11c883694bb3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 3 Jun 2024 20:34:51 +0200 Subject: [PATCH 18/18] no custom line height --- packages/codemirror/themes/algoboy.mjs | 2 +- packages/codemirror/themes/teletext.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/codemirror/themes/algoboy.mjs b/packages/codemirror/themes/algoboy.mjs index eba95b98f..fd7db580b 100644 --- a/packages/codemirror/themes/algoboy.mjs +++ b/packages/codemirror/themes/algoboy.mjs @@ -12,7 +12,7 @@ export const settings = { gutterBackground: 'transparent', gutterForeground: '#0f380f', light: true, - customStyle: '.cm-line { line-height: 1 }', + // customStyle: '.cm-line { line-height: 1 }', }; export default createTheme({ theme: 'light', diff --git a/packages/codemirror/themes/teletext.mjs b/packages/codemirror/themes/teletext.mjs index ddbf7b330..630329c10 100644 --- a/packages/codemirror/themes/teletext.mjs +++ b/packages/codemirror/themes/teletext.mjs @@ -17,7 +17,7 @@ export const settings = { lineBackground: '#00000040', gutterBackground: 'transparent', gutterForeground: '#8a919966', - customStyle: '.cm-line { line-height: 1 }', + // customStyle: '.cm-line { line-height: 1 }', }; let punctuation = colorD;