@waveform-playlist/core 11.3.0 → 12.0.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/index.d.mts CHANGED
@@ -180,6 +180,12 @@ interface AudioClip {
180
180
  audioBuffer?: AudioBuffer;
181
181
  /** Position on timeline where this clip starts (in samples at timeline sampleRate) */
182
182
  startSample: number;
183
+ /**
184
+ * Position on timeline in ticks (authoritative when present).
185
+ * When set, startSample is a derived cache recomputed from startTick via TempoMap.
186
+ * Optional for backwards compatibility — engine enriches clips without startTick on ingestion.
187
+ */
188
+ startTick?: number;
183
189
  /** Duration of this clip (in samples) - how much of the audio buffer to play */
184
190
  durationSamples: number;
185
191
  /** Offset into the audio buffer where playback starts (in samples) - the "trim start" point */
@@ -285,6 +291,7 @@ interface CreateClipOptions {
285
291
  /** Audio buffer - optional for peaks-first rendering */
286
292
  audioBuffer?: AudioBuffer;
287
293
  startSample: number;
294
+ startTick?: number;
288
295
  durationSamples?: number;
289
296
  offsetSamples?: number;
290
297
  gain?: number;
@@ -315,6 +322,7 @@ interface CreateClipOptionsSeconds {
315
322
  /** Audio buffer - optional for peaks-first rendering */
316
323
  audioBuffer?: AudioBuffer;
317
324
  startTime: number;
325
+ startTick?: number;
318
326
  duration?: number;
319
327
  offset?: number;
320
328
  gain?: number;
@@ -335,6 +343,35 @@ interface CreateClipOptionsSeconds {
335
343
  /** MIDI program number (0-127). GM instrument for SoundFont playback. */
336
344
  midiProgram?: number;
337
345
  }
346
+ /**
347
+ * Options for creating a new audio clip from tick position.
348
+ * startTick is authoritative; startSample is derived.
349
+ *
350
+ * Provide either:
351
+ * - ticksToSeconds callback (for variable-tempo / multi-tempo), or
352
+ * - bpm + ppqn (for single-tempo convenience)
353
+ */
354
+ interface CreateClipOptionsTicks {
355
+ startTick: number;
356
+ ticksToSeconds?: (tick: number) => number;
357
+ bpm?: number;
358
+ ppqn?: number;
359
+ audioBuffer?: AudioBuffer;
360
+ durationSamples?: number;
361
+ offsetSamples?: number;
362
+ gain?: number;
363
+ name?: string;
364
+ color?: string;
365
+ fadeIn?: Fade;
366
+ fadeOut?: Fade;
367
+ waveformData?: WaveformDataObject;
368
+ sampleRate?: number;
369
+ sourceDurationSamples?: number;
370
+ midiNotes?: MidiNoteData[];
371
+ midiChannel?: number;
372
+ midiProgram?: number;
373
+ }
374
+ declare function createClipFromTicks(options: CreateClipOptionsTicks): AudioClip;
338
375
  /**
339
376
  * Options for creating a new track
340
377
  */
@@ -614,8 +651,6 @@ declare function ticksToSamples(ticks: number, bpm: number, sampleRate: number,
614
651
  declare function samplesToTicks(samples: number, bpm: number, sampleRate: number, ppqn?: number): number;
615
652
  /** Snap a tick position to the nearest grid line (rounds to nearest). */
616
653
  declare function snapToGrid(ticks: number, gridSizeTicks: number): number;
617
- /** Format ticks as a 1-indexed bar.beat label. Beat 1 shows bar number only (e.g., "3" not "3.1"). */
618
- declare function ticksToBarBeatLabel(ticks: number, timeSignature: [number, number], ppqn?: number): string;
619
654
 
620
655
  /**
621
656
  * Convert a dB value to a normalized range.
@@ -639,6 +674,13 @@ declare function dBToNormalized(dB: number, floor?: number): number;
639
674
  * @returns dB value (floor at 0, 0 dB at 1, positive dB above 1)
640
675
  */
641
676
  declare function normalizedToDb(normalized: number, floor?: number): number;
677
+ /**
678
+ * Convert a linear gain value to decibels.
679
+ *
680
+ * @param gain - Linear gain (0 = silence, 1 = unity)
681
+ * @returns Decibel value (e.g., 0.5 → ≈ -6.02 dB)
682
+ */
683
+ declare function gainToDb(gain: number): number;
642
684
  /**
643
685
  * Convert a linear gain value (0-1+) to normalized 0-1 via dB.
644
686
  *
@@ -652,6 +694,137 @@ declare function normalizedToDb(normalized: number, floor?: number): number;
652
694
  */
653
695
  declare function gainToNormalized(gain: number, floor?: number): number;
654
696
 
697
+ interface MeterEntry {
698
+ tick: number;
699
+ numerator: number;
700
+ denominator: number;
701
+ }
702
+ /**
703
+ * Scans a beat number sequence and detects meter (time signature) changes.
704
+ *
705
+ * Each beat in the input has a `beat` number (1-indexed). When the beat resets
706
+ * to 1, we count how many beats were in the previous bar and derive the numerator.
707
+ *
708
+ * @param beats - Array of beat events with `time` (seconds) and `beat` (1-indexed number).
709
+ * @param firstBeatTick - The tick position of beats[0] on the timeline.
710
+ * @param ppqn - Ticks per quarter note (ticks per beat).
711
+ * @returns Array of MeterEntry sorted by tick. Always includes an entry at tick 0.
712
+ */
713
+ declare function detectMeterChanges(beats: {
714
+ time: number;
715
+ beat: number;
716
+ }[], firstBeatTick: number, ppqn: number): MeterEntry[];
717
+
718
+ /** All supported snap-to-grid values. */
719
+ type SnapTo = 'bar' | 'beat' | '1/2' | '1/4' | '1/8' | '1/16' | '1/32' | '1/2T' | '1/4T' | '1/8T' | '1/16T' | 'off';
720
+ /**
721
+ * Returns the tick interval for the given SnapTo value.
722
+ *
723
+ * Straight subdivisions (1/2, 1/4, 1/8, 1/16, 1/32) are always expressed as
724
+ * fractions of a quarter note (ppqn), independent of the time signature
725
+ * denominator. Triplet subdivisions use × 2/3 of the corresponding straight
726
+ * value. 'bar' and 'beat' depend on the first meter entry's time signature.
727
+ * 'off' returns 0.
728
+ */
729
+ declare function snapToTicks(snapTo: SnapTo, timeSignature: [number, number], ppqn?: number): number;
730
+ /**
731
+ * Three-tier tick hierarchy (following Audacity's model):
732
+ * major — Bar boundaries. Always labeled, strongest grid lines.
733
+ * minor — Beat boundaries. Labeled when wide enough, medium grid lines.
734
+ * minorMinor — Subdivisions (eighths, sixteenths). Never labeled, ruler ticks only (no grid).
735
+ */
736
+ type TickType = 'major' | 'minor' | 'minorMinor';
737
+ /** Zoom level category used to select which subdivision to iterate at. */
738
+ type ZoomLevel = 'coarse' | 'bar' | 'beat' | 'eighth' | 'sixteenth';
739
+ /** A single musical tick with rendering metadata. */
740
+ interface MusicalTick {
741
+ /** Pixel position of the tick in the timeline. */
742
+ pixel: number;
743
+ /** Three-tier type: major (bar), minor (beat), minorMinor (subdivision). */
744
+ type: TickType;
745
+ /** Human-readable label. Present for major ticks always; minor ticks when zoomed in. */
746
+ label?: string;
747
+ /** 0-based global bar index (for alternating bar-level striping). */
748
+ barIndex: number;
749
+ }
750
+ /** Result of computeMusicalTicks(). */
751
+ interface MusicalTickData {
752
+ ticks: MusicalTick[];
753
+ pixelsPerQuarterNote: number;
754
+ zoomLevel: ZoomLevel;
755
+ /** At 'coarse' zoom: how many quarter notes between rendered tick lines. */
756
+ coarseQuarterNoteStep?: number;
757
+ }
758
+ /** Parameters for computeMusicalTicks(). */
759
+ interface MusicalTickParams {
760
+ meterEntries: MeterEntry[];
761
+ /** Ticks per pixel (zoom level — lower value = more zoomed in). */
762
+ ticksPerPixel: number;
763
+ startPixel: number;
764
+ endPixel: number;
765
+ /** Pulses per quarter note. Defaults to 960. */
766
+ ppqn?: number;
767
+ }
768
+ /** Minimum pixels per musical unit before switching to a coarser zoom level. */
769
+ declare const MIN_PIXELS_PER_UNIT = 8;
770
+ /**
771
+ * Determines the zoom level and computes which tick lines to render for a
772
+ * given viewport. Pure tick arithmetic — no BPM or sample rate required.
773
+ *
774
+ * Walks meter entries in segments, so bar/beat boundaries and labels are
775
+ * correct across meter changes.
776
+ */
777
+ declare function computeMusicalTicks(params: MusicalTickParams): MusicalTickData;
778
+ /**
779
+ * Snaps a tick position to the nearest grid boundary defined by `snapTo`.
780
+ *
781
+ * Finds the meter entry active at the tick position and snaps relative to
782
+ * that meter's segment start.
783
+ *
784
+ * Returns the original tick unchanged when `snapTo` is 'off'.
785
+ */
786
+ declare function snapTickToGrid(tick: number, snapTo: SnapTo, meterEntries: MeterEntry[], ppqn?: number): number;
787
+
788
+ /**
789
+ * Peak generation for real-time waveform visualization during recording.
790
+ * Matches the format used by webaudio-peaks: min/max pairs with bit depth.
791
+ */
792
+ /**
793
+ * Generate peaks from audio samples in standard min/max pair format.
794
+ *
795
+ * @param samples - Audio samples to process
796
+ * @param samplesPerPixel - Number of samples to represent in each peak
797
+ * @param bits - Bit depth for peak values (8 or 16)
798
+ * @returns Int8Array or Int16Array of peak values (min/max pairs)
799
+ */
800
+ declare function generatePeaks(samples: Float32Array, samplesPerPixel: number, bits?: 8 | 16): Int8Array | Int16Array;
801
+ /**
802
+ * Append new peaks to existing peaks array.
803
+ * This is used for incremental peak updates during recording.
804
+ */
805
+ declare function appendPeaks(existingPeaks: Int8Array | Int16Array, newSamples: Float32Array, samplesPerPixel: number, totalSamplesProcessed: number, bits?: 8 | 16): Int8Array | Int16Array;
806
+
807
+ /**
808
+ * Utility functions for working with AudioBuffers during recording
809
+ */
810
+ /**
811
+ * Concatenate multiple Float32Arrays into a single array
812
+ */
813
+ declare function concatenateAudioData(chunks: Float32Array[]): Float32Array;
814
+ /**
815
+ * Convert channel data to AudioBuffer.
816
+ * Accepts either per-channel Float32Array[] or a single Float32Array (mono, backwards compatible).
817
+ */
818
+ declare function createAudioBuffer(audioContext: AudioContext, channelData: Float32Array[] | Float32Array, sampleRate: number, channelCount?: number): AudioBuffer;
819
+ /**
820
+ * Append new samples to an existing AudioBuffer (mono convenience)
821
+ */
822
+ declare function appendToAudioBuffer(audioContext: AudioContext, existingBuffer: AudioBuffer | null, newSamples: Float32Array, sampleRate: number): AudioBuffer;
823
+ /**
824
+ * Calculate duration in seconds from sample count and sample rate
825
+ */
826
+ declare function calculateDuration(sampleCount: number, sampleRate: number): number;
827
+
655
828
  /** Clip start position in seconds */
656
829
  declare function clipStartTime(clip: AudioClip): number;
657
830
  /** Clip end position in seconds (start + duration) */
@@ -660,6 +833,11 @@ declare function clipEndTime(clip: AudioClip): number;
660
833
  declare function clipOffsetTime(clip: AudioClip): number;
661
834
  /** Clip duration in seconds */
662
835
  declare function clipDurationTime(clip: AudioClip): number;
836
+ /**
837
+ * Max audio channel count across a track's clips.
838
+ * Used to set Panner channelCount and offline render output channels.
839
+ */
840
+ declare function trackChannelCount(track: ClipTrack): number;
663
841
  /**
664
842
  * Clip width in pixels at a given samplesPerPixel.
665
843
  * Shared by Clip.tsx (container sizing) and ChannelWithProgress.tsx (progress overlay)
@@ -745,4 +923,4 @@ declare function handleKeyboardEvent(event: KeyboardEvent, shortcuts: KeyboardSh
745
923
  */
746
924
  declare const getShortcutLabel: (shortcut: KeyboardShortcut) => string;
747
925
 
748
- export { type AnnotationAction, type AnnotationActionOptions, type AnnotationData, type AnnotationEventMap, type AnnotationFormat, type AnnotationListOptions, type AudioBuffer$1 as AudioBuffer, type AudioClip, type Bits, type ClipTrack, type ColorMapEntry, type ColorMapName, type ColorMapValue, type CreateClipOptions, type CreateClipOptionsSeconds, type CreateTrackOptions, type FFTSize, type Fade, type FadeConfig, type FadeType, type Gap, InteractionState, type KeyboardShortcut, MAX_CANVAS_WIDTH, type MidiNoteData, PPQN, type PeakData, type Peaks, type PlaylistConfig, type PlayoutState, type RenderAnnotationItemProps, type RenderMode, type SpectrogramComputeConfig, type SpectrogramConfig, type SpectrogramData, type SpectrogramDisplayConfig, type TimeSelection, type Timeline, type Track, type TrackEffectsFunction, type TrackSpectrogramOverrides, type WaveformConfig, type WaveformDataObject, applyFadeIn, applyFadeOut, clipDurationTime, clipEndTime, clipOffsetTime, clipPixelWidth, clipStartTime, clipsOverlap, createClip, createClipFromSeconds, createTimeline, createTrack, dBToNormalized, exponentialCurve, findGaps, gainToNormalized, generateCurve, getClipsAtSample, getClipsInRange, getShortcutLabel, handleKeyboardEvent, linearCurve, logarithmicCurve, normalizedToDb, pixelsToSamples, pixelsToSeconds, sCurveCurve, samplesToPixels, samplesToSeconds, samplesToTicks, secondsToPixels, secondsToSamples, snapToGrid, sortClipsByTime, ticksPerBar, ticksPerBeat, ticksToBarBeatLabel, ticksToSamples };
926
+ export { type AnnotationAction, type AnnotationActionOptions, type AnnotationData, type AnnotationEventMap, type AnnotationFormat, type AnnotationListOptions, 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, type FFTSize, type Fade, type FadeConfig, type FadeType, type Gap, InteractionState, type KeyboardShortcut, MAX_CANVAS_WIDTH, MIN_PIXELS_PER_UNIT, type MeterEntry, type MidiNoteData, type MusicalTick, type MusicalTickData, type MusicalTickParams, PPQN, type PeakData, type Peaks, type PlaylistConfig, type PlayoutState, type RenderAnnotationItemProps, type RenderMode, type SnapTo, 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, appendPeaks, appendToAudioBuffer, applyFadeIn, applyFadeOut, calculateDuration, clipDurationTime, clipEndTime, clipOffsetTime, clipPixelWidth, clipStartTime, clipsOverlap, computeMusicalTicks, concatenateAudioData, createAudioBuffer, createClip, createClipFromSeconds, createClipFromTicks, createTimeline, createTrack, dBToNormalized, detectMeterChanges, exponentialCurve, findGaps, gainToDb, gainToNormalized, generateCurve, generatePeaks, getClipsAtSample, getClipsInRange, getShortcutLabel, handleKeyboardEvent, linearCurve, logarithmicCurve, normalizedToDb, pixelsToSamples, pixelsToSeconds, sCurveCurve, samplesToPixels, samplesToSeconds, samplesToTicks, secondsToPixels, secondsToSamples, snapTickToGrid, snapToGrid, snapToTicks, sortClipsByTime, ticksPerBar, ticksPerBeat, ticksToSamples, trackChannelCount };
package/dist/index.d.ts CHANGED
@@ -180,6 +180,12 @@ interface AudioClip {
180
180
  audioBuffer?: AudioBuffer;
181
181
  /** Position on timeline where this clip starts (in samples at timeline sampleRate) */
182
182
  startSample: number;
183
+ /**
184
+ * Position on timeline in ticks (authoritative when present).
185
+ * When set, startSample is a derived cache recomputed from startTick via TempoMap.
186
+ * Optional for backwards compatibility — engine enriches clips without startTick on ingestion.
187
+ */
188
+ startTick?: number;
183
189
  /** Duration of this clip (in samples) - how much of the audio buffer to play */
184
190
  durationSamples: number;
185
191
  /** Offset into the audio buffer where playback starts (in samples) - the "trim start" point */
@@ -285,6 +291,7 @@ interface CreateClipOptions {
285
291
  /** Audio buffer - optional for peaks-first rendering */
286
292
  audioBuffer?: AudioBuffer;
287
293
  startSample: number;
294
+ startTick?: number;
288
295
  durationSamples?: number;
289
296
  offsetSamples?: number;
290
297
  gain?: number;
@@ -315,6 +322,7 @@ interface CreateClipOptionsSeconds {
315
322
  /** Audio buffer - optional for peaks-first rendering */
316
323
  audioBuffer?: AudioBuffer;
317
324
  startTime: number;
325
+ startTick?: number;
318
326
  duration?: number;
319
327
  offset?: number;
320
328
  gain?: number;
@@ -335,6 +343,35 @@ interface CreateClipOptionsSeconds {
335
343
  /** MIDI program number (0-127). GM instrument for SoundFont playback. */
336
344
  midiProgram?: number;
337
345
  }
346
+ /**
347
+ * Options for creating a new audio clip from tick position.
348
+ * startTick is authoritative; startSample is derived.
349
+ *
350
+ * Provide either:
351
+ * - ticksToSeconds callback (for variable-tempo / multi-tempo), or
352
+ * - bpm + ppqn (for single-tempo convenience)
353
+ */
354
+ interface CreateClipOptionsTicks {
355
+ startTick: number;
356
+ ticksToSeconds?: (tick: number) => number;
357
+ bpm?: number;
358
+ ppqn?: number;
359
+ audioBuffer?: AudioBuffer;
360
+ durationSamples?: number;
361
+ offsetSamples?: number;
362
+ gain?: number;
363
+ name?: string;
364
+ color?: string;
365
+ fadeIn?: Fade;
366
+ fadeOut?: Fade;
367
+ waveformData?: WaveformDataObject;
368
+ sampleRate?: number;
369
+ sourceDurationSamples?: number;
370
+ midiNotes?: MidiNoteData[];
371
+ midiChannel?: number;
372
+ midiProgram?: number;
373
+ }
374
+ declare function createClipFromTicks(options: CreateClipOptionsTicks): AudioClip;
338
375
  /**
339
376
  * Options for creating a new track
340
377
  */
@@ -614,8 +651,6 @@ declare function ticksToSamples(ticks: number, bpm: number, sampleRate: number,
614
651
  declare function samplesToTicks(samples: number, bpm: number, sampleRate: number, ppqn?: number): number;
615
652
  /** Snap a tick position to the nearest grid line (rounds to nearest). */
616
653
  declare function snapToGrid(ticks: number, gridSizeTicks: number): number;
617
- /** Format ticks as a 1-indexed bar.beat label. Beat 1 shows bar number only (e.g., "3" not "3.1"). */
618
- declare function ticksToBarBeatLabel(ticks: number, timeSignature: [number, number], ppqn?: number): string;
619
654
 
620
655
  /**
621
656
  * Convert a dB value to a normalized range.
@@ -639,6 +674,13 @@ declare function dBToNormalized(dB: number, floor?: number): number;
639
674
  * @returns dB value (floor at 0, 0 dB at 1, positive dB above 1)
640
675
  */
641
676
  declare function normalizedToDb(normalized: number, floor?: number): number;
677
+ /**
678
+ * Convert a linear gain value to decibels.
679
+ *
680
+ * @param gain - Linear gain (0 = silence, 1 = unity)
681
+ * @returns Decibel value (e.g., 0.5 → ≈ -6.02 dB)
682
+ */
683
+ declare function gainToDb(gain: number): number;
642
684
  /**
643
685
  * Convert a linear gain value (0-1+) to normalized 0-1 via dB.
644
686
  *
@@ -652,6 +694,137 @@ declare function normalizedToDb(normalized: number, floor?: number): number;
652
694
  */
653
695
  declare function gainToNormalized(gain: number, floor?: number): number;
654
696
 
697
+ interface MeterEntry {
698
+ tick: number;
699
+ numerator: number;
700
+ denominator: number;
701
+ }
702
+ /**
703
+ * Scans a beat number sequence and detects meter (time signature) changes.
704
+ *
705
+ * Each beat in the input has a `beat` number (1-indexed). When the beat resets
706
+ * to 1, we count how many beats were in the previous bar and derive the numerator.
707
+ *
708
+ * @param beats - Array of beat events with `time` (seconds) and `beat` (1-indexed number).
709
+ * @param firstBeatTick - The tick position of beats[0] on the timeline.
710
+ * @param ppqn - Ticks per quarter note (ticks per beat).
711
+ * @returns Array of MeterEntry sorted by tick. Always includes an entry at tick 0.
712
+ */
713
+ declare function detectMeterChanges(beats: {
714
+ time: number;
715
+ beat: number;
716
+ }[], firstBeatTick: number, ppqn: number): MeterEntry[];
717
+
718
+ /** All supported snap-to-grid values. */
719
+ type SnapTo = 'bar' | 'beat' | '1/2' | '1/4' | '1/8' | '1/16' | '1/32' | '1/2T' | '1/4T' | '1/8T' | '1/16T' | 'off';
720
+ /**
721
+ * Returns the tick interval for the given SnapTo value.
722
+ *
723
+ * Straight subdivisions (1/2, 1/4, 1/8, 1/16, 1/32) are always expressed as
724
+ * fractions of a quarter note (ppqn), independent of the time signature
725
+ * denominator. Triplet subdivisions use × 2/3 of the corresponding straight
726
+ * value. 'bar' and 'beat' depend on the first meter entry's time signature.
727
+ * 'off' returns 0.
728
+ */
729
+ declare function snapToTicks(snapTo: SnapTo, timeSignature: [number, number], ppqn?: number): number;
730
+ /**
731
+ * Three-tier tick hierarchy (following Audacity's model):
732
+ * major — Bar boundaries. Always labeled, strongest grid lines.
733
+ * minor — Beat boundaries. Labeled when wide enough, medium grid lines.
734
+ * minorMinor — Subdivisions (eighths, sixteenths). Never labeled, ruler ticks only (no grid).
735
+ */
736
+ type TickType = 'major' | 'minor' | 'minorMinor';
737
+ /** Zoom level category used to select which subdivision to iterate at. */
738
+ type ZoomLevel = 'coarse' | 'bar' | 'beat' | 'eighth' | 'sixteenth';
739
+ /** A single musical tick with rendering metadata. */
740
+ interface MusicalTick {
741
+ /** Pixel position of the tick in the timeline. */
742
+ pixel: number;
743
+ /** Three-tier type: major (bar), minor (beat), minorMinor (subdivision). */
744
+ type: TickType;
745
+ /** Human-readable label. Present for major ticks always; minor ticks when zoomed in. */
746
+ label?: string;
747
+ /** 0-based global bar index (for alternating bar-level striping). */
748
+ barIndex: number;
749
+ }
750
+ /** Result of computeMusicalTicks(). */
751
+ interface MusicalTickData {
752
+ ticks: MusicalTick[];
753
+ pixelsPerQuarterNote: number;
754
+ zoomLevel: ZoomLevel;
755
+ /** At 'coarse' zoom: how many quarter notes between rendered tick lines. */
756
+ coarseQuarterNoteStep?: number;
757
+ }
758
+ /** Parameters for computeMusicalTicks(). */
759
+ interface MusicalTickParams {
760
+ meterEntries: MeterEntry[];
761
+ /** Ticks per pixel (zoom level — lower value = more zoomed in). */
762
+ ticksPerPixel: number;
763
+ startPixel: number;
764
+ endPixel: number;
765
+ /** Pulses per quarter note. Defaults to 960. */
766
+ ppqn?: number;
767
+ }
768
+ /** Minimum pixels per musical unit before switching to a coarser zoom level. */
769
+ declare const MIN_PIXELS_PER_UNIT = 8;
770
+ /**
771
+ * Determines the zoom level and computes which tick lines to render for a
772
+ * given viewport. Pure tick arithmetic — no BPM or sample rate required.
773
+ *
774
+ * Walks meter entries in segments, so bar/beat boundaries and labels are
775
+ * correct across meter changes.
776
+ */
777
+ declare function computeMusicalTicks(params: MusicalTickParams): MusicalTickData;
778
+ /**
779
+ * Snaps a tick position to the nearest grid boundary defined by `snapTo`.
780
+ *
781
+ * Finds the meter entry active at the tick position and snaps relative to
782
+ * that meter's segment start.
783
+ *
784
+ * Returns the original tick unchanged when `snapTo` is 'off'.
785
+ */
786
+ declare function snapTickToGrid(tick: number, snapTo: SnapTo, meterEntries: MeterEntry[], ppqn?: number): number;
787
+
788
+ /**
789
+ * Peak generation for real-time waveform visualization during recording.
790
+ * Matches the format used by webaudio-peaks: min/max pairs with bit depth.
791
+ */
792
+ /**
793
+ * Generate peaks from audio samples in standard min/max pair format.
794
+ *
795
+ * @param samples - Audio samples to process
796
+ * @param samplesPerPixel - Number of samples to represent in each peak
797
+ * @param bits - Bit depth for peak values (8 or 16)
798
+ * @returns Int8Array or Int16Array of peak values (min/max pairs)
799
+ */
800
+ declare function generatePeaks(samples: Float32Array, samplesPerPixel: number, bits?: 8 | 16): Int8Array | Int16Array;
801
+ /**
802
+ * Append new peaks to existing peaks array.
803
+ * This is used for incremental peak updates during recording.
804
+ */
805
+ declare function appendPeaks(existingPeaks: Int8Array | Int16Array, newSamples: Float32Array, samplesPerPixel: number, totalSamplesProcessed: number, bits?: 8 | 16): Int8Array | Int16Array;
806
+
807
+ /**
808
+ * Utility functions for working with AudioBuffers during recording
809
+ */
810
+ /**
811
+ * Concatenate multiple Float32Arrays into a single array
812
+ */
813
+ declare function concatenateAudioData(chunks: Float32Array[]): Float32Array;
814
+ /**
815
+ * Convert channel data to AudioBuffer.
816
+ * Accepts either per-channel Float32Array[] or a single Float32Array (mono, backwards compatible).
817
+ */
818
+ declare function createAudioBuffer(audioContext: AudioContext, channelData: Float32Array[] | Float32Array, sampleRate: number, channelCount?: number): AudioBuffer;
819
+ /**
820
+ * Append new samples to an existing AudioBuffer (mono convenience)
821
+ */
822
+ declare function appendToAudioBuffer(audioContext: AudioContext, existingBuffer: AudioBuffer | null, newSamples: Float32Array, sampleRate: number): AudioBuffer;
823
+ /**
824
+ * Calculate duration in seconds from sample count and sample rate
825
+ */
826
+ declare function calculateDuration(sampleCount: number, sampleRate: number): number;
827
+
655
828
  /** Clip start position in seconds */
656
829
  declare function clipStartTime(clip: AudioClip): number;
657
830
  /** Clip end position in seconds (start + duration) */
@@ -660,6 +833,11 @@ declare function clipEndTime(clip: AudioClip): number;
660
833
  declare function clipOffsetTime(clip: AudioClip): number;
661
834
  /** Clip duration in seconds */
662
835
  declare function clipDurationTime(clip: AudioClip): number;
836
+ /**
837
+ * Max audio channel count across a track's clips.
838
+ * Used to set Panner channelCount and offline render output channels.
839
+ */
840
+ declare function trackChannelCount(track: ClipTrack): number;
663
841
  /**
664
842
  * Clip width in pixels at a given samplesPerPixel.
665
843
  * Shared by Clip.tsx (container sizing) and ChannelWithProgress.tsx (progress overlay)
@@ -745,4 +923,4 @@ declare function handleKeyboardEvent(event: KeyboardEvent, shortcuts: KeyboardSh
745
923
  */
746
924
  declare const getShortcutLabel: (shortcut: KeyboardShortcut) => string;
747
925
 
748
- export { type AnnotationAction, type AnnotationActionOptions, type AnnotationData, type AnnotationEventMap, type AnnotationFormat, type AnnotationListOptions, type AudioBuffer$1 as AudioBuffer, type AudioClip, type Bits, type ClipTrack, type ColorMapEntry, type ColorMapName, type ColorMapValue, type CreateClipOptions, type CreateClipOptionsSeconds, type CreateTrackOptions, type FFTSize, type Fade, type FadeConfig, type FadeType, type Gap, InteractionState, type KeyboardShortcut, MAX_CANVAS_WIDTH, type MidiNoteData, PPQN, type PeakData, type Peaks, type PlaylistConfig, type PlayoutState, type RenderAnnotationItemProps, type RenderMode, type SpectrogramComputeConfig, type SpectrogramConfig, type SpectrogramData, type SpectrogramDisplayConfig, type TimeSelection, type Timeline, type Track, type TrackEffectsFunction, type TrackSpectrogramOverrides, type WaveformConfig, type WaveformDataObject, applyFadeIn, applyFadeOut, clipDurationTime, clipEndTime, clipOffsetTime, clipPixelWidth, clipStartTime, clipsOverlap, createClip, createClipFromSeconds, createTimeline, createTrack, dBToNormalized, exponentialCurve, findGaps, gainToNormalized, generateCurve, getClipsAtSample, getClipsInRange, getShortcutLabel, handleKeyboardEvent, linearCurve, logarithmicCurve, normalizedToDb, pixelsToSamples, pixelsToSeconds, sCurveCurve, samplesToPixels, samplesToSeconds, samplesToTicks, secondsToPixels, secondsToSamples, snapToGrid, sortClipsByTime, ticksPerBar, ticksPerBeat, ticksToBarBeatLabel, ticksToSamples };
926
+ export { type AnnotationAction, type AnnotationActionOptions, type AnnotationData, type AnnotationEventMap, type AnnotationFormat, type AnnotationListOptions, 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, type FFTSize, type Fade, type FadeConfig, type FadeType, type Gap, InteractionState, type KeyboardShortcut, MAX_CANVAS_WIDTH, MIN_PIXELS_PER_UNIT, type MeterEntry, type MidiNoteData, type MusicalTick, type MusicalTickData, type MusicalTickParams, PPQN, type PeakData, type Peaks, type PlaylistConfig, type PlayoutState, type RenderAnnotationItemProps, type RenderMode, type SnapTo, 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, appendPeaks, appendToAudioBuffer, applyFadeIn, applyFadeOut, calculateDuration, clipDurationTime, clipEndTime, clipOffsetTime, clipPixelWidth, clipStartTime, clipsOverlap, computeMusicalTicks, concatenateAudioData, createAudioBuffer, createClip, createClipFromSeconds, createClipFromTicks, createTimeline, createTrack, dBToNormalized, detectMeterChanges, exponentialCurve, findGaps, gainToDb, gainToNormalized, generateCurve, generatePeaks, getClipsAtSample, getClipsInRange, getShortcutLabel, handleKeyboardEvent, linearCurve, logarithmicCurve, normalizedToDb, pixelsToSamples, pixelsToSeconds, sCurveCurve, samplesToPixels, samplesToSeconds, samplesToTicks, secondsToPixels, secondsToSamples, snapTickToGrid, snapToGrid, snapToTicks, sortClipsByTime, ticksPerBar, ticksPerBeat, ticksToSamples, trackChannelCount };