diff --git a/packages/core/drawLine.mjs b/packages/core/drawLine.mjs index cf380fd2..2fcdb07d 100644 --- a/packages/core/drawLine.mjs +++ b/packages/core/drawLine.mjs @@ -1,32 +1,25 @@ -import { gcd } from './fraction.mjs'; +import Fraction, { gcd } from './fraction.mjs'; function drawLine(pat, chars = 60) { - let c = 0; + let cycle = 0; + let pos = Fraction(0); let lines = ['']; + let emptyLine = ''; // this will be the "reference" empty line, which will be copied into extra lines const slots = []; while (lines[0].length < chars) { - const haps = pat.queryArc(c, c + 1); + const haps = pat.queryArc(cycle, cycle + 1); const durations = haps.filter((hap) => hap.hasOnset()).map((hap) => hap.duration); - const totalSlots = gcd(...durations).inverse(); - slots.push(totalSlots); - const minDuration = durations.reduce((a, b) => a.min(b), durations[0]); - lines = lines.map((line) => line + '|'); - + const totalSlots = gcd(...durations).inverse(); // number of character slots for the current cycle + slots.push(totalSlots); // remember slots for possible empty lines needed in a later cycle + const minDuration = durations.reduce((a, b) => a.min(b), durations[0]); // min duration = step length + lines = lines.map((line) => line + '|'); // add pipe character before each cycle + emptyLine += '|'; for (let i = 0; i < totalSlots; i++) { - const step = c * totalSlots + i; - const [begin, end] = [minDuration.mul(step), minDuration.mul(step + 1)]; + const [begin, end] = [pos, pos.add(minDuration)]; const matches = haps.filter((hap) => hap.whole.begin.lte(begin) && hap.whole.end.gte(end)); const missingLines = matches.length - lines.length; if (missingLines > 0) { - console.log(c, 'missingLines', missingLines); - const emptyCycles = - '|' + - new Array(c) - .fill() - .map((_, l) => Array(slots[l]).fill('.').join('')) - .join('|') + - Array(i).fill('.').join(''); - lines = lines.concat(Array(missingLines).fill(emptyCycles)); + lines = lines.concat(Array(missingLines).fill(emptyLine)); } lines = lines.map((line, i) => { const hap = matches[i]; @@ -37,8 +30,10 @@ function drawLine(pat, chars = 60) { } return line + '.'; }); + emptyLine += '.'; + pos = pos.add(minDuration); } - c++; + cycle++; } return lines.join('\n'); } diff --git a/packages/core/test/drawLine.test.mjs b/packages/core/test/drawLine.test.mjs index f7b4fca3..49575755 100644 --- a/packages/core/test/drawLine.test.mjs +++ b/packages/core/test/drawLine.test.mjs @@ -1,12 +1,19 @@ -import { fastcat, stack } from '../pattern.mjs'; +import { fastcat, stack, slowcat } from '../pattern.mjs'; import { strict as assert } from 'assert'; import drawLine from '../drawLine.mjs'; describe('drawLine', () => { - it('should work', () => { + it('supports equal lengths', () => { + assert.equal(drawLine(fastcat(0), 4), '|0|0'); + assert.equal(drawLine(fastcat(0, 1), 4), '|01|01'); + assert.equal(drawLine(fastcat(0, 1, 2), 6), '|012|012'); + }); + it('supports unequal lengths', () => { assert.equal(drawLine(fastcat(0, [1, 2]), 10), '|0-12|0-12'); assert.equal(drawLine(fastcat(0, [1, 2, 3]), 10), '|0--123|0--123'); assert.equal(drawLine(fastcat(0, 1, [2, 3]), 10), '|0-1-23|0-1-23'); + }); + it('supports multiple lines', () => { assert.equal( drawLine(fastcat(0, stack(1, 2)), 10), `|01|01|01|01 @@ -30,4 +37,7 @@ describe('drawLine', () => { |..4|..4|..4`, ); }); + it('supports unequal cycle lengths', () => { + assert.equal(drawLine(slowcat(0, [1, 2]), 10), `|0|12|0|12`); + }); });