linked-rolls 0.0.1

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.
Files changed (60) hide show
  1. package/README.md +18 -0
  2. package/lib/Collation.d.ts +4 -0
  3. package/lib/Collation.js +1 -0
  4. package/lib/Condition.d.ts +10 -0
  5. package/lib/Condition.js +1 -0
  6. package/lib/ConditionState.d.ts +9 -0
  7. package/lib/ConditionState.js +6 -0
  8. package/lib/Edit.d.ts +21 -0
  9. package/lib/Edit.js +112 -0
  10. package/lib/Edition.d.ts +54 -0
  11. package/lib/Edition.js +1 -0
  12. package/lib/EditorialAssumption.d.ts +67 -0
  13. package/lib/EditorialAssumption.js +26 -0
  14. package/lib/Emulation.d.ts +76 -0
  15. package/lib/Emulation.js +474 -0
  16. package/lib/Feature.d.ts +37 -0
  17. package/lib/Feature.js +3 -0
  18. package/lib/Measurement.d.ts +9 -0
  19. package/lib/Measurement.js +1 -0
  20. package/lib/PlaceTimeConversion.d.ts +65 -0
  21. package/lib/PlaceTimeConversion.js +175 -0
  22. package/lib/RollCopy.d.ts +85 -0
  23. package/lib/RollCopy.js +273 -0
  24. package/lib/RollEvent.d.ts +76 -0
  25. package/lib/RollEvent.js +3 -0
  26. package/lib/Stage.d.ts +37 -0
  27. package/lib/Stage.js +165 -0
  28. package/lib/Symbol.d.ts +62 -0
  29. package/lib/Symbol.js +29 -0
  30. package/lib/TrackerBar.d.ts +8 -0
  31. package/lib/TrackerBar.js +53 -0
  32. package/lib/Transcription.d.ts +7 -0
  33. package/lib/Transcription.js +9 -0
  34. package/lib/Version.d.ts +42 -0
  35. package/lib/Version.js +217 -0
  36. package/lib/WithId.d.ts +3 -0
  37. package/lib/WithId.js +1 -0
  38. package/lib/alignFeatures.d.ts +11 -0
  39. package/lib/alignFeatures.js +54 -0
  40. package/lib/alignRolls.d.ts +7 -0
  41. package/lib/alignRolls.js +49 -0
  42. package/lib/alignSymbols.d.ts +7 -0
  43. package/lib/alignSymbols.js +49 -0
  44. package/lib/asJsonLd.d.ts +3 -0
  45. package/lib/asJsonLd.js +67 -0
  46. package/lib/asMIDISpans.d.ts +23 -0
  47. package/lib/asMIDISpans.js +111 -0
  48. package/lib/aton/AtonParser.d.ts +48 -0
  49. package/lib/aton/AtonParser.js +245 -0
  50. package/lib/aton/AtonParser.test.d.ts +1 -0
  51. package/lib/aton/AtonParser.test.js +16 -0
  52. package/lib/build-schema.cjs +113 -0
  53. package/lib/context.d.ts +1 -0
  54. package/lib/context.js +1 -0
  55. package/lib/importJsonLd.d.ts +4 -0
  56. package/lib/importJsonLd.js +121 -0
  57. package/lib/index.d.ts +17 -0
  58. package/lib/index.js +17 -0
  59. package/lib/spec/context.json +192 -0
  60. package/package.json +27 -0
@@ -0,0 +1,175 @@
1
+ export class PlaceTimeConversion {
2
+ }
3
+ export class NoAccelerationConversion {
4
+ constructor() {
5
+ Object.defineProperty(this, "metersPerMinute", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: 3
10
+ }); // according to most sources
11
+ }
12
+ get summary() {
13
+ return `no aceleration (${this.metersPerMinute} m/min)`;
14
+ }
15
+ /**
16
+ * Converts physical place (in cm) to time (in seconds).
17
+ * @param x1 - The distance in mm.
18
+ * @returns Time in seconds.
19
+ */
20
+ placeToTime(cm) {
21
+ const meters = cm / 100; // convert to m
22
+ const t = meters / this.metersPerMinute;
23
+ return t * 60;
24
+ }
25
+ /**
26
+ * Converts time (in seconds) to physical place (in cm).
27
+ * @param t1 - The time in seconds.
28
+ * @returns Distance in cm.
29
+ */
30
+ timeToPlace(t1) {
31
+ return (this.metersPerMinute * (t1 / 60)) * 100;
32
+ }
33
+ }
34
+ var SpeedUnit;
35
+ (function (SpeedUnit) {
36
+ SpeedUnit[SpeedUnit["MetersPerMinute"] = 0] = "MetersPerMinute";
37
+ SpeedUnit[SpeedUnit["FeetPerMinute"] = 1] = "FeetPerMinute";
38
+ })(SpeedUnit || (SpeedUnit = {}));
39
+ var AccelerationUnit;
40
+ (function (AccelerationUnit) {
41
+ AccelerationUnit[AccelerationUnit["MillimetersPerSecondSquared"] = 0] = "MillimetersPerSecondSquared";
42
+ AccelerationUnit[AccelerationUnit["FeetPerMinuteSquared"] = 1] = "FeetPerMinuteSquared";
43
+ })(AccelerationUnit || (AccelerationUnit = {}));
44
+ export class KinematicConversion {
45
+ get summary() {
46
+ return `kinematic (acceleration: ${this.acceleration} ft/s², speed: ${this.feetPerMinute} ft/min)`;
47
+ }
48
+ constructor(feetPerMinute = KinematicConversion.normalSpeed, acceleration = KinematicConversion.baertschAcceleration) {
49
+ Object.defineProperty(this, "feetPerMinute", {
50
+ enumerable: true,
51
+ configurable: true,
52
+ writable: true,
53
+ value: void 0
54
+ });
55
+ Object.defineProperty(this, "acceleration", {
56
+ enumerable: true,
57
+ configurable: true,
58
+ writable: true,
59
+ value: void 0
60
+ });
61
+ this.feetPerMinute = feetPerMinute;
62
+ this.acceleration = acceleration;
63
+ }
64
+ setSpeed(speed, unit) {
65
+ if (unit === SpeedUnit.FeetPerMinute) {
66
+ this.feetPerMinute = speed;
67
+ }
68
+ else if (unit === SpeedUnit.MetersPerMinute) {
69
+ this.feetPerMinute = speed * 3.2808399;
70
+ }
71
+ else {
72
+ throw new Error('Unsupported unit');
73
+ }
74
+ }
75
+ setAcceleration(acceleration, unit) {
76
+ if (unit === AccelerationUnit.FeetPerMinuteSquared) {
77
+ this.acceleration = acceleration;
78
+ }
79
+ else if (unit === AccelerationUnit.MillimetersPerSecondSquared) {
80
+ this.acceleration = acceleration * 0.0032808399 * 3600;
81
+ }
82
+ else {
83
+ throw new Error('Unsupported unit');
84
+ }
85
+ }
86
+ /**
87
+ * Converts physical place (in cm) to time (in seconds).
88
+ * @param x1 - The distance in mm.
89
+ * @returns Time in seconds.
90
+ */
91
+ placeToTime(cm) {
92
+ const x1 = cm / 30.48;
93
+ const v = this.feetPerMinute;
94
+ const a = this.acceleration;
95
+ const t = (Math.sqrt(2 * a * x1 + Math.pow(v, 2)) - v) / a;
96
+ return t * 60;
97
+ }
98
+ /**
99
+ * Converts time (in seconds) to physical place (in cm).
100
+ * @param t1 - The time in seconds.
101
+ * @returns Distance in cm.
102
+ */
103
+ timeToPlace(t1) {
104
+ // Convert seconds -> minutes
105
+ const T = t1 / 60;
106
+ const xFeet = this.feetPerMinute * T + 0.5 * this.acceleration * Math.pow(T, 2);
107
+ // Convert feet -> millimeters
108
+ const xMM = xFeet * 304.8;
109
+ return xMM / 10;
110
+ }
111
+ }
112
+ Object.defineProperty(KinematicConversion, "slowSpeed", {
113
+ enumerable: true,
114
+ configurable: true,
115
+ writable: true,
116
+ value: 9.46
117
+ });
118
+ Object.defineProperty(KinematicConversion, "normalSpeed", {
119
+ enumerable: true,
120
+ configurable: true,
121
+ writable: true,
122
+ value: 9.85
123
+ });
124
+ Object.defineProperty(KinematicConversion, "stanfordAcceleration", {
125
+ enumerable: true,
126
+ configurable: true,
127
+ writable: true,
128
+ value: 0.3147
129
+ }); // cf. https://github.com/pianoroll/midi2exp/commit/6a29060
130
+ Object.defineProperty(KinematicConversion, "baertschAcceleration", {
131
+ enumerable: true,
132
+ configurable: true,
133
+ writable: true,
134
+ value: 0.1772
135
+ }); // = 0.015 mm/s^2, cf. Baertsch p. 33
136
+ export class GottschewskiConversion {
137
+ constructor() {
138
+ Object.defineProperty(this, "paperThickness", {
139
+ enumerable: true,
140
+ configurable: true,
141
+ writable: true,
142
+ value: 0.0075
143
+ });
144
+ Object.defineProperty(this, "initialCircumference", {
145
+ enumerable: true,
146
+ configurable: true,
147
+ writable: true,
148
+ value: 22.25
149
+ });
150
+ Object.defineProperty(this, "secondsPerTurn", {
151
+ enumerable: true,
152
+ configurable: true,
153
+ writable: true,
154
+ value: 4.64
155
+ }); // is that correct? Philips says 120 RPM (p. 113)
156
+ }
157
+ get summary() {
158
+ return `Gottschewski (assuming paper thickness: ${this.paperThickness}, initial circumference: ${this.initialCircumference}, seconds per turn: ${this.secondsPerTurn})`;
159
+ }
160
+ /**
161
+ * @param x1 in centimeters
162
+ */
163
+ placeToTime(x1) {
164
+ const Q0 = Math.pow(this.initialCircumference, 2) / (4 * Math.PI);
165
+ const v0 = this.initialCircumference / this.secondsPerTurn;
166
+ const d = Q0 / this.paperThickness;
167
+ return Math.pow(d, 0.5) * (1 / v0) * 2 * (Math.pow(d + x1, 0.5) - Math.pow(d, 0.5));
168
+ }
169
+ timeToPlace(t1) {
170
+ const Q0 = Math.pow(this.initialCircumference, 2) / (4 * Math.PI);
171
+ const v0 = this.initialCircumference / this.secondsPerTurn;
172
+ const d = Q0 / this.paperThickness;
173
+ return Math.pow((t1 * v0) / (2 * Math.pow(d, 0.5)) + Math.pow(d, 0.5), 2) - d;
174
+ }
175
+ }
@@ -0,0 +1,85 @@
1
+ import { ConditionState } from "./ConditionState";
2
+ import { AnySymbol } from "./Symbol";
3
+ import { EditorialAssumption } from "./EditorialAssumption";
4
+ import { PlaceTimeConversion } from "./PlaceTimeConversion";
5
+ import { RollFeature } from "./Feature";
6
+ /**
7
+ * This condition state is used to describe to roll's
8
+ * paper shrinkage or stretching. It might be calculated
9
+ * on the basis of comparing the vertical or horizontal
10
+ * extent with other witnesses of the same roll.
11
+ */
12
+ export interface PaperStretch extends ConditionState<'paper-stretch'> {
13
+ factor: number;
14
+ }
15
+ export interface GeneralRollCondition extends ConditionState<'general'> {
16
+ }
17
+ export type RollConditionAssignment = EditorialAssumption<'conditionAssignment', GeneralRollCondition | PaperStretch>;
18
+ export interface Shift {
19
+ horizontal: number;
20
+ vertical: number;
21
+ }
22
+ export type DateAssignment = EditorialAssumption<'dateAssignment', Date>;
23
+ export interface ProductionEvent {
24
+ company: string;
25
+ system: string;
26
+ paper: string;
27
+ date: DateAssignment;
28
+ }
29
+ export declare class RollCopy {
30
+ type: 'RollCopy';
31
+ id: string;
32
+ measurements: Partial<{
33
+ dimensions: {
34
+ width: number;
35
+ height: number;
36
+ unit: string;
37
+ };
38
+ punchDiameter: {
39
+ value: number;
40
+ unit: string;
41
+ };
42
+ holeSeparation: {
43
+ value: number;
44
+ unit: string;
45
+ };
46
+ margins: {
47
+ treble: number;
48
+ bass: number;
49
+ unit: string;
50
+ };
51
+ shift: Shift;
52
+ measuredBy: {
53
+ software: string;
54
+ version: string;
55
+ date: Date;
56
+ };
57
+ }>;
58
+ productionEvent?: ProductionEvent;
59
+ conditions: RollConditionAssignment[];
60
+ location: string;
61
+ /**
62
+ * Provides a reconstructed version of the roll,
63
+ * with shift, stretch and emendations already
64
+ * taken into account. This property will not be
65
+ * exported in the final JSON.
66
+ */
67
+ features: RollFeature[];
68
+ scan?: string;
69
+ insertFeature(feature: RollFeature): void;
70
+ setShift(shift: Shift): void;
71
+ setStretch(stretch: EditorialAssumption<'conditionAssignment', PaperStretch>): void;
72
+ shallowClone(): RollCopy;
73
+ }
74
+ export declare function asSymbols(features: RollFeature[]): AnySymbol[];
75
+ export declare function readFromStanfordAton(atonString: string, adjustByRewind?: boolean, shift?: number): RollCopy;
76
+ /**
77
+ * Spencer Chase's rolls seem to be scanned at a roll speed of
78
+ * 83 (=8.3 feet per minute).
79
+ *
80
+ * @param midiBuffer
81
+ * @param conversion
82
+ */
83
+ export declare function readFromSpencerMIDI(midiBuffer: ArrayBuffer, conversion?: PlaceTimeConversion): RollCopy;
84
+ export declare function shiftVertically(features: RollFeature[], amount: number): void;
85
+ export declare const findCopiesCarrying: (sources: RollCopy[], symbol: AnySymbol) => Set<string>;
@@ -0,0 +1,273 @@
1
+ import { AtonParser } from "./aton/AtonParser";
2
+ import { v4 } from "uuid";
3
+ import { assign, flat } from "./EditorialAssumption";
4
+ import { read } from "midifile-ts";
5
+ import { asSpans } from "./asMIDISpans";
6
+ import { KinematicConversion } from "./PlaceTimeConversion";
7
+ import { WelteT100 } from "./TrackerBar";
8
+ const applyShift = (shift, to) => {
9
+ for (const event of to) {
10
+ event.horizontal.from += shift.horizontal;
11
+ if (event.horizontal.to) {
12
+ event.horizontal.to += shift.horizontal;
13
+ }
14
+ event.vertical.from += shift.vertical;
15
+ if (event.vertical.to) {
16
+ event.vertical.to += shift.vertical;
17
+ }
18
+ }
19
+ };
20
+ const applyStretch = (stretch, to) => {
21
+ for (const event of to) {
22
+ event.horizontal.from *= stretch;
23
+ if (event.horizontal.to) {
24
+ event.horizontal.to *= stretch;
25
+ }
26
+ }
27
+ };
28
+ export class RollCopy {
29
+ constructor() {
30
+ Object.defineProperty(this, "type", {
31
+ enumerable: true,
32
+ configurable: true,
33
+ writable: true,
34
+ value: 'RollCopy'
35
+ });
36
+ Object.defineProperty(this, "id", {
37
+ enumerable: true,
38
+ configurable: true,
39
+ writable: true,
40
+ value: v4()
41
+ });
42
+ Object.defineProperty(this, "measurements", {
43
+ enumerable: true,
44
+ configurable: true,
45
+ writable: true,
46
+ value: {}
47
+ });
48
+ Object.defineProperty(this, "productionEvent", {
49
+ enumerable: true,
50
+ configurable: true,
51
+ writable: true,
52
+ value: void 0
53
+ });
54
+ Object.defineProperty(this, "conditions", {
55
+ enumerable: true,
56
+ configurable: true,
57
+ writable: true,
58
+ value: []
59
+ });
60
+ Object.defineProperty(this, "location", {
61
+ enumerable: true,
62
+ configurable: true,
63
+ writable: true,
64
+ value: ''
65
+ });
66
+ /**
67
+ * Provides a reconstructed version of the roll,
68
+ * with shift, stretch and emendations already
69
+ * taken into account. This property will not be
70
+ * exported in the final JSON.
71
+ */
72
+ Object.defineProperty(this, "features", {
73
+ enumerable: true,
74
+ configurable: true,
75
+ writable: true,
76
+ value: []
77
+ });
78
+ Object.defineProperty(this, "scan", {
79
+ enumerable: true,
80
+ configurable: true,
81
+ writable: true,
82
+ value: void 0
83
+ }); // P138i has representation => IIIF Image Link
84
+ }
85
+ insertFeature(feature) {
86
+ this.measurements.shift && applyShift(this.measurements.shift, [feature]);
87
+ const stretch = flat(this.conditions)
88
+ .find(state => state.type === 'paper-stretch');
89
+ if (stretch) {
90
+ applyStretch(stretch.factor, [feature]);
91
+ }
92
+ this.features.push(feature);
93
+ }
94
+ setShift(shift) {
95
+ this.measurements.shift = shift;
96
+ applyShift(shift, this.features);
97
+ }
98
+ setStretch(stretch) {
99
+ this.conditions.push(stretch);
100
+ applyStretch(flat(stretch).factor, this.features);
101
+ }
102
+ shallowClone() {
103
+ const copy = new RollCopy();
104
+ copy.id = this.id;
105
+ copy.measurements = { ...this.measurements };
106
+ copy.productionEvent = this.productionEvent;
107
+ copy.location = this.location;
108
+ copy.conditions = [...this.conditions];
109
+ copy.scan = this.scan;
110
+ copy.features = [...this.features];
111
+ return copy;
112
+ }
113
+ }
114
+ export function asSymbols(features) {
115
+ return features.map((feature) => {
116
+ return {
117
+ id: `symbol_${v4()}`,
118
+ ...new WelteT100().meaningOf(feature.vertical.from),
119
+ carriers: [assign('carrierAssignment', feature)]
120
+ };
121
+ });
122
+ }
123
+ export function readFromStanfordAton(atonString, adjustByRewind = true, shift = 0) {
124
+ function pixelsToMillimeters(pixels, dpi) {
125
+ return pixels / dpi * 25.4;
126
+ }
127
+ const parser = new AtonParser();
128
+ const json = parser.parse(atonString);
129
+ const holes = json.ROLLINFO.HOLES.HOLE;
130
+ const druid = json.ROLLINFO.DRUID;
131
+ const holeSeparation = parseFloat(json.ROLLINFO.HOLE_SEPARATION.replace('px'));
132
+ const hardMarginBass = parseFloat(json.ROLLINFO.HARD_MARGIN_BASS.replace('px'));
133
+ const hardMarginTreble = parseFloat(json.ROLLINFO.HARD_MARGIN_TREBLE.replace('px'));
134
+ const dpi = parseFloat(json.ROLLINFO.LENGTH_DPI.replace('ppi'));
135
+ const rollWidth = parseFloat(json.ROLLINFO.ROLL_WIDTH.replace('px')) / dpi * 25.4;
136
+ const rollHeight = parseFloat(json.ROLLINFO.IMAGE_LENGTH.replace('px')) / dpi * 25.4;
137
+ let averagePunchDiameter = -1;
138
+ const lastHole = +holes[holes.length - 1].TRACKER_HOLE;
139
+ const rewindShift = adjustByRewind ? 91 - lastHole : shift;
140
+ const copy = new RollCopy();
141
+ copy.measurements = {
142
+ dimensions: {
143
+ width: rollWidth,
144
+ height: rollHeight,
145
+ unit: 'mm'
146
+ },
147
+ punchDiameter: {
148
+ value: averagePunchDiameter,
149
+ unit: 'mm'
150
+ },
151
+ holeSeparation: {
152
+ value: holeSeparation,
153
+ unit: 'px'
154
+ },
155
+ margins: {
156
+ treble: hardMarginTreble,
157
+ bass: hardMarginBass,
158
+ unit: 'px'
159
+ },
160
+ // todo
161
+ shift: {
162
+ horizontal: 0,
163
+ vertical: 0
164
+ }
165
+ };
166
+ let circularPunches = 0;
167
+ const features = [];
168
+ for (let i = 0; i < holes.length; i++) {
169
+ const hole = holes[i];
170
+ const circularity = +hole.CIRCULARITY.replace('px', '');
171
+ if (circularity > 0.95) {
172
+ const perimeterInMM = pixelsToMillimeters(+hole.PERIMETER.replace('px', ''), dpi);
173
+ averagePunchDiameter += perimeterInMM;
174
+ circularPunches += 1;
175
+ }
176
+ if (!hole.NOTE_ATTACK || !hole.OFF_TIME)
177
+ continue;
178
+ const trackerHole = +hole.TRACKER_HOLE + rewindShift;
179
+ const noteAttack = +hole.NOTE_ATTACK.replace('px', '');
180
+ const offset = +hole.OFF_TIME.replace('px', '');
181
+ const height = offset - noteAttack;
182
+ const column = +hole.ORIGIN_COL.replace('px', '');
183
+ const columnWidth = +hole.WIDTH_COL.replace('px', '');
184
+ const annotates = `https://stacks.stanford.edu/image/iiif/${druid}/${druid}_0001/${column},${noteAttack},${columnWidth},${height}/128,/270/default.jpg`;
185
+ const feature = {
186
+ id: v4(),
187
+ annotates,
188
+ vertical: {
189
+ from: trackerHole,
190
+ unit: 'track'
191
+ },
192
+ horizontal: {
193
+ unit: 'mm',
194
+ from: pixelsToMillimeters(noteAttack, dpi),
195
+ to: pixelsToMillimeters(offset, dpi)
196
+ }
197
+ };
198
+ features.push(feature);
199
+ }
200
+ averagePunchDiameter /= circularPunches;
201
+ averagePunchDiameter /= Math.PI;
202
+ copy.scan = `https://stacks.stanford.edu/image/iiif/${druid}%2F${druid}_0001/`;
203
+ copy.features = features;
204
+ return copy;
205
+ }
206
+ /**
207
+ * Spencer Chase's rolls seem to be scanned at a roll speed of
208
+ * 83 (=8.3 feet per minute).
209
+ *
210
+ * @param midiBuffer
211
+ * @param conversion
212
+ */
213
+ export function readFromSpencerMIDI(midiBuffer, conversion = new KinematicConversion(8.3)) {
214
+ const midi = read(midiBuffer);
215
+ const features = [];
216
+ const copy = new RollCopy();
217
+ const spans = asSpans(midi);
218
+ for (const span of spans) {
219
+ const left = conversion.timeToPlace(span.onsetMs / 1000) * 10;
220
+ const right = conversion.timeToPlace(span.offsetMs / 1000) * 10;
221
+ const horizontalDimension = {
222
+ from: left,
223
+ to: right,
224
+ unit: 'mm'
225
+ };
226
+ if (span.type !== 'note')
227
+ continue;
228
+ const midiShift = 13;
229
+ let trackerHole = span.pitch - midiShift;
230
+ // for whatever reasons, the expression tracks
231
+ // of the Spencer Chase's MIDI rolls are off
232
+ // by two on the bass-side.
233
+ if (trackerHole < 10) {
234
+ trackerHole -= 2;
235
+ }
236
+ const feature = {
237
+ vertical: {
238
+ from: trackerHole,
239
+ unit: 'track'
240
+ },
241
+ horizontal: horizontalDimension,
242
+ id: v4()
243
+ };
244
+ features.push(feature);
245
+ }
246
+ copy.features = features;
247
+ return copy;
248
+ }
249
+ export function shiftVertically(features, amount) {
250
+ for (const event of features) {
251
+ event.vertical.from += amount;
252
+ try {
253
+ const newEvent = new WelteT100().meaningOf(event.vertical.from);
254
+ for (const key in newEvent) {
255
+ event[key] = newEvent[key];
256
+ }
257
+ }
258
+ catch (e) {
259
+ console.error(e);
260
+ }
261
+ }
262
+ }
263
+ export const findCopiesCarrying = (sources, symbol) => {
264
+ const result = new Set();
265
+ for (const feature of flat(symbol.carriers)) {
266
+ for (const copy of sources) {
267
+ if (copy.features.includes(feature)) {
268
+ result.add(copy.id);
269
+ }
270
+ }
271
+ }
272
+ return result;
273
+ };
@@ -0,0 +1,76 @@
1
+ import { RollMeasurement } from "./Measurement";
2
+ import { WithId } from "./WithId";
3
+ export interface HorizontalSpan {
4
+ unit: 'mm';
5
+ from: number;
6
+ to: number;
7
+ }
8
+ export interface VerticalSpan {
9
+ unit: 'track';
10
+ from: number;
11
+ to?: number;
12
+ }
13
+ export interface RollFeature<T> extends WithId {
14
+ type: T;
15
+ /**
16
+ * IIIF region in string form.
17
+ */
18
+ annotates?: string;
19
+ horizontal: HorizontalSpan;
20
+ vertical: VerticalSpan;
21
+ /**
22
+ * Describes whether the event takes place
23
+ * on the verso or recto side of the roll.
24
+ * Since the same perforation is present on both
25
+ * sides, this property is left optional for now.
26
+ */
27
+ side?: 'verso' | 'recto';
28
+ measurement: RollMeasurement;
29
+ }
30
+ export interface Note extends RollFeature<'note'> {
31
+ pitch: number;
32
+ }
33
+ export type ExpressionScope = 'bass' | 'treble';
34
+ export type ExpressionType = 'SustainPedalOn' | 'SustainPedalOff' | 'SoftPedalOn' | 'SoftPedalOff' | 'MezzoforteOff' | 'MezzoforteOn' | 'SlowCrescendoOn' | 'SlowCrescendoOff' | 'ForzandoOn' | 'ForzandoOff' | 'MotorOff' | 'MotorOn' | 'Rewind' | 'ElectricCutOff';
35
+ export interface Expression extends RollFeature<'expression'> {
36
+ scope: ExpressionScope;
37
+ expressionType: ExpressionType;
38
+ }
39
+ export declare const isRollEvent: (e: any) => e is AnyRollEvent;
40
+ export interface Perforation extends RollFeature<'perforation'> {
41
+ accelerating?: boolean;
42
+ }
43
+ /**
44
+ * This denotes perforations that are covered by an editor.
45
+ * The covered perforation is not considered to be part
46
+ * of the original note or expression hole anymore.
47
+ */
48
+ export interface Cover extends RollFeature<'cover'> {
49
+ /**
50
+ * This property can be used to indicate e.g. the
51
+ * color or material of the cover.
52
+ */
53
+ note?: string;
54
+ }
55
+ /**
56
+ * For handwritten insertions like e. g. the
57
+ * perforation date in the end of a roll.
58
+ */
59
+ export interface HandwrittenText extends RollFeature<'handwrittenText'> {
60
+ text: string;
61
+ rotation?: number;
62
+ }
63
+ /**
64
+ * This type can be used to indicate stamps like e. g. the
65
+ * "controlliert" stamp in the beginning of rolls or the
66
+ * date at the end of (later) Welte rolls.
67
+ */
68
+ export interface Stamp extends RollFeature<'stamp'> {
69
+ text: string;
70
+ rotation?: number;
71
+ }
72
+ export interface RollLabel extends RollFeature<'rollLabel'> {
73
+ text: string;
74
+ signed: boolean;
75
+ }
76
+ export type AnyRollEvent = Note | Expression | HandwrittenText | Stamp | Cover | RollLabel;
@@ -0,0 +1,3 @@
1
+ export const isRollEvent = (e) => {
2
+ return 'horizontal' in e && 'vertical' in e;
3
+ };
package/lib/Stage.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ import { ActorAssignment, Edit } from "./Edit";
2
+ import { EditorialAssumption, Motivation } from "./EditorialAssumption";
3
+ import { AnySymbol } from "./Symbol";
4
+ export interface Derivation extends EditorialAssumption<'derivation', Stage> {
5
+ }
6
+ declare const versionType: readonly ["edition", "authorised-revision", "unauthorised-revision", "gloss"];
7
+ export type VersionType = typeof versionType[number];
8
+ /**
9
+ * Stage + Stage Creation
10
+ */
11
+ export interface Stage {
12
+ id: string;
13
+ siglum: string;
14
+ actor?: ActorAssignment;
15
+ basedOn?: Derivation;
16
+ edits: Edit[];
17
+ motivations: Motivation<string>[];
18
+ type: VersionType;
19
+ }
20
+ export declare const traverseStages: (stage: Stage, callback: (stage: Stage) => void) => void;
21
+ export declare const getSnapshot: (stage: Stage) => AnySymbol[];
22
+ /**
23
+ * Walks through the stages. If it finds a symbol that is still
24
+ * part of the tradition (i.e. it is included in the current snapshot)
25
+ * and is equivalent with the given symbol, it will add the feature
26
+ * carrying the symbol to the collated symbol. Otherwise, the
27
+ * given symbol will be added to the current stage's insertions.
28
+ *
29
+ * All symbols of the tradition that are not included in the given
30
+ * symbols are considered to be deleted.
31
+ *
32
+ * @param creation
33
+ * @param symbols
34
+ * @returns
35
+ */
36
+ export declare function fillEdits(currentStage: Stage, symbols: AnySymbol[]): void;
37
+ export {};