Pitch.fromString constructor
Pitch.fromString(
- String notation
Constructs a Pitch from a string (e.g. "C4", "F#5", "Bb3", "C-1").
Accidentals are repeatable ("C##4", "Ebb3", "C###4") and the octave
may be negative, so the lowest MIDI note "C-1" round-trips correctly.
Implementation
factory Pitch.fromString(String notation) {
if (notation.isEmpty) {
throw ArgumentError('Notation cannot be empty');
}
// Extract the base note (first letter)
final step = notation[0].toUpperCase();
if (!isValidStep(step)) {
throw ArgumentError('Invalid note step: $step');
}
// Find where the octave number begins
int octaveStart = notation.length;
double alter = 0.0;
// Process accidentals; stop at the first octave character
// ('-' introduces a negative octave such as "C-1").
for (int i = 1; i < notation.length; i++) {
final char = notation[i];
if (char == '#') {
alter += 1.0;
} else if (char == 'b') {
alter -= 1.0;
} else if (char == '-' ||
(char.codeUnitAt(0) >= 0x30 && char.codeUnitAt(0) <= 0x39)) {
octaveStart = i;
break;
} else {
throw ArgumentError('Invalid character "$char" in notation: $notation');
}
}
// Extract the octave
if (octaveStart >= notation.length) {
throw ArgumentError('Missing octave number in notation: $notation');
}
final octaveString = notation.substring(octaveStart);
final octave = int.tryParse(octaveString);
if (octave == null) {
throw ArgumentError('Invalid octave number: $octaveString');
}
return Pitch.validated(
step: step,
octave: octave,
alter: alter,
accidentalType: _accidentalTypeForAlter(alter),
);
}