@sudobility/music_drawing 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 (57) hide show
  1. package/dist/canvas-renderer.d.ts +180 -0
  2. package/dist/canvas-renderer.d.ts.map +1 -0
  3. package/dist/canvas-renderer.js +831 -0
  4. package/dist/canvas-renderer.js.map +1 -0
  5. package/dist/convert.d.ts +122 -0
  6. package/dist/convert.d.ts.map +1 -0
  7. package/dist/convert.js +426 -0
  8. package/dist/convert.js.map +1 -0
  9. package/dist/display-timing.d.ts +68 -0
  10. package/dist/display-timing.d.ts.map +1 -0
  11. package/dist/display-timing.js +192 -0
  12. package/dist/display-timing.js.map +1 -0
  13. package/dist/icon-canvas.d.ts +12 -0
  14. package/dist/icon-canvas.d.ts.map +1 -0
  15. package/dist/icon-canvas.js +62 -0
  16. package/dist/icon-canvas.js.map +1 -0
  17. package/dist/index.d.ts +30 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +30 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/layout.d.ts +159 -0
  22. package/dist/layout.d.ts.map +1 -0
  23. package/dist/layout.js +362 -0
  24. package/dist/layout.js.map +1 -0
  25. package/dist/measure-content.d.ts +114 -0
  26. package/dist/measure-content.d.ts.map +1 -0
  27. package/dist/measure-content.js +553 -0
  28. package/dist/measure-content.js.map +1 -0
  29. package/dist/note-color.d.ts +48 -0
  30. package/dist/note-color.d.ts.map +1 -0
  31. package/dist/note-color.js +81 -0
  32. package/dist/note-color.js.map +1 -0
  33. package/dist/pagination.d.ts +57 -0
  34. package/dist/pagination.d.ts.map +1 -0
  35. package/dist/pagination.js +152 -0
  36. package/dist/pagination.js.map +1 -0
  37. package/dist/percussion.d.ts +47 -0
  38. package/dist/percussion.d.ts.map +1 -0
  39. package/dist/percussion.js +172 -0
  40. package/dist/percussion.js.map +1 -0
  41. package/dist/playhead.d.ts +37 -0
  42. package/dist/playhead.d.ts.map +1 -0
  43. package/dist/playhead.js +89 -0
  44. package/dist/playhead.js.map +1 -0
  45. package/dist/test/canvas-stub.d.ts +21 -0
  46. package/dist/test/canvas-stub.d.ts.map +1 -0
  47. package/dist/test/canvas-stub.js +51 -0
  48. package/dist/test/canvas-stub.js.map +1 -0
  49. package/dist/test/fixtures.d.ts +47 -0
  50. package/dist/test/fixtures.d.ts.map +1 -0
  51. package/dist/test/fixtures.js +433 -0
  52. package/dist/test/fixtures.js.map +1 -0
  53. package/dist/types.d.ts +74 -0
  54. package/dist/types.d.ts.map +1 -0
  55. package/dist/types.js +9 -0
  56. package/dist/types.js.map +1 -0
  57. package/package.json +62 -0
@@ -0,0 +1,180 @@
1
+ import type { Score } from '@sudobility/music_types';
2
+ import type { LayoutPlan } from './layout.js';
3
+ import type { BBox, RenderOptions, RenderTheme } from './types.js';
4
+ /**
5
+ * Logical (unscaled) content-coordinate window to draw: typically
6
+ * `scrollTop/zoom` .. `(scrollTop+clientHeight)/zoom`. `left`/`right`
7
+ * (defaults: 0/∞ — full width, page-mode behavior) window the draw
8
+ * horizontally too: continuous mode lays every measure in ONE system, so
9
+ * without them each frame would draw the entire score.
10
+ */
11
+ export type CanvasViewport = {
12
+ top: number;
13
+ bottom: number;
14
+ left?: number;
15
+ right?: number;
16
+ };
17
+ export type CanvasRenderOptions = RenderOptions & {
18
+ viewport: CanvasViewport;
19
+ /** Backing-store scale (window.devicePixelRatio); default 1. The canvas element's width/height must already be sized to cssSize × this. */
20
+ devicePixelRatio?: number;
21
+ };
22
+ export type CanvasRenderResult = {
23
+ /** Note/rest event id -> bbox, zoom-scaled CSS px, content coordinates (scroll NOT subtracted). Drawn window only. */
24
+ idToBBox: Map<string, BBox>;
25
+ /** Measure id -> its stave box (from the layout plan), same units. Drawn window only; one entry per (track, measure). */
26
+ measureIdToBBox: Map<string, BBox>;
27
+ drawnMeasureIndices: Set<number>;
28
+ /** The (cached) full-score layout this frame was drawn against. */
29
+ plan: LayoutPlan;
30
+ theme: RenderTheme;
31
+ };
32
+ /**
33
+ * Where the instrument row's text and icon go, relative to the stave's top line.
34
+ *
35
+ * Two rules, and they fix everything else:
36
+ *
37
+ * - the **top of the instrument name** sits on the stave's top line, and
38
+ * - the **icon's centre** sits on the name's centre.
39
+ *
40
+ * "Top of the name" means the top of its capitals, not the top of the font's
41
+ * em box — the em box carries room for accents that nothing here draws, so
42
+ * aligning to it leaves a visible gap that reads as misalignment. Hence
43
+ * `capHeight`, measured from the canvas rather than assumed: a baseline placed
44
+ * by arithmetic put the icon on the line and the text five pixels under it.
45
+ *
46
+ * Pure, and exported, because this is the part worth pinning exactly — the
47
+ * drawing around it is not.
48
+ */
49
+ export declare function trackInfoRowLayout(staveTopLine: number, capHeight: number, iconSize: number): {
50
+ textBaseline: number;
51
+ iconTop: number;
52
+ rowCenter: number;
53
+ };
54
+ export declare class CanvasScoreRenderer {
55
+ private cache;
56
+ /**
57
+ * The last frame's built objects, reused when only colour changed.
58
+ *
59
+ * The single most expensive thing this renderer does is construct and format
60
+ * VexFlow objects, and playback asks it to redraw on every note boundary to
61
+ * move one notehead's colour. Keyed on everything geometry depends on —
62
+ * score identity, zoom, layout mode, width, track set, viewport — and
63
+ * deliberately *not* on the theme, the note colours, the active track or the
64
+ * selection, which are exactly what a repaint changes.
65
+ *
66
+ * One frame, not an LRU: during playback the viewport is still, so
67
+ * consecutive repaints hit it; scrolling misses it and rebuilds, which is the
68
+ * same work it did before. Bounded by construction, since it only ever holds
69
+ * what was last drawn.
70
+ */
71
+ private frame;
72
+ private planFor;
73
+ render(score: Score, ctx: CanvasRenderingContext2D, options: CanvasRenderOptions): CanvasRenderResult;
74
+ /**
75
+ * The track-info gutter: name, instrument and mute/solo state beside every
76
+ * stave, for every visible system.
77
+ *
78
+ * Pinned to the viewport's left edge rather than drawn at content x=0. In
79
+ * continuous mode the score is one very wide system scrolled horizontally, so
80
+ * a gutter in content space would slide out of view — the one thing a
81
+ * permanent label column cannot do. The vertical scroll is kept, so the
82
+ * labels still track their staves.
83
+ *
84
+ * Reads `name`/`instrumentName`/`muted`/`solo` straight off the live `Track`,
85
+ * so there is no render option to keep in sync. Alignment is structural: the
86
+ * gutter is the space `layout.ts` reserved via `TRACK_INFO_WIDTH`, in the
87
+ * same coordinate space as the staves.
88
+ */
89
+ private drawTrackInfoGutter;
90
+ /**
91
+ * Styles one VexFlow note by the highest-precedence role among the domain
92
+ * events it represents (>1 for a chord, or for one segment of a
93
+ * duration-decomposed long note).
94
+ *
95
+ * Both `fillStyle` and `strokeStyle` are set: noteheads fill, stems and
96
+ * flags stroke, and a note whose stem stayed the default color would read
97
+ * as half-highlighted.
98
+ *
99
+ * `lineWidth` carries the same state redundantly *without* color (spec §27)
100
+ * — see `noteEmphasisFor`, including why this is not a shadow.
101
+ */
102
+ private styleNote;
103
+ /**
104
+ * Whether `trackId` is *the* active track. With no active track set, nothing
105
+ * is active, so every stave draws in `staveInactive` — the neutral state.
106
+ */
107
+ private isActiveTrack;
108
+ /**
109
+ * Whether a track's notes should dim.
110
+ *
111
+ * Deliberately not `!isActiveTrack`. Dimming is *relative* — it says "this
112
+ * track is not the one you are working on" — so with no active track set
113
+ * there is nothing to be relative to and no note dims. Stave lines can sit in
114
+ * their neutral colour without looking wrong; every note in the score going
115
+ * grey would just look washed out.
116
+ */
117
+ private notesDimmed;
118
+ /** The unstyled-note color for a track, which its beams and ties follow. */
119
+ private trackColor;
120
+ private recordEventBBox;
121
+ /**
122
+ * The contiguous slice of `system.measureIndices` whose stave boxes
123
+ * intersect `[left, right]`, found by binary search over the x-sorted
124
+ * measure layouts — O(log n), so a continuous-mode frame never scans the
125
+ * whole single-system score (the horizontal analogue of the y-based
126
+ * system filter).
127
+ */
128
+ private visibleMeasureIndices;
129
+ /**
130
+ * Builds one system's VexFlow objects, without deciding what colour anything
131
+ * is.
132
+ *
133
+ * Split from painting so the result can be cached: constructing and
134
+ * formatting notes is what costs milliseconds (measured at 119ms for a
135
+ * twelve-track sixteenth-note score at zoom 0.5), and a colour change — a
136
+ * note starting, a selection moving — changes none of it. See `render`.
137
+ */
138
+ private buildSystem;
139
+ /**
140
+ * Paints an already-built system.
141
+ *
142
+ * Everything here is a colour decision or a context write, so it is what runs
143
+ * again when a note starts sounding or the selection moves — cheap beside the
144
+ * building it no longer has to repeat.
145
+ */
146
+ private paintSystem;
147
+ /**
148
+ * Tints every selected measure across the full height of the system.
149
+ *
150
+ * The whole bar, not a mark near it: a selection's *extent* is the thing that
151
+ * has to be legible — "these four bars, on every staff" — and the 2px rule
152
+ * this replaces stated that in the one strip of the sheet nobody is looking
153
+ * at. Spanning the system rather than one track's stave is deliberate, and
154
+ * matches what the selection means: the measure gutter is one band per
155
+ * system, and replacing a measure region acts on every track in it.
156
+ *
157
+ * Drawn **before** the staves and notes so it reads as paper the music sits
158
+ * on. Over the top it would tint the noteheads themselves, and a selected
159
+ * bar's notes would not match the same notes anywhere else.
160
+ */
161
+ private paintSelectedMeasures;
162
+ /**
163
+ * Measure numbers in the band above the system's top stave, with any
164
+ * measure in `selectedMeasureIds` picked out in the selection colour.
165
+ *
166
+ * Extent is carried by `paintSelectedMeasures`, which tints the bar itself;
167
+ * this only has to say which number belongs to it. It used to draw a 2px rule
168
+ * under the number instead, which was the only thing showing how far a
169
+ * selection reached and was easy to miss entirely.
170
+ *
171
+ * Drawn straight to the 2D context: there is no VexFlow object for "the
172
+ * space above a stave", and a number plus a rect needs none. Measure
173
+ * geometry comes off track 0 because every track shares one measure grid
174
+ * (see `rebuildMeasureTicks`), which is what lets one gutter serve the
175
+ * whole system.
176
+ */
177
+ private drawMeasureGutter;
178
+ dispose(): void;
179
+ }
180
+ //# sourceMappingURL=canvas-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-renderer.d.ts","sourceRoot":"","sources":["../src/canvas-renderer.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAkBrD,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGnE;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG;IAChD,QAAQ,EAAE,cAAc,CAAC;IACzB,2IAA2I;IAC3I,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sHAAsH;IACtH,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5B,yHAAyH;IACzH,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnC,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,mEAAmE;IACnE,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;CACpB,CAAC;AAwEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAM9D;AAeD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,KAAK,CAAgE;IAC7E;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,KAAK,CAA2B;IAExC,OAAO,CAAC,OAAO;IAcf,MAAM,CACJ,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,wBAAwB,EAC7B,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB;IA8PrB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,mBAAmB;IAgH3B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,SAAS;IAejB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;IAInB,4EAA4E;IAC5E,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,eAAe;IAyBvB;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IAuC7B;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;IAiInB;;;;;;OAMG;IACH,OAAO,CAAC,WAAW;IAwJnB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,qBAAqB;IAuC7B;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,iBAAiB;IA4CzB,OAAO,IAAI,IAAI;CAIhB"}