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,
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}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);