diff --git a/index.html b/index.html
index 1baabcb6..6bf19cf2 100644
--- a/index.html
+++ b/index.html
@@ -1,5 +1,6 @@
-
+
Bingo
diff --git a/js/strudel.mjs b/js/strudel.mjs
index d794f070..b2f0e7b0 100644
--- a/js/strudel.mjs
+++ b/js/strudel.mjs
@@ -191,16 +191,18 @@ class Pattern {
this.query = query
}
- splitQueries() {
+ _splitQueries() {
// Splits queries at cycle boundaries. This makes some calculations
// easier to express, as all events are then constrained to happen within
// a cycle.
- var query = function(span) {
- return flatten(span.spanCycles.map(subspan => this.query(subspan)))
+ var pat = this
+ var q = function(span) {
+ return flatten(span.spanCycles.map(subspan => pat.query(subspan)))
}
- return new Pattern(query)
+ return new Pattern(q)
}
+
withQuerySpan(func) {
return new Pattern(span => this.query(func(span)))
}
@@ -235,7 +237,7 @@ class Pattern {
}
_filterEvents(event_test) {
- return new Pattern(span => this.query(span).filter(event_tespanCyclesst))
+ return new Pattern(span => this.query(span).filter(event_test))
}
_filterValues(value_test) {
@@ -424,11 +426,15 @@ class Pattern {
when(binary_pat, func) {
//binary_pat = sequence(binary_pat)
- var true_pat = binary_pat._filter_values(id)
- var false_pat = binary_pat._filter_values(val => !val)
- var with_pat = true_pat.fmap(_ => y => y).app_right(func(this))
- var without_pat = false_pat.fmap(_ => y => y).app_right(this)
- return stack(with_pat, without_pat)
+ var true_pat = binary_pat._filterValues(id)
+ var false_pat = binary_pat._filterValues(val => !val)
+ var with_pat = true_pat.fmap(_ => y => y).appRight(func(this))
+ var without_pat = false_pat.fmap(_ => y => y).appRight(this)
+ return stack([with_pat, without_pat])
+ }
+
+ off(time_pat, func) {
+ return stack([this, func(this._early(time_pat))])
}
off(time_pat, func) {
@@ -504,5 +510,27 @@ function stack(pats) {
return new Pattern(query)
}
-export {Fraction, TimeSpan, Hap, Pattern, pure, stack}
+function slowcat(pats) {
+ // Concatenation: combines a list of patterns, switching between them
+ // successively, one per cycle.
+ // (currently behaves slightly differently from Tidal)
+ //var pats = pats.map(reify)
+ var query = function(span) {
+ var pat = pats[Math.floor(span.begin) % pats.length]
+ return pat.query(span)
+ }
+ return new Pattern(query)._splitQueries()
+}
+
+function fastcat(pats) {
+ // Concatenation: as with slowcat, but squashes a cycle from each
+ // pattern into one cycle
+ return slowcat(pats)._fast(pats.length)
+}
+
+function cat(pats) {
+ return fastcat(pats)
+}
+
+export {Fraction, TimeSpan, Hap, Pattern, pure, stack, slowcat, fastcat, cat}
diff --git a/test/pattern.test.mjs b/test/pattern.test.mjs
index 34628c7e..ddb2e981 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} from "../js/strudel.mjs";
+import {TimeSpan, Hap, Pattern, pure, stack, fastcat, slowcat, cat} from "../js/strudel.mjs";
describe('TimeSpan', function() {
describe('equals()', function() {
@@ -90,5 +90,29 @@ describe('Pattern', function() {
it('Makes things slower', function () {
assert.deepStrictEqual(pure("a")._slow(2).firstCycle[0], new Hap(new TimeSpan(Fraction(0),Fraction(2)), new TimeSpan(Fraction(0), Fraction(1)), "a"))
})
+ })
+ describe('_filterValues()', function () {
+ it('Filters true', function () {
+ assert.equal(pure(true)._filterValues(x => x).firstCycle.length, 1)
+ })
+ })
+ describe('when()', function () {
+ it('Always faster', function () {
+ assert.equal(pure("a").when(pure(true), x => x._fast(2)).firstCycle.length, 2)
+ })
+ it('Never faster', function () {
+ assert.equal(pure("a").when(pure(false), x => x._fast(2)).firstCycle.length, 1)
+ })
+ })
+ describe('fastcat()', function () {
+ it('Can concatenate two things', function () {
+ assert.deepStrictEqual(fastcat([pure("a"), pure("b")]).firstCycle.map(x => x.value), ["a", "b"])
+ })
+ })
+ 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"])
+ })
})
})
\ No newline at end of file