commit
3b9e854042
4 changed files with 609 additions and 463 deletions
|
|
@ -1,35 +1,5 @@
|
|||
import Fraction from './fraction.mjs';
|
||||
import { isNote, toMidi, compose } from './util.mjs';
|
||||
|
||||
// Removes 'None' values from given list
|
||||
const removeUndefineds = (xs) => xs.filter((x) => x != undefined);
|
||||
|
||||
const flatten = (arr) => [].concat(...arr);
|
||||
|
||||
const id = (a) => a;
|
||||
|
||||
const range = (min, max) => Array.from({ length: max - min + 1 }, (_, i) => i + min);
|
||||
|
||||
export function curry(func, overload) {
|
||||
const fn = function curried(...args) {
|
||||
if (args.length >= func.length) {
|
||||
return func.apply(this, args);
|
||||
} else {
|
||||
const partial = function (...args2) {
|
||||
return curried.apply(this, args.concat(args2));
|
||||
};
|
||||
if (overload) {
|
||||
overload(partial, args);
|
||||
}
|
||||
return partial;
|
||||
}
|
||||
};
|
||||
if (overload) {
|
||||
// overload function without args... needed for chordBass.transpose(2)
|
||||
overload(fn, []);
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
import { isNote, toMidi, compose, removeUndefineds, flatten, id, listRange, curry } from './util.mjs';
|
||||
|
||||
class TimeSpan {
|
||||
constructor(begin, end) {
|
||||
|
|
@ -524,6 +494,16 @@ class Pattern {
|
|||
return this._asNumber().fmap((v) => Math.ceil(v));
|
||||
}
|
||||
|
||||
// Assumes source pattern of numbers in range 0..1
|
||||
range(min, max) {
|
||||
return this.mul(max-min).add(min);
|
||||
}
|
||||
|
||||
// Assumes source pattern of numbers in range -1..1
|
||||
range2(min, max) {
|
||||
return _fromBipolar(this).range(min,max);
|
||||
}
|
||||
|
||||
union(other) {
|
||||
return this._opleft(other, (a) => (b) => Object.assign({}, a, b));
|
||||
}
|
||||
|
|
@ -795,7 +775,7 @@ class Pattern {
|
|||
return new Pattern(query)._splitQueries();
|
||||
}
|
||||
|
||||
jux(func, by = 1) {
|
||||
juxBy(by, func) {
|
||||
by /= 2;
|
||||
const elem_or = function (dict, key, dflt) {
|
||||
if (key in dict) {
|
||||
|
|
@ -809,6 +789,10 @@ class Pattern {
|
|||
return stack(left, func(right));
|
||||
}
|
||||
|
||||
_jux(func) {
|
||||
return this.juxBy(1, func);
|
||||
}
|
||||
|
||||
// is there a different name for those in tidal?
|
||||
stack(...pats) {
|
||||
return stack(this, ...pats);
|
||||
|
|
@ -822,7 +806,7 @@ class Pattern {
|
|||
}
|
||||
|
||||
stutWith(times, time, func) {
|
||||
return stack(...range(0, times - 1).map((i) => func(this.late(i * time), i)));
|
||||
return stack(...listRange(0, times - 1).map((i) => func(this.late(i * time), i)));
|
||||
}
|
||||
|
||||
stut(times, feedback, time) {
|
||||
|
|
@ -831,7 +815,7 @@ class Pattern {
|
|||
|
||||
// these might change with: https://github.com/tidalcycles/Tidal/issues/902
|
||||
_echoWith(times, time, func) {
|
||||
return stack(...range(0, times - 1).map((i) => func(this.late(i * time), i)));
|
||||
return stack(...listRange(0, times - 1).map((i) => func(this.late(i * time), i)));
|
||||
}
|
||||
|
||||
_echo(times, time, feedback) {
|
||||
|
|
@ -839,7 +823,7 @@ class Pattern {
|
|||
}
|
||||
|
||||
iter(times, back = false) {
|
||||
return slowcat(...range(0, times - 1).map((i) => (back ? this.late(i / times) : this.early(i / times))));
|
||||
return slowcat(...listRange(0, times - 1).map((i) => (back ? this.late(i / times) : this.early(i / times))));
|
||||
}
|
||||
|
||||
// known as iter' in tidalcycles
|
||||
|
|
@ -904,6 +888,7 @@ Pattern.prototype.patternified = [
|
|||
'velocity',
|
||||
'segment',
|
||||
'color',
|
||||
'jux'
|
||||
];
|
||||
// methods that create patterns, which are added to patternified Pattern methods
|
||||
Pattern.prototype.factories = { pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr };
|
||||
|
|
@ -1101,10 +1086,13 @@ const sub = curry((a, pat) => pat.sub(a));
|
|||
const mul = curry((a, pat) => pat.mul(a));
|
||||
const div = curry((a, pat) => pat.div(a));
|
||||
const union = curry((a, pat) => pat.union(a));
|
||||
const range = curry((a, b, pat) => pat.range(a,b));
|
||||
const range2 = curry((a, b, pat) => pat.range2(a,b));
|
||||
const every = curry((i, f, pat) => pat.every(i, f));
|
||||
const when = curry((binary, f, pat) => pat.when(binary, f));
|
||||
const off = curry((t, f, pat) => pat.off(t, f));
|
||||
const jux = curry((f, pat) => pat.jux(f));
|
||||
const juxBy = curry((by, f, pat) => pat.juxBy(by, f));
|
||||
const append = curry((a, pat) => pat.append(a));
|
||||
const superimpose = curry((array, pat) => pat.superimpose(...array));
|
||||
const struct = curry((a, pat) => pat.struct(a));
|
||||
|
|
@ -1230,49 +1218,51 @@ Pattern.prototype.define('bypass', (pat) => pat.bypass(on), { patternified: true
|
|||
|
||||
export {
|
||||
Fraction,
|
||||
TimeSpan,
|
||||
Hap,
|
||||
Pattern,
|
||||
pure,
|
||||
stack,
|
||||
slowcat,
|
||||
fastcat,
|
||||
cat,
|
||||
timeCat,
|
||||
sequence,
|
||||
polymeterSteps,
|
||||
polymeter,
|
||||
pm,
|
||||
polyrhythm,
|
||||
pr,
|
||||
reify,
|
||||
silence,
|
||||
fast,
|
||||
slow,
|
||||
early,
|
||||
late,
|
||||
rev,
|
||||
TimeSpan,
|
||||
add,
|
||||
sub,
|
||||
mul,
|
||||
div,
|
||||
union,
|
||||
every,
|
||||
when,
|
||||
off,
|
||||
jux,
|
||||
append,
|
||||
superimpose,
|
||||
struct,
|
||||
mask,
|
||||
invert,
|
||||
inv,
|
||||
id,
|
||||
range,
|
||||
echo,
|
||||
iter,
|
||||
iterBack,
|
||||
cat,
|
||||
chunk,
|
||||
chunkBack,
|
||||
div,
|
||||
early,
|
||||
echo,
|
||||
every,
|
||||
fast,
|
||||
fastcat,
|
||||
id,
|
||||
inv,
|
||||
invert,
|
||||
iter,
|
||||
iterBack,
|
||||
jux,
|
||||
juxBy,
|
||||
late,
|
||||
mask,
|
||||
mul,
|
||||
off,
|
||||
ply,
|
||||
pm,
|
||||
polymeter,
|
||||
polymeterSteps,
|
||||
polyrhythm,
|
||||
pr,
|
||||
pure,
|
||||
range,
|
||||
range2,
|
||||
reify,
|
||||
rev,
|
||||
sequence,
|
||||
silence,
|
||||
slow,
|
||||
slowcat,
|
||||
stack,
|
||||
struct,
|
||||
sub,
|
||||
superimpose,
|
||||
timeCat,
|
||||
union,
|
||||
when,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import Fraction from 'fraction.js'
|
||||
import Fraction from 'fraction.js';
|
||||
|
||||
import { strict as assert } from 'assert';
|
||||
|
||||
|
|
@ -40,189 +40,203 @@ import {
|
|||
import pkg from 'tone';
|
||||
const { Time } = pkg;
|
||||
|
||||
const st = (begin, end) => new State(ts(begin, end))
|
||||
const st = (begin, end) => new State(ts(begin, end));
|
||||
const ts = (begin, end) => new TimeSpan(Fraction(begin), Fraction(end));
|
||||
const hap = (whole, part, value, context={}) => new Hap(whole, part, value, context)
|
||||
const hap = (whole, part, value, context = {}) => new Hap(whole, part, value, context);
|
||||
|
||||
const third = Fraction(1,3)
|
||||
const twothirds = Fraction(2,3)
|
||||
const third = Fraction(1, 3);
|
||||
const twothirds = Fraction(2, 3);
|
||||
|
||||
describe('TimeSpan', function () {
|
||||
describe('equals()', function () {
|
||||
it('Should be equal to the same value', function () {
|
||||
assert.equal((new TimeSpan(0,4)).equals(new TimeSpan(0,4)), true);
|
||||
assert.equal(new TimeSpan(0, 4).equals(new TimeSpan(0, 4)), true);
|
||||
});
|
||||
});
|
||||
describe('splitCycles', function () {
|
||||
it('Should split two cycles into two', function () {
|
||||
assert.equal(new TimeSpan(Fraction(0),Fraction(2)).spanCycles.length, 2)
|
||||
})
|
||||
})
|
||||
assert.equal(new TimeSpan(Fraction(0), Fraction(2)).spanCycles.length, 2);
|
||||
});
|
||||
});
|
||||
describe('intersection_e', function () {
|
||||
var a = new TimeSpan(Fraction(0), Fraction(2))
|
||||
var b = new TimeSpan(Fraction(1), Fraction(3))
|
||||
var c = new TimeSpan(Fraction(1), Fraction(2))
|
||||
var d = new TimeSpan(Fraction(1), Fraction(2))
|
||||
var a = new TimeSpan(Fraction(0), Fraction(2));
|
||||
var b = new TimeSpan(Fraction(1), Fraction(3));
|
||||
var c = new TimeSpan(Fraction(1), Fraction(2));
|
||||
var d = new TimeSpan(Fraction(1), Fraction(2));
|
||||
it('Should create an intersection', function () {
|
||||
assert.equal(a.intersection_e(b).equals(c), true)
|
||||
})
|
||||
})
|
||||
assert.equal(a.intersection_e(b).equals(c), true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Hap', function () {
|
||||
describe('hasOnset()', function () {
|
||||
it('True if part includes onset from whole', function () {
|
||||
assert.equal(new Hap(new TimeSpan(0,1), new TimeSpan(0,1), "thing").hasOnset(), true);
|
||||
assert.equal(new Hap(new TimeSpan(0, 1), new TimeSpan(0, 1), 'thing').hasOnset(), true);
|
||||
});
|
||||
});
|
||||
var a = new Hap(new TimeSpan(Fraction(0), Fraction(0.5)), new TimeSpan(Fraction(0), Fraction(0.5)), "a")
|
||||
var b = new Hap(new TimeSpan(Fraction(0), Fraction(0.5)), new TimeSpan(Fraction(0), Fraction(0.5)), "b")
|
||||
var c = new Hap(new TimeSpan(Fraction(0), Fraction(0.25)), new TimeSpan(Fraction(0), Fraction(0.5)), "c")
|
||||
var d = new Hap(undefined, new TimeSpan(Fraction(0), Fraction(0.5)), "d")
|
||||
var e = new Hap(undefined, new TimeSpan(Fraction(0), Fraction(0.5)), "e")
|
||||
var a = new Hap(new TimeSpan(Fraction(0), Fraction(0.5)), new TimeSpan(Fraction(0), Fraction(0.5)), 'a');
|
||||
var b = new Hap(new TimeSpan(Fraction(0), Fraction(0.5)), new TimeSpan(Fraction(0), Fraction(0.5)), 'b');
|
||||
var c = new Hap(new TimeSpan(Fraction(0), Fraction(0.25)), new TimeSpan(Fraction(0), Fraction(0.5)), 'c');
|
||||
var d = new Hap(undefined, new TimeSpan(Fraction(0), Fraction(0.5)), 'd');
|
||||
var e = new Hap(undefined, new TimeSpan(Fraction(0), Fraction(0.5)), 'e');
|
||||
describe('spanEquals', function () {
|
||||
it('True if two haps have the same whole and part', function () {
|
||||
assert.equal(a.spanEquals(b), true)
|
||||
})
|
||||
it('False if two haps don\'t the same whole and part', function() {
|
||||
assert.equal(a.spanEquals(c), false)
|
||||
})
|
||||
assert.equal(a.spanEquals(b), true);
|
||||
});
|
||||
it("False if two haps don't the same whole and part", function () {
|
||||
assert.equal(a.spanEquals(c), false);
|
||||
});
|
||||
it('True if two haps have the same part and undefined wholes', function () {
|
||||
assert.equal(d.spanEquals(e), true)
|
||||
})
|
||||
})
|
||||
assert.equal(d.spanEquals(e), true);
|
||||
});
|
||||
});
|
||||
describe('resolveState()', () => {
|
||||
it('Can increment some state', function () {
|
||||
const stateful_value = state => {
|
||||
const newValue = state["incrementme"]
|
||||
const stateful_value = (state) => {
|
||||
const newValue = state['incrementme'];
|
||||
// TODO Does the state *need* duplicating here?
|
||||
const newState = {...state}
|
||||
newState["incrementme"]++
|
||||
return [newState, newValue]
|
||||
}
|
||||
const state = {incrementme: 10}
|
||||
const ev1 = new Hap(ts(0,1), ts(0,1), stateful_value, {}, true)
|
||||
const [state2, ev2] = ev1.resolveState(state)
|
||||
const [state3, ev3] = ev1.resolveState(state2)
|
||||
assert.deepStrictEqual(
|
||||
ev3, new Hap(ts(0,1),ts(0,1),11,{},false)
|
||||
)
|
||||
assert.deepStrictEqual(
|
||||
state3, {incrementme: 12}
|
||||
)
|
||||
})
|
||||
})
|
||||
const newState = { ...state };
|
||||
newState['incrementme']++;
|
||||
return [newState, newValue];
|
||||
};
|
||||
const state = { incrementme: 10 };
|
||||
const ev1 = new Hap(ts(0, 1), ts(0, 1), stateful_value, {}, true);
|
||||
const [state2, ev2] = ev1.resolveState(state);
|
||||
const [state3, ev3] = ev1.resolveState(state2);
|
||||
assert.deepStrictEqual(ev3, new Hap(ts(0, 1), ts(0, 1), 11, {}, false));
|
||||
assert.deepStrictEqual(state3, { incrementme: 12 });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Pattern', function () {
|
||||
describe('pure', function () {
|
||||
it('Can make a pattern', function () {
|
||||
assert.equal(pure("hello").query(st(0.5, 2.5)).length, 3)
|
||||
})
|
||||
})
|
||||
assert.equal(pure('hello').query(st(0.5, 2.5)).length, 3);
|
||||
});
|
||||
});
|
||||
describe('fmap()', function () {
|
||||
it('Can add things', function () {
|
||||
assert.equal(pure(3).fmap(x => x + 4).firstCycle()[0].value, 7)
|
||||
})
|
||||
})
|
||||
assert.equal(
|
||||
pure(3)
|
||||
.fmap((x) => x + 4)
|
||||
.firstCycle()[0].value,
|
||||
7,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('add()', function () {
|
||||
it('Can add things', function () {
|
||||
assert.equal(pure(3).add(pure(4)).query(st(0,1))[0].value, 7)
|
||||
})
|
||||
})
|
||||
assert.equal(pure(3).add(pure(4)).query(st(0, 1))[0].value, 7);
|
||||
});
|
||||
});
|
||||
describe('sub()', function () {
|
||||
it('Can subtract things', function () {
|
||||
assert.equal(pure(3).sub(pure(4)).query(st(0,1))[0].value, -1)
|
||||
})
|
||||
})
|
||||
assert.equal(pure(3).sub(pure(4)).query(st(0, 1))[0].value, -1);
|
||||
});
|
||||
});
|
||||
describe('mul()', function () {
|
||||
it('Can multiply things', function () {
|
||||
assert.equal(pure(3).mul(pure(2)).firstCycle()[0].value, 6)
|
||||
})
|
||||
})
|
||||
assert.equal(pure(3).mul(pure(2)).firstCycle()[0].value, 6);
|
||||
});
|
||||
});
|
||||
describe('div()', function () {
|
||||
it('Can divide things', function () {
|
||||
assert.equal(pure(3).div(pure(2)).firstCycle()[0].value, 1.5)
|
||||
})
|
||||
})
|
||||
assert.equal(pure(3).div(pure(2)).firstCycle()[0].value, 1.5);
|
||||
});
|
||||
});
|
||||
describe('union()', function () {
|
||||
it('Can union things', function () {
|
||||
assert.deepStrictEqual(pure({a: 4, b: 6}).union(pure({c: 7})).firstCycle()[0].value, {a: 4, b: 6, c: 7})
|
||||
})
|
||||
})
|
||||
assert.deepStrictEqual(
|
||||
pure({ a: 4, b: 6 })
|
||||
.union(pure({ c: 7 }))
|
||||
.firstCycle()[0].value,
|
||||
{ a: 4, b: 6, c: 7 },
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('stack()', function () {
|
||||
it('Can stack things', function () {
|
||||
assert.deepStrictEqual(stack(pure("a"), pure("b"), pure("c")).firstCycle().map(h => h.value), ["a", "b", "c"])
|
||||
})
|
||||
})
|
||||
assert.deepStrictEqual(
|
||||
stack(pure('a'), pure('b'), pure('c'))
|
||||
.firstCycle()
|
||||
.map((h) => h.value),
|
||||
['a', 'b', 'c'],
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('_fast()', function () {
|
||||
it('Makes things faster', function () {
|
||||
assert.equal(pure("a")._fast(2).firstCycle().length, 2)
|
||||
})
|
||||
})
|
||||
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()
|
||||
)
|
||||
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()
|
||||
)
|
||||
})
|
||||
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()
|
||||
)
|
||||
})
|
||||
})
|
||||
sequence('a', 'b', 'c')._fastGap(2).fast(2).firstCycle(),
|
||||
sequence(['a', 'b', 'c'], silence, ['a', 'b', 'c'], silence).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
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()
|
||||
)
|
||||
})
|
||||
})
|
||||
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)
|
||||
})
|
||||
assert.equal(pure('a').fast(2).firstCycle().length, 2);
|
||||
});
|
||||
it('Makes things faster, with a pattern of factors', function () {
|
||||
assert.equal(pure("a").fast(sequence(1,4)).firstCycle().length, 3)
|
||||
assert.equal(pure('a').fast(sequence(1, 4)).firstCycle().length, 3);
|
||||
// .fast(sequence(1,silence) is a quick hack to cut an event in two..
|
||||
assert.deepStrictEqual(pure("a").fast(sequence(1,4)).firstCycle(), stack(pure("a").fast(sequence(1,silence)), sequence(silence, ["a","a"])).firstCycle())
|
||||
})
|
||||
assert.deepStrictEqual(
|
||||
pure('a').fast(sequence(1, 4)).firstCycle(),
|
||||
stack(pure('a').fast(sequence(1, silence)), sequence(silence, ['a', 'a'])).firstCycle(),
|
||||
);
|
||||
});
|
||||
it('defaults to accepting sequences', function () {
|
||||
assert.deepStrictEqual(
|
||||
sequence(1, 2, 3).fast(sequence(1.5, 2)).firstCycle(),
|
||||
sequence(1,2,3).fast(1.5,2).firstCycle()
|
||||
)
|
||||
})
|
||||
it("works as a static function", function () {
|
||||
sequence(1, 2, 3).fast(1.5, 2).firstCycle(),
|
||||
);
|
||||
});
|
||||
it('works as a static function', function () {
|
||||
assert.deepStrictEqual(
|
||||
sequence(1, 2, 3).fast(1, 2).firstCycle(),
|
||||
fast(sequence(1,2), sequence(1,2,3)).firstCycle()
|
||||
)
|
||||
})
|
||||
it("works as a curried static function", function () {
|
||||
fast(sequence(1, 2), sequence(1, 2, 3)).firstCycle(),
|
||||
);
|
||||
});
|
||||
it('works as a curried static function', function () {
|
||||
assert.deepStrictEqual(
|
||||
sequence(1, 2, 3).fast(1, 2).firstCycle(),
|
||||
fast(sequence(1,2))(sequence(1,2,3)).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
fast(sequence(1, 2))(sequence(1, 2, 3)).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('_slow()', 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"))
|
||||
assert.deepStrictEqual(
|
||||
pure('a')._slow(2).firstCycle()[0],
|
||||
new Hap(new TimeSpan(Fraction(0), Fraction(2)), new TimeSpan(Fraction(0), Fraction(1)), 'a'),
|
||||
);
|
||||
|
||||
const pat = sequence(pure('c3'), pure('eb3')._slow(2)); // => try mini('c3 eb3/2') in repl
|
||||
assert.deepStrictEqual(
|
||||
pat.query(st(0,1))[1],
|
||||
hap(ts(0.5,1.5), ts(1/2,1), "eb3")
|
||||
)
|
||||
assert.deepStrictEqual(pat.query(st(0, 1))[1], hap(ts(0.5, 1.5), ts(1 / 2, 1), 'eb3'));
|
||||
// the following test fails
|
||||
/* assert.deepStrictEqual(
|
||||
pat.query(ts(1,2))[1], undefined
|
||||
|
|
@ -232,302 +246,414 @@ describe('Pattern', function() {
|
|||
// notable examples:
|
||||
// mini('[c3 g3]/2 eb3') always plays [c3 eb3]
|
||||
// mini('eb3 [c3 g3]/2 ') always plays [c3 g3]
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
describe('_filterValues()', function () {
|
||||
it('Filters true', function () {
|
||||
assert.equal(pure(true)._filterValues(x => x).firstCycle().length, 1)
|
||||
})
|
||||
})
|
||||
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)
|
||||
})
|
||||
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)
|
||||
})
|
||||
assert.equal(
|
||||
pure('a')
|
||||
.when(pure(false), (x) => x._fast(2))
|
||||
.firstCycle().length,
|
||||
1,
|
||||
);
|
||||
});
|
||||
it('Can alternate', function () {
|
||||
assert.deepStrictEqual(
|
||||
pure(10).when(slowcat(true, false), add(3)).fast(4)._sortEventsByPart().firstCycle(),
|
||||
fastcat(13,10,13,10).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
fastcat(13, 10, 13, 10).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('fastcat()', function () {
|
||||
it('Can concatenate two things', function () {
|
||||
assert.deepStrictEqual(fastcat(pure("a"), pure("b")).firstCycle().map(x => x.value), ["a", "b"])
|
||||
})
|
||||
})
|
||||
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("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"])
|
||||
})
|
||||
})
|
||||
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("a","b","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()', () => {
|
||||
it('Can work like fastcat', () => {
|
||||
assert.deepStrictEqual(sequence(1,2,3).firstCycle(), fastcat(1,2,3).firstCycle())
|
||||
})
|
||||
})
|
||||
assert.deepStrictEqual(sequence(1, 2, 3).firstCycle(), fastcat(1, 2, 3).firstCycle());
|
||||
});
|
||||
});
|
||||
describe('polyrhythm()', () => {
|
||||
it('Can layer up cycles', () => {
|
||||
assert.deepStrictEqual(
|
||||
polyrhythm(["a","b"],["c"]).firstCycle(),
|
||||
stack(fastcat(pure("a"),pure("b")),pure("c")).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
polyrhythm(['a', 'b'], ['c']).firstCycle(),
|
||||
stack(fastcat(pure('a'), pure('b')), pure('c')).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('polymeter()', () => {
|
||||
it('Can layer up cycles, stepwise', () => {
|
||||
assert.deepStrictEqual(
|
||||
polymeterSteps(3, ["d","e"]).firstCycle(),
|
||||
fastcat(pure("d"),pure("e"),pure("d")).firstCycle()
|
||||
)
|
||||
polymeterSteps(3, ['d', 'e']).firstCycle(),
|
||||
fastcat(pure('d'), pure('e'), pure('d')).firstCycle(),
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
polymeter(["a","b","c"],["d","e"]).fast(2).firstCycle(),
|
||||
stack(sequence("a","b","c","a","b","c"),
|
||||
sequence("d","e","d","e","d","e")
|
||||
).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
polymeter(['a', 'b', 'c'], ['d', 'e']).fast(2).firstCycle(),
|
||||
stack(sequence('a', 'b', 'c', 'a', 'b', 'c'), sequence('d', 'e', 'd', 'e', 'd', 'e')).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('every()', () => {
|
||||
it('Can apply a function every 3rd time', () => {
|
||||
assert.deepStrictEqual(
|
||||
pure("a").every(3, x => x._fast(2))._fast(3).firstCycle(),
|
||||
sequence(sequence("a", "a"), "a", "a").firstCycle()
|
||||
)
|
||||
})
|
||||
it("works with currying", () => {
|
||||
pure('a')
|
||||
.every(3, (x) => x._fast(2))
|
||||
._fast(3)
|
||||
.firstCycle(),
|
||||
sequence(sequence('a', 'a'), 'a', 'a').firstCycle(),
|
||||
);
|
||||
});
|
||||
it('works with currying', () => {
|
||||
assert.deepStrictEqual(
|
||||
pure("a").every(3, fast(2))._fast(3).firstCycle(),
|
||||
sequence(sequence("a", "a"), "a", "a").firstCycle()
|
||||
)
|
||||
pure('a').every(3, fast(2))._fast(3).firstCycle(),
|
||||
sequence(sequence('a', 'a'), 'a', 'a').firstCycle(),
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
sequence(3, 4, 5).every(3, add(3)).fast(5).firstCycle(),
|
||||
sequence(6,7,8,3,4,5,3,4,5,6,7,8,3,4,5).firstCycle()
|
||||
)
|
||||
sequence(6, 7, 8, 3, 4, 5, 3, 4, 5, 6, 7, 8, 3, 4, 5).firstCycle(),
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
sequence(3, 4, 5).every(2, sub(1)).fast(5).firstCycle(),
|
||||
sequence(2,3,4,3,4,5,2,3,4,3,4,5,2,3,4).firstCycle()
|
||||
)
|
||||
sequence(2, 3, 4, 3, 4, 5, 2, 3, 4, 3, 4, 5, 2, 3, 4).firstCycle(),
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
sequence(3, 4, 5).every(3, add(3)).every(2, sub(1)).fast(2).firstCycle(),
|
||||
sequence(5,6,7,3,4,5).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
sequence(5, 6, 7, 3, 4, 5).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
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()
|
||||
)
|
||||
})
|
||||
})
|
||||
sequence('a', ['a', 'a']).firstCycle(),
|
||||
timeCat([1, 'a'], [0.5, 'a'], [0.5, 'a']).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('struct()', function () {
|
||||
it('Can restructure a pattern', function () {
|
||||
assert.deepStrictEqual(sequence('a', 'b').struct(sequence(true, true, true)).firstCycle(), [
|
||||
hap(ts(0, third), ts(0, third), 'a'),
|
||||
hap(ts(third, twothirds), ts(third, 0.5), 'a'),
|
||||
hap(ts(third, twothirds), ts(0.5, twothirds), 'b'),
|
||||
hap(ts(twothirds, 1), ts(twothirds, 1), 'b'),
|
||||
]);
|
||||
assert.deepStrictEqual(
|
||||
sequence("a", "b").struct(sequence(true, true, true)).firstCycle(),
|
||||
[hap(ts(0,third), ts(0,third), "a"),
|
||||
hap(ts(third, twothirds), ts(third, 0.5), "a"),
|
||||
hap(ts(third, twothirds), ts(0.5, twothirds), "b"),
|
||||
hap(ts(twothirds, 1), ts(twothirds, 1), "b")
|
||||
]
|
||||
)
|
||||
pure('a')
|
||||
.struct(sequence(true, [true, false], true))
|
||||
.firstCycle(),
|
||||
sequence('a', ['a', silence], 'a').firstCycle(),
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pure("a").struct(sequence(true, [true,false], true)).firstCycle(),
|
||||
sequence("a", ["a", silence], "a").firstCycle(),
|
||||
)
|
||||
pure('a')
|
||||
.struct(sequence(true, [true, false], true).invert())
|
||||
.firstCycle(),
|
||||
sequence(silence, [silence, 'a'], silence).firstCycle(),
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pure("a").struct(sequence(true, [true,false], true).invert()).firstCycle(),
|
||||
sequence(silence, [silence, "a"], silence).firstCycle(),
|
||||
)
|
||||
assert.deepStrictEqual(
|
||||
pure("a").struct(sequence(true, [true,silence], true)).firstCycle(),
|
||||
sequence("a", ["a", silence], "a").firstCycle(),
|
||||
)
|
||||
})
|
||||
})
|
||||
pure('a')
|
||||
.struct(sequence(true, [true, silence], true))
|
||||
.firstCycle(),
|
||||
sequence('a', ['a', silence], 'a').firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('mask()', function () {
|
||||
it('Can fragment a pattern', function () {
|
||||
assert.deepStrictEqual(
|
||||
sequence("a", "b").mask(sequence(true, true, true)).firstCycle(),
|
||||
[hap(ts(0, 0.5), ts(0,third), "a"),
|
||||
hap(ts(0, 0.5), ts(third, 0.5), "a"),
|
||||
hap(ts(0.5, 1), ts(0.5, twothirds), "b"),
|
||||
hap(ts(0.5, 1), ts(twothirds, 1), "b")
|
||||
]
|
||||
)
|
||||
})
|
||||
assert.deepStrictEqual(sequence('a', 'b').mask(sequence(true, true, true)).firstCycle(), [
|
||||
hap(ts(0, 0.5), ts(0, third), 'a'),
|
||||
hap(ts(0, 0.5), ts(third, 0.5), 'a'),
|
||||
hap(ts(0.5, 1), ts(0.5, twothirds), 'b'),
|
||||
hap(ts(0.5, 1), ts(twothirds, 1), 'b'),
|
||||
]);
|
||||
});
|
||||
it('Can mask off parts of a pattern', function () {
|
||||
assert.deepStrictEqual(
|
||||
sequence(["a", "b"], "c").mask(sequence(true, false)).firstCycle(),
|
||||
sequence(["a","b"], silence).firstCycle()
|
||||
)
|
||||
assert.deepStrictEqual(
|
||||
sequence("a").mask(sequence(true, false)).firstCycle(),
|
||||
[hap(ts(0,1),ts(0,0.5), "a")]
|
||||
)
|
||||
})
|
||||
})
|
||||
sequence(['a', 'b'], 'c').mask(sequence(true, false)).firstCycle(),
|
||||
sequence(['a', 'b'], silence).firstCycle(),
|
||||
);
|
||||
assert.deepStrictEqual(sequence('a').mask(sequence(true, false)).firstCycle(), [hap(ts(0, 1), ts(0, 0.5), 'a')]);
|
||||
});
|
||||
});
|
||||
describe('invert()', function () {
|
||||
it('Can invert a binary pattern', function () {
|
||||
assert.deepStrictEqual(
|
||||
sequence(true, false, [true, false]).invert().firstCycle(),
|
||||
sequence(false, true, [false, true]).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
sequence(false, true, [false, true]).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('signal()', function () {
|
||||
it('Can make saw/saw2', function () {
|
||||
assert.deepStrictEqual(
|
||||
saw.struct(true, true, true, true).firstCycle(),
|
||||
sequence(1/8,3/8,5/8,7/8).firstCycle()
|
||||
)
|
||||
sequence(1 / 8, 3 / 8, 5 / 8, 7 / 8).firstCycle(),
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
saw2.struct(true, true, true, true).firstCycle(),
|
||||
sequence(-3/4,-1/4,1/4,3/4).firstCycle()
|
||||
)
|
||||
})
|
||||
sequence(-3 / 4, -1 / 4, 1 / 4, 3 / 4).firstCycle(),
|
||||
);
|
||||
});
|
||||
it('Can make isaw/isaw2', function () {
|
||||
assert.deepStrictEqual(
|
||||
isaw.struct(true, true, true, true).firstCycle(),
|
||||
sequence(7/8,5/8,3/8,1/8).firstCycle()
|
||||
)
|
||||
sequence(7 / 8, 5 / 8, 3 / 8, 1 / 8).firstCycle(),
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
isaw2.struct(true, true, true, true).firstCycle(),
|
||||
sequence(3/4,1/4,-1/4,-3/4).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
sequence(3 / 4, 1 / 4, -1 / 4, -3 / 4).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('_setContext()', () => {
|
||||
it('Can set the event context', () => {
|
||||
assert.deepStrictEqual(
|
||||
pure("a")._setContext([[[0,1],[1,2]]]).firstCycle(true),
|
||||
[hap(ts(0,1),
|
||||
ts(0,1),
|
||||
"a",
|
||||
[[[0,1],[1,2]]]
|
||||
)
|
||||
]
|
||||
)
|
||||
})
|
||||
})
|
||||
pure('a')
|
||||
._setContext([
|
||||
[
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
],
|
||||
])
|
||||
.firstCycle(true),
|
||||
[
|
||||
hap(ts(0, 1), ts(0, 1), 'a', [
|
||||
[
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
],
|
||||
]),
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('_withContext()', () => {
|
||||
it('Can update the event context', () => {
|
||||
assert.deepStrictEqual(
|
||||
pure("a")._setContext([[[0,1],[1,2]]])._withContext(c => [...c,[[3,4],[3,4]]]).firstCycle(true),
|
||||
[hap(ts(0,1),
|
||||
ts(0,1),
|
||||
"a",
|
||||
[[[0,1],[1,2]],[[3,4],[3,4]]]
|
||||
)
|
||||
]
|
||||
)
|
||||
})
|
||||
})
|
||||
describe("apply", () => {
|
||||
it('Can apply a function', () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence("a", "b")._apply(fast(2)).firstCycle(),
|
||||
sequence("a", "b").fast(2).firstCycle()
|
||||
)
|
||||
}),
|
||||
it('Can apply a pattern of functions', () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence("a", "b").apply(fast(2)).firstCycle(),
|
||||
sequence("a", "b").fast(2).firstCycle()
|
||||
)
|
||||
assert.deepStrictEqual(
|
||||
sequence("a", "b").apply(fast(2),fast(3)).firstCycle(),
|
||||
sequence("a", "b").fast(2,3).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
describe("layer", () => {
|
||||
it('Can layer up multiple functions', () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence(1,2,3).layer(fast(2), pat => pat.add(3,4)).firstCycle(),
|
||||
stack(sequence(1,2,3).fast(2), sequence(1,2,3).add(3,4)).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
describe("early", () => {
|
||||
it("Can shift an event earlier", () => {
|
||||
assert.deepStrictEqual(
|
||||
pure(30)._late(0.25).query(st(1,2)),
|
||||
[hap(ts(1/4,5/4), ts(1,5/4), 30), hap(ts(5/4,9/4), ts(5/4,2), 30)]
|
||||
)
|
||||
})
|
||||
it("Can shift an event earlier, into negative time", () => {
|
||||
assert.deepStrictEqual(
|
||||
pure(30)._late(0.25).query(st(0,1)),
|
||||
[hap(ts(-3/4,1/4), ts(0,1/4), 30), hap(ts(1/4,5/4), ts(1/4,1), 30)]
|
||||
)
|
||||
})
|
||||
})
|
||||
describe("off", () => {
|
||||
it("Can offset a transformed pattern from the original", () => {
|
||||
assert.deepStrictEqual(
|
||||
pure(30).off(0.25, add(2)).firstCycle(),
|
||||
stack(pure(30), pure(30).late(0.25).add(2)).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
describe("jux", () => {
|
||||
it("Can juxtapose", () => {
|
||||
assert.deepStrictEqual(
|
||||
pure({a: 1}).jux(fast(2))._sortEventsByPart().firstCycle(),
|
||||
stack(pure({a:1, pan: 0}), pure({a:1, pan: 1}).fast(2))._sortEventsByPart().firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
describe("_squeezeJoin", () => {
|
||||
it("Can squeeze", () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence("a", ["a","a"]).fmap(a => fastcat("b", "c"))._squeezeJoin().firstCycle(),
|
||||
sequence(["b", "c"],[["b", "c"],["b", "c"]]).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
describe("ply", () => {
|
||||
it("Can ply(3)", () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence("a", ["b","c"]).ply(3).firstCycle(),
|
||||
sequence(pure("a").fast(3), [pure("b").fast(3), pure("c").fast(3)]).firstCycle()
|
||||
)
|
||||
})
|
||||
})
|
||||
describe("chop", () => {
|
||||
it("Can _chop(2)", () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence({sound: "a"}, {sound: "b"})._chop(2).firstCycle(),
|
||||
sequence({sound: "a", begin: 0, end: 0.5},
|
||||
{sound: "a", begin: 0.5, end: 1},
|
||||
{sound: "b", begin: 0, end: 0.5},
|
||||
{sound: "b", begin: 0.5, end: 1}
|
||||
).firstCycle()
|
||||
pure('a')
|
||||
._setContext([
|
||||
[
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
],
|
||||
])
|
||||
._withContext((c) => [
|
||||
...c,
|
||||
[
|
||||
[3, 4],
|
||||
[3, 4],
|
||||
],
|
||||
])
|
||||
.firstCycle(true),
|
||||
[
|
||||
hap(ts(0, 1), ts(0, 1), 'a', [
|
||||
[
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
],
|
||||
[
|
||||
[3, 4],
|
||||
[3, 4],
|
||||
],
|
||||
]),
|
||||
],
|
||||
);
|
||||
});
|
||||
it("Can chop(2,3)", () => {
|
||||
});
|
||||
describe('apply', () => {
|
||||
it('Can apply a function', () => {
|
||||
assert.deepStrictEqual(sequence('a', 'b')._apply(fast(2)).firstCycle(), sequence('a', 'b').fast(2).firstCycle());
|
||||
}),
|
||||
it('Can apply a pattern of functions', () => {
|
||||
assert.deepStrictEqual(sequence('a', 'b').apply(fast(2)).firstCycle(), sequence('a', 'b').fast(2).firstCycle());
|
||||
assert.deepStrictEqual(
|
||||
pure({sound: "a"}).fast(2).chop(2,3)._sortEventsByPart().firstCycle(),
|
||||
sequence([{sound: "a", begin: 0, end: 0.5},
|
||||
{sound: "a", begin: 0.5, end: 1}],
|
||||
[{sound: "a", begin: 0, end: 1/3},
|
||||
{sound: "a", begin: 1/3, end: 2/3},
|
||||
{sound: "a", begin: 2/3, end: 1}
|
||||
])._sortEventsByPart().firstCycle()
|
||||
sequence('a', 'b').apply(fast(2), fast(3)).firstCycle(),
|
||||
sequence('a', 'b').fast(2, 3).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('layer', () => {
|
||||
it('Can layer up multiple functions', () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence(1, 2, 3)
|
||||
.layer(fast(2), (pat) => pat.add(3, 4))
|
||||
.firstCycle(),
|
||||
stack(sequence(1, 2, 3).fast(2), sequence(1, 2, 3).add(3, 4)).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('early', () => {
|
||||
it('Can shift an event earlier', () => {
|
||||
assert.deepStrictEqual(pure(30)._late(0.25).query(st(1, 2)), [
|
||||
hap(ts(1 / 4, 5 / 4), ts(1, 5 / 4), 30),
|
||||
hap(ts(5 / 4, 9 / 4), ts(5 / 4, 2), 30),
|
||||
]);
|
||||
});
|
||||
it('Can shift an event earlier, into negative time', () => {
|
||||
assert.deepStrictEqual(pure(30)._late(0.25).query(st(0, 1)), [
|
||||
hap(ts(-3 / 4, 1 / 4), ts(0, 1 / 4), 30),
|
||||
hap(ts(1 / 4, 5 / 4), ts(1 / 4, 1), 30),
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe('off', () => {
|
||||
it('Can offset a transformed pattern from the original', () => {
|
||||
assert.deepStrictEqual(
|
||||
pure(30).off(0.25, add(2)).firstCycle(),
|
||||
stack(pure(30), pure(30).late(0.25).add(2)).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('jux', () => {
|
||||
it('Can juxtapose', () => {
|
||||
assert.deepStrictEqual(
|
||||
pure({ a: 1 }).jux(fast(2))._sortEventsByPart().firstCycle(),
|
||||
stack(pure({ a: 1, pan: 0 }), pure({ a: 1, pan: 1 }).fast(2))
|
||||
._sortEventsByPart()
|
||||
.firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('juxBy', () => {
|
||||
it('Can juxtapose by half', () => {
|
||||
assert.deepStrictEqual(
|
||||
pure({ a: 1 }).juxBy(0.5, fast(2))._sortEventsByPart().firstCycle(),
|
||||
stack(pure({ a: 1, pan: 0.25 }), pure({ a: 1, pan: 0.75 }).fast(2))
|
||||
._sortEventsByPart()
|
||||
.firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('_squeezeJoin', () => {
|
||||
it('Can squeeze', () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence('a', ['a', 'a'])
|
||||
.fmap((a) => fastcat('b', 'c'))
|
||||
._squeezeJoin()
|
||||
.firstCycle(),
|
||||
sequence(
|
||||
['b', 'c'],
|
||||
[
|
||||
['b', 'c'],
|
||||
['b', 'c'],
|
||||
],
|
||||
).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('ply', () => {
|
||||
it('Can ply(3)', () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence('a', ['b', 'c']).ply(3).firstCycle(),
|
||||
sequence(pure('a').fast(3), [pure('b').fast(3), pure('c').fast(3)]).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('chop', () => {
|
||||
it('Can _chop(2)', () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence({ sound: 'a' }, { sound: 'b' })._chop(2).firstCycle(),
|
||||
sequence(
|
||||
{ sound: 'a', begin: 0, end: 0.5 },
|
||||
{ sound: 'a', begin: 0.5, end: 1 },
|
||||
{ sound: 'b', begin: 0, end: 0.5 },
|
||||
{ sound: 'b', begin: 0.5, end: 1 },
|
||||
).firstCycle(),
|
||||
);
|
||||
});
|
||||
it('Can chop(2,3)', () => {
|
||||
assert.deepStrictEqual(
|
||||
pure({ sound: 'a' }).fast(2).chop(2, 3)._sortEventsByPart().firstCycle(),
|
||||
sequence(
|
||||
[
|
||||
{ sound: 'a', begin: 0, end: 0.5 },
|
||||
{ sound: 'a', begin: 0.5, end: 1 },
|
||||
],
|
||||
[
|
||||
{ sound: 'a', begin: 0, end: 1 / 3 },
|
||||
{ sound: 'a', begin: 1 / 3, end: 2 / 3 },
|
||||
{ sound: 'a', begin: 2 / 3, end: 1 },
|
||||
],
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
._sortEventsByPart()
|
||||
.firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('range2', () => {
|
||||
it('Can change the range of a bipolar pattern', () => {
|
||||
assert.deepStrictEqual(
|
||||
sequence(-1, -0.5, 0, 0.5).range2(1000, 1100).firstCycle(),
|
||||
sequence(1000, 1025, 1050, 1075).firstCycle(),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -53,3 +53,33 @@ export const pipe = (...funcs) => {
|
|||
};
|
||||
|
||||
export const compose = (...funcs) => pipe(...funcs.reverse());
|
||||
|
||||
// Removes 'None' values from given list
|
||||
export const removeUndefineds = (xs) => xs.filter((x) => x != undefined);
|
||||
|
||||
export const flatten = (arr) => [].concat(...arr);
|
||||
|
||||
export const id = (a) => a;
|
||||
|
||||
export const listRange = (min, max) => Array.from({ length: max - min + 1 }, (_, i) => i + min);
|
||||
|
||||
export function curry(func, overload) {
|
||||
const fn = function curried(...args) {
|
||||
if (args.length >= func.length) {
|
||||
return func.apply(this, args);
|
||||
} else {
|
||||
const partial = function (...args2) {
|
||||
return curried.apply(this, args.concat(args2));
|
||||
};
|
||||
if (overload) {
|
||||
overload(partial, args);
|
||||
}
|
||||
return partial;
|
||||
}
|
||||
};
|
||||
if (overload) {
|
||||
// overload function without args... needed for chordBass.transpose(2)
|
||||
overload(fn, []);
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { curry } from './strudel.mjs';
|
||||
import { curry } from './util.mjs';
|
||||
|
||||
function unionWithObj(a, b, func) {
|
||||
const common = Object.keys(a).filter((k) => Object.keys(b).includes(k));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue