@xromdev/notation 0.0.0-stage → 0.1.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.
@@ -0,0 +1,475 @@
1
+ /**
2
+ * A track as a SCORE: each pitched channel on a grand staff, the noise channel
3
+ * on a percussion staff, and the dynamics its volumes imply.
4
+ *
5
+ * Built on `./notation`, so a bar here is spelled exactly the way a single
6
+ * scrolling staff spells it — same bar line, same phase, same
7
+ * note values. What this file adds is the part a page of music needs and a
8
+ * single strip does not: which of two staves a note goes on, and what the
9
+ * volume column says in the words a player reads.
10
+ */
11
+ import { type BarGrid, type OddBar, type StaffItem, type TickNote } from './notation.js';
12
+ /**
13
+ * Middle C: in a beam group kept on the bass, the heads from here up still go
14
+ * onto the treble and the beam crosses to them — see `crossStaffVoice`.
15
+ */
16
+ export declare const GRAND_STAFF_SPLIT = 60;
17
+ export declare function splitGrandStaff<T extends {
18
+ midi: number;
19
+ }>(notes: readonly T[], split?: number): {
20
+ treble: T[];
21
+ bass: T[];
22
+ };
23
+ /** A beam group that never goes below E3 — three ledger lines under the treble — is written on the treble. */
24
+ export declare const TREBLE_FLOOR = 52;
25
+ /**
26
+ * A grand-staff part as ONE voice, each item saying which of the two staves it
27
+ * stands on.
28
+ *
29
+ * Decided per BEAM GROUP — the beamed notes of one beat, or a note on its own —
30
+ * because a beam is what a reader follows:
31
+ *
32
+ * - a group that never goes below E3 (`TREBLE_FLOOR`) is on the treble, E3
33
+ * included. Ragnarok's canyon, pulse 1, bar 29, the third beat: A3 G3 C4 A3
34
+ * E4 C4 G4 E4 — a reader wanted it all on the treble.
35
+ * - a group that does go below E3 stays on the bass, E3s and all — bar 29's
36
+ * second beat, E3 G3 C3 E3…, which "would be ugly otherwise". Only its heads
37
+ * from middle C up cross to the treble, and the beam crosses with them — the
38
+ * piano's cross-staff writing, drawn as one beam between the
39
+ * staves with no rest on either side. Bar 30's lone G5 among B2s is that case.
40
+ *
41
+ * Every rule tried per BAR before this failed on a bar of this music: a bar
42
+ * that starts low and climbs three octaves has a bass half and a treble half,
43
+ * and the only choices a whole bar has are to tear its beams with rests or put
44
+ * half of it on four ledger lines.
45
+ *
46
+ * A piece tied on from the head before it stays where that head stood; a rest
47
+ * stands where the head before it in the bar did (else the first head after
48
+ * it), and a bar with no heads at all is the treble's, so the bass shows its
49
+ * own bar rest rather than a second one.
50
+ */
51
+ export declare function crossStaffVoice(bars: readonly (readonly ScoreItem[])[]): ScoreItem[][];
52
+ /** The highest a part may reach and still be written on the bass staff alone: E4, two ledger lines up. */
53
+ export declare const BASS_ONLY_MAX = 64;
54
+ /** The lowest a part may reach and still be written on the treble staff alone: G3, two ledger lines down. */
55
+ export declare const TREBLE_ONLY_MIN = 55;
56
+ /**
57
+ * The staves a part needs: one when every note it plays sits within two ledger
58
+ * lines of a single staff, both otherwise.
59
+ *
60
+ * A grand staff whose other half is a whole track of rests is furniture: the
61
+ * triangle carries the bass in every one of the twenty tracks, and in
62
+ * Ragnarok's canyon it reaches D#4 at most — a ledger line and a half above the
63
+ * bass staff. Where both single staves would do, the part's middle decides.
64
+ */
65
+ export declare function partStaves(notes: readonly {
66
+ midi: number;
67
+ }[]): ('treble' | 'bass')[];
68
+ export type Dynamic = 'pp' | 'p' | 'mp' | 'mf' | 'f' | 'ff';
69
+ /**
70
+ * The APU's 0..15 volume in six steps.
71
+ *
72
+ * A READING, not a fact: the nibble is linear in output level and a dynamic is
73
+ * a word about loudness, so the steps are even in the nibble and nothing more
74
+ * is claimed for them.
75
+ */
76
+ export declare function dynamicOf(volume: number): Dynamic;
77
+ /** A change of level closer than this, in ticks, is folded into the mark before it. A quarter note. */
78
+ export declare const DYNAMIC_HOLD = 16;
79
+ /** The words a mark can carry after its level: a figure's shape, or "the same again". */
80
+ export type DynamicWords = 'dim.' | 'cresc.' | 'sim.';
81
+ export interface DynamicMark {
82
+ tick: number;
83
+ dynamic: Dynamic;
84
+ /**
85
+ * How the figure goes from here: `dim.` and `cresc.` are a hairpin after the
86
+ * level, `sim.` is the word alone — the level is the figure's own — with a
87
+ * dashed line for as long as it holds.
88
+ */
89
+ words?: DynamicWords;
90
+ /** With `words`: the tick of the last note the hairpin or the `sim.` covers. */
91
+ until?: number; /**
92
+ * A hairpin from a level the reader is already at: the hairpin alone, no
93
+ * letter — ragnarok's 7 7 4 2, an mp going on from the mp before it.
94
+ */
95
+ bare?: boolean;
96
+ }
97
+ /** Onset to onset, notes closer than this can make one shaped figure. An eighth note. */
98
+ export declare const FIGURE_GAP = 8;
99
+ /**
100
+ * And no closer than this, a sixteenth. Faster is one note's envelope struck
101
+ * again and again — Arctic Caverns' 8 4 2 1 in thirty-seconds on one pitch, an
102
+ * echo — not a figure a player shapes.
103
+ */
104
+ export declare const FIGURE_STEP = 4;
105
+ /** A run of notes whose level only falls, or only rises: `[from, to]` are indices, inclusive. */
106
+ export interface ShapedFigure {
107
+ from: number;
108
+ to: number;
109
+ words: 'dim.' | 'cresc.';
110
+ }
111
+ /**
112
+ * Runs of at least three notes, each `FIGURE_STEP` to `FIGURE_GAP` after the one before, whose
113
+ * level moves one way every step and by two or more in all — the 4 3 2 1 under
114
+ * every beat of a fading figure. The six steps of `dynamicOf` cannot show that:
115
+ * 4 and 3 are both p, and the hold folds the pp of 2 and 1 back into it.
116
+ *
117
+ * `notes` must be in order of start.
118
+ */
119
+ export declare function shapedFigures(notes: readonly {
120
+ start: number;
121
+ volume: number;
122
+ }[], gap?: number): ShapedFigure[];
123
+ /**
124
+ * Where a voice's level changes, as the marks a score prints.
125
+ *
126
+ * Only at a change, and never two within `DYNAMIC_HOLD`: the driver can move a
127
+ * volume on every note, and a mark under every head is noise. Inside the hold
128
+ * the LOUDER level stands — the accent is what a reader has to see — and a
129
+ * change that comes straight back to the level before it is dropped.
130
+ *
131
+ * A shaped figure (`shapedFigures`) is written as its level and a hairpin under
132
+ * the first, `sim.` under the next one just like it, its dashes running on over
133
+ * the ones after that, until some other mark is printed. A figure that turns straight
134
+ * into one going the other way — wookie hole's 6 4 2 1 2 4 6 8 on one held
135
+ * note — is a level swaying, not a figure, and is read note by note as before.
136
+ * After a hairpin the reader is where it ends, so going back to where it began
137
+ * is written — ragnarok's mp over the 7 after 7 4 2 1 — unless a `sim.` that
138
+ * goes on already says the figure comes round again.
139
+ */
140
+ export declare function dynamicMarks(notes: readonly {
141
+ start: number;
142
+ volume: number;
143
+ }[], hold?: number): DynamicMark[];
144
+ /** A noise period as a VexFlow key on the percussion staff. Only the low nibble is the period. */
145
+ export declare function noiseKey(period: number): string;
146
+ /** A pitched note, with the volume it starts at when the channel has one. */
147
+ export interface ScoreNote extends TickNote {
148
+ volume?: number;
149
+ /** The note's pitch curve — `[position 0..1, semitones]` — as a piano roll draws it. */
150
+ bend?: readonly (readonly [number, number])[];
151
+ /** Grace notes in front of it, as MIDI numbers in the order they are played. */
152
+ grace?: readonly number[];
153
+ /** A repeat of the note before, quieter — an echo, written in brackets (`echoNotes`). */
154
+ echo?: boolean;
155
+ /**
156
+ * Played short: its `ticks` are the value it is WRITTEN as, and it sounds for
157
+ * less — a staccato dot over the head instead of a rest after it.
158
+ */
159
+ staccato?: boolean;
160
+ }
161
+ /** What a pitch curve is written as. `ticks` is the whole note's length, over which it moves. */
162
+ export type PitchEffect = {
163
+ kind: 'slide';
164
+ /** Where it arrives, in semitones from the written pitch; to a tenth. */
165
+ semitones: number;
166
+ /** Where along the note the movement begins, 0..1. */
167
+ from: number;
168
+ ticks: number;
169
+ /**
170
+ * It lands on the next written note. When it does not — a sweep too wide to be a bend that
171
+ * ends on no note (ragnarok's canyon, triangle, bar 15: E3 down to B2, then a D3) — the
172
+ * staff draws where it lands as a small note in brackets. Set by `effectsOf`.
173
+ */
174
+ arrives?: boolean;
175
+ } | {
176
+ /** The pitch moves on the note it started on — a guitarist's bend, or its release downwards. */
177
+ kind: 'bend';
178
+ semitones: number;
179
+ from: number;
180
+ ticks: number;
181
+ } | {
182
+ kind: 'vibrato';
183
+ depth: number;
184
+ ticks: number;
185
+ /**
186
+ * The curve itself, `[position 0..1, semitones]`, kept for a vibrato wider than a semitone:
187
+ * a wave glyph says nothing of a swing like Turbo Tunnel Race's, bar 31, a D6 going up four
188
+ * semitones and down two and a half, so the staff draws the curve itself.
189
+ */
190
+ curve?: readonly (readonly [number, number])[];
191
+ };
192
+ /** A vibrato swinging further than this, in semitones, is drawn as its curve rather than a wave. */
193
+ export declare const WIDE_VIBRATO = 1;
194
+ /**
195
+ * A movement smaller than this, in semitones, is not written at all.
196
+ *
197
+ * 261 of the cartridge's 304 curves are a drift of a fifth of a semitone at the
198
+ * end of a note. The roll draws them as a hairline, which is right for a picture
199
+ * of the sound; on a staff a mark on every one of them would be noise over a
200
+ * third of the notes of some tracks.
201
+ */
202
+ export declare const DRIFT_LIMIT = 0.5;
203
+ /**
204
+ * A note's pitch curve read as notation: a slide to where it arrives, a
205
+ * vibrato, or nothing.
206
+ *
207
+ * Over the twenty tracks that is 33 slides (one to four semitones), 10 vibratos,
208
+ * and the drifts left out — the same split the Battletoads music tooling
209
+ * makes between a slide and a vibrato.
210
+ */
211
+ /** How far into a note a strike may reach and still be read as its attack, 0..1. */
212
+ /**
213
+ * Alien 3's kick takes three frames of a seventeen-frame bass note — 18% — and at 15% the
214
+ * vibrato after it was still read with the kick in it.
215
+ */
216
+ export declare const STRIKE_SHARE = 0.25;
217
+ export declare function pitchEffect(whole: readonly (readonly [number, number])[], ticks: number): PitchEffect | null;
218
+ /** The most a note's pitch may move on its own and still be a bend: a tone and a half. */
219
+ export declare const BEND_MAX = 3;
220
+ /**
221
+ * Each note's effect, read against the note AFTER it in the part.
222
+ *
223
+ * A curve does not say whether the pitch is sliding somewhere or bending on the
224
+ * spot; the music around it does. A slide that ends on the pitch the very next
225
+ * note is written at arrives in that note — a glissando, as in the title music's
226
+ * G4 up to A4. One that goes nowhere written is the note itself bending:
227
+ * ragnarok's canyon, pulse 1, bar 5, a D#4 pulled up 1.3 semitones and then left
228
+ * for an A3 — a guitarist's bend, which a reader said at once, where "gliss." had
229
+ * been printed. Past `BEND_MAX` nothing bends that far, and the sweeps of fifteen
230
+ * to twenty-eight semitones that open a few tracks stay lines.
231
+ *
232
+ * Except when the note after it comes straight back to the pitch the curve left:
233
+ * that is a bend and its release, however far it went. Clinger Winger, pulse 1,
234
+ * an E2 pushed up six and a half semitones over four bars and then struck again
235
+ * as E2 — a reader heard a bend where a line marked "gliss." had been drawn.
236
+ * Across the whole ROM this reads that one note differently and no other.
237
+ */
238
+ export declare function effectsOf(notes: readonly ScoreNote[]): Map<number, PitchEffect>;
239
+ /**
240
+ * A bend's size, in semitones, to one decimal — the arrow says which way.
241
+ *
242
+ * Always the number. The guitar's words (½ for a semitone, "full" for a tone)
243
+ * were printed for sizes near a step and the number for the rest, so one page
244
+ * said "½" over a bend of 0.9 semitones and "1.3" over the next: two systems
245
+ * side by side, and a "½" read as half a semitone.
246
+ */
247
+ export declare function bendLabel(semitones: number): string;
248
+ /** The pitch movement a tied piece carries on from the head of its note. */
249
+ export interface EffectCarry {
250
+ /** Where the note starts, and the pitch it is written at. */
251
+ start: number;
252
+ midi: number;
253
+ effect: PitchEffect;
254
+ }
255
+ /** A staff item, with the pitch effect of the note it is the head of. */
256
+ export type ScoreItem = StaffItem & {
257
+ effect?: PitchEffect;
258
+ /**
259
+ * On a piece tied on after the head: the movement it is part of, when that movement is drawn
260
+ * along the note — a glissando or a bend held a bar or more — so a line that runs onto the next
261
+ * system can be carried on there and land where the note ends.
262
+ */
263
+ carry?: EffectCarry;
264
+ /** On a grand staff's voice: the stave the item stands on — see `crossStaffVoice`. */
265
+ staff?: 'treble' | 'bass';
266
+ /** The grace notes of the note this is the head of — see `ScoreNote.grace`. */
267
+ grace?: readonly number[];
268
+ /** The note is leaned on — see `accentedStarts`. */
269
+ accent?: boolean;
270
+ /** The note is an echo — see `ScoreNote.echo`. Its head is written in brackets. */
271
+ echo?: boolean;
272
+ /** The note is played short — see `ScoreNote.staccato`. A dot over its head. */
273
+ staccato?: boolean;
274
+ /**
275
+ * The other heads on this one's stem, struck at the same moment: on a percussion staff, drums by
276
+ * period — a cartridge plays its noise channel and its DMC samples at once, a hat over a kick; on
277
+ * a pitched staff, notes by MIDI number — a violin's double and triple stops.
278
+ */
279
+ chord?: readonly number[];
280
+ /**
281
+ * The APU level the note STARTS at, 0..15, as the ROM holds it — for a renderer to print under
282
+ * the head when asked. The dynamics are a reading of these numbers in six steps, which is what a
283
+ * player needs; the number itself is what the cartridge says, and the two answer different
284
+ * questions. Only on a head, and only where the channel has a volume at all: the triangle has
285
+ * none, so its notes carry nothing.
286
+ */
287
+ volume?: number;
288
+ /** Its beam runs across the bar line — see `crossBarRuns`. */
289
+ across?: 'start' | 'join';
290
+ /** Beams are grouped by this number rather than by the beat — see `accentBeamGroups`. */
291
+ beamGroup?: number;
292
+ };
293
+ /**
294
+ * How much louder than BOTH its neighbours a note has to start to be written as
295
+ * accented, in nibble steps.
296
+ *
297
+ * Three is the step the tracks themselves use: the driver holds a level and
298
+ * drops or lifts the next note by 3 — ragnarok's canyon, bar 25, alternates 4
299
+ * and 7 through the bar, and 7 against 4 is what the ear hears as the accent.
300
+ */
301
+ export declare const ACCENT_STEP = 3;
302
+ /**
303
+ * The notes a voice leans on: louder than the note before it by `ACCENT_STEP`,
304
+ * no quieter than the note after it, and NOT on a beat.
305
+ *
306
+ * Off the beat is the whole point. The driver moves the volume constantly, and
307
+ * a mark on every rise would put one under a third of the heads of some tracks
308
+ * while saying nothing a reader cannot see from the dynamics. What a reader
309
+ * cannot see is a voice that leans between the beats: ragnarok's canyon, bar 25,
310
+ * plays sixteenths at 9 9 7 7 4 7 4 7 4 2 7 7 4 7 4 9 — every beat of the bar
311
+ * but the first is a 4, and the 7s fall in the gaps. On paper that is an even
312
+ * run of sixteenths; in the ears it is a syncopation, and accents are what make
313
+ * the two agree.
314
+ *
315
+ * Read on the notes as the staff has them — after `voicePhase` has taken out a
316
+ * channel's authored delay — or a voice written a tick late would count as
317
+ * off the beat throughout.
318
+ */
319
+ export declare function accentedStarts(notes: readonly ScoreNote[], beat?: number, step?: number): Set<number>;
320
+ /**
321
+ * Beam groups that follow the ACCENTS rather than the beat, for a passage that
322
+ * is written in one pulse and played in another.
323
+ *
324
+ * Ragnarok's canyon from bar 25 is the case, and it is a case, not a rule:
325
+ * beats 2, 3 and 4 of every bar sit at volume 4 while the notes between them
326
+ * are at 7, so beaming by the quarter draws four even groups over a bar whose
327
+ * weight lands in five uneven ones — 3 2 3 3 2, each beginning on a note the
328
+ * ROM leans on. Tried as a general rule over the cartridge it made beams of 14,
329
+ * 16 and 32 heads elsewhere (wookie hole, Arctic Caverns), which is why the
330
+ * passage asks for it by tick.
331
+ *
332
+ * Numbers a group per head from `from` on: a new one at every accent, and one
333
+ * after the bar's LOUDEST head when what follows is quieter — the figure's own
334
+ * peak, which ends a group rather than joining the run under it. Bar 25 is the
335
+ * one that needs the second rule: bars 26 to 28 open on the two heads a beam
336
+ * has already carried over the bar line, while 25 opens on the same pair with
337
+ * nothing to carry them, and without it they were swallowed by the five heads
338
+ * up to the first accent.
339
+ */
340
+ export declare function accentBeamGroups(bars: ScoreItem[][],
341
+ /** The passage the rule covers, in the staff's ticks: `[from, to)`. */
342
+ { from, to }: {
343
+ from: number;
344
+ to: number;
345
+ },
346
+ /** Each head's volume by its start tick — the levels the groups are read from. */
347
+ levels: ReadonlyMap<number, number>): ScoreItem[][];
348
+ /** The most notes a beam is carried across a bar line onto — the figure, and no more. */
349
+ export declare const CROSS_BAR_RUN = 4;
350
+ /**
351
+ * Figures a bar line cuts in half: a run that starts on the bar's last note and
352
+ * carries the same level into the next bar.
353
+ *
354
+ * Beams do not cross bar lines, and for good reason — the bar line is what a
355
+ * reader counts from. The exception earns itself when the figure is plainly one
356
+ * gesture and the bar line falls inside it: ragnarok's canyon, bars 25 to 28,
357
+ * ends each bar on an accented E3 and opens the next with D3 E3 at the same
358
+ * level 9, the run around it sitting at 7 and 4. Three heads, one gesture, and
359
+ * written bar by bar it reads as a stray sixteenth and a pair.
360
+ *
361
+ * Narrow on purpose: the last note must be ACCENTED (see `accentedStarts`), the
362
+ * run must be unbroken, every note must hold the same volume, and it stops after
363
+ * `CROSS_BAR_RUN` heads. Over the whole cartridge that is three places, all of
364
+ * them this figure. Loosened to "the level holds" alone it caught 148, some of
365
+ * them 240 notes long — a beam over half a track.
366
+ *
367
+ * Returns the start tick of each note in a crossing run, mapped to its part in
368
+ * it: the `start` is the note the beam leaves the bar on, the `join`s are the
369
+ * heads it reaches on the other side.
370
+ */
371
+ export declare function crossBarRuns(notes: readonly ScoreNote[], grid: BarGrid, accents?: ReadonlySet<number>): Map<number, 'start' | 'join'>;
372
+ /** Whether an effect is drawn along its note — and so has to carry on where the note does. */
373
+ export declare function drawnAlong(effect: PitchEffect, measureTicks?: number): boolean;
374
+ /** A noise hit: when, for how long, and which `$400E` period. */
375
+ export interface ScoreHit {
376
+ start: number;
377
+ ticks: number;
378
+ period: number;
379
+ /** The APU level the hit starts at, 0..15 — see `ScoreItem.volume`. */
380
+ volume?: number;
381
+ }
382
+ export type ScoreStaveKind = 'treble' | 'bass' | 'percussion';
383
+ export interface ScoreStave {
384
+ partId: string;
385
+ kind: ScoreStaveKind;
386
+ /**
387
+ * One list of items per bar. Filled to the bar line — except on a grand
388
+ * staff, where it is only what stands on THIS stave, for the layout.
389
+ */
390
+ bars: ScoreItem[][];
391
+ /** On a grand staff's upper stave: the part's whole voice, filled to the bar line, drawn across both. */
392
+ voiceBars?: ScoreItem[][];
393
+ /** On a grand staff's lower stave: its notes belong to the voice of the stave above. */
394
+ follows?: boolean;
395
+ }
396
+ export interface ScoreModel {
397
+ /** Ticks added to the piece's clock to get the score's — see `staffShift`. */
398
+ shift: number;
399
+ /** Where the bar lines fall: the metre, and the opening bar's own length. */
400
+ grid: BarGrid;
401
+ barCount: number;
402
+ staves: ScoreStave[];
403
+ /** Each part's marks, in the SCORE's ticks. */
404
+ dynamics: Record<string, DynamicMark[]>;
405
+ /**
406
+ * Each part's own delay taken out (`voicePhase`), in ticks: its notes sit
407
+ * this much EARLIER on the staff than on the piece's clock. Anything that
408
+ * compares a staff tick with the piece's — hiding what has not been read
409
+ * yet — has to take it out too.
410
+ */
411
+ phases: Record<string, number>;
412
+ }
413
+ /** Where a piece changes key: the tick the new key starts on, and its VexFlow name. */
414
+ export interface KeyChange {
415
+ /** In the PIECE's ticks, as the ROM holds them. */
416
+ tick: number;
417
+ key: string;
418
+ }
419
+ /**
420
+ * The key each bar of a score is written in.
421
+ *
422
+ * A change takes effect from the bar its tick falls in — the tick is moved onto
423
+ * the staff's clock by `shift` first — so it stays with the music when the bar
424
+ * line or the metre is read differently. Volkmire's Inferno Race turns from D
425
+ * minor to D major on tick 870, which is bar 29 of its 2/4 score.
426
+ */
427
+ export declare function barKeys(barCount: number, shift: number, grid: BarGrid, opening: string, changes?: readonly KeyChange[]): string[];
428
+ /** The part id the percussion staff carries. */
429
+ export declare const DRUMS_PART = "drums";
430
+ /** How a score is barred and read — everything `buildScore` takes beyond the notes. */
431
+ export interface ScoreOptions {
432
+ /** The tick the bar lines are counted from. Default 0. */
433
+ offset?: number;
434
+ /** Ticks in a bar: 64 is 4/4, 32 is 2/4. Default `MEASURE_TICKS`. */
435
+ measureTicks?: number;
436
+ /**
437
+ * Write the pickup as part of the opening bar rather than in a bar of its own.
438
+ *
439
+ * The music then starts on the score's first tick, and the opening bar is as
440
+ * much longer than the metre as the pickup is — one bar of 19/32 in front of
441
+ * Volkmire's Inferno Race's 2/4, instead of a bar of rests with the run in it.
442
+ */
443
+ mergePickup?: boolean;
444
+ /**
445
+ * The passage read by its accents: the only place accents are marked (`accentedStarts`), and
446
+ * where the beams follow them rather than the beat (`accentBeamGroups`). None given, no accents.
447
+ * In the PIECE's ticks, like everything a caller gives; `shift` moves it onto the staff's clock.
448
+ */
449
+ accentBeams?: {
450
+ from: number;
451
+ to: number;
452
+ };
453
+ /** Bars later in the piece with a length of their own — see `BarGrid`. */
454
+ oddBars?: readonly OddBar[];
455
+ /**
456
+ * Take a part's own delay of up to `MAX_PHASE` ticks out (`voicePhase`). Default true: a sound
457
+ * driver delays a channel a tick or two on purpose, and the staff writes it on the beat. Music
458
+ * that is already on its beat — a MIDI file — wants it off, or a voice is moved off the beat it
459
+ * keeps.
460
+ */
461
+ alignVoices?: boolean;
462
+ }
463
+ /**
464
+ * The whole score, worked out once.
465
+ *
466
+ * `options.offset` is the tick the bar lines are counted from and
467
+ * `options.measureTicks` the length of a bar; any other notation view of the
468
+ * same piece should use the same two, so they all bar the music the same way.
469
+ */
470
+ export declare function buildScore(parts: readonly {
471
+ id: string;
472
+ notes: readonly ScoreNote[];
473
+ /** Which staves, when the caller decides rather than the notes (`partStaves`). */
474
+ staves?: readonly ('treble' | 'bass')[];
475
+ }[], drums: readonly ScoreHit[], totalTicks: number, { offset, measureTicks, mergePickup, accentBeams, oddBars, alignVoices, }?: ScoreOptions): ScoreModel;