click on waveform

This commit is contained in:
2025-10-13 11:17:20 +02:00
parent 4df063f9b3
commit 179c52facc
4 changed files with 23 additions and 7 deletions

View File

@ -124,6 +124,7 @@
onProcess: processSound, onProcess: processSound,
onDownload: download, onDownload: download,
onUndo: undo, onUndo: undo,
onPlayFromStart: replaySound,
onDurationDecrease: (large) => { onDurationDecrease: (large) => {
duration = Math.max(0.05, duration - (large ? 1 : 0.05)); 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() { function download() {
if (!currentBuffer) return; if (!currentBuffer) return;
downloadWAV(currentBuffer, "synth-sound.wav"); downloadWAV(currentBuffer, "synth-sound.wav");
@ -504,7 +511,7 @@
{selectionStart} {selectionStart}
{selectionEnd} {selectionEnd}
onselectionchange={handleSelectionChange} onselectionchange={handleSelectionChange}
onclick={replaySound} onclick={playFromPosition}
/> />
{/if} {/if}

View File

@ -5,6 +5,7 @@ export class AudioService {
private currentSource: AudioBufferSourceNode | null = null; private currentSource: AudioBufferSourceNode | null = null;
private gainNode: GainNode | null = null; private gainNode: GainNode | null = null;
private startTime = 0; private startTime = 0;
private currentOffset = 0;
private isPlaying = false; private isPlaying = false;
private onPlaybackUpdate: ((position: number) => void) | null = null; private onPlaybackUpdate: ((position: number) => void) | null = null;
private animationFrameId: number | null = null; private animationFrameId: number | null = null;
@ -48,7 +49,7 @@ export class AudioService {
return buffer; return buffer;
} }
play(buffer: AudioBuffer): void { play(buffer: AudioBuffer, offset: number = 0): void {
this.stop(); this.stop();
const ctx = this.getContext(); const ctx = this.getContext();
@ -57,6 +58,7 @@ export class AudioService {
source.connect(this.gainNode!); source.connect(this.gainNode!);
this.startTime = ctx.currentTime; this.startTime = ctx.currentTime;
this.currentOffset = offset;
this.isPlaying = true; this.isPlaying = true;
this.currentSource = source; this.currentSource = source;
@ -74,7 +76,7 @@ export class AudioService {
} }
}; };
source.start(); source.start(0, offset);
this.updatePlaybackPosition(); this.updatePlaybackPosition();
} }
@ -84,7 +86,7 @@ export class AudioService {
} }
const elapsed = this.context.currentTime - this.startTime; const elapsed = this.context.currentTime - this.startTime;
this.onPlaybackUpdate(elapsed); this.onPlaybackUpdate(elapsed + this.currentOffset);
this.animationFrameId = requestAnimationFrame(() => this.updatePlaybackPosition()); this.animationFrameId = requestAnimationFrame(() => this.updatePlaybackPosition());
} }
@ -99,6 +101,7 @@ export class AudioService {
this.currentSource = null; this.currentSource = null;
} }
this.isPlaying = false; this.isPlaying = false;
this.currentOffset = 0;
if (this.animationFrameId !== null) { if (this.animationFrameId !== null) {
cancelAnimationFrame(this.animationFrameId); cancelAnimationFrame(this.animationFrameId);
this.animationFrameId = null; this.animationFrameId = null;

View File

@ -8,7 +8,7 @@
selectionStart?: number | null; selectionStart?: number | null;
selectionEnd?: number | null; selectionEnd?: number | null;
onselectionchange?: (start: number | null, end: number | null) => void; onselectionchange?: (start: number | null, end: number | null) => void;
onclick?: () => void; onclick?: (timeOffset: number) => void;
} }
let { let {
@ -75,8 +75,9 @@
} }
} }
if (onclick) { if (onclick && buffer) {
onclick(); const timeOffset = (x / canvas.width) * (buffer.length / buffer.sampleRate);
onclick(timeOffset);
} }
} }

View File

@ -9,6 +9,7 @@ export interface KeyboardActions {
onVolumeIncrease?: (large: boolean) => void; onVolumeIncrease?: (large: boolean) => void;
onEscape?: () => void; onEscape?: () => void;
onUndo?: () => void; onUndo?: () => void;
onPlayFromStart?: () => void;
} }
export function createKeyboardHandler(actions: KeyboardActions) { export function createKeyboardHandler(actions: KeyboardActions) {
@ -34,6 +35,10 @@ export function createKeyboardHandler(actions: KeyboardActions) {
case 's': case 's':
actions.onDownload?.(); actions.onDownload?.();
break; break;
case ' ':
event.preventDefault();
actions.onPlayFromStart?.();
break;
case 'arrowleft': case 'arrowleft':
event.preventDefault(); event.preventDefault();
actions.onDurationDecrease?.(isLargeAdjustment); actions.onDurationDecrease?.(isLargeAdjustment);