@sudobility/music_types 0.11.30 → 0.11.32

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 (251) hide show
  1. package/dist/domain/commands/edit-commands.d.ts +3 -3
  2. package/dist/domain/commands/edit-commands.d.ts.map +1 -1
  3. package/dist/domain/commands/edit-commands.js +25 -25
  4. package/dist/domain/commands/edit-commands.js.map +1 -1
  5. package/dist/domain/commands/history.d.ts +32 -0
  6. package/dist/domain/commands/history.d.ts.map +1 -0
  7. package/dist/domain/commands/history.js +63 -0
  8. package/dist/domain/commands/history.js.map +1 -0
  9. package/dist/domain/commands/note-commands.d.ts +9 -12
  10. package/dist/domain/commands/note-commands.d.ts.map +1 -1
  11. package/dist/domain/commands/note-commands.js +42 -72
  12. package/dist/domain/commands/note-commands.js.map +1 -1
  13. package/dist/domain/commands/note-marks.d.ts +171 -0
  14. package/dist/domain/commands/note-marks.d.ts.map +1 -0
  15. package/dist/domain/commands/note-marks.js +427 -0
  16. package/dist/domain/commands/note-marks.js.map +1 -0
  17. package/dist/domain/commands/reflow.d.ts +1 -1
  18. package/dist/domain/commands/reflow.js +17 -17
  19. package/dist/domain/commands/reflow.js.map +1 -1
  20. package/dist/domain/commands/region-commands.d.ts +4 -4
  21. package/dist/domain/commands/region-commands.d.ts.map +1 -1
  22. package/dist/domain/commands/region-commands.js +7 -7
  23. package/dist/domain/commands/region-commands.js.map +1 -1
  24. package/dist/domain/commands/relocate-commands.d.ts +3 -3
  25. package/dist/domain/commands/relocate-commands.js +15 -15
  26. package/dist/domain/commands/relocate-commands.js.map +1 -1
  27. package/dist/domain/commands/ripple-commands.d.ts +2 -2
  28. package/dist/domain/commands/ripple-commands.js +13 -13
  29. package/dist/domain/commands/ripple-commands.js.map +1 -1
  30. package/dist/domain/commands/snapshot.d.ts +3 -3
  31. package/dist/domain/commands/snapshot.js +5 -5
  32. package/dist/domain/commands/snapshot.js.map +1 -1
  33. package/dist/domain/commands/structure-commands.d.ts +86 -5
  34. package/dist/domain/commands/structure-commands.d.ts.map +1 -1
  35. package/dist/domain/commands/structure-commands.js +272 -36
  36. package/dist/domain/commands/structure-commands.js.map +1 -1
  37. package/dist/domain/commands/track-commands.d.ts +2 -2
  38. package/dist/domain/commands/track-commands.js +7 -7
  39. package/dist/domain/commands/track-commands.js.map +1 -1
  40. package/dist/domain/commands/types.d.ts +2 -2
  41. package/dist/domain/generation/replacement-region.d.ts +32 -0
  42. package/dist/domain/generation/replacement-region.d.ts.map +1 -0
  43. package/dist/domain/generation/replacement-region.js +79 -0
  44. package/dist/domain/generation/replacement-region.js.map +1 -0
  45. package/dist/domain/instruments/gm-icon.d.ts +12 -0
  46. package/dist/domain/instruments/gm-icon.d.ts.map +1 -0
  47. package/dist/domain/instruments/gm-icon.js +327 -0
  48. package/dist/domain/instruments/gm-icon.js.map +1 -0
  49. package/dist/domain/instruments/gm-kit.js +9 -9
  50. package/dist/domain/instruments/gm-kit.js.map +1 -1
  51. package/dist/domain/instruments/gm-percussion.js +48 -48
  52. package/dist/domain/instruments/gm-percussion.js.map +1 -1
  53. package/dist/domain/instruments/gm-polyphony.js +6 -6
  54. package/dist/domain/instruments/gm-range.js +6 -6
  55. package/dist/domain/instruments/gm-transposition.js +1 -1
  56. package/dist/domain/instruments/gm.d.ts +1 -1
  57. package/dist/domain/instruments/gm.js +161 -161
  58. package/dist/domain/instruments/gm.js.map +1 -1
  59. package/dist/domain/instruments/icon-art.d.ts +75 -0
  60. package/dist/domain/instruments/icon-art.d.ts.map +1 -0
  61. package/dist/domain/instruments/icon-art.js +93 -0
  62. package/dist/domain/instruments/icon-art.js.map +1 -0
  63. package/dist/domain/instruments/instrument-fit.d.ts +31 -0
  64. package/dist/domain/instruments/instrument-fit.d.ts.map +1 -0
  65. package/dist/domain/instruments/instrument-fit.js +117 -0
  66. package/dist/domain/instruments/instrument-fit.js.map +1 -0
  67. package/dist/domain/instruments/instrument-options.d.ts +62 -0
  68. package/dist/domain/instruments/instrument-options.d.ts.map +1 -0
  69. package/dist/domain/instruments/instrument-options.js +69 -0
  70. package/dist/domain/instruments/instrument-options.js.map +1 -0
  71. package/dist/domain/instruments/track-instrument.d.ts +80 -0
  72. package/dist/domain/instruments/track-instrument.d.ts.map +1 -0
  73. package/dist/domain/instruments/track-instrument.js +102 -0
  74. package/dist/domain/instruments/track-instrument.js.map +1 -0
  75. package/dist/domain/notation/chord-symbol.d.ts +26 -0
  76. package/dist/domain/notation/chord-symbol.d.ts.map +1 -0
  77. package/dist/domain/notation/chord-symbol.js +32 -0
  78. package/dist/domain/notation/chord-symbol.js.map +1 -0
  79. package/dist/domain/notation/lyric-syllables.d.ts +15 -0
  80. package/dist/domain/notation/lyric-syllables.d.ts.map +1 -0
  81. package/dist/domain/notation/lyric-syllables.js +15 -0
  82. package/dist/domain/notation/lyric-syllables.js.map +1 -0
  83. package/dist/domain/notation/music-vocabulary.d.ts +59 -0
  84. package/dist/domain/notation/music-vocabulary.d.ts.map +1 -0
  85. package/dist/domain/notation/music-vocabulary.js +164 -0
  86. package/dist/domain/notation/music-vocabulary.js.map +1 -0
  87. package/dist/domain/pitch/pitch.d.ts +1 -1
  88. package/dist/domain/pitch/pitch.js +29 -29
  89. package/dist/domain/pitch/transpose.d.ts +1 -1
  90. package/dist/domain/pitch/transpose.js +2 -2
  91. package/dist/domain/quantization/quantize.d.ts +2 -2
  92. package/dist/domain/quantization/quantize.js +9 -9
  93. package/dist/domain/quantization/quantize.js.map +1 -1
  94. package/dist/domain/score/articulation.d.ts +56 -0
  95. package/dist/domain/score/articulation.d.ts.map +1 -0
  96. package/dist/domain/score/articulation.js +56 -0
  97. package/dist/domain/score/articulation.js.map +1 -0
  98. package/dist/domain/score/bar-numbers.d.ts +38 -0
  99. package/dist/domain/score/bar-numbers.d.ts.map +1 -0
  100. package/dist/domain/score/bar-numbers.js +49 -0
  101. package/dist/domain/score/bar-numbers.js.map +1 -0
  102. package/dist/domain/score/collapse-rests.d.ts +23 -0
  103. package/dist/domain/score/collapse-rests.d.ts.map +1 -0
  104. package/dist/domain/score/collapse-rests.js +78 -0
  105. package/dist/domain/score/collapse-rests.js.map +1 -0
  106. package/dist/domain/score/cue-notes.d.ts +24 -0
  107. package/dist/domain/score/cue-notes.d.ts.map +1 -0
  108. package/dist/domain/score/cue-notes.js +105 -0
  109. package/dist/domain/score/cue-notes.js.map +1 -0
  110. package/dist/domain/score/dynamics.d.ts +62 -0
  111. package/dist/domain/score/dynamics.d.ts.map +1 -0
  112. package/dist/domain/score/dynamics.js +142 -0
  113. package/dist/domain/score/dynamics.js.map +1 -0
  114. package/dist/domain/score/effective-clef.d.ts +42 -0
  115. package/dist/domain/score/effective-clef.d.ts.map +1 -0
  116. package/dist/domain/score/effective-clef.js +39 -0
  117. package/dist/domain/score/effective-clef.js.map +1 -0
  118. package/dist/domain/score/extract-part.d.ts +10 -0
  119. package/dist/domain/score/extract-part.d.ts.map +1 -0
  120. package/dist/domain/score/extract-part.js +44 -0
  121. package/dist/domain/score/extract-part.js.map +1 -0
  122. package/dist/domain/score/factory.d.ts +1 -1
  123. package/dist/domain/score/factory.js +12 -12
  124. package/dist/domain/score/factory.js.map +1 -1
  125. package/dist/domain/score/fermata-tempo.d.ts +40 -0
  126. package/dist/domain/score/fermata-tempo.d.ts.map +1 -0
  127. package/dist/domain/score/fermata-tempo.js +95 -0
  128. package/dist/domain/score/fermata-tempo.js.map +1 -0
  129. package/dist/domain/score/flatten.d.ts +32 -0
  130. package/dist/domain/score/flatten.d.ts.map +1 -0
  131. package/dist/domain/score/flatten.js +132 -0
  132. package/dist/domain/score/flatten.js.map +1 -0
  133. package/dist/domain/score/fragment.d.ts +4 -8
  134. package/dist/domain/score/fragment.d.ts.map +1 -1
  135. package/dist/domain/score/fragment.js +8 -8
  136. package/dist/domain/score/fragment.js.map +1 -1
  137. package/dist/domain/score/ids.d.ts +1 -1
  138. package/dist/domain/score/ids.js +6 -6
  139. package/dist/domain/score/ottava.d.ts +41 -0
  140. package/dist/domain/score/ottava.d.ts.map +1 -0
  141. package/dist/domain/score/ottava.js +98 -0
  142. package/dist/domain/score/ottava.js.map +1 -0
  143. package/dist/domain/score/performance-timeline.d.ts +42 -0
  144. package/dist/domain/score/performance-timeline.d.ts.map +1 -0
  145. package/dist/domain/score/performance-timeline.js +78 -0
  146. package/dist/domain/score/performance-timeline.js.map +1 -0
  147. package/dist/domain/score/queries.d.ts +2 -2
  148. package/dist/domain/score/queries.js +7 -7
  149. package/dist/domain/score/queries.js.map +1 -1
  150. package/dist/domain/score/rehearsal-marks.d.ts +30 -0
  151. package/dist/domain/score/rehearsal-marks.d.ts.map +1 -0
  152. package/dist/domain/score/rehearsal-marks.js +126 -0
  153. package/dist/domain/score/rehearsal-marks.js.map +1 -0
  154. package/dist/domain/score/repeat-order.d.ts +21 -0
  155. package/dist/domain/score/repeat-order.d.ts.map +1 -0
  156. package/dist/domain/score/repeat-order.js +123 -0
  157. package/dist/domain/score/repeat-order.js.map +1 -0
  158. package/dist/domain/score/snapshot-tree.d.ts +23 -0
  159. package/dist/domain/score/snapshot-tree.d.ts.map +1 -0
  160. package/dist/domain/score/snapshot-tree.js +45 -0
  161. package/dist/domain/score/snapshot-tree.js.map +1 -0
  162. package/dist/domain/score/ties.d.ts +1 -1
  163. package/dist/domain/score/ties.js +7 -7
  164. package/dist/domain/score/ties.js.map +1 -1
  165. package/dist/domain/score/written-pitch.d.ts +33 -0
  166. package/dist/domain/score/written-pitch.d.ts.map +1 -0
  167. package/dist/domain/score/written-pitch.js +110 -0
  168. package/dist/domain/score/written-pitch.js.map +1 -0
  169. package/dist/domain/selection/range-select.d.ts +13 -0
  170. package/dist/domain/selection/range-select.d.ts.map +1 -0
  171. package/dist/domain/selection/range-select.js +40 -0
  172. package/dist/domain/selection/range-select.js.map +1 -0
  173. package/dist/domain/selection/selection-editing.d.ts +30 -0
  174. package/dist/domain/selection/selection-editing.d.ts.map +1 -0
  175. package/dist/domain/selection/selection-editing.js +31 -0
  176. package/dist/domain/selection/selection-editing.js.map +1 -0
  177. package/dist/domain/selection/selection.d.ts +2 -2
  178. package/dist/domain/selection/selection.js +7 -7
  179. package/dist/domain/selection/selection.js.map +1 -1
  180. package/dist/domain/selection/types.d.ts +2 -2
  181. package/dist/domain/selection/types.d.ts.map +1 -1
  182. package/dist/domain/time/duration-modifiers.d.ts +40 -0
  183. package/dist/domain/time/duration-modifiers.d.ts.map +1 -0
  184. package/dist/domain/time/duration-modifiers.js +50 -0
  185. package/dist/domain/time/duration-modifiers.js.map +1 -0
  186. package/dist/domain/time/duration-selection.d.ts +23 -0
  187. package/dist/domain/time/duration-selection.d.ts.map +1 -0
  188. package/dist/domain/time/duration-selection.js +50 -0
  189. package/dist/domain/time/duration-selection.js.map +1 -0
  190. package/dist/domain/time/durations.js +6 -6
  191. package/dist/domain/time/durations.js.map +1 -1
  192. package/dist/domain/time/fraction.d.ts +1 -1
  193. package/dist/domain/time/fraction.js +1 -1
  194. package/dist/domain/time/tap-to-note.d.ts +21 -0
  195. package/dist/domain/time/tap-to-note.d.ts.map +1 -0
  196. package/dist/domain/time/tap-to-note.js +43 -0
  197. package/dist/domain/time/tap-to-note.js.map +1 -0
  198. package/dist/domain/time/tempo-map.d.ts +1 -1
  199. package/dist/domain/time/ticks.d.ts +1 -1
  200. package/dist/domain/time/ticks.d.ts.map +1 -1
  201. package/dist/domain/time/ticks.js +14 -14
  202. package/dist/domain/time/ticks.js.map +1 -1
  203. package/dist/domain/time/tuplets.d.ts +42 -0
  204. package/dist/domain/time/tuplets.d.ts.map +1 -0
  205. package/dist/domain/time/tuplets.js +53 -0
  206. package/dist/domain/time/tuplets.js.map +1 -0
  207. package/dist/domain/validation/issues.d.ts +1 -1
  208. package/dist/domain/validation/issues.js +20 -20
  209. package/dist/domain/validation/validator.d.ts +2 -2
  210. package/dist/domain/validation/validator.d.ts.map +1 -1
  211. package/dist/domain/validation/validator.js +31 -31
  212. package/dist/domain/validation/validator.js.map +1 -1
  213. package/dist/domain/voicing/allocate.d.ts +2 -2
  214. package/dist/domain/voicing/allocate.js +6 -6
  215. package/dist/domain/voicing/allocate.js.map +1 -1
  216. package/dist/index.d.ts +72 -5535
  217. package/dist/index.d.ts.map +1 -1
  218. package/dist/index.js +79 -462
  219. package/dist/index.js.map +1 -1
  220. package/dist/model/api.d.ts +1696 -0
  221. package/dist/model/api.d.ts.map +1 -0
  222. package/dist/model/api.js +125 -0
  223. package/dist/model/api.js.map +1 -0
  224. package/dist/model/generation.d.ts +2178 -0
  225. package/dist/model/generation.d.ts.map +1 -0
  226. package/dist/model/generation.js +142 -0
  227. package/dist/model/generation.js.map +1 -0
  228. package/dist/model/schemas.d.ts +1200 -0
  229. package/dist/model/schemas.d.ts.map +1 -0
  230. package/dist/model/schemas.js +200 -0
  231. package/dist/model/schemas.js.map +1 -0
  232. package/dist/model/score.d.ts +462 -0
  233. package/dist/model/score.d.ts.map +1 -0
  234. package/dist/model/score.js +34 -0
  235. package/dist/model/score.js.map +1 -0
  236. package/dist/platform/audio.d.ts.map +1 -1
  237. package/dist/platform/file.d.ts.map +1 -1
  238. package/dist/platform/index.d.ts +7 -7
  239. package/dist/platform/index.js +7 -7
  240. package/dist/platform/midi-input.d.ts +2 -2
  241. package/dist/platform/midi.d.ts.map +1 -1
  242. package/dist/platform/mod.d.ts +2 -2
  243. package/dist/platform/playback.d.ts +7 -7
  244. package/dist/platform/xml.js +1 -1
  245. package/dist/services/regeneration/controller.d.ts +6 -6
  246. package/dist/services/regeneration/controller.js +12 -12
  247. package/dist/services/regeneration/controller.js.map +1 -1
  248. package/dist/test/fixtures.d.ts +1 -1
  249. package/dist/test/fixtures.js +103 -103
  250. package/dist/test/fixtures.js.map +1 -1
  251. package/package.json +1 -1
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Flattening a score into the notes that actually sound.
3
+ *
4
+ * One traversal, shared by live playback (`playbackPlan`) and offline audio
5
+ * export (`renderEvents`). They used to walk the score separately, and drifted:
6
+ * playback joined tied notes into one sustained note while the export
7
+ * re-articulated every tied segment — so a tie sounded once on screen and
8
+ * twice in the file, against `renderEvents`' own promise to match "what you
9
+ * just heard".
10
+ *
11
+ * Ticks, not seconds: a tempo is the caller's concern. Live playback keeps
12
+ * ticks and hands the engine a `TempoConversion`; the offline renderer
13
+ * converts, because a rendered file has no tempo map to consult.
14
+ *
15
+ * Mute and solo are *not* applied here either. The export drops silenced
16
+ * tracks' notes, while playback keeps them and lets the engine mix live — the
17
+ * whole reason `applyMix` exists.
18
+ */
19
+ import { isNoteEvent } from "../../index.js";
20
+ import { articulatedDuration, articulatedVelocity } from "./articulation.js";
21
+ import { DEFAULT_VELOCITY, dynamicsInForce, effectiveVelocity, hairpinVelocities, } from "./dynamics.js";
22
+ import { pitchToMidi } from "../pitch/pitch.js";
23
+ import { joinTiedNotes } from "./ties.js";
24
+ /**
25
+ * Every voice-ordinal channel of a track: across all measures in tick order,
26
+ * the events at that ordinal position.
27
+ *
28
+ * Voice ids are not stable across a barline, so the ordinal stands in for "the
29
+ * same voice" from bar to bar — which is what lets `joinTiedNotes` see a tie
30
+ * that crosses one. `ties.ts` exports a `voiceChannel`, but that takes a single
31
+ * ordinal and returns measure-annotated notes for tie-*partner* lookup, where
32
+ * this needs every ordinal at once with rests included.
33
+ */
34
+ export function trackVoiceChannels(track) {
35
+ const maxVoices = track.measures.reduce((max, m) => Math.max(max, m.voices.length), 0);
36
+ const channels = [];
37
+ for (let voiceIndex = 0; voiceIndex < maxVoices; voiceIndex += 1) {
38
+ const channel = [];
39
+ for (const measure of track.measures) {
40
+ const voice = measure.voices[voiceIndex];
41
+ if (voice)
42
+ channel.push(...voice.events);
43
+ }
44
+ channel.sort((a, b) => a.startTick - b.startTick);
45
+ channels.push(channel);
46
+ }
47
+ return channels;
48
+ }
49
+ /** Every note the score sounds, ties joined, in tick order. */
50
+ export function flattenScoreNotes(score) {
51
+ const notes = [];
52
+ for (const track of score.tracks) {
53
+ for (const channel of trackVoiceChannels(track)) {
54
+ const joined = joinTiedNotes(channel);
55
+ // Resolved over the joined, ordered channel: "the next dynamic" only
56
+ // means anything in tick order, and a tie join can merge the note a
57
+ // marking sits on into the one before it.
58
+ const inForce = dynamicsInForce(joined);
59
+ // The gradual half of the dynamics. Resolved over the same joined,
60
+ // ordered channel, so a wedge's endpoints are found in the order a
61
+ // player reads them.
62
+ const ramped = hairpinVelocities(joined, inForce);
63
+ for (const event of joined) {
64
+ if (!isNoteEvent(event))
65
+ continue;
66
+ // Two steps, and the order matters: the dynamic sets the level, then
67
+ // the articulation is an offset on top of it — so an accent inside a
68
+ // quiet passage stays an accent rather than being flattened to a fixed
69
+ // loud velocity.
70
+ /*
71
+ A hairpin overrides the level for the notes it spans — that is what
72
+ the wedge means, that the level is *changing* across them — while the
73
+ note's own written velocity survives as a deviation on top either
74
+ way, exactly as it does under a plain dynamic.
75
+ */
76
+ const ramp = ramped.get(event.id);
77
+ const dynamicVelocity = ramp === undefined
78
+ ? effectiveVelocity(event, inForce.get(event.id) ?? null)
79
+ : Math.max(1, Math.min(127, ramp + (event.velocity - DEFAULT_VELOCITY)));
80
+ const velocity = articulatedVelocity(dynamicVelocity, event.articulation);
81
+ /*
82
+ Ornaments sound, and they borrow from the note they decorate.
83
+
84
+ They take no time from the *bar* — that is why they hang off their
85
+ principal — but they have to take it from somewhere, and an
86
+ acciaccatura is crushed against the note it leads into. So they are
87
+ laid before it and the principal starts that much later, which leaves
88
+ the bar's total unchanged and every following note where it was.
89
+
90
+ Never more than half the principal: an ornament that swallowed its
91
+ own note would be a rewrite rather than a decoration.
92
+ */
93
+ const graceNotes = event.graceNotes ?? [];
94
+ let graceTicks = 0;
95
+ if (graceNotes.length > 0) {
96
+ const wanted = graceNotes.reduce((sum, g) => sum + g.durationTicks, 0);
97
+ graceTicks = Math.min(wanted, Math.floor(event.durationTicks / 2));
98
+ const each = Math.floor(graceTicks / graceNotes.length);
99
+ graceNotes.forEach((grace, i) => {
100
+ if (each <= 0)
101
+ return;
102
+ notes.push({
103
+ tick: event.startTick + i * each,
104
+ durTicks: each,
105
+ midi: pitchToMidi(grace.pitch),
106
+ // A shade under the principal: an ornament leads into the note,
107
+ // it does not compete with it. Off the *pre-articulation*
108
+ // velocity, because an accent belongs to the note it is written
109
+ // on and not to what leads into it.
110
+ velocity: Math.max(1, Math.round(dynamicVelocity * 0.8)),
111
+ trackId: track.id,
112
+ noteId: `${event.id}-grace-${i}`,
113
+ });
114
+ });
115
+ }
116
+ notes.push({
117
+ tick: event.startTick + graceTicks,
118
+ // Shortened by a staccato or a marcato, and only ever shortened —
119
+ // the note still *occupies* its written length, so nothing after it
120
+ // moves and the bar still adds up.
121
+ durTicks: articulatedDuration(event.durationTicks - graceTicks, event.articulation),
122
+ midi: pitchToMidi(event.pitch),
123
+ velocity,
124
+ trackId: track.id,
125
+ noteId: event.id,
126
+ });
127
+ }
128
+ }
129
+ }
130
+ return notes.sort((a, b) => a.tick - b.tick);
131
+ }
132
+ //# sourceMappingURL=flatten.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flatten.js","sourceRoot":"","sources":["../../../src/domain/score/flatten.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,7 @@
1
- import type { Score, ScoreFragment } from '../../index.js';
2
- import type { ScoreRange } from '../selection/types.js';
3
- /**
4
- * `ScoreFragment` is canonical in @sudobility/music_types and re-exported
5
- * here so domain modules keep one import site. A fragment is a snapshot of
6
- * a tick range of a score (measures shared by reference, not deep-cloned).
7
- */
8
- export type { ScoreFragment } from '../../index.js';
1
+ import type { Score } from "../../index.js";
2
+ import type { ScoreFragment } from "../../model/score.js";
3
+ import type { ScoreRange } from "../selection/types.js";
4
+ export type { ScoreFragment };
9
5
  /** Captures the measures overlapping `range` (per track named in `range.trackIds`, or all tracks if empty). */
10
6
  export declare function extractFragment(score: Score, range: ScoreRange): ScoreFragment;
11
7
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"fragment.d.ts","sourceRoot":"","sources":["../../../src/domain/score/fragment.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD;;;;GAIG;AACH,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,+GAA+G;AAC/G,wBAAgB,eAAe,CAC7B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,UAAU,GAChB,aAAa,CAMf;AAUD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,GAAG,KAAK,CA6C5E"}
1
+ {"version":3,"file":"fragment.d.ts","sourceRoot":"","sources":["../../../src/domain/score/fragment.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAQxD,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,+GAA+G;AAC/G,wBAAgB,eAAe,CAC7B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,UAAU,GAChB,aAAa,CAMf;AAUD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,GAAG,KAAK,CA6C5E"}
@@ -1,5 +1,5 @@
1
- import { rebuildMeasureTicks } from './factory.js';
2
- import { measuresInRange } from './queries.js';
1
+ import { rebuildMeasureTicks } from "./factory.js";
2
+ import { measuresInRange } from "./queries.js";
3
3
  /** Captures the measures overlapping `range` (per track named in `range.trackIds`, or all tracks if empty). */
4
4
  export function extractFragment(score, range) {
5
5
  return {
@@ -30,12 +30,12 @@ function overlapsRange(measure, range) {
30
30
  * referentially unchanged.
31
31
  */
32
32
  export function replaceFragment(score, fragment) {
33
- const replacementsByTrackId = new Map(fragment.tracks.map(t => [t.trackId, t.measures]));
34
- const tracks = score.tracks.map(track => {
33
+ const replacementsByTrackId = new Map(fragment.tracks.map((t) => [t.trackId, t.measures]));
34
+ const tracks = score.tracks.map((track) => {
35
35
  const replacementMeasures = replacementsByTrackId.get(track.id);
36
36
  if (!replacementMeasures)
37
37
  return track;
38
- const firstIndex = track.measures.findIndex(m => overlapsRange(m, fragment.range));
38
+ const firstIndex = track.measures.findIndex((m) => overlapsRange(m, fragment.range));
39
39
  if (firstIndex === -1)
40
40
  return track;
41
41
  let lastIndex = firstIndex;
@@ -43,11 +43,11 @@ export function replaceFragment(score, fragment) {
43
43
  overlapsRange(track.measures[lastIndex], fragment.range)) {
44
44
  lastIndex += 1;
45
45
  }
46
- const normalizedMeasures = replacementMeasures.map(measure => ({
46
+ const normalizedMeasures = replacementMeasures.map((measure) => ({
47
47
  ...measure,
48
- voices: measure.voices.map(voice => ({
48
+ voices: measure.voices.map((voice) => ({
49
49
  ...voice,
50
- events: voice.events.map(event => ({
50
+ events: voice.events.map((event) => ({
51
51
  ...event,
52
52
  trackId: track.id,
53
53
  voiceId: voice.id,
@@ -1 +1 @@
1
- {"version":3,"file":"fragment.js","sourceRoot":"","sources":["../../../src/domain/score/fragment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAW/C,+GAA+G;AAC/G,MAAM,UAAU,eAAe,CAC7B,KAAY,EACZ,KAAiB;IAEjB,OAAO;QACL,KAAK;QACL,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,SAAS,aAAa,CAAC,OAAgB,EAAE,KAAiB;IACxD,OAAO,CACL,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC,OAAO;QACjC,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,aAAa,GAAG,KAAK,CAAC,SAAS,CAC5D,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,KAAY,EAAE,QAAuB;IACnE,MAAM,qBAAqB,GAAG,IAAI,GAAG,CACnC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAClD,CAAC;IAEF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;QACtC,MAAM,mBAAmB,GAAG,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,mBAAmB;YAAE,OAAO,KAAK,CAAC;QAEvC,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAC9C,aAAa,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CACjC,CAAC;QACF,IAAI,UAAU,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAEpC,IAAI,SAAS,GAAG,UAAU,CAAC;QAC3B,OACE,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM;YACjC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,EACxD,CAAC;YACD,SAAS,IAAI,CAAC,CAAC;QACjB,CAAC;QAED,MAAM,kBAAkB,GAAG,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7D,GAAG,OAAO;YACV,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACnC,GAAG,KAAK;gBACR,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;oBACjC,GAAG,KAAK;oBACR,OAAO,EAAE,KAAK,CAAC,EAAE;oBACjB,OAAO,EAAE,KAAK,CAAC,EAAE;iBAClB,CAAC,CAAC;aACJ,CAAC,CAAC;SACJ,CAAC,CAAC,CAAC;QAEJ,OAAO;YACL,GAAG,KAAK;YACR,QAAQ,EAAE;gBACR,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;gBACtC,GAAG,kBAAkB;gBACrB,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC;aACnC;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,mBAAmB,CAAC,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AACnD,CAAC"}
1
+ {"version":3,"file":"fragment.js","sourceRoot":"","sources":["../../../src/domain/score/fragment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAa/C,+GAA+G;AAC/G,MAAM,UAAU,eAAe,CAC7B,KAAY,EACZ,KAAiB;IAEjB,OAAO;QACL,KAAK;QACL,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,SAAS,aAAa,CAAC,OAAgB,EAAE,KAAiB;IACxD,OAAO,CACL,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC,OAAO;QACjC,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,aAAa,GAAG,KAAK,CAAC,SAAS,CAC5D,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,KAAY,EAAE,QAAuB;IACnE,MAAM,qBAAqB,GAAG,IAAI,GAAG,CACnC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CACpD,CAAC;IAEF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACxC,MAAM,mBAAmB,GAAG,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,mBAAmB;YAAE,OAAO,KAAK,CAAC;QAEvC,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAChD,aAAa,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CACjC,CAAC;QACF,IAAI,UAAU,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAEpC,IAAI,SAAS,GAAG,UAAU,CAAC;QAC3B,OACE,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM;YACjC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,EACxD,CAAC;YACD,SAAS,IAAI,CAAC,CAAC;QACjB,CAAC;QAED,MAAM,kBAAkB,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC/D,GAAG,OAAO;YACV,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBACrC,GAAG,KAAK;gBACR,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBACnC,GAAG,KAAK;oBACR,OAAO,EAAE,KAAK,CAAC,EAAE;oBACjB,OAAO,EAAE,KAAK,CAAC,EAAE;iBAClB,CAAC,CAAC;aACJ,CAAC,CAAC;SACJ,CAAC,CAAC,CAAC;QAEJ,OAAO;YACL,GAAG,KAAK;YACR,QAAQ,EAAE;gBACR,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;gBACtC,GAAG,kBAAkB;gBACrB,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC;aACnC;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,mBAAmB,CAAC,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AACnD,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { UUID } from '../../index.js';
1
+ import type { UUID } from "../../index.js";
2
2
  /**
3
3
  * Generates a v4 UUID. Uses `crypto.randomUUID` when available, falling back
4
4
  * to a `Math.random`-based generator in non-secure contexts (e.g. `http://`
@@ -1,4 +1,4 @@
1
- const HEX_CHARS = '0123456789abcdef';
1
+ const HEX_CHARS = "0123456789abcdef";
2
2
  /**
3
3
  * Fallback v4-UUID generator for non-secure contexts, where
4
4
  * `crypto.randomUUID` is unavailable (it requires a secure context per the
@@ -6,13 +6,13 @@ const HEX_CHARS = '0123456789abcdef';
6
6
  * identifiers only.
7
7
  */
8
8
  function randomUuidFallback() {
9
- let result = '';
9
+ let result = "";
10
10
  for (let i = 0; i < 36; i += 1) {
11
11
  if (i === 8 || i === 13 || i === 18 || i === 23) {
12
- result += '-';
12
+ result += "-";
13
13
  }
14
14
  else if (i === 14) {
15
- result += '4';
15
+ result += "4";
16
16
  }
17
17
  else if (i === 19) {
18
18
  result += HEX_CHARS[8 + Math.floor(Math.random() * 4)]; // one of 8, 9, a, b
@@ -29,8 +29,8 @@ function randomUuidFallback() {
29
29
  * origins other than `localhost`) where `crypto.randomUUID` is undefined.
30
30
  */
31
31
  export function createId() {
32
- if (typeof crypto !== 'undefined' &&
33
- typeof crypto.randomUUID === 'function') {
32
+ if (typeof crypto !== "undefined" &&
33
+ typeof crypto.randomUUID === "function") {
34
34
  return crypto.randomUUID();
35
35
  }
36
36
  return randomUuidFallback();
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The octave brackets, as a display lens.
3
+ *
4
+ * `8va` means "these notes were written an octave lower to keep them on the
5
+ * stave — play them where the bracket says". The model stores **sounding**
6
+ * pitch, so the bracket is what moves the noteheads, not the sound: this walks
7
+ * a score and shifts every note inside a span to where it should be *drawn*.
8
+ *
9
+ * A lens over the whole score rather than a shift inside the renderer, for the
10
+ * reason `writtenScore` is one: the layout and everything measured from it see
11
+ * the same score, so the drawn note and its staff position agree by
12
+ * construction rather than by two matched calculations.
13
+ *
14
+ * Returns the **identical object** when no bracket exists, so `computeLayout`'s
15
+ * identity cache is untouched by a score that has none — which is almost every
16
+ * score.
17
+ *
18
+ * **Known limitation**, shared with `writtenScore`: clicking to place a note
19
+ * *inside* a bracket writes the drawn pitch as the sounding one, because note
20
+ * entry has no inverse for the display lens. That gap predates this and is not
21
+ * specific to ottava.
22
+ */
23
+ import type { Ottava, Score } from "../../index.js";
24
+ /** The octave displacement `ottava` asks for, in octaves. */
25
+ export declare function ottavaOctaves(ottava: Ottava): number;
26
+ /** Whether any note in `score` opens a bracket. */
27
+ export declare function hasOttava(score: Score): boolean;
28
+ /**
29
+ * `score` with every note inside a bracket moved to where it is written.
30
+ *
31
+ * The shift is the *opposite* of the bracket's displacement: `8va` says the
32
+ * player sounds an octave above the page, so the page shows an octave below
33
+ * the stored sound.
34
+ *
35
+ * Spans are read per voice and in tick order — a bracket opens on one note and
36
+ * closes on a later one in the same line, exactly like a slur — and an
37
+ * unclosed opening runs to the end of its voice rather than being dropped,
38
+ * which is what a reader does with a bracket whose end is missing.
39
+ */
40
+ export declare function ottavaScore(score: Score): Score;
41
+ //# sourceMappingURL=ottava.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ottava.d.ts","sourceRoot":"","sources":["../../../src/domain/score/ottava.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAa,MAAM,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAW/D,6DAA6D;AAC7D,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAQ/C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CA6B/C"}
@@ -0,0 +1,98 @@
1
+ import { isNoteEvent } from "../../index.js";
2
+ /** How many octaves, and which way, a bracket displaces what is written. */
3
+ const OTTAVA_OCTAVES = {
4
+ "8va": 1,
5
+ "8vb": -1,
6
+ "15ma": 2,
7
+ "15mb": -2,
8
+ };
9
+ /** The octave displacement `ottava` asks for, in octaves. */
10
+ export function ottavaOctaves(ottava) {
11
+ return OTTAVA_OCTAVES[ottava];
12
+ }
13
+ /** Whether any note in `score` opens a bracket. */
14
+ export function hasOttava(score) {
15
+ return score.tracks.some((track) => track.measures.some((measure) => measure.voices.some((voice) => voice.events.some((e) => isNoteEvent(e) && e.ottavaStart))));
16
+ }
17
+ /**
18
+ * `score` with every note inside a bracket moved to where it is written.
19
+ *
20
+ * The shift is the *opposite* of the bracket's displacement: `8va` says the
21
+ * player sounds an octave above the page, so the page shows an octave below
22
+ * the stored sound.
23
+ *
24
+ * Spans are read per voice and in tick order — a bracket opens on one note and
25
+ * closes on a later one in the same line, exactly like a slur — and an
26
+ * unclosed opening runs to the end of its voice rather than being dropped,
27
+ * which is what a reader does with a bracket whose end is missing.
28
+ */
29
+ export function ottavaScore(score) {
30
+ if (!hasOttava(score))
31
+ return score;
32
+ const shifts = octaveShifts(score);
33
+ if (shifts.size === 0)
34
+ return score;
35
+ return {
36
+ ...score,
37
+ tracks: score.tracks.map((track) => ({
38
+ ...track,
39
+ measures: track.measures.map((measure) => ({
40
+ ...measure,
41
+ voices: measure.voices.map((voice) => ({
42
+ ...voice,
43
+ events: voice.events.map((event) => {
44
+ const octaves = isNoteEvent(event)
45
+ ? shifts.get(event.id)
46
+ : undefined;
47
+ if (octaves === undefined)
48
+ return event;
49
+ const note = event;
50
+ return {
51
+ ...note,
52
+ pitch: { ...note.pitch, octave: note.pitch.octave - octaves },
53
+ };
54
+ }),
55
+ })),
56
+ })),
57
+ })),
58
+ };
59
+ }
60
+ /**
61
+ * Every note inside a bracket, and how many octaves it is displaced by.
62
+ *
63
+ * Walked per **voice ordinal across measures**, not per measure: a bracket
64
+ * opens on one note and closes on a later one, and the later one is usually in
65
+ * a different bar. The ordinal stands in for "the same line" from bar to bar,
66
+ * which is the convention `trackVoiceChannels` and `joinTiedNotes` already use.
67
+ */
68
+ function octaveShifts(score) {
69
+ const shifts = new Map();
70
+ for (const track of score.tracks) {
71
+ const voiceCount = track.measures.reduce((max, m) => Math.max(max, m.voices.length), 0);
72
+ for (let ordinal = 0; ordinal < voiceCount; ordinal += 1) {
73
+ const line = [];
74
+ for (const measure of track.measures) {
75
+ const voice = measure.voices[ordinal];
76
+ if (!voice)
77
+ continue;
78
+ for (const event of voice.events) {
79
+ if (isNoteEvent(event))
80
+ line.push(event);
81
+ }
82
+ }
83
+ line.sort((a, b) => a.startTick - b.startTick);
84
+ let open = null;
85
+ for (const note of line) {
86
+ if (!open && note.ottavaStart)
87
+ open = note.ottavaStart;
88
+ if (open)
89
+ shifts.set(note.id, OTTAVA_OCTAVES[open]);
90
+ // Closed *after* shifting: the closing note is inside its own bracket.
91
+ if (open && note.ottavaStop)
92
+ open = null;
93
+ }
94
+ }
95
+ }
96
+ return shifts;
97
+ }
98
+ //# sourceMappingURL=ottava.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ottava.js","sourceRoot":"","sources":["../../../src/domain/score/ottava.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Translating between where the music *is written* and where it is *played*.
3
+ *
4
+ * Without repeats these are the same number, and the whole editor was built on
5
+ * that: the caret is a score tick, `seek` takes a score tick, the
6
+ * following-scroll finds a bar from one. Expanding a repeat breaks the
7
+ * identity — bar 3 played twice has two performance positions and one written
8
+ * position — so rather than teach four separate consumers about repeats, the
9
+ * plan carries this timeline and they translate through it.
10
+ *
11
+ * A score with no repeats produces an identity timeline: one segment covering
12
+ * everything, `performanceTick === sourceTick`. That is what keeps every
13
+ * existing behaviour byte-identical.
14
+ */
15
+ import type { PerformanceTimeline, Score } from "../../index.js";
16
+ /**
17
+ * Builds the timeline for `score`, honouring its repeats.
18
+ *
19
+ * Consecutive played bars are merged into one segment: a piece with no repeats
20
+ * becomes a single identity segment, and even a repeated one has a handful —
21
+ * so the lookups below stay cheap enough to run per animation frame.
22
+ */
23
+ export declare function performanceTimeline(score: Score): PerformanceTimeline;
24
+ /**
25
+ * Where on the page a performance position is.
26
+ *
27
+ * Used by everything that draws: the caret, the following-scroll, the bar/beat
28
+ * readout. A tick past the end clamps to the last segment rather than
29
+ * returning nothing, because the engine can report a position a hair past the
30
+ * final note and the caret should sit at the end rather than vanish.
31
+ */
32
+ export declare function sourceTickFor(timeline: PerformanceTimeline, performanceTick: number): number;
33
+ /**
34
+ * Where to start playing to hear a written position.
35
+ *
36
+ * The **first** time that written tick is performed, deliberately: clicking bar
37
+ * 3 and pressing play should start the first time through, which is what
38
+ * "play from here" means to a reader looking at the page. Hearing the repeat
39
+ * means playing on to it.
40
+ */
41
+ export declare function performanceTickFor(timeline: PerformanceTimeline, sourceTick: number): number;
42
+ //# sourceMappingURL=performance-timeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-timeline.d.ts","sourceRoot":"","sources":["../../../src/domain/score/performance-timeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAOjE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,mBAAmB,CAgCrE;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,mBAAmB,EAC7B,eAAe,EAAE,MAAM,GACtB,MAAM,CAeR;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,mBAAmB,EAC7B,UAAU,EAAE,MAAM,GACjB,MAAM,CAQR"}
@@ -0,0 +1,78 @@
1
+ import { repeatPlayOrder } from "./repeat-order.js";
2
+ // The shape lives beside `PlaybackPlan` in this package's platform types, and
3
+ // is already exported from there — this module builds one rather than
4
+ // re-exporting the type and creating two names for it.
5
+ /**
6
+ * Builds the timeline for `score`, honouring its repeats.
7
+ *
8
+ * Consecutive played bars are merged into one segment: a piece with no repeats
9
+ * becomes a single identity segment, and even a repeated one has a handful —
10
+ * so the lookups below stay cheap enough to run per animation frame.
11
+ */
12
+ export function performanceTimeline(score) {
13
+ const measures = score.tracks[0]?.measures ?? [];
14
+ // Mutable while building, handed back as the readonly contract type.
15
+ const segments = [];
16
+ let performanceTick = 0;
17
+ for (const { measureIndex } of repeatPlayOrder(score)) {
18
+ const measure = measures[measureIndex];
19
+ if (!measure)
20
+ continue;
21
+ const previous = segments[segments.length - 1];
22
+ const continues = previous !== undefined &&
23
+ previous.sourceTick + previous.durationTicks === measure.startTick;
24
+ if (continues) {
25
+ previous.durationTicks += measure.durationTicks;
26
+ }
27
+ else {
28
+ segments.push({
29
+ performanceTick,
30
+ sourceTick: measure.startTick,
31
+ durationTicks: measure.durationTicks,
32
+ });
33
+ }
34
+ performanceTick += measure.durationTicks;
35
+ }
36
+ return { segments, durationTicks: performanceTick };
37
+ }
38
+ /**
39
+ * Where on the page a performance position is.
40
+ *
41
+ * Used by everything that draws: the caret, the following-scroll, the bar/beat
42
+ * readout. A tick past the end clamps to the last segment rather than
43
+ * returning nothing, because the engine can report a position a hair past the
44
+ * final note and the caret should sit at the end rather than vanish.
45
+ */
46
+ export function sourceTickFor(timeline, performanceTick) {
47
+ const { segments } = timeline;
48
+ if (segments.length === 0)
49
+ return performanceTick;
50
+ for (const segment of segments) {
51
+ const offset = performanceTick - segment.performanceTick;
52
+ if (offset >= 0 && offset < segment.durationTicks) {
53
+ return segment.sourceTick + offset;
54
+ }
55
+ }
56
+ const last = segments[segments.length - 1];
57
+ if (performanceTick < segments[0].performanceTick)
58
+ return segments[0].sourceTick;
59
+ return last.sourceTick + last.durationTicks - 1;
60
+ }
61
+ /**
62
+ * Where to start playing to hear a written position.
63
+ *
64
+ * The **first** time that written tick is performed, deliberately: clicking bar
65
+ * 3 and pressing play should start the first time through, which is what
66
+ * "play from here" means to a reader looking at the page. Hearing the repeat
67
+ * means playing on to it.
68
+ */
69
+ export function performanceTickFor(timeline, sourceTick) {
70
+ for (const segment of timeline.segments) {
71
+ const offset = sourceTick - segment.sourceTick;
72
+ if (offset >= 0 && offset < segment.durationTicks) {
73
+ return segment.performanceTick + offset;
74
+ }
75
+ }
76
+ return sourceTick;
77
+ }
78
+ //# sourceMappingURL=performance-timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-timeline.js","sourceRoot":"","sources":["../../../src/domain/score/performance-timeline.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,8EAA8E;AAC9E,sEAAsE;AACtE,uDAAuD;AAEvD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAY;IAC9C,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAC;IACjD,qEAAqE;IACrE,MAAM,QAAQ,GAIT,EAAE,CAAC;IACR,IAAI,eAAe,GAAG,CAAC,CAAC;IAExB,KAAK,MAAM,EAAE,YAAY,EAAE,IAAI,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/C,MAAM,SAAS,GACb,QAAQ,KAAK,SAAS;YACtB,QAAQ,CAAC,UAAU,GAAG,QAAQ,CAAC,aAAa,KAAK,OAAO,CAAC,SAAS,CAAC;QAErE,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC;gBACZ,eAAe;gBACf,UAAU,EAAE,OAAO,CAAC,SAAS;gBAC7B,aAAa,EAAE,OAAO,CAAC,aAAa;aACrC,CAAC,CAAC;QACL,CAAC;QACD,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC;IAC3C,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,CAAC;AACtD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,QAA6B,EAC7B,eAAuB;IAEvB,MAAM,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC;IAC9B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,eAAe,CAAC;IAElD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;QACzD,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;YAClD,OAAO,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC;QACrC,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3C,IAAI,eAAe,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,eAAe;QAC/C,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IAChC,OAAO,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAA6B,EAC7B,UAAkB;IAElB,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QAC/C,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;YAClD,OAAO,OAAO,CAAC,eAAe,GAAG,MAAM,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -1,5 +1,5 @@
1
- import type { ScoreRange } from '../selection/types.js';
2
- import type { Measure, MusicalEvent, NoteEvent, Score, Track, UUID } from '../../index.js';
1
+ import type { ScoreRange } from "../selection/types.js";
2
+ import type { Measure, MusicalEvent, NoteEvent, Score, Track, UUID } from "../../index.js";
3
3
  /** Finds a track by id, or `null` if no track has that id. */
4
4
  export declare function findTrack(score: Score, trackId: UUID): Track | null;
5
5
  /** Finds a measure by id across all tracks, or `null` if none has that id. */
@@ -1,13 +1,13 @@
1
- import { isNoteEvent } from '../../index.js';
2
- import { pitchToMidi } from '../pitch/pitch.js';
1
+ import { isNoteEvent } from "../../index.js";
2
+ import { pitchToMidi } from "../pitch/pitch.js";
3
3
  /** Finds a track by id, or `null` if no track has that id. */
4
4
  export function findTrack(score, trackId) {
5
- return score.tracks.find(track => track.id === trackId) ?? null;
5
+ return score.tracks.find((track) => track.id === trackId) ?? null;
6
6
  }
7
7
  /** Finds a measure by id across all tracks, or `null` if none has that id. */
8
8
  export function findMeasure(score, measureId) {
9
9
  for (const track of score.tracks) {
10
- const measure = track.measures.find(m => m.id === measureId);
10
+ const measure = track.measures.find((m) => m.id === measureId);
11
11
  if (measure)
12
12
  return measure;
13
13
  }
@@ -18,7 +18,7 @@ export function findEvent(score, eventId) {
18
18
  for (const track of score.tracks) {
19
19
  for (const measure of track.measures) {
20
20
  for (const voice of measure.voices) {
21
- const event = voice.events.find(e => e.id === eventId);
21
+ const event = voice.events.find((e) => e.id === eventId);
22
22
  if (event)
23
23
  return event;
24
24
  }
@@ -59,7 +59,7 @@ export function measuresInRange(score, range) {
59
59
  for (const track of score.tracks) {
60
60
  if (!rangeIncludesTrack(range, track.id))
61
61
  continue;
62
- const measures = track.measures.filter(m => overlapsRange(m.startTick, m.durationTicks, range));
62
+ const measures = track.measures.filter((m) => overlapsRange(m.startTick, m.durationTicks, range));
63
63
  result.push({ trackId: track.id, measures });
64
64
  }
65
65
  return result;
@@ -124,7 +124,7 @@ export function allNotes(score) {
124
124
  */
125
125
  export function scoreWithTracks(score, trackIds) {
126
126
  const wanted = new Set(trackIds);
127
- const tracks = score.tracks.filter(track => wanted.has(track.id));
127
+ const tracks = score.tracks.filter((track) => wanted.has(track.id));
128
128
  if (tracks.length === score.tracks.length)
129
129
  return score;
130
130
  return { ...score, tracks };
@@ -1 +1 @@
1
- {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../../src/domain/score/queries.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../../src/domain/score/queries.ts"],"names":[],"mappings":"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"}