diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index e59249ee..5602a052 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -128,6 +128,7 @@ export class StrudelMirror { id, initialCode = '', onDraw, + drawContext, drawTime = [0, 0], autodraw, prebake, @@ -140,13 +141,14 @@ export class StrudelMirror { this.widgets = []; this.painters = []; this.drawTime = drawTime; - this.onDraw = onDraw; + this.drawContext = drawContext; + this.onDraw = onDraw || this.draw; this.id = id || s4(); this.drawer = new Drawer((haps, time) => { - const currentFrame = haps.filter((hap) => time >= hap.whole.begin && time <= hap.endClipped); + const currentFrame = haps.filter((hap) => hap.isActive(time)); this.highlight(currentFrame, time); - this.onDraw?.(haps, time, currentFrame, this.painters); + this.onDraw(haps, time, this.painters); }, drawTime); this.prebaked = prebake(); @@ -236,6 +238,9 @@ export class StrudelMirror { // 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)); + } async drawFirstFrame() { if (!this.onDraw) { return; @@ -246,7 +251,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.painters); } catch (err) { console.warn('first frame could not be painted'); } diff --git a/packages/core/hap.mjs b/packages/core/hap.mjs index 7f35ce55..5488a638 100644 --- a/packages/core/hap.mjs +++ b/packages/core/hap.mjs @@ -50,7 +50,7 @@ export class Hap { } isActive(currentTime) { - return this.whole.begin <= currentTime && this.endClipped > currentTime; + return this.whole.begin <= currentTime && this.endClipped >= currentTime; } isInPast(currentTime) { diff --git a/packages/draw/pianoroll.mjs b/packages/draw/pianoroll.mjs index f24f6114..310bfd70 100644 --- a/packages/draw/pianoroll.mjs +++ b/packages/draw/pianoroll.mjs @@ -277,8 +277,8 @@ export function getDrawOptions(drawTime, options = {}) { export const getPunchcardPainter = (options = {}) => - (ctx, time, haps, drawTime, paintOptions = {}) => - pianoroll({ ctx, time, haps, ...getDrawOptions(drawTime, { ...paintOptions, ...options }) }); + (ctx, time, haps, drawTime) => + pianoroll({ ctx, time, haps, ...getDrawOptions(drawTime, options) }); Pattern.prototype.punchcard = function (options) { return this.onPaint(getPunchcardPainter(options)); diff --git a/packages/repl/repl-component.mjs b/packages/repl/repl-component.mjs index 4fa8d6d2..e6e0ee0e 100644 --- a/packages/repl/repl-component.mjs +++ b/packages/repl/repl-component.mjs @@ -41,17 +41,8 @@ if (typeof HTMLElement !== 'undefined') { initialCode: '// LOADING', pattern: silence, drawTime, - onDraw: (haps, time, frame, painters) => { - painters.length && drawContext.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2); - painters?.forEach((painter) => { - // ctx time haps drawTime paintOptions - painter(drawContext, time, haps, drawTime, { clear: false }); - }); - }, + drawContext, prebake, - afterEval: ({ code }) => { - // window.location.hash = '#' + code2hash(code); - }, onUpdateState: (state) => { const event = new CustomEvent('update', { detail: state, diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index fe618965..cadebcb3 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -39,16 +39,6 @@ export function MiniRepl({ const init = useCallback(({ code, shouldDraw }) => { const drawContext = shouldDraw ? document.querySelector('#' + canvasId)?.getContext('2d') : null; - let onDraw; - if (shouldDraw) { - onDraw = (haps, time, frame, painters) => { - painters.length && drawContext?.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2); - painters?.forEach((painter) => { - // ctx time haps drawTime paintOptions - painter(drawContext, time, haps, drawTime, { clear: false }); - }); - }; - } const editor = new StrudelMirror({ id, @@ -60,7 +50,7 @@ export function MiniRepl({ initialCode: '// LOADING', pattern: silence, drawTime, - onDraw, + drawContext, editPattern: (pat, id) => { if (onTrigger) { pat = pat.onTrigger(onTrigger, false); diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 786aad66..b5439846 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -65,13 +65,6 @@ export function Repl({ embedded = false }) { const init = useCallback(() => { const drawTime = [-2, 2]; const drawContext = getDrawContext(); - const onDraw = (haps, time, frame, painters) => { - painters.length && drawContext.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2); - painters?.forEach((painter) => { - // ctx time haps drawTime paintOptions - painter(drawContext, time, haps, drawTime, { clear: false }); - }); - }; const editor = new StrudelMirror({ sync: true, defaultOutput: webaudioOutput, @@ -84,7 +77,7 @@ export function Repl({ embedded = false }) { initialCode: '// LOADING', pattern: silence, drawTime, - onDraw, + drawContext, prebake: async () => Promise.all([modulesLoading, presets]), onUpdateState: (state) => { setReplState({ ...state });