Skip to content

Editing ​

Clips are pieces of audio on a track. Each one says where it starts on the timeline (start), how far into its audio it begins (offset) and how long it plays (duration), so cuts and trims never touch the audio itself.

Mouse and touch ​

GestureWhat it does
Drag a clipMoves it in time and to other tracks, past or over other clips
Drag below the last trackMakes a new track for the clip (needs createTrack)
Drag a clip edgeTrims it, up to the ends of its audio
Drag a corner handleFade in or fade out
Click / Shift click / Ctrl or ⌘ clickSelect, add to the selection, toggle in the selection
Drag on an empty trackSelects every clip the box touches; with Shift, adds them to the selection
Drag on the rulerSelects a time range across all tracks, for splitting and looping
Drag a range's handlesMoves its start or end, on the ruler or at its edges on the tracks
Click the ruler or an empty trackMoves the playhead
Alt while draggingTurns snapping off
Ctrl or ⌘ + wheelZooms around the pointer
Drag a track's bottom edgeMakes the track taller or shorter; double-click to reset
+ above the track headersAdds a track at the bottom and lets you name it
Right-click a clipOpens the clip menu: edit notes (note clips), make unique (copies of a pattern), split at the playhead, duplicate, delete
Click a track's name, or right-click its headerOpens the track menu: rename, duplicate, add a track below, move up or down, delete
Double-click or double-tap a track's nameRenames it; Enter keeps the name, Esc cancels

On touch screens, drag clips with a finger and swipe empty space to scroll. Range selection works from the ruler. Pinch with two fingers to zoom in and out around the point between them, and hold a finger on a clip for half a second to open its menu.

Tracks ​

The + above the track headers asks what to add: an empty audio track, audio from a file, or an instrument or drum track. A new empty track puts its name up for editing. Each track's menu, opened from its name or by right-clicking its header, can rename, duplicate (with its clips), add a track below, move it up or down, or delete it with its clips. Every change is one undo step.

Audio from a file shows when you pass importAudio. It opens the device's file picker and hands the picked files to your function. importAudioFiles from @toneflix/studio decodes each one in the page, without uploading it, and puts it on a new track named after the file, at the playhead, as one undo step:

ts
import { importAudioFiles, StudioTimeline } from '@toneflix/studio';

const timeline = new StudioTimeline('#editor', {
  importAudio: (files) => importAudioFiles(timeline, engine, files, { onSource: drawWaveform }),
});

New tracks come from createTrack when you give it, and are named Track 1, Track 2 and so on otherwise. Pass editTracks: false to hide the button and the menu, and trackLabels to rename their items. In your own renderHeader, fire TRACK_MENU_EVENT from an element to open the menu under it, and give the name element the class tfs-track-name for double-click renaming:

ts
import { TRACK_MENU_EVENT } from '@toneflix/studio';

name.className = 'tfs-track-name';
name.onclick = () => name.dispatchEvent(new CustomEvent(TRACK_MENU_EVENT, { bubbles: true }));

From code: addTrack(track?, index?), removeTrack(id), renameTrack(id, name), duplicateTrack(id), moveTrack(id, index), editTrackName(id) and showTrackMenu(id).

Keyboard ​

While the timeline has focus:

KeyWhat it does
SSplit the selected clips at the playhead, or cut a selected range at both edges. Does nothing when nothing is selected
Delete / BackspaceDelete the selected clips
Ctrl+DDuplicate the selected clips right after themselves
Ctrl+ASelect every clip
Arrow left / rightNudge by one snap step (0.1 s with snapping off)
Arrow up / downMove to the track above or below
Ctrl+Z, Ctrl+Shift+ZUndo, redo
EscCancel a drag, or clear the selection

⌘ works in place of Ctrl on macOS. Pass keyboard: false to handle shortcuts yourself.

After a split only the left pieces stay selected, so you can grab a right-hand piece and move it on its own.

Snapping ​

With the grid on and a snap value other than off, a dragged clip's start lands on the grid. With snapping off, clips are pulled towards other clips' edges, the playhead and zero when they come within 8 pixels (snapToClips: false turns that off).

ts
timeline.setGrid({ bpm: 96, meter: [6, 8], snap: '1/8' });
timeline.setGrid({ show: false });

Snap values are 'off', 'bar', 'beat', '1/8', '1/16' and '1/32'. The tempo counts quarter notes, so a beat of 6/8 is an eighth note.

Overlapping clips ​

Clips can sit on top of each other. Where they overlap, the clip that starts later is on top and is the one heard. audibleRanges gives the heard part of each clip, which is what a player or a mix renderer needs:

ts
import { audibleRanges } from '@toneflix/studio';

const onTrack = timeline.state.clips.filter((clip) => clip.track === 'vox');

for (const { clip, start, end } of audibleRanges(onTrack)) {
  // play clip.source from clip.offset + (start - clip.start) for end - start seconds
}

Editing from code ​

Everything the gestures do is also a method:

ts
timeline.setTime(8);
timeline.select(['clip-1']);
timeline.split();
timeline.nudge(0.5, 1);
timeline.duplicateSelected();
timeline.deleteSelected();
timeline.setZoom(120);
timeline.fit();

For edits the view has no method for, use the pure edit functions through the model, so they land in the undo history:

ts
import { setGain } from '@toneflix/studio';

timeline.model.apply('Gain', (state) => setGain(state, new Set(timeline.selection), 0.5));

Released under the MIT License.