@libraz/libcantus 0.9.2 → 0.9.3
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 +4 -3
- package/dist/analyze/index.cjs +315 -42
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +11 -99
- package/dist/analyze/index.d.ts +11 -99
- package/dist/analyze/index.js +6 -6
- package/dist/chunk-2ZWMSJH6.js +30 -0
- package/dist/chunk-2ZWMSJH6.js.map +1 -0
- package/dist/{chunk-R3S2LUBH.js → chunk-4MHA432G.js} +316 -184
- package/dist/chunk-4MHA432G.js.map +1 -0
- package/dist/chunk-62QZKCJQ.js +49 -0
- package/dist/chunk-62QZKCJQ.js.map +1 -0
- package/dist/chunk-AKLYPWIN.js +83 -0
- package/dist/chunk-AKLYPWIN.js.map +1 -0
- package/dist/{chunk-XTC3X6MS.js → chunk-C5XYKUVG.js} +100 -12
- package/dist/chunk-C5XYKUVG.js.map +1 -0
- package/dist/{chunk-LN7ZZMD2.js → chunk-CHMXELDS.js} +33 -14
- package/dist/chunk-CHMXELDS.js.map +1 -0
- package/dist/{chunk-A4532ZFR.js → chunk-EH6EM37U.js} +60 -4
- package/dist/chunk-EH6EM37U.js.map +1 -0
- package/dist/chunk-FBQK3ZQN.js +131 -0
- package/dist/chunk-FBQK3ZQN.js.map +1 -0
- package/dist/{chunk-5HTNMQW4.js → chunk-GOAW4VYL.js} +87 -21
- package/dist/chunk-GOAW4VYL.js.map +1 -0
- package/dist/{chunk-MSWFZF7J.js → chunk-I5R7ZBJS.js} +90 -6
- package/dist/chunk-I5R7ZBJS.js.map +1 -0
- package/dist/{chunk-GQKN5KDT.js → chunk-IT2O4XFE.js} +4 -9
- package/dist/chunk-IT2O4XFE.js.map +1 -0
- package/dist/{chunk-7Y7WF64D.js → chunk-MIWO425M.js} +6 -4
- package/dist/chunk-MIWO425M.js.map +1 -0
- package/dist/chunk-N6IHQUOX.js +1 -0
- package/dist/chunk-N6IHQUOX.js.map +1 -0
- package/dist/{chunk-COKTX2G5.js → chunk-SGU7SPLK.js} +29 -12
- package/dist/chunk-SGU7SPLK.js.map +1 -0
- package/dist/core/index.cjs +230 -14
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +56 -4
- package/dist/core/index.d.ts +56 -4
- package/dist/core/index.js +24 -4
- package/dist/{function-2bJW1Zp_.d.ts → function-DVH4Eusr.d.ts} +1 -1
- package/dist/{function-r2sh-jOO.d.cts → function-DYt4iKsn.d.cts} +1 -1
- package/dist/generate/index.cjs +830 -494
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +11 -5
- package/dist/generate/index.d.ts +11 -5
- package/dist/generate/index.js +9 -9
- package/dist/{index-BOBXBNwP.d.cts → index-BNlGP86A.d.cts} +1 -1
- package/dist/{index-CP3wAfEH.d.ts → index-Bg5dYMmZ.d.ts} +1 -1
- package/dist/{index-CM5W4rcm.d.ts → index-Bt4tOUD9.d.ts} +1 -1
- package/dist/index-CnZCo29u.d.cts +108 -0
- package/dist/{index-D_ZTUNKp.d.cts → index-CpOsP1y9.d.cts} +2 -2
- package/dist/{index-DZ1M21do.d.cts → index-CxqBQtH1.d.cts} +2 -1
- package/dist/{index-BdeQ1r_p.d.cts → index-Dikst44v.d.cts} +1 -1
- package/dist/{index-BMPxwjwV.d.ts → index-DxvARIP2.d.ts} +2 -2
- package/dist/{index-BreoJRw0.d.ts → index-Jc0Ryi79.d.ts} +2 -1
- package/dist/index-JnF4v9bx.d.ts +108 -0
- package/dist/index.cjs +818 -283
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -8
- package/dist/index.d.ts +9 -8
- package/dist/index.js +34 -13
- package/dist/model/index.cjs +170 -31
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +6 -5
- package/dist/model/index.d.ts +6 -5
- package/dist/model/index.js +6 -6
- package/dist/{styled-D7BAx3S3.d.ts → styled-DZ7GjShb.d.ts} +1 -1
- package/dist/{styled-BjXtOFNk.d.cts → styled-ZTbdaVFM.d.cts} +1 -1
- package/dist/theory/index.cjs +180 -34
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +6 -6
- package/dist/theory/index.d.ts +6 -6
- package/dist/theory/index.js +6 -5
- package/package.json +50 -19
- package/src/analyze/arrange/internal.ts +3 -1
- package/src/analyze/arrange/tension.ts +15 -3
- package/src/analyze/arrange/tracks.ts +36 -3
- package/src/analyze/detect/index.ts +46 -9
- package/src/analyze/functional/roman.ts +14 -5
- package/src/analyze/index.ts +1 -1
- package/src/analyze/timeline/index.ts +43 -7
- package/src/analyze/voice/index.ts +11 -2
- package/src/core/event-index/index.ts +104 -0
- package/src/core/index.ts +14 -0
- package/src/core/meter/index.ts +24 -4
- package/src/core/random/index.ts +26 -3
- package/src/core/tuning/index.ts +36 -6
- package/src/core/validation/index.ts +119 -0
- package/src/generate/bass/index.ts +23 -0
- package/src/generate/countermelody/index.ts +167 -76
- package/src/generate/drums/euclid.ts +10 -3
- package/src/generate/drums/index.ts +56 -24
- package/src/generate/drums/percussion.ts +1 -1
- package/src/generate/groove/index.ts +25 -0
- package/src/generate/harmonize/index.ts +55 -44
- package/src/generate/index.ts +0 -1
- package/src/generate/motif/index.ts +45 -21
- package/src/generate/progression/index.ts +8 -16
- package/src/generate/reharmony/index.ts +1 -8
- package/src/generate/rhythm/index.ts +11 -1
- package/src/index.ts +13 -247
- package/src/model/chord.ts +29 -10
- package/src/theory/chord/index.ts +4 -2
- package/src/theory/harmony/index.ts +6 -21
- package/src/theory/index.ts +6 -1
- package/src/theory/safety/index.ts +71 -2
- package/src/theory/spelling/index.ts +70 -3
- package/src/theory/voicing/satb.ts +25 -4
- package/src/theory/voicing/styled.ts +26 -3
- package/dist/chunk-5HTNMQW4.js.map +0 -1
- package/dist/chunk-7Y7WF64D.js.map +0 -1
- package/dist/chunk-A4532ZFR.js.map +0 -1
- package/dist/chunk-BHUT2S5G.js +0 -22
- package/dist/chunk-BHUT2S5G.js.map +0 -1
- package/dist/chunk-CCBLVAPK.js +0 -42
- package/dist/chunk-CCBLVAPK.js.map +0 -1
- package/dist/chunk-COKTX2G5.js.map +0 -1
- package/dist/chunk-GQKN5KDT.js.map +0 -1
- package/dist/chunk-LN7ZZMD2.js.map +0 -1
- package/dist/chunk-MSWFZF7J.js.map +0 -1
- package/dist/chunk-R3S2LUBH.js.map +0 -1
- package/dist/chunk-SDM3VJJ5.js +0 -41
- package/dist/chunk-SDM3VJJ5.js.map +0 -1
- package/dist/chunk-XTC3X6MS.js.map +0 -1
- package/dist/chunk-ZXW5YIWK.js +0 -55
- package/dist/chunk-ZXW5YIWK.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
export { AnalyzedNote, ArrangementAnalysis, ArrangementOptions, ArrangementTrack,
|
|
2
|
-
export {
|
|
3
|
-
export { C as
|
|
4
|
-
export {
|
|
1
|
+
export { AnalyzedNote, ArrangementAnalysis, ArrangementOptions, ArrangementTrack, Conflict, TensionPoint, TheoryLabel, TrackAnalysis, TrackRole, VoiceNote, analyzeArrangement, analyzeVoice, chordToRoman, romanToChord, tensionCurve } from './analyze/index.cjs';
|
|
2
|
+
export { C as ChordMatch, D as DetectChordOptions, K as KeyMatch, d as detectChord, a as detectChordBest, b as detectKey } from './index-CnZCo29u.cjs';
|
|
3
|
+
export { B as BorrowedSource, C as Cadence, a as ChordAnalysis, H as HarmonicFunction, b as analyzeChord, c as borrowedSource, d as detectCadence, f as functionOf, i as isBorrowedChord, e as isDiatonic, g as isMinorKey, p as parallelKey, s as secondaryDominant } from './function-DYt4iKsn.cjs';
|
|
4
|
+
export { C as CadenceHit, a as ChordSegment, b as ChordTimeline, c as ChordTimelineOptions, d as ChordTimelineResult, e as chordTimelineFromChords, f as chordTimelineFromNotes, g as detectCadences } from './index-CpOsP1y9.cjs';
|
|
5
|
+
export { DEFAULT_GENERATION_BUDGET, IndexedNoteEvent, IntervalQuality, JUST_RATIOS, NoteEventIndex, Rng, TWELVE_TET, Tuning, assertFiniteNumber, assertGenerationBudget, assertInteger, assertNoteEvent, assertNoteEvents, assertPositiveInt, assertRange, assertTimeSignature, centsBetweenFreq, centsOfSteps, classifyInterval, createNoteEventIndex, createRng, edo, frequencyOf, isConsonantInterval, isPerfectInterval, justDeviationCents, nearestStep, ratioToCents } from './core/index.cjs';
|
|
5
6
|
export { B as BarPosition, T as TimeSignature, b as barPositionToBeat, a as beatToBarPosition, c as beatsPerBar, f as formatTimeSignature, i as isCompound, d as isStrongBeat, m as metricWeight, p as parseTimeSignature, e as pulsesPerBar, t as tuplet } from './index-Cl7mhOFM.cjs';
|
|
6
7
|
export { N as NoteData, S as SpelledInterval, f as formatNote, m as midiToNote, n as noteToMidi, a as noteToPitchClass, p as parseNote, s as spelledInterval } from './index-CGMZNCx6.cjs';
|
|
7
8
|
export { K as KeyScale, N as NoteEvent } from './types-MGP29r3t.cjs';
|
|
8
9
|
export { BassLineOptions, BassSegment, BassStyle, BorrowedChord, CounterMelodyOptions, DrumHit, DrumRole, DrumsOptions, EuclideanKick, GrooveFeel, GrooveSlot, GrooveStyle, GrooveTemplate, HarmonizeOptions, HarmonizeResult, HumanizeOptions, MelodyNote, MotifCell, MotifContour, MotifNote, MotifOptions, MotifTransform, ProgFunction, ProgStyle, ProgressionOptions, ProgressionPreset, RhythmEvent, RhythmOptions, Section, SubstituteOptions, Substitution, SubstitutionType, applyGrooveTemplate, developMotif, extractGrooveTemplate, generateBassLine, generateCounterMelody, generateDrums, generateMotif, generateProgression, generateRhythm, harmonizeMelody, humanize, modalInterchangePalette, negativeHarmonyMirror, onsetWeightCurve, progressions, progressionsByStyle, rhythmDensity, substituteChord, transformMotif } from './generate/index.cjs';
|
|
9
10
|
export { Chord, Interval, Key, Note, Progression } from './model/index.cjs';
|
|
10
|
-
export { C as ChordData, a as ChordQuality, b as ChordSpan, c as chordFromDegree, d as chordPitchClasses, e as chordQualities, f as chordToneRole, g as diatonicSeventh, h as diatonicTriad, m as makeChord } from './index-
|
|
11
|
-
export { C as ChordScaleMatch, a as ChordScaleReportEntry, S as SATB_RANGES, b as ScaleChoice, c as StyledVoicingOptions, V as VoiceRange, d as VoicingOptions, e as VoicingStyle, f as availableTensions, g as avoidNotes, h as chordScaleReport, i as chordScales, s as scaleMatchesChord, j as scalesForChanges, v as voiceChord, k as voiceChordStyled, l as voiceProgression } from './styled-
|
|
11
|
+
export { C as ChordData, a as ChordQuality, b as ChordSpan, P as PitchSpelling, c as chordFromDegree, d as chordPitchClasses, e as chordQualities, f as chordToneRole, g as diatonicSeventh, h as diatonicTriad, m as makeChord } from './index-BNlGP86A.cjs';
|
|
12
|
+
export { C as ChordScaleMatch, a as ChordScaleReportEntry, S as SATB_RANGES, b as ScaleChoice, c as StyledVoicingOptions, V as VoiceRange, d as VoicingOptions, e as VoicingStyle, f as availableTensions, g as avoidNotes, h as chordScaleReport, i as chordScales, s as scaleMatchesChord, j as scalesForChanges, v as voiceChord, k as voiceChordStyled, l as voiceProgression } from './styled-ZTbdaVFM.cjs';
|
|
12
13
|
export { BLUES_MASK, CHROMATIC_MASK, DORIAN_MASK, HARMONIC_MINOR_MASK, LOCRIAN_MASK, LYDIAN_MASK, MAJOR_MASK, MAJOR_PENTATONIC_MASK, MELODIC_MINOR_MASK, MINOR_PENTATONIC_MASK, MIXOLYDIAN_MASK, NAMED_SCALES, NATURAL_MINOR_MASK, OCTATONIC_HALF_WHOLE_MASK, OCTATONIC_WHOLE_HALF_MASK, PHRYGIAN_MASK, WHOLE_TONE_MASK, createsHiddenParallelPerfect, createsParallelOctave, createsParallelPerfect, createsParallelUnison, createsVerticalDissonance, createsVoiceCrossing, createsVoiceOverlap, diatonicPitchClasses, exceedsSpacing, formatChordSymbol, isForbiddenMelodicLeap, isLeadingToneResolution, isScaleTone, majorKey, maskFromOffsets, minorKey, nearestScaleTone, nextVoicing, noteNames, parseChordSymbol, pitchToScaleDegree, scaleByName, scaleTonesInDegreeOrder, spellChord, spellPitchClass, spellPitchClasses, spellScale, transposeChordSymbol, voiceLeadingCost } from './theory/index.cjs';
|
|
13
|
-
export { H as HarmonyRole, L as LockLevel, V as VoicedRole, r as roleOf } from './index-
|
|
14
|
-
export { N as NoteSafety, R as ReasonFlag, S as SafetyProfile, a as SafetyQuery, b as SafetyResult, V as VoiceSnapshot, e as enumerateSafePitches, c as evaluateSafety } from './index-
|
|
14
|
+
export { H as HarmonyRole, L as LockLevel, V as VoicedRole, r as roleOf } from './index-Dikst44v.cjs';
|
|
15
|
+
export { N as NoteSafety, R as ReasonFlag, S as SafetyProfile, a as SafetyQuery, b as SafetyResult, V as VoiceSnapshot, e as enumerateSafePitches, c as evaluateSafety } from './index-CxqBQtH1.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
export { AnalyzedNote, ArrangementAnalysis, ArrangementOptions, ArrangementTrack,
|
|
2
|
-
export {
|
|
3
|
-
export { C as
|
|
4
|
-
export {
|
|
1
|
+
export { AnalyzedNote, ArrangementAnalysis, ArrangementOptions, ArrangementTrack, Conflict, TensionPoint, TheoryLabel, TrackAnalysis, TrackRole, VoiceNote, analyzeArrangement, analyzeVoice, chordToRoman, romanToChord, tensionCurve } from './analyze/index.js';
|
|
2
|
+
export { C as ChordMatch, D as DetectChordOptions, K as KeyMatch, d as detectChord, a as detectChordBest, b as detectKey } from './index-JnF4v9bx.js';
|
|
3
|
+
export { B as BorrowedSource, C as Cadence, a as ChordAnalysis, H as HarmonicFunction, b as analyzeChord, c as borrowedSource, d as detectCadence, f as functionOf, i as isBorrowedChord, e as isDiatonic, g as isMinorKey, p as parallelKey, s as secondaryDominant } from './function-DVH4Eusr.js';
|
|
4
|
+
export { C as CadenceHit, a as ChordSegment, b as ChordTimeline, c as ChordTimelineOptions, d as ChordTimelineResult, e as chordTimelineFromChords, f as chordTimelineFromNotes, g as detectCadences } from './index-DxvARIP2.js';
|
|
5
|
+
export { DEFAULT_GENERATION_BUDGET, IndexedNoteEvent, IntervalQuality, JUST_RATIOS, NoteEventIndex, Rng, TWELVE_TET, Tuning, assertFiniteNumber, assertGenerationBudget, assertInteger, assertNoteEvent, assertNoteEvents, assertPositiveInt, assertRange, assertTimeSignature, centsBetweenFreq, centsOfSteps, classifyInterval, createNoteEventIndex, createRng, edo, frequencyOf, isConsonantInterval, isPerfectInterval, justDeviationCents, nearestStep, ratioToCents } from './core/index.js';
|
|
5
6
|
export { B as BarPosition, T as TimeSignature, b as barPositionToBeat, a as beatToBarPosition, c as beatsPerBar, f as formatTimeSignature, i as isCompound, d as isStrongBeat, m as metricWeight, p as parseTimeSignature, e as pulsesPerBar, t as tuplet } from './index-Cl7mhOFM.js';
|
|
6
7
|
export { N as NoteData, S as SpelledInterval, f as formatNote, m as midiToNote, n as noteToMidi, a as noteToPitchClass, p as parseNote, s as spelledInterval } from './index-CGMZNCx6.js';
|
|
7
8
|
export { K as KeyScale, N as NoteEvent } from './types-MGP29r3t.js';
|
|
8
9
|
export { BassLineOptions, BassSegment, BassStyle, BorrowedChord, CounterMelodyOptions, DrumHit, DrumRole, DrumsOptions, EuclideanKick, GrooveFeel, GrooveSlot, GrooveStyle, GrooveTemplate, HarmonizeOptions, HarmonizeResult, HumanizeOptions, MelodyNote, MotifCell, MotifContour, MotifNote, MotifOptions, MotifTransform, ProgFunction, ProgStyle, ProgressionOptions, ProgressionPreset, RhythmEvent, RhythmOptions, Section, SubstituteOptions, Substitution, SubstitutionType, applyGrooveTemplate, developMotif, extractGrooveTemplate, generateBassLine, generateCounterMelody, generateDrums, generateMotif, generateProgression, generateRhythm, harmonizeMelody, humanize, modalInterchangePalette, negativeHarmonyMirror, onsetWeightCurve, progressions, progressionsByStyle, rhythmDensity, substituteChord, transformMotif } from './generate/index.js';
|
|
9
10
|
export { Chord, Interval, Key, Note, Progression } from './model/index.js';
|
|
10
|
-
export { C as ChordData, a as ChordQuality, b as ChordSpan, c as chordFromDegree, d as chordPitchClasses, e as chordQualities, f as chordToneRole, g as diatonicSeventh, h as diatonicTriad, m as makeChord } from './index-
|
|
11
|
-
export { C as ChordScaleMatch, a as ChordScaleReportEntry, S as SATB_RANGES, b as ScaleChoice, c as StyledVoicingOptions, V as VoiceRange, d as VoicingOptions, e as VoicingStyle, f as availableTensions, g as avoidNotes, h as chordScaleReport, i as chordScales, s as scaleMatchesChord, j as scalesForChanges, v as voiceChord, k as voiceChordStyled, l as voiceProgression } from './styled-
|
|
11
|
+
export { C as ChordData, a as ChordQuality, b as ChordSpan, P as PitchSpelling, c as chordFromDegree, d as chordPitchClasses, e as chordQualities, f as chordToneRole, g as diatonicSeventh, h as diatonicTriad, m as makeChord } from './index-Bt4tOUD9.js';
|
|
12
|
+
export { C as ChordScaleMatch, a as ChordScaleReportEntry, S as SATB_RANGES, b as ScaleChoice, c as StyledVoicingOptions, V as VoiceRange, d as VoicingOptions, e as VoicingStyle, f as availableTensions, g as avoidNotes, h as chordScaleReport, i as chordScales, s as scaleMatchesChord, j as scalesForChanges, v as voiceChord, k as voiceChordStyled, l as voiceProgression } from './styled-DZ7GjShb.js';
|
|
12
13
|
export { BLUES_MASK, CHROMATIC_MASK, DORIAN_MASK, HARMONIC_MINOR_MASK, LOCRIAN_MASK, LYDIAN_MASK, MAJOR_MASK, MAJOR_PENTATONIC_MASK, MELODIC_MINOR_MASK, MINOR_PENTATONIC_MASK, MIXOLYDIAN_MASK, NAMED_SCALES, NATURAL_MINOR_MASK, OCTATONIC_HALF_WHOLE_MASK, OCTATONIC_WHOLE_HALF_MASK, PHRYGIAN_MASK, WHOLE_TONE_MASK, createsHiddenParallelPerfect, createsParallelOctave, createsParallelPerfect, createsParallelUnison, createsVerticalDissonance, createsVoiceCrossing, createsVoiceOverlap, diatonicPitchClasses, exceedsSpacing, formatChordSymbol, isForbiddenMelodicLeap, isLeadingToneResolution, isScaleTone, majorKey, maskFromOffsets, minorKey, nearestScaleTone, nextVoicing, noteNames, parseChordSymbol, pitchToScaleDegree, scaleByName, scaleTonesInDegreeOrder, spellChord, spellPitchClass, spellPitchClasses, spellScale, transposeChordSymbol, voiceLeadingCost } from './theory/index.js';
|
|
13
|
-
export { H as HarmonyRole, L as LockLevel, V as VoicedRole, r as roleOf } from './index-
|
|
14
|
-
export { N as NoteSafety, R as ReasonFlag, S as SafetyProfile, a as SafetyQuery, b as SafetyResult, V as VoiceSnapshot, e as enumerateSafePitches, c as evaluateSafety } from './index-
|
|
14
|
+
export { H as HarmonyRole, L as LockLevel, V as VoicedRole, r as roleOf } from './index-Bg5dYMmZ.js';
|
|
15
|
+
export { N as NoteSafety, R as ReasonFlag, S as SafetyProfile, a as SafetyQuery, b as SafetyResult, V as VoiceSnapshot, e as enumerateSafePitches, c as evaluateSafety } from './index-Jc0Ryi79.js';
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
chordTimelineFromNotes,
|
|
6
6
|
detectCadences,
|
|
7
7
|
tensionCurve
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-GOAW4VYL.js";
|
|
9
9
|
import {
|
|
10
10
|
JUST_RATIOS,
|
|
11
11
|
TWELVE_TET,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
justDeviationCents,
|
|
17
17
|
nearestStep,
|
|
18
18
|
ratioToCents
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-AKLYPWIN.js";
|
|
20
20
|
import {
|
|
21
21
|
applyGrooveTemplate,
|
|
22
22
|
developMotif,
|
|
@@ -34,14 +34,15 @@ import {
|
|
|
34
34
|
progressionsByStyle,
|
|
35
35
|
rhythmDensity,
|
|
36
36
|
transformMotif
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-4MHA432G.js";
|
|
38
38
|
import {
|
|
39
39
|
createRng
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-62QZKCJQ.js";
|
|
41
41
|
import {
|
|
42
42
|
barPositionToBeat,
|
|
43
43
|
beatToBarPosition,
|
|
44
44
|
beatsPerBar,
|
|
45
|
+
createNoteEventIndex,
|
|
45
46
|
formatTimeSignature,
|
|
46
47
|
isCompound,
|
|
47
48
|
isStrongBeat,
|
|
@@ -49,19 +50,19 @@ import {
|
|
|
49
50
|
parseTimeSignature,
|
|
50
51
|
pulsesPerBar,
|
|
51
52
|
tuplet
|
|
52
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-I5R7ZBJS.js";
|
|
53
54
|
import {
|
|
54
55
|
Chord,
|
|
55
56
|
Interval,
|
|
56
57
|
Key,
|
|
57
58
|
Note,
|
|
58
59
|
Progression
|
|
59
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-SGU7SPLK.js";
|
|
60
61
|
import {
|
|
61
62
|
modalInterchangePalette,
|
|
62
63
|
negativeHarmonyMirror,
|
|
63
64
|
substituteChord
|
|
64
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-IT2O4XFE.js";
|
|
65
66
|
import {
|
|
66
67
|
analyzeChord,
|
|
67
68
|
borrowedSource,
|
|
@@ -77,16 +78,17 @@ import {
|
|
|
77
78
|
parallelKey,
|
|
78
79
|
romanToChord,
|
|
79
80
|
secondaryDominant
|
|
80
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-CHMXELDS.js";
|
|
82
|
+
import "./chunk-N6IHQUOX.js";
|
|
81
83
|
import {
|
|
82
84
|
roleOf
|
|
83
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-2ZWMSJH6.js";
|
|
84
86
|
import {
|
|
85
87
|
NoteSafety,
|
|
86
88
|
ReasonFlag,
|
|
87
89
|
enumerateSafePitches,
|
|
88
90
|
evaluateSafety
|
|
89
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-EH6EM37U.js";
|
|
90
92
|
import {
|
|
91
93
|
SATB_RANGES,
|
|
92
94
|
availableTensions,
|
|
@@ -108,7 +110,7 @@ import {
|
|
|
108
110
|
voiceChordStyled,
|
|
109
111
|
voiceLeadingCost,
|
|
110
112
|
voiceProgression
|
|
111
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-C5XYKUVG.js";
|
|
112
114
|
import {
|
|
113
115
|
formatNote,
|
|
114
116
|
midiToNote,
|
|
@@ -161,17 +163,27 @@ import {
|
|
|
161
163
|
pitchToScaleDegree,
|
|
162
164
|
scaleByName,
|
|
163
165
|
scaleTonesInDegreeOrder
|
|
164
|
-
} from "./chunk-
|
|
166
|
+
} from "./chunk-MIWO425M.js";
|
|
165
167
|
import {
|
|
168
|
+
DEFAULT_GENERATION_BUDGET,
|
|
166
169
|
IntervalQuality,
|
|
170
|
+
assertFiniteNumber,
|
|
171
|
+
assertGenerationBudget,
|
|
172
|
+
assertInteger,
|
|
173
|
+
assertNoteEvent,
|
|
174
|
+
assertNoteEvents,
|
|
175
|
+
assertPositiveInt,
|
|
176
|
+
assertRange,
|
|
177
|
+
assertTimeSignature,
|
|
167
178
|
classifyInterval,
|
|
168
179
|
isConsonantInterval,
|
|
169
180
|
isPerfectInterval
|
|
170
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-FBQK3ZQN.js";
|
|
171
182
|
export {
|
|
172
183
|
BLUES_MASK,
|
|
173
184
|
CHROMATIC_MASK,
|
|
174
185
|
Chord,
|
|
186
|
+
DEFAULT_GENERATION_BUDGET,
|
|
175
187
|
DORIAN_MASK,
|
|
176
188
|
HARMONIC_MINOR_MASK,
|
|
177
189
|
Interval,
|
|
@@ -201,6 +213,14 @@ export {
|
|
|
201
213
|
analyzeChord,
|
|
202
214
|
analyzeVoice,
|
|
203
215
|
applyGrooveTemplate,
|
|
216
|
+
assertFiniteNumber,
|
|
217
|
+
assertGenerationBudget,
|
|
218
|
+
assertInteger,
|
|
219
|
+
assertNoteEvent,
|
|
220
|
+
assertNoteEvents,
|
|
221
|
+
assertPositiveInt,
|
|
222
|
+
assertRange,
|
|
223
|
+
assertTimeSignature,
|
|
204
224
|
availableTensions,
|
|
205
225
|
avoidNotes,
|
|
206
226
|
barPositionToBeat,
|
|
@@ -219,6 +239,7 @@ export {
|
|
|
219
239
|
chordToRoman,
|
|
220
240
|
chordToneRole,
|
|
221
241
|
classifyInterval,
|
|
242
|
+
createNoteEventIndex,
|
|
222
243
|
createRng,
|
|
223
244
|
createsHiddenParallelPerfect,
|
|
224
245
|
createsParallelOctave,
|
package/dist/model/index.cjs
CHANGED
|
@@ -28,6 +28,33 @@ __export(model_exports, {
|
|
|
28
28
|
});
|
|
29
29
|
module.exports = __toCommonJS(model_exports);
|
|
30
30
|
|
|
31
|
+
// src/core/validation/index.ts
|
|
32
|
+
var DEFAULT_GENERATION_BUDGET = 1e6;
|
|
33
|
+
function assertFiniteNumber(value, name) {
|
|
34
|
+
if (!Number.isFinite(value)) {
|
|
35
|
+
throw new RangeError(`${name} must be finite; received ${value}`);
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
function assertInteger(value, name, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
|
|
40
|
+
assertFiniteNumber(value, name);
|
|
41
|
+
if (!Number.isSafeInteger(value) || value < min || value > max) {
|
|
42
|
+
throw new RangeError(`${name} must be an integer in [${min}, ${max}]; received ${value}`);
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
function assertPositiveInt(value, name, max = DEFAULT_GENERATION_BUDGET) {
|
|
47
|
+
return assertInteger(value, name, 1, max);
|
|
48
|
+
}
|
|
49
|
+
function assertGenerationBudget(estimated, name, limit = DEFAULT_GENERATION_BUDGET) {
|
|
50
|
+
assertFiniteNumber(estimated, name);
|
|
51
|
+
assertPositiveInt(limit, `${name} limit`, Number.MAX_SAFE_INTEGER);
|
|
52
|
+
if (estimated < 0 || estimated > limit) {
|
|
53
|
+
throw new RangeError(`${name} exceeds the generation budget ${limit}; received ${estimated}`);
|
|
54
|
+
}
|
|
55
|
+
return estimated;
|
|
56
|
+
}
|
|
57
|
+
|
|
31
58
|
// src/theory/scale/degrees.ts
|
|
32
59
|
function pitchClass(pitch) {
|
|
33
60
|
return (Math.trunc(pitch) % 12 + 12) % 12;
|
|
@@ -252,8 +279,10 @@ function classifySeventh(thirdIc, fifthIc, seventhIc) {
|
|
|
252
279
|
function stackThirds(degree, key, size) {
|
|
253
280
|
const tones = scaleTonesInDegreeOrder(key);
|
|
254
281
|
const length = tones.length;
|
|
255
|
-
if (length
|
|
256
|
-
|
|
282
|
+
if (length !== 7) {
|
|
283
|
+
throw new Error(
|
|
284
|
+
`diatonic chord stacking requires a heptatonic scale (received ${length} tones)`
|
|
285
|
+
);
|
|
257
286
|
}
|
|
258
287
|
const idx = (step) => ((degree + step) % length + length) % length;
|
|
259
288
|
const rootPc = tones[idx(0)] ?? pitchClass2(key.rootPc);
|
|
@@ -280,12 +309,21 @@ function pitchClass3(value) {
|
|
|
280
309
|
function uniquePitchClasses(pitches) {
|
|
281
310
|
return [...new Set(pitches.map(pitchClass3))].sort((a, b) => a - b);
|
|
282
311
|
}
|
|
283
|
-
function
|
|
312
|
+
function assertPitches(pitches) {
|
|
313
|
+
assertGenerationBudget(pitches.length, "detection pitches");
|
|
314
|
+
for (let index = 0; index < pitches.length; index += 1) {
|
|
315
|
+
assertFiniteNumber(pitches[index] ?? Number.NaN, `pitches[${index}]`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function detectChord(pitches, opts = {}) {
|
|
319
|
+
assertPitches(pitches);
|
|
320
|
+
if (opts.bassPc !== void 0) assertFiniteNumber(opts.bassPc, "bassPc");
|
|
284
321
|
const input = uniquePitchClasses(pitches);
|
|
285
322
|
if (input.length === 0) {
|
|
286
323
|
return [];
|
|
287
324
|
}
|
|
288
|
-
const
|
|
325
|
+
const inputKind = opts.input === void 0 || opts.input === "auto" ? pitches.every((pitch) => Number.isInteger(pitch) && pitch >= 0 && pitch <= 11) ? "pitchClass" : "midi" : opts.input;
|
|
326
|
+
const bassPc = opts.bassPc !== void 0 ? pitchClass3(opts.bassPc) : inputKind === "midi" ? pitchClass3(pitches.reduce((lowest, pitch) => Math.min(lowest, pitch), Infinity)) : void 0;
|
|
289
327
|
const inputSet = new Set(input);
|
|
290
328
|
const matches = [];
|
|
291
329
|
const qualities = chordQualities();
|
|
@@ -300,8 +338,8 @@ function detectChord(pitches) {
|
|
|
300
338
|
continue;
|
|
301
339
|
}
|
|
302
340
|
const extraPcs = input.filter((pc) => !toneSet.has(pc));
|
|
303
|
-
const bassIndex = chord.intervals.findIndex((iv) => pitchClass3(rootPc + iv) === bassPc);
|
|
304
|
-
const inversion = bassIndex > 0 ? bassIndex : 0;
|
|
341
|
+
const bassIndex = bassPc === void 0 ? -1 : chord.intervals.findIndex((iv) => pitchClass3(rootPc + iv) === bassPc);
|
|
342
|
+
const inversion = bassPc === void 0 ? null : bassIndex > 0 ? bassIndex : 0;
|
|
305
343
|
const match = {
|
|
306
344
|
rootPc,
|
|
307
345
|
quality,
|
|
@@ -310,7 +348,7 @@ function detectChord(pitches) {
|
|
|
310
348
|
exact: extraPcs.length === 0 && missingPcs.length === 0,
|
|
311
349
|
inversion
|
|
312
350
|
};
|
|
313
|
-
if (
|
|
351
|
+
if (bassPc !== void 0 && bassPc !== rootPc) {
|
|
314
352
|
match.bassPc = bassPc;
|
|
315
353
|
}
|
|
316
354
|
matches.push(match);
|
|
@@ -332,8 +370,8 @@ function detectChord(pitches) {
|
|
|
332
370
|
});
|
|
333
371
|
return matches;
|
|
334
372
|
}
|
|
335
|
-
function detectChordBest(pitches) {
|
|
336
|
-
const best = detectChord(pitches)[0];
|
|
373
|
+
function detectChordBest(pitches, opts = {}) {
|
|
374
|
+
const best = detectChord(pitches, opts)[0];
|
|
337
375
|
if (!best) {
|
|
338
376
|
return null;
|
|
339
377
|
}
|
|
@@ -469,11 +507,16 @@ function parseSimpleRoman(text, key) {
|
|
|
469
507
|
if (canonical !== void 0) {
|
|
470
508
|
return { rootPc, quality: canonical, inversion: 0 };
|
|
471
509
|
}
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const
|
|
510
|
+
const parsedSuffix = /^(o|°|dim|ø|\+|aug)?(maj7|M7)?(65|64|43|42|7|6|2)?$/.exec(suffix);
|
|
511
|
+
if (!parsedSuffix) {
|
|
512
|
+
throw new Error(`Unsupported suffix "${suffix}" in Roman numeral: ${text}`);
|
|
513
|
+
}
|
|
514
|
+
const qualityMarker = parsedSuffix[1] ?? "";
|
|
515
|
+
const isDim = qualityMarker === "o" || qualityMarker === "\xB0" || qualityMarker === "dim";
|
|
516
|
+
const isAug = qualityMarker === "+" || qualityMarker === "aug";
|
|
517
|
+
const isHalfDim = qualityMarker === "\xF8";
|
|
518
|
+
const explicitMaj7 = parsedSuffix[2] !== void 0;
|
|
519
|
+
const figures = parsedSuffix[3] ?? "";
|
|
477
520
|
if (figures !== "" && !INVERSION_FIGURES.has(figures)) {
|
|
478
521
|
throw new Error(`Unsupported figured-bass or extension "${figures}" in Roman numeral: ${text}`);
|
|
479
522
|
}
|
|
@@ -1055,10 +1098,58 @@ function spellPitchClass(pc, tonic, key) {
|
|
|
1055
1098
|
function spellScale(tonic, key) {
|
|
1056
1099
|
return scaleTonesInDegreeOrder(key).map((pc) => spellPitchClass(pc, tonic, key));
|
|
1057
1100
|
}
|
|
1101
|
+
function chordLetterOffset(interval, chord) {
|
|
1102
|
+
switch (interval) {
|
|
1103
|
+
case 0:
|
|
1104
|
+
case 12:
|
|
1105
|
+
return 0;
|
|
1106
|
+
case 1:
|
|
1107
|
+
case 2:
|
|
1108
|
+
case 13:
|
|
1109
|
+
case 14:
|
|
1110
|
+
return 1;
|
|
1111
|
+
case 3:
|
|
1112
|
+
case 4:
|
|
1113
|
+
case 15:
|
|
1114
|
+
case 16:
|
|
1115
|
+
return 2;
|
|
1116
|
+
case 5:
|
|
1117
|
+
case 17:
|
|
1118
|
+
case 18:
|
|
1119
|
+
return 3;
|
|
1120
|
+
case 6:
|
|
1121
|
+
case 7:
|
|
1122
|
+
case 8:
|
|
1123
|
+
case 19:
|
|
1124
|
+
return 4;
|
|
1125
|
+
case 9:
|
|
1126
|
+
return chord.quality === "dim7" ? 6 : 5;
|
|
1127
|
+
case 20:
|
|
1128
|
+
case 21:
|
|
1129
|
+
return 5;
|
|
1130
|
+
case 10:
|
|
1131
|
+
case 11:
|
|
1132
|
+
case 22:
|
|
1133
|
+
case 23:
|
|
1134
|
+
return 6;
|
|
1135
|
+
default: {
|
|
1136
|
+
const octaves = Math.floor(Math.max(0, interval) / 12);
|
|
1137
|
+
const simple = mod124(interval);
|
|
1138
|
+
const simpleOffset = [0, 1, 1, 2, 2, 3, 4, 4, 4, 5, 6, 6][simple] ?? 0;
|
|
1139
|
+
return octaves * 7 + simpleOffset;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
function spellChordFromRoot(chord, root) {
|
|
1144
|
+
return chord.intervals.map((interval) => {
|
|
1145
|
+
const letter = mod72(root.letter + chordLetterOffset(interval, chord));
|
|
1146
|
+
const pc = mod124(chord.rootPc + interval);
|
|
1147
|
+
return { letter, alter: alterFor(letter, pc) };
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1058
1150
|
function spellChord(chord, tonic, key) {
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
);
|
|
1151
|
+
const root = spellPitchClass(chord.rootPc, tonic, key);
|
|
1152
|
+
return spellChordFromRoot(chord, root);
|
|
1062
1153
|
}
|
|
1063
1154
|
|
|
1064
1155
|
// src/theory/symbol/index.ts
|
|
@@ -1388,12 +1479,23 @@ function resolveRanges(opts) {
|
|
|
1388
1479
|
if (opts.ranges.length === 0) {
|
|
1389
1480
|
throw new Error("ranges must contain at least one voice range");
|
|
1390
1481
|
}
|
|
1391
|
-
|
|
1482
|
+
assertGenerationBudget(opts.ranges.length, "voice ranges", 128);
|
|
1483
|
+
return opts.ranges.map((range, index) => {
|
|
1484
|
+
assertFiniteNumber(range.min, `ranges[${index}].min`);
|
|
1485
|
+
assertFiniteNumber(range.max, `ranges[${index}].max`);
|
|
1486
|
+
if (range.min > range.max) {
|
|
1487
|
+
throw new RangeError(`ranges[${index}].min must not exceed max`);
|
|
1488
|
+
}
|
|
1489
|
+
assertGenerationBudget(
|
|
1490
|
+
Math.floor(range.max) - Math.ceil(range.min) + 1,
|
|
1491
|
+
`ranges[${index}] span`,
|
|
1492
|
+
4096
|
|
1493
|
+
);
|
|
1494
|
+
return { ...range };
|
|
1495
|
+
});
|
|
1392
1496
|
}
|
|
1393
1497
|
const voices = opts?.voices ?? 4;
|
|
1394
|
-
|
|
1395
|
-
throw new Error("voices must be at least 1");
|
|
1396
|
-
}
|
|
1498
|
+
assertPositiveInt(voices, "voices", 128);
|
|
1397
1499
|
if (voices === 4) {
|
|
1398
1500
|
return SATB_RANGES.map((range) => ({ ...range }));
|
|
1399
1501
|
}
|
|
@@ -1412,6 +1514,8 @@ function resolveRanges(opts) {
|
|
|
1412
1514
|
function voiceChord(chord, opts) {
|
|
1413
1515
|
const ranges = resolveRanges(opts);
|
|
1414
1516
|
const maxSpacing = opts?.maxSpacing ?? DEFAULT_MAX_SPACING;
|
|
1517
|
+
assertFiniteNumber(maxSpacing, "maxSpacing");
|
|
1518
|
+
if (maxSpacing < 0) throw new RangeError("maxSpacing must be non-negative");
|
|
1415
1519
|
const candidates = enumerateVoicings(chord, ranges, maxSpacing);
|
|
1416
1520
|
let best;
|
|
1417
1521
|
let bestScore = Number.POSITIVE_INFINITY;
|
|
@@ -1436,8 +1540,11 @@ function voiceChord(chord, opts) {
|
|
|
1436
1540
|
return best;
|
|
1437
1541
|
}
|
|
1438
1542
|
function voiceProgression(chords, opts) {
|
|
1543
|
+
assertGenerationBudget(chords.length * 4e3, "voiced progression search");
|
|
1439
1544
|
const ranges = resolveRanges(opts);
|
|
1440
1545
|
const maxSpacing = opts?.maxSpacing ?? DEFAULT_MAX_SPACING;
|
|
1546
|
+
assertFiniteNumber(maxSpacing, "maxSpacing");
|
|
1547
|
+
if (maxSpacing < 0) throw new RangeError("maxSpacing must be non-negative");
|
|
1441
1548
|
const result = [];
|
|
1442
1549
|
let prev;
|
|
1443
1550
|
for (const chord of chords) {
|
|
@@ -1522,7 +1629,12 @@ function nearestPc(target, pcs) {
|
|
|
1522
1629
|
}
|
|
1523
1630
|
function voiceChordStyled(chord, opts) {
|
|
1524
1631
|
const style = opts?.style ?? "close";
|
|
1525
|
-
const
|
|
1632
|
+
const octave = opts?.octave ?? DEFAULT_STYLE_OCTAVE;
|
|
1633
|
+
assertInteger(octave, "styled voicing octave", -10, 10);
|
|
1634
|
+
if (opts?.topNote !== void 0) {
|
|
1635
|
+
assertFiniteNumber(opts.topNote, "styled voicing topNote");
|
|
1636
|
+
}
|
|
1637
|
+
const base = 12 * (octave + 1);
|
|
1526
1638
|
const rootPc = pitchClass6(chord.rootPc);
|
|
1527
1639
|
const bassPc = pitchClass6(chord.bassPc ?? chord.rootPc);
|
|
1528
1640
|
const omitRoot = style === "rootless" || opts?.rootless === true;
|
|
@@ -1538,11 +1650,11 @@ function voiceChordStyled(chord, opts) {
|
|
|
1538
1650
|
const guide = roles.includes("seventh") ? "seventh" : roles.includes("sixth") ? "sixth" : "fifth";
|
|
1539
1651
|
order = order.filter((_pc, i) => {
|
|
1540
1652
|
const role = roles[i];
|
|
1541
|
-
return role === "root" || role === "third" || role === guide;
|
|
1653
|
+
return _pc === bassPc || role === "root" || role === "third" || role === guide;
|
|
1542
1654
|
});
|
|
1543
1655
|
}
|
|
1544
1656
|
if (omitRoot) {
|
|
1545
|
-
order = order.filter((pc) => pc !== rootPc);
|
|
1657
|
+
order = order.filter((pc) => pc !== rootPc || chord.bassPc !== void 0 && pc === bassPc);
|
|
1546
1658
|
}
|
|
1547
1659
|
if (order.length === 0) {
|
|
1548
1660
|
return [];
|
|
@@ -1571,6 +1683,18 @@ function voiceChordStyled(chord, opts) {
|
|
|
1571
1683
|
} else if (style === "drop3" && stack.length >= 3) {
|
|
1572
1684
|
stack[stack.length - 3] = (stack[stack.length - 3] ?? 0) - 12;
|
|
1573
1685
|
}
|
|
1686
|
+
if (chord.bassPc !== void 0) {
|
|
1687
|
+
const bassIndexInStack = stack.findIndex((pitch) => pitchClass6(pitch) === bassPc);
|
|
1688
|
+
if (bassIndexInStack >= 0) {
|
|
1689
|
+
const otherLowest = Math.min(
|
|
1690
|
+
...stack.filter((_pitch, index) => index !== bassIndexInStack),
|
|
1691
|
+
Number.POSITIVE_INFINITY
|
|
1692
|
+
);
|
|
1693
|
+
while ((stack[bassIndexInStack] ?? 0) >= otherLowest) {
|
|
1694
|
+
stack[bassIndexInStack] = (stack[bassIndexInStack] ?? 0) - 12;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1574
1698
|
return stack.sort((a, b) => a - b);
|
|
1575
1699
|
}
|
|
1576
1700
|
|
|
@@ -1866,7 +1990,11 @@ var Chord = class _Chord {
|
|
|
1866
1990
|
* @param key Optional key context for analysis methods.
|
|
1867
1991
|
*/
|
|
1868
1992
|
constructor(data, key) {
|
|
1869
|
-
|
|
1993
|
+
const copy = copyChord(data);
|
|
1994
|
+
if (copy.rootSpelling === void 0 && key !== void 0) {
|
|
1995
|
+
copy.rootSpelling = spellPitchClass(copy.rootPc, key.tonic.data, key.scale);
|
|
1996
|
+
}
|
|
1997
|
+
this.#data = copy;
|
|
1870
1998
|
this.#key = key;
|
|
1871
1999
|
}
|
|
1872
2000
|
/**
|
|
@@ -1878,8 +2006,13 @@ var Chord = class _Chord {
|
|
|
1878
2006
|
* @returns The chord (without key context).
|
|
1879
2007
|
*/
|
|
1880
2008
|
static of(root, quality, bass) {
|
|
1881
|
-
|
|
1882
|
-
|
|
2009
|
+
if (typeof root === "string") {
|
|
2010
|
+
const rootNote = Note.of(root);
|
|
2011
|
+
const data = makeChord(rootNote.pitchClass, quality, bass);
|
|
2012
|
+
data.rootSpelling = { letter: rootNote.letter, alter: rootNote.alter };
|
|
2013
|
+
return new _Chord(data);
|
|
2014
|
+
}
|
|
2015
|
+
return new _Chord(makeChord(root, quality, bass));
|
|
1883
2016
|
}
|
|
1884
2017
|
/**
|
|
1885
2018
|
* Wrap an existing plain chord object.
|
|
@@ -1906,8 +2039,8 @@ var Chord = class _Chord {
|
|
|
1906
2039
|
* @param pitches MIDI pitches or bare pitch classes.
|
|
1907
2040
|
* @returns Ranked chord interpretations (may be empty).
|
|
1908
2041
|
*/
|
|
1909
|
-
static detect(pitches) {
|
|
1910
|
-
return detectChord(pitches).map(
|
|
2042
|
+
static detect(pitches, opts) {
|
|
2043
|
+
return detectChord(pitches, opts).map(
|
|
1911
2044
|
(match) => new _Chord(makeChord(match.rootPc, match.quality, match.bassPc))
|
|
1912
2045
|
);
|
|
1913
2046
|
}
|
|
@@ -1917,8 +2050,8 @@ var Chord = class _Chord {
|
|
|
1917
2050
|
* @param pitches MIDI pitches or bare pitch classes.
|
|
1918
2051
|
* @returns The top-ranked chord, or null when nothing matches.
|
|
1919
2052
|
*/
|
|
1920
|
-
static detectBest(pitches) {
|
|
1921
|
-
const best = detectChordBest(pitches);
|
|
2053
|
+
static detectBest(pitches, opts) {
|
|
2054
|
+
const best = detectChordBest(pitches, opts);
|
|
1922
2055
|
return best === null ? null : new _Chord(best);
|
|
1923
2056
|
}
|
|
1924
2057
|
/** The root pitch class (0..11). */
|
|
@@ -2076,8 +2209,14 @@ var Chord = class _Chord {
|
|
|
2076
2209
|
const data = copyChord(this.#data);
|
|
2077
2210
|
if (index === 0) {
|
|
2078
2211
|
delete data.bassPc;
|
|
2212
|
+
delete data.bassSpelling;
|
|
2079
2213
|
} else {
|
|
2080
2214
|
data.bassPc = mod125(this.#data.rootPc + (intervals[index] ?? 0));
|
|
2215
|
+
const rootSpelling = data.rootSpelling ?? (this.#key ? spellPitchClass(data.rootPc, this.#key.tonic.data, this.#key.scale) : spellPitchClassBare(data.rootPc, "sharp"));
|
|
2216
|
+
const bassSpelling = spellChordFromRoot(data, rootSpelling)[index];
|
|
2217
|
+
if (bassSpelling !== void 0) {
|
|
2218
|
+
data.bassSpelling = bassSpelling;
|
|
2219
|
+
}
|
|
2081
2220
|
}
|
|
2082
2221
|
return new _Chord(data, this.#key);
|
|
2083
2222
|
}
|