diff options
Diffstat (limited to 'tools/timeline_editor')
| -rw-r--r-- | tools/timeline_editor/index.html | 22 |
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 => { |
