import { type BarkBattleSession, createBarkBattleSession } from '../domain/BarkBattleSession'; import type { MicrophoneFailureReason } from '../domain/BarkBattleTypes'; import { BarkDetector } from '../domain/BarkDetector'; import type { BarkBattleConfig } from './BarkBattleConfig'; export class BarkBattleController { private session: BarkBattleSession; private detector: BarkDetector; private sampleClockMs = 0; constructor(private config: BarkBattleConfig) { this.session = createBarkBattleSession(config); this.detector = this.createDetector(); } getSnapshot() { return this.session.snapshot; } getSampleClockMs() { return this.sampleClockMs; } updateConfig(config: BarkBattleConfig) { this.config = config; this.restart(); } finishNow() { if (this.session.snapshot.phase !== 'playing') { this.session = this.session.startMockRound(); } if (this.session.snapshot.phase === 'countdown') { this.session = this.session.tick(this.session.snapshot.countdownMs); } this.session = this.session.tick(this.session.snapshot.remainingMs + 1); } startWithMockInput() { this.session = createBarkBattleSession(this.config).startMockRound(); this.detector = this.createDetector(); this.sampleClockMs = 0; } forcePlayerBark(volume = 0.9) { if (this.session.snapshot.phase !== 'playing') { this.session = this.session.startMockRound(); } if (this.session.snapshot.phase === 'countdown') { this.session = this.session.tick(this.session.snapshot.countdownMs); } this.session = this.session.applyPlayerBark({ side: 'player', atMs: this.sampleClockMs, peakVolume: volume, durationMs: this.config.minBarkDurationMs, }); } submitInputSample(volume: number, atMs = this.sampleClockMs) { const events = this.detector.acceptSample({ atMs, volume }); for (const event of events) { this.session = this.session.applyPlayerBark(event); } } submitMockSample(volume: number) { this.submitInputSample(volume); } tick(deltaMs: number) { this.sampleClockMs += deltaMs; this.session = this.session.tick(deltaMs); } restart() { this.session = createBarkBattleSession(this.config); this.detector = this.createDetector(); this.sampleClockMs = 0; } failMicrophone(reason: MicrophoneFailureReason) { this.session = this.session.failMicrophone(reason); } private createDetector() { return new BarkDetector({ threshold: this.config.barkThreshold, minBarkGapMs: this.config.minBarkGapMs, }); } }