From 9e2e5ce581840b4d6c69aadfc19990174f036ba9 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 23 Apr 2022 23:28:43 +0200 Subject: [PATCH] log + drawLine --- packages/core/drawLine.mjs | 24 ++++++++++++++++++++++++ packages/core/fraction.mjs | 6 ++++++ packages/core/hap.mjs | 2 +- packages/core/pattern.mjs | 27 ++++++++++++++++++++++++++- packages/core/test/fraction.test.mjs | 9 +++++++++ repl/src/useRepl.mjs | 5 ++++- 6 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 packages/core/drawLine.mjs create mode 100644 packages/core/test/fraction.test.mjs diff --git a/packages/core/drawLine.mjs b/packages/core/drawLine.mjs new file mode 100644 index 00000000..73fac46b --- /dev/null +++ b/packages/core/drawLine.mjs @@ -0,0 +1,24 @@ +import { gcd } from './fraction.mjs'; + +function drawLine(pat) { + let s = ''; + let c = 0; + while (s.length < 60) { + const haps = pat.queryArc(c, c + 1); + const durations = haps.map((hap) => hap.duration); + const totalSlots = gcd(...durations).inverse(); + haps.forEach((hap) => { + const duration = hap.whole.end.sub(hap.whole.begin); + const slots = totalSlots.mul(duration); + s += Array(slots.valueOf()) + .fill() + .map((_, i) => (!i ? hap.value : '-')) + .join(''); + }); + s += '|'; + ++c; + } + return s; +} + +export default drawLine; diff --git a/packages/core/fraction.mjs b/packages/core/fraction.mjs index 4fe2b12a..3b43f3a6 100644 --- a/packages/core/fraction.mjs +++ b/packages/core/fraction.mjs @@ -72,6 +72,12 @@ const fraction = (n) => { return Fraction(n); }; +export const gcd = (...fractions) => { + return fractions.reduce((gcd, fraction) => gcd.gcd(fraction), fraction(1)); +}; + +fraction._original = Fraction; + export default fraction; // "If you concern performance, cache Fraction.js objects and pass arrays/objects.“ diff --git a/packages/core/hap.mjs b/packages/core/hap.mjs index 44ff7ba0..e1ad05f1 100644 --- a/packages/core/hap.mjs +++ b/packages/core/hap.mjs @@ -24,7 +24,7 @@ export class Hap { } get duration() { - return this.whole.end.sub(this.whole.begin).valueOf(); + return this.whole.end.sub(this.whole.begin); } wholeOrPart() { diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index b5879d1d..51943b8a 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -4,6 +4,7 @@ import Hap from './hap.mjs'; import State from './state.mjs'; import { isNote, toMidi, compose, removeUndefineds, flatten, id, listRange, curry, mod } from './util.mjs'; +import drawLine from './drawLine.mjs'; export class Pattern { // the following functions will get patternFactories as nested functions: @@ -563,6 +564,17 @@ export class Pattern { return this._withContext((context) => ({ ...context, color })); } + log() { + return this._withEvent((e) => { + return e.setContext({ ...e.context, logs: (e.context?.logs || []).concat([e.show()]) }); + }); + } + + drawLine() { + console.log(drawLine(this)); + return this; + } + _segment(rate) { return this.struct(pure(true)._fast(rate)); } @@ -803,7 +815,20 @@ Pattern.prototype.patternified = [ 'velocity', ]; // methods that create patterns, which are added to patternified Pattern methods -Pattern.prototype.factories = { pure, stack, slowcat, fastcat, cat, timeCat, sequence, seq, polymeter, pm, polyrhythm, pr }; +Pattern.prototype.factories = { + pure, + stack, + slowcat, + fastcat, + cat, + timeCat, + sequence, + seq, + polymeter, + pm, + polyrhythm, + pr, +}; // the magic happens in Pattern constructor. Keeping this in prototype enables adding methods from the outside (e.g. see tonal.ts) // Elemental patterns diff --git a/packages/core/test/fraction.test.mjs b/packages/core/test/fraction.test.mjs new file mode 100644 index 00000000..90d3ac76 --- /dev/null +++ b/packages/core/test/fraction.test.mjs @@ -0,0 +1,9 @@ +import Fraction, { gcd } from '../fraction.mjs'; +import { strict as assert } from 'assert'; + +describe('gcd', () => { + it('should work', () => { + const F = Fraction._original; + assert.equal(gcd(F(1 / 6), F(1 / 4)).toFraction(), '1/12'); + }); +}); diff --git a/repl/src/useRepl.mjs b/repl/src/useRepl.mjs index c20a9cba..d48aa141 100644 --- a/repl/src/useRepl.mjs +++ b/repl/src/useRepl.mjs @@ -29,7 +29,7 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { return onDraw; } }, [activeCode, onDraw]); - + // cycle hook to control scheduling const cycle = useCycle({ onDraw, @@ -37,6 +37,9 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { (time, event, currentTime) => { try { onEvent?.(event); + if (event.context.logs?.length) { + event.context.logs.forEach(pushLog); + } const { onTrigger, velocity } = event.context; if (!onTrigger) { if (defaultSynth) {