linked-rolls 0.39.1 → 0.40.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 CHANGED
@@ -58,7 +58,7 @@ end of the end` on the `E52 Time-Span` the event has. `assignDate`,
58
58
  `notBefore` and `notAfter` build the three shapes, and `dateOf`,
59
59
  `earliestOf` and `latestOf` read them.
60
60
 
61
- Note that `before` and `after` mean something else on a perforation,
61
+ Note that `before` and `after` mean something else on a command,
62
62
  where they order two onsets. The context defines them for a date
63
63
  within the date itself, so the two never meet.
64
64
 
@@ -223,25 +223,25 @@ repository.
223
223
 
224
224
  ### Alignment, order and pairing
225
225
 
226
- A perforation takes its place from the holes that carry it. Four fields
227
- on a perforation let an editor state where the measurement should give
228
- way. `alignedWith` names another perforation whose onset this one takes
226
+ A command takes its place from the holes that carry it. Four fields
227
+ on a command let an editor state where the measurement should give
228
+ way. `alignedWith` names another command whose onset this one takes
229
229
  in the performance, as a "crescendo off" is meant to fall on the note
230
- it belongs to. `before` and `after` name a perforation whose onset this
230
+ it belongs to. `before` and `after` name a command whose onset this
231
231
  one precedes or follows, without saying by how much: where the copies
232
232
  disagree on which side of a note an expression falls, the statement
233
- settles the order. A perforation the measurement already has on the
233
+ settles the order. A command the measurement already has on the
234
234
  stated side keeps its place. One it does not is put on that side, as
235
235
  far from the reference as the copies that agree with the statement put
236
- it, and a punch diameter away where none does. A perforation makes one
236
+ it, and a punch diameter away where none does. A command makes one
237
237
  of these three statements at most. `pairedWith` names a partner whose
238
238
  distance to this one is fixed, as a "forzando on" belongs with its
239
239
  "forzando off": whatever displaces the one displaces the other. Any two
240
- perforations may be paired, the relation is symmetric, and it is stated
240
+ commands may be paired, the relation is symmetric, and it is stated
241
241
  on one side only. All are applied when a version is emulated.
242
242
  `constraintProblems` lists, version by version, the cases in which the
243
243
  statements cannot hold: a reference or partner that is absent, a
244
- perforation placed relative to itself or in several ways at once, one
244
+ command placed relative to itself or in several ways at once, one
245
245
  claimed by several pairs, or a pair whose members are both placed.
246
246
 
247
247
  ## Building
@@ -26,7 +26,7 @@ export declare class Emulation<Options extends object> {
26
26
  /**
27
27
  * Moves the negotiated events to where their statements put them.
28
28
  * The view supplies the copies, whose measurements decide how far
29
- * before or after its reference a perforation goes, and a punch
29
+ * before or after its reference a command goes, and a punch
30
30
  * diameter, or a millimetre, where no copy agrees with a statement.
31
31
  */
32
32
  applyConstraints(view: EditionView): void;
package/lib/Emulation.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MIDIControlEvents } from "midifile-ts";
2
2
  import { idOf } from "./Assumption";
3
- import { isPerforation, pairsAmong, placementsOf } from "./Symbol";
3
+ import { isCommand, pairsAmong, placementsOf } from "./Symbol";
4
4
  import { add, mean, mm, seconds, subtract } from "./Quantity";
5
5
  /** The punch diameter the edition's copies report, where any of them does. */
6
6
  const punchDiameterOf = (view) => {
@@ -137,7 +137,7 @@ export class Emulation {
137
137
  /**
138
138
  * Moves the negotiated events to where their statements put them.
139
139
  * The view supplies the copies, whose measurements decide how far
140
- * before or after its reference a perforation goes, and a punch
140
+ * before or after its reference a command goes, and a punch
141
141
  * diameter, or a millimetre, where no copy agrees with a statement.
142
142
  */
143
143
  applyConstraints(view) {
@@ -154,7 +154,7 @@ export class Emulation {
154
154
  const inScope = (event) => !range || event.type !== 'note' || (event.horizontal.from > range[0] && event.horizontal.from < range[1]);
155
155
  this.negotiatedEvents =
156
156
  view.snapshot(version.id)
157
- .filter(isPerforation)
157
+ .filter(isCommand)
158
158
  .map(symbol => view.simplifySymbol(symbol, this.system.trackerBar))
159
159
  .filter(event => event !== null)
160
160
  .filter(inScope);
@@ -199,8 +199,8 @@ export class Emulation {
199
199
  });
200
200
  // both pedals start at rest
201
201
  events.push(controller(MIDIControlEvents.SUSTAIN, 0), controller(MIDIControlEvents.SOFT_PEDAL, 0));
202
- // a pedal step is labelled with its perforation only where that
203
- // perforation changes, so the file is not swamped with labels
202
+ // a pedal step is labelled with its command only where that
203
+ // command changes, so the file is not swamped with labels
204
204
  const lastCause = {};
205
205
  let currentTick = 0;
206
206
  for (const event of this.midiEvents) {
@@ -49,8 +49,8 @@ export interface PerformedNoteOffEvent extends PerformedNoteEvent<'noteOff'> {
49
49
  }
50
50
  /**
51
51
  * One step of a pedal. A pedal driven by a bellows takes time to travel,
52
- * so a single perforation results in a run of these; `performs` is the
53
- * perforation whose reading the step follows from.
52
+ * so a single command results in a run of these; `performs` is the
53
+ * command whose reading the step follows from.
54
54
  */
55
55
  export interface PerformedPedalEvent extends PerformedRollFeature<'damper' | 'hammerRail'> {
56
56
  /** 0 with the pedal up and 127 with it fully down. */
package/lib/Symbol.d.ts CHANGED
@@ -19,52 +19,52 @@ export interface Symbol<T extends string> extends WithId {
19
19
  carriers: ReferenceAssumption[];
20
20
  }
21
21
  export declare const isSymbol: (object: any) => object is AnySymbol;
22
- export declare const isPerforation: (symbol: object | undefined) => symbol is AnyPerforation;
22
+ export declare const isCommand: (symbol: object | undefined) => symbol is AnyCommand;
23
23
  /**
24
- * A perforation is a symbol that is typically encoded as a single punched
25
- * hole or a group of punched holes in the physical carrier.
26
- * However, it might also have different physical appearences.
27
- * @see reo:Perforation
24
+ * A command is what the tracker bar reads from a perforation, or from a
25
+ * group of them: the note it sounds, or the function it operates. It is
26
+ * typically carried by a single punched hole or a chain of them, but it
27
+ * might also have different physical appearences.
28
+ * @see reo:Command
28
29
  */
29
- export interface Perforation<T extends string> extends Symbol<T> {
30
+ export interface Command<T extends string> extends Symbol<T> {
30
31
  /**
31
- * In piano rolls, perforations are often aligned with other
32
- * perforations, e.g. a "crescendo off" might be logically
33
- * aligned to the start of a note perforation. This points
34
- * to the perforation by its `@id`.
32
+ * In piano rolls, commands are often aligned with other commands,
33
+ * e.g. a "crescendo off" might be logically aligned to the start of
34
+ * a note. This points to the command by its `@id`.
35
35
  * @see reo:alignedWith
36
36
  */
37
37
  alignedWith?: ReferenceAssumption;
38
38
  /**
39
- * A perforation whose onset this one precedes when the roll is
39
+ * A command whose onset this one precedes when the roll is
40
40
  * performed, without saying by how much: a "crescendo off" ends
41
41
  * before the note it leads to begins, even where the copies
42
42
  * disagree on it. Where the measurement has it so, nothing moves;
43
43
  * where it does not, this one is placed before the reference as
44
- * far as the copies that agree put it. This points to the
45
- * perforation by its `@id`.
44
+ * far as the copies that agree put it. This points to the command
45
+ * by its `@id`.
46
46
  * @see reo:before
47
47
  */
48
48
  before?: ReferenceAssumption;
49
49
  /**
50
- * A perforation whose onset this one follows when the roll is
50
+ * A command whose onset this one follows when the roll is
51
51
  * performed, the counterpart of `before`. This points to the
52
- * perforation by its `@id`.
52
+ * command by its `@id`.
53
53
  * @see reo:after
54
54
  */
55
55
  after?: ReferenceAssumption;
56
56
  /**
57
- * The perforation this one forms a pair with, e.g. a "forzando on"
58
- * with its "forzando off". Any two perforations may be paired.
57
+ * The command this one forms a pair with, e.g. a "forzando on"
58
+ * with its "forzando off". Any two commands may be paired.
59
59
  * The distance between the two is fixed: whatever displaces the
60
60
  * one displaces the other. The relation is symmetric and is stated
61
- * on one side only. This points to the perforation by its `@id`.
61
+ * on one side only. This points to the command by its `@id`.
62
62
  * @see reo:pairedWith
63
63
  */
64
64
  pairedWith?: ReferenceAssumption;
65
65
  }
66
66
  export declare const placementRelations: readonly ['alignedWith', 'before', 'after'];
67
- /** The ways a perforation may be placed relative to another. */
67
+ /** The ways a command may be placed relative to another. */
68
68
  export type PlacementRelation = typeof placementRelations[number];
69
69
  type Placeable = Partial<Record<PlacementRelation, ReferenceAssumption>>;
70
70
  export type Placement = {
@@ -72,25 +72,25 @@ export type Placement = {
72
72
  reference: ReferenceAssumption;
73
73
  };
74
74
  /**
75
- * The statements placing a perforation relative to others, alignment
76
- * first. A perforation is meant to make one at most; the first is the
77
- * one a performance applies.
75
+ * The statements placing a command relative to others, alignment first.
76
+ * A command is meant to make one at most; the first is the one a
77
+ * performance applies.
78
78
  */
79
- export declare const placementsOf: (perforation: Placeable) => Placement[];
79
+ export declare const placementsOf: (command: Placeable) => Placement[];
80
80
  type Pairable = WithId & {
81
81
  pairedWith?: ReferenceAssumption;
82
82
  };
83
83
  /**
84
- * The pairs among the given perforations, each once and in the order
85
- * the pairing is stated. A pair whose partner is absent is left out.
84
+ * The pairs among the given commands, each once and in the order the
85
+ * pairing is stated. A pair whose partner is absent is left out.
86
86
  */
87
- export declare const pairsAmong: <S extends Pairable>(perforations: readonly S[]) => [S, S][];
87
+ export declare const pairsAmong: <S extends Pairable>(commands: readonly S[]) => [S, S][];
88
88
  /**
89
89
  * A note symbol, representing a single pitched musical event on the roll.
90
90
  * The pitch is encoded via the tracker bar position (track number).
91
91
  * @see reo:Note
92
92
  */
93
- export interface Note extends Perforation<'note'> {
93
+ export interface Note extends Command<'note'> {
94
94
  /**
95
95
  * The MIDI pitch number of the note (e.g. 60 for middle C).
96
96
  * @see reo:pitch
@@ -98,29 +98,29 @@ export interface Note extends Perforation<'note'> {
98
98
  pitch: number;
99
99
  }
100
100
  /**
101
- * The scope of an expression perforation, indicating whether it
102
- * applies to the bass or treble register of the piano.
101
+ * The scope of an expression command, indicating whether it applies to
102
+ * the bass or treble register of the piano.
103
103
  * @see reo:scope
104
104
  */
105
105
  export type ExpressionScope = 'bass' | 'treble';
106
106
  /**
107
- * An expression symbol, representing a perforation on the roll
108
- * that governs dynamics, pedaling, or mechanical functions of the
109
- * reproducing piano. Each expression has a scope (bass or treble)
107
+ * An expression symbol, representing a command that governs dynamics,
108
+ * pedaling, or mechanical functions of the reproducing piano rather
109
+ * than sounding a note. Each expression has a scope (bass or treble)
110
110
  * and a specific expression type.
111
111
  * @see reo:Expression
112
112
  */
113
- export interface Expression extends Perforation<'expression'> {
113
+ export interface Expression extends Command<'expression'> {
114
114
  /**
115
115
  * Whether this expression applies to the bass or treble register.
116
116
  * @see reo:scope
117
117
  */
118
118
  scope: ExpressionScope;
119
119
  /**
120
- * The command the perforation gives, named as the reproducing
121
- * system of the roll names it: "SustainPedalOn", "ForzandoOff"
122
- * and so on for the Welte-Mignon T-100. The tracker bar of the
123
- * system lists the values it reads.
120
+ * The kind of command, named as the reproducing system of the roll
121
+ * names it: "SustainPedalOn", "ForzandoOff" and so on for the
122
+ * Welte-Mignon T-100. The tracker bar of the system lists the
123
+ * values it reads.
124
124
  * @see crm:P2 has type
125
125
  */
126
126
  expressionType: string;
@@ -139,8 +139,8 @@ export interface Text extends Symbol<'text'> {
139
139
  }
140
140
  /**
141
141
  * A symbol can be either a note, an expression, or a text.
142
- * Notes and expressions are perforations; texts are carried by writings.
142
+ * Notes and expressions are commands; texts are carried by writings.
143
143
  */
144
144
  export type AnySymbol = Note | Expression | Text;
145
- export type AnyPerforation = Note | Expression;
145
+ export type AnyCommand = Note | Expression;
146
146
  export {};
package/lib/Symbol.js CHANGED
@@ -3,24 +3,24 @@ export const isSymbol = (object) => {
3
3
  return ('type' in object
4
4
  && (object.type === 'note' || object.type === 'expression' || object.type === 'text'));
5
5
  };
6
- export const isPerforation = (symbol) => symbol !== undefined && 'type' in symbol && (symbol.type === 'note' || symbol.type === 'expression');
6
+ export const isCommand = (symbol) => symbol !== undefined && 'type' in symbol && (symbol.type === 'note' || symbol.type === 'expression');
7
7
  export const placementRelations = ['alignedWith', 'before', 'after'];
8
8
  /**
9
- * The statements placing a perforation relative to others, alignment
10
- * first. A perforation is meant to make one at most; the first is the
11
- * one a performance applies.
9
+ * The statements placing a command relative to others, alignment first.
10
+ * A command is meant to make one at most; the first is the one a
11
+ * performance applies.
12
12
  */
13
- export const placementsOf = (perforation) => placementRelations.flatMap(relation => {
14
- const reference = perforation[relation];
13
+ export const placementsOf = (command) => placementRelations.flatMap(relation => {
14
+ const reference = command[relation];
15
15
  return reference ? [{ relation, reference }] : [];
16
16
  });
17
17
  /**
18
- * The pairs among the given perforations, each once and in the order
19
- * the pairing is stated. A pair whose partner is absent is left out.
18
+ * The pairs among the given commands, each once and in the order the
19
+ * pairing is stated. A pair whose partner is absent is left out.
20
20
  */
21
- export const pairsAmong = (perforations) => {
22
- const byId = new Map(perforations.map(p => [p.id, p]));
23
- return perforations
21
+ export const pairsAmong = (commands) => {
22
+ const byId = new Map(commands.map(p => [p.id, p]));
23
+ return commands
24
24
  .filter((p) => p.pairedWith !== undefined)
25
25
  .map((p) => [p, byId.get(idOf(p.pairedWith))])
26
26
  .filter((pair) => pair[1] !== undefined);
@@ -6,7 +6,7 @@ export type ConstraintProblem = {
6
6
  };
7
7
  /**
8
8
  * Where the edition cannot hold as stated, version by version: a
9
- * placement or pairing reference absent from the version, a perforation
9
+ * placement or pairing reference absent from the version, a command
10
10
  * placed relative to itself or in several ways at once, one claimed by
11
11
  * several pairs, a pair whose members are both placed and so cannot
12
12
  * keep their distance and follow their references at once, an
@@ -1,5 +1,5 @@
1
1
  import { idOf } from "./Assumption";
2
- import { isPerforation, pairsAmong, placementsOf } from "./Symbol";
2
+ import { isCommand, pairsAmong, placementsOf } from "./Symbol";
3
3
  import { keyOf } from "./TrackerBar";
4
4
  import { trackerBarOf } from "./systems";
5
5
  import { barOf } from "./RollCopy";
@@ -8,30 +8,30 @@ const missingReference = {
8
8
  before: 'before-reference-missing',
9
9
  after: 'after-reference-missing'
10
10
  };
11
- const problemsIn = (version, perforations) => {
12
- const ids = new Set(perforations.map(p => p.id));
11
+ const problemsIn = (version, commands) => {
12
+ const ids = new Set(commands.map(p => p.id));
13
13
  const report = (symbol, problem) => ({ version, symbol, problem });
14
- const missingReferences = perforations
14
+ const missingReferences = commands
15
15
  .flatMap(p => placementsOf(p)
16
16
  .filter(({ reference }) => !ids.has(idOf(reference)))
17
17
  .map(({ relation }) => report(p.id, missingReference[relation])));
18
- const selfPlaced = perforations
18
+ const selfPlaced = commands
19
19
  .filter(p => placementsOf(p).some(({ reference }) => idOf(reference) === p.id))
20
20
  .map(p => report(p.id, 'placed-relative-to-itself'));
21
- const placedSeveralWays = perforations
21
+ const placedSeveralWays = commands
22
22
  .filter(p => placementsOf(p).length > 1)
23
23
  .map(p => report(p.id, 'placed-several-ways'));
24
- const missingPartners = perforations
24
+ const missingPartners = commands
25
25
  .filter(p => p.pairedWith && !ids.has(idOf(p.pairedWith)))
26
26
  .map(p => report(p.id, 'partner-missing'));
27
- const selfPaired = perforations
27
+ const selfPaired = commands
28
28
  .filter(p => p.pairedWith && idOf(p.pairedWith) === p.id)
29
29
  .map(p => report(p.id, 'paired-with-itself'));
30
- const pairs = pairsAmong(perforations);
30
+ const pairs = pairsAmong(commands);
31
31
  const pairsPerId = pairs
32
32
  .flatMap(([one, other]) => one === other ? [one] : [one, other])
33
33
  .reduce((counts, p) => counts.set(p.id, (counts.get(p.id) ?? 0) + 1), new Map());
34
- const inSeveralPairs = perforations
34
+ const inSeveralPairs = commands
35
35
  .filter(p => (pairsPerId.get(p.id) ?? 0) > 1)
36
36
  .map(p => report(p.id, 'in-several-pairs'));
37
37
  const placedOnBothSides = pairs
@@ -74,7 +74,7 @@ const typesNotOnTheBar = (version, snapshot) => {
74
74
  * out says 59. Collation across systems consults only the place, so
75
75
  * without this nothing checks the tracks at all.
76
76
  */
77
- const carriersOffTheirMeaning = (view, version, perforations) => {
77
+ const carriersOffTheirMeaning = (view, version, commands) => {
78
78
  const misread = (carrier, symbol) => {
79
79
  const copy = view.copyOf(carrier.id);
80
80
  if (!copy)
@@ -84,7 +84,7 @@ const carriersOffTheirMeaning = (view, version, perforations) => {
84
84
  return !barOf(copy).meaningsOf(carrier.vertical)
85
85
  .some(meaning => keyOf(meaning) === keyOf(symbol));
86
86
  };
87
- return perforations
87
+ return commands
88
88
  .filter(symbol => view.carriersOf(symbol).some(carrier => misread(carrier, symbol)))
89
89
  .map(symbol => ({ version, symbol: symbol.id, problem: 'carrier-on-another-track' }));
90
90
  };
@@ -102,7 +102,7 @@ const paperDisagreed = (view, version) => view.speedScalesIn(version).length > 1
102
102
  : [];
103
103
  /**
104
104
  * Where the edition cannot hold as stated, version by version: a
105
- * placement or pairing reference absent from the version, a perforation
105
+ * placement or pairing reference absent from the version, a command
106
106
  * placed relative to itself or in several ways at once, one claimed by
107
107
  * several pairs, a pair whose members are both placed and so cannot
108
108
  * keep their distance and follow their references at once, an
@@ -111,11 +111,11 @@ const paperDisagreed = (view, version) => view.speedScalesIn(version).length > 1
111
111
  */
112
112
  export const constraintProblems = (view) => view.edition.versions.flatMap(version => {
113
113
  const snapshot = view.snapshot(version.id);
114
- const perforations = snapshot.filter(isPerforation);
114
+ const commands = snapshot.filter(isCommand);
115
115
  return [
116
- ...problemsIn(version.id, perforations),
116
+ ...problemsIn(version.id, commands),
117
117
  ...typesNotOnTheBar(version, snapshot),
118
- ...carriersOffTheirMeaning(view, version.id, perforations),
118
+ ...carriersOffTheirMeaning(view, version.id, commands),
119
119
  ...paperDisagreed(view, version)
120
120
  ];
121
121
  });
@@ -199,11 +199,11 @@ export declare const mergeEdits: (view: EditionView, versionId: string, toMerge:
199
199
  /** Replaces the edit with one edit per inserted and one per deleted symbol. */
200
200
  export declare const splitEdit: (versionId: string, toSplit: Edit) => EditionOp;
201
201
  /** States how the follower is placed relative to the reference, in place of any earlier statement. */
202
- export declare const placePerforation: (view: EditionView, followerId: string, referenceId: string, relation: PlacementRelation) => EditionOp;
203
- export declare const unplacePerforation: (view: EditionView, followerId: string) => EditionOp;
202
+ export declare const placeCommand: (view: EditionView, followerId: string, referenceId: string, relation: PlacementRelation) => EditionOp;
203
+ export declare const unplaceCommand: (view: EditionView, followerId: string) => EditionOp;
204
204
  /** The pair is stated on `statingId` only, as the format asks. */
205
- export declare const pairPerforations: (view: EditionView, statingId: string, partnerId: string) => EditionOp;
206
- export declare const unpairPerforation: (view: EditionView, statingId: string) => EditionOp;
205
+ export declare const pairCommands: (view: EditionView, statingId: string, partnerId: string) => EditionOp;
206
+ export declare const unpairCommand: (view: EditionView, statingId: string) => EditionOp;
207
207
  /** Annotates the assumption at the path with a belief held true, for reasons to be added. */
208
208
  export declare const createBelief: (path: Path) => EditionOp;
209
209
  export declare const clearBelief: (path: Path) => EditionOp;
package/lib/editionOps.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { current, isDraft } from "immer";
2
2
  import { v4 } from "uuid";
3
3
  import { getAt } from "./EditionView";
4
- import { isPerforation, placementRelations } from "./Symbol";
4
+ import { isCommand, placementRelations } from "./Symbol";
5
5
  import { collationsOf, defaultCollationTolerance } from "./Collation";
6
6
  import { collationToleranceOf, editsOf, insertedBy, principalDerivationOf } from "./Version";
7
7
  import { asSymbols, barOf, featuresByAct, featuresOf, isPaperStretch, statesNothing } from "./RollCopy";
@@ -216,15 +216,15 @@ export const symbolsCarriedOnlyBy = (edition, copyId) => {
216
216
  return copy ? insertedIn(edition.versions).filter(carriedOnlyOn(featureIdsOf(copy))) : [];
217
217
  };
218
218
  const references = [...placementRelations, 'pairedWith'];
219
- /** The perforation without its references to the dropped symbols, or the very same one where it makes none. */
220
- const forgettingReferences = (perforation, dropped) => {
219
+ /** The command without its references to the dropped symbols, or the very same one where it makes none. */
220
+ const forgettingReferences = (command, dropped) => {
221
221
  const stale = references.filter(relation => {
222
- const reference = perforation[relation];
222
+ const reference = command[relation];
223
223
  return reference !== undefined && dropped.has(idOf(reference));
224
224
  });
225
225
  if (stale.length === 0)
226
- return perforation;
227
- const kept = { ...perforation };
226
+ return command;
227
+ const kept = { ...command };
228
228
  stale.forEach(relation => { delete kept[relation]; });
229
229
  return kept;
230
230
  };
@@ -232,7 +232,7 @@ const forgettingReferences = (perforation, dropped) => {
232
232
  const forgettingCarriers = (features, dropped) => (symbol) => {
233
233
  const carriers = without(symbol.carriers, carrier => features.has(idOf(carrier)));
234
234
  const relieved = carriers === symbol.carriers ? symbol : { ...symbol, carriers };
235
- return isPerforation(relieved) ? forgettingReferences(relieved, dropped) : relieved;
235
+ return isCommand(relieved) ? forgettingReferences(relieved, dropped) : relieved;
236
236
  };
237
237
  /** The edit without the dropped symbols and the features, or the very same edit where it had none of them. */
238
238
  const forgettingFeatures = (features, dropped) => {
@@ -667,7 +667,7 @@ export const connectVersions = (view, childId, parentId, tolerance = defaultColl
667
667
  const collated = new Set(collations.map(({ symbol }) => symbol.id));
668
668
  const matched = new Set(collations.map(({ counterpart }) => counterpart.id));
669
669
  /**
670
- * Where the child is coded for another system, a held perforation of
670
+ * Where the child is coded for another system, a held command of
671
671
  * its own often stands for a latched pair of the parent's. Saying so
672
672
  * as one edit is the transfer being carried out, and leaving the two
673
673
  * apart would make the apparatus a list of unexplained losses beside
@@ -872,29 +872,29 @@ export const splitEdit = (versionId, toSplit) => {
872
872
  });
873
873
  };
874
874
  /**
875
- * Runs the change on the perforation the view locates by id, in whichever
875
+ * Runs the change on the command the view locates by id, in whichever
876
876
  * version inserted it. A statement made there holds in every version
877
- * that carries the perforation.
877
+ * that carries the command.
878
878
  */
879
- const onPerforation = (view, id, op) => draft => {
879
+ const onCommand = (view, id, op) => draft => {
880
880
  const path = view.getPath(id);
881
881
  const symbol = path && getAt(path, draft);
882
- if (isPerforation(symbol))
882
+ if (isCommand(symbol))
883
883
  op(symbol);
884
884
  };
885
- const clearPlacement = (perforation) => placementRelations.forEach(relation => { delete perforation[relation]; });
885
+ const clearPlacement = (command) => placementRelations.forEach(relation => { delete command[relation]; });
886
886
  /** States how the follower is placed relative to the reference, in place of any earlier statement. */
887
- export const placePerforation = (view, followerId, referenceId, relation) => onPerforation(view, followerId, perforation => {
888
- clearPlacement(perforation);
889
- perforation[relation] = assignReference(referenceId);
887
+ export const placeCommand = (view, followerId, referenceId, relation) => onCommand(view, followerId, command => {
888
+ clearPlacement(command);
889
+ command[relation] = assignReference(referenceId);
890
890
  });
891
- export const unplacePerforation = (view, followerId) => onPerforation(view, followerId, clearPlacement);
891
+ export const unplaceCommand = (view, followerId) => onCommand(view, followerId, clearPlacement);
892
892
  /** The pair is stated on `statingId` only, as the format asks. */
893
- export const pairPerforations = (view, statingId, partnerId) => onPerforation(view, statingId, perforation => {
894
- perforation.pairedWith = assignReference(partnerId);
893
+ export const pairCommands = (view, statingId, partnerId) => onCommand(view, statingId, command => {
894
+ command.pairedWith = assignReference(partnerId);
895
895
  });
896
- export const unpairPerforation = (view, statingId) => onPerforation(view, statingId, perforation => {
897
- delete perforation.pairedWith;
896
+ export const unpairCommand = (view, statingId) => onCommand(view, statingId, command => {
897
+ delete command.pairedWith;
898
898
  });
899
899
  const onAssumptionAt = (path, op) => draft => {
900
900
  const assumption = getAt(path, draft);
package/lib/notes.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * `{{<id>}}`, where the id is the entity's, and is resolved when the note
5
5
  * is shown.
6
6
  *
7
- * An entity the edition gives no name to, a perforation or an edit, needs
7
+ * An entity the edition gives no name to, a command or an edit, needs
8
8
  * the note's own words to stand in the sentence: `{{<id>|die Stanzung bei
9
9
  * 7364,7 mm}}`. The name wins where the edition has one, so a siglum
10
10
  * still follows the stemma and a written-out label cannot freeze it.
package/lib/schema.json CHANGED
@@ -101,7 +101,7 @@
101
101
  "$ref": "#/definitions/Text"
102
102
  }
103
103
  ],
104
- "description": "A symbol can be either a note, an expression, or a text. Notes and expressions are perforations; texts are carried by writings."
104
+ "description": "A symbol can be either a note, an expression, or a text. Notes and expressions are commands; texts are carried by writings."
105
105
  },
106
106
  "Argumentation": {
107
107
  "description": "An argumentation provides reasons for a belief and may be associated with a person carrying out that argumentation.",
@@ -622,21 +622,21 @@
622
622
  "type": "string"
623
623
  },
624
624
  "Expression": {
625
- "description": "An expression symbol, representing a perforation on the roll that governs dynamics, pedaling, or mechanical functions of the reproducing piano. Each expression has a scope (bass or treble) and a specific expression type.",
625
+ "description": "An expression symbol, representing a command that governs dynamics, pedaling, or mechanical functions of the reproducing piano rather than sounding a note. Each expression has a scope (bass or treble) and a specific expression type.",
626
626
  "properties": {
627
627
  "after": {
628
628
  "$ref": "#/definitions/ReferenceAssumption",
629
- "description": "A perforation whose onset this one follows when the roll is performed, the counterpart of `before`. This points to the perforation by its `@id`.",
629
+ "description": "A command whose onset this one follows when the roll is performed, the counterpart of `before`. This points to the command by its `@id`.",
630
630
  "ontology": "reo:after"
631
631
  },
632
632
  "alignedWith": {
633
633
  "$ref": "#/definitions/ReferenceAssumption",
634
- "description": "In piano rolls, perforations are often aligned with other perforations, e.g. a \"crescendo off\" might be logically aligned to the start of a note perforation. This points to the perforation by its `@id`.",
634
+ "description": "In piano rolls, commands are often aligned with other commands, e.g. a \"crescendo off\" might be logically aligned to the start of a note. This points to the command by its `@id`.",
635
635
  "ontology": "reo:alignedWith"
636
636
  },
637
637
  "before": {
638
638
  "$ref": "#/definitions/ReferenceAssumption",
639
- "description": "A perforation whose onset this one precedes when the roll is performed, without saying by how much: a \"crescendo off\" ends before the note it leads to begins, even where the copies disagree on it. Where the measurement has it so, nothing moves; where it does not, this one is placed before the reference as far as the copies that agree put it. This points to the perforation by its `@id`.",
639
+ "description": "A command whose onset this one precedes when the roll is performed, without saying by how much: a \"crescendo off\" ends before the note it leads to begins, even where the copies disagree on it. Where the measurement has it so, nothing moves; where it does not, this one is placed before the reference as far as the copies that agree put it. This points to the command by its `@id`.",
640
640
  "ontology": "reo:before"
641
641
  },
642
642
  "carriers": {
@@ -648,13 +648,13 @@
648
648
  "ontology": "crm:P128i is carried by"
649
649
  },
650
650
  "expressionType": {
651
- "description": "The command the perforation gives, named as the reproducing system of the roll names it: \"SustainPedalOn\", \"ForzandoOff\" and so on for the Welte-Mignon T-100. The tracker bar of the system lists the values it reads.",
651
+ "description": "The kind of command, named as the reproducing system of the roll names it: \"SustainPedalOn\", \"ForzandoOff\" and so on for the Welte-Mignon T-100. The tracker bar of the system lists the values it reads.",
652
652
  "type": "string",
653
653
  "ontology": "crm:P2 has type"
654
654
  },
655
655
  "pairedWith": {
656
656
  "$ref": "#/definitions/ReferenceAssumption",
657
- "description": "The perforation this one forms a pair with, e.g. a \"forzando on\" with its \"forzando off\". Any two perforations may be paired. The distance between the two is fixed: whatever displaces the one displaces the other. The relation is symmetric and is stated on one side only. This points to the perforation by its `@id`.",
657
+ "description": "The command this one forms a pair with, e.g. a \"forzando on\" with its \"forzando off\". Any two commands may be paired. The distance between the two is fixed: whatever displaces the one displaces the other. The relation is symmetric and is stated on one side only. This points to the command by its `@id`.",
658
658
  "ontology": "reo:pairedWith"
659
659
  },
660
660
  "scope": {
@@ -684,7 +684,7 @@
684
684
  "ontology": "reo:Expression"
685
685
  },
686
686
  "ExpressionScope": {
687
- "description": "The scope of an expression perforation, indicating whether it applies to the bass or treble register of the piano.",
687
+ "description": "The scope of an expression command, indicating whether it applies to the bass or treble register of the piano.",
688
688
  "enum": [
689
689
  "bass",
690
690
  "treble"
@@ -1646,17 +1646,17 @@
1646
1646
  "properties": {
1647
1647
  "after": {
1648
1648
  "$ref": "#/definitions/ReferenceAssumption",
1649
- "description": "A perforation whose onset this one follows when the roll is performed, the counterpart of `before`. This points to the perforation by its `@id`.",
1649
+ "description": "A command whose onset this one follows when the roll is performed, the counterpart of `before`. This points to the command by its `@id`.",
1650
1650
  "ontology": "reo:after"
1651
1651
  },
1652
1652
  "alignedWith": {
1653
1653
  "$ref": "#/definitions/ReferenceAssumption",
1654
- "description": "In piano rolls, perforations are often aligned with other perforations, e.g. a \"crescendo off\" might be logically aligned to the start of a note perforation. This points to the perforation by its `@id`.",
1654
+ "description": "In piano rolls, commands are often aligned with other commands, e.g. a \"crescendo off\" might be logically aligned to the start of a note. This points to the command by its `@id`.",
1655
1655
  "ontology": "reo:alignedWith"
1656
1656
  },
1657
1657
  "before": {
1658
1658
  "$ref": "#/definitions/ReferenceAssumption",
1659
- "description": "A perforation whose onset this one precedes when the roll is performed, without saying by how much: a \"crescendo off\" ends before the note it leads to begins, even where the copies disagree on it. Where the measurement has it so, nothing moves; where it does not, this one is placed before the reference as far as the copies that agree put it. This points to the perforation by its `@id`.",
1659
+ "description": "A command whose onset this one precedes when the roll is performed, without saying by how much: a \"crescendo off\" ends before the note it leads to begins, even where the copies disagree on it. Where the measurement has it so, nothing moves; where it does not, this one is placed before the reference as far as the copies that agree put it. This points to the command by its `@id`.",
1660
1660
  "ontology": "reo:before"
1661
1661
  },
1662
1662
  "carriers": {
@@ -1669,7 +1669,7 @@
1669
1669
  },
1670
1670
  "pairedWith": {
1671
1671
  "$ref": "#/definitions/ReferenceAssumption",
1672
- "description": "The perforation this one forms a pair with, e.g. a \"forzando on\" with its \"forzando off\". Any two perforations may be paired. The distance between the two is fixed: whatever displaces the one displaces the other. The relation is symmetric and is stated on one side only. This points to the perforation by its `@id`.",
1672
+ "description": "The command this one forms a pair with, e.g. a \"forzando on\" with its \"forzando off\". Any two commands may be paired. The distance between the two is fixed: whatever displaces the one displaces the other. The relation is symmetric and is stated on one side only. This points to the command by its `@id`.",
1673
1673
  "ontology": "reo:pairedWith"
1674
1674
  },
1675
1675
  "pitch": {
@@ -3,40 +3,40 @@ import { AnySymbol, Expression } from "./Symbol";
3
3
  import { Millimeters, Track } from "./Quantity";
4
4
  import { TrackerBar } from "./TrackerBar";
5
5
  /**
6
- * How a scale spells a command: as a perforation that turns a function
7
- * on, one that cancels it, or one that holds it for as long as it lasts.
6
+ * How a scale words a function: as a command that turns it on, one that
7
+ * cancels it, or one that holds it for as long as it lasts.
8
8
  */
9
9
  export type Spelling = 'on' | 'off' | 'held';
10
10
  /**
11
- * A command as what it operates rather than as the word a scale uses
12
- * for it, so that two scales can be compared at all.
11
+ * What a word of a scale operates, rather than the word itself, so that
12
+ * two scales can be compared at all.
13
13
  */
14
- export interface Command {
14
+ export interface Operation {
15
15
  /** The function operated, named the same wherever a scale has it. */
16
16
  operates: string;
17
17
  spelling: Spelling;
18
18
  /**
19
19
  * Whether the half of the keyboard the valve serves is part of the
20
- * command. The dynamics are per half; the pedals are not, and the
21
- * two Welte scales put them on opposite edges of the paper, so a
22
- * rule that compared sides would leave every pedal unpaired.
20
+ * function operated. The dynamics are per half; the pedals are not,
21
+ * and the two Welte scales put them on opposite edges of the paper,
22
+ * so a rule that compared sides would leave every pedal unpaired.
23
23
  */
24
24
  sided: boolean;
25
25
  }
26
- /** What a command operates, or nothing for a word no scale here knows. */
27
- export declare const commandOf: (expressionType: string) => Command | undefined;
26
+ /** What an expression type operates, or nothing for a word no scale here knows. */
27
+ export declare const operationOf: (expressionType: string) => Operation | undefined;
28
28
  /**
29
- * A latched function of the older version and the held perforation of
30
- * the newer one that stands for it.
29
+ * A latched function of the older version and the held command of the
30
+ * newer one that stands for it.
31
31
  */
32
32
  export interface Substitution {
33
- /** The perforation that turned the function on, and the one that cancelled it. */
33
+ /** The command that turned the function on, and the one that cancelled it. */
34
34
  replaced: readonly [Expression, Expression];
35
35
  /**
36
- * The perforations that say the same thing in the other scale's
37
- * words. Usually one, but a held command is punched as a chain of
38
- * round holes with paper bridges rather than as a slot, and a scan
39
- * whose analysis reports those singly gives one symbol per punch.
36
+ * The commands that say the same thing in the other scale's words.
37
+ * Usually one, but a held command is punched as a chain of round
38
+ * holes with paper bridges rather than as a slot, and a scan whose
39
+ * analysis reports those singly gives one symbol per punch.
40
40
  */
41
41
  by: readonly Expression[];
42
42
  }
@@ -51,23 +51,23 @@ export declare const defaultChainGap: import("./Quantity").Quantity<"mm">;
51
51
  * The position a bar reads its own command for the same function on,
52
52
  * where it has no word for this one.
53
53
  *
54
- * A version keeps the perforations it does away with in its deletions,
55
- * and those may be a scale the version is not coded for: a green
56
- * version deletes the red `SlowCrescendoOn` it inherits. That has no
57
- * position on the green bar, so drawing it as a perforation is out of
58
- * the question, but an edit still has to be shown somewhere, and the
59
- * lane the green scale gives the same function is where it belongs.
54
+ * A version keeps the commands it does away with in its deletions, and
55
+ * those may be a scale the version is not coded for: a green version
56
+ * deletes the red `SlowCrescendoOn` it inherits. That has no position on
57
+ * the green bar, so drawing it as a perforation is out of the question,
58
+ * but an edit still has to be shown somewhere, and the lane the green
59
+ * scale gives the same function is where it belongs.
60
60
  */
61
61
  export declare const positionOfSameFunction: (bar: TrackerBar, symbol: Expression) => Track | undefined;
62
62
  /**
63
- * Where a held perforation of the newer version stands for a latched
63
+ * Where a held command of the newer version stands for a latched
64
64
  * function of the older one: the same function, on the same side where
65
65
  * the side counts, spanning the same stretch of the roll.
66
66
  *
67
- * Only unambiguous correspondences are reported. Where two held
68
- * perforations answer one latched interval, or one answers two, none of
69
- * them is reported and the editor is left to say what happened. Nothing
70
- * is invented either: both sides are perforations somebody punched, and
71
- * all this asserts is which stands for which.
67
+ * Only unambiguous correspondences are reported. Where two held commands
68
+ * answer one latched interval, or one answers two, none of them is
69
+ * reported and the editor is left to say what happened. Nothing is
70
+ * invented either: both sides are perforations somebody punched, and all
71
+ * this asserts is which stands for which.
72
72
  */
73
73
  export declare const substitutionsBetween: (own: readonly AnySymbol[], inherited: readonly AnySymbol[], locate: Locate, tolerance?: CollationTolerance, chainGap?: Millimeters) => Substitution[];
@@ -1,7 +1,7 @@
1
1
  import { defaultCollationTolerance } from "./Collation";
2
2
  import { distance, mm, track } from "./Quantity";
3
3
  /**
4
- * What each Welte command operates.
4
+ * What each Welte expression type operates.
5
5
  *
6
6
  * This cannot be read off the names. The T-100 latches a function on
7
7
  * with one perforation and cancels it with a second, while the T-98
@@ -10,8 +10,8 @@ import { distance, mm, track } from "./Quantity";
10
10
  * between the scales: the red `SlowCrescendo` is the green `Crescendo`,
11
11
  * and the red's single `Forzando` valve answers to two green ones that
12
12
  * name the end they pull towards. So the correspondence is stated here
13
- * rather than derived, and only two commands that operate one function
14
- * can stand for each other.
13
+ * rather than derived, and only two types that operate one function can
14
+ * stand for each other.
15
15
  *
16
16
  * The T-100's `MotorOn`/`MotorOff`, `Rewind` and `ElectricCutOff` are
17
17
  * left out on purpose: the green scale has no word for any of them, its
@@ -19,7 +19,7 @@ import { distance, mm, track } from "./Quantity";
19
19
  * and its rewind riding on the bass sforzando-piano line. A red command
20
20
  * of those kinds has no counterpart and stays a plain deletion.
21
21
  */
22
- const commands = {
22
+ const operations = {
23
23
  MezzoforteOn: { operates: 'mezzoforte', spelling: 'on', sided: true },
24
24
  MezzoforteOff: { operates: 'mezzoforte', spelling: 'off', sided: true },
25
25
  SlowCrescendoOn: { operates: 'crescendo', spelling: 'on', sided: true },
@@ -37,8 +37,8 @@ const commands = {
37
37
  SustainPedal: { operates: 'sustainPedal', spelling: 'held', sided: false },
38
38
  SoftPedal: { operates: 'softPedal', spelling: 'held', sided: false }
39
39
  };
40
- /** What a command operates, or nothing for a word no scale here knows. */
41
- export const commandOf = (expressionType) => commands[expressionType];
40
+ /** What an expression type operates, or nothing for a word no scale here knows. */
41
+ export const operationOf = (expressionType) => operations[expressionType];
42
42
  /**
43
43
  * How wide a paper bridge may be for two held perforations to be one
44
44
  * command. The T-98 punches a hold as a chain of round holes on a
@@ -48,20 +48,20 @@ export const commandOf = (expressionType) => commands[expressionType];
48
48
  export const defaultChainGap = mm(3);
49
49
  const isExpression = (symbol) => symbol.type === 'expression';
50
50
  /** The key a command is matched on: the function, and the side where the side counts. */
51
- const functionKey = (symbol, command) => command.sided ? `${command.operates} ${symbol.scope}` : command.operates;
51
+ const functionKey = (symbol, operation) => operation.sided ? `${operation.operates} ${symbol.scope}` : operation.operates;
52
52
  /**
53
53
  * The position a bar reads its own command for the same function on,
54
54
  * where it has no word for this one.
55
55
  *
56
- * A version keeps the perforations it does away with in its deletions,
57
- * and those may be a scale the version is not coded for: a green
58
- * version deletes the red `SlowCrescendoOn` it inherits. That has no
59
- * position on the green bar, so drawing it as a perforation is out of
60
- * the question, but an edit still has to be shown somewhere, and the
61
- * lane the green scale gives the same function is where it belongs.
56
+ * A version keeps the commands it does away with in its deletions, and
57
+ * those may be a scale the version is not coded for: a green version
58
+ * deletes the red `SlowCrescendoOn` it inherits. That has no position on
59
+ * the green bar, so drawing it as a perforation is out of the question,
60
+ * but an edit still has to be shown somewhere, and the lane the green
61
+ * scale gives the same function is where it belongs.
62
62
  */
63
63
  export const positionOfSameFunction = (bar, symbol) => {
64
- const wanted = commandOf(symbol.expressionType);
64
+ const wanted = operationOf(symbol.expressionType);
65
65
  if (!wanted)
66
66
  return undefined;
67
67
  const positions = Array.from({ length: bar.trackCount }, (_, index) => track(index + 1));
@@ -69,26 +69,26 @@ export const positionOfSameFunction = (bar, symbol) => {
69
69
  const meaning = bar.meaningOf(position);
70
70
  if (meaning?.type !== 'expression')
71
71
  return false;
72
- const command = commandOf(meaning.expressionType);
73
- return command !== undefined
74
- && command.operates === wanted.operates
75
- && functionKey(meaning, command) === functionKey(symbol, wanted);
72
+ const operation = operationOf(meaning.expressionType);
73
+ return operation !== undefined
74
+ && operation.operates === wanted.operates
75
+ && functionKey(meaning, operation) === functionKey(symbol, wanted);
76
76
  });
77
77
  };
78
78
  /**
79
- * The intervals the older version latches: each perforation that turns
80
- * a function on, with the one that cancels it next on the same line.
79
+ * The intervals the older version latches: each command that turns a
80
+ * function on, with the one that cancels it next on the same line.
81
81
  */
82
82
  const latchedIn = (symbols, locate) => {
83
83
  const byFunction = new Map();
84
84
  symbols.filter(isExpression).forEach(symbol => {
85
- const command = commandOf(symbol.expressionType);
85
+ const operation = operationOf(symbol.expressionType);
86
86
  const at = locate(symbol)?.from;
87
- if (!command || command.spelling === 'held' || at === undefined)
87
+ if (!operation || operation.spelling === 'held' || at === undefined)
88
88
  return;
89
- const key = functionKey(symbol, command);
89
+ const key = functionKey(symbol, operation);
90
90
  const group = byFunction.get(key) ?? [];
91
- group.push({ symbol, at, spelling: command.spelling });
91
+ group.push({ symbol, at, spelling: operation.spelling });
92
92
  byFunction.set(key, group);
93
93
  });
94
94
  return [...byFunction.values()].flatMap(group => {
@@ -109,7 +109,7 @@ const latchedIn = (symbols, locate) => {
109
109
  off: entry.symbol,
110
110
  from: state.open.from,
111
111
  to: entry.at,
112
- key: functionKey(state.open.on, commandOf(state.open.on.expressionType))
112
+ key: functionKey(state.open.on, operationOf(state.open.on.expressionType))
113
113
  }]
114
114
  }
115
115
  : state;
@@ -117,17 +117,17 @@ const latchedIn = (symbols, locate) => {
117
117
  });
118
118
  };
119
119
  /**
120
- * The commands the newer version holds, a chain of punches counting as
120
+ * The functions the newer version holds, a chain of punches counting as
121
121
  * the one command the paper shows rather than as a run of them.
122
122
  */
123
123
  const heldRunsIn = (symbols, locate, chainGap) => {
124
124
  const byFunction = new Map();
125
125
  symbols.filter(isExpression).forEach(symbol => {
126
- const command = commandOf(symbol.expressionType);
126
+ const operation = operationOf(symbol.expressionType);
127
127
  const place = locate(symbol);
128
- if (!command || command.spelling !== 'held' || !place)
128
+ if (!operation || operation.spelling !== 'held' || !place)
129
129
  return;
130
- const key = functionKey(symbol, command);
130
+ const key = functionKey(symbol, operation);
131
131
  const group = byFunction.get(key) ?? [];
132
132
  group.push({ symbol, from: place.from, to: place.to });
133
133
  byFunction.set(key, group);
@@ -147,15 +147,15 @@ const heldRunsIn = (symbols, locate, chainGap) => {
147
147
  /** The only item of the list, or nothing where there is none or a rival. */
148
148
  const theOnly = (items) => items.length === 1 ? items[0] : undefined;
149
149
  /**
150
- * Where a held perforation of the newer version stands for a latched
150
+ * Where a held command of the newer version stands for a latched
151
151
  * function of the older one: the same function, on the same side where
152
152
  * the side counts, spanning the same stretch of the roll.
153
153
  *
154
- * Only unambiguous correspondences are reported. Where two held
155
- * perforations answer one latched interval, or one answers two, none of
156
- * them is reported and the editor is left to say what happened. Nothing
157
- * is invented either: both sides are perforations somebody punched, and
158
- * all this asserts is which stands for which.
154
+ * Only unambiguous correspondences are reported. Where two held commands
155
+ * answer one latched interval, or one answers two, none of them is
156
+ * reported and the editor is left to say what happened. Nothing is
157
+ * invented either: both sides are perforations somebody punched, and all
158
+ * this asserts is which stands for which.
159
159
  */
160
160
  export const substitutionsBetween = (own, inherited, locate, tolerance = defaultCollationTolerance, chainGap = defaultChainGap) => {
161
161
  const latched = latchedIn(inherited, locate);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linked-rolls",
3
- "version": "0.39.1",
3
+ "version": "0.40.0",
4
4
  "description": "Digital editions of piano rolls: import, collation, editorial assumptions, JSON-LD export, and emulation through a reproducing system",
5
5
  "license": "MIT",
6
6
  "repository": {