build
This commit is contained in:
parent
df0650e48d
commit
827c983175
24 changed files with 22150 additions and 20110 deletions
|
|
@ -118,21 +118,33 @@ class TimeSpan {
|
|||
}
|
||||
}
|
||||
class Hap {
|
||||
constructor(whole, part, value) {
|
||||
constructor(whole, part, value, context = {}, stateful = false) {
|
||||
this.whole = whole;
|
||||
this.part = part;
|
||||
this.value = value;
|
||||
this.context = context;
|
||||
this.stateful = stateful;
|
||||
if (stateful) {
|
||||
assert(typeof this.value === "function", "Stateful values must be functions");
|
||||
}
|
||||
}
|
||||
withSpan(func) {
|
||||
const whole = this.whole ? func(this.whole) : void 0;
|
||||
return new Hap(whole, func(this.part), this.value);
|
||||
return new Hap(whole, func(this.part), this.value, this.context);
|
||||
}
|
||||
withValue(func) {
|
||||
return new Hap(this.whole, this.part, func(this.value));
|
||||
return new Hap(this.whole, this.part, func(this.value), this.context);
|
||||
}
|
||||
hasOnset() {
|
||||
return this.whole != void 0 && this.whole.begin.equals(this.part.begin);
|
||||
}
|
||||
resolveState(state) {
|
||||
if (this.stateful && this.hasOnset()) {
|
||||
const func = this.value[newState, newValue] = func(state);
|
||||
return [newState, this.withValue(() => newValue)];
|
||||
}
|
||||
return [state, this];
|
||||
}
|
||||
spanEquals(other) {
|
||||
return this.whole == void 0 && other.whole == void 0 || this.whole.equals(other.whole);
|
||||
}
|
||||
|
|
@ -140,7 +152,25 @@ class Hap {
|
|||
return this.spanEquals(other) && this.part.equals(other.part) && this.value === other.value;
|
||||
}
|
||||
show() {
|
||||
return "(" + (this.whole == void 0 ? "~" : this.whole.show()) + ", " + this.part.show() + ", " + JSON.stringify(this.value?.value ?? this.value) + ")";
|
||||
return "(" + (this.whole == void 0 ? "~" : this.whole.show()) + ", " + this.part.show() + ", " + this.value + ")";
|
||||
}
|
||||
setContext(context) {
|
||||
return new Hap(this.whole, this.part, this.value, context);
|
||||
}
|
||||
}
|
||||
export class State {
|
||||
constructor(span, controls = {}) {
|
||||
this.span = span;
|
||||
this.controls = controls;
|
||||
}
|
||||
setSpan(span) {
|
||||
return new State(span, this.controls);
|
||||
}
|
||||
withSpan(func) {
|
||||
return this.setSpan(func(this.span));
|
||||
}
|
||||
setControls(controls) {
|
||||
return new State(this.span, controls);
|
||||
}
|
||||
}
|
||||
class Pattern {
|
||||
|
|
@ -157,42 +187,55 @@ class Pattern {
|
|||
}
|
||||
_splitQueries() {
|
||||
const pat = this;
|
||||
const q = (span) => flatten(span.spanCycles.map((subspan) => pat.query(subspan)));
|
||||
const q = (state) => {
|
||||
return flatten(state.span.spanCycles.map((subspan) => pat.query(state.setSpan(subspan))));
|
||||
};
|
||||
return new Pattern(q);
|
||||
}
|
||||
withQuerySpan(func) {
|
||||
return new Pattern((span) => this.query(func(span)));
|
||||
return new Pattern((state) => this.query(state.withSpan(func)));
|
||||
}
|
||||
withQueryTime(func) {
|
||||
return new Pattern((span) => this.query(span.withTime(func)));
|
||||
return new Pattern((state) => this.query(state.withSpan((span) => span.withTime(func))));
|
||||
}
|
||||
withEventSpan(func) {
|
||||
return new Pattern((span) => this.query(span).map((hap) => hap.withSpan(func)));
|
||||
return new Pattern((state) => this.query(state).map((hap) => hap.withSpan(func)));
|
||||
}
|
||||
withEventTime(func) {
|
||||
return this.withEventSpan((span) => span.withTime(func));
|
||||
}
|
||||
_withEvents(func) {
|
||||
return new Pattern((span) => func(this.query(span)));
|
||||
return new Pattern((state) => func(this.query(state)));
|
||||
}
|
||||
_withEvent(func) {
|
||||
return this._withEvents((events) => events.map(func));
|
||||
}
|
||||
_setContext(context) {
|
||||
return this._withEvent((event) => event.setContext(context));
|
||||
}
|
||||
_withContext(func) {
|
||||
return this._withEvent((event) => event.setContext(func(event.context)));
|
||||
}
|
||||
_stripContext() {
|
||||
return this._withEvent((event) => event.setContext({}));
|
||||
}
|
||||
withLocation(location) {
|
||||
return this.fmap((value) => {
|
||||
value = typeof value === "object" && !Array.isArray(value) ? value : {value};
|
||||
const locations = (value.locations || []).concat([location]);
|
||||
return {...value, locations};
|
||||
return this._withContext((context) => {
|
||||
const locations = (context.locations || []).concat([location]);
|
||||
return {...context, locations};
|
||||
});
|
||||
}
|
||||
withValue(func) {
|
||||
return new Pattern((span) => this.query(span).map((hap) => hap.withValue(func)));
|
||||
return new Pattern((state) => this.query(state).map((hap) => hap.withValue(func)));
|
||||
}
|
||||
fmap(func) {
|
||||
return this.withValue(func);
|
||||
}
|
||||
_filterEvents(event_test) {
|
||||
return new Pattern((span) => this.query(span).filter(event_test));
|
||||
return new Pattern((state) => this.query(state).filter(event_test));
|
||||
}
|
||||
_filterValues(value_test) {
|
||||
return new Pattern((span) => this.query(span).filter((hap) => value_test(hap.value)));
|
||||
return new Pattern((state) => this.query(state).filter((hap) => value_test(hap.value)));
|
||||
}
|
||||
_removeUndefineds() {
|
||||
return this._filterValues((val) => val != void 0);
|
||||
|
|
@ -202,15 +245,15 @@ class Pattern {
|
|||
}
|
||||
_appWhole(whole_func, pat_val) {
|
||||
const pat_func = this;
|
||||
const query = function(span) {
|
||||
const event_funcs = pat_func.query(span);
|
||||
const event_vals = pat_val.query(span);
|
||||
const query = function(state) {
|
||||
const event_funcs = pat_func.query(state);
|
||||
const event_vals = pat_val.query(state);
|
||||
const apply = function(event_func, event_val) {
|
||||
const s = event_func.part.intersection(event_val.part);
|
||||
if (s == void 0) {
|
||||
return void 0;
|
||||
}
|
||||
return new Hap(whole_func(event_func.whole, event_val.whole), s, event_func.value(event_val.value));
|
||||
return new Hap(whole_func(event_func.whole, event_val.whole), s, event_func.value(event_val.value), event_val.context);
|
||||
};
|
||||
return flatten(event_funcs.map((event_func) => removeUndefineds(event_vals.map((event_val) => apply(event_func, event_val)))));
|
||||
};
|
||||
|
|
@ -227,15 +270,19 @@ class Pattern {
|
|||
}
|
||||
appLeft(pat_val) {
|
||||
const pat_func = this;
|
||||
const query = function(span) {
|
||||
const query = function(state) {
|
||||
const haps = [];
|
||||
for (const hap_func of pat_func.query(span)) {
|
||||
const event_vals = pat_val.query(hap_func.part);
|
||||
for (const hap_func of pat_func.query(state)) {
|
||||
const event_vals = pat_val.query(state.setSpan(hap_func.part));
|
||||
for (const hap_val of event_vals) {
|
||||
const new_whole = hap_func.whole;
|
||||
const new_part = hap_func.part.intersection_e(hap_val.part);
|
||||
const new_value = hap_func.value(hap_val.value);
|
||||
const hap = new Hap(new_whole, new_part, new_value);
|
||||
const hap = new Hap(new_whole, new_part, new_value, {
|
||||
...hap_val.context,
|
||||
...hap_func.context,
|
||||
locations: (hap_val.context.locations || []).concat(hap_func.context.locations || [])
|
||||
});
|
||||
haps.push(hap);
|
||||
}
|
||||
}
|
||||
|
|
@ -245,15 +292,19 @@ class Pattern {
|
|||
}
|
||||
appRight(pat_val) {
|
||||
const pat_func = this;
|
||||
const query = function(span) {
|
||||
const query = function(state) {
|
||||
const haps = [];
|
||||
for (const hap_val of pat_val.query(span)) {
|
||||
const hap_funcs = pat_func.query(hap_val.part);
|
||||
for (const hap_val of pat_val.query(state)) {
|
||||
const hap_funcs = pat_func.query(state.setSpan(hap_val.part));
|
||||
for (const hap_func of hap_funcs) {
|
||||
const new_whole = hap_val.whole;
|
||||
const new_part = hap_func.part.intersection_e(hap_val.part);
|
||||
const new_value = hap_func.value(hap_val.value);
|
||||
const hap = new Hap(new_whole, new_part, new_value);
|
||||
const hap = new Hap(new_whole, new_part, new_value, {
|
||||
...hap_func.context,
|
||||
...hap_val.context,
|
||||
locations: (hap_val.context.locations || []).concat(hap_func.context.locations || [])
|
||||
});
|
||||
haps.push(hap);
|
||||
}
|
||||
}
|
||||
|
|
@ -261,8 +312,12 @@ class Pattern {
|
|||
};
|
||||
return new Pattern(query);
|
||||
}
|
||||
get firstCycle() {
|
||||
return this.query(new TimeSpan(Fraction(0), Fraction(1)));
|
||||
firstCycle(with_context = false) {
|
||||
var self = this;
|
||||
if (!with_context) {
|
||||
self = self._stripContext();
|
||||
}
|
||||
return self.query(new State(new TimeSpan(Fraction(0), Fraction(1))));
|
||||
}
|
||||
_sortEventsByPart() {
|
||||
return this._withEvents((events) => events.sort((a, b) => a.part.begin.sub(b.part.begin).or(a.part.end.sub(b.part.end)).or(a.whole.begin.sub(b.whole.begin).or(a.whole.end.sub(b.whole.end)))));
|
||||
|
|
@ -287,14 +342,18 @@ class Pattern {
|
|||
}
|
||||
_bindWhole(choose_whole, func) {
|
||||
const pat_val = this;
|
||||
const query = function(span) {
|
||||
const query = function(state) {
|
||||
const withWhole = function(a, b) {
|
||||
return new Hap(choose_whole(a.whole, b.whole), b.part, b.value);
|
||||
return new Hap(choose_whole(a.whole, b.whole), b.part, b.value, {
|
||||
...a.context,
|
||||
...b.context,
|
||||
locations: (a.context.locations || []).concat(b.context.locations || [])
|
||||
});
|
||||
};
|
||||
const match = function(a) {
|
||||
return func(a.value).query(a.part).map((b) => withWhole(a, b));
|
||||
return func(a.value).query(state.setSpan(a.part)).map((b) => withWhole(a, b));
|
||||
};
|
||||
return flatten(pat_val.query(span).map((a) => match(a)));
|
||||
return flatten(pat_val.query(state).map((a) => match(a)));
|
||||
};
|
||||
return new Pattern(query);
|
||||
}
|
||||
|
|
@ -409,7 +468,8 @@ class Pattern {
|
|||
}
|
||||
rev() {
|
||||
const pat = this;
|
||||
const query = function(span) {
|
||||
const query = function(state) {
|
||||
const span = state.span;
|
||||
const cycle = span.begin.sam();
|
||||
const next_cycle = span.begin.nextSam();
|
||||
const reflect = function(to_reflect) {
|
||||
|
|
@ -419,7 +479,7 @@ class Pattern {
|
|||
reflected.end = tmp;
|
||||
return reflected;
|
||||
};
|
||||
const haps = pat.query(reflect(span));
|
||||
const haps = pat.query(state.setSpan(reflect(span)));
|
||||
return haps.map((hap) => hap.withSpan(reflect));
|
||||
};
|
||||
return new Pattern(query)._splitQueries();
|
||||
|
|
@ -463,8 +523,8 @@ Pattern.prototype.patternified = ["apply", "fast", "slow", "early", "late"];
|
|||
Pattern.prototype.factories = {pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr};
|
||||
const silence = new Pattern((_) => []);
|
||||
function pure(value) {
|
||||
function query(span) {
|
||||
return span.spanCycles.map((subspan) => new Hap(Fraction(subspan.begin).wholeCycle(), subspan, value));
|
||||
function query(state) {
|
||||
return state.span.spanCycles.map((subspan) => new Hap(Fraction(subspan.begin).wholeCycle(), subspan, value));
|
||||
}
|
||||
return new Pattern(query);
|
||||
}
|
||||
|
|
@ -472,7 +532,7 @@ function steady(value) {
|
|||
return new Pattern((span) => Hap(void 0, span, value));
|
||||
}
|
||||
export const signal = (func) => {
|
||||
const query = (span) => [new Hap(void 0, span, func(span.midpoint()))];
|
||||
const query = (state) => [new Hap(void 0, state.span, func(state.span.midpoint()))];
|
||||
return new Pattern(query);
|
||||
};
|
||||
const _toBipolar = (pat) => pat.fmap((x) => x * 2 - 1);
|
||||
|
|
@ -497,28 +557,29 @@ function reify(thing) {
|
|||
}
|
||||
function stack(...pats) {
|
||||
const reified = pats.map((pat) => reify(pat));
|
||||
const query = (span) => flatten(reified.map((pat) => pat.query(span)));
|
||||
const query = (state) => flatten(reified.map((pat) => pat.query(state)));
|
||||
return new Pattern(query);
|
||||
}
|
||||
function slowcat(...pats) {
|
||||
pats = pats.map(reify);
|
||||
const query = function(span) {
|
||||
const query = function(state) {
|
||||
const span = state.span;
|
||||
const pat_n = Math.floor(span.begin) % pats.length;
|
||||
const pat = pats[pat_n];
|
||||
if (!pat) {
|
||||
return [];
|
||||
}
|
||||
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 pat.withEventTime((t) => t.add(offset)).query(state.setSpan(span.withTime((t) => t.sub(offset))));
|
||||
};
|
||||
return new Pattern(query)._splitQueries();
|
||||
}
|
||||
function slowcatPrime(...pats) {
|
||||
pats = pats.map(reify);
|
||||
const query = function(span) {
|
||||
const pat_n = Math.floor(span.begin) % pats.length;
|
||||
const query = function(state) {
|
||||
const pat_n = Math.floor(state.span.begin) % pats.length;
|
||||
const pat = pats[pat_n];
|
||||
return pat.query(span);
|
||||
return pat.query(state);
|
||||
};
|
||||
return new Pattern(query)._splitQueries();
|
||||
}
|
||||
|
|
@ -638,9 +699,8 @@ Pattern.prototype.bootstrap = () => {
|
|||
return bootstrapped;
|
||||
};
|
||||
function withLocationOffset(pat, offset) {
|
||||
return pat.fmap((value) => {
|
||||
value = typeof value === "object" && !Array.isArray(value) ? value : {value};
|
||||
let locations = value.locations || [];
|
||||
return pat._withContext((context) => {
|
||||
let locations = context.locations || [];
|
||||
locations = locations.map(({start, end}) => {
|
||||
const colOffset = start.line === 1 ? offset.start.column : 0;
|
||||
return {
|
||||
|
|
@ -656,7 +716,7 @@ function withLocationOffset(pat, offset) {
|
|||
}
|
||||
};
|
||||
});
|
||||
return {...value, locations};
|
||||
return {...context, locations};
|
||||
});
|
||||
}
|
||||
export {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue