@3sv1n/multitrack
v0.1.2
Published
Framework-agnostic audio synchronization and playback control
Downloads
58
Maintainers
Readme
@3sv1n/multitrack
A framework-agnostic audio synchronization and playback control library. It manages WebAudio contexts, multitrack synchronization, seeking, muting, volume controls, and scrubbing.
It also exports a React hook adapter (useAudioEngine) for seamlessly consuming engine state with tear-free concurrent rendering using useSyncExternalStore.
Installation
npm install @3sv1n/multitrack
# or
yarn add @3sv1n/multitrack
# or
pnpm add @3sv1n/multitrackNote: This package has a peer dependency on react >= 18 for the useAudioEngine hook. If you use the engine in a non-React environment, you can ignore the React dependency and use the core classes directly.
Basic Usage
Creating an Engine
import { NativeWebAudioEngine } from '@3sv1n/multitrack';
// Instantiate the engine
const engine = new NativeWebAudioEngine();
// Register tracks by ID and URL
await engine.registerTrack('vocals', 'https://example.com/vocals.mp3');
await engine.registerTrack('instrumental', 'https://example.com/instrumental.mp3');
// Play all tracks synchronously
engine.play();Using in React
The useAudioEngine hook allows you to bind the engine's state to your React components.
import { useState } from 'react';
import { NativeWebAudioEngine, useAudioEngine } from '@3sv1n/multitrack';
function Player() {
// Keep the engine instance stable across renders
const [engine] = useState(() => new NativeWebAudioEngine());
// Subscribe to engine state
const { state } = useAudioEngine(engine);
return (
<div>
<p>Time: {state.currentTime.toFixed(2)} / {state.duration.toFixed(2)}</p>
<button onClick={() => engine.togglePlay()}>
{state.isPlaying ? 'Pause' : 'Play'}
</button>
{state.tracks.map(track => (
<div key={track.id}>
<span>{track.id} (Volume: {track.volume})</span>
<button onClick={() => engine.setMuted(track.id, !track.isMuted)}>
{track.isMuted ? 'Unmute' : 'Mute'}
</button>
</div>
))}
</div>
);
}API Reference
IAudioEngine Interface
The IAudioEngine defines the core contract for audio manipulation. NativeWebAudioEngine is the provided implementation.
Core Methods
getState(): PlayerState- Returns the current snapshot of the player state.subscribe(listener: () => void): () => void- Subscribe to state changes.registerTrack(id: string, url: string): Promise<void>- Adds an audio track to the engine.unregisterTrack(id: string): void- Removes a track and frees its resources.destroy(): void- Cleans up the engine, stopping all playback.
Playback Controls
play(): Promise<void>pause(): voidtogglePlay(): voidseekTo(time: number): void
Scrubbing
Scrubbing allows UI sliders to pause playback visually, seek smoothly, and then resume if it was playing previously.
startScrub(): voidupdateScrub(time: number): voidcommitScrub(time: number): voidcancelScrub(): void
Mixing
setVolume(id: string, volume: number): void(Volume ranges from 0 to 1)setMuted(id: string, muted: boolean): voidsetPitch(semitones: number): voidsetPlaybackRate(rate: number): void
PlayerState
The object returned by getState().
interface PlayerState {
isPlaying: boolean;
isScrubbing: boolean;
currentTime: number;
duration: number;
pitch: number; // in semitones
playbackRate: number; // multiplier (e.g. 1.0)
error?: Error;
tracks: TrackState[]; // Array of track states
}
interface TrackState {
id: string;
volume: number;
isMuted: boolean;
isReady: boolean;
error?: Error;
}Advanced Usage
Under the hood, this package utilizes @soundtouchjs/audio-worklet for high-quality pitch and tempo shifting. The engine handles the setup automatically when instantiated.
