From 179c52facc6f1b9b9390f18ecfb0c8e497da5bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Forment?= Date: Mon, 13 Oct 2025 11:17:20 +0200 Subject: [PATCH] click on waveform --- src/App.svelte | 9 ++++++++- src/lib/audio/services/AudioService.ts | 9 ++++++--- src/lib/components/WaveformDisplay.svelte | 7 ++++--- src/lib/utils/keyboard.ts | 5 +++++ 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/App.svelte b/src/App.svelte index 80502e2..1d28d37 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -124,6 +124,7 @@ onProcess: processSound, onDownload: download, onUndo: undo, + onPlayFromStart: replaySound, onDurationDecrease: (large) => { duration = Math.max(0.05, duration - (large ? 1 : 0.05)); }, @@ -199,6 +200,12 @@ } } + function playFromPosition(offset: number) { + if (currentBuffer) { + audioService.play(currentBuffer, offset); + } + } + function download() { if (!currentBuffer) return; downloadWAV(currentBuffer, "synth-sound.wav"); @@ -504,7 +511,7 @@ {selectionStart} {selectionEnd} onselectionchange={handleSelectionChange} - onclick={replaySound} + onclick={playFromPosition} /> {/if} diff --git a/src/lib/audio/services/AudioService.ts b/src/lib/audio/services/AudioService.ts index 708185d..cf4cb40 100644 --- a/src/lib/audio/services/AudioService.ts +++ b/src/lib/audio/services/AudioService.ts @@ -5,6 +5,7 @@ export class AudioService { private currentSource: AudioBufferSourceNode | null = null; private gainNode: GainNode | null = null; private startTime = 0; + private currentOffset = 0; private isPlaying = false; private onPlaybackUpdate: ((position: number) => void) | null = null; private animationFrameId: number | null = null; @@ -48,7 +49,7 @@ export class AudioService { return buffer; } - play(buffer: AudioBuffer): void { + play(buffer: AudioBuffer, offset: number = 0): void { this.stop(); const ctx = this.getContext(); @@ -57,6 +58,7 @@ export class AudioService { source.connect(this.gainNode!); this.startTime = ctx.currentTime; + this.currentOffset = offset; this.isPlaying = true; this.currentSource = source; @@ -74,7 +76,7 @@ export class AudioService { } }; - source.start(); + source.start(0, offset); this.updatePlaybackPosition(); } @@ -84,7 +86,7 @@ export class AudioService { } const elapsed = this.context.currentTime - this.startTime; - this.onPlaybackUpdate(elapsed); + this.onPlaybackUpdate(elapsed + this.currentOffset); this.animationFrameId = requestAnimationFrame(() => this.updatePlaybackPosition()); } @@ -99,6 +101,7 @@ export class AudioService { this.currentSource = null; } this.isPlaying = false; + this.currentOffset = 0; if (this.animationFrameId !== null) { cancelAnimationFrame(this.animationFrameId); this.animationFrameId = null; diff --git a/src/lib/components/WaveformDisplay.svelte b/src/lib/components/WaveformDisplay.svelte index c763423..f9b9cb4 100644 --- a/src/lib/components/WaveformDisplay.svelte +++ b/src/lib/components/WaveformDisplay.svelte @@ -8,7 +8,7 @@ selectionStart?: number | null; selectionEnd?: number | null; onselectionchange?: (start: number | null, end: number | null) => void; - onclick?: () => void; + onclick?: (timeOffset: number) => void; } let { @@ -75,8 +75,9 @@ } } - if (onclick) { - onclick(); + if (onclick && buffer) { + const timeOffset = (x / canvas.width) * (buffer.length / buffer.sampleRate); + onclick(timeOffset); } } diff --git a/src/lib/utils/keyboard.ts b/src/lib/utils/keyboard.ts index 9ad1556..422161c 100644 --- a/src/lib/utils/keyboard.ts +++ b/src/lib/utils/keyboard.ts @@ -9,6 +9,7 @@ export interface KeyboardActions { onVolumeIncrease?: (large: boolean) => void; onEscape?: () => void; onUndo?: () => void; + onPlayFromStart?: () => void; } export function createKeyboardHandler(actions: KeyboardActions) { @@ -34,6 +35,10 @@ export function createKeyboardHandler(actions: KeyboardActions) { case 's': actions.onDownload?.(); break; + case ' ': + event.preventDefault(); + actions.onPlayFromStart?.(); + break; case 'arrowleft': event.preventDefault(); actions.onDurationDecrease?.(isLargeAdjustment);