struct() and invert()/inv()

This commit is contained in:
alex 2022-02-19 16:54:44 +00:00
parent c427b1594d
commit 7b34f3f524
2 changed files with 47 additions and 1 deletions

View File

@ -294,6 +294,10 @@ class Pattern {
return new Pattern(span => this.query(span).filter(hap => value_test(hap.value))) return new Pattern(span => this.query(span).filter(hap => value_test(hap.value)))
} }
_removeUndefineds() {
return(this._filterValues(val => val != undefined))
}
onsetsOnly() { onsetsOnly() {
// Returns a new pattern that will only return events where the start // Returns a new pattern that will only return events where the start
// of the 'whole' timespan matches the start of the 'part' // of the 'whole' timespan matches the start of the 'part'
@ -507,6 +511,17 @@ class Pattern {
return this._early(0-offset) return this._early(0-offset)
} }
struct(...binary_pats) {
// Re structure the pattern according to a binary pattern (false values are dropped)
const binary_pat = sequence(binary_pats)
return binary_pat.fmap(b => val => b ? val : undefined).appRight(this)._removeUndefineds()
}
inv() {
// Swap true/false in a binary pattern
return this.fmap(x => !x)
}
when(binary_pat, func) { when(binary_pat, func) {
//binary_pat = sequence(binary_pat) //binary_pat = sequence(binary_pat)
const true_pat = binary_pat._filterValues(id) const true_pat = binary_pat._filterValues(id)
@ -612,10 +627,13 @@ Pattern.prototype.patternified = ['fast', 'slow', 'early', 'late'];
Pattern.prototype.factories = { pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr}; Pattern.prototype.factories = { pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr};
// the magic happens in Pattern constructor. Keeping this in prototype enables adding methods from the outside (e.g. see tonal.ts) // the magic happens in Pattern constructor. Keeping this in prototype enables adding methods from the outside (e.g. see tonal.ts)
// Elemental patterns
// Nothing
const silence = new Pattern(_ => []) const silence = new Pattern(_ => [])
function pure(value) { function pure(value) {
// Returns a pattern that repeats the given value once per cycle // A discrete value that repeats once per cycle
function query(span) { function query(span) {
return span.spanCycles.map(subspan => new Hap(Fraction(subspan.begin).wholeCycle(), subspan, value)) return span.spanCycles.map(subspan => new Hap(Fraction(subspan.begin).wholeCycle(), subspan, value))
} }
@ -623,16 +641,20 @@ function pure(value) {
} }
function steady(value) { function steady(value) {
// A continuous value
return new Pattern(span => Hap(undefined, span, value)) return new Pattern(span => Hap(undefined, span, value))
} }
function reify(thing) { function reify(thing) {
// Tunrs something into a pattern, unless it's already a pattern
if (thing?.constructor?.name == "Pattern") { if (thing?.constructor?.name == "Pattern") {
return thing return thing
} }
return pure(thing) return pure(thing)
} }
// Basic functions for combining patterns
function stack(...pats) { function stack(...pats) {
const reified = pats.map(pat => reify(pat)) const reified = pats.map(pat => reify(pat))
const query = span => flatten(reified.map(pat => pat.query(span))) const query = span => flatten(reified.map(pat => pat.query(span)))
@ -682,6 +704,7 @@ function cat(...pats) {
} }
function timeCat(...timepats) { function timeCat(...timepats) {
// Like cat, but where each step has a temporal 'weight'
const total = timepats.map(a => a[0]).reduce((a,b) => a.add(b), Fraction(0)) const total = timepats.map(a => a[0]).reduce((a,b) => a.add(b), Fraction(0))
let begin = Fraction(0) let begin = Fraction(0)
const pats = [] const pats = []

View File

@ -10,6 +10,9 @@ const { Time } = pkg;
const ts = (begin, end) => new TimeSpan(Fraction(begin), Fraction(end)); const ts = (begin, end) => new TimeSpan(Fraction(begin), Fraction(end));
const hap = (whole, part, value) => new Hap(whole, part, value) const hap = (whole, part, value) => new Hap(whole, part, value)
const third = Fraction(1,3)
const twothirds = Fraction(2,3)
describe('TimeSpan', function() { describe('TimeSpan', function() {
describe('equals()', function() { describe('equals()', function() {
it('Should be equal to the same value', function() { it('Should be equal to the same value', function() {
@ -244,4 +247,24 @@ describe('Pattern', function() {
) )
}) })
}) })
describe('struct()', function() {
it('Can restructure a pattern', function() {
assert.deepStrictEqual(
sequence("a", "b").struct(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")
]
)
})
})
describe('inv()', function() {
it('Can invert a binary pattern', function() {
assert.deepStrictEqual(
sequence(true, false, [true, false]).inv().firstCycle,
sequence(false, true, [false, true]).firstCycle
)
})
})
}) })