mirror of
https://github.com/9x/sheetmusictrainer.git
synced 2026-09-02 09:34:33 +02:00
Working
This commit is contained in:
@@ -101,7 +101,7 @@ function App() {
|
|||||||
}
|
}
|
||||||
}, [pitchData, targetMidi, matchStartTime, generateNewNote]);
|
}, [pitchData, targetMidi, matchStartTime, generateNewNote]);
|
||||||
|
|
||||||
const targetDetails = getNoteDetails(targetMidi);
|
|
||||||
|
|
||||||
// Hint text construction
|
// Hint text construction
|
||||||
const hintPositions = useMemo(() => {
|
const hintPositions = useMemo(() => {
|
||||||
@@ -135,7 +135,9 @@ function App() {
|
|||||||
|
|
||||||
{settings.showHint && (
|
{settings.showHint && (
|
||||||
<div className="hint-card">
|
<div className="hint-card">
|
||||||
<div className="hint-note">{targetDetails.scientific}</div>
|
<div className="hint-note">
|
||||||
|
{getNoteDetails(targetMidi + 12).scientific} (Written)
|
||||||
|
</div>
|
||||||
<div className="hint-positions">
|
<div className="hint-positions">
|
||||||
{hintPositions.map((p, i) => (
|
{hintPositions.map((p, i) => (
|
||||||
<span key={i} className="hint-tag">
|
<span key={i} className="hint-tag">
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ interface SheetMusicProps {
|
|||||||
clef?: 'treble' | 'bass';
|
clef?: 'treble' | 'bass';
|
||||||
width?: number;
|
width?: number;
|
||||||
height?: number;
|
height?: number;
|
||||||
|
transpose?: number; // Transposition in semitones for visualization (e.g., +12 for guitar)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SheetMusic: React.FC<SheetMusicProps> = ({
|
export const SheetMusic: React.FC<SheetMusicProps> = ({
|
||||||
@@ -15,7 +16,8 @@ export const SheetMusic: React.FC<SheetMusicProps> = ({
|
|||||||
playedMidi,
|
playedMidi,
|
||||||
clef = 'treble',
|
clef = 'treble',
|
||||||
width = 300,
|
width = 300,
|
||||||
height = 200
|
height = 200,
|
||||||
|
transpose = 12 // Default to +1 octave (Guitar Notation)
|
||||||
}) => {
|
}) => {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@@ -35,37 +37,45 @@ export const SheetMusic: React.FC<SheetMusicProps> = ({
|
|||||||
stave.addClef(clef);
|
stave.addClef(clef);
|
||||||
stave.setContext(context).draw();
|
stave.setContext(context).draw();
|
||||||
|
|
||||||
|
// Helper to create keys for VexFlow
|
||||||
|
const getVexFlowKey = (midi: number) => {
|
||||||
|
const visualMidi = midi + transpose;
|
||||||
|
const details = getNoteDetails(visualMidi);
|
||||||
|
return {
|
||||||
|
keys: [`${details.name.toLowerCase()}/${details.octave}`],
|
||||||
|
hasAccidental: details.name.includes("#")
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// Create Target Note
|
// Create Target Note
|
||||||
const targetDetails = getNoteDetails(targetMidi);
|
const targetData = getVexFlowKey(targetMidi);
|
||||||
const targetKey = `${targetDetails.name.toLowerCase()}/${targetDetails.octave}`;
|
|
||||||
|
|
||||||
const targetStaveNote = new StaveNote({
|
const targetStaveNote = new StaveNote({
|
||||||
keys: [targetKey],
|
keys: targetData.keys,
|
||||||
duration: "w",
|
duration: "w",
|
||||||
clef: clef
|
clef: clef
|
||||||
});
|
});
|
||||||
|
|
||||||
if (targetDetails.name.includes("#")) {
|
if (targetData.hasAccidental) {
|
||||||
targetStaveNote.addModifier(new Accidental("#"));
|
targetStaveNote.addModifier(new Accidental("#"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playedMidi) {
|
if (playedMidi) {
|
||||||
const playedDetails = getNoteDetails(playedMidi);
|
const playedData = getVexFlowKey(playedMidi);
|
||||||
const playedKey = `${playedDetails.name.toLowerCase()}/${playedDetails.octave}`;
|
|
||||||
|
|
||||||
const playedStaveNote = new StaveNote({
|
const playedStaveNote = new StaveNote({
|
||||||
keys: [playedKey],
|
keys: playedData.keys,
|
||||||
duration: "h",
|
duration: "h",
|
||||||
clef: clef,
|
clef: clef
|
||||||
});
|
});
|
||||||
|
|
||||||
// Target note as half note to match measure
|
// Target note as half note to match measure
|
||||||
const targetNoteHalf = new StaveNote({
|
const targetNoteHalf = new StaveNote({
|
||||||
keys: [targetKey],
|
keys: targetData.keys,
|
||||||
duration: "h",
|
duration: "h",
|
||||||
clef: clef
|
clef: clef
|
||||||
});
|
});
|
||||||
if (targetDetails.name.includes("#")) targetNoteHalf.addModifier(new Accidental("#"));
|
if (targetData.hasAccidental) targetNoteHalf.addModifier(new Accidental("#"));
|
||||||
|
|
||||||
|
|
||||||
if (playedMidi === targetMidi) {
|
if (playedMidi === targetMidi) {
|
||||||
@@ -74,10 +84,11 @@ export const SheetMusic: React.FC<SheetMusicProps> = ({
|
|||||||
playedStaveNote.setStyle({ fillStyle: "var(--color-error)", strokeStyle: "var(--color-error)" });
|
playedStaveNote.setStyle({ fillStyle: "var(--color-error)", strokeStyle: "var(--color-error)" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playedDetails.name.includes("#")) {
|
if (playedData.hasAccidental) {
|
||||||
playedStaveNote.addModifier(new Accidental("#"));
|
playedStaveNote.addModifier(new Accidental("#"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use camelCase properties as fixed previously
|
||||||
const voiceCombined = new Voice({ numBeats: 4, beatValue: 4 });
|
const voiceCombined = new Voice({ numBeats: 4, beatValue: 4 });
|
||||||
voiceCombined.addTickables([targetNoteHalf, playedStaveNote]);
|
voiceCombined.addTickables([targetNoteHalf, playedStaveNote]);
|
||||||
|
|
||||||
@@ -91,7 +102,7 @@ export const SheetMusic: React.FC<SheetMusicProps> = ({
|
|||||||
voice.draw(context, stave);
|
voice.draw(context, stave);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [targetMidi, playedMidi, clef, width, height]);
|
}, [targetMidi, playedMidi, clef, width, height, transpose]);
|
||||||
|
|
||||||
return <div ref={containerRef} className="sheet-music-container" />;
|
return <div ref={containerRef} className="sheet-music-container" />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,3 +49,8 @@ export function getRandomNote(min: number, max: number, validNotes?: number[]):
|
|||||||
}
|
}
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to convert Written note to Sounding note for guitar
|
||||||
|
// e.g. Input: "C4" (Written) -> Returns C3 (Sounding) MIDI
|
||||||
|
// But usually we work with MIDI.
|
||||||
|
// This is just a note for logic: Guitar Sounding = Written - 12.
|
||||||
|
|||||||
Reference in New Issue
Block a user