diff --git a/strudel.mjs b/strudel.mjs index 8770728f..36684df9 100644 --- a/strudel.mjs +++ b/strudel.mjs @@ -558,11 +558,15 @@ function stack(...pats) { function slowcat(...pats) { // Concatenation: combines a list of patterns, switching between them // successively, one per cycle. - // (currently behaves slightly differently from Tidal) pats = pats.map(reify) - var query = function(span) { - var pat = pats[Math.floor(span.begin) % pats.length] - return pat.query(span) + const query = function(span) { + const pat_n = Math.floor(span.begin) % pats.length + const pat = pats[pat_n] + // A bit of maths to make sure that cycles from constituent patterns aren't skipped. + // For example if three patterns are slowcat-ed, the fourth cycle of the result should + // be the second (rather than fourth) cycle from the first pattern. + const offset = span.begin.floor().sub(span.begin.div(pats.length).floor()) + return pat.withEventTime(t => t.add(offset)).query(span.withTime(t => t.sub(offset))) } return new Pattern(query)._splitQueries() } diff --git a/test/pattern.test.mjs b/test/pattern.test.mjs index 21f19948..e2183b37 100644 --- a/test/pattern.test.mjs +++ b/test/pattern.test.mjs @@ -121,13 +121,15 @@ describe('Pattern', function() { }) describe('slowcat()', function () { it('Can concatenate things slowly', function () { - assert.deepStrictEqual(slowcat(pure("a"), pure("b")).firstCycle.map(x => x.value), ["a"]) - assert.deepStrictEqual(slowcat(pure("a"), pure("b"))._early(1).firstCycle.map(x => x.value), ["b"]) + assert.deepStrictEqual(slowcat("a", "b").firstCycle.map(x => x.value), ["a"]) + assert.deepStrictEqual(slowcat("a", "b")._early(1).firstCycle.map(x => x.value), ["b"]) + assert.deepStrictEqual(slowcat("a", slowcat("b", "c"))._early(1).firstCycle.map(x => x.value), ["b"]) + assert.deepStrictEqual(slowcat("a", slowcat("b", "c"))._early(3).firstCycle.map(x => x.value), ["c"]) }) }) describe('rev()', function () { it('Can reverse things', function () { - assert.deepStrictEqual(fastcat(pure("a"), pure("b"), pure("c")).rev().firstCycle.sort((a,b) => a.part.begin.sub(b.part.begin)).map(a => a.value), ["c", "b","a"]) + assert.deepStrictEqual(fastcat("a","b","c").rev().firstCycle.sort((a,b) => a.part.begin.sub(b.part.begin)).map(a => a.value), ["c", "b","a"]) }) }) // describe('sequence()', () => {