import { useRef, useEffect, useState } from 'react' const SETTINGS = [ { section: 'Chord Detection', items: [ { key: 'chromaSmooth', label: 'Chroma Smoothing', min: 1, max: 20, step: 1, desc: 'Frames to average for chord chroma. More = smoother but slower to react to chord changes.', }, { key: 'chordVoteThreshold', label: 'Chord Vote Threshold', min: 1, max: 8, step: 1, desc: 'Consecutive identical detections required to confirm a chord. Higher = more stable, slower.', }, { key: 'chordMinScore', label: 'Chord Min Score', min: 0.10, max: 0.80, step: 0.01, desc: 'Minimum coverage score to accept a chord match. Lower = more chord types detected (may add false positives).', }, ], }, { section: 'Key Detection', items: [ { key: 'noteHistorySize', label: 'Note History Size', min: 100, max: 12000, step: 100, desc: 'Pitch readings kept for key detection. ~2000 ≈ 1 min, 12000 ≈ whole session. Larger = more stable key.', }, { key: 'keyVoteWindow', label: 'Key Vote Window', min: 4, max: 30, step: 1, desc: 'Rolling window of key votes. Larger = more inertia — key changes need sustained evidence.', }, { key: 'keyVoteThreshold', label: 'Key Vote Threshold', min: 1, max: 30, step: 1, desc: 'Votes needed within the window to confirm a key. Higher = stricter consensus required.', }, { key: 'chordNoteBoost', label: 'Chord Note Boost', min: 0, max: 10, step: 1, desc: 'Times confirmed chord tones are injected into note history. Higher = chords dominate over transient melody notes.', }, ], }, { section: 'Audio Input', items: [ { key: 'minClarity', label: 'Min Pitch Clarity', min: 0.50, max: 0.99, step: 0.01, desc: 'Autocorrelation clarity threshold to accept a pitch reading. Higher = only clean, in-tune notes count.', }, { key: 'minVolume', label: 'Min Volume (RMS)', min: 0.001, max: 0.05, step: 0.001, desc: 'Minimum signal level before processing. Increase to cut through room noise.', }, ], }, ] export default function Settings({ config, onChange, onClose, onReset, monoColor, onMonoColorChange }) { // Snapshot on mount so Cancel can restore const savedConfig = useRef(config) const savedMono = useRef(monoColor) function handleCancel() { Object.entries(savedConfig.current).forEach(([k, v]) => onChange(k, v)) onMonoColorChange(savedMono.current) onClose() } function DeviceSelector({ config, onChange }) { const [devices, setDevices] = useState([]) async function refresh() { try { if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) return const list = await navigator.mediaDevices.enumerateDevices() setDevices(list.filter(d => d.kind === 'audioinput')) } catch (e) { console.warn('enumerateDevices failed', e) } } useEffect(() => { refresh() }, []) return (
Tune chord and key recognition sensitivity in real time
Mono Color Mode
Use a single purple palette instead of purple + amber for note tiers.