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,474 @@
1
+ import { MIDIControlEvents } from "midifile-ts";
2
+ import { KinematicConversion } from "./PlaceTimeConversion";
3
+ import { getSnapshot } from "./Version";
4
+ import { dimensionOf } from "./Symbol";
5
+ function resize(arr, newSize, defaultValue) {
6
+ while (newSize > arr.length)
7
+ arr.push(defaultValue);
8
+ }
9
+ const simplifySymbol = (symbol) => {
10
+ if (!symbol.carriers || !symbol.carriers.length)
11
+ return null;
12
+ const mean = dimensionOf(symbol);
13
+ return {
14
+ ...symbol,
15
+ ...mean
16
+ };
17
+ };
18
+ export class Emulation {
19
+ constructor(options = {
20
+ welte_p: 35,
21
+ welte_f: 90,
22
+ welte_mf: 60,
23
+ welte_loud: 75,
24
+ trackerBarDiameter: 1.413,
25
+ punchExtensionFraction: 0.75,
26
+ slow_decay_rate: 2380,
27
+ fastC_decay_rate: 300,
28
+ fastD_decay_rate: 400,
29
+ division: 54
30
+ }) {
31
+ Object.defineProperty(this, "placeTimeConversion", {
32
+ enumerable: true,
33
+ configurable: true,
34
+ writable: true,
35
+ value: new KinematicConversion()
36
+ });
37
+ Object.defineProperty(this, "midiEvents", {
38
+ enumerable: true,
39
+ configurable: true,
40
+ writable: true,
41
+ value: []
42
+ });
43
+ // sorted list of events with the negotiated assumptions already applied
44
+ Object.defineProperty(this, "negotiatedEvents", {
45
+ enumerable: true,
46
+ configurable: true,
47
+ writable: true,
48
+ value: []
49
+ });
50
+ // stores a velocity for every millisecond
51
+ Object.defineProperty(this, "trebleVelocities", {
52
+ enumerable: true,
53
+ configurable: true,
54
+ writable: true,
55
+ value: []
56
+ });
57
+ Object.defineProperty(this, "bassVelocities", {
58
+ enumerable: true,
59
+ configurable: true,
60
+ writable: true,
61
+ value: []
62
+ });
63
+ Object.defineProperty(this, "startTempo", {
64
+ enumerable: true,
65
+ configurable: true,
66
+ writable: true,
67
+ value: void 0
68
+ });
69
+ Object.defineProperty(this, "endTempo", {
70
+ enumerable: true,
71
+ configurable: true,
72
+ writable: true,
73
+ value: void 0
74
+ });
75
+ Object.defineProperty(this, "source", {
76
+ enumerable: true,
77
+ configurable: true,
78
+ writable: true,
79
+ value: void 0
80
+ });
81
+ Object.defineProperty(this, "options", {
82
+ enumerable: true,
83
+ configurable: true,
84
+ writable: true,
85
+ value: void 0
86
+ });
87
+ options.slow_step = (options.welte_mf - options.welte_p) / options.slow_decay_rate;
88
+ options.fastC_step = (options.welte_mf - options.welte_p) / options.fastC_decay_rate;
89
+ options.fastD_step = -(options.welte_f - options.welte_p) / options.fastD_decay_rate;
90
+ this.options = options;
91
+ }
92
+ findRollTempo(tempo) {
93
+ if (!tempo) {
94
+ this.startTempo = 104.331;
95
+ this.endTempo = 104.331;
96
+ return;
97
+ }
98
+ this.startTempo = tempo.startsWith;
99
+ this.endTempo = tempo.endsWith;
100
+ }
101
+ assignPhysicalTime(skipToFirstNote = false) {
102
+ if (this.negotiatedEvents.length === 0)
103
+ return;
104
+ const first = skipToFirstNote ? this.negotiatedEvents[0].horizontal.from : 0;
105
+ for (const event of this.negotiatedEvents) {
106
+ if (!event.assumedPhysicalTime) {
107
+ // convert from mm to cm and then to time
108
+ event.assumedPhysicalTime = [
109
+ this.placeTimeConversion.placeToTime((event.horizontal.from - first) / 10),
110
+ this.placeTimeConversion.placeToTime((event.horizontal.to - first) / 10)
111
+ ];
112
+ }
113
+ }
114
+ }
115
+ applyTrackerBarExtension() {
116
+ const correction = this.options.trackerBarDiameter * this.options.punchExtensionFraction + 0.5;
117
+ for (const event of this.negotiatedEvents) {
118
+ if (event.horizontal.to) {
119
+ event.horizontal.to += correction;
120
+ }
121
+ }
122
+ }
123
+ convertEventsToMIDI() {
124
+ for (const event of this.negotiatedEvents) {
125
+ if (event.type === 'expression') {
126
+ const expression = event;
127
+ const map = new Map([
128
+ ['SustainPedalOn', 'sustainPedalOn'],
129
+ ['SustainPedalOff', 'sustainPedalOff'],
130
+ ['SoftPedalOn', 'softPedalOn'],
131
+ ['SoftPedalOff', 'softPedalOff']
132
+ ]);
133
+ if (map.has(expression.expressionType)) {
134
+ this.midiEvents.push({
135
+ type: map.get(expression.expressionType),
136
+ performs: event,
137
+ at: event.assumedPhysicalTime[0],
138
+ });
139
+ }
140
+ }
141
+ else if (event.type === 'note') {
142
+ const note = event;
143
+ // take velocity from the calculated velocity list
144
+ const pitch = note.pitch;
145
+ if (event.vertical.from >= this.options.division) {
146
+ this.insertNote(event, pitch, this.trebleVelocities[+(event.assumedPhysicalTime[0] * 1000).toFixed()]);
147
+ }
148
+ else {
149
+ this.insertNote(event, pitch, this.bassVelocities[+(event.assumedPhysicalTime[0] * 1000).toFixed()]);
150
+ }
151
+ }
152
+ }
153
+ this.midiEvents.sort((a, b) => a.at - b.at);
154
+ }
155
+ emulateFromRoll(events) {
156
+ this.startTempo = 104.331;
157
+ this.endTempo = 104.331;
158
+ this.negotiatedEvents = events
159
+ .map(simplifySymbol)
160
+ .filter(s => s !== null);
161
+ this.applyTrackerBarExtension();
162
+ this.assignPhysicalTime();
163
+ this.applyTrackerBarExtension();
164
+ this.calculateVelocities('treble');
165
+ this.calculateVelocities('bass');
166
+ this.convertEventsToMIDI();
167
+ return this.midiEvents;
168
+ }
169
+ emulateVersion(version, rollTempo, skipToFirstNote = false) {
170
+ this.source = version.id;
171
+ this.negotiatedEvents =
172
+ getSnapshot(version)
173
+ .filter(s => s.type === 'note' || s.type === 'expression')
174
+ .map(simplifySymbol)
175
+ .filter(s => s !== null);
176
+ this.findRollTempo(rollTempo);
177
+ this.applyTrackerBarExtension();
178
+ this.assignPhysicalTime(skipToFirstNote);
179
+ this.calculateVelocities('treble');
180
+ this.calculateVelocities('bass');
181
+ this.convertEventsToMIDI();
182
+ return this.midiEvents;
183
+ }
184
+ /**
185
+ * The original code of the calculateVelocities() method,
186
+ * written by Kitty Shi and Craig Stuart Sapp,
187
+ * was taken from the midi2exp project (https://github.com/pianoroll/midi2exp)
188
+ * and adapted to the different data representation.
189
+ */
190
+ calculateVelocities(scope) {
191
+ if (!this.negotiatedEvents.length)
192
+ return;
193
+ const velocities = scope === 'treble' ? this.trebleVelocities : this.bassVelocities;
194
+ const isMF = []; // is MF hook on?
195
+ const isSlowC = []; // is slow crescendo on?
196
+ const isFastC = []; // is fast crescendo on?
197
+ const isFastD = []; // is fast decrescendo on?
198
+ let lastOnsetMs = this.negotiatedEvents[this.negotiatedEvents.length - 1].assumedPhysicalTime[0];
199
+ if (!lastOnsetMs) {
200
+ console.log('Failed calculating the last onset.');
201
+ return;
202
+ }
203
+ lastOnsetMs *= 1000;
204
+ // set all of the times to piano by default
205
+ resize(velocities, lastOnsetMs, this.options.welte_p);
206
+ // fill all hook maps with false
207
+ for (const target of [isMF, isSlowC, isFastC, isFastD]) {
208
+ resize(target, lastOnsetMs, false);
209
+ }
210
+ // Lock and Cancel
211
+ let valve_mf_on = false;
212
+ let valve_slowc_on = false;
213
+ let valve_mf_starttime = 0; // 0 for off
214
+ let valve_slowc_starttime = 0;
215
+ // First pass: For each time section calculate the current boolean
216
+ // state of each expression.
217
+ for (const negotiatedEvent of this.negotiatedEvents) {
218
+ if (negotiatedEvent.type !== 'expression')
219
+ continue;
220
+ if (scope === 'treble' && negotiatedEvent.vertical.from < this.options.division)
221
+ continue;
222
+ else if (scope === 'bass' && negotiatedEvent.vertical.from >= this.options.division)
223
+ continue;
224
+ const event = negotiatedEvent;
225
+ const startMs = event.assumedPhysicalTime[0] * 1000;
226
+ const endMs = event.assumedPhysicalTime[1] * 1000;
227
+ // console.log('encoutering expression', event.expressionType["@id"], 'from', startMs, 'to', endMs)
228
+ if (event.expressionType === 'MezzoforteOn') {
229
+ // update the mezzoforte start time
230
+ // only if the mf valve is not on already
231
+ if (!valve_mf_on) {
232
+ valve_mf_on = true;
233
+ valve_mf_starttime = startMs;
234
+ }
235
+ }
236
+ else if (event.expressionType === 'MezzoforteOff') {
237
+ if (valve_mf_on) {
238
+ // fill from the mezzoforte start time to here ...
239
+ isMF.fill(true, valve_mf_starttime, startMs);
240
+ }
241
+ valve_mf_on = false;
242
+ }
243
+ else if (event.expressionType === 'SlowCrescendoOn') {
244
+ // update the slow crescendo start time
245
+ // only if slow crescendo is not on already
246
+ if (!valve_slowc_on) {
247
+ valve_slowc_on = true;
248
+ valve_slowc_starttime = startMs;
249
+ }
250
+ }
251
+ else if (event.expressionType === 'SlowCrescendoOff') {
252
+ if (valve_slowc_on) {
253
+ // fill from the mezzoforte start time to here ...
254
+ isSlowC.fill(true, valve_slowc_starttime, startMs);
255
+ }
256
+ valve_slowc_on = false;
257
+ }
258
+ else if (event.expressionType === 'ForzandoOn') {
259
+ // Forzando On/Off are a direct operations (length of perforation matters)
260
+ isFastC.fill(true, startMs, endMs);
261
+ }
262
+ else if (event.expressionType === 'ForzandoOff') {
263
+ // Forzando On/Off are a direct operations (length of perforation matters)
264
+ isFastD.fill(true, startMs, endMs);
265
+ }
266
+ }
267
+ // TODO: deal with the last case (if crescendo OFF is missing)
268
+ // Second pass, update the current velocity according to the previous one
269
+ let amount = 0.0;
270
+ let eps = 0.0001;
271
+ for (let i = 1; i < lastOnsetMs; i++) {
272
+ if (!isSlowC[i] && !isFastC[i] && !isFastD[i]) {
273
+ // slow decrescendo is always on
274
+ amount = -this.options.slow_step;
275
+ }
276
+ else {
277
+ amount =
278
+ (isSlowC[i] ? this.options.slow_step : 0) +
279
+ (isFastC[i] ? this.options.fastC_step : 0) +
280
+ (isFastD[i] ? this.options.fastD_step : 0);
281
+ }
282
+ velocities[i] = velocities[i - 1] + amount;
283
+ if (isMF[i]) {
284
+ if (velocities[i - 1] > this.options.welte_mf) {
285
+ if (amount < 0) {
286
+ velocities[i] = Math.max(this.options.welte_mf + eps, velocities[i]);
287
+ }
288
+ else {
289
+ velocities[i] = Math.min(this.options.welte_f, velocities[i]);
290
+ }
291
+ }
292
+ else if (velocities[i - 1] < this.options.welte_mf) {
293
+ if (amount > 0) {
294
+ velocities[i] = Math.min(this.options.welte_mf - eps, velocities[i]);
295
+ }
296
+ else {
297
+ velocities[i] = Math.max(this.options.welte_p, velocities[i]);
298
+ }
299
+ }
300
+ }
301
+ else {
302
+ // slow crescendo will only reach welte_loud
303
+ if (isSlowC[i] && !isFastC[i] && velocities[i - 1] < this.options.welte_loud) {
304
+ velocities[i] = Math.min(velocities[i], this.options.welte_loud - eps);
305
+ }
306
+ }
307
+ // regulating max and min
308
+ velocities[i] = Math.max(this.options.welte_p, velocities[i]);
309
+ velocities[i] = Math.min(this.options.welte_f, velocities[i]);
310
+ }
311
+ }
312
+ insertNote(event, pitch, velocity) {
313
+ this.midiEvents.push({
314
+ type: 'noteOn',
315
+ performs: event,
316
+ velocity,
317
+ at: event.assumedPhysicalTime[0],
318
+ pitch
319
+ });
320
+ this.midiEvents.push({
321
+ type: 'noteOff',
322
+ performs: event,
323
+ velocity: 127,
324
+ at: event.assumedPhysicalTime[1],
325
+ pitch
326
+ });
327
+ }
328
+ findEventsPerforming(id) {
329
+ return this.midiEvents.filter(event => event.performs.id === id);
330
+ }
331
+ asMIDI() {
332
+ const events = [];
333
+ this.midiEvents.sort((a, b) => a.at - b.at);
334
+ let currentTime = 0;
335
+ // insert metadata first
336
+ events.push({
337
+ type: 'meta',
338
+ subtype: 'text',
339
+ text: 'linked-rolls (based on midi2exp)',
340
+ deltaTime: 0
341
+ });
342
+ if (this.source) {
343
+ events.push({
344
+ type: 'meta',
345
+ subtype: 'text',
346
+ text: this.source,
347
+ deltaTime: 0
348
+ });
349
+ }
350
+ events.push({
351
+ type: 'meta',
352
+ subtype: 'text',
353
+ text: `place-time-conversion: ${this.placeTimeConversion.summary}`,
354
+ deltaTime: 0
355
+ });
356
+ for (const [key, value] of Object.entries(this.options)) {
357
+ events.push({
358
+ type: 'meta',
359
+ subtype: 'text',
360
+ text: `${key}=${value}`,
361
+ deltaTime: 0
362
+ });
363
+ }
364
+ events.push({
365
+ type: 'meta',
366
+ subtype: 'setTempo',
367
+ microsecondsPerBeat: 1000000,
368
+ deltaTime: 0
369
+ });
370
+ for (const event of this.midiEvents) {
371
+ const deltaTimeMs = (event.at - currentTime) * 1000;
372
+ if (event.type === 'noteOn') {
373
+ console.log('dealing with note on', event.pitch, event.at, deltaTimeMs);
374
+ events.push({
375
+ type: 'meta',
376
+ subtype: 'text',
377
+ deltaTime: deltaTimeMs,
378
+ text: event.performs.id
379
+ });
380
+ events.push({
381
+ type: 'channel',
382
+ subtype: 'noteOn',
383
+ noteNumber: event.pitch,
384
+ velocity: +event.velocity.toFixed(0),
385
+ deltaTime: 0,
386
+ channel: 0
387
+ });
388
+ }
389
+ else if (event.type === 'noteOff') {
390
+ events.push({
391
+ type: 'channel',
392
+ subtype: 'noteOff',
393
+ noteNumber: event.pitch,
394
+ velocity: 127,
395
+ deltaTime: deltaTimeMs,
396
+ channel: 0
397
+ });
398
+ }
399
+ else if (event.type === 'sustainPedalOn') {
400
+ events.push({
401
+ type: 'meta',
402
+ subtype: 'text',
403
+ deltaTime: deltaTimeMs,
404
+ text: event.performs.id
405
+ });
406
+ events.push({
407
+ type: 'channel',
408
+ subtype: 'controller',
409
+ controllerType: MIDIControlEvents.SUSTAIN,
410
+ deltaTime: 0,
411
+ channel: 0,
412
+ value: 127
413
+ });
414
+ }
415
+ else if (event.type === 'sustainPedalOff') {
416
+ events.push({
417
+ type: 'meta',
418
+ subtype: 'text',
419
+ deltaTime: deltaTimeMs,
420
+ text: event.performs.id
421
+ });
422
+ events.push({
423
+ type: 'channel',
424
+ subtype: 'controller',
425
+ controllerType: MIDIControlEvents.SUSTAIN,
426
+ deltaTime: 0,
427
+ channel: 0,
428
+ value: 0
429
+ });
430
+ }
431
+ else if (event.type === 'softPedalOn') {
432
+ events.push({
433
+ type: 'meta',
434
+ subtype: 'text',
435
+ deltaTime: deltaTimeMs,
436
+ text: event.performs.id
437
+ });
438
+ events.push({
439
+ type: 'channel',
440
+ subtype: 'controller',
441
+ controllerType: MIDIControlEvents.SOFT_PEDAL,
442
+ deltaTime: 0,
443
+ channel: 0,
444
+ value: 127
445
+ });
446
+ }
447
+ else if (event.type === 'softPedalOff') {
448
+ events.push({
449
+ type: 'meta',
450
+ subtype: 'text',
451
+ deltaTime: deltaTimeMs,
452
+ text: event.performs.id
453
+ });
454
+ events.push({
455
+ type: 'channel',
456
+ subtype: 'controller',
457
+ controllerType: MIDIControlEvents.SOFT_PEDAL,
458
+ deltaTime: 0,
459
+ channel: 0,
460
+ value: 0
461
+ });
462
+ }
463
+ currentTime = event.at;
464
+ }
465
+ return {
466
+ header: {
467
+ ticksPerBeat: 1000,
468
+ formatType: 0,
469
+ trackCount: 1
470
+ },
471
+ tracks: [events]
472
+ };
473
+ }
474
+ }
@@ -0,0 +1,37 @@
1
+ import { ConditionState } from "./ConditionState";
2
+ import { EditorialAssumption } from "./EditorialAssumption";
3
+ import { WithId } from "./WithId";
4
+ export interface FeatureCondition extends ConditionState<'missing-perforation' | 'damaged-perforation' | 'illegible'> {
5
+ }
6
+ export type FeatureConditionAssignment = EditorialAssumption<'conditionAssignment', FeatureCondition>;
7
+ export interface HorizontalSpan {
8
+ unit: 'mm';
9
+ from: number;
10
+ to: number;
11
+ }
12
+ export interface VerticalSpan {
13
+ unit: 'track';
14
+ from: number;
15
+ to?: number;
16
+ }
17
+ export interface RollFeature extends WithId {
18
+ /**
19
+ * IIIF region in string form.
20
+ */
21
+ annotates?: string;
22
+ horizontal: HorizontalSpan;
23
+ vertical: VerticalSpan;
24
+ /**
25
+ * Describes whether the event takes place
26
+ * on the verso or recto side of the roll.
27
+ * Since the same perforation is present on both
28
+ * sides, this property is left optional for now.
29
+ */
30
+ side?: 'verso' | 'recto';
31
+ /**
32
+ * This can be used e.g. to indicate a perforation
33
+ * which is torn out or in any other way damaged.
34
+ */
35
+ condition?: FeatureConditionAssignment;
36
+ }
37
+ export declare const isRollFeature: (obj: object) => obj is RollFeature;
package/lib/Feature.js ADDED
@@ -0,0 +1,3 @@
1
+ export const isRollFeature = (obj) => {
2
+ return 'horizontal' in obj && 'vertical' in obj;
3
+ };
@@ -0,0 +1,9 @@
1
+ import { WithId } from "./WithId";
2
+ /**
3
+ * Based on D11 Digital Measurement Event and D10 Software Execution
4
+ */
5
+ export interface RollMeasurement extends WithId {
6
+ actor?: string;
7
+ software: string;
8
+ date: string;
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,65 @@
1
+ export declare abstract class PlaceTimeConversion {
2
+ abstract get summary(): string;
3
+ abstract placeToTime(x1: number): number;
4
+ abstract timeToPlace(t1: number): number;
5
+ }
6
+ export declare class NoAccelerationConversion implements PlaceTimeConversion {
7
+ get summary(): string;
8
+ metersPerMinute: number;
9
+ /**
10
+ * Converts physical place (in cm) to time (in seconds).
11
+ * @param x1 - The distance in mm.
12
+ * @returns Time in seconds.
13
+ */
14
+ placeToTime(cm: number): number;
15
+ /**
16
+ * Converts time (in seconds) to physical place (in cm).
17
+ * @param t1 - The time in seconds.
18
+ * @returns Distance in cm.
19
+ */
20
+ timeToPlace(t1: number): number;
21
+ }
22
+ declare enum SpeedUnit {
23
+ MetersPerMinute = 0,
24
+ FeetPerMinute = 1
25
+ }
26
+ declare enum AccelerationUnit {
27
+ MillimetersPerSecondSquared = 0,
28
+ FeetPerMinuteSquared = 1
29
+ }
30
+ export declare class KinematicConversion implements PlaceTimeConversion {
31
+ get summary(): string;
32
+ static readonly slowSpeed = 9.46;
33
+ static readonly normalSpeed = 9.85;
34
+ static readonly stanfordAcceleration = 0.3147;
35
+ static readonly baertschAcceleration = 0.1772;
36
+ private feetPerMinute;
37
+ private acceleration;
38
+ constructor(feetPerMinute?: number, acceleration?: number);
39
+ setSpeed(speed: number, unit: SpeedUnit): void;
40
+ setAcceleration(acceleration: number, unit: AccelerationUnit): void;
41
+ /**
42
+ * Converts physical place (in cm) to time (in seconds).
43
+ * @param x1 - The distance in mm.
44
+ * @returns Time in seconds.
45
+ */
46
+ placeToTime(cm: number): number;
47
+ /**
48
+ * Converts time (in seconds) to physical place (in cm).
49
+ * @param t1 - The time in seconds.
50
+ * @returns Distance in cm.
51
+ */
52
+ timeToPlace(t1: number): number;
53
+ }
54
+ export declare class GottschewskiConversion implements PlaceTimeConversion {
55
+ get summary(): string;
56
+ paperThickness: number;
57
+ initialCircumference: number;
58
+ secondsPerTurn: number;
59
+ /**
60
+ * @param x1 in centimeters
61
+ */
62
+ placeToTime(x1: number): number;
63
+ timeToPlace(t1: number): number;
64
+ }
65
+ export {};