remove beginner/advanced mode, fix D7 detection, history on key lock, stable loop display

This commit is contained in:
vadimwit
2026-03-05 22:51:42 +00:00
parent 8f96afe015
commit 1697a14716
+13 -30
View File
@@ -22,9 +22,6 @@ export default function App() {
// ── Listening state ────────────────────────────────────────────────────── // ── Listening state ──────────────────────────────────────────────────────
const [isListening, setIsListening] = useState(false) const [isListening, setIsListening] = useState(false)
// ── App mode ─────────────────────────────────────────────────────────────
const [appMode, setAppMode] = useState('beginner') // 'beginner' | 'advanced'
// ── Key: auto-detected + optional lock ─────────────────────────────────── // ── Key: auto-detected + optional lock ───────────────────────────────────
const [keyInfo, setKeyInfo] = useState(null) // auto-detected const [keyInfo, setKeyInfo] = useState(null) // auto-detected
const [lockedKey, setLockedKey] = useState(null) // { root, mode } or null const [lockedKey, setLockedKey] = useState(null) // { root, mode } or null
@@ -33,9 +30,6 @@ export default function App() {
// Effective key used by all components // Effective key used by all components
const effectiveKey = lockedKey ?? keyInfo const effectiveKey = lockedKey ?? keyInfo
// Beginner + locked key = only match the 7 diatonic chords (simpler, fewer false positives)
// Advanced + locked key = allow borrowed/chromatic chords like D7 in Am
const isStrictMode = appMode === 'beginner' && lockedKey !== null
// ── Chord state ─────────────────────────────────────────────────────────── // ── Chord state ───────────────────────────────────────────────────────────
const [chordHistory, setChordHistory] = useState([]) const [chordHistory, setChordHistory] = useState([])
@@ -52,14 +46,22 @@ export default function App() {
Array.from({ length: CHROMA_SMOOTH }, () => new Float32Array(12)) Array.from({ length: CHROMA_SMOOTH }, () => new Float32Array(12))
) )
const chromaIdxRef = useRef(0) const chromaIdxRef = useRef(0)
const chordVotesRef = useRef([]) const chordVotesRef = useRef([])
const progressionVoteRef = useRef(null) // stabilise loop display
// Keep ref in sync // Keep ref in sync
useEffect(() => { effectiveKeyRef.current = effectiveKey }, [effectiveKey]) useEffect(() => { effectiveKeyRef.current = effectiveKey }, [effectiveKey])
// ── Detect progression whenever chord history changes ──────────────────── // ── Detect progression — require 2 consecutive identical results to commit
useEffect(() => { useEffect(() => {
setDetectedProgression(detectRepeatingProgression(chordHistory)) const detected = detectRepeatingProgression(chordHistory)
if (!detected) return
const key = detected.join(',')
if (progressionVoteRef.current === key) {
setDetectedProgression(detected)
} else {
progressionVoteRef.current = key
}
}, [chordHistory]) }, [chordHistory])
// ── Key lock handlers ───────────────────────────────────────────────────── // ── Key lock handlers ─────────────────────────────────────────────────────
@@ -68,8 +70,6 @@ export default function App() {
setLockedKey(info) setLockedKey(info)
effectiveKeyRef.current = info effectiveKeyRef.current = info
chordVotesRef.current = [] chordVotesRef.current = []
setChordHistory([])
setDetectedProgression(null)
} }
function quickLock({ root, mode, confidence }) { function quickLock({ root, mode, confidence }) {
@@ -77,8 +77,6 @@ export default function App() {
setLockedKey(info) setLockedKey(info)
effectiveKeyRef.current = info effectiveKeyRef.current = info
chordVotesRef.current = [] chordVotesRef.current = []
setChordHistory([])
setDetectedProgression(null)
} }
function removeLock() { function removeLock() {
@@ -136,7 +134,7 @@ export default function App() {
for (const frame of ring) for (let i = 0; i < 12; i++) avg[i] += frame[i] for (const frame of ring) for (let i = 0; i < 12; i++) avg[i] += frame[i]
for (let i = 0; i < 12; i++) avg[i] /= CHROMA_SMOOTH for (let i = 0; i < 12; i++) avg[i] /= CHROMA_SMOOTH
const chord = matchChordFromChroma(avg, key, bassPC, isStrictMode) const chord = matchChordFromChroma(avg, key, bassPC, false)
if (!chord) { if (!chord) {
// Ambiguous moment (transition, silence) — reset streak, history is untouched // Ambiguous moment (transition, silence) — reset streak, history is untouched
chordVotesRef.current = [] chordVotesRef.current = []
@@ -184,21 +182,6 @@ export default function App() {
{/* ── Controls bar ── */} {/* ── Controls bar ── */}
<div className="mb-4 flex flex-wrap gap-3 items-center p-3 bg-panel border border-border rounded-xl"> <div className="mb-4 flex flex-wrap gap-3 items-center p-3 bg-panel border border-border rounded-xl">
{/* Mode toggle */}
<div className="flex bg-surface border border-border rounded-full p-0.5 text-sm">
{['beginner', 'advanced'].map(m => (
<button
key={m}
onClick={() => setAppMode(m)}
className={`px-4 py-1 rounded-full capitalize transition-all ${
appMode === m ? 'bg-accent text-white' : 'text-gray-400 hover:text-gray-200'
}`}
>
{m}
</button>
))}
</div>
{/* Key lock */} {/* Key lock */}
{lockedKey ? ( {lockedKey ? (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -276,7 +259,7 @@ export default function App() {
<Fretboard <Fretboard
keyInfo={effectiveKey} keyInfo={effectiveKey}
currentChord={currentChord} currentChord={currentChord}
pentatonicOnly={appMode === 'beginner'} pentatonicOnly={false}
/> />
</div> </div>
<div className="md:col-span-2"> <div className="md:col-span-2">