linked-rolls 0.19.1 → 0.21.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 +31 -6
- package/lib/Collation.d.ts +1 -3
- package/lib/Collation.js +9 -11
- package/lib/Edition.d.ts +1 -9
- package/lib/EditionView.d.ts +54 -6
- package/lib/EditionView.js +93 -20
- package/lib/Emulation.js +5 -4
- package/lib/ReproducingSystem.d.ts +38 -2
- package/lib/RollCopy.d.ts +25 -2
- package/lib/RollCopy.js +30 -4
- package/lib/TrackerBar.d.ts +57 -2
- package/lib/TrackerBar.js +35 -17
- package/lib/Version.d.ts +49 -1
- package/lib/asJsonLd.js +23 -8
- package/lib/constraints.d.ts +8 -19
- package/lib/constraints.js +71 -15
- package/lib/context.d.ts +10 -1
- package/lib/context.js +10 -1
- package/lib/editionOps.d.ts +3 -1
- package/lib/editionOps.js +77 -15
- package/lib/importJsonLd.js +4 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/migrate.js +85 -11
- package/lib/readers/phillipsEroll.d.ts +4 -6
- package/lib/readers/phillipsEroll.js +6 -7
- package/lib/readers/spencerBar.d.ts +4 -5
- package/lib/readers/spencerBar.js +7 -8
- package/lib/readers/stanfordAton.d.ts +4 -7
- package/lib/readers/stanfordAton.js +4 -5
- package/lib/reservations.d.ts +1 -1
- package/lib/reservations.js +24 -2
- package/lib/schema.json +27 -5
- package/lib/spec/context.json +1 -0
- package/lib/spec/welte-licensee.context.json +10 -0
- package/lib/spec/welte-t98.context.json +10 -0
- package/lib/substitution.d.ts +73 -0
- package/lib/substitution.js +175 -0
- package/lib/systems/velocity.d.ts +34 -0
- package/lib/systems/velocity.js +36 -0
- package/lib/systems/welteLicensee/system.d.ts +46 -0
- package/lib/systems/welteLicensee/system.js +60 -0
- package/lib/systems/welteT100/system.d.ts +19 -16
- package/lib/systems/welteT100/system.js +42 -47
- package/lib/systems/welteT98/bar.d.ts +15 -2
- package/lib/systems/welteT98/bar.js +31 -3
- package/lib/systems/welteT98/system.d.ts +119 -0
- package/lib/systems/welteT98/system.js +245 -0
- package/package.json +12 -4
package/lib/migrate.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { conditions } from "./Feature";
|
|
2
2
|
import { rollConditions } from "./RollCopy";
|
|
3
|
-
import { systemOf } from "./TrackerBar";
|
|
3
|
+
import { systemIdIn, systemOf, translationBetween } from "./TrackerBar";
|
|
4
|
+
import { trackerBars } from "./systems";
|
|
4
5
|
import { welteT100 } from "./systems/welteT100/bar";
|
|
5
6
|
import { versionTypes } from "./Version";
|
|
6
7
|
const versionTypeValues = new Set(versionTypes);
|
|
@@ -88,20 +89,93 @@ const walk = (value) => {
|
|
|
88
89
|
return withWalkedChildren(migrateNode(value));
|
|
89
90
|
return value;
|
|
90
91
|
};
|
|
92
|
+
/** The production of a copy, under whichever of its two names it carries. */
|
|
93
|
+
const productionKeyOf = (copy) => copy?.productionEvent && !copy?.production ? 'productionEvent' : 'production';
|
|
94
|
+
/** The list under the key, or nothing where the document holds something else there. */
|
|
95
|
+
const listAt = (edition, key) => Array.isArray(edition[key]) ? edition[key] : undefined;
|
|
96
|
+
/** A file written while the system belonged to the roll rather than to each version. */
|
|
97
|
+
const namesSystemOnTheRoll = (edition) => edition.roll?.system !== undefined
|
|
98
|
+
|| (listAt(edition, 'versions') ?? []).some((version) => !version?.system);
|
|
99
|
+
const barNamed = (system) => trackerBars.find(bar => bar.id === systemIdIn(system?.['@id']));
|
|
100
|
+
const withSystem = (node, system) => node.system && typeof node.system === 'object' ? node : { ...node, system };
|
|
101
|
+
/** A span on the other bar, or nothing where that bar does not read one of its ends. */
|
|
102
|
+
const spanOnBar = (span, at) => {
|
|
103
|
+
const from = at(span.from);
|
|
104
|
+
if (from === undefined)
|
|
105
|
+
return undefined;
|
|
106
|
+
if (span.to === undefined)
|
|
107
|
+
return { ...span, from };
|
|
108
|
+
const to = at(span.to);
|
|
109
|
+
return to === undefined ? undefined : { ...span, from, to };
|
|
110
|
+
};
|
|
111
|
+
/** The features on the copy's own bar, those it does not read left out, patches and all. */
|
|
112
|
+
const featuresOnBar = (features, at) => features.flatMap((feature) => {
|
|
113
|
+
const vertical = feature.vertical?.unit === 'track'
|
|
114
|
+
? spanOnBar(feature.vertical, at)
|
|
115
|
+
: feature.vertical;
|
|
116
|
+
if (!vertical)
|
|
117
|
+
return [];
|
|
118
|
+
return [{
|
|
119
|
+
...feature,
|
|
120
|
+
vertical,
|
|
121
|
+
...(Array.isArray(feature.features) && { features: featuresOnBar(feature.features, at) })
|
|
122
|
+
}];
|
|
123
|
+
});
|
|
124
|
+
/**
|
|
125
|
+
* A copy cut for another system had its holes put onto the roll's bar
|
|
126
|
+
* as it was read, so they are numbered in the roll's system and not in
|
|
127
|
+
* its own. They go back onto the bar the copy names, which is the only
|
|
128
|
+
* numbering that means anything once each copy is read by its own bar.
|
|
129
|
+
* Between two Welte scales the difference is two tracks, which is a
|
|
130
|
+
* legal position a whole tone away rather than a visible error.
|
|
131
|
+
*/
|
|
132
|
+
const onOwnBar = (copy, rollSystem) => {
|
|
133
|
+
if (!copy || typeof copy !== 'object')
|
|
134
|
+
return copy;
|
|
135
|
+
const key = productionKeyOf(copy);
|
|
136
|
+
const own = copy[key]?.system;
|
|
137
|
+
const from = barNamed(rollSystem);
|
|
138
|
+
const to = own && typeof own === 'object' ? barNamed(own) : undefined;
|
|
139
|
+
if (!from || !to || from.id === to.id || !Array.isArray(copy.features))
|
|
140
|
+
return copy;
|
|
141
|
+
return { ...copy, features: featuresOnBar(copy.features, translationBetween(from, to)) };
|
|
142
|
+
};
|
|
91
143
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
144
|
+
* Systems belonged to the roll before they belonged to the versions
|
|
145
|
+
* and the copies. Every 0.1 edition was read with the T-100 bar, so a
|
|
146
|
+
* roll that named no system was a T-100 roll, and the text a copy's
|
|
147
|
+
* production gave for it is kept as the system's name.
|
|
95
148
|
*/
|
|
96
|
-
const
|
|
97
|
-
if (!edition.roll || edition
|
|
149
|
+
const withSystems = (edition) => {
|
|
150
|
+
if (!edition.roll || !namesSystemOnTheRoll(edition))
|
|
98
151
|
return edition;
|
|
99
|
-
const
|
|
100
|
-
|
|
152
|
+
const versions = listAt(edition, 'versions');
|
|
153
|
+
const copies = listAt(edition, 'copies');
|
|
154
|
+
const stated = (copies ?? [])
|
|
155
|
+
.map((copy) => copy?.[productionKeyOf(copy)]?.system)
|
|
101
156
|
.find((system) => typeof system === 'string' && system !== '');
|
|
102
157
|
const { id, ...concept } = systemOf(welteT100);
|
|
103
|
-
const system = { '@id': id, ...concept, ...(stated && { name: stated }) };
|
|
104
|
-
|
|
158
|
+
const system = edition.roll.system ?? { '@id': id, ...concept, ...(stated && { name: stated }) };
|
|
159
|
+
const { system: _named, ...roll } = edition.roll;
|
|
160
|
+
const created = roll.recordingEvent?.created;
|
|
161
|
+
return {
|
|
162
|
+
...edition,
|
|
163
|
+
roll: created
|
|
164
|
+
? { ...roll, recordingEvent: { ...roll.recordingEvent, created: withSystem(created, system) } }
|
|
165
|
+
: roll,
|
|
166
|
+
...(versions && {
|
|
167
|
+
versions: versions.map((version) => withSystem(version, system))
|
|
168
|
+
}),
|
|
169
|
+
...(copies && {
|
|
170
|
+
copies: copies.map((copy) => {
|
|
171
|
+
if (!copy || typeof copy !== 'object')
|
|
172
|
+
return copy;
|
|
173
|
+
const key = productionKeyOf(copy);
|
|
174
|
+
const onOwn = onOwnBar(copy, system);
|
|
175
|
+
return { ...onOwn, [key]: withSystem(onOwn[key] ?? {}, system) };
|
|
176
|
+
})
|
|
177
|
+
})
|
|
178
|
+
};
|
|
105
179
|
};
|
|
106
180
|
/** An edition written before the editors were carried names none. */
|
|
107
181
|
const withEditors = (edition) => !edition.creation || edition.creation.editors
|
|
@@ -126,5 +200,5 @@ const withDerivationTolerance = (edition) => {
|
|
|
126
200
|
: version)
|
|
127
201
|
};
|
|
128
202
|
};
|
|
129
|
-
const editionSteps = [
|
|
203
|
+
const editionSteps = [withSystems, withEditors, withDerivationTolerance];
|
|
130
204
|
export const migrate = (edition) => walk(editionSteps.reduce((result, step) => step(result), edition));
|
|
@@ -37,8 +37,6 @@ export interface PhillipsErollOptions {
|
|
|
37
37
|
* the roll he read.
|
|
38
38
|
*/
|
|
39
39
|
system?: TrackerBar;
|
|
40
|
-
/** The edition's bar, onto which the positions are put. */
|
|
41
|
-
bar?: TrackerBar;
|
|
42
40
|
/**
|
|
43
41
|
* How far above its position an expression number sits. Defaults to
|
|
44
42
|
* what his samples show for that bar.
|
|
@@ -47,16 +45,16 @@ export interface PhillipsErollOptions {
|
|
|
47
45
|
/**
|
|
48
46
|
* Where on the paper the roll had run after so many seconds. The
|
|
49
47
|
* default is the constant speed the system states, which ignores
|
|
50
|
-
* the take-up spool; pass `paperAt` of welte-
|
|
48
|
+
* the take-up spool; pass `paperAt` of welte-mignon-emulator to
|
|
51
49
|
* account for it.
|
|
52
50
|
*/
|
|
53
51
|
placeAt?: (elapsed: Seconds) => Millimeters;
|
|
54
52
|
}
|
|
55
53
|
/**
|
|
56
54
|
* Reads one of his e-roll files as a copy of the roll, in millimetres
|
|
57
|
-
* of paper
|
|
58
|
-
* the bar would leave it.
|
|
55
|
+
* of paper, on the bar it was cut for and in that bar's numbering. A
|
|
56
|
+
* position the bar does not read is left out, as the bar would leave it.
|
|
59
57
|
*/
|
|
60
|
-
export declare function readFromPhillipsEroll(buffer: ArrayBuffer, { system,
|
|
58
|
+
export declare function readFromPhillipsEroll(buffer: ArrayBuffer, { system, controlOffset, placeAt }?: PhillipsErollOptions): RollCopy;
|
|
61
59
|
/** The bars his files are known to be numbered by. */
|
|
62
60
|
export declare const phillipsSystems: readonly TrackerBar[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { read } from "midifile-ts";
|
|
2
2
|
import { v4 } from "uuid";
|
|
3
3
|
import { assignObject } from "../Assumption";
|
|
4
|
-
import { systemOf
|
|
4
|
+
import { systemOf } from "../TrackerBar";
|
|
5
5
|
import { welteT100 } from "../systems/welteT100/bar";
|
|
6
6
|
import { welteLicensee } from "../systems/welteLicensee/bar";
|
|
7
7
|
import { inMetersPerMinute, mm, seconds, track } from "../Quantity";
|
|
@@ -116,21 +116,20 @@ const positionsByPitch = (bar) => new Map(Array.from({ length: bar.trackCount },
|
|
|
116
116
|
}));
|
|
117
117
|
/**
|
|
118
118
|
* Reads one of his e-roll files as a copy of the roll, in millimetres
|
|
119
|
-
* of paper
|
|
120
|
-
* the bar would leave it.
|
|
119
|
+
* of paper, on the bar it was cut for and in that bar's numbering. A
|
|
120
|
+
* position the bar does not read is left out, as the bar would leave it.
|
|
121
121
|
*/
|
|
122
|
-
export function readFromPhillipsEroll(buffer, { system = welteT100,
|
|
122
|
+
export function readFromPhillipsEroll(buffer, { system = welteT100, controlOffset, placeAt } = {}) {
|
|
123
123
|
const file = read(new Uint8Array(buffer));
|
|
124
124
|
const timed = onOneClock(file.tracks);
|
|
125
125
|
const elapsedAt = clockOf(temposIn(timed), file.header.ticksPerBeat);
|
|
126
126
|
const place = placeAt ?? atStatedSpeed(system);
|
|
127
127
|
const offset = controlOffsetOf(system, controlOffset);
|
|
128
128
|
const notePositions = positionsByPitch(system);
|
|
129
|
-
const onBar = translationBetween(system, bar);
|
|
130
129
|
const positionOf = (number) => notePositions.get(number) ?? track(number - offset);
|
|
131
130
|
const features = notesIn(timed).flatMap((note) => {
|
|
132
|
-
const position =
|
|
133
|
-
if (position
|
|
131
|
+
const position = positionOf(note.pitch);
|
|
132
|
+
if (!system.meaningOf(position))
|
|
134
133
|
return [];
|
|
135
134
|
return [{
|
|
136
135
|
type: 'Hole',
|
|
@@ -16,14 +16,13 @@ export interface SpencerBarOptions {
|
|
|
16
16
|
* the roll it was scanned from. His Welte files are Licensee rolls.
|
|
17
17
|
*/
|
|
18
18
|
system?: TrackerBar;
|
|
19
|
-
/** The edition's bar, onto which the positions are put. */
|
|
20
|
-
bar?: TrackerBar;
|
|
21
19
|
}
|
|
22
20
|
/**
|
|
23
|
-
* Reads the copy
|
|
24
|
-
*
|
|
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
|
|
23
|
+
* would leave it.
|
|
25
24
|
*/
|
|
26
|
-
export declare function readFromSpencerBar(buffer: ArrayBuffer, { rowsPerInch, system
|
|
25
|
+
export declare function readFromSpencerBar(buffer: ArrayBuffer, { rowsPerInch, system }?: SpencerBarOptions): RollCopy;
|
|
27
26
|
/**
|
|
28
27
|
* The `.ann` file beside a `.bar` holds the player's settings for the
|
|
29
28
|
* roll as lines of "/key: value": title, composer, pianist, roll
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
|
-
import { systemOf
|
|
3
|
-
import { welteT100 } from "../systems/welteT100/bar";
|
|
2
|
+
import { systemOf } from "../TrackerBar";
|
|
4
3
|
import { welteLicensee } from "../systems/welteLicensee/bar";
|
|
5
4
|
import { feetPerMinute, inMillimeters, px, track } from "../Quantity";
|
|
6
5
|
/**
|
|
@@ -80,20 +79,20 @@ const holesOf = (events) => {
|
|
|
80
79
|
return holes.sort((a, b) => a.from - b.from);
|
|
81
80
|
};
|
|
82
81
|
/**
|
|
83
|
-
* Reads the copy
|
|
84
|
-
*
|
|
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
|
|
84
|
+
* would leave it.
|
|
85
85
|
*/
|
|
86
|
-
export function readFromSpencerBar(buffer, { rowsPerInch = SPENCER_ROWS_PER_INCH, system = welteLicensee
|
|
86
|
+
export function readFromSpencerBar(buffer, { rowsPerInch = SPENCER_ROWS_PER_INCH, system = welteLicensee } = {}) {
|
|
87
87
|
const bytes = new Uint8Array(buffer);
|
|
88
88
|
if (byteAt(bytes, TEXT_AT) !== TEXT_TAG) {
|
|
89
89
|
throw new Error('Not a Spencer .bar file: no text after the header');
|
|
90
90
|
}
|
|
91
91
|
const placeOf = (row) => inMillimeters(px(row), rowsPerInch);
|
|
92
|
-
const onBar = translationBetween(system, bar);
|
|
93
92
|
const features = holesOf(eventsIn(bytes, endOfText(bytes, TEXT_AT + 1)))
|
|
94
93
|
.flatMap((hole) => {
|
|
95
|
-
const position =
|
|
96
|
-
if (position
|
|
94
|
+
const position = track(hole.position);
|
|
95
|
+
if (!system.meaningOf(position))
|
|
97
96
|
return [];
|
|
98
97
|
return [{
|
|
99
98
|
type: 'Hole',
|
|
@@ -8,13 +8,10 @@ export interface StanfordAtonOptions {
|
|
|
8
8
|
* perforation on the bar's rewind track.
|
|
9
9
|
*/
|
|
10
10
|
trackShift?: Track;
|
|
11
|
-
/** The edition's bar, onto which the holes are put. */
|
|
12
|
-
bar?: TrackerBar;
|
|
13
11
|
/**
|
|
14
|
-
* The bar the scanned roll was cut for
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* read is left out.
|
|
12
|
+
* The bar the scanned roll was cut for. The scan is calibrated on
|
|
13
|
+
* it and the holes keep its numbering, since a copy is read by the
|
|
14
|
+
* bar it was cut for and by no other.
|
|
18
15
|
*/
|
|
19
16
|
system?: TrackerBar;
|
|
20
17
|
/**
|
|
@@ -24,4 +21,4 @@ export interface StanfordAtonOptions {
|
|
|
24
21
|
*/
|
|
25
22
|
scan?: string;
|
|
26
23
|
}
|
|
27
|
-
export declare function readFromStanfordAton(atonString: string, { trackShift,
|
|
24
|
+
export declare function readFromStanfordAton(atonString: string, { trackShift, system, scan }?: StanfordAtonOptions): RollCopy;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
2
|
import { AtonParser } from "./AtonParser";
|
|
3
|
-
import { systemOf
|
|
3
|
+
import { systemOf } from "../TrackerBar";
|
|
4
4
|
import { welteT100 } from "../systems/welteT100/bar";
|
|
5
5
|
import { inMillimeters, mean, mm, pixelsPerInch, px, subtract, track } from "../Quantity";
|
|
6
6
|
/** Values in these files carry their unit as a suffix, e.g. "37.7646px". */
|
|
@@ -110,7 +110,7 @@ const measuredByOf = (rollinfo) => {
|
|
|
110
110
|
date
|
|
111
111
|
};
|
|
112
112
|
};
|
|
113
|
-
export function readFromStanfordAton(atonString, { trackShift,
|
|
113
|
+
export function readFromStanfordAton(atonString, { trackShift, system = welteT100, scan } = {}) {
|
|
114
114
|
const parser = new AtonParser();
|
|
115
115
|
const json = parser.parse(atonString);
|
|
116
116
|
const holes = json.ROLLINFO.HOLES.HOLE;
|
|
@@ -128,11 +128,10 @@ export function readFromStanfordAton(atonString, { trackShift, bar = welteT100,
|
|
|
128
128
|
};
|
|
129
129
|
const punchDiameter = punchDiameterOf(holes, dpi);
|
|
130
130
|
const chains = chainsAmong([...holes, ...chainedBadHoles(listOf(json.ROLLINFO.BADHOLES?.HOLE), calibration)]);
|
|
131
|
-
const onBar = translationBetween(system, bar);
|
|
132
131
|
const features = chains
|
|
133
132
|
.flatMap(({ hole, attack, release }) => {
|
|
134
|
-
const position =
|
|
135
|
-
if (position
|
|
133
|
+
const position = track(+hole.TRACKER_HOLE + shift);
|
|
134
|
+
if (!system.meaningOf(position))
|
|
136
135
|
return [];
|
|
137
136
|
const column = readPx(hole.ORIGIN_COL);
|
|
138
137
|
const columnWidth = readPx(hole.WIDTH_COL);
|
package/lib/reservations.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RollCopy } from "./RollCopy";
|
|
2
|
-
export declare const reservationTypes: readonly ['source-not-stated', 'source-undocumented', 'features-interpreted', 'no-physical-evidence', 'measurement-undocumented', 'not-calibrated'];
|
|
2
|
+
export declare const reservationTypes: readonly ['source-not-stated', 'source-undocumented', 'features-interpreted', 'no-physical-evidence', 'measurement-undocumented', 'not-calibrated', 'system-unknown'];
|
|
3
3
|
export type ReservationType = typeof reservationTypes[number];
|
|
4
4
|
/**
|
|
5
5
|
* Something an edition cannot vouch for in one of its copies.
|
package/lib/reservations.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { bearsPhysicalEvidence, isMeasured, sourceLabels } from "./FeatureSource";
|
|
2
2
|
import { calibrationOf } from "./RollCopy";
|
|
3
|
+
import { trackerBarOf } from "./systems";
|
|
3
4
|
export const reservationTypes = [
|
|
4
5
|
'source-not-stated',
|
|
5
6
|
'source-undocumented',
|
|
6
7
|
'features-interpreted',
|
|
7
8
|
'no-physical-evidence',
|
|
8
9
|
'measurement-undocumented',
|
|
9
|
-
'not-calibrated'
|
|
10
|
+
'not-calibrated',
|
|
11
|
+
'system-unknown'
|
|
10
12
|
];
|
|
11
13
|
const sourceStated = copy => copy.readFrom ? undefined : {
|
|
12
14
|
type: 'source-not-stated',
|
|
@@ -37,13 +39,33 @@ const calibrated = copy => calibrationOf(copy) ? undefined : {
|
|
|
37
39
|
type: 'not-calibrated',
|
|
38
40
|
note: 'The copy is not calibrated against the tracker bar, so its track positions rest on the numbering its source used.'
|
|
39
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* The bar decides what every track on the copy means, so a copy the
|
|
44
|
+
* edition cannot place in a system is read by the T-100 for want of
|
|
45
|
+
* anything better. Between two Welte scales that is a semitone rather
|
|
46
|
+
* than a visible error, which is why it is said out loud.
|
|
47
|
+
*/
|
|
48
|
+
const systemKnown = copy => {
|
|
49
|
+
const system = copy.production?.system;
|
|
50
|
+
if (system === undefined) {
|
|
51
|
+
return {
|
|
52
|
+
type: 'system-unknown',
|
|
53
|
+
note: 'The copy names no reproducing system, so it is read by the T-100 tracker bar.'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return trackerBarOf(system) ? undefined : {
|
|
57
|
+
type: 'system-unknown',
|
|
58
|
+
note: `The copy names ${system.name || 'a reproducing system'}, which the edition has no tracker bar for, so it is read by the T-100's.`
|
|
59
|
+
};
|
|
60
|
+
};
|
|
40
61
|
const checks = [
|
|
41
62
|
sourceStated,
|
|
42
63
|
sourceDocumented,
|
|
43
64
|
featuresMeasured,
|
|
44
65
|
physicalEvidence,
|
|
45
66
|
measurementDocumented,
|
|
46
|
-
calibrated
|
|
67
|
+
calibrated,
|
|
68
|
+
systemKnown
|
|
47
69
|
];
|
|
48
70
|
/**
|
|
49
71
|
* What the edition cannot vouch for in a copy, in the order the
|
package/lib/schema.json
CHANGED
|
@@ -1802,15 +1802,10 @@
|
|
|
1802
1802
|
"recordingEvent": {
|
|
1803
1803
|
"$ref": "#/definitions/RecordingEvent",
|
|
1804
1804
|
"description": "[ontology: lrmoo:R19i was realised through]"
|
|
1805
|
-
},
|
|
1806
|
-
"system": {
|
|
1807
|
-
"$ref": "#/definitions/Concept",
|
|
1808
|
-
"description": "The reproducing system the roll was cut for. A system the type vocabulary knows carries the IRI of its concept as `id`, from which the export takes the system's own context, so that the expression types are read as that system's. [ontology: crm:P2 has type]"
|
|
1809
1805
|
}
|
|
1810
1806
|
},
|
|
1811
1807
|
"required": [
|
|
1812
1808
|
"catalogueNumber",
|
|
1813
|
-
"system",
|
|
1814
1809
|
"recordingEvent"
|
|
1815
1810
|
],
|
|
1816
1811
|
"type": "object"
|
|
@@ -2089,6 +2084,10 @@
|
|
|
2089
2084
|
"$ref": "#/definitions/Derivation",
|
|
2090
2085
|
"description": "If no derivation is defined, it is assumed that this version represents the mother roll. [ontology: lrmoo:R76 is derivative of]"
|
|
2091
2086
|
},
|
|
2087
|
+
"creation": {
|
|
2088
|
+
"$ref": "#/definitions/VersionCreation",
|
|
2089
|
+
"description": "The act that made this version, where it is known: who carried it out, when, and by what rule. [ontology: lrmoo:R17i was created by]"
|
|
2090
|
+
},
|
|
2092
2091
|
"edits": {
|
|
2093
2092
|
"description": "The list of edits that, applied to the base version, produce this version. [ontology: reo:involvedEdit]",
|
|
2094
2093
|
"items": {
|
|
@@ -2107,6 +2106,10 @@
|
|
|
2107
2106
|
"description": "A short siglum to identify the version, e.g. \"A\", \"B1\", \"B2_rev\", etc. [ontology: reo:siglum]",
|
|
2108
2107
|
"type": "string"
|
|
2109
2108
|
},
|
|
2109
|
+
"system": {
|
|
2110
|
+
"$ref": "#/definitions/Concept",
|
|
2111
|
+
"description": "The reproducing system this version is coded for. One roll was often issued for several of them, and a version is a reading in one system's words: its expression types are that system's vocabulary and its notes sit on that bar's positions. A system the type vocabulary knows carries the IRI of its concept as `id`, from which the export takes the system's own context. [ontology: crm:P2 has type]"
|
|
2112
|
+
},
|
|
2110
2113
|
"versionType": {
|
|
2111
2114
|
"$ref": "#/definitions/VersionType",
|
|
2112
2115
|
"description": "Whether the version served as a master for reproductions or exists on one copy only. [ontology: crm:P2 has type]"
|
|
@@ -2127,11 +2130,30 @@
|
|
|
2127
2130
|
"@id",
|
|
2128
2131
|
"motivations",
|
|
2129
2132
|
"siglum",
|
|
2133
|
+
"system",
|
|
2130
2134
|
"@type",
|
|
2131
2135
|
"versionType"
|
|
2132
2136
|
],
|
|
2133
2137
|
"type": "object"
|
|
2134
2138
|
},
|
|
2139
|
+
"VersionCreation": {
|
|
2140
|
+
"description": "How a version was made, where that is known and worth stating.\n\nA roll issued for another system was re-punched by an editor of the publisher's, and that was an editorial act rather than a conversion: Lawson names Kähle as the man who corrected second masters for the green system. The rule he worked by is the procedure named here, and the version's edits carry it out, so the mechanical part of a transfer is stated once instead of being spelled out per note. [ontology: lrmoo:F28 Expression Creation]",
|
|
2141
|
+
"properties": {
|
|
2142
|
+
"actor": {
|
|
2143
|
+
"$ref": "#/definitions/ActorAssignment",
|
|
2144
|
+
"description": "Who carried the act out. An `ObjectAssumption`, so an attribution can carry the belief it rests on and the reasons for it. [ontology: crm:P14 carried out by]"
|
|
2145
|
+
},
|
|
2146
|
+
"date": {
|
|
2147
|
+
"$ref": "#/definitions/DateAssignment",
|
|
2148
|
+
"description": "When it took place. [ontology: dcterms:date]"
|
|
2149
|
+
},
|
|
2150
|
+
"procedure": {
|
|
2151
|
+
"$ref": "#/definitions/Concept",
|
|
2152
|
+
"description": "The rule followed, as a term of the vocabulary: the notes stand at their pitch, the expression is re-spelled in the other system's words. [ontology: crm:P33 used specific technique]"
|
|
2153
|
+
}
|
|
2154
|
+
},
|
|
2155
|
+
"type": "object"
|
|
2156
|
+
},
|
|
2135
2157
|
"VersionType": {
|
|
2136
2158
|
"description": "The type of a version. An 'edition' version may serve as the master for several roll copies; a 'unicum' version exists only on one specific copy.",
|
|
2137
2159
|
"enum": [
|
package/lib/spec/context.json
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { CollationTolerance, Locate } from "./Collation";
|
|
2
|
+
import { AnySymbol, Expression } from "./Symbol";
|
|
3
|
+
import { Millimeters, Track } from "./Quantity";
|
|
4
|
+
import { TrackerBar } from "./TrackerBar";
|
|
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.
|
|
8
|
+
*/
|
|
9
|
+
export type Spelling = 'on' | 'off' | 'held';
|
|
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.
|
|
13
|
+
*/
|
|
14
|
+
export interface Command {
|
|
15
|
+
/** The function operated, named the same wherever a scale has it. */
|
|
16
|
+
operates: string;
|
|
17
|
+
spelling: Spelling;
|
|
18
|
+
/**
|
|
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.
|
|
23
|
+
*/
|
|
24
|
+
sided: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** What a command operates, or nothing for a word no scale here knows. */
|
|
27
|
+
export declare const commandOf: (expressionType: string) => Command | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* A latched function of the older version and the held perforation of
|
|
30
|
+
* the newer one that stands for it.
|
|
31
|
+
*/
|
|
32
|
+
export interface Substitution {
|
|
33
|
+
/** The perforation that turned the function on, and the one that cancelled it. */
|
|
34
|
+
replaced: readonly [Expression, Expression];
|
|
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.
|
|
40
|
+
*/
|
|
41
|
+
by: readonly Expression[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* How wide a paper bridge may be for two held perforations to be one
|
|
45
|
+
* command. The T-98 punches a hold as a chain of round holes on a
|
|
46
|
+
* 2.66 mm grid with bridges of about a millimetre, so a scan read hole
|
|
47
|
+
* by hole shows a run where the paper shows one command.
|
|
48
|
+
*/
|
|
49
|
+
export declare const defaultChainGap: import("./Quantity").Quantity<"mm">;
|
|
50
|
+
/**
|
|
51
|
+
* The position a bar reads its own command for the same function on,
|
|
52
|
+
* where it has no word for this one.
|
|
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.
|
|
60
|
+
*/
|
|
61
|
+
export declare const positionOfSameFunction: (bar: TrackerBar, symbol: Expression) => Track | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Where a held perforation of the newer version stands for a latched
|
|
64
|
+
* function of the older one: the same function, on the same side where
|
|
65
|
+
* the side counts, spanning the same stretch of the roll.
|
|
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.
|
|
72
|
+
*/
|
|
73
|
+
export declare const substitutionsBetween: (own: readonly AnySymbol[], inherited: readonly AnySymbol[], locate: Locate, tolerance?: CollationTolerance, chainGap?: Millimeters) => Substitution[];
|