import { loopbackTest, playAudio, startMicListener } from './audio' import { handleGuess, getSecret } from './game' import type { GuessResult } from './game' const RESET = '\x1b[0m' const BOLD = '\x1b[1m' const DIM = '\x1b[2m' const GREEN = '\x1b[32m' const YELLOW = '\x1b[33m' const BLUE = '\x1b[34m' const CYAN = '\x1b[36m' const RED = '\x1b[31m' async function prompt(question: string): Promise { process.stdout.write(question) for await (const line of console) { return line.trim() } return '' } function getLocalHostname() { const proc = Bun.spawnSync(['scutil', '--get', 'LocalHostName']) if (proc.exitCode === 0) return proc.stdout.toString().trim() + '.local' return 'localhost' } function getDeviceName(type: 'input' | 'output'): string { const args = type === 'input' ? ['-c', '-t', 'input'] : ['-c'] const proc = Bun.spawnSync(['SwitchAudioSource', ...args]) if (proc.exitCode === 0) return proc.stdout.toString().trim() return 'system default' } function logGuess(result: GuessResult) { const { type, guess, guessCount } = result if (type === 'higher') { console.log(`${DIM}Guess #${guessCount}:${RESET} ${BOLD}${guess}${RESET} โ†’ ${YELLOW}๐Ÿ“ข Higher!${RESET}`) return } if (type === 'lower') { console.log(`${DIM}Guess #${guessCount}:${RESET} ${BOLD}${guess}${RESET} โ†’ ${BLUE}๐Ÿ“ข Lower!${RESET}`) return } console.log(`${DIM}Guess #${guessCount}:${RESET} ${BOLD}${guess}${RESET} โ†’ ${GREEN}๐ŸŽ‰ CORRECT!${RESET}`) console.log() console.log(`${CYAN}New round! Secret number: ${BOLD}${getSecret()}${RESET}`) console.log(`${'โ”€'.repeat(40)}`) console.log() } async function onMessage(text: string) { await Bun.sleep(500) if (text === 'HELLO') { console.log(`${GREEN}${BOLD}Player connected via audio!${RESET}`) await playAudio('HEY BUDDY') return } const result = await handleGuess(text) if (result) logGuess(result) } export async function startup(port: number) { const soxCheck = Bun.spawnSync(['which', 'sox']) if (soxCheck.exitCode !== 0) { console.error(`\n ${BOLD}sox is not installed.${RESET} Run: brew install sox\n`) process.exit(1) } console.clear() console.log() console.log(`${BOLD}Corey's Screechy Audio Demo${RESET}`) console.log() const speaker = getDeviceName('output') const mic = getDeviceName('input') console.log(`${BOLD}Speaker:${RESET} ${GREEN}${speaker}${RESET}`) console.log(`${BOLD}Microphone:${RESET} ${GREEN}${mic}${RESET}`) console.log() console.log(`${YELLOW}${BOLD}๐Ÿ”Š Turn your volume up!${RESET}`) console.log(`${DIM}Testing audio: playing a chirp and listening for it...${RESET}`) console.log() const loopbackOk = await loopbackTest() if (loopbackOk) { console.log(`${GREEN}${BOLD}โœ“ Audio working!${RESET} ${DIM}Speaker โ†’ mic pipeline verified${RESET}`) } else { console.log(`${RED}${BOLD}โœ— Couldn't hear the test chirp.${RESET}`) console.log() console.log(`${YELLOW}Try:${RESET}`) console.log(` โ€ข Disconnect headphones โ€” sound needs to travel through the air`) console.log(` โ€ข Check System Settings > Sound (output: "${speaker}", input: "${mic}")`) console.log(` โ€ข Turn your volume up`) console.log() await prompt(` Press Enter to continue anyway... `) } console.clear() console.log() console.log(`${BOLD}Corey's Screechy Audio Demo${RESET}`) console.log(`${DIM}Speaker: ${speaker} ยท Mic: ${mic}${RESET}`) console.log() const hostname = getLocalHostname() const url = `https://${hostname}:${port}` console.log(`${GREEN}${BOLD}Scan QR code on your phone to play!${RESET}`) console.log() try { const QRCode = await import('qrcode') const qr = await QRCode.toString(url, { type: 'terminal', small: true }) console.log(qr) } catch { console.log(`${BOLD}${CYAN}${url}${RESET}`) console.log() } console.log(`${BOLD}Secret number: ${GREEN}${getSecret()}${RESET}`) console.log(`${'โ”€'.repeat(40)}`) console.log(`${DIM}๐ŸŽค Listening for guesses...${RESET}`) console.log() startMicListener(onMessage) }