Compare commits

...

5 Commits

Author SHA1 Message Date
eefano 06463da7fb Merge remote-tracking branch 'upstream/main' into start-and-loop-at-cycle 2025-02-07 17:40:01 +01:00
eefano 2a0e66a862 Merge remote-tracking branch 'upstream/main' into start-and-loop-at-cycle 2025-02-07 17:38:17 +01:00
eefano 9c37725436 Merge remote-tracking branch 'upstream/main' into start-and-loop-at-cycle 2024-10-21 17:45:38 +02:00
eefano 06f3696ab0 Merge remote-tracking branch 'upstream/main' into start-and-loop-at-cycle 2024-07-31 11:40:24 +02:00
eefano a4c4c6025c start-and-loop
Adds setLoop(start, length) and cyclecounter() widget.
2024-07-03 11:21:04 +02:00
5 changed files with 45 additions and 1 deletions
+5
View File
@@ -140,3 +140,8 @@ registerWidget('_spectrum', (id, options = {}, pat) => {
const ctx = getCanvasWidget(id, options).getContext('2d');
return pat.spectrum({ ...options, ctx, id });
});
registerWidget('_cyclecounter', (id, options = {}, pat) => {
const ctx = getCanvasWidget(id, options).getContext('2d');
return pat.cyclecounter({ ...options, ctx, id });
});
+20 -1
View File
@@ -23,6 +23,8 @@ export class Cyclist {
this.beforeStart = beforeStart;
this.cps = 0.5;
this.num_ticks_since_cps_change = 0;
this.loopStart = 0;
this.loopLength = 0;
this.lastTick = 0; // absolute time when last tick (clock callback) happened
this.lastBegin = 0; // query begin of last tick
this.lastEnd = 0; // query end of last tick
@@ -48,6 +50,10 @@ export class Cyclist {
this.lastBegin = begin;
const end = this.num_cycles_at_cps_change + num_cycles_since_cps_change;
this.lastEnd = end;
if (this.loopLength > 0 && this.lastEnd >= this.loopStart + this.loopLength) {
this.lastEnd = this.loopStart + (this.lastEnd % 1);
this.num_ticks_since_cps_change = 0;
}
this.lastTick = phase;
if (phase < t) {
@@ -116,7 +122,7 @@ export class Cyclist {
stop() {
logger('[cyclist] stop');
this.clock.stop();
this.lastEnd = 0;
this.lastEnd = this.loopStart;
this.setStarted(false);
}
async setPattern(pat, autostart = false) {
@@ -132,6 +138,19 @@ export class Cyclist {
this.cps = cps;
this.num_ticks_since_cps_change = 0;
}
setLoop(start = 0, length = 0) {
if (start >= 0 && length >= 0) {
start = Math.floor(start);
length = Math.floor(length);
if (start != this.loopStart || length != this.loopLength) {
this.loopStart = Math.floor(start);
this.loopLength = Math.floor(length);
this.lastEnd = this.loopStart + (this.lastEnd % 1);
this.num_ticks_since_cps_change = 0;
}
}
}
log(begin, end, haps) {
const onsets = haps.filter((h) => h.hasOnset());
console.log(`${begin.toFixed(4)} - ${end.toFixed(4)} ${Array(onsets.length).fill('I').join('')}`);
+3
View File
@@ -86,6 +86,7 @@ export function repl({
const toggle = () => scheduler.toggle();
const setCps = (cps) => scheduler.setCps(cps);
const setCpm = (cpm) => scheduler.setCps(cpm / 60);
const setLoop = (start, length) => scheduler.setLoop(start, length);
// TODO - not documented as jsdoc examples as the test framework doesn't simulate enough context for `each` and `all`..
@@ -167,6 +168,8 @@ export function repl({
setcps: setCps,
setCpm,
setcpm: setCpm,
setLoop,
setloop: setLoop,
});
};
+16
View File
@@ -0,0 +1,16 @@
import { Pattern } from '@strudel/core';
Pattern.prototype.cyclecounter = function (options = {}) {
return this.onPaint((ctx, time, haps, drawTime) => {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.font = options.font || '2em monospace';
ctx.fillStyle = options.color || 'red';
ctx.textBaseline = 'bottom';
ctx.textAlign = 'right';
const div = options.div || 1;
ctx.fillText('Cycle' + (div > 1 ? '/' + div : '') + ' ' + ((time / div) >> 0), ctx.canvas.width, ctx.canvas.height);
});
};
+1
View File
@@ -4,3 +4,4 @@ export * from './draw.mjs';
export * from './pianoroll.mjs';
export * from './spiral.mjs';
export * from './pitchwheel.mjs';
export * from './cyclecounter.mjs';