linked-rolls 0.56.0 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -361
- package/lib/{constraints.d.ts → analysis/constraints.d.ts} +1 -1
- package/lib/{constraints.js → analysis/constraints.js} +9 -8
- package/lib/analysis/ownPaper.d.ts +26 -0
- package/lib/analysis/ownPaper.js +41 -0
- package/lib/{reservations.d.ts → analysis/reservations.d.ts} +3 -3
- package/lib/{reservations.js → analysis/reservations.js} +3 -3
- package/lib/{sigla.d.ts → analysis/sigla.d.ts} +2 -2
- package/lib/{sigla.js → analysis/sigla.js} +4 -4
- package/lib/{witnesses.d.ts → analysis/witnesses.d.ts} +2 -2
- package/lib/{witnesses.js → analysis/witnesses.js} +4 -4
- package/lib/{Collation.d.ts → collation/Collation.d.ts} +4 -4
- package/lib/{Collation.js → collation/Collation.js} +4 -4
- package/lib/{alignment.d.ts → collation/alignment.d.ts} +4 -4
- package/lib/{alignment.js → collation/alignment.js} +10 -16
- package/lib/{scatter.d.ts → collation/scatter.d.ts} +4 -4
- package/lib/{scatter.js → collation/scatter.js} +6 -6
- package/lib/{statistics.d.ts → collation/statistics.d.ts} +1 -1
- package/lib/{statistics.js → collation/statistics.js} +2 -2
- package/lib/{substitution.d.ts → collation/substitution.d.ts} +9 -24
- package/lib/{substitution.js → collation/substitution.js} +13 -37
- package/lib/emulation/Emulation.d.ts +64 -0
- package/lib/emulation/Emulation.js +282 -0
- package/lib/emulation/negotiation.d.ts +14 -0
- package/lib/emulation/negotiation.js +20 -0
- package/lib/index.d.ts +43 -35
- package/lib/index.js +36 -35
- package/lib/{asJsonLd.d.ts → io/asJsonLd.d.ts} +1 -1
- package/lib/{asJsonLd.js → io/asJsonLd.js} +22 -51
- package/lib/{context.d.ts → io/context.d.ts} +4 -4
- package/lib/{context.js → io/context.js} +4 -4
- package/lib/{importJsonLd.d.ts → io/importJsonLd.d.ts} +1 -1
- package/lib/io/importJsonLd.js +128 -0
- package/lib/{migrate.d.ts → io/migrate.d.ts} +9 -0
- package/lib/{migrate.js → io/migrate.js} +97 -54
- package/lib/{Agent.d.ts → model/Agent.d.ts} +1 -1
- package/lib/{Assumption.d.ts → model/Assumption.d.ts} +1 -1
- package/lib/{ConditionState.d.ts → model/ConditionState.d.ts} +1 -2
- package/lib/{Edit.d.ts → model/Edit.d.ts} +1 -1
- package/lib/{Edition.d.ts → model/Edition.d.ts} +2 -2
- package/lib/{Feature.d.ts → model/Feature.d.ts} +3 -1
- package/lib/{Feature.js → model/Feature.js} +2 -0
- package/lib/{FeatureSource.d.ts → model/FeatureSource.d.ts} +1 -1
- package/lib/{Perforator.d.ts → model/Perforator.d.ts} +1 -1
- package/lib/{RollCopy.d.ts → model/RollCopy.d.ts} +5 -12
- package/lib/{RollCopy.js → model/RollCopy.js} +3 -5
- package/lib/{Symbol.d.ts → model/Symbol.d.ts} +1 -1
- package/lib/{Version.d.ts → model/Version.d.ts} +11 -3
- package/lib/{Version.js → model/Version.js} +24 -1
- package/lib/{vocabulary.js → model/vocabulary.js} +2 -2
- package/lib/ops/beliefs.d.ts +9 -0
- package/lib/ops/beliefs.js +31 -0
- package/lib/ops/collation.d.ts +62 -0
- package/lib/ops/collation.js +228 -0
- package/lib/ops/commands.d.ts +9 -0
- package/lib/ops/commands.js +29 -0
- package/lib/ops/copies.d.ts +74 -0
- package/lib/ops/copies.js +135 -0
- package/lib/ops/draft.d.ts +59 -0
- package/lib/ops/draft.js +81 -0
- package/lib/ops/edits.d.ts +10 -0
- package/lib/ops/edits.js +82 -0
- package/lib/ops/features.d.ts +84 -0
- package/lib/ops/features.js +296 -0
- package/lib/ops/forget.d.ts +31 -0
- package/lib/ops/forget.js +110 -0
- package/lib/ops/immutable.d.ts +16 -0
- package/lib/ops/immutable.js +46 -0
- package/lib/ops/index.d.ts +13 -0
- package/lib/ops/index.js +7 -0
- package/lib/ops/versions.d.ts +33 -0
- package/lib/ops/versions.js +95 -0
- package/lib/readers/AtonParser.js +5 -7
- package/lib/readers/phillipsEroll.d.ts +3 -3
- package/lib/readers/phillipsEroll.js +4 -5
- package/lib/readers/spencerBar.d.ts +2 -2
- package/lib/readers/spencerBar.js +2 -3
- package/lib/readers/stanfordAton.d.ts +3 -3
- package/lib/readers/stanfordAton.js +2 -4
- package/lib/schema.json +11 -151
- package/lib/spec/context.json +2 -12
- package/lib/{ReproducingSystem.d.ts → systems/ReproducingSystem.d.ts} +3 -3
- package/lib/{TrackerBar.d.ts → systems/TrackerBar.d.ts} +48 -8
- package/lib/{TrackerBar.js → systems/TrackerBar.js} +11 -2
- package/lib/systems/index.d.ts +8 -2
- package/lib/systems/index.js +7 -1
- package/lib/systems/welte.d.ts +100 -0
- package/lib/systems/welte.js +119 -0
- package/lib/systems/welteLicensee/bar.d.ts +1 -1
- package/lib/systems/welteLicensee/bar.js +5 -2
- package/lib/systems/welteLicensee/system.d.ts +1 -1
- package/lib/systems/welteLicensee/system.js +1 -1
- package/lib/systems/welteT100/bar.d.ts +27 -1
- package/lib/systems/welteT100/bar.js +44 -2
- package/lib/systems/welteT100/system.d.ts +6 -39
- package/lib/systems/welteT100/system.js +19 -128
- package/lib/systems/welteT98/bar.d.ts +1 -1
- package/lib/systems/welteT98/bar.js +18 -2
- package/lib/systems/welteT98/system.d.ts +20 -38
- package/lib/systems/welteT98/system.js +20 -121
- package/lib/validate.d.ts +1 -1
- package/lib/{EditionView.d.ts → view/EditionView.d.ts} +38 -48
- package/lib/{EditionView.js → view/EditionView.js} +90 -96
- package/package.json +7 -2
- package/lib/Emulation.d.ts +0 -36
- package/lib/Emulation.js +0 -250
- package/lib/editionOps.d.ts +0 -260
- package/lib/editionOps.js +0 -1081
- package/lib/importJsonLd.js +0 -62
- /package/lib/{Agent.js → model/Agent.js} +0 -0
- /package/lib/{Assumption.js → model/Assumption.js} +0 -0
- /package/lib/{ConditionState.js → model/ConditionState.js} +0 -0
- /package/lib/{Edit.js → model/Edit.js} +0 -0
- /package/lib/{Edition.js → model/Edition.js} +0 -0
- /package/lib/{FeatureSource.js → model/FeatureSource.js} +0 -0
- /package/lib/{Perforator.js → model/Perforator.js} +0 -0
- /package/lib/{Quantity.d.ts → model/Quantity.d.ts} +0 -0
- /package/lib/{Quantity.js → model/Quantity.js} +0 -0
- /package/lib/{Symbol.js → model/Symbol.js} +0 -0
- /package/lib/{TrackCalibration.d.ts → model/TrackCalibration.d.ts} +0 -0
- /package/lib/{TrackCalibration.js → model/TrackCalibration.js} +0 -0
- /package/lib/{notes.d.ts → model/notes.d.ts} +0 -0
- /package/lib/{notes.js → model/notes.js} +0 -0
- /package/lib/{procedures.d.ts → model/procedures.d.ts} +0 -0
- /package/lib/{procedures.js → model/procedures.js} +0 -0
- /package/lib/{vocabulary.d.ts → model/vocabulary.d.ts} +0 -0
- /package/lib/{sorted.d.ts → shared/sorted.d.ts} +0 -0
- /package/lib/{sorted.js → shared/sorted.js} +0 -0
- /package/lib/{utils.d.ts → shared/utils.d.ts} +0 -0
- /package/lib/{utils.js → shared/utils.js} +0 -0
- /package/lib/{ReproducingSystem.js → systems/ReproducingSystem.js} +0 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { MIDIControlEvents } from "midifile-ts";
|
|
2
|
+
import { idOf } from "../model/Assumption.js";
|
|
3
|
+
import { isCommand, pairsAmong, placementsOf } from "../model/Symbol.js";
|
|
4
|
+
import { add, mean, mm, seconds, subtract } from "../model/Quantity.js";
|
|
5
|
+
import { punchDiameterOf } from "../model/RollCopy.js";
|
|
6
|
+
import { toOwnPaperOf } from "../analysis/ownPaper.js";
|
|
7
|
+
import { negotiatedEventOf } from "./negotiation.js";
|
|
8
|
+
/** The punch diameter the edition's copies report, where any of them does. */
|
|
9
|
+
const meanPunchDiameterOf = (view) => {
|
|
10
|
+
const measured = view.edition.copies
|
|
11
|
+
.map(punchDiameterOf)
|
|
12
|
+
.filter(value => value !== undefined);
|
|
13
|
+
return measured.length > 0 ? mean(measured) : undefined;
|
|
14
|
+
};
|
|
15
|
+
const propertiesOf = (view, version) => ({
|
|
16
|
+
punchDiameter: meanPunchDiameterOf(view),
|
|
17
|
+
tempo: view.edition.tempoAdjustment,
|
|
18
|
+
toOwnPaper: toOwnPaperOf(view, version)
|
|
19
|
+
});
|
|
20
|
+
/** The onset a symbol has on each copy carrying it, by the copy's id, as the mean of its chains there. */
|
|
21
|
+
const onsetsByCopy = (view, symbolId) => {
|
|
22
|
+
const symbol = view.symbol(symbolId);
|
|
23
|
+
if (!symbol)
|
|
24
|
+
return new Map();
|
|
25
|
+
const onsets = view.placedCarriersOf(symbol).flatMap((carrier) => {
|
|
26
|
+
const copy = view.copyOf(carrier.id);
|
|
27
|
+
return copy ? [[copy.id, carrier.horizontal.from]] : [];
|
|
28
|
+
});
|
|
29
|
+
const copies = new Set(onsets.map(([copy]) => copy));
|
|
30
|
+
return new Map([...copies].map(copy => [copy, mean(onsets.filter(([at]) => at === copy).map(([, onset]) => onset))]));
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* The measured distance from the onset of the reference to the onset of
|
|
34
|
+
* the follower on each copy carrying both, negative where the follower
|
|
35
|
+
* comes first there.
|
|
36
|
+
*/
|
|
37
|
+
const offsetsBetween = (view, followerId, referenceId) => {
|
|
38
|
+
const references = onsetsByCopy(view, referenceId);
|
|
39
|
+
return [...onsetsByCopy(view, followerId)].flatMap(([copy, onset]) => {
|
|
40
|
+
const reference = references.get(copy);
|
|
41
|
+
return reference === undefined ? [] : [subtract(onset, reference)];
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* How far before or after its reference a follower is put when the
|
|
46
|
+
* measurement does not already have it there: as far as the copies
|
|
47
|
+
* that agree with the statement put it, and one gap where none does.
|
|
48
|
+
*/
|
|
49
|
+
const distanceOnSide = (side, offsets, gap) => {
|
|
50
|
+
const agreeing = offsets.filter(offset => side === 'before' ? offset < 0 : offset > 0);
|
|
51
|
+
return agreeing.length > 0 ? mm(Math.abs(mean(agreeing))) : gap;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* How far each event has to move for the placements to hold:
|
|
55
|
+
* an aligned event takes the onset of its reference, one placed before
|
|
56
|
+
* or after its reference keeps its place where the measurement has it
|
|
57
|
+
* on that side and is moved there where it does not, and a paired
|
|
58
|
+
* event follows its partner so that the distance between the two is
|
|
59
|
+
* kept. Events that stay where they are do not appear.
|
|
60
|
+
*/
|
|
61
|
+
const displacementsOf = (events, offsetsBetween, gap) => {
|
|
62
|
+
const byId = new Map(events.map(event => [event.id, event]));
|
|
63
|
+
/** Where an event comes to lie once its statement and those of its references hold. */
|
|
64
|
+
const placedOnsetOf = (event, visited = new Set()) => {
|
|
65
|
+
const measured = event.horizontal.from;
|
|
66
|
+
const placement = placementsOf(event)[0];
|
|
67
|
+
const reference = placement && byId.get(idOf(placement.reference));
|
|
68
|
+
if (!placement || !reference || reference.id === event.id || visited.has(event.id))
|
|
69
|
+
return measured;
|
|
70
|
+
const referenceOnset = placedOnsetOf(reference, new Set([...visited, event.id]));
|
|
71
|
+
const distance = (side) => distanceOnSide(side, offsetsBetween(event.id, reference.id), gap);
|
|
72
|
+
switch (placement.relation) {
|
|
73
|
+
case 'alignedWith': return referenceOnset;
|
|
74
|
+
case 'before': return measured < referenceOnset ? measured : subtract(referenceOnset, distance('before'));
|
|
75
|
+
case 'after': return measured > referenceOnset ? measured : add(referenceOnset, distance('after'));
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const displacements = new Map(events
|
|
79
|
+
.map((event) => [event, subtract(placedOnsetOf(event), event.horizontal.from)])
|
|
80
|
+
.filter(([, distance]) => distance !== 0));
|
|
81
|
+
pairsAmong(events).forEach(([one, other]) => {
|
|
82
|
+
const shared = displacements.get(one) ?? displacements.get(other);
|
|
83
|
+
if (shared === undefined)
|
|
84
|
+
return;
|
|
85
|
+
displacements.set(one, shared);
|
|
86
|
+
displacements.set(other, shared);
|
|
87
|
+
});
|
|
88
|
+
return displacements;
|
|
89
|
+
};
|
|
90
|
+
/** The earliest of the times, or the beginning of the roll where there are none. */
|
|
91
|
+
const earliestOf = (times) => times.length === 0 ? seconds(0) : times.reduce((soonest, at) => at < soonest ? at : soonest);
|
|
92
|
+
/**
|
|
93
|
+
* The events moved to where their statements put them, the events given
|
|
94
|
+
* left as they were. The view supplies the copies, whose measurements
|
|
95
|
+
* decide how far before or after its reference a command goes, and a
|
|
96
|
+
* punch diameter, or a millimetre, where no copy agrees with a statement.
|
|
97
|
+
*/
|
|
98
|
+
export const withPlacementsApplied = (view, events) => {
|
|
99
|
+
const gap = meanPunchDiameterOf(view) ?? mm(1);
|
|
100
|
+
const offsets = (follower, reference) => offsetsBetween(view, follower, reference);
|
|
101
|
+
const displacements = displacementsOf(events, offsets, gap);
|
|
102
|
+
return events.map(event => {
|
|
103
|
+
const distance = displacements.get(event);
|
|
104
|
+
return distance === undefined ? event : {
|
|
105
|
+
...event,
|
|
106
|
+
horizontal: { ...event.horizontal, from: add(event.horizontal.from, distance), to: add(event.horizontal.to, distance) }
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* The commands of a version as the bar performs them, in order of place,
|
|
112
|
+
* within the scope and with the placements applied. A note plays only
|
|
113
|
+
* where its onset falls in the range; expressions play throughout.
|
|
114
|
+
*/
|
|
115
|
+
export const negotiatedEventsOf = (view, version, bar, { range } = {}) => {
|
|
116
|
+
const inScope = (event) => !range || event.type !== 'note' || (event.horizontal.from > range[0] && event.horizontal.from < range[1]);
|
|
117
|
+
return withPlacementsApplied(view, view.snapshot(version.id)
|
|
118
|
+
.filter(isCommand)
|
|
119
|
+
.map(symbol => negotiatedEventOf(view, symbol, bar))
|
|
120
|
+
.filter(event => event !== null)
|
|
121
|
+
.filter(inScope));
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Performs a version on a reproducing system: the symbols are negotiated
|
|
125
|
+
* into placed events and the system plays them. Nothing given is changed.
|
|
126
|
+
*/
|
|
127
|
+
export const emulate = (system, version, view, options = system.defaultOptions, { range, skipToFirstNote = false } = {}) => {
|
|
128
|
+
const negotiated = negotiatedEventsOf(view, version, system.trackerBar, { range });
|
|
129
|
+
if (negotiated.length === 0)
|
|
130
|
+
return { source: version.id, negotiated, events: [], curves: [] };
|
|
131
|
+
const performance = system.perform(negotiated, options, propertiesOf(view, version));
|
|
132
|
+
const onsets = performance.events.filter(event => event.type === 'noteOn').map(event => event.at);
|
|
133
|
+
const origin = skipToFirstNote ? earliestOf(onsets) : seconds(0);
|
|
134
|
+
return {
|
|
135
|
+
source: version.id,
|
|
136
|
+
negotiated,
|
|
137
|
+
curves: performance.curves,
|
|
138
|
+
events: performance.events
|
|
139
|
+
.map(event => ({ ...event, at: subtract(event.at, origin) }))
|
|
140
|
+
.filter(event => event.at >= 0)
|
|
141
|
+
.sort((a, b) => a.at - b.at)
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* The performed events as a MIDI file, in which every note and pedal step
|
|
146
|
+
* is labelled with the symbol it performs. The file names the system, the
|
|
147
|
+
* version and the options it was played with.
|
|
148
|
+
*/
|
|
149
|
+
export const midiOf = (events, systemName, options, source) => {
|
|
150
|
+
const TICKS_PER_SECOND = 1000;
|
|
151
|
+
const midi = [];
|
|
152
|
+
const text = (text, deltaTime = 0) => ({ type: 'meta', subtype: 'text', text, deltaTime });
|
|
153
|
+
const controller = (controllerType, value, deltaTime = 0) => ({ type: 'channel', subtype: 'controller', controllerType, value, deltaTime, channel: 0 });
|
|
154
|
+
const controllerOf = (event) => event.type === 'damper' ? MIDIControlEvents.SUSTAIN : MIDIControlEvents.SOFT_PEDAL;
|
|
155
|
+
midi.push(text(`linked-rolls (${systemName})`));
|
|
156
|
+
if (source) {
|
|
157
|
+
midi.push(text(source));
|
|
158
|
+
}
|
|
159
|
+
for (const [key, value] of Object.entries(options)) {
|
|
160
|
+
midi.push(text(`${key}=${typeof value === 'object' ? JSON.stringify(value) : value}`));
|
|
161
|
+
}
|
|
162
|
+
midi.push({
|
|
163
|
+
type: 'meta',
|
|
164
|
+
subtype: 'setTempo',
|
|
165
|
+
microsecondsPerBeat: 1000000,
|
|
166
|
+
deltaTime: 0
|
|
167
|
+
});
|
|
168
|
+
// both pedals start at rest
|
|
169
|
+
midi.push(controller(MIDIControlEvents.SUSTAIN, 0), controller(MIDIControlEvents.SOFT_PEDAL, 0));
|
|
170
|
+
// a pedal step is labelled with its command only where that
|
|
171
|
+
// command changes, so the file is not swamped with labels
|
|
172
|
+
const lastCause = {};
|
|
173
|
+
let currentTick = 0;
|
|
174
|
+
for (const event of events.toSorted((a, b) => a.at - b.at)) {
|
|
175
|
+
const tick = Math.round(event.at * TICKS_PER_SECOND);
|
|
176
|
+
const deltaTime = tick - currentTick;
|
|
177
|
+
currentTick = tick;
|
|
178
|
+
if (event.type === 'noteOn') {
|
|
179
|
+
midi.push(text(event.performs.id, deltaTime));
|
|
180
|
+
midi.push({
|
|
181
|
+
type: 'channel',
|
|
182
|
+
subtype: 'noteOn',
|
|
183
|
+
noteNumber: event.pitch,
|
|
184
|
+
velocity: +event.velocity.toFixed(0),
|
|
185
|
+
deltaTime: 0,
|
|
186
|
+
channel: 0
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else if (event.type === 'noteOff') {
|
|
190
|
+
midi.push({
|
|
191
|
+
type: 'channel',
|
|
192
|
+
subtype: 'noteOff',
|
|
193
|
+
noteNumber: event.pitch,
|
|
194
|
+
velocity: 127,
|
|
195
|
+
deltaTime,
|
|
196
|
+
channel: 0
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
const labelled = lastCause[event.type] === event.performs.id;
|
|
201
|
+
lastCause[event.type] = event.performs.id;
|
|
202
|
+
if (!labelled) {
|
|
203
|
+
midi.push(text(event.performs.id, deltaTime));
|
|
204
|
+
}
|
|
205
|
+
midi.push(controller(controllerOf(event), event.value, labelled ? deltaTime : 0));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
header: {
|
|
210
|
+
ticksPerBeat: TICKS_PER_SECOND,
|
|
211
|
+
formatType: 0,
|
|
212
|
+
trackCount: 1
|
|
213
|
+
},
|
|
214
|
+
tracks: [midi]
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
/**
|
|
218
|
+
* A version of the edition, performed and kept: `emulate` and `midiOf`
|
|
219
|
+
* with the result held on the object between the two calls. Prefer the
|
|
220
|
+
* functions where nothing needs holding.
|
|
221
|
+
*/
|
|
222
|
+
export class Emulation {
|
|
223
|
+
constructor(system, options = system.defaultOptions) {
|
|
224
|
+
Object.defineProperty(this, "system", {
|
|
225
|
+
enumerable: true,
|
|
226
|
+
configurable: true,
|
|
227
|
+
writable: true,
|
|
228
|
+
value: void 0
|
|
229
|
+
});
|
|
230
|
+
Object.defineProperty(this, "options", {
|
|
231
|
+
enumerable: true,
|
|
232
|
+
configurable: true,
|
|
233
|
+
writable: true,
|
|
234
|
+
value: void 0
|
|
235
|
+
});
|
|
236
|
+
Object.defineProperty(this, "midiEvents", {
|
|
237
|
+
enumerable: true,
|
|
238
|
+
configurable: true,
|
|
239
|
+
writable: true,
|
|
240
|
+
value: []
|
|
241
|
+
});
|
|
242
|
+
// sorted list of events with the negotiated assumptions already applied
|
|
243
|
+
Object.defineProperty(this, "negotiatedEvents", {
|
|
244
|
+
enumerable: true,
|
|
245
|
+
configurable: true,
|
|
246
|
+
writable: true,
|
|
247
|
+
value: []
|
|
248
|
+
});
|
|
249
|
+
Object.defineProperty(this, "curves", {
|
|
250
|
+
enumerable: true,
|
|
251
|
+
configurable: true,
|
|
252
|
+
writable: true,
|
|
253
|
+
value: []
|
|
254
|
+
});
|
|
255
|
+
Object.defineProperty(this, "source", {
|
|
256
|
+
enumerable: true,
|
|
257
|
+
configurable: true,
|
|
258
|
+
writable: true,
|
|
259
|
+
value: void 0
|
|
260
|
+
});
|
|
261
|
+
this.system = system;
|
|
262
|
+
this.options = options;
|
|
263
|
+
}
|
|
264
|
+
/** Moves the negotiated events to where their statements put them; see `withPlacementsApplied`. */
|
|
265
|
+
applyConstraints(view) {
|
|
266
|
+
this.negotiatedEvents = withPlacementsApplied(view, this.negotiatedEvents);
|
|
267
|
+
}
|
|
268
|
+
emulateVersion(version, view, scope = {}) {
|
|
269
|
+
const emulated = emulate(this.system, version, view, this.options, scope);
|
|
270
|
+
this.source = emulated.source;
|
|
271
|
+
this.negotiatedEvents = [...emulated.negotiated];
|
|
272
|
+
this.curves = emulated.curves;
|
|
273
|
+
this.midiEvents = [...emulated.events];
|
|
274
|
+
return this.midiEvents;
|
|
275
|
+
}
|
|
276
|
+
findEventsPerforming(id) {
|
|
277
|
+
return this.midiEvents.filter(event => event.performs.id === id);
|
|
278
|
+
}
|
|
279
|
+
asMIDI() {
|
|
280
|
+
return midiOf(this.midiEvents, this.system.name, this.options, this.source);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EditionView } from "../view/EditionView.js";
|
|
2
|
+
import type { Expression, Note } from "../model/Symbol.js";
|
|
3
|
+
import type { TrackerBar } from "../systems/TrackerBar.js";
|
|
4
|
+
import type { NegotiatedEvent } from "../systems/ReproducingSystem.js";
|
|
5
|
+
/**
|
|
6
|
+
* The symbol as a performance needs it: where it lies, and the
|
|
7
|
+
* position the performing bar reads it on.
|
|
8
|
+
*
|
|
9
|
+
* Nothing where that bar reads nothing of it, which is the case a
|
|
10
|
+
* transfer between systems leaves behind: a red `ForzandoOn` a
|
|
11
|
+
* green version still inherits cannot be performed on a green
|
|
12
|
+
* machine, and an edit has yet to say what took its place.
|
|
13
|
+
*/
|
|
14
|
+
export declare const negotiatedEventOf: (view: EditionView, symbol: Note | Expression, bar: TrackerBar) => NegotiatedEvent | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The symbol as a performance needs it: where it lies, and the
|
|
3
|
+
* position the performing bar reads it on.
|
|
4
|
+
*
|
|
5
|
+
* Nothing where that bar reads nothing of it, which is the case a
|
|
6
|
+
* transfer between systems leaves behind: a red `ForzandoOn` a
|
|
7
|
+
* green version still inherits cannot be performed on a green
|
|
8
|
+
* machine, and an edit has yet to say what took its place.
|
|
9
|
+
*/
|
|
10
|
+
export const negotiatedEventOf = (view, symbol, bar) => {
|
|
11
|
+
const horizontal = view.placeOf(symbol);
|
|
12
|
+
const position = bar.positionOf(symbol);
|
|
13
|
+
if (!horizontal || position === undefined)
|
|
14
|
+
return null;
|
|
15
|
+
return {
|
|
16
|
+
...symbol,
|
|
17
|
+
horizontal,
|
|
18
|
+
vertical: { unit: 'track', from: position }
|
|
19
|
+
};
|
|
20
|
+
};
|
package/lib/index.d.ts
CHANGED
|
@@ -1,43 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
export * from './
|
|
9
|
-
export * from './
|
|
10
|
-
export * from './
|
|
11
|
-
export * from './
|
|
12
|
-
export * from './
|
|
1
|
+
/**
|
|
2
|
+
* The public interface of the library. Everything else under lib/ is its
|
|
3
|
+
* implementation and may change in any release: the in-place helpers the
|
|
4
|
+
* operations are built from, the date conversions of the serialisation,
|
|
5
|
+
* and the general utilities.
|
|
6
|
+
*/
|
|
7
|
+
export type { WithId, WithNote, WithType } from './shared/utils.js';
|
|
8
|
+
export * from './model/Quantity.js';
|
|
9
|
+
export * from './model/Agent.js';
|
|
10
|
+
export * from './model/Assumption.js';
|
|
11
|
+
export * from './model/ConditionState.js';
|
|
12
|
+
export * from './model/Symbol.js';
|
|
13
|
+
export * from './model/Feature.js';
|
|
14
|
+
export * from './model/Edit.js';
|
|
15
|
+
export * from './model/Version.js';
|
|
16
|
+
export * from './collation/Collation.js';
|
|
17
|
+
export * from './model/TrackCalibration.js';
|
|
18
|
+
export * from './systems/TrackerBar.js';
|
|
13
19
|
export * from './systems/welteT100/bar.js';
|
|
14
20
|
export * from './systems/welteLicensee/bar.js';
|
|
15
21
|
export * from './systems/welteT98/bar.js';
|
|
16
22
|
export * from './systems/index.js';
|
|
17
|
-
export * from './ReproducingSystem.js';
|
|
18
|
-
export * from './FeatureSource.js';
|
|
19
|
-
export * from './Perforator.js';
|
|
20
|
-
export * from './RollCopy.js';
|
|
21
|
-
export * from './procedures.js';
|
|
22
|
-
export * from './vocabulary.js';
|
|
23
|
-
export * from './reservations.js';
|
|
24
|
-
export * from './witnesses.js';
|
|
25
|
-
export
|
|
26
|
-
export * from './statistics.js';
|
|
27
|
-
export * from './Edition.js';
|
|
28
|
-
export * from './EditionView.js';
|
|
29
|
-
export * from './
|
|
30
|
-
export * from './
|
|
31
|
-
export * from './
|
|
23
|
+
export * from './systems/ReproducingSystem.js';
|
|
24
|
+
export * from './model/FeatureSource.js';
|
|
25
|
+
export * from './model/Perforator.js';
|
|
26
|
+
export * from './model/RollCopy.js';
|
|
27
|
+
export * from './model/procedures.js';
|
|
28
|
+
export * from './model/vocabulary.js';
|
|
29
|
+
export * from './analysis/reservations.js';
|
|
30
|
+
export * from './analysis/witnesses.js';
|
|
31
|
+
export { alignFeatures, tooShortToShorten, type AlignmentResult } from './collation/alignment.js';
|
|
32
|
+
export * from './collation/statistics.js';
|
|
33
|
+
export * from './model/Edition.js';
|
|
34
|
+
export * from './view/EditionView.js';
|
|
35
|
+
export * from './analysis/ownPaper.js';
|
|
36
|
+
export * from './emulation/negotiation.js';
|
|
37
|
+
export * from './collation/scatter.js';
|
|
38
|
+
export * from './ops/index.js';
|
|
39
|
+
export * from './emulation/Emulation.js';
|
|
32
40
|
export * from './validate.js';
|
|
33
|
-
export * from './constraints.js';
|
|
34
|
-
export * from './substitution.js';
|
|
35
|
-
export * from './context.js';
|
|
36
|
-
export * from './sigla.js';
|
|
37
|
-
export * from './notes.js';
|
|
38
|
-
export
|
|
39
|
-
export
|
|
40
|
-
export
|
|
41
|
+
export * from './analysis/constraints.js';
|
|
42
|
+
export * from './collation/substitution.js';
|
|
43
|
+
export * from './io/context.js';
|
|
44
|
+
export * from './analysis/sigla.js';
|
|
45
|
+
export * from './model/notes.js';
|
|
46
|
+
export { asJsonLd } from './io/asJsonLd.js';
|
|
47
|
+
export { importJsonLd } from './io/importJsonLd.js';
|
|
48
|
+
export { formatVersion, migrate } from './io/migrate.js';
|
|
41
49
|
export { readFromStanfordAton, type StanfordAtonOptions } from './readers/stanfordAton.js';
|
|
42
50
|
export { readFromPhillipsEroll, CONTROL_OFFSET, phillipsSystems, type PhillipsErollOptions } from './readers/phillipsEroll.js';
|
|
43
51
|
export { readFromSpencerBar, readSpencerAnn, paperSpeedOfSpencerAnn, SPENCER_ROWS_PER_INCH, type SpencerBarOptions } from './readers/spencerBar.js';
|
package/lib/index.js
CHANGED
|
@@ -1,43 +1,44 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './
|
|
6
|
-
export * from './
|
|
7
|
-
export * from './
|
|
8
|
-
export * from './
|
|
9
|
-
export * from './
|
|
10
|
-
export * from './
|
|
11
|
-
export * from './
|
|
12
|
-
export * from './TrackerBar.js';
|
|
1
|
+
export * from './model/Quantity.js';
|
|
2
|
+
export * from './model/Agent.js';
|
|
3
|
+
export * from './model/Assumption.js';
|
|
4
|
+
export * from './model/ConditionState.js';
|
|
5
|
+
export * from './model/Symbol.js';
|
|
6
|
+
export * from './model/Feature.js';
|
|
7
|
+
export * from './model/Edit.js';
|
|
8
|
+
export * from './model/Version.js';
|
|
9
|
+
export * from './collation/Collation.js';
|
|
10
|
+
export * from './model/TrackCalibration.js';
|
|
11
|
+
export * from './systems/TrackerBar.js';
|
|
13
12
|
export * from './systems/welteT100/bar.js';
|
|
14
13
|
export * from './systems/welteLicensee/bar.js';
|
|
15
14
|
export * from './systems/welteT98/bar.js';
|
|
16
15
|
export * from './systems/index.js';
|
|
17
|
-
export * from './ReproducingSystem.js';
|
|
18
|
-
export * from './FeatureSource.js';
|
|
19
|
-
export * from './Perforator.js';
|
|
20
|
-
export * from './RollCopy.js';
|
|
21
|
-
export * from './procedures.js';
|
|
22
|
-
export * from './vocabulary.js';
|
|
23
|
-
export * from './reservations.js';
|
|
24
|
-
export * from './witnesses.js';
|
|
25
|
-
export
|
|
26
|
-
export * from './statistics.js';
|
|
27
|
-
export * from './Edition.js';
|
|
28
|
-
export * from './EditionView.js';
|
|
29
|
-
export * from './
|
|
30
|
-
export * from './
|
|
31
|
-
export * from './
|
|
16
|
+
export * from './systems/ReproducingSystem.js';
|
|
17
|
+
export * from './model/FeatureSource.js';
|
|
18
|
+
export * from './model/Perforator.js';
|
|
19
|
+
export * from './model/RollCopy.js';
|
|
20
|
+
export * from './model/procedures.js';
|
|
21
|
+
export * from './model/vocabulary.js';
|
|
22
|
+
export * from './analysis/reservations.js';
|
|
23
|
+
export * from './analysis/witnesses.js';
|
|
24
|
+
export { alignFeatures, tooShortToShorten } from './collation/alignment.js';
|
|
25
|
+
export * from './collation/statistics.js';
|
|
26
|
+
export * from './model/Edition.js';
|
|
27
|
+
export * from './view/EditionView.js';
|
|
28
|
+
export * from './analysis/ownPaper.js';
|
|
29
|
+
export * from './emulation/negotiation.js';
|
|
30
|
+
export * from './collation/scatter.js';
|
|
31
|
+
export * from './ops/index.js';
|
|
32
|
+
export * from './emulation/Emulation.js';
|
|
32
33
|
export * from './validate.js';
|
|
33
|
-
export * from './constraints.js';
|
|
34
|
-
export * from './substitution.js';
|
|
35
|
-
export * from './context.js';
|
|
36
|
-
export * from './sigla.js';
|
|
37
|
-
export * from './notes.js';
|
|
38
|
-
export
|
|
39
|
-
export
|
|
40
|
-
export
|
|
34
|
+
export * from './analysis/constraints.js';
|
|
35
|
+
export * from './collation/substitution.js';
|
|
36
|
+
export * from './io/context.js';
|
|
37
|
+
export * from './analysis/sigla.js';
|
|
38
|
+
export * from './model/notes.js';
|
|
39
|
+
export { asJsonLd } from './io/asJsonLd.js';
|
|
40
|
+
export { importJsonLd } from './io/importJsonLd.js';
|
|
41
|
+
export { formatVersion, migrate } from './io/migrate.js';
|
|
41
42
|
export { readFromStanfordAton } from './readers/stanfordAton.js';
|
|
42
43
|
export { readFromPhillipsEroll, CONTROL_OFFSET, phillipsSystems } from './readers/phillipsEroll.js';
|
|
43
44
|
export { readFromSpencerBar, readSpencerAnn, paperSpeedOfSpencerAnn, SPENCER_ROWS_PER_INCH } from './readers/spencerBar.js';
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { systemIdIn } from "
|
|
2
|
-
import { certaintyOf, isAsserted } from "
|
|
3
|
-
import context from "
|
|
1
|
+
import { systemIdIn } from "../systems/TrackerBar.js";
|
|
2
|
+
import { certaintyOf, isAsserted } from "../model/Assumption.js";
|
|
3
|
+
import context from "../spec/context.json" with { type: 'json' };
|
|
4
|
+
import { formatVersion } from "./migrate.js";
|
|
4
5
|
/**
|
|
5
6
|
* The keys an export derives from the tree, which no node of the
|
|
6
7
|
* edition states itself. An import reads them off again.
|
|
7
8
|
*/
|
|
8
|
-
export const derivedKeys = new Set(['
|
|
9
|
+
export const derivedKeys = new Set(['augmented', 'diminished']);
|
|
9
10
|
export const exportDate = (date) => {
|
|
10
11
|
const year = date.getFullYear();
|
|
11
12
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
@@ -53,32 +54,12 @@ const asJsonLdEntity = (obj) => {
|
|
|
53
54
|
* reading as whichever came last. An embedded context merges with the
|
|
54
55
|
* active one, so the shared prefixes survive.
|
|
55
56
|
*/
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (node === null || typeof node !== 'object')
|
|
60
|
-
return node;
|
|
61
|
-
const walked = Object.fromEntries(Object.entries(node).map(([key, value]) => [key, withSystemContexts(value)]));
|
|
62
|
-
const system = node['@type'] === 'Version'
|
|
63
|
-
? systemIdIn(node.system?.['@id'])
|
|
64
|
-
: undefined;
|
|
65
|
-
return system
|
|
66
|
-
? { '@context': `https://w3id.org/reo/${system}/context.jsonld`, ...walked }
|
|
67
|
-
: walked;
|
|
57
|
+
const withSystemContext = (version) => {
|
|
58
|
+
const system = systemIdIn(version?.system?.['@id']);
|
|
59
|
+
return system ? { '@context': `https://w3id.org/reo/${system}/context.jsonld`, ...version } : version;
|
|
68
60
|
};
|
|
61
|
+
const withSystemContexts = (edition) => Array.isArray(edition.versions) ? { ...edition, versions: edition.versions.map(withSystemContext) } : edition;
|
|
69
62
|
const isRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
70
|
-
const nodesIn = (value) => Array.isArray(value) ? value.filter(isRecord) : [];
|
|
71
|
-
/** What the acts of a copy brought onto it: the features they produced and the patches they glued on. */
|
|
72
|
-
const madeOn = (copy) => [
|
|
73
|
-
...nodesIn(copy.production?.produced),
|
|
74
|
-
...nodesIn(copy.modifications).flatMap(act => [...nodesIn(act.produced), ...nodesIn(act.added)])
|
|
75
|
-
];
|
|
76
|
-
const referencing = (nodes, patches) => nodes.filter(node => (node['@type'] === 'Patch') === patches && typeof node['@id'] === 'string')
|
|
77
|
-
.map(node => ({ '@id': node['@id'] }));
|
|
78
|
-
const featuresAmong = (nodes) => referencing(nodes, false);
|
|
79
|
-
const patchesAmong = (nodes) => referencing(nodes, true);
|
|
80
|
-
/** The key, where there is anything to state under it. */
|
|
81
|
-
const stating = (key, references) => references.length > 0 ? { [key]: references } : {};
|
|
82
63
|
/** The act with what it changed named: an attachment augments the copy, a removal diminishes it. */
|
|
83
64
|
const changing = (copyId) => (act) => {
|
|
84
65
|
if (typeof copyId !== 'string' || !isRecord(act))
|
|
@@ -90,31 +71,21 @@ const changing = (copyId) => (act) => {
|
|
|
90
71
|
return act;
|
|
91
72
|
};
|
|
92
73
|
/**
|
|
93
|
-
* The document with
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* P56 bears feature takes only features, so a patch is stated as a part.
|
|
74
|
+
* The document with what each act changed stated. Which of P110
|
|
75
|
+
* augmented and P112 diminished applies depends on the class of the
|
|
76
|
+
* act, which no property chain in OWL 2 RL can test, so the export
|
|
77
|
+
* states it. What a copy or a patch bears is left to a reasoner (see
|
|
78
|
+
* the entailments in reo.ttl).
|
|
99
79
|
*/
|
|
100
|
-
const
|
|
80
|
+
const withChanges = (value) => {
|
|
101
81
|
if (Array.isArray(value))
|
|
102
|
-
return value.map(
|
|
82
|
+
return value.map(withChanges);
|
|
103
83
|
if (!isRecord(value))
|
|
104
84
|
return value;
|
|
105
|
-
const node = Object.fromEntries(Object.entries(value).map(([key, child]) => [key,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
...node,
|
|
110
|
-
...(Array.isArray(node.modifications) && { modifications: node.modifications.map(changing(node['@id'])) }),
|
|
111
|
-
...stating('bears', featuresAmong(made)),
|
|
112
|
-
...stating('composedOf', patchesAmong(made))
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
if (node['@type'] === 'Patch')
|
|
116
|
-
return { ...node, ...stating('bears', featuresAmong(nodesIn(node.features))) };
|
|
117
|
-
return node;
|
|
85
|
+
const node = Object.fromEntries(Object.entries(value).map(([key, child]) => [key, withChanges(child)]));
|
|
86
|
+
return node['@type'] === 'RollCopy' && Array.isArray(node.modifications)
|
|
87
|
+
? { ...node, modifications: node.modifications.map(changing(node['@id'])) }
|
|
88
|
+
: node;
|
|
118
89
|
};
|
|
119
90
|
/** Terms the context sets to null, which say nothing when the edition is read as RDF. */
|
|
120
91
|
const silentTerms = new Set(Object.entries(context['@context'])
|
|
@@ -182,7 +153,7 @@ const withDoubtedReferencesQuoted = (value) => {
|
|
|
182
153
|
};
|
|
183
154
|
};
|
|
184
155
|
export const asJsonLd = (edition) => {
|
|
185
|
-
const { node, quoted } = withDoubtedReferencesQuoted(withSystemContexts(
|
|
156
|
+
const { node, quoted } = withDoubtedReferencesQuoted(withSystemContexts(withChanges(asJsonLdEntity(edition))));
|
|
186
157
|
// The context is the export's own; one carried in from an import must not override it.
|
|
187
158
|
const { base, '@context': carried, ...rest } = node;
|
|
188
159
|
return {
|
|
@@ -192,8 +163,8 @@ export const asJsonLd = (edition) => {
|
|
|
192
163
|
'@base': edition.base
|
|
193
164
|
}
|
|
194
165
|
],
|
|
195
|
-
'@type': "Edition",
|
|
196
166
|
'@id': edition.base,
|
|
167
|
+
formatVersion,
|
|
197
168
|
...rest,
|
|
198
169
|
...(quoted.length > 0 && { '@included': quoted })
|
|
199
170
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export { default as jsonLdContext } from '
|
|
1
|
+
export { default as jsonLdContext } from '../spec/context.json';
|
|
2
2
|
/** The context of the Welte-Mignon T-100, added to a version coded for it. */
|
|
3
|
-
export { default as welteT100JsonLdContext } from '
|
|
3
|
+
export { default as welteT100JsonLdContext } from '../spec/welte-t100.context.json';
|
|
4
4
|
/**
|
|
5
5
|
* The context of the Welte-Mignon Licensee. Its expression terms are
|
|
6
6
|
* the T-100's, the two systems differing in the tracker scale rather
|
|
7
7
|
* than in the coding, so it reads them out of the T-100's vocabulary
|
|
8
8
|
* rather than minting a second set of IRIs for the same commands.
|
|
9
9
|
*/
|
|
10
|
-
export { default as welteLicenseeJsonLdContext } from '
|
|
10
|
+
export { default as welteLicenseeJsonLdContext } from '../spec/welte-licensee.context.json';
|
|
11
11
|
/** The context of the Welte-Mignon T-98, added to an edition of a green roll. */
|
|
12
|
-
export { default as welteT98JsonLdContext } from '
|
|
12
|
+
export { default as welteT98JsonLdContext } from '../spec/welte-t98.context.json';
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export { default as jsonLdContext } from '
|
|
1
|
+
export { default as jsonLdContext } from '../spec/context.json' with { type: 'json' };
|
|
2
2
|
/** The context of the Welte-Mignon T-100, added to a version coded for it. */
|
|
3
|
-
export { default as welteT100JsonLdContext } from '
|
|
3
|
+
export { default as welteT100JsonLdContext } from '../spec/welte-t100.context.json' with { type: 'json' };
|
|
4
4
|
/**
|
|
5
5
|
* The context of the Welte-Mignon Licensee. Its expression terms are
|
|
6
6
|
* the T-100's, the two systems differing in the tracker scale rather
|
|
7
7
|
* than in the coding, so it reads them out of the T-100's vocabulary
|
|
8
8
|
* rather than minting a second set of IRIs for the same commands.
|
|
9
9
|
*/
|
|
10
|
-
export { default as welteLicenseeJsonLdContext } from '
|
|
10
|
+
export { default as welteLicenseeJsonLdContext } from '../spec/welte-licensee.context.json' with { type: 'json' };
|
|
11
11
|
/** The context of the Welte-Mignon T-98, added to an edition of a green roll. */
|
|
12
|
-
export { default as welteT98JsonLdContext } from '
|
|
12
|
+
export { default as welteT98JsonLdContext } from '../spec/welte-t98.context.json' with { type: 'json' };
|