@real-music-packages/web-core 0.20.0 → 0.22.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/scene/index.d.ts +34 -26
- package/dist/scene/index.js +32 -32
- package/dist/scene/index.js.map +1 -1
- package/package.json +1 -1
package/dist/scene/index.d.ts
CHANGED
|
@@ -678,12 +678,11 @@ declare const notationFactory: LayerFactory<NotationProps>;
|
|
|
678
678
|
|
|
679
679
|
interface ScrollCursorProps {
|
|
680
680
|
/**
|
|
681
|
-
*
|
|
682
|
-
* note-by-note off the audio clock against each note's `onsetMs
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
* for back-compat; prefer leaving this unset.
|
|
681
|
+
* DEPRECATED / back-compat only. The cursor is ALWAYS audio-onset locked now —
|
|
682
|
+
* driven note-by-note off the audio clock against each note's `onsetMs` (see
|
|
683
|
+
* `ctx.score`). Both `'audio'` and `'linear'` resolve to that single onset path;
|
|
684
|
+
* `'linear'` no longer re-enables the legacy measure-linear sweep (removed —
|
|
685
|
+
* that was the drift footgun). Prefer leaving this unset.
|
|
687
686
|
*/
|
|
688
687
|
mode?: 'audio' | 'linear';
|
|
689
688
|
/**
|
|
@@ -704,9 +703,9 @@ interface ScrollCursorProps {
|
|
|
704
703
|
/** Opening-zoom duration in ms before the music/cursor start (RSR INTRO_MS=900).
|
|
705
704
|
* During this lead-in the follow window is held at the start. Default 900. */
|
|
706
705
|
openingZoomMs?: number;
|
|
707
|
-
/** Total music length in ms (RSR musicMs).
|
|
708
|
-
*
|
|
709
|
-
* and
|
|
706
|
+
/** DEPRECATED. Total music length in ms (RSR musicMs). No longer used to
|
|
707
|
+
* position the cursor (the onset clock drives all pacing); accepted for
|
|
708
|
+
* back-compat and ignored. */
|
|
710
709
|
musicMs?: number;
|
|
711
710
|
/** Cursor stroke colour. Defaults to theme.accent. */
|
|
712
711
|
color?: string;
|
|
@@ -731,29 +730,38 @@ declare function measureSpanBox(rn: RenderedNotation, lo: number, hi: number): B
|
|
|
731
730
|
declare function firstMeasureBox(rn: RenderedNotation): Box | null;
|
|
732
731
|
/** Number of distinct measures in the notation. (RSR measureCount) */
|
|
733
732
|
declare function measureCount(rn: RenderedNotation): number;
|
|
733
|
+
/** The DISTINCT measure indices present in the engraving, ASCENDING. For excerpts
|
|
734
|
+
* these do NOT start at 0 (e.g. bars 5-8 → [4,5,6,7]) and may be non-contiguous,
|
|
735
|
+
* so the follow window must scroll across THESE indices, not a 0..measureCount
|
|
736
|
+
* range. (measureCount returns maxIndex+1 — a count valid only for 0-based scores.) */
|
|
737
|
+
declare function distinctMeasureIndices(rn: RenderedNotation): number[];
|
|
734
738
|
/** The follow window (canvas coords) for a continuous measure-start position,
|
|
735
739
|
* spanning FOLLOW_BARS and lerping between adjacent windows. (RSR followBoxAt) */
|
|
736
740
|
declare function followBoxAt(rn: RenderedNotation, posMeasures: number): Box | null;
|
|
737
741
|
/**
|
|
738
|
-
* The continuous follow-window START measure for an
|
|
742
|
+
* The continuous follow-window START measure (ABSOLUTE index) for an hstack
|
|
743
|
+
* audio-clock progress 0..1.
|
|
739
744
|
*
|
|
740
|
-
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
743
|
-
*
|
|
744
|
-
* once the playhead reaches the bottom bar. Concretely the resting window start is
|
|
745
|
-
* `curBar - (FOLLOW_BARS - 1)`; over the tail of each bar we ease that forward by
|
|
746
|
-
* one bar so the NEXT bar slides into the bottom slot just as the playhead crosses
|
|
747
|
-
* into it. Because the eased start stays within `[curBar-(FOLLOW_BARS-1),
|
|
748
|
-
* curBar-(FOLLOW_BARS-2)]`, `curBar` never leaves `[start, start+FOLLOW_BARS)` —
|
|
749
|
-
* the current measure (and its playhead) can never ride off the top.
|
|
745
|
+
* hstack (single horizontal staffline): pan CONTINUOUSLY so the playhead sits at a
|
|
746
|
+
* stable fraction (`HSTACK_PLAYHEAD_LEAD`) from the LEFT of the window — the playing
|
|
747
|
+
* bar is always on screen with look-ahead to its right, and the cursor never drifts
|
|
748
|
+
* to the screen edge.
|
|
750
749
|
*
|
|
751
|
-
*
|
|
752
|
-
*
|
|
753
|
-
*
|
|
754
|
-
*
|
|
750
|
+
* BUG FIX (web-core 0.21.0) — playhead pinned at the right edge for EXCERPTS. This
|
|
751
|
+
* used to take `nBars = measureCount(rn) = maxIndex+1` and pan progress across a
|
|
752
|
+
* 0..nBars range. That is only correct when measure indices are 0-based: RSR's
|
|
753
|
+
* excerpts engrave e.g. bars 5-8 → indices [4,5,6,7], so measureCount=8 but only 4
|
|
754
|
+
* measures exist. The window then panned a phantom 0..8 axis while the playhead
|
|
755
|
+
* (which steps over the 4 REAL columns) raced ahead — pinning the cursor at the far
|
|
756
|
+
* right while the music barely scrolled. We now pan across the ACTUAL distinct
|
|
757
|
+
* indices: progress 0..1 maps to absolute index `firstIndex .. firstIndex+nReal`,
|
|
758
|
+
* and `followBoxAt` (which already indexes absolute measures via measureSpanBox)
|
|
759
|
+
* frames the right bars. Clamped so the window never runs past the last measure.
|
|
760
|
+
*
|
|
761
|
+
* Pass the RenderedNotation so the real index range is known. (The legacy 0-based
|
|
762
|
+
* `nBars`-only call still works via the `firstIndex=0, nReal=nBars` fallback.)
|
|
755
763
|
*/
|
|
756
|
-
declare function followWindowStart(
|
|
764
|
+
declare function followWindowStart(rn: RenderedNotation | number, camProgress01: number): number;
|
|
757
765
|
/** For each measure index, the system (row) it lives on — ordered by index.
|
|
758
766
|
* Empty when geometry is missing. */
|
|
759
767
|
declare function measureSystemMap(rn: RenderedNotation): number[];
|
|
@@ -1620,4 +1628,4 @@ interface SectionMinimapProps {
|
|
|
1620
1628
|
}
|
|
1621
1629
|
declare const sectionMinimapFactory: LayerFactory<SectionMinimapProps>;
|
|
1622
1630
|
|
|
1623
|
-
export { type Affine, type AudioClock, type AudioEvent, type BackgroundProps, type BeatGridOpts, type BeatTick, type BrandingProps, type BufferFactory, type BuildSceneOpts, type BuiltScene, type CameraState, type CaptionCue, type CaptionProps, type CaptionScript, type CaptionStyle, type ChordSpan, type CircleOfFifthsProps, type CirclePoint, type ClickTrackOpts, type ColorBy, type ContourPlot, type ContourPoint, type CountInOpts, type CountingTrackProps, type CtaProps, DEFAULT_FUNCTION_COLORS, type DegreeLabel, type DegreeLabelsProps, type DroneOpts, type DuckWindow, type Easing, type ExtendedDemoOpts, FIFTHS_MAJOR, FIFTHS_MINOR, FOLLOW_BARS, FOLLOW_PAD, type FallingKeyboardDemoOpts, type FallingNotesProps, type FunctionColors, type FunctionalHarmonyProps, type GateError, type GateInput, type HandColors, type HarmonicFunction, type HarmonyMode, type HighlightRegion, type HookProps, type KeyRect, type KeyboardLayout, type KeyboardLayoutOpts, type KeyboardProps, type LabelMode, type Layer, type LayerFactory, type McqCardProps, type NotationEngraving, type NotationLayout, type NotationLayoutOpts, type NotationProps, type NotationRect, type OutputProbe, PIANO_HIGH, PIANO_LOW, type PitchContourProps, type Placement, type PlayheadLine, type PortraitProps, type PromoCardsDemoOpts, type Quiz, type QuizOption, type QuizPhase, type RayEndpoints, type RecordSceneSpecOpts, type Rect, type RenderCtx, type ResolvedSegment, type RevealProps, type SafeGuidesProps, type SceneSpec, type ScheduleTarget, type Score, type ScoreFromMusicXMLOpts, type ScoreNote, type ScrollCursorProps, type Section, type SectionMinimapProps, type SegmentAudio, type SegmentAudioCtx, type SegmentTransition, type SpecLayer, type SpectrumInput, type SpectrumProps, type StaffKeyboardRayProps, type TempoMap, type TimeAnchor, type TimelineSegment, activeChord, activeCue, activeSection, animatedSlot, applySchedule, applyToContext, assertGate, audioPlayheadLine, ballArc, ballX, beatGrid, beatPhase, blackKeys, bpmOf, brandingFactory, buildScene, cameraForFollow, cameraTransform, circleOfFifthsDemoSpec, circleOfFifthsFactory, clamp, clickTrackSchedule, contourMinimapDemoSpec, contourPoints, contourPolyline, countInLeadSec, countInSchedule, countdownRemaining, countdownSeconds, countingDegreeDemoSpec, countingTrackFactory, cropAroundBox, ctaFactory, cubicEaseInOut, cueOpacity, degreeLabel, degreeLabelsFactory, distinctOnsets, dotAt, drawCaption, drawHighlight, droneSchedule, duckGainAt, easeIn, easeInOut, easeOut, fallingKeyboardDemoScore, fallingKeyboardDemoSpec, fallingNotesFactory, firstMeasureBox, followBoxAt, followSrcBox, followWindowStart, fracSlotPoint, frameRect, functionColor, functionalHarmonyFactory, getKeyboardLayout, getLayerFactory, getNotationEngraving, harmonyDemoSpec, highlightIntensity, hookFactory, identityCamera, inRange, invLerp, isBlackKey, kenBurns, keyCenterX, keyColumnWidth, keyRect, keySlot, keyboardFactory, keyboardLayout, lerp, lerpBox, lerpCamera, linear, mapBoxThroughLayout, mcqCardFactory, mcqDemoSpec, measureColumnsFromLayout, measureCount, measureSpanBox, measureSpans, measureSystemMap, timeToX as minimapTimeToX, msPerBeat, notationFactory, notationLayout, noteColor, noteSetXRange, parseKey, parseTimeSig, pcToSlot, pitchAt, pitchContourFactory, pitchRange, playheadLine, portraitFactory, progress01, projectPoint, promoCardsDemoSpec, quizPhase, rayEndpoints, rayPointAt, recordSceneSpec, registerLayer, registeredKeys, resolveAnchor, resolveKeyboardLayout, resolveTimeline, revealFactory, revealProgress, runGate, safeGuidesFactory, scoreFromMusicXML, scorePitchSpan, scrollCursorFactory, sectionMinimapFactory, setFollowLayoutProvider, setKeyboardLayout, setNotationEngraving, slotAngle, slotPc, slotPoint, spectrumFactory, staffAnchor, staffKeyboardRayFactory, staffRayDemoSpec, systemBox, transitionProgress, validateChordTrack, validateQuiz, validateSections, visualTimelineMs, vstackAudioPlayheadLine, vstackFollowBox, whiteKeys, worldToViewport };
|
|
1631
|
+
export { type Affine, type AudioClock, type AudioEvent, type BackgroundProps, type BeatGridOpts, type BeatTick, type BrandingProps, type BufferFactory, type BuildSceneOpts, type BuiltScene, type CameraState, type CaptionCue, type CaptionProps, type CaptionScript, type CaptionStyle, type ChordSpan, type CircleOfFifthsProps, type CirclePoint, type ClickTrackOpts, type ColorBy, type ContourPlot, type ContourPoint, type CountInOpts, type CountingTrackProps, type CtaProps, DEFAULT_FUNCTION_COLORS, type DegreeLabel, type DegreeLabelsProps, type DroneOpts, type DuckWindow, type Easing, type ExtendedDemoOpts, FIFTHS_MAJOR, FIFTHS_MINOR, FOLLOW_BARS, FOLLOW_PAD, type FallingKeyboardDemoOpts, type FallingNotesProps, type FunctionColors, type FunctionalHarmonyProps, type GateError, type GateInput, type HandColors, type HarmonicFunction, type HarmonyMode, type HighlightRegion, type HookProps, type KeyRect, type KeyboardLayout, type KeyboardLayoutOpts, type KeyboardProps, type LabelMode, type Layer, type LayerFactory, type McqCardProps, type NotationEngraving, type NotationLayout, type NotationLayoutOpts, type NotationProps, type NotationRect, type OutputProbe, PIANO_HIGH, PIANO_LOW, type PitchContourProps, type Placement, type PlayheadLine, type PortraitProps, type PromoCardsDemoOpts, type Quiz, type QuizOption, type QuizPhase, type RayEndpoints, type RecordSceneSpecOpts, type Rect, type RenderCtx, type ResolvedSegment, type RevealProps, type SafeGuidesProps, type SceneSpec, type ScheduleTarget, type Score, type ScoreFromMusicXMLOpts, type ScoreNote, type ScrollCursorProps, type Section, type SectionMinimapProps, type SegmentAudio, type SegmentAudioCtx, type SegmentTransition, type SpecLayer, type SpectrumInput, type SpectrumProps, type StaffKeyboardRayProps, type TempoMap, type TimeAnchor, type TimelineSegment, activeChord, activeCue, activeSection, animatedSlot, applySchedule, applyToContext, assertGate, audioPlayheadLine, ballArc, ballX, beatGrid, beatPhase, blackKeys, bpmOf, brandingFactory, buildScene, cameraForFollow, cameraTransform, circleOfFifthsDemoSpec, circleOfFifthsFactory, clamp, clickTrackSchedule, contourMinimapDemoSpec, contourPoints, contourPolyline, countInLeadSec, countInSchedule, countdownRemaining, countdownSeconds, countingDegreeDemoSpec, countingTrackFactory, cropAroundBox, ctaFactory, cubicEaseInOut, cueOpacity, degreeLabel, degreeLabelsFactory, distinctMeasureIndices, distinctOnsets, dotAt, drawCaption, drawHighlight, droneSchedule, duckGainAt, easeIn, easeInOut, easeOut, fallingKeyboardDemoScore, fallingKeyboardDemoSpec, fallingNotesFactory, firstMeasureBox, followBoxAt, followSrcBox, followWindowStart, fracSlotPoint, frameRect, functionColor, functionalHarmonyFactory, getKeyboardLayout, getLayerFactory, getNotationEngraving, harmonyDemoSpec, highlightIntensity, hookFactory, identityCamera, inRange, invLerp, isBlackKey, kenBurns, keyCenterX, keyColumnWidth, keyRect, keySlot, keyboardFactory, keyboardLayout, lerp, lerpBox, lerpCamera, linear, mapBoxThroughLayout, mcqCardFactory, mcqDemoSpec, measureColumnsFromLayout, measureCount, measureSpanBox, measureSpans, measureSystemMap, timeToX as minimapTimeToX, msPerBeat, notationFactory, notationLayout, noteColor, noteSetXRange, parseKey, parseTimeSig, pcToSlot, pitchAt, pitchContourFactory, pitchRange, playheadLine, portraitFactory, progress01, projectPoint, promoCardsDemoSpec, quizPhase, rayEndpoints, rayPointAt, recordSceneSpec, registerLayer, registeredKeys, resolveAnchor, resolveKeyboardLayout, resolveTimeline, revealFactory, revealProgress, runGate, safeGuidesFactory, scoreFromMusicXML, scorePitchSpan, scrollCursorFactory, sectionMinimapFactory, setFollowLayoutProvider, setKeyboardLayout, setNotationEngraving, slotAngle, slotPc, slotPoint, spectrumFactory, staffAnchor, staffKeyboardRayFactory, staffRayDemoSpec, systemBox, transitionProgress, validateChordTrack, validateQuiz, validateSections, visualTimelineMs, vstackAudioPlayheadLine, vstackFollowBox, whiteKeys, worldToViewport };
|
package/dist/scene/index.js
CHANGED
|
@@ -390,6 +390,11 @@ function measureCount(rn) {
|
|
|
390
390
|
const idx = (rn.measures ?? []).map((m) => m.index);
|
|
391
391
|
return idx.length ? Math.max(...idx) + 1 : 0;
|
|
392
392
|
}
|
|
393
|
+
function distinctMeasureIndices(rn) {
|
|
394
|
+
const set = /* @__PURE__ */ new Set();
|
|
395
|
+
for (const m of rn.measures ?? []) set.add(m.index);
|
|
396
|
+
return [...set].sort((a, b) => a - b);
|
|
397
|
+
}
|
|
393
398
|
function followBoxAt(rn, posMeasures) {
|
|
394
399
|
const cur = Math.floor(posMeasures);
|
|
395
400
|
const frac = posMeasures - cur;
|
|
@@ -399,14 +404,25 @@ function followBoxAt(rn, posMeasures) {
|
|
|
399
404
|
if (!b) return a;
|
|
400
405
|
return lerpBox(a, b, frac);
|
|
401
406
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
407
|
+
var HSTACK_PLAYHEAD_LEAD = 0.35;
|
|
408
|
+
function followWindowStart(rn, camProgress01) {
|
|
409
|
+
let firstIndex;
|
|
410
|
+
let nReal;
|
|
411
|
+
if (typeof rn === "number") {
|
|
412
|
+
firstIndex = 0;
|
|
413
|
+
nReal = rn;
|
|
414
|
+
} else {
|
|
415
|
+
const idx = distinctMeasureIndices(rn);
|
|
416
|
+
firstIndex = idx.length ? idx[0] : 0;
|
|
417
|
+
nReal = idx.length;
|
|
418
|
+
}
|
|
419
|
+
const p = Math.max(0, Math.min(1, camProgress01));
|
|
420
|
+
const posBars = firstIndex + p * nReal;
|
|
421
|
+
const start = posBars - HSTACK_PLAYHEAD_LEAD * FOLLOW_BARS;
|
|
422
|
+
const lastIndex = firstIndex + Math.max(0, nReal - 1);
|
|
423
|
+
const minStart = firstIndex;
|
|
424
|
+
const maxStart = Math.max(minStart, lastIndex - (FOLLOW_BARS - 1));
|
|
425
|
+
return Math.max(minStart, Math.min(maxStart, start));
|
|
410
426
|
}
|
|
411
427
|
function systemIndexOfBox(systems, box) {
|
|
412
428
|
if (!systems.length) return 0;
|
|
@@ -802,25 +818,18 @@ var notationFactory = {
|
|
|
802
818
|
};
|
|
803
819
|
|
|
804
820
|
// src/scene/layers/scrollCursor.ts
|
|
805
|
-
function followLayoutFor(ctx,
|
|
821
|
+
function followLayoutFor(ctx, progress012, scrollMode) {
|
|
806
822
|
const eng = getNotationEngraving(ctx);
|
|
807
823
|
if (!eng) return null;
|
|
808
824
|
const nBars = measureCount(eng.rendered);
|
|
809
825
|
if (nBars <= 0) return eng.base;
|
|
810
|
-
const focusBox = scrollMode === "vstack" ? vstackFollowBox(eng.rendered,
|
|
826
|
+
const focusBox = scrollMode === "vstack" ? vstackFollowBox(eng.rendered, progress012) : followBoxAt(eng.rendered, followWindowStart(eng.rendered, progress012));
|
|
811
827
|
return notationLayout(eng.rendered, ctx.W, ctx.H, eng.bandTop, eng.bandHeight, { focusBox });
|
|
812
828
|
}
|
|
813
829
|
function scrollCursorLayer() {
|
|
814
|
-
let mode = "audio";
|
|
815
830
|
let scrollMode = "hstack";
|
|
816
|
-
let musicMs = 0;
|
|
817
831
|
let openingZoomMs = 900;
|
|
818
832
|
let color;
|
|
819
|
-
function camProgress(tMs) {
|
|
820
|
-
const phMs = tMs - openingZoomMs;
|
|
821
|
-
if (phMs < 0 || musicMs <= 0) return 0;
|
|
822
|
-
return Math.min(1, phMs / musicMs);
|
|
823
|
-
}
|
|
824
833
|
function onsetsFor(ctx) {
|
|
825
834
|
const notes = ctx.score?.notes;
|
|
826
835
|
return notes && notes.length ? distinctOnsets(notes) : [];
|
|
@@ -843,9 +852,7 @@ function scrollCursorLayer() {
|
|
|
843
852
|
return (lo + segFrac) / (n - 1);
|
|
844
853
|
}
|
|
845
854
|
function followProgress(ctx, tMs) {
|
|
846
|
-
|
|
847
|
-
const onsets = onsetsFor(ctx);
|
|
848
|
-
return onsets.length ? notesProgress(onsets, tMs) : camProgress(tMs);
|
|
855
|
+
return notesProgress(onsetsFor(ctx), tMs);
|
|
849
856
|
}
|
|
850
857
|
function layoutAt(ctx, tMs) {
|
|
851
858
|
const eng = getNotationEngraving(ctx);
|
|
@@ -854,9 +861,7 @@ function scrollCursorLayer() {
|
|
|
854
861
|
return {
|
|
855
862
|
key: "scroll-cursor",
|
|
856
863
|
init(ctx, props) {
|
|
857
|
-
mode = props.mode ?? "audio";
|
|
858
864
|
scrollMode = props.scrollMode ?? "hstack";
|
|
859
|
-
musicMs = props.musicMs ?? 0;
|
|
860
865
|
openingZoomMs = props.openingZoomMs ?? 900;
|
|
861
866
|
color = props.color;
|
|
862
867
|
setFollowLayoutProvider(ctx, layoutAt);
|
|
@@ -865,16 +870,12 @@ function scrollCursorLayer() {
|
|
|
865
870
|
const eng = getNotationEngraving(ctx);
|
|
866
871
|
if (!eng) return;
|
|
867
872
|
const layout = layoutAt(ctx, tMs);
|
|
873
|
+
const onsets = onsetsFor(ctx);
|
|
868
874
|
let line;
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
if (scrollMode === "vstack") {
|
|
872
|
-
line = vstackAudioPlayheadLine(layout, onsets, tMs, measureCount(eng.rendered));
|
|
873
|
-
} else {
|
|
874
|
-
line = audioPlayheadLine(layout, onsets, tMs);
|
|
875
|
-
}
|
|
875
|
+
if (scrollMode === "vstack") {
|
|
876
|
+
line = vstackAudioPlayheadLine(layout, onsets, tMs, measureCount(eng.rendered));
|
|
876
877
|
} else {
|
|
877
|
-
line =
|
|
878
|
+
line = audioPlayheadLine(layout, onsets, tMs);
|
|
878
879
|
}
|
|
879
880
|
if (!line) return;
|
|
880
881
|
const c = ctx.ctx2d;
|
|
@@ -901,8 +902,6 @@ var scrollCursorFactory = {
|
|
|
901
902
|
errs.push('scroll-cursor.mode must be "audio" | "linear"');
|
|
902
903
|
if (p.scrollMode != null && p.scrollMode !== "hstack" && p.scrollMode !== "vstack")
|
|
903
904
|
errs.push('scroll-cursor.scrollMode must be "hstack" | "vstack"');
|
|
904
|
-
if (p.mode === "linear" && (typeof p.musicMs !== "number" || !(p.musicMs > 0)))
|
|
905
|
-
errs.push('scroll-cursor.musicMs must be a positive number for mode:"linear"');
|
|
906
905
|
if (p.musicMs != null && (typeof p.musicMs !== "number" || !(p.musicMs > 0)))
|
|
907
906
|
errs.push("scroll-cursor.musicMs must be a positive number");
|
|
908
907
|
if (p.followBars != null && (typeof p.followBars !== "number" || p.followBars < 1))
|
|
@@ -3812,6 +3811,7 @@ export {
|
|
|
3812
3811
|
cueOpacity,
|
|
3813
3812
|
degreeLabel,
|
|
3814
3813
|
degreeLabelsFactory,
|
|
3814
|
+
distinctMeasureIndices,
|
|
3815
3815
|
distinctOnsets,
|
|
3816
3816
|
dotAt,
|
|
3817
3817
|
drawCaption,
|