From ab2cfdeeec8840357abde9248a796060a1aa2f44 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 9 Feb 2022 21:18:53 +0000 Subject: [PATCH 1/3] attempt at fastGap, with failing test --- strudel.mjs | 21 +++++++++++++++++++++ test/pattern.test.mjs | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/strudel.mjs b/strudel.mjs index c08519a9..1c249711 100644 --- a/strudel.mjs +++ b/strudel.mjs @@ -426,6 +426,27 @@ class Pattern { return patterned } + _fastGap (factor) { + // Maybe it's better without this fallback.. + // if (factor < 1) { + // // there is no gap.. so maybe revert to _fast? + // return this._fast(factor) + // } + const qf = function(span) { + const cycle = span.begin.sam() + const begin = cycle.add(span.begin.sub(span.cycle).mul(factor).min(1)) + const end = cycle.add(span.end.sub(span.cycle).mul(factor).min(1)) + return new TimeSpan(begin, end) + } + const ef = function(span) { + const cycle = span.begin.sam() + const begin = cycle.add(span.begin.sub(span.cycle).div(factor).min(1)) + const end = cycle.add(span.end.sub(span.cycle).div(factor).min(1)) + return new TimeSpan(begin, end) + } + return this.withQuerySpan(qf).withEventSpan(ef)._splitQueries() + } + _fast(factor) { const fastQuery = this.withQueryTime(t => t.mul(factor)) return fastQuery.withEventTime(t => t.div(factor)) diff --git a/test/pattern.test.mjs b/test/pattern.test.mjs index bd13c4d3..b1afb3d9 100644 --- a/test/pattern.test.mjs +++ b/test/pattern.test.mjs @@ -89,6 +89,24 @@ describe('Pattern', function() { assert.equal(pure("a")._fast(2).firstCycle.length, 2) }) }) + describe('_fastGap()', function () { + it('Makes things faster, with a gap', function () { + assert.deepStrictEqual( + sequence("a", "b", "c")._fastGap(2).firstCycle, + sequence(["a","b","c"], silence).firstCycle + ) + assert.deepStrictEqual( + sequence("a", "b", "c")._fastGap(3).firstCycle, + sequence(["a","b","c"], silence, silence).firstCycle + ) + }) + it('Makes things faster, with a gap, when speeded up further', function () { + assert.deepStrictEqual( + sequence("a", "b", "c")._fastGap(2).fast(2).firstCycle, + sequence(["a","b","c"], silence, ["a","b","c"], silence).firstCycle + ) + }) + }) describe('fast()', function () { it('Makes things faster', function () { assert.equal(pure("a").fast(2).firstCycle.length, 2) From f5fb5857df58513aa2d7f76a6c6a0b1eabdcea4e Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 9 Feb 2022 22:41:44 +0000 Subject: [PATCH 2/3] fix _fastGap, add compressSpan --- strudel.mjs | 18 ++++++++++++++---- test/pattern.test.mjs | 11 +++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/strudel.mjs b/strudel.mjs index 1c249711..0bb4fecb 100644 --- a/strudel.mjs +++ b/strudel.mjs @@ -434,19 +434,29 @@ class Pattern { // } const qf = function(span) { const cycle = span.begin.sam() - const begin = cycle.add(span.begin.sub(span.cycle).mul(factor).min(1)) - const end = cycle.add(span.end.sub(span.cycle).mul(factor).min(1)) + const begin = cycle.add(span.begin.sub(cycle).mul(factor).min(1)) + const end = cycle.add(span.end.sub(cycle).mul(factor).min(1)) return new TimeSpan(begin, end) } const ef = function(span) { const cycle = span.begin.sam() - const begin = cycle.add(span.begin.sub(span.cycle).div(factor).min(1)) - const end = cycle.add(span.end.sub(span.cycle).div(factor).min(1)) + const begin = cycle.add(span.begin.sub(cycle).div(factor).min(1)) + const end = cycle.add(span.end.sub(cycle).div(factor).min(1)) return new TimeSpan(begin, end) } return this.withQuerySpan(qf).withEventSpan(ef)._splitQueries() } + _compressSpan(span) { + const b = span.begin + const e = span.end + if (b > e || b > 1 || e > 1 || b < 0 || e < 0) { + return silence + } + return this._fastGap(Fraction(1).div(e.sub(b)))._late(b) + } + + _fast(factor) { const fastQuery = this.withQueryTime(t => t.mul(factor)) return fastQuery.withEventTime(t => t.div(factor)) diff --git a/test/pattern.test.mjs b/test/pattern.test.mjs index b1afb3d9..8dbb33a3 100644 --- a/test/pattern.test.mjs +++ b/test/pattern.test.mjs @@ -3,6 +3,9 @@ import Fraction from 'fraction.js' import { strict as assert } from 'assert'; import {TimeSpan, Hap, Pattern, pure, stack, fastcat, slowcat, cat, sequence, polyrhythm, silence, fast} from "../strudel.mjs"; +//import { Time } from 'tone'; +import pkg from 'tone'; +const { Time } = pkg; const ts = (begin, end) => new TimeSpan(Fraction(begin), Fraction(end)); const hap = (whole, part, value) => new Hap(whole, part, value) @@ -107,6 +110,14 @@ describe('Pattern', function() { ) }) }) + describe('_compressSpan()', function () { + it('Can squash cycles of a pattern into a given timespan', function () { + assert.deepStrictEqual( + pure("a")._compressSpan(new TimeSpan(0.25, 0.5)).firstCycle, + sequence(silence, "a", silence, silence).firstCycle + ) + }) + }) describe('fast()', function () { it('Makes things faster', function () { assert.equal(pure("a").fast(2).firstCycle.length, 2) From 5b8c34e50444cf275c5039226f80436cc7954ce0 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 9 Feb 2022 23:50:06 +0000 Subject: [PATCH 3/3] timeCat seems to work --- strudel.mjs | 15 +++++++++++++-- test/pattern.test.mjs | 10 +++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/strudel.mjs b/strudel.mjs index 0bb4fecb..5eaa8a20 100644 --- a/strudel.mjs +++ b/strudel.mjs @@ -456,7 +456,6 @@ class Pattern { return this._fastGap(Fraction(1).div(e.sub(b)))._late(b) } - _fast(factor) { const fastQuery = this.withQueryTime(t => t.mul(factor)) return fastQuery.withEventTime(t => t.div(factor)) @@ -604,6 +603,18 @@ function cat(...pats) { return fastcat(...pats) } +function timeCat(...timepats) { + const total = timepats.map(a => a[0]).reduce((a,b) => a.add(b), Fraction(0)) + let begin = Fraction(0) + const pats = [] + for (const [time, pat] of timepats) { + const end = begin.add(time) + pats.push(reify(pat)._compressSpan(new TimeSpan(begin.div(total), end.div(total)))) + begin = end + } + return stack(...pats) +} + function _sequenceCount(x) { if(Array.isArray(x)) { if (x.length == 0) { @@ -670,7 +681,7 @@ const late = curry((a, pat) => pat.late(a)) const rev = pat => pat.rev() export {Fraction, TimeSpan, Hap, Pattern, - pure, stack, slowcat, fastcat, cat, sequence, polymeter, pm, polyrhythm, pr, reify, silence, + pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr, reify, silence, fast, slow, early, late, rev } diff --git a/test/pattern.test.mjs b/test/pattern.test.mjs index 8dbb33a3..f234ad77 100644 --- a/test/pattern.test.mjs +++ b/test/pattern.test.mjs @@ -2,7 +2,7 @@ import Fraction from 'fraction.js' import { strict as assert } from 'assert'; -import {TimeSpan, Hap, Pattern, pure, stack, fastcat, slowcat, cat, sequence, polyrhythm, silence, fast} from "../strudel.mjs"; +import {TimeSpan, Hap, Pattern, pure, stack, fastcat, slowcat, cat, sequence, polyrhythm, silence, fast, timeCat} from "../strudel.mjs"; //import { Time } from 'tone'; import pkg from 'tone'; const { Time } = pkg; @@ -224,4 +224,12 @@ describe('Pattern', function() { ) }) }) + describe('timeCat()', function() { + it('Can concatenate patterns with different relative durations', function() { + assert.deepStrictEqual( + sequence("a", ["a", "a"]).firstCycle, + timeCat([1,"a"], [0.5, "a"], [0.5, "a"]).firstCycle + ) + }) + }) })