@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.
Files changed (126) hide show
  1. package/README.md +4 -3
  2. package/dist/analyze/index.cjs +315 -42
  3. package/dist/analyze/index.cjs.map +1 -1
  4. package/dist/analyze/index.d.cts +11 -99
  5. package/dist/analyze/index.d.ts +11 -99
  6. package/dist/analyze/index.js +6 -6
  7. package/dist/chunk-2ZWMSJH6.js +30 -0
  8. package/dist/chunk-2ZWMSJH6.js.map +1 -0
  9. package/dist/{chunk-R3S2LUBH.js → chunk-4MHA432G.js} +316 -184
  10. package/dist/chunk-4MHA432G.js.map +1 -0
  11. package/dist/chunk-62QZKCJQ.js +49 -0
  12. package/dist/chunk-62QZKCJQ.js.map +1 -0
  13. package/dist/chunk-AKLYPWIN.js +83 -0
  14. package/dist/chunk-AKLYPWIN.js.map +1 -0
  15. package/dist/{chunk-XTC3X6MS.js → chunk-C5XYKUVG.js} +100 -12
  16. package/dist/chunk-C5XYKUVG.js.map +1 -0
  17. package/dist/{chunk-LN7ZZMD2.js → chunk-CHMXELDS.js} +33 -14
  18. package/dist/chunk-CHMXELDS.js.map +1 -0
  19. package/dist/{chunk-A4532ZFR.js → chunk-EH6EM37U.js} +60 -4
  20. package/dist/chunk-EH6EM37U.js.map +1 -0
  21. package/dist/chunk-FBQK3ZQN.js +131 -0
  22. package/dist/chunk-FBQK3ZQN.js.map +1 -0
  23. package/dist/{chunk-5HTNMQW4.js → chunk-GOAW4VYL.js} +87 -21
  24. package/dist/chunk-GOAW4VYL.js.map +1 -0
  25. package/dist/{chunk-MSWFZF7J.js → chunk-I5R7ZBJS.js} +90 -6
  26. package/dist/chunk-I5R7ZBJS.js.map +1 -0
  27. package/dist/{chunk-GQKN5KDT.js → chunk-IT2O4XFE.js} +4 -9
  28. package/dist/chunk-IT2O4XFE.js.map +1 -0
  29. package/dist/{chunk-7Y7WF64D.js → chunk-MIWO425M.js} +6 -4
  30. package/dist/chunk-MIWO425M.js.map +1 -0
  31. package/dist/chunk-N6IHQUOX.js +1 -0
  32. package/dist/chunk-N6IHQUOX.js.map +1 -0
  33. package/dist/{chunk-COKTX2G5.js → chunk-SGU7SPLK.js} +29 -12
  34. package/dist/chunk-SGU7SPLK.js.map +1 -0
  35. package/dist/core/index.cjs +230 -14
  36. package/dist/core/index.cjs.map +1 -1
  37. package/dist/core/index.d.cts +56 -4
  38. package/dist/core/index.d.ts +56 -4
  39. package/dist/core/index.js +24 -4
  40. package/dist/{function-2bJW1Zp_.d.ts → function-DVH4Eusr.d.ts} +1 -1
  41. package/dist/{function-r2sh-jOO.d.cts → function-DYt4iKsn.d.cts} +1 -1
  42. package/dist/generate/index.cjs +830 -494
  43. package/dist/generate/index.cjs.map +1 -1
  44. package/dist/generate/index.d.cts +11 -5
  45. package/dist/generate/index.d.ts +11 -5
  46. package/dist/generate/index.js +9 -9
  47. package/dist/{index-BOBXBNwP.d.cts → index-BNlGP86A.d.cts} +1 -1
  48. package/dist/{index-CP3wAfEH.d.ts → index-Bg5dYMmZ.d.ts} +1 -1
  49. package/dist/{index-CM5W4rcm.d.ts → index-Bt4tOUD9.d.ts} +1 -1
  50. package/dist/index-CnZCo29u.d.cts +108 -0
  51. package/dist/{index-D_ZTUNKp.d.cts → index-CpOsP1y9.d.cts} +2 -2
  52. package/dist/{index-DZ1M21do.d.cts → index-CxqBQtH1.d.cts} +2 -1
  53. package/dist/{index-BdeQ1r_p.d.cts → index-Dikst44v.d.cts} +1 -1
  54. package/dist/{index-BMPxwjwV.d.ts → index-DxvARIP2.d.ts} +2 -2
  55. package/dist/{index-BreoJRw0.d.ts → index-Jc0Ryi79.d.ts} +2 -1
  56. package/dist/index-JnF4v9bx.d.ts +108 -0
  57. package/dist/index.cjs +818 -283
  58. package/dist/index.cjs.map +1 -1
  59. package/dist/index.d.cts +9 -8
  60. package/dist/index.d.ts +9 -8
  61. package/dist/index.js +34 -13
  62. package/dist/model/index.cjs +170 -31
  63. package/dist/model/index.cjs.map +1 -1
  64. package/dist/model/index.d.cts +6 -5
  65. package/dist/model/index.d.ts +6 -5
  66. package/dist/model/index.js +6 -6
  67. package/dist/{styled-D7BAx3S3.d.ts → styled-DZ7GjShb.d.ts} +1 -1
  68. package/dist/{styled-BjXtOFNk.d.cts → styled-ZTbdaVFM.d.cts} +1 -1
  69. package/dist/theory/index.cjs +180 -34
  70. package/dist/theory/index.cjs.map +1 -1
  71. package/dist/theory/index.d.cts +6 -6
  72. package/dist/theory/index.d.ts +6 -6
  73. package/dist/theory/index.js +6 -5
  74. package/package.json +50 -19
  75. package/src/analyze/arrange/internal.ts +3 -1
  76. package/src/analyze/arrange/tension.ts +15 -3
  77. package/src/analyze/arrange/tracks.ts +36 -3
  78. package/src/analyze/detect/index.ts +46 -9
  79. package/src/analyze/functional/roman.ts +14 -5
  80. package/src/analyze/index.ts +1 -1
  81. package/src/analyze/timeline/index.ts +43 -7
  82. package/src/analyze/voice/index.ts +11 -2
  83. package/src/core/event-index/index.ts +104 -0
  84. package/src/core/index.ts +14 -0
  85. package/src/core/meter/index.ts +24 -4
  86. package/src/core/random/index.ts +26 -3
  87. package/src/core/tuning/index.ts +36 -6
  88. package/src/core/validation/index.ts +119 -0
  89. package/src/generate/bass/index.ts +23 -0
  90. package/src/generate/countermelody/index.ts +167 -76
  91. package/src/generate/drums/euclid.ts +10 -3
  92. package/src/generate/drums/index.ts +56 -24
  93. package/src/generate/drums/percussion.ts +1 -1
  94. package/src/generate/groove/index.ts +25 -0
  95. package/src/generate/harmonize/index.ts +55 -44
  96. package/src/generate/index.ts +0 -1
  97. package/src/generate/motif/index.ts +45 -21
  98. package/src/generate/progression/index.ts +8 -16
  99. package/src/generate/reharmony/index.ts +1 -8
  100. package/src/generate/rhythm/index.ts +11 -1
  101. package/src/index.ts +13 -247
  102. package/src/model/chord.ts +29 -10
  103. package/src/theory/chord/index.ts +4 -2
  104. package/src/theory/harmony/index.ts +6 -21
  105. package/src/theory/index.ts +6 -1
  106. package/src/theory/safety/index.ts +71 -2
  107. package/src/theory/spelling/index.ts +70 -3
  108. package/src/theory/voicing/satb.ts +25 -4
  109. package/src/theory/voicing/styled.ts +26 -3
  110. package/dist/chunk-5HTNMQW4.js.map +0 -1
  111. package/dist/chunk-7Y7WF64D.js.map +0 -1
  112. package/dist/chunk-A4532ZFR.js.map +0 -1
  113. package/dist/chunk-BHUT2S5G.js +0 -22
  114. package/dist/chunk-BHUT2S5G.js.map +0 -1
  115. package/dist/chunk-CCBLVAPK.js +0 -42
  116. package/dist/chunk-CCBLVAPK.js.map +0 -1
  117. package/dist/chunk-COKTX2G5.js.map +0 -1
  118. package/dist/chunk-GQKN5KDT.js.map +0 -1
  119. package/dist/chunk-LN7ZZMD2.js.map +0 -1
  120. package/dist/chunk-MSWFZF7J.js.map +0 -1
  121. package/dist/chunk-R3S2LUBH.js.map +0 -1
  122. package/dist/chunk-SDM3VJJ5.js +0 -41
  123. package/dist/chunk-SDM3VJJ5.js.map +0 -1
  124. package/dist/chunk-XTC3X6MS.js.map +0 -1
  125. package/dist/chunk-ZXW5YIWK.js +0 -55
  126. package/dist/chunk-ZXW5YIWK.js.map +0 -1
package/dist/index.d.cts CHANGED
@@ -1,14 +1,15 @@
1
- export { AnalyzedNote, ArrangementAnalysis, ArrangementOptions, ArrangementTrack, ChordMatch, Conflict, KeyMatch, TensionPoint, TheoryLabel, TrackAnalysis, TrackRole, VoiceNote, analyzeArrangement, analyzeVoice, chordToRoman, detectChord, detectChordBest, detectKey, romanToChord, tensionCurve } from './analyze/index.cjs';
2
- 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-r2sh-jOO.cjs';
3
- 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-D_ZTUNKp.cjs';
4
- export { IntervalQuality, JUST_RATIOS, Rng, TWELVE_TET, Tuning, centsBetweenFreq, centsOfSteps, classifyInterval, createRng, edo, frequencyOf, isConsonantInterval, isPerfectInterval, justDeviationCents, nearestStep, ratioToCents } from './core/index.cjs';
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-BOBXBNwP.cjs';
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-BjXtOFNk.cjs';
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-BdeQ1r_p.cjs';
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-DZ1M21do.cjs';
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, ChordMatch, Conflict, KeyMatch, TensionPoint, TheoryLabel, TrackAnalysis, TrackRole, VoiceNote, analyzeArrangement, analyzeVoice, chordToRoman, detectChord, detectChordBest, detectKey, romanToChord, tensionCurve } from './analyze/index.js';
2
- 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-2bJW1Zp_.js';
3
- 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-BMPxwjwV.js';
4
- export { IntervalQuality, JUST_RATIOS, Rng, TWELVE_TET, Tuning, centsBetweenFreq, centsOfSteps, classifyInterval, createRng, edo, frequencyOf, isConsonantInterval, isPerfectInterval, justDeviationCents, nearestStep, ratioToCents } from './core/index.js';
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-CM5W4rcm.js';
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-D7BAx3S3.js';
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-CP3wAfEH.js';
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-BreoJRw0.js';
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-5HTNMQW4.js";
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-ZXW5YIWK.js";
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-R3S2LUBH.js";
37
+ } from "./chunk-4MHA432G.js";
38
38
  import {
39
39
  createRng
40
- } from "./chunk-BHUT2S5G.js";
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-MSWFZF7J.js";
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-COKTX2G5.js";
60
+ } from "./chunk-SGU7SPLK.js";
60
61
  import {
61
62
  modalInterchangePalette,
62
63
  negativeHarmonyMirror,
63
64
  substituteChord
64
- } from "./chunk-GQKN5KDT.js";
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-LN7ZZMD2.js";
81
+ } from "./chunk-CHMXELDS.js";
82
+ import "./chunk-N6IHQUOX.js";
81
83
  import {
82
84
  roleOf
83
- } from "./chunk-SDM3VJJ5.js";
85
+ } from "./chunk-2ZWMSJH6.js";
84
86
  import {
85
87
  NoteSafety,
86
88
  ReasonFlag,
87
89
  enumerateSafePitches,
88
90
  evaluateSafety
89
- } from "./chunk-A4532ZFR.js";
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-XTC3X6MS.js";
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-7Y7WF64D.js";
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-CCBLVAPK.js";
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,
@@ -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 === 0) {
256
- return { rootPc: pitchClass2(key.rootPc), quality: "maj", intervals: [0, 4, 7] };
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 detectChord(pitches) {
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 bassPc = pitchClass3(Math.min(...pitches));
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 (inversion > 0) {
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 isDim = /o|°|dim/.test(suffix);
473
- const isAug = /\+|aug/.test(suffix);
474
- const isHalfDim = /ø/.test(suffix);
475
- const explicitMaj7 = /maj7|M7/.test(suffix);
476
- const figures = suffix.replace(/maj7|M7/g, "").replace(/[^0-9]/g, "");
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
- return chord.intervals.map(
1060
- (interval) => spellPitchClass(mod124(chord.rootPc + interval), tonic, key)
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
- return opts.ranges.map((range) => ({ ...range }));
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
- if (voices < 1) {
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 base = 12 * ((opts?.octave ?? DEFAULT_STYLE_OCTAVE) + 1);
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
- this.#data = copyChord(data);
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
- const rootPc = typeof root === "string" ? Note.of(root).pitchClass : root;
1882
- return new _Chord(makeChord(rootPc, quality, bass));
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
  }