// AVA — sticky app header: logo, audio source controls (segmented), demo BPM // slider, BPM readout, and the beat indicator + "Set Beat" button side by side // (hard requirement: that pairing is always visible in the header). 'use client' import { useRef } from 'react' import { AudioWaveform, Disc3, FileAudio, Mic, Square, Timer } from 'lucide-react' import { Button } from '@/components/ui/button' import { Slider } from '@/components/ui/slider' import { BeatDot } from '@/components/ava/beat-dot' import { tapBeat, useAudioSource } from '@/components/ava/audio-source' import { useAvaStore } from '@/lib/store' import { cn } from '@/lib/utils' function SourceSegmentButton({ active, onClick, icon: Icon, label, title, tone = 'default', }: { active: boolean onClick: () => void icon: React.ComponentType<{ className?: string }> label: string title: string tone?: 'default' | 'stop' }) { return ( ) } function SourceControls() { const source = useAvaStore((s) => s.source) const setDemoBpm = useAvaStore((s) => s.setDemoBpm) const demoBpm = useAvaStore((s) => s.demoBpm) const { startDemo, startMic, startFile, stop } = useAudioSource() const fileInputRef = useRef(null) return (
void startDemo()} icon={Disc3} label="Demo" title="Built-in demo track (synthesized techno)" /> void startMic()} icon={Mic} label="Mic" title="Live microphone / line-in" /> fileInputRef.current?.click()} icon={FileAudio} label="File" title="Play an audio file (loops)" />
{source === 'demo' && (
DEMO setDemoBpm(v)} className="w-24" aria-label="Demo track tempo" /> {demoBpm}
)} { const file = e.target.files?.[0] if (file) void startFile(file) e.target.value = '' }} />
) } function BpmReadout() { const bpm = useAvaStore((s) => s.stats?.beat.bpm ?? 0) return (
{bpm > 0 ? bpm.toFixed(1) : '—'}
BPM
) } export function AppHeader() { return (
{/* logo */}

AVA

ADVANCED VISUALIZATION AGENT

{/* source controls — full row on mobile, after logo on desktop */}
{/* BPM readout + beat indicator + Set Beat — always paired, always visible */}
) }