@waveform-playlist/core 12.6.0 → 12.6.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.
- package/dist/index.d.mts +80 -1
- package/dist/index.d.ts +80 -1
- package/dist/index.js +177 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +168 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -476,6 +476,10 @@ interface AnnotationData {
|
|
|
476
476
|
end: number;
|
|
477
477
|
lines: string[];
|
|
478
478
|
language?: string;
|
|
479
|
+
/** Musical position (ticks). Authoritative when BOTH tick fields are set —
|
|
480
|
+
* start/end seconds are then a derived cache (clip startTick pattern). */
|
|
481
|
+
startTick?: number;
|
|
482
|
+
endTick?: number;
|
|
479
483
|
}
|
|
480
484
|
/**
|
|
481
485
|
* Annotation format definition for parsing/serializing
|
|
@@ -775,6 +779,21 @@ declare const MIN_PIXELS_PER_UNIT = 8;
|
|
|
775
779
|
* correct across meter changes.
|
|
776
780
|
*/
|
|
777
781
|
declare function computeMusicalTicks(params: MusicalTickParams): MusicalTickData;
|
|
782
|
+
/**
|
|
783
|
+
* Convert an absolute tick to a 1-based bar.beat position, honoring meter
|
|
784
|
+
* changes. Bars/beats are counted per meter segment (the same walk
|
|
785
|
+
* `computeMusicalTicks` uses to build its `barOffset` accumulator). Beat is
|
|
786
|
+
* the integer beat the tick falls WITHIN (floor, 1-based) — a tick exactly on
|
|
787
|
+
* a bar line is beat 1.
|
|
788
|
+
*
|
|
789
|
+
* Guards: empty `meterEntries` → treat as 4/4 from tick 0. `ppqn <= 0` →
|
|
790
|
+
* returns `{ bar: 1, beat: 1 }` (division-by-zero guard, matches
|
|
791
|
+
* `computeMusicalTicks`'s ppqn guard).
|
|
792
|
+
*/
|
|
793
|
+
declare function ticksToBarBeat(tick: number, meterEntries: MeterEntry[], ppqn: number): {
|
|
794
|
+
bar: number;
|
|
795
|
+
beat: number;
|
|
796
|
+
};
|
|
778
797
|
/**
|
|
779
798
|
* Snaps a tick position to the nearest grid boundary defined by `snapTo`.
|
|
780
799
|
*
|
|
@@ -1025,6 +1044,13 @@ interface KeyboardShortcut {
|
|
|
1025
1044
|
description?: string;
|
|
1026
1045
|
preventDefault?: boolean;
|
|
1027
1046
|
}
|
|
1047
|
+
/** A key + modifier combination, without an action. Used for remapping maps. */
|
|
1048
|
+
type KeyBinding = Pick<KeyboardShortcut, 'key' | 'ctrlKey' | 'shiftKey' | 'metaKey' | 'altKey'>;
|
|
1049
|
+
/**
|
|
1050
|
+
* Does a keyboard event match a key binding?
|
|
1051
|
+
* `undefined` modifier = match any state; `false` = must NOT be pressed.
|
|
1052
|
+
*/
|
|
1053
|
+
declare function matchesKeyBinding(event: KeyboardEvent, binding: KeyBinding): boolean;
|
|
1028
1054
|
/**
|
|
1029
1055
|
* Handle a keyboard event against a list of shortcuts.
|
|
1030
1056
|
* Pure function, no framework dependency.
|
|
@@ -1114,4 +1140,57 @@ declare function enumerateMicrophones(mediaDevices?: MediaDevices): Promise<Micr
|
|
|
1114
1140
|
*/
|
|
1115
1141
|
declare function watchMicrophoneDevices(listener: (enumeration: MicrophoneEnumeration) => void, mediaDevices?: MediaDevices): () => void;
|
|
1116
1142
|
|
|
1117
|
-
|
|
1143
|
+
/** Edges within this distance (seconds) are considered "linked". */
|
|
1144
|
+
declare const LINK_THRESHOLD = 0.01;
|
|
1145
|
+
/** Minimum annotation duration (seconds) enforced by boundary edits. */
|
|
1146
|
+
declare const MIN_ANNOTATION_DURATION = 0.1;
|
|
1147
|
+
/** Link threshold for INTEGER TICK positions — closer than half a tick means equal. */
|
|
1148
|
+
declare const ANNOTATION_LINK_THRESHOLD_TICKS = 0.5;
|
|
1149
|
+
/** Minimum tick-annotation duration: a 128th note, floored at 1 tick. */
|
|
1150
|
+
declare function annotationMinDurationTicks(ppqn: number): number;
|
|
1151
|
+
/** Unit constants for a boundary-math run. Defaults are the seconds-domain values. */
|
|
1152
|
+
interface AnnotationBoundaryOptions {
|
|
1153
|
+
linkThreshold?: number;
|
|
1154
|
+
minDuration?: number;
|
|
1155
|
+
}
|
|
1156
|
+
interface AnnotationBoundaryUpdate {
|
|
1157
|
+
annotationIndex: number;
|
|
1158
|
+
newTime: number;
|
|
1159
|
+
isDraggingStart: boolean;
|
|
1160
|
+
annotations: AnnotationData[];
|
|
1161
|
+
duration: number;
|
|
1162
|
+
linkEndpoints: boolean;
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Pure boundary-update logic shared by the React annotations package and the
|
|
1166
|
+
* dawcore annotation web components. Handles linked endpoints (moving one edge
|
|
1167
|
+
* drags the linked neighbor edge, with cascade) and collision push-back.
|
|
1168
|
+
* Returns a NEW array; never mutates inputs.
|
|
1169
|
+
*/
|
|
1170
|
+
declare function updateAnnotationBoundaries(params: AnnotationBoundaryUpdate, options?: AnnotationBoundaryOptions): AnnotationData[];
|
|
1171
|
+
|
|
1172
|
+
type AnnotationShortcutAction = 'selectPrevious' | 'selectNext' | 'selectFirst' | 'selectLast' | 'clearSelection' | 'moveStartEarlier' | 'moveStartLater' | 'moveEndEarlier' | 'moveEndLater' | 'playActive';
|
|
1173
|
+
/** Key remapping map — null on the consumer means "use defaults". */
|
|
1174
|
+
interface AnnotationShortcutMap {
|
|
1175
|
+
selectPrevious?: KeyBinding;
|
|
1176
|
+
selectNext?: KeyBinding;
|
|
1177
|
+
selectFirst?: KeyBinding;
|
|
1178
|
+
selectLast?: KeyBinding;
|
|
1179
|
+
clearSelection?: KeyBinding;
|
|
1180
|
+
moveStartEarlier?: KeyBinding;
|
|
1181
|
+
moveStartLater?: KeyBinding;
|
|
1182
|
+
moveEndEarlier?: KeyBinding;
|
|
1183
|
+
moveEndLater?: KeyBinding;
|
|
1184
|
+
playActive?: KeyBinding;
|
|
1185
|
+
}
|
|
1186
|
+
declare const DEFAULT_ANNOTATION_SHORTCUTS: Record<AnnotationShortcutAction, KeyBinding[]>;
|
|
1187
|
+
/**
|
|
1188
|
+
* Flatten defaults + remap into a matchable list. A remapped action replaces
|
|
1189
|
+
* ALL of its default bindings with the single provided binding.
|
|
1190
|
+
*/
|
|
1191
|
+
declare function resolveAnnotationShortcuts(remap: AnnotationShortcutMap | null): Array<{
|
|
1192
|
+
action: AnnotationShortcutAction;
|
|
1193
|
+
binding: KeyBinding;
|
|
1194
|
+
}>;
|
|
1195
|
+
|
|
1196
|
+
export { ANNOTATION_LINK_THRESHOLD_TICKS, type AnnotationAction, type AnnotationActionOptions, type AnnotationBoundaryOptions, type AnnotationBoundaryUpdate, type AnnotationData, type AnnotationEventMap, type AnnotationFormat, type AnnotationListOptions, type AnnotationShortcutAction, type AnnotationShortcutMap, type AudioBuffer$1 as AudioBuffer, type AudioClip, type Bits, type ClipTrack, type ColorMapEntry, type ColorMapName, type ColorMapValue, type CreateClipOptions, type CreateClipOptionsSeconds, type CreateClipOptionsTicks, type CreateTrackOptions, DEFAULT_ANNOTATION_SHORTCUTS, DEFAULT_SPECTROGRAM_COLOR_MAP, type FFTSize, type Fade, type FadeConfig, type FadeType, type Gap, InteractionState, type KeyBinding, type KeyboardShortcut, LINK_THRESHOLD, MAX_CANVAS_WIDTH, MIN_ANNOTATION_DURATION, MIN_PIXELS_PER_UNIT, type MeterEntry, type MicrophoneDeviceInfo, type MicrophoneEnumeration, type MidiNoteData, type MusicalTick, type MusicalTickData, type MusicalTickParams, PPQN, type PeakData, type Peaks, type PlaylistConfig, type PlayoutState, type RangeSupport, type RenderAnnotationItemProps, type RenderMode, SPECTROGRAM_DEFAULTS, type SnapTo, type SpectrogramCanvasIdParts, type SpectrogramComputeConfig, type SpectrogramConfig, type SpectrogramData, type SpectrogramDisplayConfig, type TickType, type TimeSelection, type Timeline, type Track, type TrackEffectsFunction, type TrackSpectrogramOverrides, type WaveformConfig, type WaveformDataObject, type ZoomLevel, annotationMinDurationTicks, appendPeaks, appendToAudioBuffer, applyFadeIn, applyFadeOut, audibleLatencySamples, buildSpectrogramCanvasId, calculateDuration, carveClipRange, clipDurationTime, clipEndTime, clipOffsetTime, clipPixelWidth, clipStartTime, clipsOverlap, computeMusicalTicks, concatenateAudioData, createAudioBuffer, createClip, createClipFromSeconds, createClipFromTicks, createTimeline, createTrack, dBToNormalized, detectMeterChanges, enumerateMicrophones, exponentialCurve, findGaps, gainToDb, gainToNormalized, generateCurve, generatePeaks, getClipsAtSample, getClipsInRange, getShortcutLabel, handleKeyboardEvent, linearCurve, logarithmicCurve, matchesKeyBinding, normalizedToDb, parseSpectrogramCanvasId, pixelsToSamples, pixelsToSeconds, probeRangeSupport, resolveAnnotationShortcuts, resolveRecordingOffsetSamples, sCurveCurve, samplesToPixels, samplesToSeconds, samplesToTicks, secondsToPixels, secondsToSamples, snapTickToGrid, snapToGrid, snapToTicks, sortClipsByTime, ticksPerBar, ticksPerBeat, ticksToBarBeat, ticksToSamples, trackChannelCount, updateAnnotationBoundaries, watchMicrophoneDevices };
|
package/dist/index.d.ts
CHANGED
|
@@ -476,6 +476,10 @@ interface AnnotationData {
|
|
|
476
476
|
end: number;
|
|
477
477
|
lines: string[];
|
|
478
478
|
language?: string;
|
|
479
|
+
/** Musical position (ticks). Authoritative when BOTH tick fields are set —
|
|
480
|
+
* start/end seconds are then a derived cache (clip startTick pattern). */
|
|
481
|
+
startTick?: number;
|
|
482
|
+
endTick?: number;
|
|
479
483
|
}
|
|
480
484
|
/**
|
|
481
485
|
* Annotation format definition for parsing/serializing
|
|
@@ -775,6 +779,21 @@ declare const MIN_PIXELS_PER_UNIT = 8;
|
|
|
775
779
|
* correct across meter changes.
|
|
776
780
|
*/
|
|
777
781
|
declare function computeMusicalTicks(params: MusicalTickParams): MusicalTickData;
|
|
782
|
+
/**
|
|
783
|
+
* Convert an absolute tick to a 1-based bar.beat position, honoring meter
|
|
784
|
+
* changes. Bars/beats are counted per meter segment (the same walk
|
|
785
|
+
* `computeMusicalTicks` uses to build its `barOffset` accumulator). Beat is
|
|
786
|
+
* the integer beat the tick falls WITHIN (floor, 1-based) — a tick exactly on
|
|
787
|
+
* a bar line is beat 1.
|
|
788
|
+
*
|
|
789
|
+
* Guards: empty `meterEntries` → treat as 4/4 from tick 0. `ppqn <= 0` →
|
|
790
|
+
* returns `{ bar: 1, beat: 1 }` (division-by-zero guard, matches
|
|
791
|
+
* `computeMusicalTicks`'s ppqn guard).
|
|
792
|
+
*/
|
|
793
|
+
declare function ticksToBarBeat(tick: number, meterEntries: MeterEntry[], ppqn: number): {
|
|
794
|
+
bar: number;
|
|
795
|
+
beat: number;
|
|
796
|
+
};
|
|
778
797
|
/**
|
|
779
798
|
* Snaps a tick position to the nearest grid boundary defined by `snapTo`.
|
|
780
799
|
*
|
|
@@ -1025,6 +1044,13 @@ interface KeyboardShortcut {
|
|
|
1025
1044
|
description?: string;
|
|
1026
1045
|
preventDefault?: boolean;
|
|
1027
1046
|
}
|
|
1047
|
+
/** A key + modifier combination, without an action. Used for remapping maps. */
|
|
1048
|
+
type KeyBinding = Pick<KeyboardShortcut, 'key' | 'ctrlKey' | 'shiftKey' | 'metaKey' | 'altKey'>;
|
|
1049
|
+
/**
|
|
1050
|
+
* Does a keyboard event match a key binding?
|
|
1051
|
+
* `undefined` modifier = match any state; `false` = must NOT be pressed.
|
|
1052
|
+
*/
|
|
1053
|
+
declare function matchesKeyBinding(event: KeyboardEvent, binding: KeyBinding): boolean;
|
|
1028
1054
|
/**
|
|
1029
1055
|
* Handle a keyboard event against a list of shortcuts.
|
|
1030
1056
|
* Pure function, no framework dependency.
|
|
@@ -1114,4 +1140,57 @@ declare function enumerateMicrophones(mediaDevices?: MediaDevices): Promise<Micr
|
|
|
1114
1140
|
*/
|
|
1115
1141
|
declare function watchMicrophoneDevices(listener: (enumeration: MicrophoneEnumeration) => void, mediaDevices?: MediaDevices): () => void;
|
|
1116
1142
|
|
|
1117
|
-
|
|
1143
|
+
/** Edges within this distance (seconds) are considered "linked". */
|
|
1144
|
+
declare const LINK_THRESHOLD = 0.01;
|
|
1145
|
+
/** Minimum annotation duration (seconds) enforced by boundary edits. */
|
|
1146
|
+
declare const MIN_ANNOTATION_DURATION = 0.1;
|
|
1147
|
+
/** Link threshold for INTEGER TICK positions — closer than half a tick means equal. */
|
|
1148
|
+
declare const ANNOTATION_LINK_THRESHOLD_TICKS = 0.5;
|
|
1149
|
+
/** Minimum tick-annotation duration: a 128th note, floored at 1 tick. */
|
|
1150
|
+
declare function annotationMinDurationTicks(ppqn: number): number;
|
|
1151
|
+
/** Unit constants for a boundary-math run. Defaults are the seconds-domain values. */
|
|
1152
|
+
interface AnnotationBoundaryOptions {
|
|
1153
|
+
linkThreshold?: number;
|
|
1154
|
+
minDuration?: number;
|
|
1155
|
+
}
|
|
1156
|
+
interface AnnotationBoundaryUpdate {
|
|
1157
|
+
annotationIndex: number;
|
|
1158
|
+
newTime: number;
|
|
1159
|
+
isDraggingStart: boolean;
|
|
1160
|
+
annotations: AnnotationData[];
|
|
1161
|
+
duration: number;
|
|
1162
|
+
linkEndpoints: boolean;
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Pure boundary-update logic shared by the React annotations package and the
|
|
1166
|
+
* dawcore annotation web components. Handles linked endpoints (moving one edge
|
|
1167
|
+
* drags the linked neighbor edge, with cascade) and collision push-back.
|
|
1168
|
+
* Returns a NEW array; never mutates inputs.
|
|
1169
|
+
*/
|
|
1170
|
+
declare function updateAnnotationBoundaries(params: AnnotationBoundaryUpdate, options?: AnnotationBoundaryOptions): AnnotationData[];
|
|
1171
|
+
|
|
1172
|
+
type AnnotationShortcutAction = 'selectPrevious' | 'selectNext' | 'selectFirst' | 'selectLast' | 'clearSelection' | 'moveStartEarlier' | 'moveStartLater' | 'moveEndEarlier' | 'moveEndLater' | 'playActive';
|
|
1173
|
+
/** Key remapping map — null on the consumer means "use defaults". */
|
|
1174
|
+
interface AnnotationShortcutMap {
|
|
1175
|
+
selectPrevious?: KeyBinding;
|
|
1176
|
+
selectNext?: KeyBinding;
|
|
1177
|
+
selectFirst?: KeyBinding;
|
|
1178
|
+
selectLast?: KeyBinding;
|
|
1179
|
+
clearSelection?: KeyBinding;
|
|
1180
|
+
moveStartEarlier?: KeyBinding;
|
|
1181
|
+
moveStartLater?: KeyBinding;
|
|
1182
|
+
moveEndEarlier?: KeyBinding;
|
|
1183
|
+
moveEndLater?: KeyBinding;
|
|
1184
|
+
playActive?: KeyBinding;
|
|
1185
|
+
}
|
|
1186
|
+
declare const DEFAULT_ANNOTATION_SHORTCUTS: Record<AnnotationShortcutAction, KeyBinding[]>;
|
|
1187
|
+
/**
|
|
1188
|
+
* Flatten defaults + remap into a matchable list. A remapped action replaces
|
|
1189
|
+
* ALL of its default bindings with the single provided binding.
|
|
1190
|
+
*/
|
|
1191
|
+
declare function resolveAnnotationShortcuts(remap: AnnotationShortcutMap | null): Array<{
|
|
1192
|
+
action: AnnotationShortcutAction;
|
|
1193
|
+
binding: KeyBinding;
|
|
1194
|
+
}>;
|
|
1195
|
+
|
|
1196
|
+
export { ANNOTATION_LINK_THRESHOLD_TICKS, type AnnotationAction, type AnnotationActionOptions, type AnnotationBoundaryOptions, type AnnotationBoundaryUpdate, type AnnotationData, type AnnotationEventMap, type AnnotationFormat, type AnnotationListOptions, type AnnotationShortcutAction, type AnnotationShortcutMap, type AudioBuffer$1 as AudioBuffer, type AudioClip, type Bits, type ClipTrack, type ColorMapEntry, type ColorMapName, type ColorMapValue, type CreateClipOptions, type CreateClipOptionsSeconds, type CreateClipOptionsTicks, type CreateTrackOptions, DEFAULT_ANNOTATION_SHORTCUTS, DEFAULT_SPECTROGRAM_COLOR_MAP, type FFTSize, type Fade, type FadeConfig, type FadeType, type Gap, InteractionState, type KeyBinding, type KeyboardShortcut, LINK_THRESHOLD, MAX_CANVAS_WIDTH, MIN_ANNOTATION_DURATION, MIN_PIXELS_PER_UNIT, type MeterEntry, type MicrophoneDeviceInfo, type MicrophoneEnumeration, type MidiNoteData, type MusicalTick, type MusicalTickData, type MusicalTickParams, PPQN, type PeakData, type Peaks, type PlaylistConfig, type PlayoutState, type RangeSupport, type RenderAnnotationItemProps, type RenderMode, SPECTROGRAM_DEFAULTS, type SnapTo, type SpectrogramCanvasIdParts, type SpectrogramComputeConfig, type SpectrogramConfig, type SpectrogramData, type SpectrogramDisplayConfig, type TickType, type TimeSelection, type Timeline, type Track, type TrackEffectsFunction, type TrackSpectrogramOverrides, type WaveformConfig, type WaveformDataObject, type ZoomLevel, annotationMinDurationTicks, appendPeaks, appendToAudioBuffer, applyFadeIn, applyFadeOut, audibleLatencySamples, buildSpectrogramCanvasId, calculateDuration, carveClipRange, clipDurationTime, clipEndTime, clipOffsetTime, clipPixelWidth, clipStartTime, clipsOverlap, computeMusicalTicks, concatenateAudioData, createAudioBuffer, createClip, createClipFromSeconds, createClipFromTicks, createTimeline, createTrack, dBToNormalized, detectMeterChanges, enumerateMicrophones, exponentialCurve, findGaps, gainToDb, gainToNormalized, generateCurve, generatePeaks, getClipsAtSample, getClipsInRange, getShortcutLabel, handleKeyboardEvent, linearCurve, logarithmicCurve, matchesKeyBinding, normalizedToDb, parseSpectrogramCanvasId, pixelsToSamples, pixelsToSeconds, probeRangeSupport, resolveAnnotationShortcuts, resolveRecordingOffsetSamples, sCurveCurve, samplesToPixels, samplesToSeconds, samplesToTicks, secondsToPixels, secondsToSamples, snapTickToGrid, snapToGrid, snapToTicks, sortClipsByTime, ticksPerBar, ticksPerBeat, ticksToBarBeat, ticksToSamples, trackChannelCount, updateAnnotationBoundaries, watchMicrophoneDevices };
|
package/dist/index.js
CHANGED
|
@@ -20,12 +20,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
ANNOTATION_LINK_THRESHOLD_TICKS: () => ANNOTATION_LINK_THRESHOLD_TICKS,
|
|
24
|
+
DEFAULT_ANNOTATION_SHORTCUTS: () => DEFAULT_ANNOTATION_SHORTCUTS,
|
|
23
25
|
DEFAULT_SPECTROGRAM_COLOR_MAP: () => DEFAULT_SPECTROGRAM_COLOR_MAP,
|
|
24
26
|
InteractionState: () => InteractionState,
|
|
27
|
+
LINK_THRESHOLD: () => LINK_THRESHOLD,
|
|
25
28
|
MAX_CANVAS_WIDTH: () => MAX_CANVAS_WIDTH,
|
|
29
|
+
MIN_ANNOTATION_DURATION: () => MIN_ANNOTATION_DURATION,
|
|
26
30
|
MIN_PIXELS_PER_UNIT: () => MIN_PIXELS_PER_UNIT,
|
|
27
31
|
PPQN: () => PPQN,
|
|
28
32
|
SPECTROGRAM_DEFAULTS: () => SPECTROGRAM_DEFAULTS,
|
|
33
|
+
annotationMinDurationTicks: () => annotationMinDurationTicks,
|
|
29
34
|
appendPeaks: () => appendPeaks,
|
|
30
35
|
appendToAudioBuffer: () => appendToAudioBuffer,
|
|
31
36
|
applyFadeIn: () => applyFadeIn,
|
|
@@ -63,11 +68,13 @@ __export(index_exports, {
|
|
|
63
68
|
handleKeyboardEvent: () => handleKeyboardEvent,
|
|
64
69
|
linearCurve: () => linearCurve,
|
|
65
70
|
logarithmicCurve: () => logarithmicCurve,
|
|
71
|
+
matchesKeyBinding: () => matchesKeyBinding,
|
|
66
72
|
normalizedToDb: () => normalizedToDb,
|
|
67
73
|
parseSpectrogramCanvasId: () => parseSpectrogramCanvasId,
|
|
68
74
|
pixelsToSamples: () => pixelsToSamples,
|
|
69
75
|
pixelsToSeconds: () => pixelsToSeconds,
|
|
70
76
|
probeRangeSupport: () => probeRangeSupport,
|
|
77
|
+
resolveAnnotationShortcuts: () => resolveAnnotationShortcuts,
|
|
71
78
|
resolveRecordingOffsetSamples: () => resolveRecordingOffsetSamples,
|
|
72
79
|
sCurveCurve: () => sCurveCurve,
|
|
73
80
|
samplesToPixels: () => samplesToPixels,
|
|
@@ -81,8 +88,10 @@ __export(index_exports, {
|
|
|
81
88
|
sortClipsByTime: () => sortClipsByTime,
|
|
82
89
|
ticksPerBar: () => ticksPerBar,
|
|
83
90
|
ticksPerBeat: () => ticksPerBeat,
|
|
91
|
+
ticksToBarBeat: () => ticksToBarBeat,
|
|
84
92
|
ticksToSamples: () => ticksToSamples,
|
|
85
93
|
trackChannelCount: () => trackChannelCount,
|
|
94
|
+
updateAnnotationBoundaries: () => updateAnnotationBoundaries,
|
|
86
95
|
watchMicrophoneDevices: () => watchMicrophoneDevices
|
|
87
96
|
});
|
|
88
97
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -545,6 +554,37 @@ function computeMusicalTicks(params) {
|
|
|
545
554
|
};
|
|
546
555
|
return result;
|
|
547
556
|
}
|
|
557
|
+
function ticksToBarBeat(tick, meterEntries, ppqn) {
|
|
558
|
+
if (ppqn <= 0) return { bar: 1, beat: 1 };
|
|
559
|
+
const entries = meterEntries.length > 0 ? meterEntries : [{ tick: 0, numerator: 4, denominator: 4 }];
|
|
560
|
+
let barOffset = 0;
|
|
561
|
+
for (let i = 0; i < entries.length; i++) {
|
|
562
|
+
const meter = entries[i];
|
|
563
|
+
const segmentStart = meter.tick;
|
|
564
|
+
const segmentEnd = i + 1 < entries.length ? entries[i + 1].tick : Number.MAX_SAFE_INTEGER;
|
|
565
|
+
const ts2 = [meter.numerator, meter.denominator];
|
|
566
|
+
const tpBar2 = ticksPerBar(ts2, ppqn);
|
|
567
|
+
const tpBeat2 = ticksPerBeat(ts2, ppqn);
|
|
568
|
+
if (tick >= segmentStart && tick < segmentEnd) {
|
|
569
|
+
const offset2 = tick - segmentStart;
|
|
570
|
+
const barIndexInSegment2 = Math.floor(offset2 / tpBar2);
|
|
571
|
+
const beatInBar2 = Math.floor(offset2 % tpBar2 / tpBeat2);
|
|
572
|
+
return { bar: barOffset + barIndexInSegment2 + 1, beat: beatInBar2 + 1 };
|
|
573
|
+
}
|
|
574
|
+
if (segmentEnd !== Number.MAX_SAFE_INTEGER) {
|
|
575
|
+
const segmentLen = segmentEnd - segmentStart;
|
|
576
|
+
barOffset += Math.floor(segmentLen / tpBar2);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
const first = entries[0];
|
|
580
|
+
const ts = [first.numerator, first.denominator];
|
|
581
|
+
const tpBar = ticksPerBar(ts, ppqn);
|
|
582
|
+
const tpBeat = ticksPerBeat(ts, ppqn);
|
|
583
|
+
const offset = tick - first.tick;
|
|
584
|
+
const barIndexInSegment = Math.floor(offset / tpBar);
|
|
585
|
+
const beatInBar = Math.floor(offset % tpBar / tpBeat);
|
|
586
|
+
return { bar: barIndexInSegment + 1, beat: beatInBar + 1 };
|
|
587
|
+
}
|
|
548
588
|
function snapTickToGrid(tick, snapTo, meterEntries, ppqn = 960) {
|
|
549
589
|
if (snapTo === "off") return tick;
|
|
550
590
|
let meter = meterEntries[0] ?? { tick: 0, numerator: 4, denominator: 4 };
|
|
@@ -889,6 +929,14 @@ function applyFadeOut(param, startTime, duration, type = "linear", startValue =
|
|
|
889
929
|
}
|
|
890
930
|
|
|
891
931
|
// src/keyboard.ts
|
|
932
|
+
function matchesKeyBinding(event, binding) {
|
|
933
|
+
const keyMatch = event.key.toLowerCase() === binding.key.toLowerCase() || event.key === binding.key;
|
|
934
|
+
const ctrlMatch = binding.ctrlKey === void 0 || event.ctrlKey === binding.ctrlKey;
|
|
935
|
+
const shiftMatch = binding.shiftKey === void 0 || event.shiftKey === binding.shiftKey;
|
|
936
|
+
const metaMatch = binding.metaKey === void 0 || event.metaKey === binding.metaKey;
|
|
937
|
+
const altMatch = binding.altKey === void 0 || event.altKey === binding.altKey;
|
|
938
|
+
return keyMatch && ctrlMatch && shiftMatch && metaMatch && altMatch;
|
|
939
|
+
}
|
|
892
940
|
function handleKeyboardEvent(event, shortcuts, enabled) {
|
|
893
941
|
if (!enabled) return;
|
|
894
942
|
if (event.repeat) return;
|
|
@@ -896,14 +944,7 @@ function handleKeyboardEvent(event, shortcuts, enabled) {
|
|
|
896
944
|
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
|
|
897
945
|
return;
|
|
898
946
|
}
|
|
899
|
-
const matchingShortcut = shortcuts.find((shortcut) =>
|
|
900
|
-
const keyMatch = event.key.toLowerCase() === shortcut.key.toLowerCase() || event.key === shortcut.key;
|
|
901
|
-
const ctrlMatch = shortcut.ctrlKey === void 0 || event.ctrlKey === shortcut.ctrlKey;
|
|
902
|
-
const shiftMatch = shortcut.shiftKey === void 0 || event.shiftKey === shortcut.shiftKey;
|
|
903
|
-
const metaMatch = shortcut.metaKey === void 0 || event.metaKey === shortcut.metaKey;
|
|
904
|
-
const altMatch = shortcut.altKey === void 0 || event.altKey === shortcut.altKey;
|
|
905
|
-
return keyMatch && ctrlMatch && shiftMatch && metaMatch && altMatch;
|
|
906
|
-
});
|
|
947
|
+
const matchingShortcut = shortcuts.find((shortcut) => matchesKeyBinding(event, shortcut));
|
|
907
948
|
if (matchingShortcut) {
|
|
908
949
|
if (matchingShortcut.preventDefault !== false) {
|
|
909
950
|
event.preventDefault();
|
|
@@ -1004,14 +1045,138 @@ function watchMicrophoneDevices(listener, mediaDevices) {
|
|
|
1004
1045
|
md.removeEventListener("devicechange", deliver);
|
|
1005
1046
|
};
|
|
1006
1047
|
}
|
|
1048
|
+
|
|
1049
|
+
// src/annotations/boundaries.ts
|
|
1050
|
+
var LINK_THRESHOLD = 0.01;
|
|
1051
|
+
var MIN_ANNOTATION_DURATION = 0.1;
|
|
1052
|
+
var ANNOTATION_LINK_THRESHOLD_TICKS = 0.5;
|
|
1053
|
+
function annotationMinDurationTicks(ppqn) {
|
|
1054
|
+
return Math.max(1, Math.round(ppqn / 32));
|
|
1055
|
+
}
|
|
1056
|
+
function updateAnnotationBoundaries(params, options = {}) {
|
|
1057
|
+
const { annotationIndex, newTime, isDraggingStart, annotations, duration, linkEndpoints } = params;
|
|
1058
|
+
const linkThreshold = options.linkThreshold ?? LINK_THRESHOLD;
|
|
1059
|
+
const minDuration = options.minDuration ?? MIN_ANNOTATION_DURATION;
|
|
1060
|
+
const updatedAnnotations = [...annotations];
|
|
1061
|
+
const annotation = annotations[annotationIndex];
|
|
1062
|
+
if (isDraggingStart) {
|
|
1063
|
+
const constrainedStart = Math.min(annotation.end - minDuration, Math.max(0, newTime));
|
|
1064
|
+
const delta = constrainedStart - annotation.start;
|
|
1065
|
+
updatedAnnotations[annotationIndex] = { ...annotation, start: constrainedStart };
|
|
1066
|
+
if (linkEndpoints && annotationIndex > 0) {
|
|
1067
|
+
const prevAnnotation = updatedAnnotations[annotationIndex - 1];
|
|
1068
|
+
if (Math.abs(prevAnnotation.end - annotation.start) < linkThreshold) {
|
|
1069
|
+
updatedAnnotations[annotationIndex - 1] = {
|
|
1070
|
+
...prevAnnotation,
|
|
1071
|
+
end: Math.max(prevAnnotation.start + minDuration, prevAnnotation.end + delta)
|
|
1072
|
+
};
|
|
1073
|
+
} else if (constrainedStart <= prevAnnotation.end) {
|
|
1074
|
+
updatedAnnotations[annotationIndex] = {
|
|
1075
|
+
...updatedAnnotations[annotationIndex],
|
|
1076
|
+
start: prevAnnotation.end
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
} else if (!linkEndpoints && annotationIndex > 0 && constrainedStart < updatedAnnotations[annotationIndex - 1].end) {
|
|
1080
|
+
updatedAnnotations[annotationIndex - 1] = {
|
|
1081
|
+
...updatedAnnotations[annotationIndex - 1],
|
|
1082
|
+
end: constrainedStart
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
} else {
|
|
1086
|
+
const constrainedEnd = Math.max(annotation.start + minDuration, Math.min(newTime, duration));
|
|
1087
|
+
const delta = constrainedEnd - annotation.end;
|
|
1088
|
+
updatedAnnotations[annotationIndex] = { ...annotation, end: constrainedEnd };
|
|
1089
|
+
if (linkEndpoints && annotationIndex < updatedAnnotations.length - 1) {
|
|
1090
|
+
const nextAnnotation = updatedAnnotations[annotationIndex + 1];
|
|
1091
|
+
if (Math.abs(nextAnnotation.start - annotation.end) < linkThreshold) {
|
|
1092
|
+
const newStart = nextAnnotation.start + delta;
|
|
1093
|
+
updatedAnnotations[annotationIndex + 1] = {
|
|
1094
|
+
...nextAnnotation,
|
|
1095
|
+
start: Math.min(nextAnnotation.end - minDuration, newStart)
|
|
1096
|
+
};
|
|
1097
|
+
let currentIndex = annotationIndex + 1;
|
|
1098
|
+
while (currentIndex < updatedAnnotations.length - 1) {
|
|
1099
|
+
const current = updatedAnnotations[currentIndex];
|
|
1100
|
+
const next = updatedAnnotations[currentIndex + 1];
|
|
1101
|
+
if (Math.abs(next.start - current.end) < linkThreshold) {
|
|
1102
|
+
const nextDelta = current.end - annotations[currentIndex].end;
|
|
1103
|
+
updatedAnnotations[currentIndex + 1] = {
|
|
1104
|
+
...next,
|
|
1105
|
+
start: Math.min(next.end - minDuration, next.start + nextDelta)
|
|
1106
|
+
};
|
|
1107
|
+
currentIndex++;
|
|
1108
|
+
} else {
|
|
1109
|
+
break;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
} else if (constrainedEnd >= nextAnnotation.start) {
|
|
1113
|
+
updatedAnnotations[annotationIndex] = {
|
|
1114
|
+
...updatedAnnotations[annotationIndex],
|
|
1115
|
+
end: nextAnnotation.start
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
} else if (!linkEndpoints && annotationIndex < updatedAnnotations.length - 1 && constrainedEnd > updatedAnnotations[annotationIndex + 1].start) {
|
|
1119
|
+
const nextAnnotation = updatedAnnotations[annotationIndex + 1];
|
|
1120
|
+
updatedAnnotations[annotationIndex + 1] = { ...nextAnnotation, start: constrainedEnd };
|
|
1121
|
+
let currentIndex = annotationIndex + 1;
|
|
1122
|
+
while (currentIndex < updatedAnnotations.length - 1) {
|
|
1123
|
+
const current = updatedAnnotations[currentIndex];
|
|
1124
|
+
const next = updatedAnnotations[currentIndex + 1];
|
|
1125
|
+
if (current.end > next.start) {
|
|
1126
|
+
updatedAnnotations[currentIndex + 1] = { ...next, start: current.end };
|
|
1127
|
+
currentIndex++;
|
|
1128
|
+
} else {
|
|
1129
|
+
break;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
return updatedAnnotations;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// src/annotations/shortcuts.ts
|
|
1138
|
+
var noMods = { ctrlKey: false, metaKey: false };
|
|
1139
|
+
var DEFAULT_ANNOTATION_SHORTCUTS = {
|
|
1140
|
+
selectPrevious: [
|
|
1141
|
+
{ key: "ArrowUp", ...noMods },
|
|
1142
|
+
{ key: "ArrowLeft", ...noMods }
|
|
1143
|
+
],
|
|
1144
|
+
selectNext: [
|
|
1145
|
+
{ key: "ArrowDown", ...noMods },
|
|
1146
|
+
{ key: "ArrowRight", ...noMods }
|
|
1147
|
+
],
|
|
1148
|
+
selectFirst: [{ key: "Home", ...noMods }],
|
|
1149
|
+
selectLast: [{ key: "End", ...noMods }],
|
|
1150
|
+
clearSelection: [{ key: "Escape", ...noMods }],
|
|
1151
|
+
moveStartEarlier: [{ key: "[", ...noMods }],
|
|
1152
|
+
moveStartLater: [{ key: "]", ...noMods }],
|
|
1153
|
+
// '{' / '}' are what event.key reports for Shift+[ / Shift+] — no explicit
|
|
1154
|
+
// shiftKey needed; the key value itself encodes it.
|
|
1155
|
+
moveEndEarlier: [{ key: "{", ...noMods }],
|
|
1156
|
+
moveEndLater: [{ key: "}", ...noMods }],
|
|
1157
|
+
playActive: [{ key: "Enter", ...noMods }]
|
|
1158
|
+
};
|
|
1159
|
+
var ALL_ACTIONS = Object.keys(DEFAULT_ANNOTATION_SHORTCUTS);
|
|
1160
|
+
function resolveAnnotationShortcuts(remap) {
|
|
1161
|
+
return ALL_ACTIONS.flatMap((action) => {
|
|
1162
|
+
const override = remap?.[action];
|
|
1163
|
+
const bindings = override ? [override] : DEFAULT_ANNOTATION_SHORTCUTS[action];
|
|
1164
|
+
return bindings.map((binding) => ({ action, binding }));
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1007
1167
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1008
1168
|
0 && (module.exports = {
|
|
1169
|
+
ANNOTATION_LINK_THRESHOLD_TICKS,
|
|
1170
|
+
DEFAULT_ANNOTATION_SHORTCUTS,
|
|
1009
1171
|
DEFAULT_SPECTROGRAM_COLOR_MAP,
|
|
1010
1172
|
InteractionState,
|
|
1173
|
+
LINK_THRESHOLD,
|
|
1011
1174
|
MAX_CANVAS_WIDTH,
|
|
1175
|
+
MIN_ANNOTATION_DURATION,
|
|
1012
1176
|
MIN_PIXELS_PER_UNIT,
|
|
1013
1177
|
PPQN,
|
|
1014
1178
|
SPECTROGRAM_DEFAULTS,
|
|
1179
|
+
annotationMinDurationTicks,
|
|
1015
1180
|
appendPeaks,
|
|
1016
1181
|
appendToAudioBuffer,
|
|
1017
1182
|
applyFadeIn,
|
|
@@ -1049,11 +1214,13 @@ function watchMicrophoneDevices(listener, mediaDevices) {
|
|
|
1049
1214
|
handleKeyboardEvent,
|
|
1050
1215
|
linearCurve,
|
|
1051
1216
|
logarithmicCurve,
|
|
1217
|
+
matchesKeyBinding,
|
|
1052
1218
|
normalizedToDb,
|
|
1053
1219
|
parseSpectrogramCanvasId,
|
|
1054
1220
|
pixelsToSamples,
|
|
1055
1221
|
pixelsToSeconds,
|
|
1056
1222
|
probeRangeSupport,
|
|
1223
|
+
resolveAnnotationShortcuts,
|
|
1057
1224
|
resolveRecordingOffsetSamples,
|
|
1058
1225
|
sCurveCurve,
|
|
1059
1226
|
samplesToPixels,
|
|
@@ -1067,8 +1234,10 @@ function watchMicrophoneDevices(listener, mediaDevices) {
|
|
|
1067
1234
|
sortClipsByTime,
|
|
1068
1235
|
ticksPerBar,
|
|
1069
1236
|
ticksPerBeat,
|
|
1237
|
+
ticksToBarBeat,
|
|
1070
1238
|
ticksToSamples,
|
|
1071
1239
|
trackChannelCount,
|
|
1240
|
+
updateAnnotationBoundaries,
|
|
1072
1241
|
watchMicrophoneDevices
|
|
1073
1242
|
});
|
|
1074
1243
|
//# sourceMappingURL=index.js.map
|