Welcome to Mankunku

Jazz ear training — call and response. Pick your instrument to get started.

API Reference: Music Theory

Modules for scales, chords, keys, intervals, notation, and transposition.

Source: src/lib/music/


intervals.ts

MIDI and pitch math utilities. All MIDI note numbers are concert pitch.

Note conversion

FunctionSignatureDescription
midiToPitchClass(midi) → numberPitch class index 0–11
midiToOctave(midi) → numberOctave number (C4 = octave 4)
pitchClassToMidi(pc, octave) → numberPitch class + octave to MIDI
midiToNoteName(midi) → stringe.g. 60 → 'C4', 58 → 'Bb3'
noteNameToMidi(name) → numbere.g. 'C4' → 60, 'Bb3' → 58

noteNameToMidi handles sharps by converting to flat equivalents (e.g. C# → Db).

Frequency conversion

FunctionSignatureDescription
frequencyToMidi(freq) → numberFractional MIDI: 12 * log2(freq / 440) + 69
midiToFrequency(midi) → numberHz: 440 * 2^((midi - 69) / 12)
quantizePitch(fractionalMidi) → { midi, cents }Round to nearest integer MIDI + cents deviation

Interval measurement

FunctionSignatureDescription
semitoneDistance(from, to) → numberSigned interval
intervalSize(a, b) → numberAbsolute interval (always positive)

Fraction arithmetic

Fractions [numerator, denominator] represent note durations and offsets without floating-point error.

FunctionSignatureDescription
fractionToFloat(f) → numberf[0] / f[1]
addFractions(a, b) → FractionAddition with GCD reduction
subtractFractions(a, b) → FractionSubtraction with GCD reduction
multiplyFraction(f, scalar) → FractionMultiply by integer scalar
compareFractions(a, b) → number-1 / 0 / 1 sort comparator
gcd(a, b) → numberGreatest common divisor (used internally by the fraction helpers)

scales.ts

Complete scale catalog — 35 scales across 7 families.

SCALE_CATALOG: ScaleDefinition[]

FamilyCountExamples
major7Ionian, Dorian, Mixolydian, Locrian
melodic-minor7Melodic Minor, Lydian Dominant, Altered
harmonic-minor7Harmonic Minor, Phrygian Dominant
symmetric4Whole-Half Diminished, Whole Tone, Chromatic
pentatonic2Minor, Major
blues2Minor, Major
bebop4Dominant, Dorian, Major, Melodic Minor

Each ScaleDefinition contains:

  • id — Unique identifier (e.g. 'major.dorian')
  • intervals — Semitone steps between consecutive degrees (must sum to 12)
  • degrees — Degree labels relative to major scale
  • chordApplications — Applicable chord qualities
  • targetNotes / avoidNotes — Improvisation guidance

Query functions

FunctionSignatureDescription
getScale(id) → ScaleDefinition | undefinedO(1) lookup by ID
getScalesByFamily(family) → ScaleDefinition[]All scales in a family
getScalesForChord(quality) → ScaleDefinition[]Scales applicable to a chord quality
getMvpScales() → ScaleDefinition[]20 scales selected for MVP

MVP_SCALE_IDS: string[]

20 scale IDs selected for the MVP — 12 must-have + 8 should-have.


chords.ts

Chord definitions and utilities.

CHORD_DEFINITIONS: Record

18 chord qualities with intervals and display symbols:

QualityNameIntervalsSymbol
maj7Major 7th[0, 4, 7, 11]maj7
min7Minor 7th[0, 3, 7, 10]m7
7Dominant 7th[0, 4, 7, 10]7
min7b5Half-Diminished[0, 3, 6, 10]m7b5
dim7Diminished 7th[0, 3, 6, 9]dim7
7altAltered Dominant[0, 4, 6, 10]7alt
...(18 total)......

chordTones(rootMidi, quality): number[]

Get chord tones as MIDI notes from a root MIDI note.

chordSymbol(root, quality): string

Get display symbol (e.g. chordSymbol('D', 'min7')'Dm7').


keys.ts

Key signatures, circle of fifths, and scale realization.

keySignatureAccidentals(key): number

Sharps (positive) or flats (negative) for a major key. E.g. 'Bb' → -2, 'D' → 2.

circleOfFifths(): PitchClass[]

Returns ['C', 'G', 'D', 'A', 'E', 'B', 'Gb', 'Db', 'Ab', 'Eb', 'Bb', 'F'].

circleOfFourths(): PitchClass[]

Reverse of circleOfFifths() (without duplicating the starting note).

getNextKeyInCircle(current, direction?): PitchClass

Return the next key around the circle of fourths. direction is 1 (fourths, default) or -1 (fifths).

getKeyAtIndex(index: number): PitchClass

Return the key at the given position in the circle of fourths. The index wraps around (negative values and values ≥ 12 are normalized via modulo).

relativeMajor(minorKey): PitchClass

relativeMinor(majorKey): PitchClass

realizeScale(root, intervals): number[]

Returns pitch class indices (0–11) for a scale.

realizeScaleMidi(root, intervals, lowMidi, highMidi): number[]

Returns all MIDI notes in a scale within a range.

scalePitchClasses(root, intervals): PitchClass[]

Returns all pitch classes in a scale.


notation.ts

ABC notation generation from Phrase data. Used by NotationDisplay.svelte to render sheet music via abcjs.

phraseToAbc(phrase, instrument?, defaultLength?): string

Generate an ABC notation string.

ParameterTypeDefaultDescription
phrasePhraseThe phrase to render
instrumentInstrumentConfigIf provided, transposes to written pitch
defaultLength[number, number][1, 8]ABC L: field (eighth note)

Output includes:

  • ABC header: X:, T:, M:, L:, K: fields
  • Notes with proper ABC octave conventions (uppercase C4, lowercase c5, apostrophes/commas)
  • Key-signature-aware accidentals: Notes matching the key signature (e.g., F# in D major) omit the accidental symbol. Natural signs (=) are emitted when a note cancels a key signature accidental. Chromatic alterations outside the key signature display as before.
  • Duration modifiers relative to L: value
  • Final barline |]

Uses KEY_SIG_ACCIDENTALS lookup table (maps each key to its altered pitch classes) to determine which accidentals are implicit vs. explicit.

displayPitchClass(pc, keyContext): string

Return a pitch class name spelled for a given key context. Only special-cases F#Gb when keyContext is a flat key; all other pitch classes pass through unchanged. Used by UI chips that show the current scale's notes.

midiToDisplayName(midi, useFlats?): string

Convert MIDI to display name (e.g. 60 → 'C4', 58 → 'Bb3'). Defaults to flats.


transposition.ts

Concert/written pitch conversion for transposing instruments.

concertToWritten(concertMidi, instrument): number

Concert pitch → written pitch. written = concert + transpositionSemitones.

writtenToConcert(writtenMidi, instrument): number

Written pitch → concert pitch. concert = written - transpositionSemitones.

concertKeyToWritten(concertKey, instrument): PitchClass

Transpose a key name (e.g. C concert → D for Bb instruments).

writtenKeyToConcert(writtenKey, instrument): PitchClass

Reverse key transposition.

transpose(midi, semitones): number

Simple MIDI transposition.

transposePitchClass(pc, semitones): PitchClass

Transpose a pitch class by semitones.

pitchClassInterval(from, to): number

Ascending interval in semitones between two pitch classes.

isInRange(midi, instrument): boolean

Check if a MIDI note is within an instrument's concert range.


key-ordering.ts

Staged 12-key orderings for lick practice. The order a lick cycles through the 12 keys is chosen from a pool of "stages" unlocked at the current tempo.

Ordering generators

FunctionSignatureDescription
circleOfFifthsFrom(start) → PitchClass[]Rotate the standard circle of fifths so start is first
chromaticFrom(start) → PitchClass[]Semitone-step ordering starting on start
wholeTonePairFrom(start) → PitchClass[]The six keys of the whole-tone scale containing start, then the six keys of the complementary whole-tone scale
shufflePitchClasses(rng?) → PitchClass[]Fisher–Yates shuffle, RNG-parameterizable for deterministic tests

KeyOrderingStage type

export type KeyOrderingStage = 0 | 1 | 2 | 3 | 4;

unlockedStages(tempo, minBpm): KeyOrderingStage[]

Return the stages unlocked at tempo:

  • Stage 0 always unlocked — circle of fifths from the player's written C.
  • Stages 1 and 2 unlock linearly between minBpm and 150 BPM — circle of fifths / chromatic from a random root.
  • Stages 3 and 4 unlock together at 150 BPM — whole-tone pair and full shuffle.

PlanLickKeysArgs interface

interface PlanLickKeysArgs {
  tempo: number;
  minBpm: number;
  instrument: InstrumentConfig;   // resolves "written C" for Stage 0
  rng?: () => number;
}

planLickKeys(args): PitchClass[]

Pick a stage uniformly at random from unlockedStages(tempo, minBpm), then draw that stage's 12-key ordering. The returned array is always a permutation of all 12 pitch classes.