Files
sheetmusictrainer/src/music/InstrumentConfigs.ts

155 lines
5.8 KiB
TypeScript

import type { Instrument } from './Tunings';
export type ClefMode = 'treble' | 'bass' | 'grand';
export type NoteSetType = 'static' | 'open_strings' | 'first_position' | 'custom_fret' | 'specific_string';
export interface NoteSetConfig {
id: string;
label: string;
type: NoteSetType;
min?: number; // MIDI number for static
max?: number; // MIDI number for static
notes?: number[]; // Explicit list for static
defaultMinFret?: number;
defaultMaxFret?: number;
stringIndex?: number; // 0-based index from lowest string (0) to highest
transpose?: number; // Override instrument default
clef?: ClefMode; // Override instrument default
}
export interface InstrumentDefinition {
id: Instrument | 'piano' | 'voice' | 'whistle';
displayName: string;
clefMode: ClefMode;
transpose: number; // Semitones to add to MIDI to get written note (e.g. +12 for guitar)
ranges: NoteSetConfig[];
showTuning: boolean;
}
export const INSTRUMENT_DEFINITIONS: Record<string, InstrumentDefinition> = {
guitar: {
id: 'guitar',
displayName: 'Guitar',
clefMode: 'treble',
transpose: 12, // Guitar sounds octave lower than written, so we add 12 to played midi to show it
showTuning: true,
ranges: [
{
id: 'open',
label: 'Open Strings',
type: 'open_strings',
// Legacy fallback if needed, but App should use type
min: 40, max: 64
},
{
id: 'first_pos',
label: 'First Position',
type: 'first_position',
min: 40, max: 68
},
{
id: 'all',
label: 'All Notes',
type: 'static',
min: 40, max: 76
},
{
id: 'custom',
label: 'Custom Fret Range',
type: 'custom_fret',
defaultMinFret: 0,
defaultMaxFret: 12
},
// Per String Sets (High E is index 5, Low E is index 0)
{ id: 'string_1', label: 'String 1 (High)', type: 'specific_string', stringIndex: 5 },
{ id: 'string_2', label: 'String 2', type: 'specific_string', stringIndex: 4 },
{ id: 'string_3', label: 'String 3', type: 'specific_string', stringIndex: 3 },
{ id: 'string_4', label: 'String 4', type: 'specific_string', stringIndex: 2 },
{ id: 'string_5', label: 'String 5', type: 'specific_string', stringIndex: 1 },
{ id: 'string_6', label: 'String 6 (Low)', type: 'specific_string', stringIndex: 0 },
]
},
bass: {
id: 'bass',
displayName: 'Bass Guitar',
clefMode: 'bass',
transpose: 12,
showTuning: true,
ranges: [
// Bass Standard: E1 (28) -> G3 approx (55)
{ id: 'all', label: 'All Notes', type: 'static', min: 28, max: 55 },
{ id: 'string_1', label: 'String 1 (High)', type: 'specific_string', stringIndex: 3 },
{ id: 'string_2', label: 'String 2', type: 'specific_string', stringIndex: 2 },
{ id: 'string_3', label: 'String 3', type: 'specific_string', stringIndex: 1 },
{ id: 'string_4', label: 'String 4 (Low)', type: 'specific_string', stringIndex: 0 },
]
},
piano: {
id: 'piano',
displayName: 'Piano',
clefMode: 'grand',
transpose: 0,
showTuning: true,
ranges: [
{ id: 'middle_c', label: 'Middle C Area', type: 'static', min: 53, max: 67 }, // F3 to G4
{ id: 'two_octave', label: 'Two Octaves', type: 'static', min: 48, max: 72 }, // C3 to C5
{ id: 'grand_staff', label: 'Grand Staff Wide', type: 'static', min: 36, max: 84 } // C2 to C6
]
},
voice: {
id: 'voice',
displayName: 'Voice',
clefMode: 'treble', // Default
transpose: 0,
showTuning: false,
ranges: [
{ id: 'soprano', label: 'Soprano (C4-A5)', type: 'static', min: 60, max: 81 },
{ id: 'alto', label: 'Alto (G3-E5)', type: 'static', min: 55, max: 76 },
{
id: 'tenor',
label: 'Tenor (C3-A4) [8vb]',
type: 'static',
min: 48, max: 69,
transpose: 12 // Reads Treble, Sounds octave lower.
},
{
id: 'bass_voice',
label: 'Bass (E2-E4)',
type: 'static',
min: 40, max: 64,
clef: 'bass', // Override to Bass Clef
transpose: 0 // Reads actual pitch on Bass Clef
}
]
},
whistle: {
id: 'whistle',
displayName: 'Whistle',
clefMode: 'treble',
transpose: -12, // Reads 8va (written C4 = sounding C5). E5 (76) sounds -> reads as E4. C8 (108) -> C7.
showTuning: false,
ranges: [
// "starts around E5 for men" -> E5 = 76.
{ id: 'basic', label: 'Basic (E5-E6)', type: 'static', min: 76, max: 88 },
{ id: 'extended', label: 'Extended (E5-E7)', type: 'static', min: 76, max: 100 },
{ id: 'extreme', label: 'Whistle Register (C6-C8)', type: 'static', min: 84, max: 108 }
]
}
};
/**
* Clef + display transpose for rendering, shared by the single-note and
* phrase renderers (identical semantics: sounding midi + transpose = written).
*/
export function resolveClefTranspose(
instrumentDef: InstrumentDefinition,
difficulty: string,
): { clef: ClefMode; transpose: number } {
const rangeDef = instrumentDef.ranges.find(r => r.id === difficulty);
return {
clef: rangeDef?.clef ?? instrumentDef.clefMode,
transpose: rangeDef?.transpose ?? instrumentDef.transpose,
};
}