feat: add split at cursor functionality
Implemented track splitting at playback cursor: - Added handleSplitAtCursor function to split selected track at current time - Extracts two audio segments: before and after cursor position - Creates two new tracks from the segments with numbered names - Removes original track after split - Added 'Split at Cursor' command to command palette (keyboard shortcut: S) - Validation for edge cases (no track selected, no audio, invalid position) - User feedback via toast notifications 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -803,6 +803,66 @@ export function AudioEditor() {
|
||||
});
|
||||
}, [tracks, executeCommand, updateTrack, addToast]);
|
||||
|
||||
const handleSplitAtCursor = React.useCallback(() => {
|
||||
if (!selectedTrackId) {
|
||||
addToast({
|
||||
title: 'No Track Selected',
|
||||
description: 'Select a track to split',
|
||||
variant: 'error',
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const track = tracks.find((t) => t.id === selectedTrackId);
|
||||
if (!track || !track.audioBuffer) {
|
||||
addToast({
|
||||
title: 'No Audio',
|
||||
description: 'Selected track has no audio to split',
|
||||
variant: 'error',
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const splitTime = currentTime;
|
||||
const duration = track.audioBuffer.duration;
|
||||
|
||||
// Can't split at the very beginning or end
|
||||
if (splitTime <= 0 || splitTime >= duration) {
|
||||
addToast({
|
||||
title: 'Invalid Split Position',
|
||||
description: 'Cannot split at the beginning or end of the track',
|
||||
variant: 'error',
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract two segments
|
||||
const firstSegment = extractBufferSegment(track.audioBuffer, 0, splitTime);
|
||||
const secondSegment = extractBufferSegment(track.audioBuffer, splitTime, duration);
|
||||
|
||||
// Create two new tracks
|
||||
const trackIndex = tracks.indexOf(track);
|
||||
const firstName = `${track.name} (1)`;
|
||||
const secondName = `${track.name} (2)`;
|
||||
|
||||
// Add the two new tracks
|
||||
addTrackFromBuffer(firstSegment, firstName);
|
||||
addTrackFromBuffer(secondSegment, secondName);
|
||||
|
||||
// Remove the original track
|
||||
removeTrack(track.id);
|
||||
|
||||
addToast({
|
||||
title: 'Track Split',
|
||||
description: `Split track at ${formatDuration(splitTime)}`,
|
||||
variant: 'success',
|
||||
duration: 2000,
|
||||
});
|
||||
}, [selectedTrackId, tracks, currentTime, addTrackFromBuffer, removeTrack, addToast]);
|
||||
|
||||
// Export handler
|
||||
const handleExport = React.useCallback(async (settings: ExportSettings) => {
|
||||
if (tracks.length === 0) {
|
||||
@@ -1381,6 +1441,14 @@ export function AudioEditor() {
|
||||
category: 'edit',
|
||||
action: handleDuplicate,
|
||||
},
|
||||
{
|
||||
id: 'split-at-cursor',
|
||||
label: 'Split at Cursor',
|
||||
description: 'Split selected track at current playback position',
|
||||
shortcut: 'S',
|
||||
category: 'edit',
|
||||
action: handleSplitAtCursor,
|
||||
},
|
||||
{
|
||||
id: 'select-all',
|
||||
label: 'Select All',
|
||||
|
||||
Reference in New Issue
Block a user