Table of Contents

Class ModeLibrary

Namespace
Celeritas.Core.Analysis
Assembly
Celeritas.dll

Provides scale masks and mode analysis utilities.

public static class ModeLibrary
Inheritance
ModeLibrary
Inherited Members

Fields

ModeCharacter

Mode characteristics for musical description.

public static readonly Dictionary<Mode, string> ModeCharacter

Field Value

Dictionary<Mode, string>

Methods

ContainsPitch(ModalKey, int)

Check if a pitch class belongs to a scale. A pitchClass outside 0-11 is folded to its pitch class rather than rejected.

public static bool ContainsPitch(ModalKey key, int pitchClass)

Parameters

key ModalKey
pitchClass int

Returns

bool

DetectMode(float[])

Detect the most likely mode from a pitch class distribution.

public static (ModalKey key, float confidence) DetectMode(float[] distribution)

Parameters

distribution float[]

Returns

(ModalKey key, float confidence)

Remarks

The answer is never MajorPentatonic or MinorPentatonic. Each is contained in seven-note modes that are candidates, and the score rewards containing the notes played, so a contained scale can only tie with its container: a pentatonic is reported as a heptatonic mode that contains it, at confidence 0 — the margin that says several modes fit equally. Which mode depends on whether a note stands out. When the pentatonic's own root is the most prominent note, a major pentatonic comes back as Ionian on that root and a minor pentatonic as Aeolian on it. When no note stands out — each of the five played equally — both come back as Ionian, on the one of the three major keys that contain the five notes that the tie-break below points to: for a major pentatonic that is its own tonic, so C major pentatonic is C major and G major pentatonic is G major; for a minor pentatonic it is the relative major, so A minor pentatonic is C major and C minor pentatonic is E flat major.

On each root the mode is the one DetectModeWithRoot(float[], int) names there, so asking again with the detected root gives the same answer; the preferences for a prominent root and for the common modes then decide between roots. When roots still tie — six notes of an octatonic scale fit four half-whole and four whole-half roots exactly, and the tonic, third, fifth, sixth and seventh of a melodic minor also fit the harmonic minor a major third up — the tie is broken by the distribution itself: the root carrying the most weight, then the root nearest above the heaviest pitch class, then the root from which the weights read heaviest-first, and only then the order of the modes. Each of those moves with the music, so a transposed passage is answered in the transposed key with the same mode and the same confidence.

The tie used to go to the lowest-numbered root, and the confidence was measured on it: the same octatonic lick read as C# half-whole in one key, as C half-whole a whole tone higher and as C whole-half, at twice the confidence, a major third higher; and a cell that read as C melodic minor read as C harmonic minor eight semitones up. Confidence is the margin among modes on the chosen root, not "how well it fits": a single note fits many modes, so a fit-based score reported false certainty (#30). The common-mode preference also used to be added to every mode on every root, so it picked between modes on one root as well: a set that fit Lydian a little better was still named Ionian, and the confidence — that margin — then described Lydian's lead over the mode actually named, while DetectModeWithRoot(float[], int) on the same root said Lydian.

Exceptions

ArgumentNullException

distribution is null.

DetectModeWithRoot(IEnumerable<NoteEvent>, int?)

Detect mode from notes with root hint (automatically extracts pitch classes).

public static (ModalKey key, float confidence) DetectModeWithRoot(IEnumerable<NoteEvent> notes, int? rootHint = null)

Parameters

notes IEnumerable<NoteEvent>

Collection of note events. Rests are silence and do not count towards the mode, nor can one be the root.

rootHint int?

Hint for the root note (pitch class). If null, uses the first sounding note's pitch class.

Returns

(ModalKey key, float confidence)

Remarks

A pentatonic is answered as DetectModeWithRoot(float[], int) documents: as a heptatonic mode on the root that contains it, at confidence 0.

Exceptions

ArgumentNullException

notes is null.

ArgumentException

notes holds nothing that sounds — it is empty, or every event in it is a rest.

DetectModeWithRoot(IEnumerable<int>, int)

Detect mode from pitch classes with root hint.

public static (ModalKey key, float confidence) DetectModeWithRoot(IEnumerable<int> pitchClasses, int rootHint)

Parameters

pitchClasses IEnumerable<int>

Collection of pitch classes; values outside 0-11 are folded to their pitch class rather than rejected.

rootHint int

Hint for the root note (pitch class).

Returns

(ModalKey key, float confidence)

Remarks

A pentatonic is answered as DetectModeWithRoot(float[], int) documents: as a heptatonic mode on the hinted root that contains it, at confidence 0.

Exceptions

ArgumentNullException

pitchClasses is null.

DetectModeWithRoot(float[], int)

Detect mode with a hint about which note is the root. More accurate when the first note of a melody/scale is provided.

public static (ModalKey key, float confidence) DetectModeWithRoot(float[] distribution, int rootHint)

Parameters

distribution float[]
rootHint int

Returns

(ModalKey key, float confidence)

Remarks

The answer is never MajorPentatonic or MinorPentatonic. Each is contained in seven-note modes on the same root that are candidates, and the score rewards containing the notes played, so a contained scale can only tie with its container. A major pentatonic on the hinted root comes back as Ionian on that root, and a minor pentatonic as Aeolian on it — the most common of Dorian, Phrygian and Aeolian, which the five notes do not tell apart — both at confidence 0, the margin that says so.

Modes that fit the hinted root equally — a minor pentatonic fits Aeolian, Dorian, Phrygian and the blues scale alike — are settled by the same preference for the common modes that DetectMode(float[]) applies, so the two name the same mode on the same root. The first in the candidate list used to win here: that pentatonic with its root stressed was C Dorian from this overload and C minor from DetectMode(float[]), so the two could disagree about the very root one of them had just detected.

Exceptions

ArgumentNullException

distribution is null.

GetCharacteristicNotes(Mode)

Get the characteristic and avoid notes of a mode, as semitones above its root.

public static (int[] characteristic, int[] avoid) GetCharacteristicNotes(Mode mode)

Parameters

mode Mode

Returns

(int[] characteristic, int[] avoid)

Remarks

A characteristic note is the degree that tells this mode from the parallel major or minor: the raised 6th of Dorian, the lowered 2nd of Phrygian, the raised 4th of Lydian. Ionian and Aeolian have none, because they are what the others are compared against, and the list is empty for the scales that are not compared this way at all — the pentatonics, the blues scale, and the symmetrical whole-tone and diminished scales.

An avoid note is a degree a semitone above a note of the mode's own tonic seventh chord: it sounds against that chord rather than with it, so it is passed through rather than rested on. This half of the answer used to be empty for all nineteen modes, so a caller asking the question got nothing back for it whatever the mode. It is worked out from the scale rather than listed, which means a mode added later answers too, and it comes out where the textbooks put it: the 4th in Ionian and Mixolydian, the flat 6th in Aeolian, the flat 2nd in Locrian — and nothing at all in Lydian and Dorian, which is exactly why those two are the modes a melody can move through freely.

Exceptions

ArgumentOutOfRangeException

mode is not a defined Mode value.

GetDiatonicChordQualities(Mode)

Get common chord types built on each scale degree for a mode.

public static ChordQuality[] GetDiatonicChordQualities(Mode mode)

Parameters

mode Mode

Returns

ChordQuality[]

Exceptions

ArgumentOutOfRangeException

mode is not a defined Mode value.

GetIntervals(Mode)

Get intervals for a mode.

public static ReadOnlySpan<int> GetIntervals(Mode mode)

Parameters

mode Mode

Returns

ReadOnlySpan<int>

Exceptions

ArgumentOutOfRangeException

mode is not a defined Mode value.

GetScaleMask(ModalKey)

Get the 12-bit mask for a mode rooted on a given pitch.

public static ushort GetScaleMask(ModalKey key)

Parameters

key ModalKey

Returns

ushort

GetScaleNoteNames(ModalKey)

Get note names for a scale.

public static string[] GetScaleNoteNames(ModalKey key)

Parameters

key ModalKey

Returns

string[]

Remarks

A heptatonic scale uses each of the seven letters A-G exactly once, so its notes are spelled out from the root's letter rather than read off the table of pitch-class names. Reading them off the table gave F sharp Ionian as "F# G# A# B C# D# F" — an F sharp and an F natural in one scale and no E at all, so that where the leading tone belongs a reader sees a diminished octave. Ninety-two of the hundred and fifty-six heptatonic mode and root pairs came back spelled that way.

A root that has a letter of its own keeps it whenever the scale can be written from that letter: F Locrian is F Gb Ab Bb Cb Db Eb, not E# Locrian, though both need six accidentals — a mode is named by its final, and a chart of F Locrian that opens on E sharp tells the player the tonic is a raised E. Where a root sounds the same as two letters, the spelling that needs the fewest accidentals wins, which is what a musician writes: the Ionian mode on pitch class 8 is A flat major, not G sharp major with a double-sharped seventh. Ties between those go to the earlier letter, so pitch class 6 is spelled F sharp rather than G flat. The one heptatonic scale whose natural root cannot be written is F Altered, whose third degree would be B double-flat; it is spelled from E sharp.

A scale that is not heptatonic — the pentatonics, the blues scale, whole tone, the diminished scales — has no letter-per-degree to keep, and its notes are named from the pitch-class table. So is a heptatonic scale that no spelling can write within single accidentals, since this library's note names carry at most one.

GetScaleNotes(ModalKey)

Get scale notes as pitch classes.

public static int[] GetScaleNotes(ModalKey key)

Parameters

key ModalKey

Returns

int[]