Files
bruitiste/src/lib/bytebeat/BytebeatGenerator.ts
2025-09-30 14:20:50 +02:00

109 lines
3.0 KiB
TypeScript

import type { BytebeatOptions, BitDepth } from './types'
import type { EffectValues } from '../../types/effects'
import { compileFormula } from '../../domain/audio/BytebeatCompiler'
import { generateSamples } from '../../domain/audio/SampleGenerator'
import { exportToWav } from '../../domain/audio/WavExporter'
import { AudioPlayer } from '../../domain/audio/AudioPlayer'
export class BytebeatGenerator {
private sampleRate: number
private duration: number
private audioBuffer: Float32Array | null = null
private audioPlayer: AudioPlayer
constructor(options: BytebeatOptions = {}) {
this.sampleRate = options.sampleRate ?? 8000
this.duration = options.duration ?? 10
this.audioPlayer = new AudioPlayer({ sampleRate: this.sampleRate, duration: this.duration })
}
updateOptions(options: Partial<BytebeatOptions>): void {
if (options.sampleRate !== undefined) {
this.sampleRate = options.sampleRate
this.audioBuffer = null
}
if (options.duration !== undefined) {
this.duration = options.duration
this.audioBuffer = null
}
this.audioPlayer.updateOptions({ sampleRate: this.sampleRate, duration: this.duration })
}
setFormula(formula: string): void {
const result = compileFormula(formula)
if (!result.success || !result.compiledFormula) {
throw new Error(`Invalid formula: ${result.error}`)
}
this.audioBuffer = generateSamples(result.compiledFormula, {
sampleRate: this.sampleRate,
duration: this.duration
})
}
generate(): Float32Array {
if (!this.audioBuffer) {
throw new Error('No formula set. Call setFormula() first.')
}
return this.audioBuffer
}
setEffects(values: EffectValues): void {
this.audioPlayer.setEffects(values)
}
getPlaybackPosition(): number {
return this.audioPlayer.getPlaybackPosition()
}
play(): void {
if (!this.audioBuffer) {
throw new Error('No audio buffer. Call setFormula() first.')
}
this.audioPlayer.play(this.audioBuffer)
}
onLoopEnd(callback: () => void): void {
if (!this.audioBuffer) return
this.audioPlayer.setLooping(false)
this.audioPlayer.play(this.audioBuffer, callback)
}
setLooping(loop: boolean): void {
this.audioPlayer.setLooping(loop)
}
scheduleNextTrack(callback: () => void): void {
this.audioPlayer.scheduleNextTrack(callback)
}
pause(): void {
this.audioPlayer.pause()
}
stop(): void {
this.audioPlayer.stop()
}
exportWAV(bitDepth: BitDepth = 8): Blob {
if (!this.audioBuffer) {
throw new Error('No audio buffer. Call setFormula() first.')
}
return exportToWav(this.audioBuffer, { sampleRate: this.sampleRate, bitDepth })
}
downloadWAV(filename: string = 'bytebeat.wav', bitDepth: BitDepth = 8): void {
const blob = this.exportWAV(bitDepth)
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = filename
a.click()
URL.revokeObjectURL(url)
}
dispose(): void {
this.audioPlayer.dispose()
}
}