mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-13 22:35:15 -04:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 06463da7fb | |||
| 2a0e66a862 | |||
| 9c37725436 | |||
| 06f3696ab0 | |||
| a4c4c6025c |
@@ -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 });
|
||||
});
|
||||
|
||||
@@ -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('')}`);
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
};
|
||||
@@ -4,3 +4,4 @@ export * from './draw.mjs';
|
||||
export * from './pianoroll.mjs';
|
||||
export * from './spiral.mjs';
|
||||
export * from './pitchwheel.mjs';
|
||||
export * from './cyclecounter.mjs';
|
||||
|
||||
Reference in New Issue
Block a user