ktsu.Semantics.Music 5.12.1

Prefix Reserved
dotnet add package ktsu.Semantics.Music --version 5.12.1
                    
NuGet\Install-Package ktsu.Semantics.Music -Version 5.12.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ktsu.Semantics.Music" Version="5.12.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ktsu.Semantics.Music" Version="5.12.1" />
                    
Directory.Packages.props
<PackageReference Include="ktsu.Semantics.Music" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ktsu.Semantics.Music --version 5.12.1
                    
#r "nuget: ktsu.Semantics.Music, 5.12.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ktsu.Semantics.Music@5.12.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ktsu.Semantics.Music&version=5.12.1
                    
Install as a Cake Addin
#tool nuget:?package=ktsu.Semantics.Music&version=5.12.1
                    
Install as a Cake Tool

ktsu.Semantics.Music

Immutable, validated musical value types plus a harmonic and structural analysis layer, all pure logic with no I/O.

License NuGet Version NuGet Version NuGet Downloads GitHub commit activity GitHub contributors GitHub Actions Workflow Status

ktsu.Semantics.Music is one package in the ktsu.Semantics family. Start at the root README for the family overview.

Introduction

ktsu.Semantics.Music models music theory as immutable value types. Pitches, intervals, scales, modes, chords, keys, rational durations, and time signatures are all first-class, validate on creation, and return new instances on every operation. The pitch convention is MIDI 60 = C4, and equal temperament is anchored at A4 = 440 Hz.

Above the single-event types sits an analysis layer that models harmony nested inside structure. A Progression is an ordered chord sequence with bar-based harmonic rhythm that computes roman numerals, functional roles, cadences, an inferred key, and chromatic classifications. Sections group progressions, an Arrangement orders them into a piece, and Form names the structural pattern.

Features

  • Pitch and interval types: PitchClass, Pitch (MIDI, with name and frequency conversion), Interval (signed semitones, cents, folding).
  • Scales and modes: Mode with roughly 29 presets (diatonic, jazz, symmetric, pentatonic, blues), Scale rooting a mode at a pitch class, with Contains and DegreeOf.
  • Chord-symbol parsing: Chord.Parse handles triads, sixths, sevenths (including m7b5, the half-diminished ø7, mmaj7, and a flat fifth over a major third such as 7b5 and maj7b5), extensions and altered tensions (9/11/13, b9/#9/#11/b13), suspensions, power chords, omissions (no3/no5), the six-nine idiom (C6/9), and slash bass.
  • Chord realization: ChordTones() and Voice(octave) / Voice(octave, inversion), plus Transpose.
  • Roman-numeral analysis both directions: Key.RomanNumeralOf(chord) and Key.ChordFromRomanNumeral(numeral).
  • Rhythm and real time: rational Duration, TimeSignature, Tempo, and Note / Rest / ChordEvent events that convert to seconds.
  • Analysis layer: Progression (roman numerals, functions, cadences, key inference, chromatic chords), Section, Arrangement, and Form with named-form recognition.

Installation

Package Manager Console

Install-Package ktsu.Semantics.Music

.NET CLI

dotnet add package ktsu.Semantics.Music

Package Reference

<PackageReference Include="ktsu.Semantics.Music" Version="x.y.z" />

Usage Examples

Pitches, intervals, scales

using ktsu.Semantics.Music;

Pitch middleC = Pitch.Parse("C4");              // MIDI 60
Pitch cSharp4 = Pitch.Create(NoteLetter.C, Accidental.Sharp, octave: 4); // type-safe, no parsing
Pitch g4 = middleC.Transpose(7);                // a perfect fifth up
Interval fifth = Interval.Between(middleC, g4); // +7 semitones
double hz = Pitch.Parse("A4").FrequencyHz;      // 440.0

Scale dDorian = Scale.Create(PitchClass.Create(2), Mode.Dorian);
bool hasF = dDorian.Contains(PitchClass.Create(5));   // true

Chord parsing, voicing, and rhythm

using ktsu.Semantics.Music;

Chord cmaj7 = Chord.Parse("Cmaj7");
IReadOnlyList<Pitch> voicing = cmaj7.Voice(octave: 4);   // C4, E4, G4, B4
IReadOnlyList<int> tones = Chord.Parse("Cmaj7#11").ChordTones();
Chord up = cmaj7.Transpose(2);                           // Dmaj7

Tempo tempo = Tempo.Create(120.0);                       // quarter = 120 bpm
double halfNoteSeconds = tempo.Seconds(Duration.Half);   // 1.0 s
Note a4 = Note.Create(Pitch.Parse("A4"), Duration.Quarter, Velocity.Forte);
double noteSeconds = a4.Seconds(tempo);                  // 0.5 s

Chord symbols use one grammar for parsing and canonical formatting:

symbol      = root body [ "/" bass ] EOF
root, bass  = letter { accidental }
accidental  = "#" | "b" | "♯" | "♭"
body        = [ quality ] [ extension ] [ suspension ] { modifier }
quality     = minor [ "aug" | "+" ] | "dim" | "°" | "ø" | "aug" | "+"
            | majorWord
minor       = "m" | "min" | "-"
majorWord   = "maj" | "Maj" | "M" | "Δ"
extension   = [ majorWord ] number | number "M" | "Δ"
            | "6" [ "/9" | "9" ] | "b6" | "♭6" | "5"
number      = "7" | "9" | "11" | "13"
suspension  = "sus2" | "sus4" | "sus"
modifier    = alteration | add | omit | "b6" | "♭6"
            | "(" modifier { [ "," ] modifier } ")"
alteration  = ("b" | "♭" | "-") ( "5" | "9" | "13" )
            | ("#" | "♯" | "+") ( "5" | "9" | "11" )
add         = "add" ( "9" | "11" | "13" | "6" | "b6" )
omit        = "no3" | "no5"

The grammar consumes the complete symbol and does not permit whitespace. A numbered extension implies a seventh and its natural lower stack tones unless an alteration replaces that degree; addN adds only that tone. M/maj before an extension or an M suffix on its number marks a major seventh. A small compatibility reader also accepts previously printed forms such as C79, Cmaj79, Csus47, and C6add9; a bare + after a numbered chord remains an augmentation mark. ToString() emits the canonical form, for example C13b9, C7sus4, C6/9, and C(#11).

Roman numerals, both directions

using ktsu.Semantics.Music;

Key cMajor = Key.Create(PitchClass.Create(0), Mode.Major);

string label = cMajor.RomanNumeralOf(Chord.Parse("Dm7"));  // "ii7"
Chord five = cMajor.ChordFromRomanNumeral("V7");           // G7

Analysis: progressions, cadences, key inference, and form

using ktsu.Semantics.Music;

// Chart style: a leading time signature, bars separated by "|", and a beat slash "/"
// extends the preceding chord by one beat (so "Cmaj7 / / /" is a whole bar of 4/4).
Progression prog = Progression.Parse("4/4  Dm7 / / / | G7 / / / | Cmaj7 / / / | Cmaj7 / / /");

Key key = prog.InferKey()!;                                   // C major (quality-weighted fit)
IReadOnlyList<string> roman = prog.RomanNumerals(key);        // ii7, V7, Imaj7, Imaj7
IReadOnlyList<HarmonicFunction> fns = prog.Functions(key);    // Predominant, Dominant, Tonic, Tonic
IReadOnlyList<CadenceInstance> cadences = prog.Cadences(key); // Authentic at the resolution

// Chromatic analysis: secondary dominants, borrowed chords, Neapolitan
IReadOnlyList<ChromaticAnalysis> chromatic =
    Progression.Parse("4/4  C / / / | A7 / / / | Dm / / / | G7 / / /").ChromaticChords(key); // A7 -> secondary dominant

// Structure: sections -> arrangement -> form
Progression verse  = Progression.Parse("4/4  C / / / | G / / / | Am / / / | F / / /");
Progression bridge = Progression.Parse("4/4  F / / / | C / / / | G / / / | C / / /");
Arrangement song = Arrangement.Create(key,
[
    Section.Create(SectionType.Verse,  verse,  "Verse 1"),
    Section.Create(SectionType.Verse,  verse,  "Verse 2"),
    Section.Create(SectionType.Bridge, bridge, "Bridge"),
    Section.Create(SectionType.Verse,  verse,  "Verse 3"),
]);
Form form = song.Form;   // Pattern "AABA", Name NamedForm.ThirtyTwoBarAABA

Type-safe construction and round-trippable text

using ktsu.Semantics.Music;

// Compiler-enforced construction — no strings to mistype
Pitch p = Pitch.Create(NoteLetter.C, Accidental.Sharp, octave: 4); // C#4

// Every in-scope type has a canonical ToString() and a Parse/TryParse that inverts it
Chord c = Chord.Parse("Cmaj7");
Chord same = Chord.Parse(c.ToString());   // c == same

// Progressions read like a lead sheet and round-trip through their chart form
Progression prog = Progression.Parse("4/4  Dm7 / G7 / | Cmaj7 / / /");
Progression reparsed = Progression.Parse(prog.ToString());   // prog == reparsed

// TryParse never throws; Parse throws FormatException on malformed text
bool ok = Interval.TryParse("-5", out Interval? descendingFourth);

API Reference

Core value types

Type Description Key factories / members
PitchClass One of twelve pitch classes, folded to 0..11. Create(int), Create(NoteLetter, Accidental), Parse/TryParse, Value, Name
Pitch MIDI pitch 0..127 (60 = C4). Create(int), Create(NoteLetter, Accidental, int), Parse/TryParse, FromFrequency(double), Transpose(int), FrequencyHz, Octave
Interval Signed interval in semitones. Create(int), Between(Pitch, Pitch), Parse/TryParse, Semitones, Cents, Folded
Mode Scale shape by semitone offsets. Parse/TryParse, presets (Major, Dorian, HarmonicMinor, WholeTone, MajorPentatonic, ...), Intervals
Scale A mode rooted at a pitch class. Create(PitchClass, Mode), Parse/TryParse, Contains, DegreeOf, Transpose
Chord Chord parsed from a symbol. Parse/TryParse, ChordTones(), Voice(octave), Voice(octave, inversion), Transpose
Key Tonic in a mode, resolves function. Create(PitchClass, Mode), Parse/TryParse, RomanNumeralOf(Chord), ChordFromRomanNumeral(string), FunctionOf, Scale
Duration Exact rational fraction of a whole note. Create(int, int), Parse/TryParse, presets (Whole..Sixteenth), Dotted(), Add, Multiply, AsWholeNotes
TimeSignature Bar and beat lengths. Create(int, int), Parse/TryParse, BarDuration, BeatDuration
Note / Rest / ChordEvent Timed musical events (IMusicalEvent). Create(...), Parse/TryParse, Duration, Seconds(Tempo)
Velocity MIDI velocity 0..127. Create(int), Parse/TryParse, presets (Piano..Fortissimo)
Tempo Beats per minute with a beat unit. Create(double), Parse/TryParse, Seconds(Duration), SecondsPerBeat

Analysis layer

Type Description Key members
Progression Chord sequence with bar-based harmonic rhythm. Parse(string), Create(...), RomanNumerals(Key), Functions(Key), Cadences(Key), InferKey(), InferKeys(), ChromaticChords(Key)
Section Labeled structural unit. Create(SectionType, Progression, label?, key?), Parse/TryParse, IsSameStructure(Section)
Arrangement Sections in performance order. Create(Key, IEnumerable<Section>), Parse/TryParse, Form, TotalBars
Form Structural pattern and its name. Of(Arrangement), Parse/TryParse, Pattern, Name
HarmonicFunction enum: Tonic, Predominant, Dominant, Chromatic.
CadenceInstance A cadence at a resolution index. Index, Type (Cadence enum: Authentic, Plagal, Half, Deceptive)
ChromaticAnalysis A non-diatonic chord classification. Index, Kind (ChromaticKind), Detail
NamedForm enum: ThirtyTwoBarAABA, TwelveBarBlues, Binary, Ternary, Rondo, Strophic, ...

InferKey() returns Key? (null for all-chromatic input), while InferKeys() returns the full ranked IReadOnlyList<KeyMatch>. See the complete library guide for a wider tour.

Contributing

Contributions are welcome! Feel free to open issues or submit pull requests.

License

This project is licensed under the MIT License. See the LICENSE.md file for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.12.1 305 10/12/2026
5.12.0 125 10/11/2026
5.11.6 105 10/10/2026
5.11.5 107 10/9/2026
5.11.4 103 10/9/2026
5.11.3 168 10/8/2026
5.11.2 134 10/6/2026
5.11.1 107 10/6/2026
5.11.1-pre.1 71 10/5/2026
5.11.0 150 10/2/2026
5.10.0 132 9/30/2026
5.9.0 123 9/29/2026
5.8.5 131 9/29/2026
5.8.4 120 9/29/2026
5.8.3 132 9/28/2026
5.8.2 138 9/28/2026
5.8.1 129 9/28/2026
5.8.0 138 9/25/2026
5.7.0 133 9/24/2026
5.6.0 127 9/23/2026
Loading failed

## v5.12.1 (patch)

Changes since v5.12.0:

- Name secondary dominant targets by the mode's own triad [patch] ([@Claude](https://github.com/Claude))
- Escape section labels so ToString round-trips through Parse [patch] ([@Claude](https://github.com/Claude))
- Stop Duration arithmetic from wrapping silently on int overflow [patch] ([@Claude](https://github.com/Claude))