linked-rolls 0.66.0 → 0.67.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/lib/analysis/paper.d.ts +11 -1
- package/lib/analysis/paper.js +23 -2
- package/lib/emulation/Emulation.js +59 -4
- package/lib/io/migrate.js +13 -1
- package/lib/model/Edition.d.ts +1 -8
- package/lib/model/RollCopy.d.ts +8 -5
- package/lib/schema.json +1 -101
- package/lib/spec/context.json +0 -7
- package/lib/systems/ReproducingSystem.d.ts +21 -28
- package/lib/systems/welte.d.ts +27 -6
- package/lib/systems/welte.js +33 -11
- package/lib/systems/welteLicensee/system.d.ts +10 -4
- package/lib/systems/welteLicensee/system.js +11 -5
- package/lib/systems/welteT100/system.d.ts +6 -5
- package/lib/systems/welteT100/system.js +7 -5
- package/lib/systems/welteT98/system.js +1 -0
- package/package.json +1 -1
package/lib/analysis/paper.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Edition } from "../model/Edition.js";
|
|
2
2
|
import { Strain } from "../model/RollCopy.js";
|
|
3
3
|
import { LengthRatio } from "../model/Version.js";
|
|
4
|
-
import { Percent } from "../model/Quantity.js";
|
|
4
|
+
import { MetersPerMinute, Percent } from "../model/Quantity.js";
|
|
5
5
|
/**
|
|
6
6
|
* How far the paper of one copy is taken to have stretched or shrunk
|
|
7
7
|
* along the roll, as a standard deviation, where the edition has too few
|
|
@@ -121,6 +121,16 @@ export type AlignmentProblem = {
|
|
|
121
121
|
*/
|
|
122
122
|
by?: number;
|
|
123
123
|
};
|
|
124
|
+
/**
|
|
125
|
+
* The speed the version's paper starts at, as the copies of its own system
|
|
126
|
+
* that bear witness to it at first hand state they were cut for: the mean
|
|
127
|
+
* of the speeds the edition holds true or likely. A stated speed is the
|
|
128
|
+
* speed at the beginning of the roll, as a tempo marking gives it. Nothing
|
|
129
|
+
* where no such copy states one; in particular, a copy that reaches the
|
|
130
|
+
* version only through a later one says nothing about it, since the later
|
|
131
|
+
* one may have been cut for another speed.
|
|
132
|
+
*/
|
|
133
|
+
export declare const paperSpeedOf: (edition: Edition, versionId: string) => MetersPerMinute | undefined;
|
|
124
134
|
/**
|
|
125
135
|
* Where the alignments of the edition's copies, or what they say about
|
|
126
136
|
* the paper, want looking into. None of it is recomputed, so it is cheap
|
package/lib/analysis/paper.js
CHANGED
|
@@ -4,8 +4,8 @@ import { certaintyOf, idOf, isAsserted } from "../model/Assumption.js";
|
|
|
4
4
|
import { principalDerivationOf } from "../model/Version.js";
|
|
5
5
|
import { versionIn } from "../lookup/lookup.js";
|
|
6
6
|
import { witnessesOf } from "./witnesses.js";
|
|
7
|
-
import { inMetersPerMinute, percent } from "../model/Quantity.js";
|
|
8
|
-
import { trackerBarOf } from "../systems/index.js";
|
|
7
|
+
import { inMetersPerMinute, mean, percent } from "../model/Quantity.js";
|
|
8
|
+
import { defaultTrackerBar, trackerBarOf } from "../systems/index.js";
|
|
9
9
|
/**
|
|
10
10
|
* How far the paper of one copy is taken to have stretched or shrunk
|
|
11
11
|
* along the roll, as a standard deviation, where the edition has too few
|
|
@@ -217,6 +217,27 @@ const statedSpeed = (copy) => {
|
|
|
217
217
|
const speed = copy.production?.speed;
|
|
218
218
|
return speed && isAsserted(certaintyOf(speed)) ? inMetersPerMinute(speed) : undefined;
|
|
219
219
|
};
|
|
220
|
+
/**
|
|
221
|
+
* The speed the version's paper starts at, as the copies of its own system
|
|
222
|
+
* that bear witness to it at first hand state they were cut for: the mean
|
|
223
|
+
* of the speeds the edition holds true or likely. A stated speed is the
|
|
224
|
+
* speed at the beginning of the roll, as a tempo marking gives it. Nothing
|
|
225
|
+
* where no such copy states one; in particular, a copy that reaches the
|
|
226
|
+
* version only through a later one says nothing about it, since the later
|
|
227
|
+
* one may have been cut for another speed.
|
|
228
|
+
*/
|
|
229
|
+
export const paperSpeedOf = (edition, versionId) => {
|
|
230
|
+
const version = versionIn(edition, versionId);
|
|
231
|
+
if (!version)
|
|
232
|
+
return undefined;
|
|
233
|
+
const system = (trackerBarOf(version.system) ?? defaultTrackerBar).id;
|
|
234
|
+
const speeds = witnessesOf(edition, versionId)
|
|
235
|
+
.filter(witness => witness.through === undefined)
|
|
236
|
+
.flatMap(witness => edition.copies.filter(copy => copy.id === witness.copy && barOf(copy).id === system))
|
|
237
|
+
.map(statedSpeed)
|
|
238
|
+
.filter(speed => speed !== undefined);
|
|
239
|
+
return speeds.length > 0 ? mean(speeds) : undefined;
|
|
240
|
+
};
|
|
220
241
|
/** The speed the reference copy was cut at: as stated for it, or as its system runs. */
|
|
221
242
|
const referenceSpeed = (reference) => {
|
|
222
243
|
const system = barOf(reference).paperSpeed;
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { MIDIControlEvents } from "midifile-ts";
|
|
2
|
-
import { idOf } from "../model/Assumption.js";
|
|
2
|
+
import { certaintyOf, idOf, isAsserted } from "../model/Assumption.js";
|
|
3
3
|
import { isCommand, pairsAmong, placementsOf } from "../model/Symbol.js";
|
|
4
|
+
import { principalDerivationOf } from "../model/Version.js";
|
|
4
5
|
import { add, mean, mm, seconds, subtract } from "../model/Quantity.js";
|
|
5
6
|
import { punchDiameterOf } from "../model/RollCopy.js";
|
|
6
7
|
import { toOwnPaperOf } from "../analysis/ownPaper.js";
|
|
8
|
+
import { paperSpeedOf } from "../analysis/paper.js";
|
|
9
|
+
import { defaultTrackerBar, trackerBarOf } from "../systems/index.js";
|
|
7
10
|
import { negotiatedEventOf } from "./negotiation.js";
|
|
8
11
|
import { placedCarriersOf, snapshotOf } from "../analysis/text.js";
|
|
9
|
-
import { copyOfFeature, symbolIn } from "../lookup/lookup.js";
|
|
12
|
+
import { copyOfFeature, symbolIn, versionIn } from "../lookup/lookup.js";
|
|
10
13
|
/** The punch diameter the edition's copies report, where any of them does. */
|
|
11
14
|
const meanPunchDiameterOf = (edition) => {
|
|
12
15
|
const measured = edition.copies
|
|
@@ -14,10 +17,62 @@ const meanPunchDiameterOf = (edition) => {
|
|
|
14
17
|
.filter(value => value !== undefined);
|
|
15
18
|
return measured.length > 0 ? mean(measured) : undefined;
|
|
16
19
|
};
|
|
20
|
+
/** The version this one derives from, where it names one the edition has. */
|
|
21
|
+
const baseOf = (edition, version) => {
|
|
22
|
+
const derivation = principalDerivationOf(version);
|
|
23
|
+
return derivation && versionIn(edition, idOf(derivation));
|
|
24
|
+
};
|
|
25
|
+
const onOneSystem = (one, other) => (trackerBarOf(one.system) ?? defaultTrackerBar).id === (trackerBarOf(other.system) ?? defaultTrackerBar).id;
|
|
26
|
+
/**
|
|
27
|
+
* The speed the version starts at, as far as the edition states one: as
|
|
28
|
+
* its own copies state it (`paperSpeedOf`), or else as stated for the
|
|
29
|
+
* version it derives from on the same system, whose paper it keeps.
|
|
30
|
+
*/
|
|
31
|
+
const statedSpeedOf = (edition, version, seen = new Set()) => {
|
|
32
|
+
const own = paperSpeedOf(edition, version.id);
|
|
33
|
+
if (own !== undefined || seen.has(version.id))
|
|
34
|
+
return own;
|
|
35
|
+
const base = baseOf(edition, version);
|
|
36
|
+
return base && onOneSystem(base, version)
|
|
37
|
+
? statedSpeedOf(edition, base, new Set([...seen, version.id]))
|
|
38
|
+
: undefined;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* How long the version's paper runs for a length of the paper of the
|
|
42
|
+
* version it derives from: as its creation states it where the edition
|
|
43
|
+
* holds to that, else as the papers the two are performed on relate. That
|
|
44
|
+
* is what the alignments give for the two systems (`toOwnPaperOf`), which
|
|
45
|
+
* a performance credits every version of a system with, whether or not its
|
|
46
|
+
* own copies measure the paper (cf. `lengthRatioOf`).
|
|
47
|
+
*/
|
|
48
|
+
const lengthRatioIn = (edition, version, base) => {
|
|
49
|
+
const stated = version.creation?.lengthRatio;
|
|
50
|
+
if (stated && isAsserted(certaintyOf(stated)))
|
|
51
|
+
return stated.value;
|
|
52
|
+
const own = toOwnPaperOf(edition, version);
|
|
53
|
+
const theirs = toOwnPaperOf(edition, base);
|
|
54
|
+
return own !== undefined && theirs !== undefined ? own / theirs : undefined;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The roll a re-cut was made from, as far as its timing goes: the length
|
|
58
|
+
* ratio, and the speed stated for the original. Nothing for a version that
|
|
59
|
+
* derives from none, or from one on its own system.
|
|
60
|
+
*/
|
|
61
|
+
const recutFromOf = (edition, version) => {
|
|
62
|
+
const base = baseOf(edition, version);
|
|
63
|
+
if (!base || onOneSystem(base, version))
|
|
64
|
+
return undefined;
|
|
65
|
+
const lengthRatio = lengthRatioIn(edition, version, base);
|
|
66
|
+
if (lengthRatio === undefined)
|
|
67
|
+
return undefined;
|
|
68
|
+
const paperSpeed = statedSpeedOf(edition, base);
|
|
69
|
+
return { lengthRatio, ...(paperSpeed !== undefined && { paperSpeed }) };
|
|
70
|
+
};
|
|
17
71
|
const propertiesOf = (edition, version) => ({
|
|
18
72
|
punchDiameter: meanPunchDiameterOf(edition),
|
|
19
|
-
|
|
20
|
-
|
|
73
|
+
toOwnPaper: toOwnPaperOf(edition, version),
|
|
74
|
+
paperSpeed: statedSpeedOf(edition, version),
|
|
75
|
+
recutFrom: recutFromOf(edition, version)
|
|
21
76
|
});
|
|
22
77
|
/** The onset a symbol has on each copy carrying it, by the copy's id, as the mean of its chains there. */
|
|
23
78
|
const onsetsByCopy = (edition, symbolId) => {
|
package/lib/io/migrate.js
CHANGED
|
@@ -644,6 +644,18 @@ const withoutFormatVersion = (edition) => {
|
|
|
644
644
|
const { formatVersion: _stated, ...rest } = edition;
|
|
645
645
|
return rest;
|
|
646
646
|
};
|
|
647
|
+
/**
|
|
648
|
+
* An edition once stated one tempo for the roll, which cannot hold where the
|
|
649
|
+
* roll was issued for systems whose papers run at different speeds. A copy
|
|
650
|
+
* states the speed it was cut for, and a re-cut's follows from its original's
|
|
651
|
+
* and the length ratio, so the edition's goes.
|
|
652
|
+
*/
|
|
653
|
+
const withoutTempoAdjustment = (edition) => {
|
|
654
|
+
if (!Object.hasOwn(edition, 'tempoAdjustment'))
|
|
655
|
+
return edition;
|
|
656
|
+
const { tempoAdjustment: _stated, ...rest } = edition;
|
|
657
|
+
return rest;
|
|
658
|
+
};
|
|
647
659
|
/** Whether the copy states features, in either shape. */
|
|
648
660
|
const hasFeatures = (copy) => [copy?.features, copy?.production?.produced, copy?.productionEvent?.produced]
|
|
649
661
|
.some(features => Array.isArray(features) && features.length > 0);
|
|
@@ -664,5 +676,5 @@ const withReferenceCopy = (edition) => {
|
|
|
664
676
|
? { ...edition, referenceCopy: plainCopyId(reference['@id']) }
|
|
665
677
|
: edition;
|
|
666
678
|
};
|
|
667
|
-
const editionSteps = [withoutFormatVersion, withoutEditionType, withSystems, withEditors, withDerivationTolerance, withReferenceCopy];
|
|
679
|
+
const editionSteps = [withoutFormatVersion, withoutTempoAdjustment, withoutEditionType, withSystems, withEditors, withDerivationTolerance, withReferenceCopy];
|
|
668
680
|
export const migrate = (edition) => walk(editionSteps.reduce((result, step) => step(result), edition));
|
package/lib/model/Edition.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { RollCopy } from "./RollCopy.js";
|
|
2
2
|
import { Version } from "./Version.js";
|
|
3
|
-
import { DateAssignment
|
|
3
|
+
import { DateAssignment } from "./Assumption.js";
|
|
4
4
|
import { Editor, Person, Place } from "./Agent.js";
|
|
5
|
-
import { RollTempo } from "../systems/ReproducingSystem.js";
|
|
6
5
|
/**
|
|
7
6
|
* This type describes the creation of an edition,
|
|
8
7
|
* i.e. the editor, publisher, and publication date.
|
|
@@ -145,12 +144,6 @@ export interface Edition {
|
|
|
145
144
|
* @see lrmoo:R75 incorporates
|
|
146
145
|
*/
|
|
147
146
|
versions: Version[];
|
|
148
|
-
/**
|
|
149
|
-
* An optional tempo adjustment for playback of the roll,
|
|
150
|
-
* annotatable with a belief about its correctness.
|
|
151
|
-
* @see reo:tempo
|
|
152
|
-
*/
|
|
153
|
-
tempoAdjustment?: ObjectAssumption<RollTempo>;
|
|
154
147
|
}
|
|
155
148
|
export type EditionMetadata = Pick<Edition, 'base' | 'title' | 'license' | 'creation' | 'roll'>;
|
|
156
149
|
/**
|
package/lib/model/RollCopy.d.ts
CHANGED
|
@@ -231,11 +231,14 @@ export interface ProductionEvent {
|
|
|
231
231
|
*/
|
|
232
232
|
system?: Concept;
|
|
233
233
|
/**
|
|
234
|
-
* The paper speed the copy was cut for
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
234
|
+
* The paper speed the copy was cut for, as the speed at the
|
|
235
|
+
* beginning of the roll: a tempo marking states it so, and the
|
|
236
|
+
* take-up spool accelerates from there. A performance of a version
|
|
237
|
+
* the copy bears witness to starts at it (`paperSpeedOf`). A copy cut
|
|
238
|
+
* from the same master for another speed comes out longer or shorter
|
|
239
|
+
* than the roll it is aligned with by the ratio of the speeds. The
|
|
240
|
+
* alignment measures that ratio far more closely than a label states
|
|
241
|
+
* a speed, so the speed is held against what the alignments give
|
|
239
242
|
* (`alignmentProblems`) rather than used to find it.
|
|
240
243
|
* @see reo:paperSpeed
|
|
241
244
|
*/
|
package/lib/schema.json
CHANGED
|
@@ -609,11 +609,6 @@
|
|
|
609
609
|
"description": "The roll which is edited in this edition.",
|
|
610
610
|
"ontology": "lrmoo:R3i realises"
|
|
611
611
|
},
|
|
612
|
-
"tempoAdjustment": {
|
|
613
|
-
"$ref": "#/definitions/ObjectAssumption%3CRollTempo%3E",
|
|
614
|
-
"description": "An optional tempo adjustment for playback of the roll, annotatable with a belief about its correctness.",
|
|
615
|
-
"ontology": "reo:tempo"
|
|
616
|
-
},
|
|
617
612
|
"title": {
|
|
618
613
|
"description": "The title of the edition.",
|
|
619
614
|
"examples": [
|
|
@@ -2815,101 +2810,6 @@
|
|
|
2815
2810
|
],
|
|
2816
2811
|
"type": "object"
|
|
2817
2812
|
},
|
|
2818
|
-
"ObjectAssumption<RollTempo>": {
|
|
2819
|
-
"anyOf": [
|
|
2820
|
-
{
|
|
2821
|
-
"properties": {
|
|
2822
|
-
"@annotation": {
|
|
2823
|
-
"description": "An optional annotation expressing a belief about this assumption. Uses the JSON-LD-star `@annotation` mechanism to attach epistemic metadata (certainty and reasons) to any triple.",
|
|
2824
|
-
"properties": {
|
|
2825
|
-
"belief": {
|
|
2826
|
-
"$ref": "#/definitions/Belief",
|
|
2827
|
-
"description": "The belief held about the annotated statement.",
|
|
2828
|
-
"ontology": "crminf:J4i is subject of"
|
|
2829
|
-
},
|
|
2830
|
-
"@id": {
|
|
2831
|
-
"description": "A unique identifier for this object.",
|
|
2832
|
-
"type": "string"
|
|
2833
|
-
}
|
|
2834
|
-
},
|
|
2835
|
-
"required": [
|
|
2836
|
-
"belief",
|
|
2837
|
-
"@id"
|
|
2838
|
-
],
|
|
2839
|
-
"type": "object"
|
|
2840
|
-
},
|
|
2841
|
-
"endsWith": {
|
|
2842
|
-
"$ref": "#/definitions/Quantity%3C%22ft%2Fmin%22%3E",
|
|
2843
|
-
"description": "The tempo at the end of the roll.",
|
|
2844
|
-
"ontology": "reo:to"
|
|
2845
|
-
},
|
|
2846
|
-
"startsWith": {
|
|
2847
|
-
"$ref": "#/definitions/Quantity%3C%22ft%2Fmin%22%3E",
|
|
2848
|
-
"description": "The tempo at the beginning of the roll.",
|
|
2849
|
-
"ontology": "reo:from"
|
|
2850
|
-
},
|
|
2851
|
-
"unit": {
|
|
2852
|
-
"const": "ft/min",
|
|
2853
|
-
"description": "The unit of the tempo measurement.",
|
|
2854
|
-
"type": "string",
|
|
2855
|
-
"ontology": "crm:P91 has unit"
|
|
2856
|
-
}
|
|
2857
|
-
},
|
|
2858
|
-
"required": [
|
|
2859
|
-
"endsWith",
|
|
2860
|
-
"startsWith",
|
|
2861
|
-
"unit"
|
|
2862
|
-
],
|
|
2863
|
-
"type": "object"
|
|
2864
|
-
},
|
|
2865
|
-
{
|
|
2866
|
-
"properties": {
|
|
2867
|
-
"@annotation": {
|
|
2868
|
-
"description": "An optional annotation expressing a belief about this assumption. Uses the JSON-LD-star `@annotation` mechanism to attach epistemic metadata (certainty and reasons) to any triple.",
|
|
2869
|
-
"properties": {
|
|
2870
|
-
"belief": {
|
|
2871
|
-
"$ref": "#/definitions/Belief",
|
|
2872
|
-
"description": "The belief held about the annotated statement.",
|
|
2873
|
-
"ontology": "crminf:J4i is subject of"
|
|
2874
|
-
},
|
|
2875
|
-
"@id": {
|
|
2876
|
-
"description": "A unique identifier for this object.",
|
|
2877
|
-
"type": "string"
|
|
2878
|
-
}
|
|
2879
|
-
},
|
|
2880
|
-
"required": [
|
|
2881
|
-
"belief",
|
|
2882
|
-
"@id"
|
|
2883
|
-
],
|
|
2884
|
-
"type": "object"
|
|
2885
|
-
},
|
|
2886
|
-
"endsWith": {
|
|
2887
|
-
"$ref": "#/definitions/Quantity%3C%22m%2Fmin%22%3E",
|
|
2888
|
-
"description": "The tempo at the end of the roll.",
|
|
2889
|
-
"ontology": "reo:to"
|
|
2890
|
-
},
|
|
2891
|
-
"startsWith": {
|
|
2892
|
-
"$ref": "#/definitions/Quantity%3C%22m%2Fmin%22%3E",
|
|
2893
|
-
"description": "The tempo at the beginning of the roll.",
|
|
2894
|
-
"ontology": "reo:from"
|
|
2895
|
-
},
|
|
2896
|
-
"unit": {
|
|
2897
|
-
"const": "m/min",
|
|
2898
|
-
"description": "The unit of the tempo measurement.",
|
|
2899
|
-
"type": "string",
|
|
2900
|
-
"ontology": "crm:P91 has unit"
|
|
2901
|
-
}
|
|
2902
|
-
},
|
|
2903
|
-
"required": [
|
|
2904
|
-
"endsWith",
|
|
2905
|
-
"startsWith",
|
|
2906
|
-
"unit"
|
|
2907
|
-
],
|
|
2908
|
-
"type": "object"
|
|
2909
|
-
}
|
|
2910
|
-
],
|
|
2911
|
-
"description": "An object assumption wraps a complex object with an optional annotation. Used for structured values (e.g. persons, conditions) whose properties may be uncertain."
|
|
2912
|
-
},
|
|
2913
2813
|
"ObjectAssumption<Transcription>": {
|
|
2914
2814
|
"description": "An object assumption wraps a complex object with an optional annotation. Used for structured values (e.g. persons, conditions) whose properties may be uncertain.",
|
|
2915
2815
|
"properties": {
|
|
@@ -3165,7 +3065,7 @@
|
|
|
3165
3065
|
},
|
|
3166
3066
|
"speed": {
|
|
3167
3067
|
"$ref": "#/definitions/ObjectAssumption%3CPaperSpeed%3E",
|
|
3168
|
-
"description": "The paper speed the copy was cut for. A copy cut from the same master for another speed comes out longer or shorter than the roll it is aligned with by the ratio of the speeds. The alignment measures that ratio far more closely than a label states a speed, so the speed is held against what the alignments give (`alignmentProblems`) rather than used to find it.",
|
|
3068
|
+
"description": "The paper speed the copy was cut for, as the speed at the beginning of the roll: a tempo marking states it so, and the take-up spool accelerates from there. A performance of a version the copy bears witness to starts at it (`paperSpeedOf`). A copy cut from the same master for another speed comes out longer or shorter than the roll it is aligned with by the ratio of the speeds. The alignment measures that ratio far more closely than a label states a speed, so the speed is held against what the alignments give (`alignmentProblems`) rather than used to find it.",
|
|
3169
3069
|
"ontology": "reo:paperSpeed"
|
|
3170
3070
|
},
|
|
3171
3071
|
"system": {
|
package/lib/spec/context.json
CHANGED
|
@@ -150,13 +150,6 @@
|
|
|
150
150
|
"created": "lrmoo:R17_created",
|
|
151
151
|
"copies": "reo:witness",
|
|
152
152
|
"versions": "lrmoo:R75_incorporates",
|
|
153
|
-
"tempoAdjustment": {
|
|
154
|
-
"@id": "reo:tempo",
|
|
155
|
-
"@context": {
|
|
156
|
-
"startsWith": "reo:from",
|
|
157
|
-
"endsWith": "reo:to"
|
|
158
|
-
}
|
|
159
|
-
},
|
|
160
153
|
"name": "rdfs:label",
|
|
161
154
|
"sameAs": {
|
|
162
155
|
"@id": "owl:sameAs",
|
|
@@ -1,32 +1,7 @@
|
|
|
1
1
|
import { HoleChain } from "../model/Feature.js";
|
|
2
2
|
import { Expression, Note } from "../model/Symbol.js";
|
|
3
3
|
import { TrackerBar } from "./TrackerBar.js";
|
|
4
|
-
import {
|
|
5
|
-
export type SpeedUnit = 'ft/min' | 'm/min';
|
|
6
|
-
/**
|
|
7
|
-
* The playback tempo of the roll as a paper speed, stated at the
|
|
8
|
-
* beginning and at the end, since the speed may change over the
|
|
9
|
-
* course of the roll through acceleration.
|
|
10
|
-
* @see crm:E54 Dimension
|
|
11
|
-
*/
|
|
12
|
-
export interface RollTempoIn<U extends SpeedUnit> {
|
|
13
|
-
/**
|
|
14
|
-
* The tempo at the beginning of the roll.
|
|
15
|
-
* @see reo:from
|
|
16
|
-
*/
|
|
17
|
-
startsWith: Quantity<U>;
|
|
18
|
-
/**
|
|
19
|
-
* The tempo at the end of the roll.
|
|
20
|
-
* @see reo:to
|
|
21
|
-
*/
|
|
22
|
-
endsWith: Quantity<U>;
|
|
23
|
-
/**
|
|
24
|
-
* The unit of the tempo measurement.
|
|
25
|
-
* @see crm:P91 has unit
|
|
26
|
-
*/
|
|
27
|
-
unit: U;
|
|
28
|
-
}
|
|
29
|
-
export type RollTempo = RollTempoIn<'ft/min'> | RollTempoIn<'m/min'>;
|
|
4
|
+
import { MetersPerMinute, Millimeters, Seconds } from "../model/Quantity.js";
|
|
30
5
|
/**
|
|
31
6
|
* A note or expression of a version with the dimensions of its carriers
|
|
32
7
|
* averaged in and the editorial assumptions applied, which is all a
|
|
@@ -99,8 +74,26 @@ export type EmulatedCurve = DynamicsCurve | PedalCurve;
|
|
|
99
74
|
export type RollProperties = {
|
|
100
75
|
/** Diameter of the punches, where the copies record it. */
|
|
101
76
|
punchDiameter?: Millimeters;
|
|
102
|
-
/**
|
|
103
|
-
|
|
77
|
+
/**
|
|
78
|
+
* The speed the version's paper starts at, where the copies that bear
|
|
79
|
+
* witness to it state the speed they were cut for (`paperSpeedOf`), or
|
|
80
|
+
* failing them those of the version it derives from on the same
|
|
81
|
+
* system, whose paper it keeps. A stated speed is the speed at the
|
|
82
|
+
* beginning of the roll, as a tempo marking gives it, and the spool
|
|
83
|
+
* accelerates from there.
|
|
84
|
+
*/
|
|
85
|
+
paperSpeed?: MetersPerMinute;
|
|
86
|
+
/**
|
|
87
|
+
* Where the version is a re-cut for another system: how long its paper
|
|
88
|
+
* runs for a length of the paper of the version it derives from, and
|
|
89
|
+
* the speed stated for that version, if any. A system with no spool of
|
|
90
|
+
* its own times such a version by these, so that it sounds at the
|
|
91
|
+
* tempo of the roll it was re-cut from.
|
|
92
|
+
*/
|
|
93
|
+
recutFrom?: {
|
|
94
|
+
readonly lengthRatio: number;
|
|
95
|
+
readonly paperSpeed?: MetersPerMinute;
|
|
96
|
+
};
|
|
104
97
|
/**
|
|
105
98
|
* Place on the edition's shared axis × this = millimetres of the version's
|
|
106
99
|
* own paper, unstretched. About 0.775 for a green issue of a red
|
package/lib/systems/welte.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Grid, Half, Model, ModelInput, Parameters, PedalInput, PedalMode, PedalTravel, PortGeometry, Spool } from "welte-mignon-emulator";
|
|
2
2
|
import { Expression } from "../model/Symbol.js";
|
|
3
3
|
import { NegotiatedEvent, Performance, RollProperties } from "./ReproducingSystem.js";
|
|
4
|
-
import { Millimeters, Seconds, Track } from "../model/Quantity.js";
|
|
4
|
+
import { MetersPerMinute, Millimeters, Seconds, Track } from "../model/Quantity.js";
|
|
5
5
|
import { type VelocityMap } from "./velocity.js";
|
|
6
6
|
/**
|
|
7
7
|
* What the Welte systems share downstream of the relay. Hagmann has the
|
|
@@ -15,6 +15,9 @@ export type WelteOptions = {
|
|
|
15
15
|
/**
|
|
16
16
|
* The take-up spool, which sets the time axis: it is held at a constant
|
|
17
17
|
* rate of revolution, so the paper runs faster as the spool fills.
|
|
18
|
+
* Where a speed is stated for the version's copies, or a re-cut is timed
|
|
19
|
+
* by the roll it was made from, the spool is started at that speed and
|
|
20
|
+
* only its geometry is taken from here; see `spoolFor`.
|
|
18
21
|
*/
|
|
19
22
|
spool: Spool;
|
|
20
23
|
/** Constants of the nuancing mechanism, one set for each half of the keyboard. */
|
|
@@ -79,6 +82,21 @@ export type Paper = {
|
|
|
79
82
|
};
|
|
80
83
|
/** When the spool brings a place on the roll to the tracker bar. */
|
|
81
84
|
export declare const secondsAt: (spool: Spool, place: Millimeters) => Seconds;
|
|
85
|
+
/** The speed the spool starts the paper at. */
|
|
86
|
+
export declare const startingSpeedOf: (spool: Spool) => MetersPerMinute;
|
|
87
|
+
/**
|
|
88
|
+
* The spool a version runs on.
|
|
89
|
+
*
|
|
90
|
+
* A speed stated for the version's copies is where it starts, as a tempo
|
|
91
|
+
* marking is the speed at the beginning of the roll. Failing that, a system
|
|
92
|
+
* whose spool is a reading of its own instruments runs on it as it stands:
|
|
93
|
+
* the red and the green spool are both calibrated at Welte's Tempo 70. A
|
|
94
|
+
* system with no spool of its own, as the Licensee has none, times a re-cut
|
|
95
|
+
* by the roll it was re-cut from, at that roll's stated speed or else the
|
|
96
|
+
* spool's own, shortened by the length ratio, so that it sounds at the tempo
|
|
97
|
+
* of the original. Where none of this applies the spool stands as given.
|
|
98
|
+
*/
|
|
99
|
+
export declare const spoolFor: (spool: Spool, roll: RollProperties, ownSpool: boolean) => Spool;
|
|
82
100
|
/** A perforation as the emulator reads it: the control it operates and the rows it spans. */
|
|
83
101
|
export type WeltePunch = {
|
|
84
102
|
readonly half: Half;
|
|
@@ -101,6 +119,12 @@ export type Mechanism<P extends WeltePunch> = {
|
|
|
101
119
|
readonly portsOf: (grid: Grid, punches: readonly P[], geometry: PortGeometry) => Ports;
|
|
102
120
|
readonly model: Model;
|
|
103
121
|
readonly runPedals: (input: PedalInput, params: Parameters) => PedalTravel;
|
|
122
|
+
/**
|
|
123
|
+
* Whether the spool in the options is a reading of this system's own
|
|
124
|
+
* instruments. Where it is not, a re-cut is timed by the roll it was
|
|
125
|
+
* re-cut from (`spoolFor`).
|
|
126
|
+
*/
|
|
127
|
+
readonly ownSpool: boolean;
|
|
104
128
|
/** The name of the instrument the curves say they came from. */
|
|
105
129
|
readonly instrument: string;
|
|
106
130
|
};
|
|
@@ -111,10 +135,7 @@ export type WeltePerformance = Performance & {
|
|
|
111
135
|
};
|
|
112
136
|
/**
|
|
113
137
|
* Plays the events on a Welte mechanism: notes at the velocity of their half's
|
|
114
|
-
* bellows, and the two pedals as the travel of theirs
|
|
115
|
-
*
|
|
116
|
-
* The edition's tempo adjustment is left aside: it is stated as a paper
|
|
117
|
-
* speed, and what the spool holds constant is its rate of revolution, so
|
|
118
|
-
* the two are not the same quantity. The spool in the options sets the speed.
|
|
138
|
+
* bellows, and the two pedals as the travel of theirs, on the spool
|
|
139
|
+
* `spoolFor` gives the version.
|
|
119
140
|
*/
|
|
120
141
|
export declare const performWelte: <P extends WeltePunch>(events: readonly NegotiatedEvent[], options: WelteOptions, roll: RollProperties, mechanism: Mechanism<P>) => WeltePerformance;
|
package/lib/systems/welte.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { clamp, geometryInMm, Grid, levelChanges, mezzoforteTravel, paperSeconds, pedalBrushing, pedalDefaults, ROWS_PER_MM, travelBetweenRails, } from "welte-mignon-emulator";
|
|
2
|
-
import { inCentimeters, mm, seconds } from "../model/Quantity.js";
|
|
1
|
+
import { clamp, geometryInMm, Grid, levelChanges, mezzoforteTravel, paperSeconds, paperSpeed, pedalBrushing, pedalDefaults, ROWS_PER_MM, travelBetweenRails, } from "welte-mignon-emulator";
|
|
2
|
+
import { inCentimeters, metersPerMinute, mm, seconds } from "../model/Quantity.js";
|
|
3
3
|
import { partitionPoint } from "../shared/sorted.js";
|
|
4
4
|
import { velocityOf } from "./velocity.js";
|
|
5
5
|
/** Whether two sets of constants are the same, value for value. */
|
|
@@ -33,6 +33,30 @@ const paperOf = (toOwnPaper) => ({
|
|
|
33
33
|
});
|
|
34
34
|
/** When the spool brings a place on the roll to the tracker bar. */
|
|
35
35
|
export const secondsAt = (spool, place) => seconds(paperSeconds(spool, inCentimeters(place)));
|
|
36
|
+
/** The speed the spool starts the paper at. */
|
|
37
|
+
export const startingSpeedOf = (spool) => metersPerMinute(paperSpeed(spool, 0) * 60 / 100);
|
|
38
|
+
/** The spool turned so that it starts the paper at the speed, its geometry and acceleration kept. */
|
|
39
|
+
const startingAt = (spool, speed) => ({ ...spool, revolutionSeconds: spool.circumferenceCm / (speed * 100 / 60) });
|
|
40
|
+
/**
|
|
41
|
+
* The spool a version runs on.
|
|
42
|
+
*
|
|
43
|
+
* A speed stated for the version's copies is where it starts, as a tempo
|
|
44
|
+
* marking is the speed at the beginning of the roll. Failing that, a system
|
|
45
|
+
* whose spool is a reading of its own instruments runs on it as it stands:
|
|
46
|
+
* the red and the green spool are both calibrated at Welte's Tempo 70. A
|
|
47
|
+
* system with no spool of its own, as the Licensee has none, times a re-cut
|
|
48
|
+
* by the roll it was re-cut from, at that roll's stated speed or else the
|
|
49
|
+
* spool's own, shortened by the length ratio, so that it sounds at the tempo
|
|
50
|
+
* of the original. Where none of this applies the spool stands as given.
|
|
51
|
+
*/
|
|
52
|
+
export const spoolFor = (spool, roll, ownSpool) => {
|
|
53
|
+
if (roll.paperSpeed !== undefined)
|
|
54
|
+
return startingAt(spool, roll.paperSpeed);
|
|
55
|
+
if (ownSpool || !roll.recutFrom)
|
|
56
|
+
return spool;
|
|
57
|
+
const { lengthRatio, paperSpeed: original = startingSpeedOf(spool) } = roll.recutFrom;
|
|
58
|
+
return startingAt(spool, metersPerMinute(original * lengthRatio));
|
|
59
|
+
};
|
|
36
60
|
const halfOf = (note, division) => note.vertical.from >= division ? 'treble' : 'bass';
|
|
37
61
|
/**
|
|
38
62
|
* One sample per row of the scan the constants were fitted on, from the
|
|
@@ -63,12 +87,12 @@ const nuanceCurves = (grid, ports, samples, options, model, instrument) => {
|
|
|
63
87
|
};
|
|
64
88
|
return { bass: curveOf('bass'), treble: curveOf('treble') };
|
|
65
89
|
};
|
|
66
|
-
const performNotes = (events, grid, nuance, options, paper) => events
|
|
90
|
+
const performNotes = (events, grid, nuance, options, paper, spool) => events
|
|
67
91
|
.filter(isNote)
|
|
68
92
|
.flatMap((note) => {
|
|
69
93
|
const curve = nuance[halfOf(note, options.division)];
|
|
70
94
|
const velocity = curve.velocity[grid.indexOfRow(paper.rowOf(note.horizontal.from))];
|
|
71
|
-
const at = (place) => secondsAt(
|
|
95
|
+
const at = (place) => secondsAt(spool, paper.paperOfPlace(place));
|
|
72
96
|
return [
|
|
73
97
|
{ type: 'noteOn', performs: note, pitch: note.pitch, velocity, at: at(note.horizontal.from) },
|
|
74
98
|
{ type: 'noteOff', performs: note, pitch: note.pitch, velocity: 127, at: at(note.horizontal.to) }
|
|
@@ -95,11 +119,8 @@ const performPedal = (type, curve, grid, readings, mode) => {
|
|
|
95
119
|
};
|
|
96
120
|
/**
|
|
97
121
|
* Plays the events on a Welte mechanism: notes at the velocity of their half's
|
|
98
|
-
* bellows, and the two pedals as the travel of theirs
|
|
99
|
-
*
|
|
100
|
-
* The edition's tempo adjustment is left aside: it is stated as a paper
|
|
101
|
-
* speed, and what the spool holds constant is its rate of revolution, so
|
|
102
|
-
* the two are not the same quantity. The spool in the options sets the speed.
|
|
122
|
+
* bellows, and the two pedals as the travel of theirs, on the spool
|
|
123
|
+
* `spoolFor` gives the version.
|
|
103
124
|
*/
|
|
104
125
|
export const performWelte = (events, options, roll, mechanism) => {
|
|
105
126
|
const paper = paperOf(roll.toOwnPaper ?? 1);
|
|
@@ -112,7 +133,8 @@ export const performWelte = (events, options, roll, mechanism) => {
|
|
|
112
133
|
});
|
|
113
134
|
return punch ? [{ event, punch }] : [];
|
|
114
135
|
});
|
|
115
|
-
const
|
|
136
|
+
const spool = spoolFor(options.spool, roll, mechanism.ownSpool);
|
|
137
|
+
const grid = gridOver(events, spool, paper);
|
|
116
138
|
const geometry = geometryInMm(roll.punchDiameter ?? options.punchDiameter, options.trackerBore);
|
|
117
139
|
const ports = mechanism.portsOf(grid, readings.map(reading => reading.punch), geometry);
|
|
118
140
|
const samples = {
|
|
@@ -128,7 +150,7 @@ export const performWelte = (events, options, roll, mechanism) => {
|
|
|
128
150
|
grid,
|
|
129
151
|
ports,
|
|
130
152
|
events: [
|
|
131
|
-
...performNotes(events, grid, nuance, options, paper),
|
|
153
|
+
...performNotes(events, grid, nuance, options, paper, spool),
|
|
132
154
|
...performPedal('damper', damper, grid, readingsOf('sustainPedal'), options.pedalMode),
|
|
133
155
|
...performPedal('hammerRail', hammerRail, grid, readingsOf('hammerRail'), options.pedalMode)
|
|
134
156
|
],
|
|
@@ -27,9 +27,13 @@ export declare const instrumentNames: readonly WelteLicenseeInstrumentName[];
|
|
|
27
27
|
* Welte's own spool is carried over with the constants. Phillips (p. 181) says
|
|
28
28
|
* Licensee rolls "play at a range of paper speeds", so there is no one figure
|
|
29
29
|
* to put here and the red geometry is a placeholder rather than a reading.
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* It is therefore never played as it stands where anything better is known:
|
|
31
|
+
* a speed stated for the version's copies, as a Licensee label states its
|
|
32
|
+
* tempo, sets where it starts, and failing that a re-cut runs at the speed of
|
|
33
|
+
* the roll it was re-cut from times the length ratio, so that it sounds at
|
|
34
|
+
* that roll's tempo (`spoolFor`). Either way only its geometry is used, and
|
|
35
|
+
* that is better varied than trusted: it scales every conductance by k and
|
|
36
|
+
* every time constant by 1/k, and touches nothing dimensionless.
|
|
33
37
|
*/
|
|
34
38
|
export declare const defaultWelteLicenseeOptions: WelteLicenseeOptions;
|
|
35
39
|
/**
|
|
@@ -41,6 +45,8 @@ export declare const defaultWelteLicenseeOptions: WelteLicenseeOptions;
|
|
|
41
45
|
* What it does not have is an instrument of its own. The constants are the
|
|
42
46
|
* T-100's, the spool is the T-100's, and neither has ever been checked against
|
|
43
47
|
* a Licensee. `instruments` therefore offers a single `unfitted` arm, and every
|
|
44
|
-
* curve produced here names itself as such.
|
|
48
|
+
* curve produced here names itself as such. The spool sets no tempo of its
|
|
49
|
+
* own: a version runs at the speed stated for its copies, or at that of the
|
|
50
|
+
* roll it was re-cut from times the length ratio.
|
|
45
51
|
*/
|
|
46
52
|
export declare const welteLicenseeSystem: ReproducingSystem<WelteLicenseeOptions>;
|
|
@@ -23,9 +23,13 @@ export const instrumentNames = [
|
|
|
23
23
|
* Welte's own spool is carried over with the constants. Phillips (p. 181) says
|
|
24
24
|
* Licensee rolls "play at a range of paper speeds", so there is no one figure
|
|
25
25
|
* to put here and the red geometry is a placeholder rather than a reading.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* It is therefore never played as it stands where anything better is known:
|
|
27
|
+
* a speed stated for the version's copies, as a Licensee label states its
|
|
28
|
+
* tempo, sets where it starts, and failing that a re-cut runs at the speed of
|
|
29
|
+
* the roll it was re-cut from times the length ratio, so that it sounds at
|
|
30
|
+
* that roll's tempo (`spoolFor`). Either way only its geometry is used, and
|
|
31
|
+
* that is better varied than trusted: it scales every conductance by k and
|
|
32
|
+
* every time constant by 1/k, and touches nothing dimensionless.
|
|
29
33
|
*/
|
|
30
34
|
export const defaultWelteLicenseeOptions = {
|
|
31
35
|
...defaultWelteT100Options,
|
|
@@ -50,11 +54,13 @@ const licenseeInstrument = (nuance) => instrumentNameOf(nuance) === 'consensus'
|
|
|
50
54
|
* What it does not have is an instrument of its own. The constants are the
|
|
51
55
|
* T-100's, the spool is the T-100's, and neither has ever been checked against
|
|
52
56
|
* a Licensee. `instruments` therefore offers a single `unfitted` arm, and every
|
|
53
|
-
* curve produced here names itself as such.
|
|
57
|
+
* curve produced here names itself as such. The spool sets no tempo of its
|
|
58
|
+
* own: a version runs at the speed stated for its copies, or at that of the
|
|
59
|
+
* roll it was re-cut from times the length ratio.
|
|
54
60
|
*/
|
|
55
61
|
export const welteLicenseeSystem = {
|
|
56
62
|
name: 'Welte-Mignon (Licensee)',
|
|
57
63
|
trackerBar: welteLicensee,
|
|
58
64
|
defaultOptions: defaultWelteLicenseeOptions,
|
|
59
|
-
perform: performAs(licenseeInstrument)
|
|
65
|
+
perform: performAs(licenseeInstrument, false)
|
|
60
66
|
};
|
|
@@ -24,12 +24,13 @@ export type WelteT100Options = WelteOptions;
|
|
|
24
24
|
export declare const defaultWelteT100Options: WelteT100Options;
|
|
25
25
|
/**
|
|
26
26
|
* The mechanism, given a way of naming the instrument on the curves it
|
|
27
|
-
* produces
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* curve has to say
|
|
27
|
+
* produces and whether the spool it is given is that instrument's own. The
|
|
28
|
+
* Licensee reads the same commands and is played by the same valves, so it
|
|
29
|
+
* shares this; what it may not share is the name, since a Licensee playback
|
|
30
|
+
* runs on constants fitted to Freiburg instruments and the curve has to say
|
|
31
|
+
* so, nor the spool, which is the red one it carries over.
|
|
31
32
|
*/
|
|
32
|
-
export declare const performAs: (instrumentOf: (nuance: Record<Half, Parameters>) => string) => (events: readonly NegotiatedEvent[], options: WelteT100Options, roll: RollProperties) => Performance;
|
|
33
|
+
export declare const performAs: (instrumentOf: (nuance: Record<Half, Parameters>) => string, ownSpool?: boolean) => (events: readonly NegotiatedEvent[], options: WelteT100Options, roll: RollProperties) => Performance;
|
|
33
34
|
/**
|
|
34
35
|
* The red Welte, as welte-mignon-emulator models it: the take-up spool sets
|
|
35
36
|
* the time axis, the Nuancierbälge fill through their conduits and are
|
|
@@ -55,17 +55,19 @@ const punchOf = (event, rows) => {
|
|
|
55
55
|
};
|
|
56
56
|
/**
|
|
57
57
|
* The mechanism, given a way of naming the instrument on the curves it
|
|
58
|
-
* produces
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* curve has to say
|
|
58
|
+
* produces and whether the spool it is given is that instrument's own. The
|
|
59
|
+
* Licensee reads the same commands and is played by the same valves, so it
|
|
60
|
+
* shares this; what it may not share is the name, since a Licensee playback
|
|
61
|
+
* runs on constants fitted to Freiburg instruments and the curve has to say
|
|
62
|
+
* so, nor the spool, which is the red one it carries over.
|
|
62
63
|
*/
|
|
63
|
-
export const performAs = (instrumentOf) => (events, options, roll) => {
|
|
64
|
+
export const performAs = (instrumentOf, ownSpool = true) => (events, options, roll) => {
|
|
64
65
|
const { events: performed, curves } = performWelte(events, options, roll, {
|
|
65
66
|
punchOf,
|
|
66
67
|
portsOf: aperturePorts,
|
|
67
68
|
model: pneumaticModel,
|
|
68
69
|
runPedals,
|
|
70
|
+
ownSpool,
|
|
69
71
|
instrument: instrumentOf(options.nuance)
|
|
70
72
|
});
|
|
71
73
|
return { events: performed, curves };
|
|
@@ -110,6 +110,7 @@ const perform = (events, options, roll) => {
|
|
|
110
110
|
portsOf: (grid, punches, geometry) => aperturePorts(grid, punches, geometry, gap),
|
|
111
111
|
model: pneumaticT98Model,
|
|
112
112
|
runPedals,
|
|
113
|
+
ownSpool: true,
|
|
113
114
|
instrument: `Welte-Mignon T-98, ${labelOf(options.instrument)}`
|
|
114
115
|
});
|
|
115
116
|
const stops = rewindRow(grid, ports, options);
|
package/package.json
CHANGED