import { compileFormula } from '../domain/audio/BytebeatCompiler' import { generateSamples } from '../domain/audio/SampleGenerator' import { AudioPlayer } from '../domain/audio/AudioPlayer' import type { EffectValues } from '../types/effects' export interface PlaybackOptions { sampleRate: number duration: number } export class PlaybackManager { private player: AudioPlayer private currentFormula: string | null = null private currentBuffer: Float32Array | null = null private queuedCallback: (() => void) | null = null constructor(options: PlaybackOptions) { this.player = new AudioPlayer(options) } updateOptions(options: Partial): void { this.player.updateOptions(options) this.currentBuffer = null } setEffects(values: EffectValues): void { this.player.setEffects(values) } play(formula: string, sampleRate: number, duration: number): boolean { const result = compileFormula(formula) if (!result.success || !result.compiledFormula) { console.error('Failed to compile formula:', result.error) return false } try { this.currentBuffer = generateSamples(result.compiledFormula, { sampleRate, duration }) this.currentFormula = formula this.player.setLooping(true) this.player.play(this.currentBuffer) return true } catch (error) { console.error('Failed to generate samples:', error) return false } } stop(): void { this.player.stop() this.currentFormula = null this.queuedCallback = null } scheduleNextTrack(callback: () => void): void { this.queuedCallback = callback this.player.scheduleNextTrack(() => { if (this.queuedCallback) { this.queuedCallback() this.queuedCallback = null } }) } getPlaybackPosition(): number { return this.player.getPlaybackPosition() } isPlaying(): boolean { return this.currentFormula !== null } getCurrentFormula(): string | null { return this.currentFormula } dispose(): void { this.player.dispose() } }