summaryrefslogtreecommitdiff
path: root/tools/timeline_editor/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'tools/timeline_editor/index.html')
-rw-r--r--tools/timeline_editor/index.html22
1 files changed, 20 insertions, 2 deletions
diff --git a/tools/timeline_editor/index.html b/tools/timeline_editor/index.html
index 1fbfcbf..4d6c81e 100644
--- a/tools/timeline_editor/index.html
+++ b/tools/timeline_editor/index.html
@@ -143,6 +143,7 @@
<div id="playbackControls" style="display: none; margin-left: 20px; gap: 10px; align-items: center;">
<span id="playbackTime">0.00s (0.00b)</span>
<button id="playPauseBtn">▶ Play</button>
+ <button id="replayBtn" disabled>↻ Replay</button>
</div>
</div>
@@ -200,7 +201,7 @@
showBeats: true, quantizeUnit: 1, bpm: 120, isDragging: false, dragOffset: { x: 0, y: 0 },
lastActiveSeqIndex: -1, isDraggingHandle: false, handleType: null, handleDragOffset: 0,
audioBuffer: null, audioDuration: 0, audioSource: null, audioContext: null,
- isPlaying: false, playbackStartTime: 0, playbackOffset: 0, animationFrameId: null,
+ isPlaying: false, playbackStartTime: 0, playbackOffset: 0, playStartPosition: 0, animationFrameId: null,
lastExpandedSeqIndex: -1, dragMoved: false
};
@@ -227,6 +228,7 @@
stats: document.getElementById('stats'),
playbackControls: document.getElementById('playbackControls'),
playPauseBtn: document.getElementById('playPauseBtn'),
+ replayBtn: document.getElementById('replayBtn'),
playbackTime: document.getElementById('playbackTime'),
playbackIndicator: document.getElementById('playbackIndicator'),
panelToggle: document.getElementById('panelToggle'),
@@ -341,6 +343,7 @@
dom.playbackControls.style.display = 'flex';
dom.playbackIndicator.style.display = 'block';
dom.clearAudioBtn.disabled = false;
+ dom.replayBtn.disabled = false;
showMessage(`Audio loaded: ${state.audioDuration.toFixed(2)}s`, 'success');
renderTimeline();
} catch (err) {
@@ -474,9 +477,11 @@
function clearAudio() {
stopPlayback(); state.audioBuffer = null; state.audioDuration = 0; state.playbackOffset = 0;
+ state.playStartPosition = 0;
dom.playbackControls.style.display = 'none';
dom.playbackIndicator.style.display = 'none';
dom.clearAudioBtn.disabled = true;
+ dom.replayBtn.disabled = true;
const ctx = dom.waveformCanvas.getContext('2d');
ctx.clearRect(0, 0, dom.waveformCanvas.width, dom.waveformCanvas.height);
renderTimeline();
@@ -881,7 +886,20 @@
dom.clearAudioBtn.addEventListener('click', () => { clearAudio(); dom.audioInput.value = ''; });
dom.playPauseBtn.addEventListener('click', async () => {
if (state.isPlaying) stopPlayback();
- else { if (state.playbackOffset >= state.audioDuration) state.playbackOffset = 0; await startPlayback(); }
+ else {
+ if (state.playbackOffset >= state.audioDuration) state.playbackOffset = 0;
+ state.playStartPosition = state.playbackOffset;
+ await startPlayback();
+ }
+ });
+
+ dom.replayBtn.addEventListener('click', async () => {
+ stopPlayback(false);
+ state.playbackOffset = state.playStartPosition;
+ const replayBeats = timeToBeats(state.playbackOffset);
+ dom.playbackTime.textContent = `${state.playbackOffset.toFixed(2)}s (${replayBeats.toFixed(2)}b)`;
+ updateIndicatorPosition(replayBeats, false);
+ await startPlayback();
});
dom.waveformContainer.addEventListener('click', async e => {