Files
evilspins/app/platine-tools/sampler.ts
2025-12-07 19:44:21 +01:00

98 lines
2.4 KiB
TypeScript

class Sampler {
public audioContext: AudioContext = new AudioContext();
public gainNode: GainNode = new GainNode(this.audioContext);
public audioBuffer: AudioBuffer | null = null;
public audioBufferReversed: AudioBuffer | null = null;
public audioSource: AudioBufferSourceNode | null = null;
public duration: number = 0;
public isReversed: boolean = false;
constructor() {
this.gainNode.connect(this.audioContext.destination);
}
async getAudioBuffer(audioUrl: string) {
const response = await fetch(audioUrl);
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer);
return audioBuffer;
}
async loadTrack(audioUrl: string) {
this.audioBuffer = await this.getAudioBuffer(audioUrl);
this.audioBufferReversed = this.getReversedAudioBuffer(this.audioBuffer);
this.duration = this.audioBuffer.duration;
}
getReversedAudioBuffer(audioBuffer: AudioBuffer) {
const bufferArray = audioBuffer.getChannelData(0).slice().reverse();
const audioBufferReversed = this.audioContext.createBuffer(
1,
audioBuffer.length,
audioBuffer.sampleRate,
);
audioBufferReversed.getChannelData(0).set(bufferArray);
return audioBufferReversed;
}
changeDirection(isReversed: boolean, secondsPlayed: number) {
this.isReversed = isReversed;
this.play(secondsPlayed);
}
play(offset = 0) {
this.pause();
const buffer = this.isReversed
? this.audioBufferReversed
: this.audioBuffer;
const cueTime = this.isReversed ? this.duration - offset : offset;
this.audioSource = this.audioContext.createBufferSource();
this.audioSource.buffer = buffer;
this.audioSource.loop = false;
this.audioSource.connect(this.gainNode);
this.audioSource.start(0, cueTime);
}
updateSpeed(speed: number, isReversed: boolean, secondsPlayed: number) {
if (!this.audioSource) {
return;
}
if (isReversed !== this.isReversed) {
this.changeDirection(isReversed, secondsPlayed);
}
const { currentTime } = this.audioContext;
const speedAbsolute = Math.abs(speed);
this.audioSource.playbackRate.cancelScheduledValues(currentTime);
this.audioSource.playbackRate.linearRampToValueAtTime(
Math.max(0.001, speedAbsolute),
currentTime,
);
}
pause() {
if (!this.audioSource) {
return;
}
this.audioSource.stop();
}
}
export default Sampler;