Skip to main content

@waveform-playlist/core

The core package provides foundational types, interfaces, and utilities used throughout the Waveform Playlist library. It has zero dependencies and can be used independently for type-safe audio editing data structures.

Installation

npm install @waveform-playlist/core
No peer dependencies required - this package is dependency-free.

Main Exports

Types

Audio Clip Model

AudioClip
interface
Represents a single audio clip on the timeline with sample-accurate positioning
ClipTrack
interface
Represents a track containing multiple audio clips with volume, pan, and effects
Timeline
interface
Represents the complete project with all tracks, sample rate, and duration
WaveformDataObject
interface
Interface for waveform-data.js library objects (BBC audiowaveform format)

Configuration Types

Fade
interface
Fade configuration with duration and type (linear, logarithmic, sCurve, exponential)
FadeType
type
Union type: 'logarithmic' | 'linear' | 'sCurve' | 'exponential'
WaveformConfig
interface
Waveform visualization configuration (sample rate, samples per pixel, colors)
PlaylistConfig
interface
Complete playlist configuration (zoom levels, colors, controls, timescale)
TimeSelection
interface
Time selection with start and end times

Peak Data Types

Peaks
type
Union type for peak arrays: Int8Array | Int16Array
Bits
type
Union type for bit depth: 8 | 16
PeakData
interface
Result of peak extraction with interleaved min/max data for each channel

Spectrogram Types

RenderMode
type
Visualization mode: 'waveform' | 'spectrogram'
SpectrogramConfig
interface
FFT configuration (size, window type, frequency scale, mel bands, etc.)
ColorMapValue
type
Predefined color map name or custom color array

Annotation Types

AnnotationData
interface
Annotation with start/end times, label, and optional ID
AnnotationFormat
type
Export format: 'json' | 'aeneas'
AnnotationListOptions
interface
Configuration for annotation list (annotations array, editable, linkEndpoints, etc.)

State Enums

InteractionState
enum
User interaction modes: Cursor, Select, Shift, FadeIn, FadeOut
PlayoutState
interface
Playback state with isPlaying, isPaused, cursor position, and duration

Factory Functions

createClip(options)
function
Create a new AudioClip with sample-based positioning. Supports peaks-first rendering when audioBuffer is omitted.
createClipFromSeconds(options)
function
Create a new AudioClip using time-based values (seconds). Automatically converts to samples.
createTrack(options)
function
Create a new ClipTrack with sensible defaults (volume: 1.0, pan: 0, muted: false, etc.)
createTimeline(tracks, sampleRate, options)
function
Create a new Timeline and calculate total duration from all clips

Utility Functions

Clip Queries

getClipsInRange(track, startSample, endSample)
function
Get all clips that overlap with a sample range
getClipsAtSample(track, sample)
function
Get all clips at a specific sample position
clipsOverlap(clip1, clip2)
function
Check if two clips overlap in time
sortClipsByTime(clips)
function
Sort clips by start time (returns new array)
findGaps(track)
function
Find silent regions (gaps) between clips on a track

Time Conversion

samplesToSeconds(samples, sampleRate)
function
Convert sample count to seconds
secondsToSamples(seconds, sampleRate)
function
Convert seconds to sample count (rounded)
samplesToPixels(samples, samplesPerPixel)
function
Convert samples to pixel position
pixelsToSamples(pixels, samplesPerPixel)
function
Convert pixel position to samples

Clip Time Helpers

clipStartTime(clip)
function
Get clip start time in seconds
clipEndTime(clip)
function
Get clip end time in seconds
clipOffsetTime(clip)
function
Get clip trim offset in seconds
clipDurationTime(clip)
function
Get clip duration in seconds

Constants

MAX_CANVAS_WIDTH
number
Maximum width for canvas chunks (1000px) for horizontal virtual scrolling

Usage Examples

Creating a Clip-Based Timeline

import {
  createClipFromSeconds,
  createTrack,
  createTimeline,
  type AudioClip,
  type ClipTrack,
} from '@waveform-playlist/core';

// Create clips using time-based values
const clip1 = createClipFromSeconds({
  audioBuffer, // Your Web Audio API AudioBuffer
  startTime: 0, // Position on timeline (seconds)
  duration: 5.5, // Clip duration (seconds)
  offset: 0.2, // Trim start (seconds)
  gain: 1.0,
  fadeIn: { duration: 0.5, type: 'linear' },
  fadeOut: { duration: 0.3, type: 'exponential' },
});

const clip2 = createClipFromSeconds({
  audioBuffer: audioBuffer2,
  startTime: 6.0,
  gain: 0.8,
});

// Create a track with clips
const track = createTrack({
  name: 'Vocals',
  clips: [clip1, clip2],
  volume: 0.85,
  pan: -0.2, // Slightly left
  color: '#3b82f6',
});

// Create timeline
const timeline = createTimeline([track], 44100, {
  name: 'My Song',
  tempo: 120,
});

console.log(timeline.duration); // Auto-calculated from clips

Peaks-First Rendering

Create clips with pre-computed waveform data but no audio buffer for instant visual rendering:
import { createClip, loadWaveformData } from '@waveform-playlist/browser';
import type { WaveformDataObject } from '@waveform-playlist/core';

// Load pre-computed peaks (BBC audiowaveform format)
const waveformData: WaveformDataObject = await loadWaveformData('/peaks.dat');

// Create clip with peaks only (no audioBuffer yet)
const clip = createClip({
  waveformData,
  startSample: 0,
  // sampleRate and sourceDurationSamples auto-derived from waveformData
});

// Visual rendering works immediately!
// Audio playback requires audioBuffer to be added later:
clip.audioBuffer = await loadAudioBuffer('/audio.mp3');

Querying Clips

import {
  getClipsInRange,
  getClipsAtSample,
  clipsOverlap,
  findGaps,
} from '@waveform-playlist/core';

// Find clips in a time range (1.5s to 3.0s at 44.1kHz)
const clipsInRange = getClipsInRange(
  track,
  1.5 * 44100, // start sample
  3.0 * 44100  // end sample
);

// Find clips at playhead position (2.3s)
const clipsAtPlayhead = getClipsAtSample(
  track,
  2.3 * 44100
);

// Check for overlaps
if (clipsOverlap(clip1, clip2)) {
  console.log('Clips overlap - crossfade opportunity!');
}

// Find silent gaps
const gaps = findGaps(track);
gaps.forEach(gap => {
  console.log(`Gap: ${gap.durationSamples / 44100}s`);
});

Time Conversions

import {
  samplesToSeconds,
  secondsToSamples,
  samplesToPixels,
  pixelsToSamples,
} from '@waveform-playlist/core';

const sampleRate = 44100;
const samplesPerPixel = 100;

// Sample <-> Seconds
const seconds = samplesToSeconds(44100, sampleRate); // 1.0
const samples = secondsToSamples(2.5, sampleRate); // 110250

// Sample <-> Pixels
const pixels = samplesToPixels(44100, samplesPerPixel); // 441
const samplesFromPx = pixelsToSamples(441, samplesPerPixel); // 44100

Key Concepts

Sample-Accurate Positioning

All clip positions, durations, and offsets are stored as integer sample counts, not floating-point seconds. This eliminates floating-point precision errors in audio editing:
interface AudioClip {
  startSample: number;        // Timeline position (samples)
  durationSamples: number;    // Clip duration (samples)
  offsetSamples: number;      // Trim start (samples)
  sampleRate: number;         // For time conversion
  sourceDurationSamples: number; // Total source length
}
Convert to seconds only when needed: seconds = samples / sampleRate

Peaks-First Rendering

Clips can be created with waveformData but without audioBuffer. This enables:
  1. Instant visual rendering - Load pre-computed peaks (1-2 KB) instead of full audio (MB)
  2. Progressive loading - Show waveforms immediately, load audio in background
  3. Bandwidth optimization - Only load audio when user needs playback
The audioBuffer property is optional - add it later when audio loads.

Multi-Clip Tracks

Unlike traditional DAWs with single-file-per-track, Waveform Playlist uses a clip-based model:
  • Each track contains an array of clips
  • Clips can be positioned anywhere on the timeline
  • Gaps between clips are silent
  • Clips can overlap for crossfades
  • Each clip has independent trim points and gain

Type Safety

This package provides complete TypeScript definitions for all data structures. Import types for full IDE autocomplete and compile-time checking:
import type {
  AudioClip,
  ClipTrack,
  Timeline,
  Fade,
  FadeType,
  AnnotationData,
  SpectrogramConfig,
} from '@waveform-playlist/core';
  • Browser - Complete React solution using these types
  • UI Components - React components for visualization
  • Playout - Audio playback using these data structures

Build docs developers (and LLMs) love