diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index c06ac4a0..e59249ee 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -141,7 +141,6 @@ export class StrudelMirror { this.painters = []; this.drawTime = drawTime; this.onDraw = onDraw; - const self = this; this.id = id || s4(); this.drawer = new Drawer((haps, time) => { @@ -150,13 +149,6 @@ export class StrudelMirror { this.onDraw?.(haps, time, currentFrame, this.painters); }, drawTime); - // this approach does not work with multiple repls on screen - // TODO: refactor onPaint usages + find fix, maybe remove painters here? - Pattern.prototype.onPaint = function (onPaint) { - self.painters.push(onPaint); - return this; - }; - this.prebaked = prebake(); autodraw && this.drawFirstFrame(); @@ -182,6 +174,14 @@ export class StrudelMirror { beforeEval: async () => { cleanupDraw(); 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?.(); }, diff --git a/packages/codemirror/widget.mjs b/packages/codemirror/widget.mjs index facfe1c2..98d78b36 100644 --- a/packages/codemirror/widget.mjs +++ b/packages/codemirror/widget.mjs @@ -106,17 +106,23 @@ function getCanvasWidget(id, options = {}) { registerWidget('_pianoroll', (id, options = {}, pat) => { const ctx = getCanvasWidget(id, options).getContext('2d'); - return pat.pianoroll({ fold: 1, ...options, ctx, id }); + return pat.id(id).pianoroll({ fold: 1, ...options, ctx, id }); }); -/* registerWidget('_spiral', (id, options = {}, pat) => { - options = { width: 200, height: 200, size: 36, ...options }; +registerWidget('_punchcard', (id, options = {}, pat) => { const ctx = getCanvasWidget(id, options).getContext('2d'); - return pat.spiral({ ...options, ctx, id }); -}); */ + return pat.id(id).punchcard({ fold: 1, ...options, ctx, id }); +}); + +registerWidget('_spiral', (id, options = {}, pat) => { + let _size = options.size || 275; + options = { width: _size, height: _size, ...options, size: _size / 5 }; + const ctx = getCanvasWidget(id, options).getContext('2d'); + return pat.id(id).spiral({ ...options, ctx, id }); +}); registerWidget('_scope', (id, options = {}, pat) => { options = { width: 500, height: 60, pos: 0.5, scale: 1, ...options }; const ctx = getCanvasWidget(id, options).getContext('2d'); - return pat.scope({ ...options, ctx, id }); + return pat.id(id).scope({ ...options, ctx, id }); }); diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 38748f4a..234042ac 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2476,6 +2476,16 @@ export const hsl = register('hsl', (h, s, l, pat) => { return pat.color(`hsl(${h}turn,${s * 100}%,${l * 100}%)`); }); +/** + * Sets the id of the hap in, for filtering in the future. + * @name id + * @noAutocomplete + * @param {string} id anything unique + */ +Pattern.prototype.id = function (id) { + return this.withContext((ctx) => ({ ...ctx, id })); +}; + ////////////////////////////////////////////////////////////////////// // Control-related functions, i.e. ones that manipulate patterns of // objects diff --git a/packages/draw/draw.mjs b/packages/draw/draw.mjs index 4e84878f..0b5a1a4f 100644 --- a/packages/draw/draw.mjs +++ b/packages/draw/draw.mjs @@ -96,9 +96,8 @@ export const cleanupDraw = (clearScreen = true) => { } }; -Pattern.prototype.onPaint = function (onPaint) { - // this is evil! TODO: add pattern.context - this.context = { onPaint }; +Pattern.prototype.onPaint = function () { + console.warn('[draw] onPaint was not overloaded. Some drawings might not work'); return this; }; diff --git a/packages/draw/pianoroll.mjs b/packages/draw/pianoroll.mjs index 272793e2..f24f6114 100644 --- a/packages/draw/pianoroll.mjs +++ b/packages/draw/pianoroll.mjs @@ -129,12 +129,17 @@ export function pianoroll({ colorizeInactive = 1, fontFamily, ctx, + id, } = {}) { const w = ctx.canvas.width; const h = ctx.canvas.height; let from = -cycles * playhead; let to = cycles * (1 - playhead); + if (id) { + haps = haps.filter((hap) => hap.context.id === id); + } + if (timeframeProp) { console.warn('timeframe is deprecated! use from/to instead'); from = 0; diff --git a/packages/draw/spiral.mjs b/packages/draw/spiral.mjs index 4762e843..e0104c29 100644 --- a/packages/draw/spiral.mjs +++ b/packages/draw/spiral.mjs @@ -19,7 +19,7 @@ function spiralSegment(options) { cy = 100, rotate = 0, thickness = margin / 2, - color = '#0000ff30', + color = 'steelblue', cap = 'round', stretch = 1, fromOpacity = 1, @@ -50,18 +50,18 @@ function spiralSegment(options) { } function drawSpiral(options) { - const { + let { stretch = 1, size = 80, thickness = size / 2, cap = 'butt', // round butt squar, inset = 3, // start angl, - playheadColor = '#ffffff90', + playheadColor = '#ffffff', playheadLength = 0.02, playheadThickness = thickness, padding = 0, steady = 1, - inactiveColor = '#ffffff20', + inactiveColor = '#ffffff50', colorizeInactive = 0, fade = true, // logSpiral = true, @@ -69,8 +69,13 @@ function drawSpiral(options) { time, haps, drawTime, + id, } = options; + if (id) { + haps = haps.filter((hap) => hap.context.id === id); + } + const [w, h] = [ctx.canvas.width, ctx.canvas.height]; ctx.clearRect(0, 0, w * 2, h * 2); const [cx, cy] = [w / 2, h / 2]; @@ -97,7 +102,7 @@ function drawSpiral(options) { const isActive = hap.whole.begin <= time && hap.endClipped > time; const from = hap.whole.begin - time + inset; const to = hap.endClipped - time + inset - padding; - const { color } = hap.context; + const color = hap.value?.color; const opacity = fade ? 1 - Math.abs((hap.whole.begin - time) / min) : 1; spiralSegment({ ctx,