@real-music-packages/web-core 0.32.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audio.js +4 -4
- package/dist/index.js +5 -5
- package/dist/playback.d.ts +61 -0
- package/dist/playback.js +128 -0
- package/dist/playback.js.map +1 -0
- package/dist/scene/index.d.ts +14 -198
- package/dist/scene/index.js +18 -3
- package/dist/scene/index.js.map +1 -1
- package/dist/waveform-DdSMAbYQ.d.ts +202 -0
- package/package.json +5 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { PromoTheme, SafeBox } from './video.js';
|
|
2
|
+
|
|
3
|
+
interface ScoreNote {
|
|
4
|
+
/** MIDI note number (middle C = 60). */
|
|
5
|
+
pitchMidi: number;
|
|
6
|
+
/** Diatonic letter name: C D E F G A B. */
|
|
7
|
+
step: string;
|
|
8
|
+
/** Chromatic alteration in semitones: -1 flat, +1 sharp, 0 natural, ±2 double. */
|
|
9
|
+
alter: number;
|
|
10
|
+
/** Scientific octave (middle C = C4). */
|
|
11
|
+
octave: number;
|
|
12
|
+
/** Onset on the linear playback clock, in ms (repeats expanded). */
|
|
13
|
+
onsetMs: number;
|
|
14
|
+
/** Sounding duration in ms (tie chains merged). */
|
|
15
|
+
durMs: number;
|
|
16
|
+
/** Staff index within the whole sheet (0-based). */
|
|
17
|
+
staff: number;
|
|
18
|
+
/** Voice id within the part. */
|
|
19
|
+
voice: number;
|
|
20
|
+
/** Performing hand: grand-staff top -> "R", bottom -> "L" (see hand-inference stub). */
|
|
21
|
+
hand: 'L' | 'R';
|
|
22
|
+
/** Engraved bar this note sits in, 1-based. Repeat passes keep the printed
|
|
23
|
+
* number — a cursor or scrubber points at bars as printed, not as played. */
|
|
24
|
+
measure: number;
|
|
25
|
+
/** Lyric syllable attached to this note, if any. */
|
|
26
|
+
lyric?: string;
|
|
27
|
+
/** Fingering digit attached to this note, if any. */
|
|
28
|
+
fingering?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Tempo map. v1 is a single constant tempo (one segment at t=0). The piecewise
|
|
32
|
+
* shape is the documented seam for rubato / multiple `<sound tempo>` — see the
|
|
33
|
+
* tempo-map stub note in scoreFromMusicXML.
|
|
34
|
+
*/
|
|
35
|
+
interface TempoMap {
|
|
36
|
+
/** Where the tempo came from: the XML's notated tempo, the fallback, or an override. */
|
|
37
|
+
source: 'xml' | 'fallback' | 'override';
|
|
38
|
+
/** Piecewise-constant segments, ordered by onset. v1 always has exactly one (at 0). */
|
|
39
|
+
segments: Array<{
|
|
40
|
+
atMs: number;
|
|
41
|
+
bpm: number;
|
|
42
|
+
}>;
|
|
43
|
+
}
|
|
44
|
+
interface Score {
|
|
45
|
+
notes: ScoreNote[];
|
|
46
|
+
tempoMap: TempoMap;
|
|
47
|
+
/** End of the last sounding note, in ms. */
|
|
48
|
+
durationMs: number;
|
|
49
|
+
key?: string;
|
|
50
|
+
timeSig?: string;
|
|
51
|
+
title?: string;
|
|
52
|
+
composer?: string;
|
|
53
|
+
}
|
|
54
|
+
interface ScoreFromMusicXMLOpts {
|
|
55
|
+
/** bpm to use when the XML has no notated tempo (DefaultStartTempoInBpm === 0). Default 100. */
|
|
56
|
+
tempoFallback?: number;
|
|
57
|
+
/** Force this bpm regardless of the XML's notated tempo (per-recipe override). */
|
|
58
|
+
tempoOverride?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Provide the OSMD instance. Defaults to a literal `import('opensheetmusicdisplay')`
|
|
61
|
+
* + a detached div (works in a browser, or in Node after `setupHeadlessDom()`).
|
|
62
|
+
* Inject for tests or non-DOM environments.
|
|
63
|
+
*/
|
|
64
|
+
osmdFactory?: () => any;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Parse MusicXML into a timed, typed Score via OSMD's source model.
|
|
68
|
+
*
|
|
69
|
+
* @param xml MusicXML document (uncompressed string; unzip .mxl first).
|
|
70
|
+
* @param opts tempoFallback / tempoOverride / osmdFactory.
|
|
71
|
+
*/
|
|
72
|
+
declare function scoreFromMusicXML(xml: string, opts?: ScoreFromMusicXMLOpts): Promise<Score>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Audio clock the runner exposes to layers. `nowMs` is the current playback
|
|
76
|
+
* position in milliseconds (audio-clock-driven, NOT wall-clock). During an
|
|
77
|
+
* offline/deterministic render the runner supplies the frame time directly, so
|
|
78
|
+
* `nowMs` and the `tMs` passed to `draw` agree.
|
|
79
|
+
*/
|
|
80
|
+
interface AudioClock {
|
|
81
|
+
/** Current playback position in ms. */
|
|
82
|
+
nowMs(): number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Everything a layer needs to draw a frame. Constructed once per render and
|
|
86
|
+
* passed to every `init`/`draw`. World coordinates: layers draw in the frame's
|
|
87
|
+
* pixel space (0,0 top-left, W×H); the camera primitive (./camera) applies any
|
|
88
|
+
* pan/zoom transform to `ctx2d` BEFORE the layer's `draw` runs, so a layer never
|
|
89
|
+
* re-derives the viewport.
|
|
90
|
+
*/
|
|
91
|
+
interface RenderCtx {
|
|
92
|
+
/** The shared 2D context all layers draw onto. */
|
|
93
|
+
ctx2d: CanvasRenderingContext2D;
|
|
94
|
+
/** Frame width in px. */
|
|
95
|
+
W: number;
|
|
96
|
+
/** Frame height in px. */
|
|
97
|
+
H: number;
|
|
98
|
+
/** The parsed Score (timing/pitch/hands/lyrics). May be undefined for
|
|
99
|
+
* non-musical scenes (a pure hook/CTA card). */
|
|
100
|
+
score?: Score;
|
|
101
|
+
/** Audio playback clock. */
|
|
102
|
+
audioClock: AudioClock;
|
|
103
|
+
/** Per-app theme tokens (colours/fonts/brand). */
|
|
104
|
+
theme: PromoTheme;
|
|
105
|
+
/** Phone-safe content rectangle (./video safeBox) — layers anchor to this
|
|
106
|
+
* instead of re-deriving insets. */
|
|
107
|
+
safeBox: SafeBox;
|
|
108
|
+
/** Capture frame rate. */
|
|
109
|
+
fps: number;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* A composable, time-synced render component.
|
|
113
|
+
*
|
|
114
|
+
* @typeParam P the layer's prop type (what a SceneSpec passes as `p`).
|
|
115
|
+
*/
|
|
116
|
+
interface Layer<P = unknown> {
|
|
117
|
+
/** Stable identity, e.g. "notation" | "falling-notes" | "caption". */
|
|
118
|
+
readonly key: string;
|
|
119
|
+
/**
|
|
120
|
+
* One-time setup: load assets, lay out, rasterize an offscreen bitmap, etc.
|
|
121
|
+
* Runs before the first captured frame. May be async (e.g. font/IR load).
|
|
122
|
+
*/
|
|
123
|
+
init(ctx: RenderCtx, props: P): void | Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Per-frame draw. MUST be cheap and a pure function of `tMs` (no rAF / wall
|
|
126
|
+
* clock). `tMs` is the absolute playback time in ms.
|
|
127
|
+
*/
|
|
128
|
+
draw(ctx: RenderCtx, tMs: number): void;
|
|
129
|
+
/** Optional teardown (free bitmaps / audio nodes). */
|
|
130
|
+
dispose?(): void;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* A layer factory keyed by name, with a runtime prop validator so the runner /
|
|
134
|
+
* pre-render gate can reject an unknown prop before capture (spec: "unknown
|
|
135
|
+
* layer/prop → fail fast"). `validateProps` returns an array of human-readable
|
|
136
|
+
* errors ([] = valid).
|
|
137
|
+
*/
|
|
138
|
+
interface LayerFactory<P = unknown> {
|
|
139
|
+
key: string;
|
|
140
|
+
create(): Layer<P>;
|
|
141
|
+
/** Validate a SceneSpec's `p` object. Return [] when valid. */
|
|
142
|
+
validateProps(props: unknown): string[];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Host-provided level source attached to RenderCtx by the app/capture harness. */
|
|
146
|
+
interface SpectrumInput {
|
|
147
|
+
/** Normalized 0..1 magnitudes for `bands` bars at time tMs (preferred). */
|
|
148
|
+
levels?(tMs: number, bands: number): Float32Array | number[] | null | undefined;
|
|
149
|
+
/** Raw byte-FFT (0..255), log-binned by the layer (AnalyserNode shape). */
|
|
150
|
+
byteFreq?(tMs: number): Uint8Array | null | undefined;
|
|
151
|
+
}
|
|
152
|
+
/** Augment RenderCtx with the optional spectrum input (declaration merging). */
|
|
153
|
+
declare module '../layer' {
|
|
154
|
+
interface RenderCtx {
|
|
155
|
+
/** Optional audio-reactive level source for the spectrum layer (host-wired). */
|
|
156
|
+
spectrum?: SpectrumInput;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
interface SpectrumProps {
|
|
160
|
+
/** Number of bars. Default 44 (whozart SPEC_BARS). */
|
|
161
|
+
bars?: number;
|
|
162
|
+
/** Vertical center as a fraction of H. Default 0.46 (whozart). */
|
|
163
|
+
centerFrac?: number;
|
|
164
|
+
/** Max half-height as a fraction of H. Default 0.135 (whozart). */
|
|
165
|
+
maxHeightFrac?: number;
|
|
166
|
+
/** Bar fill at low magnitude (wine). Default theme.accent. */
|
|
167
|
+
colorLow?: string;
|
|
168
|
+
/** Bar fill at high magnitude (gold). Default theme.gold. */
|
|
169
|
+
colorHigh?: string;
|
|
170
|
+
/** Per-frame level provider (overrides ctx.spectrum). Pure fn of t for tests. */
|
|
171
|
+
levelsFn?: (tMs: number, bands: number) => Float32Array | number[] | null;
|
|
172
|
+
}
|
|
173
|
+
declare const spectrumFactory: LayerFactory<SpectrumProps>;
|
|
174
|
+
|
|
175
|
+
/** Host-provided time-domain sample source (AnalyserNode shape). */
|
|
176
|
+
interface WaveformInput {
|
|
177
|
+
/** 0..255 samples centered ~128 (AnalyserNode.getByteTimeDomainData). */
|
|
178
|
+
byteTime?(tMs: number): Uint8Array | null | undefined;
|
|
179
|
+
}
|
|
180
|
+
declare module '../layer' {
|
|
181
|
+
interface RenderCtx {
|
|
182
|
+
/** Optional time-domain source for the waveform layer (host-wired). */
|
|
183
|
+
waveform?: WaveformInput;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
interface WaveformProps {
|
|
187
|
+
/** Number of samples plotted. Default 128. */
|
|
188
|
+
samples?: number;
|
|
189
|
+
/** Vertical center as a fraction of H. Default 0.46. */
|
|
190
|
+
centerFrac?: number;
|
|
191
|
+
/** Max deflection as a fraction of H. Default 0.10. */
|
|
192
|
+
amplitudeFrac?: number;
|
|
193
|
+
/** Line width px. Default 5. */
|
|
194
|
+
lineWidth?: number;
|
|
195
|
+
/** Line colour. Default theme.accent. */
|
|
196
|
+
color?: string;
|
|
197
|
+
/** Per-frame sample provider returning -1..1 (overrides ctx.waveform). */
|
|
198
|
+
samplesFn?: (tMs: number, n: number) => Float32Array | number[] | null;
|
|
199
|
+
}
|
|
200
|
+
declare const waveformFactory: LayerFactory<WaveformProps>;
|
|
201
|
+
|
|
202
|
+
export { type AudioClock as A, type Layer as L, type RenderCtx as R, type Score as S, type TempoMap as T, type WaveformInput as W, type LayerFactory as a, type ScoreFromMusicXMLOpts as b, type ScoreNote as c, type SpectrumInput as d, type SpectrumProps as e, type WaveformProps as f, spectrumFactory as g, scoreFromMusicXML as s, waveformFactory as w };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@real-music-packages/web-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "Shared music-theory + audio primitives for the music-suite web apps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
"types": "./dist/streak.d.ts",
|
|
32
32
|
"import": "./dist/streak.js"
|
|
33
33
|
},
|
|
34
|
+
"./playback": {
|
|
35
|
+
"types": "./dist/playback.d.ts",
|
|
36
|
+
"import": "./dist/playback.js"
|
|
37
|
+
},
|
|
34
38
|
"./scene": {
|
|
35
39
|
"types": "./dist/scene/index.d.ts",
|
|
36
40
|
"import": "./dist/scene/index.js"
|