@libraz/libcantus 0.9.3 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/analyze/index.cjs +39 -1947
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +197 -37
- package/dist/analyze/index.d.ts +197 -37
- package/dist/analyze/index.js +19 -8
- package/dist/chunk-36N73KZ3.cjs +246 -0
- package/dist/chunk-36N73KZ3.cjs.map +1 -0
- package/dist/chunk-4HLLZPXT.cjs +3077 -0
- package/dist/chunk-4HLLZPXT.cjs.map +1 -0
- package/dist/chunk-7MGZ7D62.cjs +498 -0
- package/dist/chunk-7MGZ7D62.cjs.map +1 -0
- package/dist/{chunk-4MHA432G.js → chunk-7NKDPF74.js} +403 -180
- package/dist/chunk-7NKDPF74.js.map +1 -0
- package/dist/chunk-CAN76NCU.cjs +679 -0
- package/dist/chunk-CAN76NCU.cjs.map +1 -0
- package/dist/{chunk-MIWO425M.js → chunk-D2FAJBYL.js} +101 -34
- package/dist/chunk-D2FAJBYL.js.map +1 -0
- package/dist/{chunk-SGU7SPLK.js → chunk-EHVEBWM5.js} +1056 -531
- package/dist/chunk-EHVEBWM5.js.map +1 -0
- package/dist/chunk-FCANXBAT.cjs +30 -0
- package/dist/chunk-FCANXBAT.cjs.map +1 -0
- package/dist/chunk-FNDWXRRI.cjs +479 -0
- package/dist/chunk-FNDWXRRI.cjs.map +1 -0
- package/dist/{chunk-IT2O4XFE.js → chunk-GQSGS2N4.js} +43 -24
- package/dist/chunk-GQSGS2N4.js.map +1 -0
- package/dist/{chunk-62QZKCJQ.js → chunk-HKGYCQ34.js} +10 -6
- package/dist/chunk-HKGYCQ34.js.map +1 -0
- package/dist/{chunk-AKLYPWIN.js → chunk-I24MV65U.js} +29 -6
- package/dist/chunk-I24MV65U.js.map +1 -0
- package/dist/{chunk-CHMXELDS.js → chunk-KMHOICIY.js} +311 -181
- package/dist/chunk-KMHOICIY.js.map +1 -0
- package/dist/chunk-LW53AHQU.cjs +1117 -0
- package/dist/chunk-LW53AHQU.cjs.map +1 -0
- package/dist/{chunk-2ZWMSJH6.js → chunk-NKIBQ6PT.js} +2 -2
- package/dist/chunk-NKIBQ6PT.js.map +1 -0
- package/dist/chunk-NP4NA2FB.cjs +106 -0
- package/dist/chunk-NP4NA2FB.cjs.map +1 -0
- package/dist/chunk-NVE34YGZ.cjs +1449 -0
- package/dist/chunk-NVE34YGZ.cjs.map +1 -0
- package/dist/{chunk-EH6EM37U.js → chunk-NYYWMV2C.js} +61 -49
- package/dist/chunk-NYYWMV2C.js.map +1 -0
- package/dist/{chunk-GOAW4VYL.js → chunk-Q2XUP227.js} +243 -117
- package/dist/chunk-Q2XUP227.js.map +1 -0
- package/dist/chunk-Q6OP4U43.cjs +327 -0
- package/dist/chunk-Q6OP4U43.cjs.map +1 -0
- package/dist/chunk-RC6GBMCD.cjs +845 -0
- package/dist/chunk-RC6GBMCD.cjs.map +1 -0
- package/dist/{chunk-C5XYKUVG.js → chunk-RK35RIN7.js} +370 -157
- package/dist/chunk-RK35RIN7.js.map +1 -0
- package/dist/chunk-RUMU3UA6.cjs +53 -0
- package/dist/chunk-RUMU3UA6.cjs.map +1 -0
- package/dist/chunk-T64C7ZD7.cjs +1 -0
- package/dist/chunk-T64C7ZD7.cjs.map +1 -0
- package/dist/chunk-XEBG3G53.js +498 -0
- package/dist/chunk-XEBG3G53.js.map +1 -0
- package/dist/{chunk-I5R7ZBJS.js → chunk-YLEMGEFH.js} +103 -59
- package/dist/chunk-YLEMGEFH.js.map +1 -0
- package/dist/chunk-ZEJR4TKL.cjs +173 -0
- package/dist/chunk-ZEJR4TKL.cjs.map +1 -0
- package/dist/core/index.cjs +130 -647
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +301 -39
- package/dist/core/index.d.ts +301 -39
- package/dist/core/index.js +54 -16
- package/dist/{function-DYt4iKsn.d.cts → function-BtiZb9i9.d.ts} +28 -7
- package/dist/{function-DVH4Eusr.d.ts → function-DNugAOrt.d.cts} +28 -7
- package/dist/generate/index.cjs +28 -4085
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +370 -62
- package/dist/generate/index.d.ts +370 -62
- package/dist/generate/index.js +23 -9
- package/dist/{index-CxqBQtH1.d.cts → index-6VR8-kit.d.ts} +19 -4
- package/dist/index-70p168VM.d.ts +192 -0
- package/dist/{index-CpOsP1y9.d.cts → index-Be74mcon.d.cts} +18 -17
- package/dist/index-BtXT6UQ0.d.cts +192 -0
- package/dist/{index-DxvARIP2.d.ts → index-C5UBbQ4G.d.ts} +18 -17
- package/dist/{index-Bt4tOUD9.d.ts → index-C83mZI1P.d.ts} +93 -8
- package/dist/{index-Bg5dYMmZ.d.ts → index-D6b6na69.d.cts} +14 -11
- package/dist/{index-Cl7mhOFM.d.cts → index-DXd9JikN.d.cts} +92 -10
- package/dist/{index-Cl7mhOFM.d.ts → index-DXd9JikN.d.ts} +92 -10
- package/dist/index-OG65ocOr.d.cts +272 -0
- package/dist/index-OG65ocOr.d.ts +272 -0
- package/dist/{index-Jc0Ryi79.d.ts → index-tJhkmQgE.d.cts} +19 -4
- package/dist/{index-Dikst44v.d.cts → index-tSQh-xwY.d.ts} +14 -11
- package/dist/{index-BNlGP86A.d.cts → index-y_ak9_Hi.d.cts} +93 -8
- package/dist/index.cjs +419 -7383
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +111 -27
- package/dist/model/index.cjs +8 -2562
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +433 -75
- package/dist/model/index.d.ts +433 -75
- package/dist/model/index.js +6 -7
- package/dist/styled-DIRkk9Uz.d.ts +506 -0
- package/dist/styled-DJbkJQfj.d.cts +506 -0
- package/dist/theory/index.cjs +172 -1822
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +151 -233
- package/dist/theory/index.d.ts +151 -233
- package/dist/theory/index.js +30 -7
- package/dist/{types-MGP29r3t.d.cts → types-BN6_Q9Kl.d.cts} +11 -2
- package/dist/{types-MGP29r3t.d.ts → types-BN6_Q9Kl.d.ts} +11 -2
- package/package.json +24 -6
- package/dist/chunk-2ZWMSJH6.js.map +0 -1
- package/dist/chunk-4MHA432G.js.map +0 -1
- package/dist/chunk-62QZKCJQ.js.map +0 -1
- package/dist/chunk-AKLYPWIN.js.map +0 -1
- package/dist/chunk-C5XYKUVG.js.map +0 -1
- package/dist/chunk-CHMXELDS.js.map +0 -1
- package/dist/chunk-DYWFNC4A.js +0 -152
- package/dist/chunk-DYWFNC4A.js.map +0 -1
- package/dist/chunk-EH6EM37U.js.map +0 -1
- package/dist/chunk-FBQK3ZQN.js +0 -131
- package/dist/chunk-FBQK3ZQN.js.map +0 -1
- package/dist/chunk-GOAW4VYL.js.map +0 -1
- package/dist/chunk-I5R7ZBJS.js.map +0 -1
- package/dist/chunk-IT2O4XFE.js.map +0 -1
- package/dist/chunk-MIWO425M.js.map +0 -1
- package/dist/chunk-SGU7SPLK.js.map +0 -1
- package/dist/index-CGMZNCx6.d.cts +0 -140
- package/dist/index-CGMZNCx6.d.ts +0 -140
- package/dist/index-CnZCo29u.d.cts +0 -108
- package/dist/index-JnF4v9bx.d.ts +0 -108
- package/dist/styled-DZ7GjShb.d.ts +0 -282
- package/dist/styled-ZTbdaVFM.d.cts +0 -282
- package/src/analyze/arrange/index.ts +0 -21
- package/src/analyze/arrange/internal.ts +0 -127
- package/src/analyze/arrange/tension.ts +0 -199
- package/src/analyze/arrange/tracks.ts +0 -312
- package/src/analyze/detect/index.ts +0 -272
- package/src/analyze/functional/borrowed.ts +0 -84
- package/src/analyze/functional/cadence.ts +0 -66
- package/src/analyze/functional/function.ts +0 -184
- package/src/analyze/functional/index.ts +0 -23
- package/src/analyze/functional/internal.ts +0 -29
- package/src/analyze/functional/roman.ts +0 -402
- package/src/analyze/index.ts +0 -49
- package/src/analyze/timeline/index.ts +0 -451
- package/src/analyze/voice/index.ts +0 -339
- package/src/core/event-index/index.ts +0 -104
- package/src/core/index.ts +0 -61
- package/src/core/interval/index.ts +0 -81
- package/src/core/meter/index.ts +0 -302
- package/src/core/pitch/index.ts +0 -311
- package/src/core/random/index.ts +0 -76
- package/src/core/tuning/index.ts +0 -186
- package/src/core/types.ts +0 -29
- package/src/core/validation/index.ts +0 -119
- package/src/generate/bass/index.ts +0 -373
- package/src/generate/countermelody/index.ts +0 -470
- package/src/generate/drums/beat.ts +0 -266
- package/src/generate/drums/euclid.ts +0 -65
- package/src/generate/drums/fills.ts +0 -356
- package/src/generate/drums/ghost.ts +0 -119
- package/src/generate/drums/hihat.ts +0 -285
- package/src/generate/drums/hit.ts +0 -31
- package/src/generate/drums/index.ts +0 -361
- package/src/generate/drums/internal.ts +0 -257
- package/src/generate/drums/kick.ts +0 -160
- package/src/generate/drums/percussion.ts +0 -121
- package/src/generate/drums/rng.ts +0 -7
- package/src/generate/drums/swing.ts +0 -71
- package/src/generate/groove/index.ts +0 -351
- package/src/generate/harmonize/index.ts +0 -451
- package/src/generate/index.ts +0 -58
- package/src/generate/motif/index.ts +0 -422
- package/src/generate/progression/index.ts +0 -362
- package/src/generate/reharmony/index.ts +0 -323
- package/src/generate/rhythm/index.ts +0 -175
- package/src/index.ts +0 -13
- package/src/model/chord.ts +0 -442
- package/src/model/index.ts +0 -15
- package/src/model/interval.ts +0 -82
- package/src/model/key.ts +0 -266
- package/src/model/note.ts +0 -176
- package/src/model/progression.ts +0 -161
- package/src/model/shared.ts +0 -12
- package/src/theory/chord/index.ts +0 -375
- package/src/theory/chordscale/index.ts +0 -374
- package/src/theory/counterpoint/index.ts +0 -230
- package/src/theory/harmony/index.ts +0 -77
- package/src/theory/index.ts +0 -112
- package/src/theory/safety/index.ts +0 -488
- package/src/theory/scale/degrees.ts +0 -123
- package/src/theory/scale/index.ts +0 -28
- package/src/theory/scale/key.ts +0 -56
- package/src/theory/scale/masks.ts +0 -153
- package/src/theory/spelling/index.ts +0 -249
- package/src/theory/symbol/index.ts +0 -268
- package/src/theory/voicing/index.ts +0 -5
- package/src/theory/voicing/internal.ts +0 -168
- package/src/theory/voicing/leading.ts +0 -112
- package/src/theory/voicing/satb.ts +0 -216
- package/src/theory/voicing/styled.ts +0 -199
- package/tsconfig.json +0 -23
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/model/shared.ts","../src/model/note.ts","../src/model/progression.ts","../src/model/chord.ts","../src/model/interval.ts","../src/model/key.ts"],"sourcesContent":["import { midiToNote, type Note as NoteData } from '../core/pitch/index.js';\n\n/** Reduce any integer to a pitch class in [0, 11]. */\nexport function mod12(n: number): number {\n return ((n % 12) + 12) % 12;\n}\n\n/** Spell a bare pitch class as an octave-less note with a sharp/flat preference. */\nexport function spellPitchClassBare(pc: number, spelling: 'sharp' | 'flat'): NoteData {\n const spelled = midiToNote(60 + mod12(pc), spelling);\n return { letter: spelled.letter, alter: spelled.alter };\n}\n","import {\n formatNote,\n midiToNote,\n type Note as NoteData,\n noteToMidi,\n noteToPitchClass,\n parseNote,\n type SpelledInterval,\n spelledInterval,\n} from '../core/pitch/index.js';\nimport { spellPitchClassBare } from './shared.js';\n\n/** Defensive copy of a plain note. */\nfunction copyNote(data: NoteData): NoteData {\n const copy: NoteData = { letter: data.letter, alter: data.alter };\n if (data.octave !== undefined) {\n copy.octave = data.octave;\n }\n return copy;\n}\n\n/**\n * An immutable spelled note: a diatonic letter plus a chromatic alteration and\n * an optional octave. Wraps the plain note object and delegates to the pitch\n * module; every transformation returns a new instance.\n *\n * @category Class API\n * @example\n * ```ts\n * import { Note } from '@libraz/libcantus';\n * Note.of('C4').transpose(7).name; // 'G4'\n * ```\n */\nexport class Note {\n readonly #data: NoteData;\n\n /**\n * Wrap a plain note object.\n *\n * @param data The spelled note; it is copied, never retained or mutated.\n */\n constructor(data: NoteData) {\n this.#data = copyNote(data);\n }\n\n /**\n * Parse scientific pitch notation (e.g. `'C#4'`, `'Bb'`, `'F##3'`).\n *\n * @param name The note text.\n * @returns The parsed note.\n * @throws If the text is not a valid note.\n */\n static of(name: string): Note {\n return new Note(parseNote(name));\n }\n\n /**\n * Name a MIDI number (middle C = C4 = 60) as a note.\n *\n * @param midi The MIDI number.\n * @param spelling Whether to prefer sharps or flats for black keys.\n * @returns The spelled note, with octave.\n */\n static fromMidi(midi: number, spelling: 'sharp' | 'flat' = 'sharp'): Note {\n return new Note(midiToNote(midi, spelling));\n }\n\n /**\n * Wrap an existing plain note object.\n *\n * @param data The plain note.\n * @returns The wrapped note.\n */\n static fromData(data: NoteData): Note {\n return new Note(data);\n }\n\n /** The note rendered as scientific pitch notation, e.g. `'G4'` or `'Bb'`. */\n get name(): string {\n return formatNote(this.#data);\n }\n\n /** The pitch class (0..11), ignoring octave. */\n get pitchClass(): number {\n return noteToPitchClass(this.#data);\n }\n\n /**\n * The MIDI number (middle C = C4 = 60).\n *\n * @throws If the note has no octave and therefore no fixed pitch.\n */\n get midi(): number {\n if (this.#data.octave === undefined) {\n throw new Error(`note ${this.name} has no octave, so it has no MIDI number`);\n }\n return noteToMidi(this.#data);\n }\n\n /** The diatonic letter number: 0..6 for C..B. */\n get letter(): number {\n return this.#data.letter;\n }\n\n /** The chromatic alteration in semitones: -1 flat, 0 natural, +1 sharp, ... */\n get alter(): number {\n return this.#data.alter;\n }\n\n /** The octave (scientific pitch notation), or undefined for a bare pitch class. */\n get octave(): number | undefined {\n return this.#data.octave;\n }\n\n /** A copy of the underlying plain note object. */\n get data(): NoteData {\n return copyNote(this.#data);\n }\n\n /**\n * Transpose by a signed number of semitones.\n *\n * When the note carries an octave the transposition happens in MIDI space and\n * the result is spelled with a sharp preference. An octave-less note stays\n * octave-less: only its pitch class is moved. Transposing by zero is the\n * identity: the original spelling is preserved (no enharmonic respelling).\n *\n * @param semitones The signed semitone offset.\n * @returns The transposed note.\n */\n transpose(semitones: number): Note {\n if (semitones === 0) {\n return new Note(this.#data);\n }\n if (this.#data.octave !== undefined) {\n return Note.fromMidi(this.midi + semitones);\n }\n return new Note(spellPitchClassBare(this.pitchClass + semitones, 'sharp'));\n }\n\n /**\n * The spelled interval from this note to another.\n *\n * @param other The second note.\n * @returns The diatonic number, quality, and semitone span.\n */\n intervalTo(other: Note): SpelledInterval {\n return spelledInterval(this.#data, other.#data);\n }\n\n /**\n * Whether another note has the same letter, alteration, and octave.\n *\n * @param other The note to compare.\n * @returns True if the spellings are identical.\n */\n equals(other: Note): boolean {\n return (\n this.#data.letter === other.#data.letter &&\n this.#data.alter === other.#data.alter &&\n this.#data.octave === other.#data.octave\n );\n }\n\n /**\n * The plain note data, for JSON serialization.\n *\n * Private class fields do not serialize, so an explicit `toJSON` keeps\n * `JSON.stringify(note)` from collapsing to `{}`.\n *\n * @returns A copy of the underlying plain note object.\n */\n toJSON(): NoteData {\n return this.data;\n }\n}\n","import {\n type Cadence,\n type ChordAnalysis,\n detectCadence,\n type HarmonicFunction,\n} from '../analyze/functional/index.js';\nimport type { Note as NoteData } from '../core/pitch/index.js';\nimport type { KeyScale } from '../core/types.js';\nimport type { Chord as ChordData } from '../theory/chord/index.js';\nimport { type VoicingOptions, voiceProgression } from '../theory/voicing/index.js';\nimport type { Chord } from './chord.js';\nimport type { Key } from './key.js';\n\n/**\n * An immutable ordered sequence of chords, optionally carrying a {@link Key}\n * context shared by its analysis methods.\n *\n * @category Class API\n * @example\n * ```ts\n * import { Key } from '@libraz/libcantus';\n * const key = Key.major('C');\n * key.chord(1).progressionTo(key.chord(4), key.chord(0)).roman();\n * // ['ii', 'V', 'I']\n * ```\n */\nexport class Progression {\n readonly #chords: readonly Chord[];\n readonly #key: Key | undefined;\n\n /**\n * Wrap a chord sequence.\n *\n * @param chords The chords in order; the array is copied.\n * @param key Optional key context for analysis methods.\n */\n constructor(chords: readonly Chord[], key?: Key) {\n this.#chords = [...chords];\n this.#key = key;\n }\n\n /** A copy of the chord sequence. */\n get chords(): readonly Chord[] {\n return [...this.#chords];\n }\n\n /** The carried key context, if any. */\n get key(): Key | undefined {\n return this.#key;\n }\n\n /** The number of chords. */\n get length(): number {\n return this.#chords.length;\n }\n\n /**\n * A copy of this progression with a chord appended.\n *\n * @param chord The chord to append.\n * @returns The new progression.\n */\n add(chord: Chord): Progression {\n return new Progression([...this.#chords, chord], this.#key);\n }\n\n /**\n * A copy of this progression carrying the given key context.\n *\n * @param key The key context to attach.\n * @returns The new progression.\n */\n withKey(key: Key): Progression {\n return new Progression(this.#chords, key);\n }\n\n /**\n * Voice the progression with smooth voice leading.\n *\n * @param opts Voicing options; defaults to four SATB voices.\n * @returns One ascending voicing (MIDI pitches) per chord.\n * @throws If any chord admits no voicing within the given ranges.\n */\n voice(opts?: VoicingOptions): number[][] {\n return voiceProgression(\n this.#chords.map((chord) => chord.data),\n opts,\n );\n }\n\n /**\n * The Roman numeral of each chord in a key.\n *\n * @param key Key to analyze in; falls back to the carried context.\n * @returns One numeral per chord.\n * @throws If no key is given and none is carried.\n */\n roman(key?: Key): string[] {\n const resolved = this.#resolveKey(key);\n return this.#chords.map((chord) => chord.roman(resolved));\n }\n\n /**\n * The harmonic function of each chord in a key.\n *\n * @param key Key to analyze in; falls back to the carried context.\n * @returns One function per chord.\n * @throws If no key is given and none is carried.\n */\n functions(key?: Key): HarmonicFunction[] {\n const resolved = this.#resolveKey(key);\n return this.#chords.map((chord) => chord.function(resolved));\n }\n\n /**\n * Analyze every chord and classify the closing cadence.\n *\n * The cadence is detected on the final chord pair and is null when the\n * progression has fewer than two chords.\n *\n * @param key Key to analyze in; falls back to the carried context.\n * @returns Per-chord analyses and the closing cadence.\n * @throws If no key is given and none is carried.\n */\n analyze(key?: Key): { chords: ChordAnalysis[]; cadence: Cadence } {\n const resolved = this.#resolveKey(key);\n const chords = this.#chords.map((chord) => chord.analyze(resolved));\n const from = this.#chords[this.#chords.length - 2];\n const to = this.#chords[this.#chords.length - 1];\n const cadence =\n from !== undefined && to !== undefined\n ? detectCadence(from.data, to.data, resolved.scale)\n : null;\n return { chords, cadence };\n }\n\n /**\n * The plain progression data, for JSON serialization.\n *\n * Private class fields do not serialize, so an explicit `toJSON` keeps\n * `JSON.stringify(progression)` from collapsing to `{}`. The chords are\n * emitted as plain data and the carried key, when present, as its own data.\n *\n * @returns The chord data sequence and the carried key, if any.\n */\n toJSON(): { chords: ChordData[]; key: { scale: KeyScale; tonic: NoteData } | undefined } {\n return {\n chords: this.#chords.map((chord) => chord.data),\n key: this.#key?.toJSON(),\n };\n }\n\n /** Resolve the key for an analysis method: explicit first, then carried. */\n #resolveKey(key?: Key): Key {\n const resolved = key ?? this.#key;\n if (resolved === undefined) {\n throw new Error('progression has no key context; pass a Key or attach one with withKey()');\n }\n return resolved;\n }\n}\n","import { type DetectChordOptions, detectChord, detectChordBest } from '../analyze/detect/index.js';\nimport {\n analyzeChord,\n type BorrowedSource,\n borrowedSource,\n type ChordAnalysis,\n chordToRoman,\n functionOf,\n type HarmonicFunction,\n isBorrowedChord,\n} from '../analyze/functional/index.js';\nimport { negativeHarmonyMirror } from '../generate/reharmony/index.js';\nimport {\n type Chord as ChordData,\n type ChordQuality,\n chordPitchClasses,\n makeChord,\n} from '../theory/chord/index.js';\nimport {\n availableTensions,\n avoidNotes,\n type ChordScaleMatch,\n chordScales,\n} from '../theory/chordscale/index.js';\nimport { spellChord, spellChordFromRoot, spellPitchClass } from '../theory/spelling/index.js';\nimport { formatChordSymbol, parseChordSymbol } from '../theory/symbol/index.js';\nimport {\n type StyledVoicingOptions,\n type VoicingOptions,\n voiceChord,\n voiceChordStyled,\n} from '../theory/voicing/index.js';\nimport type { Key } from './key.js';\nimport { Note } from './note.js';\nimport { Progression } from './progression.js';\nimport { mod12, spellPitchClassBare } from './shared.js';\n\n/**\n * Defensive copy of a plain chord.\n *\n * Any enharmonic spelling hints (`rootSpelling`/`bassSpelling`, populated by\n * `parseChordSymbol`) are carried through so a flat-named chord round-trips\n * through the class API; a hint that no longer matches its pitch class is\n * simply ignored by the formatter.\n */\nfunction copyChord(data: ChordData): ChordData {\n const copy: ChordData = {\n rootPc: data.rootPc,\n quality: data.quality,\n intervals: [...data.intervals],\n };\n if (data.bassPc !== undefined) {\n copy.bassPc = data.bassPc;\n }\n if (data.rootSpelling !== undefined) {\n copy.rootSpelling = { letter: data.rootSpelling.letter, alter: data.rootSpelling.alter };\n }\n if (data.bassSpelling !== undefined) {\n copy.bassSpelling = { letter: data.bassSpelling.letter, alter: data.bassSpelling.alter };\n }\n return copy;\n}\n\n/**\n * An immutable chord: a root pitch class, quality, interval template, and\n * optional slash bass, optionally carrying a {@link Key} context. Analysis\n * methods (`roman`, `function`, `analyze`, ...) use an explicitly passed key\n * first and fall back to the carried context.\n *\n * @category Class API\n * @example\n * ```ts\n * import { Chord } from '@libraz/libcantus';\n * Chord.parse('Cmaj7').invert(1).symbol(); // 'Cmaj7/E' (third in the bass)\n * ```\n */\nexport class Chord {\n readonly #data: ChordData;\n readonly #key: Key | undefined;\n\n /**\n * Wrap a plain chord object.\n *\n * @param data The chord; it is copied, never retained or mutated.\n * @param key Optional key context for analysis methods.\n */\n constructor(data: ChordData, key?: Key) {\n const copy = copyChord(data);\n if (copy.rootSpelling === undefined && key !== undefined) {\n copy.rootSpelling = spellPitchClass(copy.rootPc, key.tonic.data, key.scale);\n }\n this.#data = copy;\n this.#key = key;\n }\n\n /**\n * Build a chord from a root and quality.\n *\n * @param root Root as a note name (e.g. `'Eb'`) or a pitch class.\n * @param quality The chord quality.\n * @param bass Optional slash-chord bass pitch class.\n * @returns The chord (without key context).\n */\n static of(root: string | number, quality: ChordQuality, bass?: number): Chord {\n if (typeof root === 'string') {\n const rootNote = Note.of(root);\n const data = makeChord(rootNote.pitchClass, quality, bass);\n data.rootSpelling = { letter: rootNote.letter, alter: rootNote.alter };\n return new Chord(data);\n }\n return new Chord(makeChord(root, quality, bass));\n }\n\n /**\n * Wrap an existing plain chord object.\n *\n * @param data The plain chord.\n * @returns The wrapped chord (without key context).\n */\n static from(data: ChordData): Chord {\n return new Chord(data);\n }\n\n /**\n * Parse a lead-sheet chord symbol (e.g. `'Cmaj7'`, `'F#m7b5'`, `'C/G'`).\n *\n * @param symbol The chord symbol.\n * @returns The chord (without key context).\n * @throws If the root or quality is not recognized.\n */\n static parse(symbol: string): Chord {\n return new Chord(parseChordSymbol(symbol));\n }\n\n /**\n * Identify the chords matching a set of pitches, best interpretation first.\n *\n * @param pitches MIDI pitches or bare pitch classes.\n * @returns Ranked chord interpretations (may be empty).\n */\n static detect(pitches: number[], opts?: DetectChordOptions): Chord[] {\n return detectChord(pitches, opts).map(\n (match) => new Chord(makeChord(match.rootPc, match.quality, match.bassPc)),\n );\n }\n\n /**\n * The single best chord interpretation of a pitch set.\n *\n * @param pitches MIDI pitches or bare pitch classes.\n * @returns The top-ranked chord, or null when nothing matches.\n */\n static detectBest(pitches: number[], opts?: DetectChordOptions): Chord | null {\n const best = detectChordBest(pitches, opts);\n return best === null ? null : new Chord(best);\n }\n\n /** The root pitch class (0..11). */\n get rootPc(): number {\n return this.#data.rootPc;\n }\n\n /** The chord quality. */\n get quality(): ChordQuality {\n return this.#data.quality;\n }\n\n /** A copy of the semitone offsets above the root. */\n get intervals(): number[] {\n return [...this.#data.intervals];\n }\n\n /** The slash-chord bass pitch class, or undefined in root position. */\n get bassPc(): number | undefined {\n return this.#data.bassPc;\n }\n\n /** A copy of the underlying plain chord object. */\n get data(): ChordData {\n return copyChord(this.#data);\n }\n\n /** The carried key context, if any. */\n get key(): Key | undefined {\n return this.#key;\n }\n\n /**\n * A copy of this chord carrying the given key context.\n *\n * @param key The key context to attach.\n * @returns The new chord.\n */\n withKey(key: Key): Chord {\n return new Chord(this.#data, key);\n }\n\n /**\n * The chord's sorted, deduplicated pitch classes.\n *\n * @returns Pitch classes ascending in [0, 11].\n */\n pitchClasses(): number[] {\n return chordPitchClasses(this.#data);\n }\n\n /**\n * The chord's Roman numeral in a key.\n *\n * @param key Key to analyze in; falls back to the carried context.\n * @returns The Roman numeral string.\n * @throws If no key is given and none is carried.\n */\n roman(key?: Key): string {\n return chordToRoman(this.#data, this.#resolveKey(key).scale);\n }\n\n /**\n * The chord's harmonic function (tonic / subdominant / dominant) in a key.\n *\n * @param key Key to analyze in; falls back to the carried context.\n * @returns The harmonic function.\n * @throws If no key is given and none is carried.\n */\n function(key?: Key): HarmonicFunction {\n return functionOf(this.#data, this.#resolveKey(key).scale);\n }\n\n /**\n * Full functional analysis: function, borrowing, and Roman numeral.\n *\n * @param key Key to analyze in; falls back to the carried context.\n * @returns The chord analysis.\n * @throws If no key is given and none is carried.\n */\n analyze(key?: Key): ChordAnalysis {\n return analyzeChord(this.#data, this.#resolveKey(key).scale);\n }\n\n /**\n * Whether the chord is borrowed from the parallel mode (modal interchange).\n *\n * @param key Key to analyze in; falls back to the carried context.\n * @returns True if the chord is borrowed.\n * @throws If no key is given and none is carried.\n */\n isBorrowed(key?: Key): boolean {\n return isBorrowedChord(this.#data, this.#resolveKey(key).scale);\n }\n\n /**\n * The origin of a non-diatonic chord (parallel mode or Neapolitan), or null.\n *\n * @param key Key to analyze in; falls back to the carried context.\n * @returns The borrowing source, or null.\n * @throws If no key is given and none is carried.\n */\n borrowedSource(key?: Key): BorrowedSource {\n return borrowedSource(this.#data, this.#resolveKey(key).scale);\n }\n\n /**\n * The chord rendered as a lead-sheet symbol (e.g. `'Cmaj7'`, `'F#m7'`, `'C/G'`).\n *\n * @param opts Set `flats: true` to spell the root/bass with flats.\n * @returns The chord symbol.\n */\n symbol(opts?: { flats?: boolean }): string {\n return formatChordSymbol(this.#data, opts);\n }\n\n /**\n * Realize the chord as one MIDI pitch per voice, ascending.\n *\n * @param opts Voicing options; defaults to four SATB voices.\n * @returns MIDI pitches, ascending, one per voice.\n * @throws If no voicing fits the given ranges.\n */\n voice(opts?: VoicingOptions): number[] {\n return voiceChord(this.#data, opts);\n }\n\n /**\n * Realize the chord as a single styled voicing (`close`, `drop2`, `drop3`,\n * `shell`, or `rootless`), optionally constraining the top voice.\n *\n * @param opts Styled-voicing options; defaults to a close-position voicing.\n * @returns MIDI pitches, ascending.\n */\n styledVoicing(opts?: StyledVoicingOptions): number[] {\n return voiceChordStyled(this.#data, opts);\n }\n\n /**\n * The negative-harmony mirror of the chord about the key's tonic–dominant\n * axis (major becomes minor and vice versa).\n *\n * @param key Key providing the reflection axis; falls back to the carried\n * context.\n * @returns The mirrored chord, keeping any key context.\n * @throws If no key is given and none is carried.\n */\n negativeHarmony(key?: Key): Chord {\n const resolved = this.#resolveKey(key);\n // Retain the key that anchored the reflection (explicit first, then carried)\n // so a later no-arg analysis method still has a key context.\n return new Chord(negativeHarmonyMirror(this.#data, resolved.scale), key ?? this.#key);\n }\n\n /**\n * The n-th inversion: a copy whose bass is the chord tone `n` steps above the\n * root in the interval template (`invert(1)` puts the third in the bass).\n * `n` wraps around the template length; negative values count backwards.\n *\n * `invert(0)` (and any `n` that wraps to it) is root position, so it carries\n * no slash bass and equals the original chord.\n *\n * @param n The inversion number.\n * @returns The inverted chord, keeping any key context.\n * @throws If the chord has no intervals.\n */\n invert(n: number): Chord {\n const intervals = this.#data.intervals;\n const length = intervals.length;\n if (length === 0) {\n throw new Error('cannot invert a chord with no intervals');\n }\n const index = ((n % length) + length) % length;\n const data = copyChord(this.#data);\n if (index === 0) {\n delete data.bassPc;\n delete data.bassSpelling;\n } else {\n data.bassPc = mod12(this.#data.rootPc + (intervals[index] ?? 0));\n const rootSpelling =\n data.rootSpelling ??\n (this.#key\n ? spellPitchClass(data.rootPc, this.#key.tonic.data, this.#key.scale)\n : spellPitchClassBare(data.rootPc, 'sharp'));\n const bassSpelling = spellChordFromRoot(data, rootSpelling)[index];\n if (bassSpelling !== undefined) {\n data.bassSpelling = bassSpelling;\n }\n }\n return new Chord(data, this.#key);\n }\n\n /**\n * The named scales that fit over this chord, best fit first, rooted on the\n * chord root.\n *\n * @returns The matching scales.\n */\n scales(): ChordScaleMatch[] {\n return chordScales(this.#data);\n }\n\n /**\n * The available tensions (usable non-chord, non-avoid scale tones) of a\n * scale over this chord.\n *\n * @param scaleName A named scale, rooted on the chord root.\n * @returns Tension pitch classes, ascending in [0, 11].\n */\n tensions(scaleName: string): number[] {\n return availableTensions(this.#data, scaleName);\n }\n\n /**\n * The avoid notes (scale tones a semitone above a chord tone) of a scale\n * over this chord.\n *\n * @param scaleName A named scale, rooted on the chord root.\n * @returns Avoid-note pitch classes, ascending in [0, 11].\n */\n avoidNotes(scaleName: string): number[] {\n return avoidNotes(this.#data, scaleName);\n }\n\n /**\n * Spell the chord tones with letter names, root first, in the key's spelling.\n *\n * @param key Key providing the spelled tonic; falls back to the carried\n * context.\n * @returns Spelled octave-less notes in the chord's own (tertian) order.\n * @throws If no key is given and none is carried.\n */\n spell(key?: Key): Note[] {\n const resolved = this.#resolveKey(key);\n return spellChord(this.#data, resolved.tonic.data, resolved.scale).map(\n (note) => new Note(note),\n );\n }\n\n /**\n * Start a progression with this chord followed by others, carrying this\n * chord's key context (if any).\n *\n * @param others The chords following this one.\n * @returns The progression.\n */\n progressionTo(...others: Chord[]): Progression {\n return new Progression([this, ...others], this.#key);\n }\n\n /**\n * Whether another chord has the same root, quality, intervals, and bass.\n * Key context is not compared.\n *\n * @param other The chord to compare.\n * @returns True if the chord data is identical.\n */\n equals(other: Chord): boolean {\n const a = this.#data;\n const b = other.#data;\n return (\n a.rootPc === b.rootPc &&\n a.quality === b.quality &&\n a.bassPc === b.bassPc &&\n a.intervals.length === b.intervals.length &&\n a.intervals.every((interval, i) => interval === b.intervals[i])\n );\n }\n\n /**\n * The plain chord data, for JSON serialization.\n *\n * @returns A copy of the underlying plain chord object.\n */\n toJSON(): ChordData {\n return this.data;\n }\n\n /** Resolve the key for an analysis method: explicit first, then carried. */\n #resolveKey(key?: Key): Key {\n const resolved = key ?? this.#key;\n if (resolved === undefined) {\n throw new Error('chord has no key context; pass a Key or attach one with withKey()');\n }\n return resolved;\n }\n}\n","import type { SpelledInterval } from '../core/pitch/index.js';\nimport type { Note } from './note.js';\n\n/**\n * An immutable spelled interval value: a diatonic number, a quality label, and\n * a signed semitone span. A thin convenience wrapper over the pitch module's\n * plain interval result.\n *\n * @category Class API\n * @example\n * ```ts\n * import { Interval, Note } from '@libraz/libcantus';\n * Interval.between(Note.of('C4'), Note.of('G4')).name; // 'P5'\n * ```\n */\nexport class Interval {\n readonly #number: number;\n readonly #quality: string;\n readonly #semitones: number;\n\n private constructor(numberValue: number, quality: string, semitones: number) {\n this.#number = numberValue;\n this.#quality = quality;\n this.#semitones = semitones;\n }\n\n /**\n * The spelled interval between two notes.\n *\n * @param a The first note.\n * @param b The second note.\n * @returns The interval from `a` to `b`.\n */\n static between(a: Note, b: Note): Interval {\n const spelled = a.intervalTo(b);\n return new Interval(spelled.number, spelled.quality, spelled.semitones);\n }\n\n /**\n * Build an interval from explicit components.\n *\n * @param numberValue Diatonic size: 1 = unison, 2 = second, ... 8 = octave.\n * @param quality Quality label: `'P'`, `'M'`, `'m'`, or repeated `'A'`/`'d'`.\n * @param semitones Signed semitone span.\n * @returns The interval.\n */\n static of(numberValue: number, quality: string, semitones: number): Interval {\n return new Interval(numberValue, quality, semitones);\n }\n\n /** Diatonic size: 1 = unison, 2 = second, ... 8 = octave, and beyond. */\n get number(): number {\n return this.#number;\n }\n\n /** Quality label: `'P'`, `'M'`, `'m'`, or repeated `'A'`/`'d'`. */\n get quality(): string {\n return this.#quality;\n }\n\n /** Signed semitone span. */\n get semitones(): number {\n return this.#semitones;\n }\n\n /** A readable label composed of quality and number, e.g. `'P5'` or `'M3'`. */\n get name(): string {\n return `${this.#quality}${this.#number}`;\n }\n\n /**\n * The plain interval data, for JSON serialization.\n *\n * Private class fields do not serialize, so an explicit `toJSON` keeps\n * `JSON.stringify(interval)` from collapsing to `{}`.\n *\n * @returns The diatonic number, quality, and semitone span.\n */\n toJSON(): SpelledInterval {\n return { number: this.#number, quality: this.#quality, semitones: this.#semitones };\n }\n}\n","import { isMinorKey, romanToChord } from '../analyze/functional/index.js';\nimport type { Note as NoteData } from '../core/pitch/index.js';\nimport type { KeyScale } from '../core/types.js';\nimport {\n type ChordQuality,\n chordFromDegree,\n diatonicSeventh,\n diatonicTriad,\n} from '../theory/chord/index.js';\nimport {\n isScaleTone,\n majorKey,\n minorKey,\n scaleByName,\n scaleTonesInDegreeOrder,\n} from '../theory/scale/index.js';\nimport { spellScale } from '../theory/spelling/index.js';\nimport { Chord } from './chord.js';\nimport { Note } from './note.js';\nimport { mod12, spellPitchClassBare } from './shared.js';\n\n/** Resolve a string or numeric key root into a spelled tonic note. */\nfunction resolveTonic(root: string | number, spelling: 'sharp' | 'flat'): Note {\n return typeof root === 'string' ? Note.of(root) : new Note(spellPitchClassBare(root, spelling));\n}\n\n/** Total accidentals a spelled tonic produces across a key's whole scale. */\nfunction accidentalLoad(tonic: NoteData, scale: KeyScale): number {\n return spellScale(tonic, scale).reduce((sum, note) => sum + Math.abs(note.alter), 0);\n}\n\n/**\n * Choose the tonic spelling (sharp- or flat-side) that spells `scale` with the\n * fewest accidentals, so a numeric root never yields a double-flat/double-sharp\n * scale (e.g. pitch class 6 minor spells as F# minor, not Gb minor with Bbb).\n */\nfunction bestTonicForScale(rootPc: number, scale: KeyScale): Note {\n const sharp = spellPitchClassBare(rootPc, 'sharp');\n const flat = spellPitchClassBare(rootPc, 'flat');\n if (sharp.letter === flat.letter && sharp.alter === flat.alter) {\n return new Note(sharp);\n }\n return accidentalLoad(flat, scale) <= accidentalLoad(sharp, scale)\n ? new Note(flat)\n : new Note(sharp);\n}\n\n/**\n * An immutable key/scale: a `KeyScale` (root pitch class plus mode mask) paired\n * with a spelled tonic that anchors letter-name spelling. Acts as the factory\n * for key-aware chords.\n *\n * @category Class API\n * @example\n * ```ts\n * import { Key } from '@libraz/libcantus';\n * Key.major('C').chord(4).symbol(); // 'G' (the diatonic triad on scale degree 4)\n * ```\n */\nexport class Key {\n readonly #scale: KeyScale;\n readonly #tonic: Note;\n\n /**\n * Wrap a key/scale and its spelled tonic.\n *\n * @param scale The key/scale; its root is normalized to a pitch class.\n * @param tonic The spelled tonic anchoring letter-name spelling.\n */\n constructor(scale: KeyScale, tonic: Note) {\n this.#scale = { rootPc: mod12(scale.rootPc), modeMask12: scale.modeMask12 };\n this.#tonic = tonic;\n }\n\n /**\n * A major key.\n *\n * @param root Tonic as a note name (e.g. `'Eb'`) or a pitch class; a numeric\n * root is spelled with whichever accidental side yields the fewest\n * accidentals across the scale.\n * @returns The major key.\n */\n static major(root: string | number): Key {\n if (typeof root === 'string') {\n const tonic = Note.of(root);\n return new Key(majorKey(tonic.pitchClass), tonic);\n }\n const scale = majorKey(root);\n return new Key(scale, bestTonicForScale(root, scale));\n }\n\n /**\n * A natural-minor key.\n *\n * @param root Tonic as a note name or a pitch class; a numeric root is\n * spelled with whichever accidental side yields the fewest accidentals\n * across the scale.\n * @returns The minor key.\n */\n static minor(root: string | number): Key {\n if (typeof root === 'string') {\n const tonic = Note.of(root);\n return new Key(minorKey(tonic.pitchClass), tonic);\n }\n const scale = minorKey(root);\n return new Key(scale, bestTonicForScale(root, scale));\n }\n\n /**\n * A key on a named scale (e.g. `'dorian'`, `'harmonicMinor'`).\n *\n * @param name The scale name, a key of the scale module's named-scale table.\n * @param root Tonic as a note name or a pitch class.\n * @returns The key.\n * @throws If the name is not a known scale.\n */\n static named(name: string, root: string | number): Key {\n const tonic = resolveTonic(root, 'sharp');\n return new Key(scaleByName(name, tonic.pitchClass), tonic);\n }\n\n /**\n * Wrap an existing `KeyScale`, synthesizing a spelled tonic when none is\n * given (flat-preferred for minor-third scales, sharp-preferred otherwise).\n *\n * @param scale The key/scale to wrap.\n * @param tonic Optional spelled tonic.\n * @returns The key.\n */\n static of(scale: KeyScale, tonic?: Note): Key {\n const spelled =\n tonic ?? new Note(spellPitchClassBare(scale.rootPc, isMinorKey(scale) ? 'flat' : 'sharp'));\n return new Key(scale, spelled);\n }\n\n /** A copy of the underlying plain `KeyScale`. */\n get scale(): KeyScale {\n return { rootPc: this.#scale.rootPc, modeMask12: this.#scale.modeMask12 };\n }\n\n /** The spelled tonic. */\n get tonic(): Note {\n return this.#tonic;\n }\n\n /** The tonic pitch class (0..11). */\n get rootPc(): number {\n return this.#scale.rootPc;\n }\n\n /** Whether the scale has a minor third and no major third. */\n get isMinor(): boolean {\n return isMinorKey(this.#scale);\n }\n\n /**\n * The scale's pitch classes in ascending scale-degree order (degree 0 first).\n *\n * @returns One pitch class per scale degree.\n */\n pitchClasses(): number[] {\n return scaleTonesInDegreeOrder(this.#scale);\n }\n\n /**\n * The spelled scale, one note per degree (e.g. C D E F G A B for C major).\n *\n * @returns Spelled octave-less notes in scale-degree order.\n */\n notes(): Note[] {\n return spellScale(this.#tonic.data, this.#scale).map((note) => new Note(note));\n }\n\n /**\n * Alias of {@link Key.notes}.\n *\n * @returns Spelled octave-less notes in scale-degree order.\n */\n spell(): Note[] {\n return this.notes();\n }\n\n /**\n * The spelled scale as letter-name strings.\n *\n * @returns One name per scale degree.\n */\n noteNames(): string[] {\n return this.notes().map((note) => note.name);\n }\n\n /**\n * Build a chord on a scale degree, carrying this key as context.\n *\n * With an explicit quality the quality's interval template is attached to the\n * degree's diatonic root; without one the scale-correct diatonic triad is\n * stacked (e.g. a diminished triad on the leading tone of a major key).\n *\n * @param degree 0-based scale degree of the chord root.\n * @param quality Optional chord quality.\n * @returns The chord, with this key attached.\n */\n chord(degree: number, quality?: ChordQuality): Chord {\n const data =\n quality === undefined\n ? diatonicTriad(degree, this.#scale)\n : chordFromDegree(degree, quality, this.#scale);\n return new Chord(data, this);\n }\n\n /**\n * The diatonic triad on a scale degree, carrying this key as context.\n *\n * @param degree 0-based scale degree of the chord root.\n * @returns The triad, with this key attached.\n */\n diatonicTriad(degree: number): Chord {\n return new Chord(diatonicTriad(degree, this.#scale), this);\n }\n\n /**\n * The diatonic seventh chord on a scale degree, carrying this key as context.\n *\n * @param degree 0-based scale degree of the chord root.\n * @returns The seventh chord, with this key attached.\n */\n diatonicSeventh(degree: number): Chord {\n return new Chord(diatonicSeventh(degree, this.#scale), this);\n }\n\n /**\n * Build the chord denoted by a Roman numeral in this key (including applied\n * chords such as `'V7/V'`), carrying this key as context.\n *\n * @param text The Roman numeral.\n * @returns The chord, with this key attached.\n * @throws If the numeral is not valid.\n */\n roman(text: string): Chord {\n return new Chord(romanToChord(text, this.#scale), this);\n }\n\n /**\n * Whether a pitch belongs to the scale.\n *\n * @param x A MIDI pitch, bare pitch class, or note.\n * @returns True if the pitch class is a scale tone.\n */\n contains(x: number | Note): boolean {\n return isScaleTone(typeof x === 'number' ? x : x.pitchClass, this.#scale);\n }\n\n /**\n * The plain key data, for JSON serialization.\n *\n * Private class fields do not serialize, so an explicit `toJSON` keeps\n * `JSON.stringify(key)` from collapsing to `{}`. The result pairs the\n * `KeyScale` with the spelled tonic, enough to reconstruct the key via\n * {@link Key.of}.\n *\n * @returns The key/scale and its spelled tonic.\n */\n toJSON(): { scale: KeyScale; tonic: NoteData } {\n return { scale: this.scale, tonic: this.#tonic.data };\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pitch spelling: letter-name notes, enharmonic-aware conversion, and spelled
|
|
3
|
-
* intervals.
|
|
4
|
-
*
|
|
5
|
-
* The rest of the library works in pitch classes (0..11), which cannot tell a
|
|
6
|
-
* G# from an Ab or an augmented fourth from a diminished fifth. This module adds
|
|
7
|
-
* an explicit spelling layer — a note is a diatonic letter plus a chromatic
|
|
8
|
-
* alteration — so interval quality (P/M/m/A/d) and enharmonic identity are
|
|
9
|
-
* preserved.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* A spelled note: a diatonic letter, a chromatic alteration, and an optional
|
|
13
|
-
* octave.
|
|
14
|
-
*
|
|
15
|
-
* - `letter` is 0..6 for C..B.
|
|
16
|
-
* - `alter` is the number of semitones of alteration: -2 double-flat, -1 flat,
|
|
17
|
-
* 0 natural, +1 sharp, +2 double-sharp.
|
|
18
|
-
* - `octave` follows scientific pitch notation (middle C = C4 = MIDI 60). When
|
|
19
|
-
* absent, the note denotes a bare pitch class.
|
|
20
|
-
*
|
|
21
|
-
* @category Pitch & Intervals
|
|
22
|
-
*/
|
|
23
|
-
type Note = {
|
|
24
|
-
letter: number;
|
|
25
|
-
alter: number;
|
|
26
|
-
octave?: number;
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* A spelled interval: a diatonic number, a quality label, and its semitone span.
|
|
30
|
-
*
|
|
31
|
-
* @category Pitch & Intervals
|
|
32
|
-
*/
|
|
33
|
-
type SpelledInterval = {
|
|
34
|
-
/** Diatonic size: 1 = unison, 2 = second, ... 8 = octave, and beyond. */
|
|
35
|
-
number: number;
|
|
36
|
-
/** Quality label: 'P', 'M', 'm', or repeated 'A'/'d' for (multiply) aug/dim. */
|
|
37
|
-
quality: string;
|
|
38
|
-
/** Signed semitone distance from the first note to the second. */
|
|
39
|
-
semitones: number;
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* Parse scientific pitch notation into a {@link Note}.
|
|
43
|
-
*
|
|
44
|
-
* Accepts a letter (case-insensitive) followed by any number of same-direction
|
|
45
|
-
* accidentals and an optional octave, e.g. `"C"`, `"C#4"`, `"Bb"`, `"F##3"`,
|
|
46
|
-
* `"Ebb2"`. Both `#` and `x` (double-sharp) are accepted for sharps; `b` for
|
|
47
|
-
* flats. Mixing sharps and flats (e.g. `"C#b"`) is rejected.
|
|
48
|
-
*
|
|
49
|
-
* @param text The note text.
|
|
50
|
-
* @returns The parsed note.
|
|
51
|
-
* @throws If the text is not a valid note.
|
|
52
|
-
* @example
|
|
53
|
-
* ```ts
|
|
54
|
-
* import { parseNote, noteToMidi } from '@libraz/libcantus';
|
|
55
|
-
* const n = parseNote('C#4');
|
|
56
|
-
* noteToMidi(n); // 61
|
|
57
|
-
* ```
|
|
58
|
-
* @category Pitch & Intervals
|
|
59
|
-
*/
|
|
60
|
-
declare function parseNote(text: string): Note;
|
|
61
|
-
/**
|
|
62
|
-
* Render a {@link Note} as scientific pitch notation.
|
|
63
|
-
*
|
|
64
|
-
* @param note The note to format.
|
|
65
|
-
* @returns The note text, including the octave when present.
|
|
66
|
-
* @example
|
|
67
|
-
* ```ts
|
|
68
|
-
* import { formatNote, parseNote } from '@libraz/libcantus';
|
|
69
|
-
* formatNote(parseNote('C#4')); // 'C#4'
|
|
70
|
-
* ```
|
|
71
|
-
* @category Pitch & Intervals
|
|
72
|
-
*/
|
|
73
|
-
declare function formatNote(note: Note): string;
|
|
74
|
-
/**
|
|
75
|
-
* Pitch class (0..11) of a note, ignoring octave.
|
|
76
|
-
*
|
|
77
|
-
* @param note The note.
|
|
78
|
-
* @returns The pitch class.
|
|
79
|
-
* @example
|
|
80
|
-
* ```ts
|
|
81
|
-
* import { noteToPitchClass, parseNote } from '@libraz/libcantus';
|
|
82
|
-
* noteToPitchClass(parseNote('Db')); // 1
|
|
83
|
-
* ```
|
|
84
|
-
* @category Pitch & Intervals
|
|
85
|
-
*/
|
|
86
|
-
declare function noteToPitchClass(note: Note): number;
|
|
87
|
-
/**
|
|
88
|
-
* MIDI number of a note (middle C = C4 = 60).
|
|
89
|
-
*
|
|
90
|
-
* @param note The note; must carry an octave.
|
|
91
|
-
* @returns The MIDI number.
|
|
92
|
-
* @throws If the note has no octave.
|
|
93
|
-
* @example
|
|
94
|
-
* ```ts
|
|
95
|
-
* import { noteToMidi, parseNote } from '@libraz/libcantus';
|
|
96
|
-
* noteToMidi(parseNote('A4')); // 69
|
|
97
|
-
* ```
|
|
98
|
-
* @category Pitch & Intervals
|
|
99
|
-
*/
|
|
100
|
-
declare function noteToMidi(note: Note): number;
|
|
101
|
-
/**
|
|
102
|
-
* Name a MIDI number as a {@link Note}, choosing sharp or flat spelling.
|
|
103
|
-
*
|
|
104
|
-
* The input is rounded to the nearest integer but is not clamped to the MIDI
|
|
105
|
-
* range 0..127: out-of-range values extrapolate linearly (e.g. `-1` -> `B-2`,
|
|
106
|
-
* `128` -> `G#9`) and remain an exact inverse of {@link noteToMidi}.
|
|
107
|
-
*
|
|
108
|
-
* @param midi The MIDI number.
|
|
109
|
-
* @param spelling Whether to prefer sharps or flats for black keys.
|
|
110
|
-
* @returns The spelled note, with octave.
|
|
111
|
-
* @example
|
|
112
|
-
* ```ts
|
|
113
|
-
* import { midiToNote, formatNote } from '@libraz/libcantus';
|
|
114
|
-
* formatNote(midiToNote(61)); // 'C#4'
|
|
115
|
-
* formatNote(midiToNote(61, 'flat')); // 'Db4'
|
|
116
|
-
* ```
|
|
117
|
-
* @category Pitch & Intervals
|
|
118
|
-
*/
|
|
119
|
-
declare function midiToNote(midi: number, spelling?: 'sharp' | 'flat'): Note;
|
|
120
|
-
/**
|
|
121
|
-
* The spelled interval from one note to another.
|
|
122
|
-
*
|
|
123
|
-
* When both notes carry octaves, the interval reflects their full signed
|
|
124
|
-
* distance (so `C4 -> C5` is a perfect octave). When either lacks an octave the
|
|
125
|
-
* interval is measured within a single ascending octave from `a` to `b`.
|
|
126
|
-
*
|
|
127
|
-
* @param a The lower/first note.
|
|
128
|
-
* @param b The upper/second note.
|
|
129
|
-
* @returns The diatonic number, quality, and semitone span.
|
|
130
|
-
* @example
|
|
131
|
-
* ```ts
|
|
132
|
-
* import { spelledInterval, parseNote } from '@libraz/libcantus';
|
|
133
|
-
* spelledInterval(parseNote('C4'), parseNote('G4'));
|
|
134
|
-
* // { number: 5, quality: 'P', semitones: 7 }
|
|
135
|
-
* ```
|
|
136
|
-
* @category Pitch & Intervals
|
|
137
|
-
*/
|
|
138
|
-
declare function spelledInterval(a: Note, b: Note): SpelledInterval;
|
|
139
|
-
|
|
140
|
-
export { type Note as N, type SpelledInterval as S, noteToPitchClass as a, formatNote as f, midiToNote as m, noteToMidi as n, parseNote as p, spelledInterval as s };
|
package/dist/index-CGMZNCx6.d.ts
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pitch spelling: letter-name notes, enharmonic-aware conversion, and spelled
|
|
3
|
-
* intervals.
|
|
4
|
-
*
|
|
5
|
-
* The rest of the library works in pitch classes (0..11), which cannot tell a
|
|
6
|
-
* G# from an Ab or an augmented fourth from a diminished fifth. This module adds
|
|
7
|
-
* an explicit spelling layer — a note is a diatonic letter plus a chromatic
|
|
8
|
-
* alteration — so interval quality (P/M/m/A/d) and enharmonic identity are
|
|
9
|
-
* preserved.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* A spelled note: a diatonic letter, a chromatic alteration, and an optional
|
|
13
|
-
* octave.
|
|
14
|
-
*
|
|
15
|
-
* - `letter` is 0..6 for C..B.
|
|
16
|
-
* - `alter` is the number of semitones of alteration: -2 double-flat, -1 flat,
|
|
17
|
-
* 0 natural, +1 sharp, +2 double-sharp.
|
|
18
|
-
* - `octave` follows scientific pitch notation (middle C = C4 = MIDI 60). When
|
|
19
|
-
* absent, the note denotes a bare pitch class.
|
|
20
|
-
*
|
|
21
|
-
* @category Pitch & Intervals
|
|
22
|
-
*/
|
|
23
|
-
type Note = {
|
|
24
|
-
letter: number;
|
|
25
|
-
alter: number;
|
|
26
|
-
octave?: number;
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* A spelled interval: a diatonic number, a quality label, and its semitone span.
|
|
30
|
-
*
|
|
31
|
-
* @category Pitch & Intervals
|
|
32
|
-
*/
|
|
33
|
-
type SpelledInterval = {
|
|
34
|
-
/** Diatonic size: 1 = unison, 2 = second, ... 8 = octave, and beyond. */
|
|
35
|
-
number: number;
|
|
36
|
-
/** Quality label: 'P', 'M', 'm', or repeated 'A'/'d' for (multiply) aug/dim. */
|
|
37
|
-
quality: string;
|
|
38
|
-
/** Signed semitone distance from the first note to the second. */
|
|
39
|
-
semitones: number;
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* Parse scientific pitch notation into a {@link Note}.
|
|
43
|
-
*
|
|
44
|
-
* Accepts a letter (case-insensitive) followed by any number of same-direction
|
|
45
|
-
* accidentals and an optional octave, e.g. `"C"`, `"C#4"`, `"Bb"`, `"F##3"`,
|
|
46
|
-
* `"Ebb2"`. Both `#` and `x` (double-sharp) are accepted for sharps; `b` for
|
|
47
|
-
* flats. Mixing sharps and flats (e.g. `"C#b"`) is rejected.
|
|
48
|
-
*
|
|
49
|
-
* @param text The note text.
|
|
50
|
-
* @returns The parsed note.
|
|
51
|
-
* @throws If the text is not a valid note.
|
|
52
|
-
* @example
|
|
53
|
-
* ```ts
|
|
54
|
-
* import { parseNote, noteToMidi } from '@libraz/libcantus';
|
|
55
|
-
* const n = parseNote('C#4');
|
|
56
|
-
* noteToMidi(n); // 61
|
|
57
|
-
* ```
|
|
58
|
-
* @category Pitch & Intervals
|
|
59
|
-
*/
|
|
60
|
-
declare function parseNote(text: string): Note;
|
|
61
|
-
/**
|
|
62
|
-
* Render a {@link Note} as scientific pitch notation.
|
|
63
|
-
*
|
|
64
|
-
* @param note The note to format.
|
|
65
|
-
* @returns The note text, including the octave when present.
|
|
66
|
-
* @example
|
|
67
|
-
* ```ts
|
|
68
|
-
* import { formatNote, parseNote } from '@libraz/libcantus';
|
|
69
|
-
* formatNote(parseNote('C#4')); // 'C#4'
|
|
70
|
-
* ```
|
|
71
|
-
* @category Pitch & Intervals
|
|
72
|
-
*/
|
|
73
|
-
declare function formatNote(note: Note): string;
|
|
74
|
-
/**
|
|
75
|
-
* Pitch class (0..11) of a note, ignoring octave.
|
|
76
|
-
*
|
|
77
|
-
* @param note The note.
|
|
78
|
-
* @returns The pitch class.
|
|
79
|
-
* @example
|
|
80
|
-
* ```ts
|
|
81
|
-
* import { noteToPitchClass, parseNote } from '@libraz/libcantus';
|
|
82
|
-
* noteToPitchClass(parseNote('Db')); // 1
|
|
83
|
-
* ```
|
|
84
|
-
* @category Pitch & Intervals
|
|
85
|
-
*/
|
|
86
|
-
declare function noteToPitchClass(note: Note): number;
|
|
87
|
-
/**
|
|
88
|
-
* MIDI number of a note (middle C = C4 = 60).
|
|
89
|
-
*
|
|
90
|
-
* @param note The note; must carry an octave.
|
|
91
|
-
* @returns The MIDI number.
|
|
92
|
-
* @throws If the note has no octave.
|
|
93
|
-
* @example
|
|
94
|
-
* ```ts
|
|
95
|
-
* import { noteToMidi, parseNote } from '@libraz/libcantus';
|
|
96
|
-
* noteToMidi(parseNote('A4')); // 69
|
|
97
|
-
* ```
|
|
98
|
-
* @category Pitch & Intervals
|
|
99
|
-
*/
|
|
100
|
-
declare function noteToMidi(note: Note): number;
|
|
101
|
-
/**
|
|
102
|
-
* Name a MIDI number as a {@link Note}, choosing sharp or flat spelling.
|
|
103
|
-
*
|
|
104
|
-
* The input is rounded to the nearest integer but is not clamped to the MIDI
|
|
105
|
-
* range 0..127: out-of-range values extrapolate linearly (e.g. `-1` -> `B-2`,
|
|
106
|
-
* `128` -> `G#9`) and remain an exact inverse of {@link noteToMidi}.
|
|
107
|
-
*
|
|
108
|
-
* @param midi The MIDI number.
|
|
109
|
-
* @param spelling Whether to prefer sharps or flats for black keys.
|
|
110
|
-
* @returns The spelled note, with octave.
|
|
111
|
-
* @example
|
|
112
|
-
* ```ts
|
|
113
|
-
* import { midiToNote, formatNote } from '@libraz/libcantus';
|
|
114
|
-
* formatNote(midiToNote(61)); // 'C#4'
|
|
115
|
-
* formatNote(midiToNote(61, 'flat')); // 'Db4'
|
|
116
|
-
* ```
|
|
117
|
-
* @category Pitch & Intervals
|
|
118
|
-
*/
|
|
119
|
-
declare function midiToNote(midi: number, spelling?: 'sharp' | 'flat'): Note;
|
|
120
|
-
/**
|
|
121
|
-
* The spelled interval from one note to another.
|
|
122
|
-
*
|
|
123
|
-
* When both notes carry octaves, the interval reflects their full signed
|
|
124
|
-
* distance (so `C4 -> C5` is a perfect octave). When either lacks an octave the
|
|
125
|
-
* interval is measured within a single ascending octave from `a` to `b`.
|
|
126
|
-
*
|
|
127
|
-
* @param a The lower/first note.
|
|
128
|
-
* @param b The upper/second note.
|
|
129
|
-
* @returns The diatonic number, quality, and semitone span.
|
|
130
|
-
* @example
|
|
131
|
-
* ```ts
|
|
132
|
-
* import { spelledInterval, parseNote } from '@libraz/libcantus';
|
|
133
|
-
* spelledInterval(parseNote('C4'), parseNote('G4'));
|
|
134
|
-
* // { number: 5, quality: 'P', semitones: 7 }
|
|
135
|
-
* ```
|
|
136
|
-
* @category Pitch & Intervals
|
|
137
|
-
*/
|
|
138
|
-
declare function spelledInterval(a: Note, b: Note): SpelledInterval;
|
|
139
|
-
|
|
140
|
-
export { type Note as N, type SpelledInterval as S, noteToPitchClass as a, formatNote as f, midiToNote as m, noteToMidi as n, parseNote as p, spelledInterval as s };
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { K as KeyScale } from './types-MGP29r3t.cjs';
|
|
2
|
-
import { a as ChordQuality, C as Chord } from './index-BNlGP86A.cjs';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Recognition: infer a chord name from a set of pitches, or a key from a set of
|
|
6
|
-
* pitch classes. This is the inverse direction of the chord/scale builders,
|
|
7
|
-
* which only go name -> notes.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* A candidate chord interpretation of a pitch set.
|
|
12
|
-
*
|
|
13
|
-
* @category Recognition
|
|
14
|
-
*/
|
|
15
|
-
type ChordMatch = {
|
|
16
|
-
rootPc: number;
|
|
17
|
-
quality: ChordQuality;
|
|
18
|
-
/** Chord tones absent from the input (an incomplete voicing). */
|
|
19
|
-
missingPcs: number[];
|
|
20
|
-
/** Input pitch classes not belonging to the chord. */
|
|
21
|
-
extraPcs: number[];
|
|
22
|
-
/** True when the input pitch-class set equals the chord exactly. */
|
|
23
|
-
exact: boolean;
|
|
24
|
-
/** Inversion implied by a known bass, or null for an unordered pitch-class set. */
|
|
25
|
-
inversion: number | null;
|
|
26
|
-
/** Bass pitch class when inverted (the lowest note is not the root). */
|
|
27
|
-
bassPc?: number;
|
|
28
|
-
};
|
|
29
|
-
/** Input interpretation for {@link detectChord} and {@link detectChordBest}. */
|
|
30
|
-
type DetectChordOptions = {
|
|
31
|
-
/**
|
|
32
|
-
* `midi` uses the numerically lowest pitch as bass; `pitchClass` treats the
|
|
33
|
-
* input as unordered. `auto` (default) selects pitch-class mode only when all
|
|
34
|
-
* values lie in 0..11.
|
|
35
|
-
*/
|
|
36
|
-
input?: 'auto' | 'midi' | 'pitchClass';
|
|
37
|
-
/** Explicit bass pitch class, including for an unordered pitch-class set. */
|
|
38
|
-
bassPc?: number;
|
|
39
|
-
};
|
|
40
|
-
/**
|
|
41
|
-
* A candidate key interpretation of a pitch-class set.
|
|
42
|
-
*
|
|
43
|
-
* @category Recognition
|
|
44
|
-
*/
|
|
45
|
-
type KeyMatch = {
|
|
46
|
-
key: KeyScale;
|
|
47
|
-
mode: 'major' | 'minor';
|
|
48
|
-
/** Fraction of input pitch classes that are in the scale, in [0, 1]. */
|
|
49
|
-
fit: number;
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Identify chords matching a set of pitches.
|
|
53
|
-
*
|
|
54
|
-
* Every input pitch class is tried as a root against every known chord quality.
|
|
55
|
-
* A match is reported when all of the chord's tones are present in the input, or
|
|
56
|
-
* when the only absent tone is the perfect fifth (a common omission in shell
|
|
57
|
-
* voicings); matches are ranked best-first by fewest extra notes, then fewest
|
|
58
|
-
* missing notes, then most specific (largest) chord. An exact match (no extras,
|
|
59
|
-
* no missing) is flagged and ranked first.
|
|
60
|
-
*
|
|
61
|
-
* @param pitches MIDI pitches or bare pitch classes (octave-agnostic).
|
|
62
|
-
* @returns Ranked chord interpretations (may be empty).
|
|
63
|
-
* @example
|
|
64
|
-
* ```ts
|
|
65
|
-
* import { detectChord } from '@libraz/libcantus';
|
|
66
|
-
* const matches = detectChord([60, 64, 67]); // C E G
|
|
67
|
-
* matches[0]; // { rootPc: 0, quality: 'maj', exact: true, ... }
|
|
68
|
-
* ```
|
|
69
|
-
* @category Recognition
|
|
70
|
-
*/
|
|
71
|
-
declare function detectChord(pitches: number[], opts?: DetectChordOptions): ChordMatch[];
|
|
72
|
-
/**
|
|
73
|
-
* The single best chord interpretation of a pitch set, or null if none.
|
|
74
|
-
*
|
|
75
|
-
* @param pitches MIDI pitches or bare pitch classes.
|
|
76
|
-
* @returns The top-ranked chord, or null when nothing matches.
|
|
77
|
-
* @example
|
|
78
|
-
* ```ts
|
|
79
|
-
* import { detectChordBest } from '@libraz/libcantus';
|
|
80
|
-
* detectChordBest([60, 64, 67]); // C major triad: { rootPc: 0, quality: 'maj', ... }
|
|
81
|
-
* ```
|
|
82
|
-
* @category Recognition
|
|
83
|
-
*/
|
|
84
|
-
declare function detectChordBest(pitches: number[], opts?: DetectChordOptions): Chord | null;
|
|
85
|
-
/**
|
|
86
|
-
* Rank major and minor keys by how well they contain a set of pitch classes.
|
|
87
|
-
*
|
|
88
|
-
* The tonic is weighted so that, among equally-fitting keys, the one whose root
|
|
89
|
-
* appears in the input is preferred. Minor candidates are scored against the
|
|
90
|
-
* natural, harmonic, and melodic minor variants and keep the best of the three,
|
|
91
|
-
* so a minor cadence containing the leading tone still resolves to its own
|
|
92
|
-
* tonic; the returned key is always the natural-minor scale. Returns all 24
|
|
93
|
-
* keys ranked best-first, or an empty array for an empty input (mirroring
|
|
94
|
-
* {@link detectChord}).
|
|
95
|
-
*
|
|
96
|
-
* @param pitches MIDI pitches or bare pitch classes.
|
|
97
|
-
* @returns Ranked key interpretations (empty for an empty input).
|
|
98
|
-
* @example
|
|
99
|
-
* ```ts
|
|
100
|
-
* import { detectKey } from '@libraz/libcantus';
|
|
101
|
-
* const keys = detectKey([60, 62, 64, 65, 67, 69, 71]); // C major scale
|
|
102
|
-
* keys[0].mode; // 'major', with keys[0].key.rootPc === 0
|
|
103
|
-
* ```
|
|
104
|
-
* @category Recognition
|
|
105
|
-
*/
|
|
106
|
-
declare function detectKey(pitches: number[]): KeyMatch[];
|
|
107
|
-
|
|
108
|
-
export { type ChordMatch as C, type DetectChordOptions as D, type KeyMatch as K, detectChordBest as a, detectKey as b, detectChord as d };
|
package/dist/index-JnF4v9bx.d.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { K as KeyScale } from './types-MGP29r3t.js';
|
|
2
|
-
import { a as ChordQuality, C as Chord } from './index-Bt4tOUD9.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Recognition: infer a chord name from a set of pitches, or a key from a set of
|
|
6
|
-
* pitch classes. This is the inverse direction of the chord/scale builders,
|
|
7
|
-
* which only go name -> notes.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* A candidate chord interpretation of a pitch set.
|
|
12
|
-
*
|
|
13
|
-
* @category Recognition
|
|
14
|
-
*/
|
|
15
|
-
type ChordMatch = {
|
|
16
|
-
rootPc: number;
|
|
17
|
-
quality: ChordQuality;
|
|
18
|
-
/** Chord tones absent from the input (an incomplete voicing). */
|
|
19
|
-
missingPcs: number[];
|
|
20
|
-
/** Input pitch classes not belonging to the chord. */
|
|
21
|
-
extraPcs: number[];
|
|
22
|
-
/** True when the input pitch-class set equals the chord exactly. */
|
|
23
|
-
exact: boolean;
|
|
24
|
-
/** Inversion implied by a known bass, or null for an unordered pitch-class set. */
|
|
25
|
-
inversion: number | null;
|
|
26
|
-
/** Bass pitch class when inverted (the lowest note is not the root). */
|
|
27
|
-
bassPc?: number;
|
|
28
|
-
};
|
|
29
|
-
/** Input interpretation for {@link detectChord} and {@link detectChordBest}. */
|
|
30
|
-
type DetectChordOptions = {
|
|
31
|
-
/**
|
|
32
|
-
* `midi` uses the numerically lowest pitch as bass; `pitchClass` treats the
|
|
33
|
-
* input as unordered. `auto` (default) selects pitch-class mode only when all
|
|
34
|
-
* values lie in 0..11.
|
|
35
|
-
*/
|
|
36
|
-
input?: 'auto' | 'midi' | 'pitchClass';
|
|
37
|
-
/** Explicit bass pitch class, including for an unordered pitch-class set. */
|
|
38
|
-
bassPc?: number;
|
|
39
|
-
};
|
|
40
|
-
/**
|
|
41
|
-
* A candidate key interpretation of a pitch-class set.
|
|
42
|
-
*
|
|
43
|
-
* @category Recognition
|
|
44
|
-
*/
|
|
45
|
-
type KeyMatch = {
|
|
46
|
-
key: KeyScale;
|
|
47
|
-
mode: 'major' | 'minor';
|
|
48
|
-
/** Fraction of input pitch classes that are in the scale, in [0, 1]. */
|
|
49
|
-
fit: number;
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Identify chords matching a set of pitches.
|
|
53
|
-
*
|
|
54
|
-
* Every input pitch class is tried as a root against every known chord quality.
|
|
55
|
-
* A match is reported when all of the chord's tones are present in the input, or
|
|
56
|
-
* when the only absent tone is the perfect fifth (a common omission in shell
|
|
57
|
-
* voicings); matches are ranked best-first by fewest extra notes, then fewest
|
|
58
|
-
* missing notes, then most specific (largest) chord. An exact match (no extras,
|
|
59
|
-
* no missing) is flagged and ranked first.
|
|
60
|
-
*
|
|
61
|
-
* @param pitches MIDI pitches or bare pitch classes (octave-agnostic).
|
|
62
|
-
* @returns Ranked chord interpretations (may be empty).
|
|
63
|
-
* @example
|
|
64
|
-
* ```ts
|
|
65
|
-
* import { detectChord } from '@libraz/libcantus';
|
|
66
|
-
* const matches = detectChord([60, 64, 67]); // C E G
|
|
67
|
-
* matches[0]; // { rootPc: 0, quality: 'maj', exact: true, ... }
|
|
68
|
-
* ```
|
|
69
|
-
* @category Recognition
|
|
70
|
-
*/
|
|
71
|
-
declare function detectChord(pitches: number[], opts?: DetectChordOptions): ChordMatch[];
|
|
72
|
-
/**
|
|
73
|
-
* The single best chord interpretation of a pitch set, or null if none.
|
|
74
|
-
*
|
|
75
|
-
* @param pitches MIDI pitches or bare pitch classes.
|
|
76
|
-
* @returns The top-ranked chord, or null when nothing matches.
|
|
77
|
-
* @example
|
|
78
|
-
* ```ts
|
|
79
|
-
* import { detectChordBest } from '@libraz/libcantus';
|
|
80
|
-
* detectChordBest([60, 64, 67]); // C major triad: { rootPc: 0, quality: 'maj', ... }
|
|
81
|
-
* ```
|
|
82
|
-
* @category Recognition
|
|
83
|
-
*/
|
|
84
|
-
declare function detectChordBest(pitches: number[], opts?: DetectChordOptions): Chord | null;
|
|
85
|
-
/**
|
|
86
|
-
* Rank major and minor keys by how well they contain a set of pitch classes.
|
|
87
|
-
*
|
|
88
|
-
* The tonic is weighted so that, among equally-fitting keys, the one whose root
|
|
89
|
-
* appears in the input is preferred. Minor candidates are scored against the
|
|
90
|
-
* natural, harmonic, and melodic minor variants and keep the best of the three,
|
|
91
|
-
* so a minor cadence containing the leading tone still resolves to its own
|
|
92
|
-
* tonic; the returned key is always the natural-minor scale. Returns all 24
|
|
93
|
-
* keys ranked best-first, or an empty array for an empty input (mirroring
|
|
94
|
-
* {@link detectChord}).
|
|
95
|
-
*
|
|
96
|
-
* @param pitches MIDI pitches or bare pitch classes.
|
|
97
|
-
* @returns Ranked key interpretations (empty for an empty input).
|
|
98
|
-
* @example
|
|
99
|
-
* ```ts
|
|
100
|
-
* import { detectKey } from '@libraz/libcantus';
|
|
101
|
-
* const keys = detectKey([60, 62, 64, 65, 67, 69, 71]); // C major scale
|
|
102
|
-
* keys[0].mode; // 'major', with keys[0].key.rootPc === 0
|
|
103
|
-
* ```
|
|
104
|
-
* @category Recognition
|
|
105
|
-
*/
|
|
106
|
-
declare function detectKey(pitches: number[]): KeyMatch[];
|
|
107
|
-
|
|
108
|
-
export { type ChordMatch as C, type DetectChordOptions as D, type KeyMatch as K, detectChordBest as a, detectKey as b, detectChord as d };
|