From ca6b901bc802367f1c6f144b72eda8b733118d3a Mon Sep 17 00:00:00 2001 From: vadimwit Date: Fri, 6 Mar 2026 00:08:15 +0000 Subject: [PATCH] compact layout, instrument select near fretboard, collapsible tuner, chord sensitivity tuning --- src/App.jsx | 95 +++++++++++------------ src/components/ChordDisplay.jsx | 8 +- src/components/KeyDisplay.jsx | 6 +- src/components/ProgressionSuggestions.jsx | 12 +-- src/components/SafeNotes.jsx | 10 +-- 5 files changed, 64 insertions(+), 67 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index d894fec..4691d2d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -17,15 +17,17 @@ const KEY_VOTE_THRESHOLD = 9 // out of 12 const CHORD_NOTE_BOOST = 3 // confirmed chord tones injected N× into note history // Chord detection tuning -const CHROMA_SMOOTH = 12 // frames to average (~200ms at 60fps) -const CHORD_VOTE_THRESHOLD = 3 // consecutive identical detections required +const CHROMA_SMOOTH = 8 // frames to average — more responsive +const CHORD_VOTE_THRESHOLD = 2 // consecutive identical detections required +const CHORD_MIN_SCORE = 0.38 // lower = more chord types detected export default function App() { // ── Listening state ────────────────────────────────────────────────────── const [isListening, setIsListening] = useState(false) - // ── Instrument view ─────────────────────────────────────────────────────── + // ── Instrument view + tuner ─────────────────────────────────────────────── const [instrument, setInstrument] = useState('guitar') // 'guitar' | 'piano' + const [showTuner, setShowTuner] = useState(false) // ── Key: auto-detected + optional lock ─────────────────────────────────── const [keyInfo, setKeyInfo] = useState(null) // auto-detected @@ -168,7 +170,7 @@ export default function App() { 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 - const chord = matchChordFromChroma(avg, key, bassPC, false) + const chord = matchChordFromChroma(avg, key, bassPC, false, CHORD_MIN_SCORE) if (!chord) { // Ambiguous moment (transition, silence) — reset streak, history is untouched chordVotesRef.current = [] @@ -203,26 +205,27 @@ export default function App() { const currentChord = chordHistory[chordHistory.length - 1] return ( -
+
{/* ── Header ── */} -
+
-

+

WhatTheFlat ♭?

-

Real-time key detection for real humans

+

Real-time key detection for live jams

{/* ── Controls bar ── */} -
- {/* Instrument toggle */} -
- {['guitar', 'piano'].map(v => ( - - ))} -
- - {/* Key lock */} +
{lockedKey ? (
🔒 {lockedKey.root} {lockedKey.mode} -
) : (
- {/* Top 3 detected key candidates — click to lock */} {topKeyCandidates.map((k, i) => (
+ {instrument === 'guitar' + ? + : + }
+ + {/* ── Tuner — collapsible ── */}
- + + {showTuner &&
}
diff --git a/src/components/ChordDisplay.jsx b/src/components/ChordDisplay.jsx index cc4b8b1..515d6e6 100644 --- a/src/components/ChordDisplay.jsx +++ b/src/components/ChordDisplay.jsx @@ -3,13 +3,13 @@ export default function ChordDisplay({ history }) { const past = history.slice(-8, -1) return ( -
-

Chord

-

+

+

Chord

+

{current ?? '—'}

{past.length > 0 && ( -
+
{past.map((chord, i) => ( -

+

+

{locked ? '🔒 Key (locked)' : 'Detected Key'}

{root ? ( <> -

+

{root} {mode}

diff --git a/src/components/ProgressionSuggestions.jsx b/src/components/ProgressionSuggestions.jsx index 39c5c61..72662a1 100644 --- a/src/components/ProgressionSuggestions.jsx +++ b/src/components/ProgressionSuggestions.jsx @@ -8,17 +8,17 @@ export default function ProgressionSuggestions({ keyInfo }) { const progressions = getSuggestedProgressions(root, mode) return ( -
-

+

+

Progressions in {root} {mode}

-
+
{progressions.map(prog => ( -
+
{prog.genre} -
+
{prog.chords.map((chord, i) => ( - + {chord} ({prog.rn[i]}) diff --git a/src/components/SafeNotes.jsx b/src/components/SafeNotes.jsx index f5cfeb0..f6979c2 100644 --- a/src/components/SafeNotes.jsx +++ b/src/components/SafeNotes.jsx @@ -12,15 +12,15 @@ export default function SafeNotes({ keyInfo, currentChord }) { const chordTones = currentChord ? getChordTones(currentChord) : [] return ( -
-

Safe Notes

-
+
+

Safe Notes

+
{ALL_NOTES.map(note => { const isChordTone = chordTones.includes(note) const isPenta = penta.includes(note) const isScale = full.includes(note) - let cls = 'px-3 py-2 rounded-lg text-sm font-semibold border transition-all ' + let cls = 'px-2.5 py-1.5 rounded-lg text-sm font-semibold border transition-all ' if (isChordTone) { cls += 'bg-accent text-white border-accent scale-105' } else if (isPenta) { @@ -36,7 +36,7 @@ export default function SafeNotes({ keyInfo, currentChord }) { ) })}
-
+
Chord tone Pentatonic Scale