mirror of
https://github.com/9x/sheetmusictrainer.git
synced 2026-09-02 09:34:33 +02:00
move tuner
This commit is contained in:
107
src/App.tsx
107
src/App.tsx
@@ -306,6 +306,13 @@ function App() {
|
|||||||
return getFretboardPositions(targetMidi, currentTuning);
|
return getFretboardPositions(targetMidi, currentTuning);
|
||||||
}, [settings.showHint, targetMidi, currentTuning, currentInstrumentDef]);
|
}, [settings.showHint, targetMidi, currentTuning, currentInstrumentDef]);
|
||||||
|
|
||||||
|
// Auto-enable mic when tuner is turned on
|
||||||
|
useEffect(() => {
|
||||||
|
if (settings.showTuningMeter && !listening) {
|
||||||
|
setListening(true);
|
||||||
|
}
|
||||||
|
}, [settings.showTuningMeter, listening]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`app-container ${settings.zenMode ? 'zen-mode' : ''}`}>
|
<div className={`app-container ${settings.zenMode ? 'zen-mode' : ''}`}>
|
||||||
{!settings.zenMode && (
|
{!settings.zenMode && (
|
||||||
@@ -423,22 +430,18 @@ function App() {
|
|||||||
{listening ? <Mic size={28} /> : <MicOff size={28} />}
|
{listening ? <Mic size={28} /> : <MicOff size={28} />}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{settings.showTuningMeter && pitchData ? (
|
<div className={`pitch-readout ${pitchData ? 'active' : ''}`}>
|
||||||
<TuningMeter cents={pitchData.cents} noteName={pitchData.note} />
|
{pitchData ? (
|
||||||
) : (
|
<>
|
||||||
<div className={`pitch-readout ${pitchData ? 'active' : ''}`}>
|
<span className={`detected-note ${pitchData.midi === targetMidi ? 'match' : ''}`}>
|
||||||
{pitchData ? (
|
{pitchData.note}
|
||||||
<>
|
</span>
|
||||||
<span className={`detected-note ${pitchData.midi === targetMidi ? 'match' : ''}`}>
|
<span className="detected-hz">{Math.round(pitchData.frequency)} Hz</span>
|
||||||
{pitchData.note}
|
</>
|
||||||
</span>
|
) : (
|
||||||
<span className="detected-hz">{Math.round(pitchData.frequency)} Hz</span>
|
<span className="placeholder">{listening ? "Listening..." : "Mic Off"}</span>
|
||||||
</>
|
)}
|
||||||
) : (
|
</div>
|
||||||
<span className="placeholder">{listening ? "Listening..." : "Mic Off"}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -446,13 +449,17 @@ function App() {
|
|||||||
|
|
||||||
{!settings.zenMode && (
|
{!settings.zenMode && (
|
||||||
<footer className="settings-footer">
|
<footer className="settings-footer">
|
||||||
<Controls settings={settings} onUpdateSettings={setSettings} />
|
<Controls
|
||||||
|
settings={settings}
|
||||||
|
onUpdateSettings={setSettings}
|
||||||
|
currentPitch={pitchData ? { note: pitchData.note, cents: pitchData.cents } : null}
|
||||||
|
/>
|
||||||
<div className="app-subtitle">
|
<div className="app-subtitle">
|
||||||
<a href="http://jensmohrmann.de" target="_blank" rel="noopener noreferrer">jensmohrmann.de</a>
|
<a href="http://jensmohrmann.de" target="_blank" rel="noopener noreferrer">jensmohrmann.de</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
)
|
)}
|
||||||
}
|
|
||||||
|
|
||||||
{/* Floating Zen Mode Button (Toggle) */}
|
{/* Floating Zen Mode Button (Toggle) */}
|
||||||
<button
|
<button
|
||||||
@@ -464,39 +471,41 @@ function App() {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Help Popup */}
|
{/* Help Popup */}
|
||||||
{showHelp && (
|
{
|
||||||
<div className="help-popup-overlay" onClick={() => setShowHelp(false)}>
|
showHelp && (
|
||||||
<div className="help-popup" onClick={e => e.stopPropagation()}>
|
<div className="help-popup-overlay" onClick={() => setShowHelp(false)}>
|
||||||
<button className="help-close" onClick={() => setShowHelp(false)}><X size={20} /></button>
|
<div className="help-popup" onClick={e => e.stopPropagation()}>
|
||||||
<h2 style={{ marginTop: 0, marginBottom: '24px' }}>Keyboard Shortcuts</h2>
|
<button className="help-close" onClick={() => setShowHelp(false)}><X size={20} /></button>
|
||||||
|
<h2 style={{ marginTop: 0, marginBottom: '24px' }}>Keyboard Shortcuts</h2>
|
||||||
|
|
||||||
<div className="help-item">
|
<div className="help-item">
|
||||||
<span>Skip Note</span>
|
<span>Skip Note</span>
|
||||||
<span className="shortcut-key">Space</span>
|
<span className="shortcut-key">Space</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="help-item">
|
<div className="help-item">
|
||||||
<span>Toggle Hint</span>
|
<span>Toggle Hint</span>
|
||||||
<span className="shortcut-key">H</span>
|
<span className="shortcut-key">H</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="help-item">
|
<div className="help-item">
|
||||||
<span>Toggle Zen Mode</span>
|
<span>Toggle Zen Mode</span>
|
||||||
<span className="shortcut-key">Z</span>
|
<span className="shortcut-key">Z</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="help-item">
|
<div className="help-item">
|
||||||
<span>Replay Note</span>
|
<span>Replay Note</span>
|
||||||
<span className="shortcut-key">R</span>
|
<span className="shortcut-key">R</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="help-item">
|
<div className="help-item">
|
||||||
<span>Toggle Game Mode</span>
|
<span>Toggle Game Mode</span>
|
||||||
<span className="shortcut-key">M</span>
|
<span className="shortcut-key">M</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="help-item">
|
<div className="help-item">
|
||||||
<span>Close Help / Exit Zen</span>
|
<span>Close Help / Exit Zen</span>
|
||||||
<span className="shortcut-key">Esc</span>
|
<span className="shortcut-key">Esc</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)}
|
}
|
||||||
</div >
|
</div >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Settings, Guitar, Music, Gauge } from 'lucide-react';
|
|||||||
import { TUNINGS, INSTRUMENT_TUNINGS } from '../music/Tunings';
|
import { TUNINGS, INSTRUMENT_TUNINGS } from '../music/Tunings';
|
||||||
import { INSTRUMENT_DEFINITIONS } from '../music/InstrumentConfigs';
|
import { INSTRUMENT_DEFINITIONS } from '../music/InstrumentConfigs';
|
||||||
import { getTempoMarking } from '../music/TempoMarkings';
|
import { getTempoMarking } from '../music/TempoMarkings';
|
||||||
|
import { TuningMeter } from './TuningMeter';
|
||||||
|
|
||||||
export type Difficulty = string;
|
export type Difficulty = string;
|
||||||
|
|
||||||
@@ -33,9 +34,10 @@ export interface AppSettings {
|
|||||||
interface ControlsProps {
|
interface ControlsProps {
|
||||||
settings: AppSettings;
|
settings: AppSettings;
|
||||||
onUpdateSettings: (s: AppSettings) => void;
|
onUpdateSettings: (s: AppSettings) => void;
|
||||||
|
currentPitch: { note: string; cents: number } | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Controls: React.FC<ControlsProps> = ({ settings, onUpdateSettings }) => {
|
export const Controls: React.FC<ControlsProps> = ({ settings, onUpdateSettings, currentPitch }) => {
|
||||||
const handleDifficultyChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
const handleDifficultyChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
onUpdateSettings({ ...settings, difficulty: e.target.value as Difficulty });
|
onUpdateSettings({ ...settings, difficulty: e.target.value as Difficulty });
|
||||||
};
|
};
|
||||||
@@ -223,6 +225,16 @@ export const Controls: React.FC<ControlsProps> = ({ settings, onUpdateSettings }
|
|||||||
<div className="switch-thumb" />
|
<div className="switch-thumb" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{settings.showTuningMeter && currentPitch && (
|
||||||
|
<div style={{ paddingTop: '8px', borderTop: '1px solid rgba(255,255,255,0.1)' }}>
|
||||||
|
<TuningMeter cents={currentPitch.cents} noteName={currentPitch.note} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{settings.showTuningMeter && !currentPitch && (
|
||||||
|
<div style={{ paddingTop: '8px', borderTop: '1px solid rgba(255,255,255,0.1)', fontSize: '11px', opacity: 0.5, textAlign: 'center' }}>
|
||||||
|
Listening...
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tool 2: Metronome */}
|
{/* Tool 2: Metronome */}
|
||||||
|
|||||||
Reference in New Issue
Block a user