linked-rolls 0.57.0 → 0.59.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 +54 -367
- package/lib/{constraints.d.ts → analysis/constraints.d.ts} +1 -1
- package/lib/{constraints.js → analysis/constraints.js} +8 -7
- package/lib/analysis/ownPaper.d.ts +26 -0
- package/lib/analysis/ownPaper.js +41 -0
- package/lib/{reservations.d.ts → analysis/reservations.d.ts} +3 -3
- package/lib/{reservations.js → analysis/reservations.js} +3 -3
- package/lib/{sigla.d.ts → analysis/sigla.d.ts} +2 -2
- package/lib/{sigla.js → analysis/sigla.js} +4 -4
- package/lib/{witnesses.d.ts → analysis/witnesses.d.ts} +2 -2
- package/lib/{witnesses.js → analysis/witnesses.js} +2 -2
- package/lib/{Collation.d.ts → collation/Collation.d.ts} +4 -4
- package/lib/{Collation.js → collation/Collation.js} +4 -4
- package/lib/{alignment.d.ts → collation/alignment.d.ts} +4 -4
- package/lib/{alignment.js → collation/alignment.js} +10 -16
- package/lib/{scatter.d.ts → collation/scatter.d.ts} +4 -4
- package/lib/{scatter.js → collation/scatter.js} +3 -3
- package/lib/{statistics.d.ts → collation/statistics.d.ts} +1 -1
- package/lib/{statistics.js → collation/statistics.js} +2 -2
- package/lib/{substitution.d.ts → collation/substitution.d.ts} +9 -24
- package/lib/{substitution.js → collation/substitution.js} +13 -37
- package/lib/emulation/Emulation.d.ts +64 -0
- package/lib/emulation/Emulation.js +282 -0
- package/lib/emulation/negotiation.d.ts +14 -0
- package/lib/emulation/negotiation.js +20 -0
- package/lib/index.d.ts +43 -35
- package/lib/index.js +36 -35
- package/lib/{asJsonLd.d.ts → io/asJsonLd.d.ts} +1 -1
- package/lib/{asJsonLd.js → io/asJsonLd.js} +3 -3
- package/lib/{context.d.ts → io/context.d.ts} +4 -4
- package/lib/{context.js → io/context.js} +4 -4
- package/lib/{importJsonLd.d.ts → io/importJsonLd.d.ts} +1 -1
- package/lib/io/importJsonLd.js +128 -0
- package/lib/{migrate.js → io/migrate.js} +59 -55
- package/lib/{Agent.d.ts → model/Agent.d.ts} +1 -1
- package/lib/{Assumption.d.ts → model/Assumption.d.ts} +1 -1
- package/lib/{Edit.d.ts → model/Edit.d.ts} +1 -1
- package/lib/{Edition.d.ts → model/Edition.d.ts} +2 -2
- package/lib/{Feature.d.ts → model/Feature.d.ts} +1 -1
- package/lib/{FeatureSource.d.ts → model/FeatureSource.d.ts} +1 -1
- package/lib/{Perforator.d.ts → model/Perforator.d.ts} +1 -1
- package/lib/{RollCopy.d.ts → model/RollCopy.d.ts} +3 -10
- package/lib/{RollCopy.js → model/RollCopy.js} +3 -5
- package/lib/{Symbol.d.ts → model/Symbol.d.ts} +1 -1
- package/lib/{Version.d.ts → model/Version.d.ts} +10 -2
- package/lib/{Version.js → model/Version.js} +24 -1
- package/lib/{vocabulary.js → model/vocabulary.js} +2 -2
- package/lib/ops/beliefs.d.ts +9 -0
- package/lib/ops/beliefs.js +31 -0
- package/lib/ops/collation.d.ts +62 -0
- package/lib/ops/collation.js +228 -0
- package/lib/ops/commands.d.ts +9 -0
- package/lib/ops/commands.js +29 -0
- package/lib/ops/copies.d.ts +74 -0
- package/lib/ops/copies.js +135 -0
- package/lib/ops/draft.d.ts +59 -0
- package/lib/ops/draft.js +81 -0
- package/lib/ops/edits.d.ts +10 -0
- package/lib/ops/edits.js +82 -0
- package/lib/ops/features.d.ts +84 -0
- package/lib/ops/features.js +296 -0
- package/lib/ops/forget.d.ts +31 -0
- package/lib/ops/forget.js +110 -0
- package/lib/ops/immutable.d.ts +16 -0
- package/lib/ops/immutable.js +46 -0
- package/lib/ops/index.d.ts +13 -0
- package/lib/ops/index.js +7 -0
- package/lib/ops/versions.d.ts +33 -0
- package/lib/ops/versions.js +95 -0
- package/lib/readers/AtonParser.js +5 -7
- package/lib/readers/phillipsEroll.d.ts +3 -3
- package/lib/readers/phillipsEroll.js +4 -5
- package/lib/readers/spencerBar.d.ts +2 -2
- package/lib/readers/spencerBar.js +2 -3
- package/lib/readers/stanfordAton.d.ts +3 -3
- package/lib/readers/stanfordAton.js +2 -3
- package/lib/schema.json +0 -13
- package/lib/{ReproducingSystem.d.ts → systems/ReproducingSystem.d.ts} +3 -3
- package/lib/{TrackerBar.d.ts → systems/TrackerBar.d.ts} +48 -8
- package/lib/{TrackerBar.js → systems/TrackerBar.js} +11 -2
- package/lib/systems/index.d.ts +8 -2
- package/lib/systems/index.js +7 -1
- package/lib/systems/welte.d.ts +100 -0
- package/lib/systems/welte.js +119 -0
- package/lib/systems/welteLicensee/bar.d.ts +1 -1
- package/lib/systems/welteLicensee/bar.js +5 -2
- package/lib/systems/welteLicensee/system.d.ts +1 -1
- package/lib/systems/welteLicensee/system.js +1 -1
- package/lib/systems/welteT100/bar.d.ts +27 -1
- package/lib/systems/welteT100/bar.js +44 -2
- package/lib/systems/welteT100/system.d.ts +6 -39
- package/lib/systems/welteT100/system.js +19 -128
- package/lib/systems/welteT98/bar.d.ts +1 -1
- package/lib/systems/welteT98/bar.js +18 -2
- package/lib/systems/welteT98/system.d.ts +20 -38
- package/lib/systems/welteT98/system.js +20 -121
- package/lib/validate.d.ts +1 -1
- package/lib/{EditionView.d.ts → view/EditionView.d.ts} +17 -41
- package/lib/{EditionView.js → view/EditionView.js} +26 -75
- package/package.json +7 -2
- package/lib/Emulation.d.ts +0 -36
- package/lib/Emulation.js +0 -250
- package/lib/editionOps.d.ts +0 -260
- package/lib/editionOps.js +0 -1079
- package/lib/importJsonLd.js +0 -57
- /package/lib/{migrate.d.ts → io/migrate.d.ts} +0 -0
- /package/lib/{Agent.js → model/Agent.js} +0 -0
- /package/lib/{Assumption.js → model/Assumption.js} +0 -0
- /package/lib/{ConditionState.d.ts → model/ConditionState.d.ts} +0 -0
- /package/lib/{ConditionState.js → model/ConditionState.js} +0 -0
- /package/lib/{Edit.js → model/Edit.js} +0 -0
- /package/lib/{Edition.js → model/Edition.js} +0 -0
- /package/lib/{Feature.js → model/Feature.js} +0 -0
- /package/lib/{FeatureSource.js → model/FeatureSource.js} +0 -0
- /package/lib/{Perforator.js → model/Perforator.js} +0 -0
- /package/lib/{Quantity.d.ts → model/Quantity.d.ts} +0 -0
- /package/lib/{Quantity.js → model/Quantity.js} +0 -0
- /package/lib/{Symbol.js → model/Symbol.js} +0 -0
- /package/lib/{TrackCalibration.d.ts → model/TrackCalibration.d.ts} +0 -0
- /package/lib/{TrackCalibration.js → model/TrackCalibration.js} +0 -0
- /package/lib/{notes.d.ts → model/notes.d.ts} +0 -0
- /package/lib/{notes.js → model/notes.js} +0 -0
- /package/lib/{procedures.d.ts → model/procedures.d.ts} +0 -0
- /package/lib/{procedures.js → model/procedures.js} +0 -0
- /package/lib/{vocabulary.d.ts → model/vocabulary.d.ts} +0 -0
- /package/lib/{sorted.d.ts → shared/sorted.d.ts} +0 -0
- /package/lib/{sorted.js → shared/sorted.js} +0 -0
- /package/lib/{utils.d.ts → shared/utils.d.ts} +0 -0
- /package/lib/{utils.js → shared/utils.js} +0 -0
- /package/lib/{ReproducingSystem.js → systems/ReproducingSystem.js} +0 -0
|
@@ -70,13 +70,13 @@ export class AtonParser {
|
|
|
70
70
|
// Ignore unassociated text.
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
|
-
else if (matches = line.match(/^@@[^@ ]/)) {
|
|
73
|
+
else if ((matches = line.match(/^@@[^@ ]/))) {
|
|
74
74
|
// Control message.
|
|
75
75
|
// End current property.
|
|
76
76
|
this.cleanParameter(state);
|
|
77
77
|
state.curkey = undefined;
|
|
78
78
|
state.ocurkey = undefined;
|
|
79
|
-
if (matches = line.match(/^@@(BEGIN|START)\s*:\s*(.*)\s*$/i)) {
|
|
79
|
+
if ((matches = line.match(/^@@(BEGIN|START)\s*:\s*(.*)\s*$/i))) {
|
|
80
80
|
state.label = matches[2];
|
|
81
81
|
//console.log(state.label)
|
|
82
82
|
if (typeof state.curobj[state.label] === 'undefined') {
|
|
@@ -107,7 +107,7 @@ export class AtonParser {
|
|
|
107
107
|
state.curobj = state.curobj[state.label][state.curobj[state.label].length - 1];
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
else if (matches = line.match(/^@@(END|STOP)\s*:?\s*(.*)\s*$/i)) {
|
|
110
|
+
else if ((matches = line.match(/^@@(END|STOP)\s*:?\s*(.*)\s*$/i))) {
|
|
111
111
|
// End an object, so go back to the parent.
|
|
112
112
|
if (typeof state.curkey !== 'undefined') {
|
|
113
113
|
// clean whitespace of last read property:
|
|
@@ -121,8 +121,6 @@ export class AtonParser {
|
|
|
121
121
|
if (typeof state.node[state.node.length - 1].startline === 'undefined') {
|
|
122
122
|
throw new Error('No start for ' + state.action + ' tag on line '
|
|
123
123
|
+ state.node[state.node.length - 1].startline + ': ' + line);
|
|
124
|
-
state.output = {};
|
|
125
|
-
// return v.output;
|
|
126
124
|
}
|
|
127
125
|
if (typeof state.labelend !== 'undefined') {
|
|
128
126
|
// ensure that the v.label begin/end tags match
|
|
@@ -144,12 +142,12 @@ export class AtonParser {
|
|
|
144
142
|
obj[x.label][x.index] : obj[x.label];
|
|
145
143
|
}, state.output);
|
|
146
144
|
}
|
|
147
|
-
else if (matches = line.match(/^@@TYPE\s*:\s*([^:]+)\s*:\s*(.*)\s*$/i)) {
|
|
145
|
+
else if ((matches = line.match(/^@@TYPE\s*:\s*([^:]+)\s*:\s*(.*)\s*$/i))) {
|
|
148
146
|
// Automatic property value conversion.
|
|
149
147
|
state.typer[matches[1]] = matches[2];
|
|
150
148
|
}
|
|
151
149
|
}
|
|
152
|
-
else if (matches = line.match(/^@([^\s:@][^:]*)\s*:\s*(.*)\s*$/)) {
|
|
150
|
+
else if ((matches = line.match(/^@([^\s:@][^:]*)\s*:\s*(.*)\s*$/))) {
|
|
153
151
|
// New property
|
|
154
152
|
state.newkey = matches[1];
|
|
155
153
|
state.onewkey = state.newkey;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { RollCopy } from "../RollCopy.js";
|
|
2
|
-
import { TrackerBar } from "../TrackerBar.js";
|
|
3
|
-
import { Millimeters, Seconds } from "../Quantity.js";
|
|
1
|
+
import { RollCopy } from "../model/RollCopy.js";
|
|
2
|
+
import { TrackerBar } from "../systems/TrackerBar.js";
|
|
3
|
+
import { Millimeters, Seconds } from "../model/Quantity.js";
|
|
4
4
|
/**
|
|
5
5
|
* Peter Phillips's "e-roll" file, the unprocessed output of his
|
|
6
6
|
* pneumatic roll reader (thesis pp. 182–196): the roll runs over a
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { read } from "midifile-ts";
|
|
2
2
|
import { v4 } from "uuid";
|
|
3
|
-
import { assignObject } from "../Assumption.js";
|
|
4
|
-
import { systemOf } from "../TrackerBar.js";
|
|
5
|
-
import { shortenChains } from "../alignment.js";
|
|
3
|
+
import { assignObject } from "../model/Assumption.js";
|
|
4
|
+
import { systemOf } from "../systems/TrackerBar.js";
|
|
5
|
+
import { shortenChains } from "../collation/alignment.js";
|
|
6
6
|
import { welteT100 } from "../systems/welteT100/bar.js";
|
|
7
7
|
import { welteLicensee } from "../systems/welteLicensee/bar.js";
|
|
8
|
-
import { inMetersPerMinute, mm, seconds, track } from "../Quantity.js";
|
|
8
|
+
import { inMetersPerMinute, mm, seconds, track } from "../model/Quantity.js";
|
|
9
9
|
/**
|
|
10
10
|
* Peter Phillips's "e-roll" file, the unprocessed output of his
|
|
11
11
|
* pneumatic roll reader (thesis pp. 182–196): the roll runs over a
|
|
@@ -166,7 +166,6 @@ export function readFromPhillipsEroll(buffer, { system = welteT100, controlOffse
|
|
|
166
166
|
const copy = {
|
|
167
167
|
type: 'RollCopy',
|
|
168
168
|
id: v4(),
|
|
169
|
-
ops: [],
|
|
170
169
|
conditions: [],
|
|
171
170
|
measurements: {},
|
|
172
171
|
production: { system: systemOf(system), produced: features },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PaperSpeed, RollCopy } from "../RollCopy.js";
|
|
2
|
-
import { TrackerBar } from "../TrackerBar.js";
|
|
1
|
+
import { PaperSpeed, RollCopy } from "../model/RollCopy.js";
|
|
2
|
+
import { TrackerBar } from "../systems/TrackerBar.js";
|
|
3
3
|
/**
|
|
4
4
|
* Rows of the image on an inch of paper. The player reads eight rows a
|
|
5
5
|
* second per unit of roll tempo (tempo 80 comes with a sample rate of
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
|
-
import { systemOf } from "../TrackerBar.js";
|
|
2
|
+
import { systemOf } from "../systems/TrackerBar.js";
|
|
3
3
|
import { welteLicensee } from "../systems/welteLicensee/bar.js";
|
|
4
|
-
import { feetPerMinute, inMillimeters, px, track } from "../Quantity.js";
|
|
4
|
+
import { feetPerMinute, inMillimeters, px, track } from "../model/Quantity.js";
|
|
5
5
|
/**
|
|
6
6
|
* Spencer Chase's e-roll file (`.bar`, "eRoll Tracker Bar Image") holds
|
|
7
7
|
* a roll as a list of events: a distance in rows of the scanned image,
|
|
@@ -111,7 +111,6 @@ export function readFromSpencerBar(buffer, { rowsPerInch = SPENCER_ROWS_PER_INCH
|
|
|
111
111
|
return {
|
|
112
112
|
type: 'RollCopy',
|
|
113
113
|
id: v4(),
|
|
114
|
-
ops: [],
|
|
115
114
|
conditions: [],
|
|
116
115
|
measurements: {},
|
|
117
116
|
production: { system: systemOf(system), produced: features },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { RollCopy } from "../RollCopy.js";
|
|
2
|
-
import { TrackerBar } from "../TrackerBar.js";
|
|
3
|
-
import { Track } from "../Quantity.js";
|
|
1
|
+
import { RollCopy } from "../model/RollCopy.js";
|
|
2
|
+
import { TrackerBar } from "../systems/TrackerBar.js";
|
|
3
|
+
import { Track } from "../model/Quantity.js";
|
|
4
4
|
export interface StanfordAtonOptions {
|
|
5
5
|
/**
|
|
6
6
|
* Added to the scanning software's hole numbering to reach the
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
2
|
import { AtonParser } from "./AtonParser.js";
|
|
3
|
-
import { systemOf } from "../TrackerBar.js";
|
|
3
|
+
import { systemOf } from "../systems/TrackerBar.js";
|
|
4
4
|
import { welteT100 } from "../systems/welteT100/bar.js";
|
|
5
|
-
import { inMillimeters, mean, mm, pixelsPerInch, px, subtract, track } from "../Quantity.js";
|
|
5
|
+
import { inMillimeters, mean, mm, pixelsPerInch, px, subtract, track } from "../model/Quantity.js";
|
|
6
6
|
/** Values in these files carry their unit as a suffix, e.g. "37.7646px". */
|
|
7
7
|
const readPx = (value) => px(parseFloat(value));
|
|
8
8
|
/** The parser writes one record as an object and several as an array. */
|
|
@@ -155,7 +155,6 @@ export function readFromStanfordAton(atonString, { trackShift, system = welteT10
|
|
|
155
155
|
return {
|
|
156
156
|
type: 'RollCopy',
|
|
157
157
|
id: v4(),
|
|
158
|
-
ops: [],
|
|
159
158
|
conditions: [],
|
|
160
159
|
production: {
|
|
161
160
|
system: systemOf(system),
|
package/lib/schema.json
CHANGED
|
@@ -3023,18 +3023,6 @@
|
|
|
3023
3023
|
"type": "array",
|
|
3024
3024
|
"ontology": "crm:P31i was modified by"
|
|
3025
3025
|
},
|
|
3026
|
-
"ops": {
|
|
3027
|
-
"description": "A list of operations that have been applied to this copy's features (e.g. 'shifted', 'stretched') to normalize measurements for comparison with other copies. Not exported to RDF.",
|
|
3028
|
-
"items": {
|
|
3029
|
-
"enum": [
|
|
3030
|
-
"shifted",
|
|
3031
|
-
"stretched",
|
|
3032
|
-
"shortened"
|
|
3033
|
-
],
|
|
3034
|
-
"type": "string"
|
|
3035
|
-
},
|
|
3036
|
-
"type": "array"
|
|
3037
|
-
},
|
|
3038
3026
|
"production": {
|
|
3039
3027
|
"$ref": "#/definitions/ProductionEvent",
|
|
3040
3028
|
"description": "The production event that created this roll copy.",
|
|
@@ -3071,7 +3059,6 @@
|
|
|
3071
3059
|
"@id",
|
|
3072
3060
|
"measurements",
|
|
3073
3061
|
"modifications",
|
|
3074
|
-
"ops",
|
|
3075
3062
|
"@type"
|
|
3076
3063
|
],
|
|
3077
3064
|
"type": "object",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { HoleChain } from "
|
|
2
|
-
import { Expression, Note } from "
|
|
1
|
+
import { HoleChain } from "../model/Feature.js";
|
|
2
|
+
import { Expression, Note } from "../model/Symbol.js";
|
|
3
3
|
import { TrackerBar } from "./TrackerBar.js";
|
|
4
|
-
import { Millimeters, Quantity, Seconds } from "
|
|
4
|
+
import { Millimeters, Quantity, Seconds } from "../model/Quantity.js";
|
|
5
5
|
export type SpeedUnit = 'ft/min' | 'm/min';
|
|
6
6
|
/**
|
|
7
7
|
* The playback tempo of the roll as a paper speed, stated at the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Concept } from "
|
|
2
|
-
import { Expression, Note } from "
|
|
3
|
-
import { Millimeters, SpeedMeasure, Track } from "
|
|
1
|
+
import type { Concept } from "../model/Agent.js";
|
|
2
|
+
import { Expression, Note } from "../model/Symbol.js";
|
|
3
|
+
import { Millimeters, SpeedMeasure, Track } from "../model/Quantity.js";
|
|
4
4
|
/**
|
|
5
5
|
* What a tracker bar position does: sound a note, or operate one of
|
|
6
6
|
* the expression valves on the bass or the treble side.
|
|
@@ -15,6 +15,27 @@ export interface TrackArea {
|
|
|
15
15
|
readonly from: Track;
|
|
16
16
|
readonly to: Track;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* How a scale words a function: as a command that turns it on, one that
|
|
20
|
+
* cancels it, or one that holds it for as long as it lasts.
|
|
21
|
+
*/
|
|
22
|
+
export type Spelling = 'on' | 'off' | 'held';
|
|
23
|
+
/**
|
|
24
|
+
* What a word of a scale operates, rather than the word itself, so that
|
|
25
|
+
* two scales can be compared at all.
|
|
26
|
+
*/
|
|
27
|
+
export interface Operation {
|
|
28
|
+
/** The function operated, named the same wherever a scale has it. */
|
|
29
|
+
operates: string;
|
|
30
|
+
spelling: Spelling;
|
|
31
|
+
/**
|
|
32
|
+
* Whether the half of the keyboard the valve serves is part of the
|
|
33
|
+
* function operated. The dynamics are per half; the pedals are not,
|
|
34
|
+
* and the two Welte scales put them on opposite edges of the paper,
|
|
35
|
+
* so a rule that compared sides would leave every pedal unpaired.
|
|
36
|
+
*/
|
|
37
|
+
sided: boolean;
|
|
38
|
+
}
|
|
18
39
|
export type NoteMeaning = Pick<Note, 'type' | 'pitch'>;
|
|
19
40
|
export type ExpressionMeaning = Pick<Expression, 'type' | 'expressionType' | 'scope'>;
|
|
20
41
|
export type TrackMeaning = NoteMeaning | ExpressionMeaning;
|
|
@@ -44,6 +65,12 @@ export interface TrackerBar {
|
|
|
44
65
|
readonly areas: readonly TrackArea[];
|
|
45
66
|
/** The expression types the bar reads, each a term of the system. */
|
|
46
67
|
readonly expressionTypes: readonly string[];
|
|
68
|
+
/**
|
|
69
|
+
* How the system spells a single added accent, each spelling a
|
|
70
|
+
* sequence of its expression types: a latched system turns a valve on
|
|
71
|
+
* and off again, a held one holds one perforation for the accent.
|
|
72
|
+
*/
|
|
73
|
+
readonly accents: readonly (readonly string[])[];
|
|
47
74
|
/**
|
|
48
75
|
* The position carrying the rewind perforation, which runs at
|
|
49
76
|
* the very end of a roll and is the usual landmark for calibrating
|
|
@@ -90,6 +117,11 @@ export interface TrackerBar {
|
|
|
90
117
|
positionOf(meaning: TrackMeaning): Track | undefined;
|
|
91
118
|
/** `undefined` for a position the bar does not read; snapped as `meaningOf` is. */
|
|
92
119
|
roleOf(position: Track): TrackRole | undefined;
|
|
120
|
+
/**
|
|
121
|
+
* What the expression type operates, or `undefined` for one the bar
|
|
122
|
+
* does not read or whose function has no counterpart in another scale.
|
|
123
|
+
*/
|
|
124
|
+
operationOf(expressionType: string): Operation | undefined;
|
|
93
125
|
/** The positions a feature lies across, snapped to the grid. */
|
|
94
126
|
positionsIn(span: OnBar): readonly Track[];
|
|
95
127
|
}
|
|
@@ -105,11 +137,6 @@ export declare const systemOf: (bar: TrackerBar) => Concept;
|
|
|
105
137
|
export declare const systemIdIn: (id: string | undefined) => string | undefined;
|
|
106
138
|
/** The identifier of a system the type vocabulary knows, from its concept. */
|
|
107
139
|
export declare const systemIdOf: (system: Concept | undefined) => string | undefined;
|
|
108
|
-
/**
|
|
109
|
-
* A tracker bar as written down, with its positions as plain numbers
|
|
110
|
-
* in the bar's own 1-based numbering; `describeTrackerBar` gives them
|
|
111
|
-
* their type.
|
|
112
|
-
*/
|
|
113
140
|
/**
|
|
114
141
|
* Where a roll's own content ends, as far as its perforations say.
|
|
115
142
|
*
|
|
@@ -141,6 +168,11 @@ export type OnBar = {
|
|
|
141
168
|
readonly from: Track;
|
|
142
169
|
readonly to?: Track;
|
|
143
170
|
};
|
|
171
|
+
/**
|
|
172
|
+
* A tracker bar as written down, with its positions as plain numbers
|
|
173
|
+
* in the bar's own 1-based numbering; `describeTrackerBar` gives them
|
|
174
|
+
* their type.
|
|
175
|
+
*/
|
|
144
176
|
export interface TrackerBarSpec {
|
|
145
177
|
id: string;
|
|
146
178
|
name: string;
|
|
@@ -170,6 +202,14 @@ export interface TrackerBarSpec {
|
|
|
170
202
|
* its own needs no threshold, since anything there is the rewind.
|
|
171
203
|
*/
|
|
172
204
|
rewindHold?: Millimeters;
|
|
205
|
+
/**
|
|
206
|
+
* What each expression type operates, keyed by type. A type left out
|
|
207
|
+
* operates a function no other scale has a word for, and a transfer
|
|
208
|
+
* leaves it a plain deletion.
|
|
209
|
+
*/
|
|
210
|
+
operations?: Readonly<Record<string, Operation>>;
|
|
211
|
+
/** How the system spells a single added accent; see `TrackerBar.accents`. */
|
|
212
|
+
accents?: readonly (readonly string[])[];
|
|
173
213
|
}
|
|
174
214
|
export declare const describeTrackerBar: (spec: TrackerBarSpec) => TrackerBar;
|
|
175
215
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mm, track } from "
|
|
1
|
+
import { mm, track } from "../model/Quantity.js";
|
|
2
2
|
/**
|
|
3
3
|
* What a position says, as a key. Two bars read the same thing exactly
|
|
4
4
|
* where their keys agree, which is what lets a symbol cross from one
|
|
@@ -66,6 +66,13 @@ export const describeTrackerBar = (spec) => {
|
|
|
66
66
|
if (rewind === undefined) {
|
|
67
67
|
throw new Error(`${spec.name} declares no rewind track`);
|
|
68
68
|
}
|
|
69
|
+
const expressionTypes = [...new Set(spec.expressions.values())];
|
|
70
|
+
const operations = spec.operations ?? {};
|
|
71
|
+
const accents = spec.accents ?? [];
|
|
72
|
+
const unread = [...Object.keys(operations), ...accents.flat()].filter(type => !expressionTypes.includes(type));
|
|
73
|
+
if (unread.length > 0) {
|
|
74
|
+
throw new Error(`${spec.name} names expression types its bar does not read: ${[...new Set(unread)].join(', ')}`);
|
|
75
|
+
}
|
|
69
76
|
// A rewind on a line of its own is unambiguous; one sharing a line is only
|
|
70
77
|
// the rewind when it is far longer than that line's usual command.
|
|
71
78
|
const shared = spec.rewindTrack !== undefined;
|
|
@@ -84,13 +91,15 @@ export const describeTrackerBar = (spec) => {
|
|
|
84
91
|
trackCount: spec.trackCount,
|
|
85
92
|
endsAt,
|
|
86
93
|
areas,
|
|
87
|
-
expressionTypes
|
|
94
|
+
expressionTypes,
|
|
95
|
+
accents,
|
|
88
96
|
rewindTrack: track(rewind),
|
|
89
97
|
...(spec.paperSpeed && { paperSpeed: spec.paperSpeed }),
|
|
90
98
|
meaningOf,
|
|
91
99
|
meaningsOf,
|
|
92
100
|
positionOf: meaning => positions.get(keyOf(meaning)),
|
|
93
101
|
roleOf,
|
|
102
|
+
operationOf: expressionType => Object.hasOwn(operations, expressionType) ? operations[expressionType] : undefined,
|
|
94
103
|
positionsIn: positionsBetween
|
|
95
104
|
};
|
|
96
105
|
};
|
package/lib/systems/index.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import { Concept } from "../Agent.js";
|
|
2
|
-
import { TrackerBar } from "
|
|
1
|
+
import { Concept } from "../model/Agent.js";
|
|
2
|
+
import { TrackerBar } from "./TrackerBar.js";
|
|
3
3
|
/** The tracker bars the library knows, the T-100 first as the usual one. */
|
|
4
4
|
export declare const trackerBars: readonly TrackerBar[];
|
|
5
5
|
/** The bar of a system the type vocabulary knows, from its concept. */
|
|
6
6
|
export declare const trackerBarOf: (system: Concept | undefined) => TrackerBar | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* The bar a copy is read by where it names no system of its own: every
|
|
9
|
+
* copy was read by the T-100's before the systems were told apart, and
|
|
10
|
+
* `reservationsAbout` reports a copy that still relies on this.
|
|
11
|
+
*/
|
|
12
|
+
export declare const defaultTrackerBar: TrackerBar;
|
package/lib/systems/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { systemIdOf } from "
|
|
1
|
+
import { systemIdOf } from "./TrackerBar.js";
|
|
2
2
|
import { welteT100 } from "./welteT100/bar.js";
|
|
3
3
|
import { welteLicensee } from "./welteLicensee/bar.js";
|
|
4
4
|
import { welteT98 } from "./welteT98/bar.js";
|
|
@@ -9,3 +9,9 @@ export const trackerBarOf = (system) => {
|
|
|
9
9
|
const id = systemIdOf(system);
|
|
10
10
|
return trackerBars.find(bar => bar.id === id);
|
|
11
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* The bar a copy is read by where it names no system of its own: every
|
|
14
|
+
* copy was read by the T-100's before the systems were told apart, and
|
|
15
|
+
* `reservationsAbout` reports a copy that still relies on this.
|
|
16
|
+
*/
|
|
17
|
+
export const defaultTrackerBar = welteT100;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Grid, Half, Model, ModelInput, Parameters, PedalInput, PedalMode, PedalTravel, PortGeometry, Spool } from "welte-mignon-emulator";
|
|
2
|
+
import { Expression } from "../model/Symbol.js";
|
|
3
|
+
import { NegotiatedEvent, Performance, RollProperties } from "./ReproducingSystem.js";
|
|
4
|
+
import { Millimeters, Seconds, Track } from "../model/Quantity.js";
|
|
5
|
+
import { type VelocityMap } from "./velocity.js";
|
|
6
|
+
/**
|
|
7
|
+
* What the Welte systems share downstream of the relay. Hagmann has the
|
|
8
|
+
* nuancing unit built the same for both tracker scales (p. 96) and the valves
|
|
9
|
+
* and bellows that move the pedals the same in both (p. 106), so the way a
|
|
10
|
+
* performance is read off the emulator is one; what differs is in front of it,
|
|
11
|
+
* and each system says that in the `Mechanism` it hands to `performWelte`.
|
|
12
|
+
*/
|
|
13
|
+
/** The options every Welte system takes. */
|
|
14
|
+
export type WelteOptions = {
|
|
15
|
+
/**
|
|
16
|
+
* The take-up spool, which sets the time axis: it is held at a constant
|
|
17
|
+
* rate of revolution, so the paper runs faster as the spool fills.
|
|
18
|
+
*/
|
|
19
|
+
spool: Spool;
|
|
20
|
+
/** Constants of the nuancing mechanism, one set for each half of the keyboard. */
|
|
21
|
+
nuance: Record<Half, Parameters>;
|
|
22
|
+
/** Constants of the two pedal actions, one of `pedalPresets` or a set of one's own. */
|
|
23
|
+
pedals: Parameters;
|
|
24
|
+
velocity: VelocityMap;
|
|
25
|
+
/**
|
|
26
|
+
* How the pedals go out: as a continuous controller carrying the travel
|
|
27
|
+
* of the bellows, or thresholded to the two values a switching renderer
|
|
28
|
+
* understands.
|
|
29
|
+
*/
|
|
30
|
+
pedalMode: PedalMode;
|
|
31
|
+
/** Diameter of the tracker-bar bore. */
|
|
32
|
+
trackerBore: Millimeters;
|
|
33
|
+
/** Punch diameter for an edition whose copies record none. */
|
|
34
|
+
punchDiameter: Millimeters;
|
|
35
|
+
/**
|
|
36
|
+
* The track at which the keyboard is divided, so that notes from here
|
|
37
|
+
* upwards follow the treble expression and the ones below it the bass.
|
|
38
|
+
* Which side an expression perforation itself belongs to is not decided
|
|
39
|
+
* here but read off the tracker bar.
|
|
40
|
+
*/
|
|
41
|
+
division: Track;
|
|
42
|
+
};
|
|
43
|
+
/** Whether two sets of constants are the same, value for value. */
|
|
44
|
+
export declare const sameParameters: (a: Parameters, b: Parameters) => boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Between the edition's shared place axis and this version's own paper.
|
|
47
|
+
* `toOwnPaper` is 1 for a version on the axis it was measured on, and about
|
|
48
|
+
* 0.775 for a green version whose places are in the red axis; see
|
|
49
|
+
* `RollProperties`.
|
|
50
|
+
*
|
|
51
|
+
* Rows are rows of the version's own paper, so the spool is asked in
|
|
52
|
+
* `paperOfRow` and never in `placeOfRow`: one is the paper that passes the
|
|
53
|
+
* tracker bar, the other is the coordinate the edition states.
|
|
54
|
+
*/
|
|
55
|
+
export type Paper = {
|
|
56
|
+
readonly rowOf: (place: Millimeters) => number;
|
|
57
|
+
readonly placeOfRow: (row: number) => Millimeters;
|
|
58
|
+
readonly paperOfRow: (row: number) => Millimeters;
|
|
59
|
+
};
|
|
60
|
+
/** When the spool brings a place on the roll to the tracker bar. */
|
|
61
|
+
export declare const secondsAt: (spool: Spool, place: Millimeters) => Seconds;
|
|
62
|
+
/** A perforation as the emulator reads it: the control it operates and the rows it spans. */
|
|
63
|
+
export type WeltePunch = {
|
|
64
|
+
readonly half: Half;
|
|
65
|
+
readonly control: string;
|
|
66
|
+
readonly rowOn: number;
|
|
67
|
+
readonly rowOff: number;
|
|
68
|
+
};
|
|
69
|
+
export type Ports = ModelInput['ports'];
|
|
70
|
+
/**
|
|
71
|
+
* What a Welte system puts in front of the shared nuancing unit and pedals:
|
|
72
|
+
* how it reads a perforation, how it opens the ports, which pneumatic model
|
|
73
|
+
* drives the bellows, and which the pedals.
|
|
74
|
+
*/
|
|
75
|
+
export type Mechanism<P extends WeltePunch> = {
|
|
76
|
+
/** The punch the expression is read as, or nothing for one the mechanism does not read. */
|
|
77
|
+
readonly punchOf: (event: NegotiatedEvent & Expression, rows: {
|
|
78
|
+
rowOn: number;
|
|
79
|
+
rowOff: number;
|
|
80
|
+
}) => P | undefined;
|
|
81
|
+
readonly portsOf: (grid: Grid, punches: readonly P[], geometry: PortGeometry) => Ports;
|
|
82
|
+
readonly model: Model;
|
|
83
|
+
readonly runPedals: (input: PedalInput, params: Parameters) => PedalTravel;
|
|
84
|
+
/** The name of the instrument the curves say they came from. */
|
|
85
|
+
readonly instrument: string;
|
|
86
|
+
};
|
|
87
|
+
/** A performance, with the grid and ports it was read off, for a system that has more to ask of them. */
|
|
88
|
+
export type WeltePerformance = Performance & {
|
|
89
|
+
readonly grid: Grid;
|
|
90
|
+
readonly ports: Ports;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Plays the events on a Welte mechanism: notes at the velocity of their half's
|
|
94
|
+
* bellows, and the two pedals as the travel of theirs.
|
|
95
|
+
*
|
|
96
|
+
* The edition's tempo adjustment is left aside: it is stated as a paper
|
|
97
|
+
* speed, and what the spool holds constant is its rate of revolution, so
|
|
98
|
+
* the two are not the same quantity. The spool in the options sets the speed.
|
|
99
|
+
*/
|
|
100
|
+
export declare const performWelte: <P extends WeltePunch>(events: readonly NegotiatedEvent[], options: WelteOptions, roll: RollProperties, mechanism: Mechanism<P>) => WeltePerformance;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { clamp, geometryInMm, Grid, levelChanges, mezzoforteTravel, paperSeconds, ROWS_PER_MM, travelBetweenRails, } from "welte-mignon-emulator";
|
|
2
|
+
import { inCentimeters, mm, seconds } from "../model/Quantity.js";
|
|
3
|
+
import { partitionPoint } from "../shared/sorted.js";
|
|
4
|
+
import { velocityOf } from "./velocity.js";
|
|
5
|
+
/** Whether two sets of constants are the same, value for value. */
|
|
6
|
+
export const sameParameters = (a, b) => Object.keys(a).length === Object.keys(b).length
|
|
7
|
+
&& Object.entries(a).every(([name, value]) => b[name] === value);
|
|
8
|
+
/** Paper the grid runs on past the last hole, so that a final pedal release completes. */
|
|
9
|
+
const RUN_OUT = mm(100);
|
|
10
|
+
const isNote = (event) => event.type === 'note';
|
|
11
|
+
const isExpression = (event) => event.type === 'expression';
|
|
12
|
+
const paperOf = (toOwnPaper) => ({
|
|
13
|
+
rowOf: place => place * toOwnPaper * ROWS_PER_MM,
|
|
14
|
+
placeOfRow: row => mm(row / (toOwnPaper * ROWS_PER_MM)),
|
|
15
|
+
paperOfRow: row => mm(row / ROWS_PER_MM)
|
|
16
|
+
});
|
|
17
|
+
/** When the spool brings a place on the roll to the tracker bar. */
|
|
18
|
+
export const secondsAt = (spool, place) => seconds(paperSeconds(spool, inCentimeters(place)));
|
|
19
|
+
const halfOf = (note, division) => note.vertical.from >= division ? 'treble' : 'bass';
|
|
20
|
+
/**
|
|
21
|
+
* One sample per row of the scan the constants were fitted on, from the
|
|
22
|
+
* beginning of the roll to a little past the last hole. The rows are
|
|
23
|
+
* equally spaced on the paper and not in time, which is what the
|
|
24
|
+
* emulator expects.
|
|
25
|
+
*/
|
|
26
|
+
const gridOver = (events, spool, paper) => {
|
|
27
|
+
const last = mm(events.reduce((furthest, event) => Math.max(furthest, event.horizontal.to), 0));
|
|
28
|
+
const length = Math.ceil(paper.rowOf(last) + RUN_OUT * ROWS_PER_MM) + 1;
|
|
29
|
+
const times = new Float64Array(length).map((_, row) => secondsAt(spool, paper.paperOfRow(row)));
|
|
30
|
+
return new Grid(0, times);
|
|
31
|
+
};
|
|
32
|
+
const nuanceCurves = (grid, ports, samples, options, model, instrument) => {
|
|
33
|
+
const curveOf = (half) => {
|
|
34
|
+
const params = options.nuance[half];
|
|
35
|
+
const output = model.run({ grid, half, ports }, params);
|
|
36
|
+
const travel = travelBetweenRails(output, params);
|
|
37
|
+
const hook = clamp(mezzoforteTravel(params), 0.01, 0.99);
|
|
38
|
+
return {
|
|
39
|
+
...samples,
|
|
40
|
+
name: half,
|
|
41
|
+
kind: 'dynamics',
|
|
42
|
+
instrument,
|
|
43
|
+
travel,
|
|
44
|
+
velocity: travel.map(value => velocityOf(value, hook, options.velocity))
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
return { bass: curveOf('bass'), treble: curveOf('treble') };
|
|
48
|
+
};
|
|
49
|
+
const performNotes = (events, grid, nuance, options, paper) => events
|
|
50
|
+
.filter(isNote)
|
|
51
|
+
.flatMap((note) => {
|
|
52
|
+
const curve = nuance[halfOf(note, options.division)];
|
|
53
|
+
const velocity = curve.velocity[grid.indexOfRow(paper.rowOf(note.horizontal.from))];
|
|
54
|
+
return [
|
|
55
|
+
{ type: 'noteOn', performs: note, pitch: note.pitch, velocity, at: secondsAt(options.spool, note.horizontal.from) },
|
|
56
|
+
{ type: 'noteOff', performs: note, pitch: note.pitch, velocity: 127, at: secondsAt(options.spool, note.horizontal.to) }
|
|
57
|
+
];
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* The travel of one pedal as controller steps. Each step is attributed to
|
|
61
|
+
* the last perforation of that pedal the tracker bar has reached, which is
|
|
62
|
+
* the one whose reading it follows from.
|
|
63
|
+
*/
|
|
64
|
+
const performPedal = (type, curve, grid, readings, mode) => {
|
|
65
|
+
if (readings.length === 0)
|
|
66
|
+
return [];
|
|
67
|
+
const ordered = readings.toSorted((a, b) => a.punch.rowOn - b.punch.rowOn);
|
|
68
|
+
const causeOf = (row) => ordered[Math.max(partitionPoint(ordered, reading => reading.punch.rowOn <= row) - 1, 0)].event;
|
|
69
|
+
return levelChanges(curve.travel, { mode })
|
|
70
|
+
.filter(change => change.index > 0)
|
|
71
|
+
.map(change => ({
|
|
72
|
+
type,
|
|
73
|
+
performs: causeOf(grid.rowAt(change.index)),
|
|
74
|
+
value: change.value,
|
|
75
|
+
at: seconds(curve.seconds[change.index])
|
|
76
|
+
}));
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Plays the events on a Welte mechanism: notes at the velocity of their half's
|
|
80
|
+
* bellows, and the two pedals as the travel of theirs.
|
|
81
|
+
*
|
|
82
|
+
* The edition's tempo adjustment is left aside: it is stated as a paper
|
|
83
|
+
* speed, and what the spool holds constant is its rate of revolution, so
|
|
84
|
+
* the two are not the same quantity. The spool in the options sets the speed.
|
|
85
|
+
*/
|
|
86
|
+
export const performWelte = (events, options, roll, mechanism) => {
|
|
87
|
+
const paper = paperOf(roll.toOwnPaper ?? 1);
|
|
88
|
+
const readings = events
|
|
89
|
+
.filter(isExpression)
|
|
90
|
+
.flatMap((event) => {
|
|
91
|
+
const punch = mechanism.punchOf(event, {
|
|
92
|
+
rowOn: paper.rowOf(event.horizontal.from),
|
|
93
|
+
rowOff: paper.rowOf(event.horizontal.to)
|
|
94
|
+
});
|
|
95
|
+
return punch ? [{ event, punch }] : [];
|
|
96
|
+
});
|
|
97
|
+
const grid = gridOver(events, options.spool, paper);
|
|
98
|
+
const geometry = geometryInMm(roll.punchDiameter ?? options.punchDiameter, options.trackerBore);
|
|
99
|
+
const ports = mechanism.portsOf(grid, readings.map(reading => reading.punch), geometry);
|
|
100
|
+
const samples = {
|
|
101
|
+
place: grid.seconds.map((_, row) => paper.placeOfRow(row)),
|
|
102
|
+
seconds: grid.seconds
|
|
103
|
+
};
|
|
104
|
+
const nuance = nuanceCurves(grid, ports, samples, options, mechanism.model, mechanism.instrument);
|
|
105
|
+
const travel = mechanism.runPedals({ grid, ports }, options.pedals);
|
|
106
|
+
const damper = { ...samples, name: 'damper', kind: 'pedal', travel: travel.damper };
|
|
107
|
+
const hammerRail = { ...samples, name: 'hammerRail', kind: 'pedal', travel: travel.hammerRail };
|
|
108
|
+
const readingsOf = (control) => readings.filter(reading => reading.punch.control === control);
|
|
109
|
+
return {
|
|
110
|
+
grid,
|
|
111
|
+
ports,
|
|
112
|
+
events: [
|
|
113
|
+
...performNotes(events, grid, nuance, options, paper),
|
|
114
|
+
...performPedal('damper', damper, grid, readingsOf('sustainPedal'), options.pedalMode),
|
|
115
|
+
...performPedal('hammerRail', hammerRail, grid, readingsOf('hammerRail'), options.pedalMode)
|
|
116
|
+
],
|
|
117
|
+
curves: [nuance.bass, nuance.treble, damper, hammerRail]
|
|
118
|
+
};
|
|
119
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { describeTrackerBar } from "
|
|
2
|
-
import { mm } from "../../Quantity.js";
|
|
1
|
+
import { describeTrackerBar } from "../TrackerBar.js";
|
|
2
|
+
import { mm } from "../../model/Quantity.js";
|
|
3
|
+
import { welteT100Accents, welteT100Operations } from "../welteT100/bar.js";
|
|
3
4
|
/**
|
|
4
5
|
* Welte-Mignon (Licensee), the American re-cut of the T-100 rolls on
|
|
5
6
|
* a roll 11¼ inches wide with 98 positions at nine to the inch, cf.
|
|
@@ -15,6 +16,8 @@ export const welteLicensee = describeTrackerBar({
|
|
|
15
16
|
width: mm(285.75),
|
|
16
17
|
trackCount: 98,
|
|
17
18
|
notes: { from: 9, to: 88, lowestPitch: 24 },
|
|
19
|
+
operations: welteT100Operations,
|
|
20
|
+
accents: welteT100Accents,
|
|
18
21
|
expressions: new Map([
|
|
19
22
|
[1, 'MezzoforteOff'],
|
|
20
23
|
[2, 'MezzoforteOn'],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CONSENSUS } from "welte-mignon-emulator/t100";
|
|
2
|
-
import { track } from "../../Quantity.js";
|
|
2
|
+
import { track } from "../../model/Quantity.js";
|
|
3
3
|
import { welteLicensee } from "./bar.js";
|
|
4
4
|
import { defaultWelteT100Options, instrumentNameOf, nuanceOf, performAs } from "../welteT100/system.js";
|
|
5
5
|
/**
|
|
@@ -1,9 +1,35 @@
|
|
|
1
|
-
import { TrackerBar } from "
|
|
1
|
+
import { Operation, TrackerBar } from "../TrackerBar.js";
|
|
2
2
|
/**
|
|
3
3
|
* The commands of the Welte-Mignon T-100, as its tracker bar reads them.
|
|
4
4
|
*/
|
|
5
5
|
export declare const welteT100ExpressionTypes: readonly ['SustainPedalOn', 'SustainPedalOff', 'SoftPedalOn', 'SoftPedalOff', 'MezzoforteOff', 'MezzoforteOn', 'SlowCrescendoOn', 'SlowCrescendoOff', 'ForzandoOn', 'ForzandoOff', 'MotorOff', 'MotorOn', 'Rewind', 'ElectricCutOff'];
|
|
6
6
|
export type WelteT100ExpressionType = typeof welteT100ExpressionTypes[number];
|
|
7
|
+
/**
|
|
8
|
+
* What each T-100 command operates, so that it can be set against the
|
|
9
|
+
* T-98's words for the same function.
|
|
10
|
+
*
|
|
11
|
+
* This cannot be read off the names. The T-100 latches a function on
|
|
12
|
+
* with one perforation and cancels it with a second, while the T-98
|
|
13
|
+
* holds it for as long as one perforation lasts (Hagmann pp. 89 f. and
|
|
14
|
+
* 100–103; Phillips p. 121), and Welte renamed two of the functions
|
|
15
|
+
* between the scales: the red `SlowCrescendo` is the green `Crescendo`,
|
|
16
|
+
* and the red's single `Forzando` valve answers to two green ones that
|
|
17
|
+
* name the end they pull towards. So the correspondence is stated here
|
|
18
|
+
* rather than derived, and only two types that operate one function can
|
|
19
|
+
* stand for each other.
|
|
20
|
+
*
|
|
21
|
+
* `MotorOn`/`MotorOff`, `Rewind` and `ElectricCutOff` are left out on
|
|
22
|
+
* purpose: the green scale has no word for any of them, its motor switch
|
|
23
|
+
* being an automatic mercury contact (Skala-Rolle 98 §12) and its rewind
|
|
24
|
+
* riding on the bass sforzando-piano line. A red command of those kinds
|
|
25
|
+
* has no counterpart and stays a plain deletion.
|
|
26
|
+
*/
|
|
27
|
+
export declare const welteT100Operations: Readonly<Partial<Record<WelteT100ExpressionType, Operation>>>;
|
|
28
|
+
/**
|
|
29
|
+
* A single added accent on the T-100: a valve latched on and off again
|
|
30
|
+
* straight away.
|
|
31
|
+
*/
|
|
32
|
+
export declare const welteT100Accents: readonly (readonly WelteT100ExpressionType[])[];
|
|
7
33
|
/**
|
|
8
34
|
* Welte-Mignon T-100 ("red Welte"), cf. Hagmann, pp. 75 and 178.
|
|
9
35
|
*
|