Class MusicNotation
Parser for musical notation (scientific pitch notation) Supports: C4, D#5, Bb3, etc.
public static class MusicNotation
- Inheritance
-
MusicNotation
- Inherited Members
Fields
RestPitch
Special pitch value indicating a rest (silence).
public const int RestPitch = -1
Field Value
Remarks
This value is reserved across the library: a note event carrying it is silence, not a note. Analysis ignores it — it contributes no pitch class, no onset and no duration — and the MIDI and MusicXML writers leave a gap where it falls rather than writing a note. Transpose(NoteBuffer, int) leaves it alone for the same reason.
Methods
FormatDuration(Rational, bool, bool)
Format duration to string
public static string FormatDuration(Rational duration, bool useDot = true, bool useLetters = false)
Parameters
durationRationalDuration as Rational
useDotboolEnable dotted note notation (e.g., 3/8 -> "4.")
useLettersboolUse letter notation (q, h, e, w) instead of numbers
Returns
- string
Formatted duration string
FormatNoteSequence(ReadOnlySpan<NoteEvent>, bool, bool, bool)
Format note sequence to string with chord grouping
public static string FormatNoteSequence(ReadOnlySpan<NoteEvent> sequence, bool useDot = true, bool useLetters = false, bool groupChords = true)
Parameters
sequenceReadOnlySpan<NoteEvent>Sequence of note events
useDotboolEnable dotted note notation
useLettersboolUse letter notation (q, h, e, w) instead of numbers
groupChordsboolGroup simultaneous notes as chords [C4 E4 G4]/4
Returns
- string
Formatted sequence (e.g., "C4/4 [E4 G4]/4 R/2" or "C4:q [E4 G4]:q R:h")
FormatWithDirectives(ReadOnlySpan<NoteEvent>, ReadOnlySpan<NotationDirective>, bool, bool, bool)
Format notes and directives together in timeline order.
public static string FormatWithDirectives(ReadOnlySpan<NoteEvent> notes, ReadOnlySpan<NotationDirective> directives, bool useDot = true, bool useLetters = false, bool groupChords = true)
Parameters
notesReadOnlySpan<NoteEvent>directivesReadOnlySpan<NotationDirective>useDotbooluseLettersboolgroupChordsbool
Returns
Remarks
The notes go through the same voice separation as FormatNoteSequence(ReadOnlySpan<NoteEvent>, bool, bool, bool). This walked them as one melodic line instead, and so carried the three faults that method was rewritten to lose: a gap between notes vanished, notes struck together but held for different lengths became a succession, and so did overlapping notes. Half of a small set of test passages came back as different music, and none of them had a directive in it.
A directive is not a sound, so the notation has nowhere to put one but inside a voice. They ride in the first, whose cursor is the timeline's, and read back at the same times. Where a directive's time falls inside a note, the note is written as tied pieces with the directive between them; inside a rest, as two rests. Written at the next note boundary instead, as they were, directives read back later than they were given — in 2297 of 3000 random passages at least one moved. A chord in that voice gives way to a directive inside it, since the notation ties notes and not chords: one of its notes stays there, cut and tied, and the others move to a voice of their own.
With no notes at all, the directives are still written at their times, carried by rests: written bare, as they were, every one of them read back at time zero.
Exceptions
- ArgumentNullException
An element of
directivesis null.
Parse(string, bool)
Parse music notation into note events. Supports: notes, chords, rests, ties, time signatures, measures, polyphony. Examples: "C4/4 E4/4 G4/2", "[C4 E4 G4]/4", "C4/4~ C4/4", "4/4: C4/4 E4/4 | G4/2"
public static NoteEvent[] Parse(string input, bool validateMeasures = false)
Parameters
inputstringMusic notation string
validateMeasuresboolValidate measure durations against time signature
Returns
- NoteEvent[]
Array of note events with timing information
Exceptions
- ArgumentNullException
inputis null.- ArgumentException
inputis not valid notation: a syntax error, an unknown pitch or duration, or a pitch outside the MIDI range 0-127.
ParseDuration(string)
Parse duration string. Supports: any note value written as its denominator — 1 (whole), 2 (half), 4 (quarter), 8, 16, 32, 64, and the tuplet values like 3, 6 and 12 w/whole, h/half, q/quarter, e/eighth, s/16th, t/32nd Dotted: 4. (dotted quarter = 3/8), 2. (dotted half = 3/4)
public static Rational ParseDuration(string duration)
Parameters
durationstring
Returns
Remarks
The bare number is the same vocabulary the notation grammar accepts after the slash, so everything FormatDuration(Rational, bool, bool) writes for a duration of the form 1/n reads back here. It used to stop at 32 and reject the rest: a 64th note was written "64" and then refused, and so was every tuplet value the grammar reads happily inside a note.
Exceptions
- ArgumentNullException
durationis null.- ArgumentException
durationis not a note value — including the "3/8" form, which names a duration the notation writes as a dotted note ("4.") rather than as a fraction.
ParseFull(string, bool)
Parse music notation into a full result: notes plus directives (tempo, dynamics, sections, parts) and the leading time signature. Use this when you need more than the note events Parse(string, bool) returns.
public static ParseResult ParseFull(string input, bool validateMeasures = false)
Parameters
inputstringMusic notation string
validateMeasuresboolValidate measure durations against time signature
Returns
- ParseResult
The parsed notes together with directives and the leading time signature. Errors is always empty — a parse error throws instead.
Exceptions
- ArgumentNullException
inputis null.- ArgumentException
inputis not valid notation: a syntax error, an unknown pitch or duration, or a pitch outside the MIDI range 0-127.
ParseKey(string)
Parse key signature from various formats Supports: "C", "Cm", "C minor", "c", "C#", "C# major", "Db minor" The whole string must be consumed: a pitch class, then at most one mode token. No token means major; the word forms "min"/"minor" and "maj"/"major" are case-insensitive and may follow a single space. A lone 'm'/'M' must attach directly to the pitch and is case-significant, so "Em" is E minor and "EM" is E major (changed in 0.10.0). Trailing text is rejected — "Gm7", "dorian" and "Cat" are all invalid.
public static KeySignature ParseKey(string keyString)
Parameters
keyStringstring
Returns
Exceptions
- ArgumentNullException
keyStringis null.- ArgumentException
keyStringis blank or is not a key signature.
ParseNote(string)
Parse scientific pitch notation to MIDI pitch number Examples: "C4" -> 60, "A4" -> 69, "C#5" -> 73, "Db3" -> 49
public static int ParseNote(string notation)
Parameters
notationstring
Returns
ToNotation(int, bool)
Convert MIDI pitch number to scientific notation Examples: 60 -> "C4", 69 -> "A4", 73 -> "C#5"
public static string ToNotation(int midiPitch, bool preferSharps = true)
Parameters
Returns
TryParseNote(ReadOnlySpan<char>, out int)
Try-parse scientific pitch notation to MIDI pitch number. Accepts: MIDI numbers (0-127), C4, D#5, Db3, Bb3, and Unicode accidentals (♯, ♭).
public static bool TryParseNote(ReadOnlySpan<char> notation, out int midi)
Parameters
notationReadOnlySpan<char>midiint