linked-rolls 0.54.0 → 0.55.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
@@ -153,19 +153,20 @@ and the onset alone 39, so neither test is idle, but a difference at the
153
153
  end is as often a punch measured badly as a punch genuinely prolonged,
154
154
  and the two are not worth confusing.
155
155
 
156
- ## What a reader adds to a hole
156
+ ## What a reader adds to a chain of holes
157
157
 
158
158
  A copy read pneumatically rather than scanned reports how long a valve
159
159
  stayed open, and a valve is held on past the perforation that opened it,
160
- so its holes run longer than the punched slots while their onsets agree.
161
- Left in, that is not a difference between copies: a collation comparing
162
- such a copy's hole ends against a scanned copy's compares an on-time
163
- with a slot, and reads the one as a lengthening of the other.
160
+ so the chains it reports run longer than the punched ones while their
161
+ onsets agree. Left in, that is not a difference between copies: a
162
+ collation comparing such a copy's chain ends against a scanned copy's
163
+ compares an on-time with a slot, and reads the one as a lengthening of
164
+ the other.
164
165
 
165
- `shortenHoles` takes the extension off and records it on the copy,
166
+ `shortenChains` takes the extension off and records it on the copy,
166
167
  `revertShortening` puts it back, and `readFromPhillipsEroll` will take
167
- it off at import. Only holes are touched, what a writing spans being no
168
- valve. The figure is measured against the other copies rather than
168
+ it off at import. Only chains of holes are touched, what a writing spans
169
+ being no valve. The figure is measured against the other copies rather than
169
170
  derived from the bar, since Phillips gives only the difference between
170
171
  two bars and not the absolute.
171
172
 
@@ -223,7 +224,7 @@ hand, and says nothing about what kind of feature it is. A hole may be
223
224
  punched by hand long after the roll was cut, and a mark may come from
224
225
  the factory, rarely though that happens. A feature no later act is
225
226
  known to have made belongs to the punching, which is where a reading of
226
- a scan puts every hole it finds.
227
+ a scan puts every chain of holes it finds.
227
228
 
228
229
  Three kinds of act rather than two, because the CRM tells them apart.
229
230
  E79 Part Addition asks that what is added be "a separate identifiable
@@ -358,9 +359,9 @@ repository.
358
359
 
359
360
  ### Alignment, order and pairing
360
361
 
361
- A command takes its place from the holes that carry it. Four fields
362
- on a command let an editor state where the measurement should give
363
- way. `alignedWith` names another command whose onset this one takes
362
+ A command takes its place from the chains of holes that carry it. Four
363
+ fields on a command let an editor state where the measurement should
364
+ give way. `alignedWith` names another command whose onset this one takes
364
365
  in the performance, as a "crescendo off" is meant to fall on the note
365
366
  it belongs to. `before` and `after` name a command whose onset this
366
367
  one precedes or follows, without saying by how much: where the copies
package/lib/Emulation.js CHANGED
@@ -15,7 +15,7 @@ const propertiesOf = (view, version) => ({
15
15
  tempo: view.edition.tempoAdjustment,
16
16
  toOwnPaper: view.toOwnPaperOf(version)
17
17
  });
18
- /** The onset a symbol has on each copy carrying it, by the copy's index, as the mean of its holes there. */
18
+ /** The onset a symbol has on each copy carrying it, by the copy's index, as the mean of its chains there. */
19
19
  const onsetsByCopy = (view, symbolId) => {
20
20
  const symbol = view.get(symbolId);
21
21
  if (!symbol)
package/lib/Feature.d.ts CHANGED
@@ -53,7 +53,7 @@ export interface VerticalSpan {
53
53
  */
54
54
  to?: Track;
55
55
  }
56
- export declare const featureTypes: readonly ['Hole', 'Writing', 'Mark', 'GluedOn'];
56
+ export declare const featureTypes: readonly ['HoleChain', 'Writing', 'Mark', 'GluedOn'];
57
57
  export type FeatureType = typeof featureTypes[number];
58
58
  export declare const isFeatureType: (value: unknown) => value is FeatureType;
59
59
  /**
@@ -86,7 +86,7 @@ export interface RollFeature<T extends FeatureType, DamageT extends string> exte
86
86
  condition?: ObjectAssumption<ConditionState<DamageT>>;
87
87
  }
88
88
  export declare const conditions: {
89
- readonly Hole: readonly ["partially-torn", "missing-perforation"];
89
+ readonly HoleChain: readonly ["partially-torn", "missing-perforation"];
90
90
  readonly Writing: readonly ["illegible"];
91
91
  readonly Mark: readonly ["faded"];
92
92
  readonly GluedOn: readonly ["detaching", "ripped"];
@@ -100,19 +100,21 @@ export type FeatureConditionType = typeof conditions[FeatureType][number];
100
100
  */
101
101
  export type FeatureConditionAssignment = ObjectAssumption<ConditionState<FeatureConditionType>>;
102
102
  /**
103
- * A hole (perforation) in the roll paper. Holes are the primary
104
- * carriers of musical information on piano rolls, as they trigger
105
- * notes and expression controls when passing over the tracker bar.
106
- * A punched hole is a human-made feature: CRM counts "the information
107
- * encoding features on mechanical or digital carriers" among the
108
- * features purposely created by human activity.
109
- * @see reo:Hole
103
+ * A chain of holes punched along the roll, which the tracker bar reads
104
+ * as it passes. The perforator cuts a held note or function as a row of
105
+ * punches with bridges of paper left between them, so most perforations
106
+ * are chains; one without a bridge is a chain of a single hole. The
107
+ * holes are the chain's parts and are not stated one by one. A punched
108
+ * chain is a human-made feature: CRM counts "the information encoding
109
+ * features on mechanical or digital carriers" among the features
110
+ * purposely created by human activity.
111
+ * @see reo:HoleChain
110
112
  */
111
- export interface Hole extends RollFeature<'Hole', typeof conditions.Hole[number]> {
113
+ export interface HoleChain extends RollFeature<'HoleChain', typeof conditions.HoleChain[number]> {
112
114
  }
113
115
  /**
114
116
  * Something that lies on a face of the paper rather than through it. A
115
- * hole is not one: it goes through, and is on both faces at once.
117
+ * chain of holes is not one: it goes through, and is on both faces at once.
116
118
  */
117
119
  export interface OnAFace {
118
120
  /**
@@ -216,11 +218,11 @@ export interface GluedOn extends RollFeature<'GluedOn', typeof conditions.GluedO
216
218
  features?: NestedFeature[];
217
219
  }
218
220
  /**
219
- * The features proper: a hole, a writing and a mark are all human-made
220
- * features, and each of them is borne by whatever it sits on. A patch
221
- * is an object glued onto the paper and stands apart from them.
221
+ * The features proper: a chain of holes, a writing and a mark are all
222
+ * human-made features, and each of them is borne by whatever it sits on.
223
+ * A patch is an object glued onto the paper and stands apart from them.
222
224
  */
223
- export type AnyFeature = Hole | Writing | Mark;
225
+ export type AnyFeature = HoleChain | Writing | Mark;
224
226
  /**
225
227
  * Anything found at a place of its own on the roll: a feature or a
226
228
  * glued-on patch. E24 Physical Human-Made Thing is the class both fall
package/lib/Feature.js CHANGED
@@ -1,7 +1,7 @@
1
- export const featureTypes = ['Hole', 'Writing', 'Mark', 'GluedOn'];
1
+ export const featureTypes = ['HoleChain', 'Writing', 'Mark', 'GluedOn'];
2
2
  export const isFeatureType = (value) => featureTypes.includes(value);
3
3
  export const conditions = {
4
- Hole: ['partially-torn', 'missing-perforation'],
4
+ HoleChain: ['partially-torn', 'missing-perforation'],
5
5
  Writing: ['illegible'],
6
6
  Mark: ['faded'],
7
7
  GluedOn: ['detaching', 'ripped']
@@ -16,7 +16,7 @@ export declare const sourceLabels: Record<SourceKind, string>;
16
16
  * roll reader measures when each perforation passes its bar. An
17
17
  * emulation and a recording give the reading somebody else made: the
18
18
  * roll has been turned into notes and commands already, and turning
19
- * those back into holes reconstructs them.
19
+ * those back into chains of holes reconstructs them.
20
20
  */
21
21
  export declare const isMeasured: (kind: SourceKind) => boolean;
22
22
  /**
@@ -27,7 +27,7 @@ const physical = ['roll', 'scan'];
27
27
  * roll reader measures when each perforation passes its bar. An
28
28
  * emulation and a recording give the reading somebody else made: the
29
29
  * roll has been turned into notes and commands already, and turning
30
- * those back into holes reconstructs them.
30
+ * those back into chains of holes reconstructs them.
31
31
  */
32
32
  export const isMeasured = (kind) => measured.includes(kind);
33
33
  /**
@@ -1,4 +1,4 @@
1
- import { Hole } from "./Feature.js";
1
+ import { HoleChain } from "./Feature.js";
2
2
  import { Expression, Note } from "./Symbol.js";
3
3
  import { TrackerBar } from "./TrackerBar.js";
4
4
  import { Millimeters, Quantity, Seconds } from "./Quantity.js";
@@ -32,7 +32,7 @@ export type RollTempo = RollTempoIn<'ft/min'> | RollTempoIn<'m/min'>;
32
32
  * averaged in and the editorial assumptions applied, which is all a
33
33
  * performance needs to know of a symbol.
34
34
  */
35
- export type NegotiatedEvent = Omit<Note | Expression, 'carriers'> & Pick<Hole, 'horizontal' | 'vertical'>;
35
+ export type NegotiatedEvent = Omit<Note | Expression, 'carriers'> & Pick<HoleChain, 'horizontal' | 'vertical'>;
36
36
  interface PerformedRollFeature<T> {
37
37
  type: T;
38
38
  performs: NegotiatedEvent;
package/lib/RollCopy.d.ts CHANGED
@@ -124,10 +124,10 @@ export interface ProductionEvent {
124
124
  /**
125
125
  * The features the copy came from its punching with: the note and
126
126
  * expression perforations, and now and then a mark the perforator
127
- * left. A reading of a scan finds every hole on the paper at once
128
- * and states it here, and a feature an editor reads as the work of
129
- * a later hand belongs in the act that made it, whichever kind of
130
- * feature it is.
127
+ * left. A reading of a scan finds every chain of holes on the paper
128
+ * at once and states it here, and a feature an editor reads as the
129
+ * work of a later hand belongs in the act that made it, whichever
130
+ * kind of feature it is.
131
131
  * @see crm:P108 has produced
132
132
  */
133
133
  produced?: AnyFeature[];
@@ -266,24 +266,24 @@ export interface RollCopy extends WithType<'RollCopy'>, WithId {
266
266
  */
267
267
  scale: number;
268
268
  /**
269
- * What a pneumatic reader added to this copy's holes, where it
270
- * was taken off again. Such a reader reports how long a valve
271
- * stayed open, which exceeds the perforation that opened it, so
272
- * its holes are overlong by a constant while its onsets agree.
273
- * Nothing for a copy read by other means, whose holes are the
274
- * punched slots themselves.
269
+ * What a pneumatic reader added to this copy's chains of holes,
270
+ * where it was taken off again. Such a reader reports how long a
271
+ * valve stayed open, which exceeds the perforation that opened it,
272
+ * so its chains are overlong by a constant while its onsets agree.
273
+ * Nothing for a copy read by other means, whose chains are the
274
+ * punched ones themselves.
275
275
  * Not exported to RDF.
276
276
  */
277
277
  readerExtension: {
278
- /** How much longer the reading of a hole ran than the perforation that caused it. */
278
+ /** How much longer the reading of a chain ran than the perforation that caused it. */
279
279
  length: Millimeters;
280
280
  /**
281
- * The holes it was not taken off, by `@id`, being no longer
281
+ * The chains it was not taken off, by `@id`, being no longer
282
282
  * than it is. The constant reaches its limit there rather
283
283
  * than the copy being wrong, and why they were left is for
284
284
  * the edition to state about the features themselves; this
285
285
  * only records that they stand as the reader gave them, so
286
- * that putting the extension back does not lengthen a hole
286
+ * that putting the extension back does not lengthen a chain
287
287
  * nothing was taken from.
288
288
  */
289
289
  leaving?: string[];
@@ -411,8 +411,8 @@ export declare const barOf: (copy: Pick<RollCopy, 'production'>) => TrackerBar;
411
411
  export declare const punchDiameterOf: (copy: Pick<RollCopy, 'production'>) => Millimeters | undefined;
412
412
  /**
413
413
  * Reads the features of a copy as the tracker bar would read them.
414
- * Holes on a position the bar does not read carry no symbol and are
415
- * dropped, which is what happens physically as well.
414
+ * Chains of holes on a position the bar does not read carry no symbol
415
+ * and are dropped, which is what happens physically as well.
416
416
  *
417
417
  * The bar is named rather than defaulted: a copy is read by its own
418
418
  * bar, and reading a green copy with the red one is a silent semitone.
@@ -428,7 +428,7 @@ export declare const punchDiameterOf: (copy: Pick<RollCopy, 'production'>) => Mi
428
428
  export declare function asSymbols(features: readonly FeatureOrPatch[], bar: TrackerBar): AnySymbol[];
429
429
  /**
430
430
  * The tracks a copy carries holes on that the tracker bar does not read.
431
- * A non-empty result usually means the scan is calibrated wrongly. A hole
431
+ * A non-empty result usually means the scan is calibrated wrongly. A chain
432
432
  * lying across several positions is counted against each one the bar
433
433
  * cannot read, and not at all where it reads them all.
434
434
  */
package/lib/RollCopy.js CHANGED
@@ -54,8 +54,8 @@ export const punchDiameterOf = (copy) => {
54
54
  };
55
55
  /**
56
56
  * Reads the features of a copy as the tracker bar would read them.
57
- * Holes on a position the bar does not read carry no symbol and are
58
- * dropped, which is what happens physically as well.
57
+ * Chains of holes on a position the bar does not read carry no symbol
58
+ * and are dropped, which is what happens physically as well.
59
59
  *
60
60
  * The bar is named rather than defaulted: a copy is read by its own
61
61
  * bar, and reading a green copy with the red one is a silent semitone.
@@ -69,9 +69,9 @@ export const punchDiameterOf = (copy) => {
69
69
  * scan; it is the reading that stops.
70
70
  */
71
71
  export function asSymbols(features, bar) {
72
- const holes = features.filter(feature => feature.type === 'Hole');
73
- const end = bar.endsAt(holes);
74
- return holes
72
+ const chains = features.filter(feature => feature.type === 'HoleChain');
73
+ const end = bar.endsAt(chains);
74
+ return chains
75
75
  .filter(feature => end === undefined || feature.horizontal.from <= end.at)
76
76
  // An opening across two positions uncovers both bar holes and so
77
77
  // reads as both commands; one on a single position gives the one.
@@ -83,14 +83,14 @@ export function asSymbols(features, bar) {
83
83
  }
84
84
  /**
85
85
  * The tracks a copy carries holes on that the tracker bar does not read.
86
- * A non-empty result usually means the scan is calibrated wrongly. A hole
86
+ * A non-empty result usually means the scan is calibrated wrongly. A chain
87
87
  * lying across several positions is counted against each one the bar
88
88
  * cannot read, and not at all where it reads them all.
89
89
  */
90
90
  export function unreadTracks(features, bar) {
91
91
  const counts = new Map();
92
92
  features
93
- .filter(feature => feature.type === 'Hole')
93
+ .filter(feature => feature.type === 'HoleChain')
94
94
  .flatMap(feature => bar.positionsIn(feature.vertical))
95
95
  .filter(position => !bar.meaningOf(position))
96
96
  .forEach(position => counts.set(position, (counts.get(position) || 0) + 1));
package/lib/Symbol.d.ts CHANGED
@@ -3,13 +3,13 @@ import { WithId } from "./utils.js";
3
3
  /**
4
4
  * A symbol is an abstract musical or textual entity carried by one or more
5
5
  * physical features on the roll. Symbols are the result of interpreting
6
- * the physical features (holes, writings, etc.) on the roll copies.
6
+ * the physical features (chains of holes, writings, etc.) on the roll copies.
7
7
  * @see crm:E90 Symbolic Object
8
8
  */
9
9
  export interface Symbol<T extends string> extends WithId {
10
10
  type: T;
11
11
  /**
12
- * References to the physical features (e.g. holes) on the roll copies
12
+ * References to the physical features (e.g. chains of holes) on the roll copies
13
13
  * that carry this symbol. Since the association might be debatable,
14
14
  * it can be annotated. There might be e.g. doubts about the meaning
15
15
  * and correct transcription of a feature on a physical roll.
@@ -21,10 +21,10 @@ export interface Symbol<T extends string> extends WithId {
21
21
  export declare const isSymbol: (object: any) => object is AnySymbol;
22
22
  export declare const isCommand: (symbol: object | undefined) => symbol is AnyCommand;
23
23
  /**
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.
24
+ * A command is what the tracker bar reads from a chain of holes: the
25
+ * note it sounds, or the function it operates. It is typically carried
26
+ * by such a chain, but it might also have different physical
27
+ * appearances.
28
28
  * @see reo:Command
29
29
  */
30
30
  export interface Command<T extends string> extends Symbol<T> {
@@ -11,13 +11,13 @@ export declare const revertShift: (copy: RollCopy) => void;
11
11
  export declare const revertScale: (copy: RollCopy) => void;
12
12
  /**
13
13
  * Takes the extension a pneumatic reader adds off the ends of the
14
- * copy's holes, and records how much was taken.
14
+ * copy's chains of holes, and records how much was taken.
15
15
  *
16
16
  * Such a reader reports how long a valve stayed open, and a valve is
17
- * held on past the perforation that opened it, so its holes run longer
18
- * than the punched slots while their onsets agree. Left in, the
17
+ * held on past the perforation that opened it, so its chains run longer
18
+ * than the punched ones while their onsets agree. Left in, the
19
19
  * difference is not a difference between copies at all: a collation
20
- * comparing this copy's hole ends against a scanned copy's compares a
20
+ * comparing this copy's chain ends against a scanned copy's compares a
21
21
  * pneumatic on-time with a punched slot, and reads the one as a
22
22
  * lengthening of the other.
23
23
  *
@@ -30,10 +30,10 @@ export declare const revertScale: (copy: RollCopy) => void;
30
30
  * way and without any gradient across the bar, which is measured but
31
31
  * too coarse to model from one roll.
32
32
  *
33
- * Only holes are touched. What a writing or a mark spans is no valve.
33
+ * Only chains of holes are touched. What a writing or a mark spans is no valve.
34
34
  */
35
35
  /**
36
- * The holes the extension cannot be taken off, being no longer than it
36
+ * The chains the extension cannot be taken off, being no longer than it
37
37
  * is: the reader reported them open for less time than it holds a valve
38
38
  * on beyond the perforation, so the constant over-corrects them and
39
39
  * would leave them ending before they begin.
@@ -41,23 +41,23 @@ export declare const revertScale: (copy: RollCopy) => void;
41
41
  * They are where the constant shows its limit rather than where the
42
42
  * copy is wrong, the extension varying by about half a millimetre with
43
43
  * the port. What to do with them is an editorial question — a condition
44
- * on the feature, a reading of the hole, a smaller extension — and
45
- * `shortenHoles` throws rather than answer it.
44
+ * on the feature, a reading of the chain, a smaller extension — and
45
+ * `shortenChains` throws rather than answer it.
46
46
  */
47
47
  export declare const tooShortToShorten: (extension: Millimeters, copy: RollCopy, leaving?: ReadonlySet<string>) => Readonly<FeatureOrPatch>[];
48
48
  /**
49
- * Takes the extension off, leaving the named holes as the reader gave
50
- * them. Naming a hole is an editorial act and not a repair: it says
49
+ * Takes the extension off, leaving the named chains as the reader gave
50
+ * them. Naming a chain is an editorial act and not a repair: it says
51
51
  * this one is where the constant stops applying, and the edition is
52
52
  * what has to say why. The copy records which were left, so that
53
- * putting the extension back does not lengthen a hole nothing was
53
+ * putting the extension back does not lengthen a chain nothing was
54
54
  * taken from.
55
55
  *
56
- * Throws where a hole that was not named is no longer than the
56
+ * Throws where a chain that was not named is no longer than the
57
57
  * extension, `tooShortToShorten` saying beforehand which those are.
58
58
  */
59
- export declare const shortenHoles: (extension: Millimeters, copy: RollCopy, leaving?: ReadonlySet<string>) => void;
60
- /** Puts the reader's extension back on the holes it was taken off, as far as one was taken off. */
59
+ export declare const shortenChains: (extension: Millimeters, copy: RollCopy, leaving?: ReadonlySet<string>) => void;
60
+ /** Puts the reader's extension back on the chains it was taken off, as far as one was taken off. */
61
61
  export declare const revertShortening: (copy: RollCopy) => void;
62
62
  /**
63
63
  * How a copy's places are carried onto another copy's:
package/lib/alignment.js CHANGED
@@ -54,16 +54,16 @@ export const revertScale = (copy) => {
54
54
  copy.ops = copy.ops.filter(op => op !== 'stretched');
55
55
  delete copy.measurements.scale;
56
56
  };
57
- const holesOf = (copy) => featuresOf(copy).filter(feature => feature.type === 'Hole');
57
+ const chainsOf = (copy) => featuresOf(copy).filter(feature => feature.type === 'HoleChain');
58
58
  /**
59
59
  * Takes the extension a pneumatic reader adds off the ends of the
60
- * copy's holes, and records how much was taken.
60
+ * copy's chains of holes, and records how much was taken.
61
61
  *
62
62
  * Such a reader reports how long a valve stayed open, and a valve is
63
- * held on past the perforation that opened it, so its holes run longer
64
- * than the punched slots while their onsets agree. Left in, the
63
+ * held on past the perforation that opened it, so its chains run longer
64
+ * than the punched ones while their onsets agree. Left in, the
65
65
  * difference is not a difference between copies at all: a collation
66
- * comparing this copy's hole ends against a scanned copy's compares a
66
+ * comparing this copy's chain ends against a scanned copy's compares a
67
67
  * pneumatic on-time with a punched slot, and reads the one as a
68
68
  * lengthening of the other.
69
69
  *
@@ -76,10 +76,10 @@ const holesOf = (copy) => featuresOf(copy).filter(feature => feature.type === 'H
76
76
  * way and without any gradient across the bar, which is measured but
77
77
  * too coarse to model from one roll.
78
78
  *
79
- * Only holes are touched. What a writing or a mark spans is no valve.
79
+ * Only chains of holes are touched. What a writing or a mark spans is no valve.
80
80
  */
81
81
  /**
82
- * The holes the extension cannot be taken off, being no longer than it
82
+ * The chains the extension cannot be taken off, being no longer than it
83
83
  * is: the reader reported them open for less time than it holds a valve
84
84
  * on beyond the perforation, so the constant over-corrects them and
85
85
  * would leave them ending before they begin.
@@ -87,46 +87,46 @@ const holesOf = (copy) => featuresOf(copy).filter(feature => feature.type === 'H
87
87
  * They are where the constant shows its limit rather than where the
88
88
  * copy is wrong, the extension varying by about half a millimetre with
89
89
  * the port. What to do with them is an editorial question — a condition
90
- * on the feature, a reading of the hole, a smaller extension — and
91
- * `shortenHoles` throws rather than answer it.
90
+ * on the feature, a reading of the chain, a smaller extension — and
91
+ * `shortenChains` throws rather than answer it.
92
92
  */
93
- export const tooShortToShorten = (extension, copy, leaving = new Set()) => holesOf(copy).filter(hole => !leaving.has(hole.id) && hole.horizontal.to - hole.horizontal.from <= extension);
93
+ export const tooShortToShorten = (extension, copy, leaving = new Set()) => chainsOf(copy).filter(chain => !leaving.has(chain.id) && chain.horizontal.to - chain.horizontal.from <= extension);
94
94
  /**
95
- * Takes the extension off, leaving the named holes as the reader gave
96
- * them. Naming a hole is an editorial act and not a repair: it says
95
+ * Takes the extension off, leaving the named chains as the reader gave
96
+ * them. Naming a chain is an editorial act and not a repair: it says
97
97
  * this one is where the constant stops applying, and the edition is
98
98
  * what has to say why. The copy records which were left, so that
99
- * putting the extension back does not lengthen a hole nothing was
99
+ * putting the extension back does not lengthen a chain nothing was
100
100
  * taken from.
101
101
  *
102
- * Throws where a hole that was not named is no longer than the
102
+ * Throws where a chain that was not named is no longer than the
103
103
  * extension, `tooShortToShorten` saying beforehand which those are.
104
104
  */
105
- export const shortenHoles = (extension, copy, leaving = new Set()) => {
105
+ export const shortenChains = (extension, copy, leaving = new Set()) => {
106
106
  if (copy.ops.includes('shortened'))
107
107
  return;
108
108
  const tooShort = tooShortToShorten(extension, copy, leaving);
109
109
  if (tooShort.length > 0) {
110
110
  throw new Error(`The extension of ${extension} mm cannot be taken off ${tooShort.length} `
111
- + `hole(s) of copy ${copy.id}, which are no longer than it: `
112
- + `${tooShort.map(hole => hole.id).join(', ')}`);
111
+ + `chain(s) of holes of copy ${copy.id}, which are no longer than it: `
112
+ + `${tooShort.map(chain => chain.id).join(', ')}`);
113
113
  }
114
- const left = holesOf(copy).filter(hole => leaving.has(hole.id)).map(hole => hole.id);
115
- holesOf(copy)
116
- .filter(hole => !leaving.has(hole.id))
117
- .forEach(hole => { hole.horizontal.to = subtract(hole.horizontal.to, extension); });
114
+ const left = chainsOf(copy).filter(chain => leaving.has(chain.id)).map(chain => chain.id);
115
+ chainsOf(copy)
116
+ .filter(chain => !leaving.has(chain.id))
117
+ .forEach(chain => { chain.horizontal.to = subtract(chain.horizontal.to, extension); });
118
118
  copy.ops = [...copy.ops, 'shortened'];
119
119
  copy.measurements.readerExtension = { length: extension, ...(left.length > 0 && { leaving: left }) };
120
120
  };
121
- /** Puts the reader's extension back on the holes it was taken off, as far as one was taken off. */
121
+ /** Puts the reader's extension back on the chains it was taken off, as far as one was taken off. */
122
122
  export const revertShortening = (copy) => {
123
123
  const taken = copy.measurements.readerExtension;
124
124
  if (!copy.ops.includes('shortened') || taken === undefined)
125
125
  return;
126
126
  const left = new Set(taken.leaving ?? []);
127
- holesOf(copy)
128
- .filter(hole => !left.has(hole.id))
129
- .forEach(hole => { hole.horizontal.to = add(hole.horizontal.to, taken.length); });
127
+ chainsOf(copy)
128
+ .filter(chain => !left.has(chain.id))
129
+ .forEach(chain => { chain.horizontal.to = add(chain.horizontal.to, taken.length); });
130
130
  copy.ops = copy.ops.filter(op => op !== 'shortened');
131
131
  delete copy.measurements.readerExtension;
132
132
  };
@@ -134,7 +134,7 @@ const byPlace = (x, y) => x.at - y.at || x.pitch - y.pitch;
134
134
  /** The notes the bar reads off the features, in the order they pass it. */
135
135
  const noteOnsets = (features, bar) => features
136
136
  .flatMap((feature) => {
137
- if (feature.type !== 'Hole')
137
+ if (feature.type !== 'HoleChain')
138
138
  return [];
139
139
  return bar.meaningsOf(feature.vertical)
140
140
  .filter(meaning => meaning.type === 'note')
@@ -43,11 +43,11 @@ export declare const alignCopy: (copyId: string, shift: Shift, scale: number, re
43
43
  export declare const unalignCopy: (copyId: string) => EditionOp;
44
44
  /**
45
45
  * Takes the extension a pneumatic reader adds off the ends of the
46
- * copy's holes, and records how much was taken, so that its lengths
46
+ * copy's chains of holes, and records how much was taken, so that their lengths
47
47
  * can be compared with a scanned copy's at all.
48
48
  */
49
49
  export declare const shortenCopy: (copyId: string, extension: Millimeters, leaving?: ReadonlySet<string>) => EditionOp;
50
- /** Puts the reader's extension back on the copy's holes. */
50
+ /** Puts the reader's extension back on the copy's chains of holes. */
51
51
  export declare const unshortenCopy: (copyId: string) => EditionOp;
52
52
  /** States what the copy's features were read from, in place of any earlier statement. */
53
53
  export declare const stateSource: (copyId: string, source: FeatureSource) => EditionOp;
@@ -86,7 +86,7 @@ export declare const symbolsCarriedOnlyBy: (edition: Edition, copyId: string) =>
86
86
  * punched, being glued on, so `punched` says nothing of one.
87
87
  */
88
88
  export interface FeatureAct {
89
- /** The copy came from its punching with it, which is where a reading of a scan puts every hole. */
89
+ /** The copy came from its punching with it, which is where a reading of a scan puts every chain of holes. */
90
90
  punched?: boolean;
91
91
  /** The act that brought this feature about brought the new one about as well. */
92
92
  beside?: string;
package/lib/editionOps.js CHANGED
@@ -8,7 +8,7 @@ import { asSymbols, barOf, featuresByAct, featuresOf, isPaperStretch, statesNoth
8
8
  import { systemOf } from "./TrackerBar.js";
9
9
  import { substitutionsBetween } from "./substitution.js";
10
10
  import { trackerBarOf } from "./systems/index.js";
11
- import { applyShift, applyScale, revertShift, revertScale, revertShortening, shortenHoles } from "./alignment.js";
11
+ import { applyShift, applyScale, revertShift, revertScale, revertShortening, shortenChains } from "./alignment.js";
12
12
  import { assignReference, idOf } from "./Assumption.js";
13
13
  import { conditions as conditionsAllowed, featuresBorneBy, isGluedOn, withBorneFeatures } from "./Feature.js";
14
14
  import { distance, mm, subtract } from "./Quantity.js";
@@ -138,11 +138,11 @@ export const unalignCopy = (copyId) => onCopy(copyId, copy => {
138
138
  });
139
139
  /**
140
140
  * Takes the extension a pneumatic reader adds off the ends of the
141
- * copy's holes, and records how much was taken, so that its lengths
141
+ * copy's chains of holes, and records how much was taken, so that their lengths
142
142
  * can be compared with a scanned copy's at all.
143
143
  */
144
- export const shortenCopy = (copyId, extension, leaving) => onCopy(copyId, copy => shortenHoles(extension, copy, leaving));
145
- /** Puts the reader's extension back on the copy's holes. */
144
+ export const shortenCopy = (copyId, extension, leaving) => onCopy(copyId, copy => shortenChains(extension, copy, leaving));
145
+ /** Puts the reader's extension back on the copy's chains of holes. */
146
146
  export const unshortenCopy = (copyId) => onCopy(copyId, copy => revertShortening(copy));
147
147
  /** States what the copy's features were read from, in place of any earlier statement. */
148
148
  export const stateSource = (copyId, source) => onCopy(copyId, copy => {
package/lib/migrate.js CHANGED
@@ -33,6 +33,8 @@ const withTypology = (node) => {
33
33
  }
34
34
  return node;
35
35
  };
36
+ /** A chain of holes written while its class was named after a single hole. */
37
+ const withHoleChainType = (node) => node['@type'] === 'Hole' ? { ...node, '@type': 'HoleChain' } : node;
36
38
  /** A version once stated whether it served as a master or stood on one copy. */
37
39
  const withoutVersionType = (node) => {
38
40
  if (!Object.hasOwn(node, 'versionType'))
@@ -163,9 +165,9 @@ const withTypedPerforator = (node) => {
163
165
  };
164
166
  const asynchronous = 'https://w3id.org/reo/type/drive/asynchronous';
165
167
  /**
166
- * Each hole once stated its punching pattern. A staggering hole the copy
167
- * was punched with shows that its perforator drove each punch on its
168
- * own; one a later act made shows nothing about the machine. Regular
168
+ * Each chain once stated its punching pattern. A staggering chain the
169
+ * copy was punched with shows that its perforator drove each punch on
170
+ * its own; one a later act made shows nothing about the machine. Regular
169
171
  * and accelerating bridges are not carried over: the chain pitch states
170
172
  * the one, and for the other no source was found. The features are in
171
173
  * their acts here, since a node is migrated before its children are.
@@ -180,7 +182,7 @@ const withDriveOfStaggering = (node) => {
180
182
  return { ...node, production: { ...node.production, perforator: { ...perforator, drive: { '@id': asynchronous } } } };
181
183
  };
182
184
  const withoutPattern = (node) => {
183
- if (node['@type'] !== 'Hole' || !Object.hasOwn(node, 'pattern'))
185
+ if (node['@type'] !== 'HoleChain' || !Object.hasOwn(node, 'pattern'))
184
186
  return node;
185
187
  const { pattern: _moved, ...rest } = node;
186
188
  return rest;
@@ -193,13 +195,14 @@ const featuresOf = (copy) => [
193
195
  ...(Array.isArray(copy.features) ? copy.features : []),
194
196
  ...(Array.isArray(copy.production?.produced) ? copy.production.produced : [])
195
197
  ];
198
+ /** A chain of holes under either name, since a node is migrated before its children are. */
199
+ const isHoleChain = (feature) => feature?.['@type'] === 'HoleChain' || feature?.['@type'] === 'Hole';
196
200
  /**
197
201
  * A copy read on a roll reader was stated as a recording before a sound
198
202
  * recording could be one. A sound recording gives no holes, so a recording
199
203
  * with holes is a reading.
200
204
  */
201
- const withReadingKind = (node) => node.readFrom?.kind === 'recording'
202
- && featuresOf(node).some((feature) => feature?.['@type'] === 'Hole')
205
+ const withReadingKind = (node) => node.readFrom?.kind === 'recording' && featuresOf(node).some(isHoleChain)
203
206
  ? { ...node, readFrom: { ...node.readFrom, kind: 'reading' } }
204
207
  : node;
205
208
  /** A feature written while the kind of a feature was a type beside its class. */
@@ -300,7 +303,7 @@ const withTimeSpanDates = (node) => {
300
303
  const { '@value': within, '@type': _typed, ...rest } = node;
301
304
  return { ...rest, within };
302
305
  };
303
- const migrateNode = (node) => [withRenamedKeys, withTypology, withoutVersionType, withoutVersionSiglum, withLowerCaseTerms, withSplitMethod, withReferences, withKeeper, withoutEmptyKeeper,
306
+ const migrateNode = (node) => [withRenamedKeys, withTypology, withHoleChainType, withoutVersionType, withoutVersionSiglum, withLowerCaseTerms, withSplitMethod, withReferences, withKeeper, withoutEmptyKeeper,
304
307
  withPerforator, withProductionNodes, withTypedPerforator, withScale, withDerivationList, withReadingKind, withTimeSpanDates,
305
308
  withoutFeatureKind, withBorneFeaturesNamed, withFeaturesInActs, withDriveOfStaggering, withoutPattern]
306
309
  .reduce((result, step) => step(result), node);
@@ -14,17 +14,17 @@ import { Millimeters, Seconds } from "../Quantity.js";
14
14
  * elapsed time, not paper, and the take-up spool accelerates the paper
15
15
  * as it fills, so `placeAt` has to put the time back onto the paper.
16
16
  * And a switch stays open longer than its perforation is long, so a
17
- * hole read here runs past the punched one: Phillips measures the
17
+ * chain read here runs past the punched one: Phillips measures the
18
18
  * pneumatic on-time as exceeding the apparent length of a perforation
19
19
  * (p. 178), and names what it depends on as the length of the
20
20
  * perforation, the height of the tracker bar hole and the paper speed
21
21
  * (p. 180).
22
22
  *
23
23
  * Left in, that extension is not a difference between copies at all:
24
- * the end of a hole here is a pneumatic on-time where the end of a
25
- * scanned copy's hole is a punched slot, so a collation comparing the
24
+ * the end of a chain here is a pneumatic on-time where the end of a
25
+ * scanned copy's chain is a punched slot, so a collation comparing the
26
26
  * two reads the one as a lengthening of the other. `extension` takes it
27
- * off at the end of every hole, and the copy records what was taken.
27
+ * off at the end of every chain, and the copy records what was taken.
28
28
  *
29
29
  * How much to take off is measured rather than derived, since he gives
30
30
  * only the 0.5 mm by which the Welte bar's holes exceed the Licensee's
@@ -71,8 +71,8 @@ export interface PhillipsErollOptions {
71
71
  placeAt?: (elapsed: Seconds) => Millimeters;
72
72
  /**
73
73
  * How much longer a valve is held on than the perforation that
74
- * opened it, taken off the end of every hole so that these lengths
75
- * can be compared with a scanned copy's. Nothing leaves the holes
74
+ * opened it, taken off the end of every chain so that these lengths
75
+ * can be compared with a scanned copy's. Nothing leaves the chains
76
76
  * as the reader reported them, which is what every copy read before
77
77
  * this option existed states.
78
78
  *
@@ -2,7 +2,7 @@ import { read } from "midifile-ts";
2
2
  import { v4 } from "uuid";
3
3
  import { assignObject } from "../Assumption.js";
4
4
  import { systemOf } from "../TrackerBar.js";
5
- import { shortenHoles } from "../alignment.js";
5
+ import { shortenChains } from "../alignment.js";
6
6
  import { welteT100 } from "../systems/welteT100/bar.js";
7
7
  import { welteLicensee } from "../systems/welteLicensee/bar.js";
8
8
  import { inMetersPerMinute, mm, seconds, track } from "../Quantity.js";
@@ -19,17 +19,17 @@ import { inMetersPerMinute, mm, seconds, track } from "../Quantity.js";
19
19
  * elapsed time, not paper, and the take-up spool accelerates the paper
20
20
  * as it fills, so `placeAt` has to put the time back onto the paper.
21
21
  * And a switch stays open longer than its perforation is long, so a
22
- * hole read here runs past the punched one: Phillips measures the
22
+ * chain read here runs past the punched one: Phillips measures the
23
23
  * pneumatic on-time as exceeding the apparent length of a perforation
24
24
  * (p. 178), and names what it depends on as the length of the
25
25
  * perforation, the height of the tracker bar hole and the paper speed
26
26
  * (p. 180).
27
27
  *
28
28
  * Left in, that extension is not a difference between copies at all:
29
- * the end of a hole here is a pneumatic on-time where the end of a
30
- * scanned copy's hole is a punched slot, so a collation comparing the
29
+ * the end of a chain here is a pneumatic on-time where the end of a
30
+ * scanned copy's chain is a punched slot, so a collation comparing the
31
31
  * two reads the one as a lengthening of the other. `extension` takes it
32
- * off at the end of every hole, and the copy records what was taken.
32
+ * off at the end of every chain, and the copy records what was taken.
33
33
  *
34
34
  * How much to take off is measured rather than derived, since he gives
35
35
  * only the 0.5 mm by which the Welte bar's holes exceed the Licensee's
@@ -153,7 +153,7 @@ export function readFromPhillipsEroll(buffer, { system = welteT100, controlOffse
153
153
  if (!system.meaningOf(position))
154
154
  return [];
155
155
  return [{
156
- type: 'Hole',
156
+ type: 'HoleChain',
157
157
  id: v4(),
158
158
  vertical: { from: position, unit: 'track' },
159
159
  horizontal: {
@@ -174,11 +174,11 @@ export function readFromPhillipsEroll(buffer, { system = welteT100, controlOffse
174
174
  readFrom: {
175
175
  kind: 'reading',
176
176
  actor: assignObject({ name: 'Phillips, Peter', sameAs: [] }),
177
- note: 'Read on Phillips’s pneumatic roll reader. The places are elapsed time put back onto the paper, and a hole runs as long as its switch stayed open, which is longer than the perforation.'
177
+ note: 'Read on Phillips’s pneumatic roll reader. The places are elapsed time put back onto the paper, and a chain of holes runs as long as its switch stayed open, which is longer than the perforation.'
178
178
  }
179
179
  };
180
180
  if (extension !== undefined)
181
- shortenHoles(extension, copy);
181
+ shortenChains(extension, copy);
182
182
  return copy;
183
183
  }
184
184
  /** The bars his files are known to be numbered by. */
@@ -19,7 +19,7 @@ export interface SpencerBarOptions {
19
19
  }
20
20
  /**
21
21
  * Reads the copy on the bar it was cut for, whose numbering it keeps.
22
- * A hole on a position that bar does not read is left out, as the bar
22
+ * A chain on a position that bar does not read is left out, as the bar
23
23
  * would leave it.
24
24
  */
25
25
  export declare function readFromSpencerBar(buffer: ArrayBuffer, { rowsPerInch, system }?: SpencerBarOptions): RollCopy;
@@ -80,7 +80,7 @@ const holesOf = (events) => {
80
80
  };
81
81
  /**
82
82
  * Reads the copy on the bar it was cut for, whose numbering it keeps.
83
- * A hole on a position that bar does not read is left out, as the bar
83
+ * A chain on a position that bar does not read is left out, as the bar
84
84
  * would leave it.
85
85
  */
86
86
  export function readFromSpencerBar(buffer, { rowsPerInch = SPENCER_ROWS_PER_INCH, system = welteLicensee } = {}) {
@@ -95,7 +95,7 @@ export function readFromSpencerBar(buffer, { rowsPerInch = SPENCER_ROWS_PER_INCH
95
95
  if (!system.meaningOf(position))
96
96
  return [];
97
97
  return [{
98
- type: 'Hole',
98
+ type: 'HoleChain',
99
99
  id: v4(),
100
100
  vertical: {
101
101
  from: position,
@@ -136,7 +136,7 @@ export function readFromStanfordAton(atonString, { trackShift, system = welteT10
136
136
  const column = readPx(hole.ORIGIN_COL);
137
137
  const columnWidth = readPx(hole.WIDTH_COL);
138
138
  return [{
139
- type: 'Hole',
139
+ type: 'HoleChain',
140
140
  id: v4(),
141
141
  ...(stanford && {
142
142
  depiction: stanford.depictionOf(column, attack, columnWidth, subtract(release, attack))
package/lib/schema.json CHANGED
@@ -78,7 +78,7 @@
78
78
  "AnyFeature": {
79
79
  "anyOf": [
80
80
  {
81
- "$ref": "#/definitions/Hole"
81
+ "$ref": "#/definitions/HoleChain"
82
82
  },
83
83
  {
84
84
  "$ref": "#/definitions/Writing"
@@ -87,7 +87,7 @@
87
87
  "$ref": "#/definitions/Mark"
88
88
  }
89
89
  ],
90
- "description": "The features proper: a hole, a writing and a mark are all human-made features, and each of them is borne by whatever it sits on. A patch is an object glued onto the paper and stands apart from them."
90
+ "description": "The features proper: a chain of holes, a writing and a mark are all human-made features, and each of them is borne by whatever it sits on. A patch is an object glued onto the paper and stands apart from them."
91
91
  },
92
92
  "AnySymbol": {
93
93
  "anyOf": [
@@ -688,7 +688,7 @@
688
688
  "ontology": "reo:before"
689
689
  },
690
690
  "carriers": {
691
- "description": "References to the physical features (e.g. holes) on the roll copies that carry this symbol. Since the association might be debatable, it can be annotated. There might be e.g. doubts about the meaning and correct transcription of a feature on a physical roll. This points to a feature by its `@id`.",
691
+ "description": "References to the physical features (e.g. chains of holes) on the roll copies that carry this symbol. Since the association might be debatable, it can be annotated. There might be e.g. doubts about the meaning and correct transcription of a feature on a physical roll. This points to a feature by its `@id`.",
692
692
  "items": {
693
693
  "$ref": "#/definitions/ReferenceAssumption"
694
694
  },
@@ -884,8 +884,8 @@
884
884
  "type": "object",
885
885
  "ontology": "reo:GluedOn"
886
886
  },
887
- "Hole": {
888
- "description": "A hole (perforation) in the roll paper. Holes are the primary carriers of musical information on piano rolls, as they trigger notes and expression controls when passing over the tracker bar. A punched hole is a human-made feature: CRM counts \"the information encoding features on mechanical or digital carriers\" among the features purposely created by human activity.",
887
+ "HoleChain": {
888
+ "description": "A chain of holes punched along the roll, which the tracker bar reads as it passes. The perforator cuts a held note or function as a row of punches with bridges of paper left between them, so most perforations are chains; one without a bridge is a chain of a single hole. The holes are the chain's parts and are not stated one by one. A punched chain is a human-made feature: CRM counts \"the information encoding features on mechanical or digital carriers\" among the features purposely created by human activity.",
889
889
  "properties": {
890
890
  "condition": {
891
891
  "$ref": "#/definitions/ObjectAssumption%3CConditionState%3C(%22partially-torn%22%7C%22missing-perforation%22)%3E%3E",
@@ -912,7 +912,7 @@
912
912
  "type": "string"
913
913
  },
914
914
  "@type": {
915
- "const": "Hole",
915
+ "const": "HoleChain",
916
916
  "description": "The type discriminator for this object.",
917
917
  "type": "string",
918
918
  "ontology": "rdf:type"
@@ -925,7 +925,7 @@
925
925
  "vertical"
926
926
  ],
927
927
  "type": "object",
928
- "ontology": "reo:Hole"
928
+ "ontology": "reo:HoleChain"
929
929
  },
930
930
  "HorizontalSpan": {
931
931
  "description": "Describes the horizontal extent of a feature on the roll, measured in millimeters from the beginning of the roll. The `from` value is the start position and `to` is the end position.",
@@ -1455,7 +1455,7 @@
1455
1455
  "type": "string"
1456
1456
  },
1457
1457
  "@type": {
1458
- "const": "Hole",
1458
+ "const": "HoleChain",
1459
1459
  "description": "The type discriminator for this object.",
1460
1460
  "type": "string",
1461
1461
  "ontology": "rdf:type"
@@ -1703,7 +1703,7 @@
1703
1703
  "ontology": "reo:before"
1704
1704
  },
1705
1705
  "carriers": {
1706
- "description": "References to the physical features (e.g. holes) on the roll copies that carry this symbol. Since the association might be debatable, it can be annotated. There might be e.g. doubts about the meaning and correct transcription of a feature on a physical roll. This points to a feature by its `@id`.",
1706
+ "description": "References to the physical features (e.g. chains of holes) on the roll copies that carry this symbol. Since the association might be debatable, it can be annotated. There might be e.g. doubts about the meaning and correct transcription of a feature on a physical roll. This points to a feature by its `@id`.",
1707
1707
  "items": {
1708
1708
  "$ref": "#/definitions/ReferenceAssumption"
1709
1709
  },
@@ -2808,7 +2808,7 @@
2808
2808
  "ontology": "crm:P16 used specific object"
2809
2809
  },
2810
2810
  "produced": {
2811
- "description": "The features the copy came from its punching with: the note and expression perforations, and now and then a mark the perforator left. A reading of a scan finds every hole on the paper at once and states it here, and a feature an editor reads as the work of a later hand belongs in the act that made it, whichever kind of feature it is.",
2811
+ "description": "The features the copy came from its punching with: the note and expression perforations, and now and then a mark the perforator left. A reading of a scan finds every chain of holes on the paper at once and states it here, and a feature an editor reads as the work of a later hand belongs in the act that made it, whichever kind of feature it is.",
2812
2812
  "items": {
2813
2813
  "$ref": "#/definitions/AnyFeature"
2814
2814
  },
@@ -3064,10 +3064,10 @@
3064
3064
  "ontology": "crmdig:L23 used software or firmware"
3065
3065
  },
3066
3066
  "readerExtension": {
3067
- "description": "What a pneumatic reader added to this copy's holes, where it was taken off again. Such a reader reports how long a valve stayed open, which exceeds the perforation that opened it, so its holes are overlong by a constant while its onsets agree. Nothing for a copy read by other means, whose holes are the punched slots themselves. Not exported to RDF.",
3067
+ "description": "What a pneumatic reader added to this copy's chains of holes, where it was taken off again. Such a reader reports how long a valve stayed open, which exceeds the perforation that opened it, so its chains are overlong by a constant while its onsets agree. Nothing for a copy read by other means, whose chains are the punched ones themselves. Not exported to RDF.",
3068
3068
  "properties": {
3069
3069
  "leaving": {
3070
- "description": "The holes it was not taken off, by `@id`, being no longer than it is. The constant reaches its limit there rather than the copy being wrong, and why they were left is for the edition to state about the features themselves; this only records that they stand as the reader gave them, so that putting the extension back does not lengthen a hole nothing was taken from.",
3070
+ "description": "The chains it was not taken off, by `@id`, being no longer than it is. The constant reaches its limit there rather than the copy being wrong, and why they were left is for the edition to state about the features themselves; this only records that they stand as the reader gave them, so that putting the extension back does not lengthen a chain nothing was taken from.",
3071
3071
  "items": {
3072
3072
  "type": "string"
3073
3073
  },
@@ -3075,7 +3075,7 @@
3075
3075
  },
3076
3076
  "length": {
3077
3077
  "$ref": "#/definitions/Millimeters",
3078
- "description": "How much longer the reading of a hole ran than the perforation that caused it."
3078
+ "description": "How much longer the reading of a chain ran than the perforation that caused it."
3079
3079
  }
3080
3080
  },
3081
3081
  "required": [
@@ -3258,7 +3258,7 @@
3258
3258
  "description": "A textual symbol, e.g. a label or annotation found on the roll.",
3259
3259
  "properties": {
3260
3260
  "carriers": {
3261
- "description": "References to the physical features (e.g. holes) on the roll copies that carry this symbol. Since the association might be debatable, it can be annotated. There might be e.g. doubts about the meaning and correct transcription of a feature on a physical roll. This points to a feature by its `@id`.",
3261
+ "description": "References to the physical features (e.g. chains of holes) on the roll copies that carry this symbol. Since the association might be debatable, it can be annotated. There might be e.g. doubts about the meaning and correct transcription of a feature on a physical roll. This points to a feature by its `@id`.",
3262
3262
  "items": {
3263
3263
  "$ref": "#/definitions/ReferenceAssumption"
3264
3264
  },
@@ -14,7 +14,7 @@
14
14
  "Edition": "lrmoo:F2_Expression",
15
15
  "Version": "lrmoo:F2_Expression",
16
16
  "RollCopy": "reo:RollCopy",
17
- "Hole": "reo:Hole",
17
+ "HoleChain": "reo:HoleChain",
18
18
  "Mark": "reo:Mark",
19
19
  "Writing": "reo:Writing",
20
20
  "GluedOn": "reo:GluedOn",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linked-rolls",
3
- "version": "0.54.0",
3
+ "version": "0.55.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": {