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:
2025-11-20 07:38:07 +01:00
parent 9007522e18
commit 08b33aacb5

View File

@@ -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',