Track Management
Control individual tracks with mute, solo, volume, and pan controls.
Track Controls Component​
Enable the built-in track controls panel:
<WaveformPlaylistProvider
tracks={tracks}
controls={{ show: true, width: 200 }}
>
<Waveform />
</WaveformPlaylistProvider>
The controls panel displays:
- Track name
- Mute button
- Solo button
- Volume slider
- Pan slider
useTrackControls Hook​
For custom track control UI:
import { useTrackControls } from '@waveform-playlist/browser';
function CustomTrackControls({ trackIndex }: { trackIndex: number }) {
const {
muted,
soloed,
volume,
pan,
setMuted,
setSoloed,
setVolume,
setPan,
} = useTrackControls(trackIndex);
return (
<div>
<button onClick={() => setMuted(!muted)}>
{muted ? 'Unmute' : 'Mute'}
</button>
<button onClick={() => setSoloed(!soloed)}>
{soloed ? 'Unsolo' : 'Solo'}
</button>
<input
type="range"
min="0"
max="1"
step="0.01"
value={volume}
onChange={(e) => setVolume(parseFloat(e.target.value))}
/>
<input
type="range"
min="-1"
max="1"
step="0.01"
value={pan}
onChange={(e) => setPan(parseFloat(e.target.value))}
/>
</div>
);
}
Mute and Solo​
Mute​
Muting a track silences it completely:
const { muted, setMuted } = useTrackControls(trackIndex);
// Toggle mute
setMuted(!muted);
// Mute track
setMuted(true);
// Unmute track
setMuted(false);
Solo​
Soloing a track mutes all other non-soloed tracks:
const { soloed, setSoloed } = useTrackControls(trackIndex);
// Toggle solo
setSoloed(!soloed);
When multiple tracks are soloed, only those tracks are audible.
Volume Control​
Volume ranges from 0 (silent) to 1 (full volume):
const { volume, setVolume } = useTrackControls(trackIndex);
// Set to 50% volume
setVolume(0.5);
// Fade out
for (let v = volume; v >= 0; v -= 0.1) {
setVolume(v);
await delay(100);
}
Pan Control​
Pan ranges from -1 (full left) to 1 (full right):
const { pan, setPan } = useTrackControls(trackIndex);
// Pan fully left
setPan(-1);
// Center
setPan(0);
// Pan fully right
setPan(1);
Track Selection​
Select tracks for operations like deletion or effects:
import { usePlaylistState, usePlaylistControls } from '@waveform-playlist/browser';
function TrackSelector() {
const { tracks, selectedTrackIndex } = usePlaylistState();
const { selectTrack } = usePlaylistControls();
return (
<ul>
{tracks.map((track, index) => (
<li
key={index}
onClick={() => selectTrack(index)}
style={{
background: selectedTrackIndex === index ? '#e0e0ff' : 'transparent',
}}
>
{track.name}
</li>
))}
</ul>
);
}
Adding and Removing Tracks​
Adding Tracks​
import { usePlaylistControls, useAudioTracks } from '@waveform-playlist/browser';
function AddTrackButton() {
const { addTrack } = usePlaylistControls();
const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
const blobUrl = URL.createObjectURL(file);
const { tracks } = await useAudioTracks([
{ src: blobUrl, name: file.name.replace(/\.[^/.]+$/, '') },
]);
if (tracks.length > 0) {
addTrack(tracks[0]);
}
};
return <input type="file" accept="audio/*" onChange={handleFileSelect} />;
}
Removing Tracks​
import { usePlaylistControls, usePlaylistState } from '@waveform-playlist/browser';
function RemoveTrackButton() {
const { selectedTrackIndex } = usePlaylistState();
const { removeTrack } = usePlaylistControls();
return (
<button
onClick={() => removeTrack(selectedTrackIndex)}
disabled={selectedTrackIndex === null}
>
Remove Selected Track
</button>
);
}
Track Reordering​
Reorder tracks by drag and drop or programmatically:
import { usePlaylistControls } from '@waveform-playlist/browser';
function TrackReorder() {
const { moveTrack } = usePlaylistControls();
// Move track from index 2 to index 0
const moveToTop = () => moveTrack(2, 0);
return <button onClick={moveToTop}>Move Track 3 to Top</button>;
}
Initial Track Configuration​
Set initial track states when loading:
const { tracks, loading } = useAudioTracks([
{
src: '/audio/drums.mp3',
name: 'Drums',
gain: 0.8, // 80% volume
muted: false,
soloed: false,
pan: 0, // Center
},
{
src: '/audio/bass.mp3',
name: 'Bass',
gain: 1.0, // Full volume
muted: false,
soloed: false,
pan: -0.3, // Slightly left
},
{
src: '/audio/keys.mp3',
name: 'Keys',
gain: 0.7,
muted: true, // Start muted
soloed: false,
pan: 0.3, // Slightly right
},
]);
Complete Example​
import {
WaveformPlaylistProvider,
Waveform,
useAudioTracks,
usePlaylistState,
useTrackControls,
} from '@waveform-playlist/browser';
function TrackControlRow({ trackIndex }: { trackIndex: number }) {
const { tracks } = usePlaylistState();
const { muted, soloed, volume, pan, setMuted, setSoloed, setVolume, setPan } =
useTrackControls(trackIndex);
const track = tracks[trackIndex];
return (
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center', padding: '0.5rem' }}>
<span style={{ width: '100px' }}>{track.name}</span>
<button
onClick={() => setMuted(!muted)}
style={{ background: muted ? '#ff6b6b' : '#e0e0e0' }}
>
M
</button>
<button
onClick={() => setSoloed(!soloed)}
style={{ background: soloed ? '#ffd93d' : '#e0e0e0' }}
>
S
</button>
<label>
Vol
<input
type="range"
min="0"
max="1"
step="0.01"
value={volume}
onChange={(e) => setVolume(parseFloat(e.target.value))}
/>
</label>
<label>
Pan
<input
type="range"
min="-1"
max="1"
step="0.01"
value={pan}
onChange={(e) => setPan(parseFloat(e.target.value))}
/>
</label>
</div>
);
}
function TrackManagementExample() {
const { tracks, loading } = useAudioTracks([
{ src: '/audio/drums.mp3', name: 'Drums' },
{ src: '/audio/bass.mp3', name: 'Bass' },
{ src: '/audio/vocals.mp3', name: 'Vocals' },
]);
if (loading) return <div>Loading...</div>;
return (
<WaveformPlaylistProvider tracks={tracks} timescale>
<div>
{tracks.map((_, index) => (
<TrackControlRow key={index} trackIndex={index} />
))}
</div>
<Waveform />
</WaveformPlaylistProvider>
);
}
Next Steps​
- Annotations - Add time-synchronized annotations
- Audio Effects - Apply effects to tracks
