click on waveform
This commit is contained in:
@ -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}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
Reference in New Issue
Block a user