diff --git a/src/components/Controls.tsx b/src/components/Controls.tsx index 6c1b99e..d29d369 100644 --- a/src/components/Controls.tsx +++ b/src/components/Controls.tsx @@ -3,6 +3,7 @@ import { TUNINGS, INSTRUMENT_TUNINGS } from '../music/Tunings'; import { INSTRUMENT_DEFINITIONS } from '../music/InstrumentConfigs'; import { getTempoMarking } from '../music/TempoMarkings'; import { TuningMeter } from './TuningMeter'; +import { TargetNoteControls } from './TargetNoteControls'; import { useSettings } from '../context/useSettings'; import { type Difficulty, type RhythmSettings } from '../types/SettingsTypes'; @@ -193,6 +194,9 @@ export const Controls: React.FC = ({ currentPitch }) => { )} + {/* Target-note filter: unified controls, all modes */} + + {/* Bottom Section: Tools Grid (2 Columns now) */}
{/* Tool 1: Tuner */} diff --git a/src/components/PhraseTrainer.tsx b/src/components/PhraseTrainer.tsx index 9d9a0d5..6cf7a5d 100644 --- a/src/components/PhraseTrainer.tsx +++ b/src/components/PhraseTrainer.tsx @@ -13,13 +13,13 @@ import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRe import { useSettings } from '../context/useSettings'; import { useAudioPlayer } from '../hooks/useAudioPlayer'; import { usePhraseTrainer, type PhraseTrainerApi, type PhrasePhase } from '../hooks/usePhraseTrainer'; -import { getPhraseSettings, type PhraseSettings } from '../types/SettingsTypes'; +import { getPhraseSettings, getPracticeFilter, type PhraseSettings, type PracticeFilter } from '../types/SettingsTypes'; import { rawFrameCount } from '../hooks/rawFrameBus'; import { audioEngine } from '../audio/AudioEngine'; import { computePlayableNotes, isFrettedInstrument, positionsWithinWindow, fretWindowNotes } from '../music/playableRange'; import { generateMelody } from '../music/melodyGenerator'; import { generateScaleDrill } from '../music/scaleDrills'; -import { isMode, MODE_LABELS, TONICS, type ModeId } from '../music/scales'; +import { isMode, type ModeId } from '../music/scales'; import { scoreEvents, type Result, type Score, type ScoreEvent } from '../score/model'; import { getNoteDetails } from '../music/NoteUtils'; import { EXERCISES, loadExercise } from '../exercises/library'; @@ -68,8 +68,27 @@ export const PhraseTrainer = forwardRef( const setSettings = updateSettings; const { playNote } = useAudioPlayer(); const phrase = getPhraseSettings(settings); + // Unified target-note controls: Phrase Mode reads/writes the shared + // practice filter so all modes expose identical key/fret-window state. + const pf = getPracticeFilter(settings); + phrase.keyTonic = pf.keyTonic; + phrase.keyMode = pf.keyMode; + phrase.fretWindowEnabled = pf.fretWindowEnabled; + phrase.fretMin = pf.fretMin; + phrase.fretMax = pf.fretMax; const setPhrase = useCallback((updates: Partial) => { - updateSettings(s => ({ ...s, phrase: { ...getPhraseSettings(s), ...updates } })); + updateSettings(s => { + const next = { ...s, phrase: { ...getPhraseSettings(s), ...updates } }; + // Mirror shared filter fields into the unified practice filter. + const shared: Partial = {}; + if ('keyTonic' in updates) shared.keyTonic = updates.keyTonic; + if ('keyMode' in updates) shared.keyMode = updates.keyMode; + if ('fretWindowEnabled' in updates) shared.fretWindowEnabled = updates.fretWindowEnabled; + if ('fretMin' in updates) shared.fretMin = updates.fretMin; + if ('fretMax' in updates) shared.fretMax = updates.fretMax; + if (Object.keys(shared).length > 0) next.practice = { ...getPracticeFilter(s), ...shared }; + return next; + }); }, [updateSettings]); const currentInstrumentDef = INSTRUMENT_DEFINITIONS[settings.instrument]; @@ -489,22 +508,9 @@ export const PhraseTrainer = forwardRef( {(phrase.material === 'melody' || phrase.material === 'scale') && ( - <> - - - + + Key/mode: use the "Target key" controls below the sheet — shared across modes. + )} {phrase.material === 'melody' && ( @@ -604,28 +610,9 @@ export const PhraseTrainer = forwardRef( )} {fretted && ( - <> - - {phrase.fretWindowEnabled && ( - <> - - - - )} - + + Fret window: use the "Fret window" controls below the sheet — shared across modes. + )}