@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
package/dist/analyze/index.d.cts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { T as TimeSignature } from '../index-
|
|
2
|
-
import { K as KeyScale, N as NoteEvent } from '../types-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { C as
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
1
|
+
import { T as TimeSignature } from '../index-DXd9JikN.cjs';
|
|
2
|
+
import { K as KeyScale, N as NoteEvent } from '../types-BN6_Q9Kl.cjs';
|
|
3
|
+
import { C as Chord, d as ChordToneRole } from '../index-y_ak9_Hi.cjs';
|
|
4
|
+
export { a as ChordQuality, b as ChordSegment, c as ChordSpan, P as PitchSpelling } from '../index-y_ak9_Hi.cjs';
|
|
5
|
+
import { V as VoiceSnapshot, N as NoteSafety, S as SafetyProfile } from '../index-tJhkmQgE.cjs';
|
|
6
|
+
import { a as ChordTimeline, C as CadenceHit } from '../index-Be74mcon.cjs';
|
|
7
|
+
export { b as ChordTimelineOptions, c as ChordTimelineResult, d as chordTimelineFromChords, e as chordTimelineFromNotes, f as detectCadences } from '../index-Be74mcon.cjs';
|
|
8
|
+
export { C as ChordMatch, D as DetectChordOptions, a as DetectKeyOptions, K as KeyMatch, b as KeyVariant, d as detectChord, c as detectChordBest, e as detectKey, f as detectKeyBest, g as detectKeyFromNotes } from '../index-BtXT6UQ0.cjs';
|
|
9
|
+
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-DNugAOrt.cjs';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Roman-numeral parsing and formatting.
|
|
@@ -46,30 +47,64 @@ export { B as BorrowedSource, C as Cadence, a as ChordAnalysis, H as HarmonicFun
|
|
|
46
47
|
* @category Functional Harmony
|
|
47
48
|
*/
|
|
48
49
|
declare function romanToChord(text: string, key: KeyScale): Chord;
|
|
50
|
+
/**
|
|
51
|
+
* Options for {@link chordToRoman}.
|
|
52
|
+
*
|
|
53
|
+
* @category Functional Harmony
|
|
54
|
+
*/
|
|
55
|
+
type ChordToRomanOptions = {
|
|
56
|
+
/**
|
|
57
|
+
* Render a tonicizing chord as an applied numeral (`V7/V`, `viio7/ii`)
|
|
58
|
+
* instead of naming its root against the home key (`II7`, `#ivo7`).
|
|
59
|
+
*
|
|
60
|
+
* Off by default: naming the root is always a correct spelling, whereas
|
|
61
|
+
* whether a chromatic dominant is genuinely applied is a reading only the
|
|
62
|
+
* caller can make. Turning it on makes {@link chordToRoman} the exact inverse
|
|
63
|
+
* of {@link romanToChord} for the chords {@link secondaryDominant} builds.
|
|
64
|
+
*/
|
|
65
|
+
applied?: boolean;
|
|
66
|
+
};
|
|
49
67
|
/**
|
|
50
68
|
* Render a chord as a Roman numeral relative to a key.
|
|
51
69
|
*
|
|
52
70
|
* Diatonic roots take their scale-degree numeral directly, so numerals are
|
|
53
71
|
* correct in both major and minor keys (and any custom scale). The quality
|
|
54
72
|
* selects the case and suffix; chromatic roots receive a flat/sharp spelling by
|
|
55
|
-
* convention.
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
73
|
+
* convention. A key that is not heptatonic has no numeral of its own for every
|
|
74
|
+
* degree, so its roots are named against its parallel major.
|
|
75
|
+
*
|
|
76
|
+
* When the chord carries a `bassPc` on a chord tone, a figured-bass inversion
|
|
77
|
+
* (`6`, `64`, `65`, `43`, `42`) is emitted for plain triads and true seventh
|
|
78
|
+
* chords; added-tone and extended qualities have no lossless figure and render
|
|
79
|
+
* in root position instead (the bass is dropped, pitch classes are preserved).
|
|
80
|
+
*
|
|
81
|
+
* A `bassPc` that is *not* a chord tone — a pedal or passing bass such as
|
|
82
|
+
* `C/D` — is likewise dropped, and the numeral names the upper chord alone.
|
|
83
|
+
* Roman-numeral notation spends its slash on applied chords (`V7/V`), so there
|
|
84
|
+
* is no unambiguous way to write such a bass; a caller that must keep it should
|
|
85
|
+
* read `chord.bassPc` alongside the numeral.
|
|
60
86
|
*
|
|
61
87
|
* @param chord The chord to name.
|
|
62
88
|
* @param key The prevailing key.
|
|
89
|
+
* @param opts `applied` renders tonicizing chords as `V7/V`-style numerals.
|
|
63
90
|
* @returns The Roman numeral string.
|
|
64
91
|
* @example
|
|
65
92
|
* ```ts
|
|
66
93
|
* import { chordToRoman, makeChord, majorKey } from '@libraz/libcantus';
|
|
67
94
|
* chordToRoman(makeChord(7, 'dom7'), majorKey(0)); // => 'V7' (G7 in C major)
|
|
95
|
+
* chordToRoman(makeChord(2, 'dom7'), majorKey(0), { applied: true }); // => 'V7/V'
|
|
68
96
|
* ```
|
|
69
97
|
* @category Functional Harmony
|
|
70
98
|
*/
|
|
71
|
-
declare function chordToRoman(chord: Chord, key: KeyScale): string;
|
|
99
|
+
declare function chordToRoman(chord: Chord, key: KeyScale, opts?: ChordToRomanOptions): string;
|
|
72
100
|
|
|
101
|
+
/**
|
|
102
|
+
* A suspension figure, named by the interval above the bass and the interval it
|
|
103
|
+
* resolves to.
|
|
104
|
+
*
|
|
105
|
+
* @category Arrangement & Analysis
|
|
106
|
+
*/
|
|
107
|
+
type SuspensionFigure = 'sus4-3' | 'sus6-5' | 'sus7-6' | 'sus9-8' | 'sus2-3';
|
|
73
108
|
/**
|
|
74
109
|
* A theory annotation attached to a note.
|
|
75
110
|
*
|
|
@@ -77,7 +112,7 @@ declare function chordToRoman(chord: Chord, key: KeyScale): string;
|
|
|
77
112
|
*/
|
|
78
113
|
type TheoryLabel = {
|
|
79
114
|
kind: 'chordTone';
|
|
80
|
-
role:
|
|
115
|
+
role: ChordToneRole;
|
|
81
116
|
} | {
|
|
82
117
|
kind: 'tension';
|
|
83
118
|
degree: 9 | 11 | 13;
|
|
@@ -89,7 +124,7 @@ type TheoryLabel = {
|
|
|
89
124
|
kind: 'neighbor';
|
|
90
125
|
} | {
|
|
91
126
|
kind: 'suspension';
|
|
92
|
-
type:
|
|
127
|
+
type: SuspensionFigure;
|
|
93
128
|
resolveTo: number;
|
|
94
129
|
} | {
|
|
95
130
|
kind: 'anticipation';
|
|
@@ -105,21 +140,60 @@ type TheoryLabel = {
|
|
|
105
140
|
/**
|
|
106
141
|
* A note with its theory labels and a short rationale.
|
|
107
142
|
*
|
|
143
|
+
* The labels describe the note against the chord sounding at its **onset**;
|
|
144
|
+
* they are not re-derived for the later chords a long note sustains across.
|
|
145
|
+
* `analyzeArrangement` does re-check every crossed chord change, and reports
|
|
146
|
+
* what it finds as conflicts, so a note labelled a chord tone here can still
|
|
147
|
+
* appear in `conflicts` at a later beat.
|
|
148
|
+
*
|
|
149
|
+
* The identity fields make an annotation mappable back to the caller's input:
|
|
150
|
+
* `originalIndex` is the note's position in the array that was passed in, and
|
|
151
|
+
* `trackIndex` is set by {@link analyzeArrangement}.
|
|
152
|
+
*
|
|
108
153
|
* @category Arrangement & Analysis
|
|
109
154
|
*/
|
|
110
155
|
type AnalyzedNote = {
|
|
111
156
|
noteId: number;
|
|
157
|
+
/** The note's index in the caller's own array, when the caller supplied one. */
|
|
158
|
+
originalIndex?: number;
|
|
159
|
+
/** The note's track, set by `analyzeArrangement`. */
|
|
160
|
+
trackIndex?: number;
|
|
161
|
+
pitch: number;
|
|
162
|
+
startBeat: number;
|
|
163
|
+
durationBeat: number;
|
|
112
164
|
labels: TheoryLabel[];
|
|
113
165
|
rationale?: string;
|
|
114
166
|
};
|
|
115
167
|
/**
|
|
116
|
-
* A single note in a monophonic voice: a {@link NoteEvent} with a stable id
|
|
168
|
+
* A single note in a monophonic voice: a {@link NoteEvent} with a stable id and,
|
|
169
|
+
* optionally, its index in the caller's original array.
|
|
117
170
|
*
|
|
118
171
|
* @category Arrangement & Analysis
|
|
119
172
|
*/
|
|
120
173
|
type VoiceNote = NoteEvent & {
|
|
174
|
+
id?: number;
|
|
175
|
+
originalIndex?: number;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* A voice note whose id has been assigned, as {@link toVoiceNotes} returns and
|
|
179
|
+
* {@link analyzeArrangement} works in.
|
|
180
|
+
*
|
|
181
|
+
* @category Arrangement & Analysis
|
|
182
|
+
*/
|
|
183
|
+
type IdentifiedVoiceNote = VoiceNote & {
|
|
121
184
|
id: number;
|
|
122
185
|
};
|
|
186
|
+
/**
|
|
187
|
+
* Give plain note events the ids {@link analyzeVoice} reports back.
|
|
188
|
+
*
|
|
189
|
+
* The id is only an identity handle, so the array position serves; this exists
|
|
190
|
+
* so the mapping is a named call rather than a `map` every caller writes.
|
|
191
|
+
*
|
|
192
|
+
* @param events The note events, in time order.
|
|
193
|
+
* @returns The same notes as voice notes, each carrying its index as its id.
|
|
194
|
+
* @category Arrangement & Analysis
|
|
195
|
+
*/
|
|
196
|
+
declare function toVoiceNotes(events: readonly NoteEvent[]): IdentifiedVoiceNote[];
|
|
123
197
|
/**
|
|
124
198
|
* Label every note of a voice with its theory roles.
|
|
125
199
|
*
|
|
@@ -136,26 +210,28 @@ type VoiceNote = NoteEvent & {
|
|
|
136
210
|
* escape) — only harmonic ones. Callers with truly polyphonic material should
|
|
137
211
|
* split it into monophonic sub-voices first, as `analyzeArrangement` does.
|
|
138
212
|
*
|
|
139
|
-
* @param voice The monophonic voice, in time order.
|
|
213
|
+
* @param voice The monophonic voice, in time order. A note without an `id` is
|
|
214
|
+
* identified by its position, so plain note events can be passed straight in.
|
|
140
215
|
* @param chordAtBeat Chord sounding at a given beat, or null.
|
|
141
216
|
* @param key Key context for leading-tone detection.
|
|
142
|
-
* @param otherVoicesAtBeat Other sounding voices at a given beat
|
|
217
|
+
* @param otherVoicesAtBeat Other sounding voices at a given beat; defaults to
|
|
218
|
+
* none, which is the whole story for a solo line.
|
|
143
219
|
* @returns One annotation per input note.
|
|
144
220
|
* @example
|
|
145
221
|
* ```ts
|
|
146
222
|
* import { analyzeVoice, makeChord, majorKey } from '@libraz/libcantus';
|
|
147
223
|
* const voice = [
|
|
148
|
-
* {
|
|
149
|
-
* {
|
|
150
|
-
* {
|
|
224
|
+
* { pitch: 60, startBeat: 0, durationBeat: 1 },
|
|
225
|
+
* { pitch: 62, startBeat: 1, durationBeat: 1 },
|
|
226
|
+
* { pitch: 64, startBeat: 2, durationBeat: 1 },
|
|
151
227
|
* ];
|
|
152
228
|
* const cMajor = makeChord(0, 'maj');
|
|
153
|
-
* const labels = analyzeVoice(voice, () => cMajor, majorKey(0)
|
|
229
|
+
* const labels = analyzeVoice(voice, () => cMajor, majorKey(0));
|
|
154
230
|
* labels; // one AnalyzedNote per input note, in the same order
|
|
155
231
|
* ```
|
|
156
232
|
* @category Arrangement & Analysis
|
|
157
233
|
*/
|
|
158
|
-
declare function analyzeVoice(voice: VoiceNote[], chordAtBeat: (beat: number) => Chord | null, key: KeyScale, otherVoicesAtBeat
|
|
234
|
+
declare function analyzeVoice(voice: readonly VoiceNote[], chordAtBeat: (beat: number) => Chord | null, key: KeyScale, otherVoicesAtBeat?: (beat: number) => VoiceSnapshot[]): AnalyzedNote[];
|
|
159
235
|
|
|
160
236
|
/**
|
|
161
237
|
* Arrangement track-role analysis: a single harmony is inferred from every
|
|
@@ -167,9 +243,18 @@ declare function analyzeVoice(voice: VoiceNote[], chordAtBeat: (beat: number) =>
|
|
|
167
243
|
/**
|
|
168
244
|
* The musical role a track plays in the arrangement.
|
|
169
245
|
*
|
|
246
|
+
* Only `drums` changes the analysis: its pitches select instruments rather than
|
|
247
|
+
* naming harmony, so such a track is excluded from chord and key inference and
|
|
248
|
+
* from every voice-leading comparison, and is reported back with no
|
|
249
|
+
* annotations. `harmony` is meaningful through
|
|
250
|
+
* {@link ArrangementOptions.harmonyTracks}, which names the tracks the chords
|
|
251
|
+
* are inferred from. The rest are labels carried through to
|
|
252
|
+
* {@link TrackAnalysis.role} for the caller's own use; nothing is inferred, so
|
|
253
|
+
* a track left unlabelled reports `'other'` rather than a guess.
|
|
254
|
+
*
|
|
170
255
|
* @category Arrangement & Analysis
|
|
171
256
|
*/
|
|
172
|
-
type TrackRole = 'melody' | 'harmony' | 'bass' | 'other';
|
|
257
|
+
type TrackRole = 'melody' | 'harmony' | 'bass' | 'drums' | 'other';
|
|
173
258
|
/**
|
|
174
259
|
* One input track: its notes plus optional name and role.
|
|
175
260
|
*
|
|
@@ -178,7 +263,7 @@ type TrackRole = 'melody' | 'harmony' | 'bass' | 'other';
|
|
|
178
263
|
type ArrangementTrack = {
|
|
179
264
|
name?: string;
|
|
180
265
|
role?: TrackRole;
|
|
181
|
-
notes: NoteEvent[];
|
|
266
|
+
notes: readonly NoteEvent[];
|
|
182
267
|
};
|
|
183
268
|
/**
|
|
184
269
|
* A track after analysis: its resolved name, role, and per-note annotations.
|
|
@@ -199,10 +284,22 @@ type TrackAnalysis = {
|
|
|
199
284
|
type Conflict = {
|
|
200
285
|
beat: number;
|
|
201
286
|
trackName: string;
|
|
287
|
+
/** The clashing track's index in the caller's input array. */
|
|
288
|
+
trackIndex: number;
|
|
289
|
+
/** The note's index in that track's own note array. */
|
|
290
|
+
originalIndex?: number;
|
|
291
|
+
/** The id the note carries in {@link TrackAnalysis.notes}. */
|
|
292
|
+
noteId: number;
|
|
202
293
|
pitch: number;
|
|
294
|
+
/**
|
|
295
|
+
* The note's theory labels at its onset, so a caller can tell a genuine clash
|
|
296
|
+
* from a passing tone, a neighbour, or a prepared suspension — all of which
|
|
297
|
+
* are ordinary non-chord tones that still evaluate as unsafe.
|
|
298
|
+
*/
|
|
299
|
+
labels: TheoryLabel[];
|
|
203
300
|
/** The clash severity: {@link NoteSafety.Warning} or {@link NoteSafety.Dissonant}. */
|
|
204
301
|
safety: NoteSafety;
|
|
205
|
-
/** {@link
|
|
302
|
+
/** {@link SafetyResult.reasons} bitmask. */
|
|
206
303
|
reasons: number;
|
|
207
304
|
/** Preferred stepwise resolution, when the safety evaluator provides one. */
|
|
208
305
|
resolveTo?: number;
|
|
@@ -232,6 +329,23 @@ type ArrangementAnalysis = {
|
|
|
232
329
|
type ArrangementOptions = {
|
|
233
330
|
/** Key context; inferred from the pooled notes when omitted. */
|
|
234
331
|
key?: KeyScale;
|
|
332
|
+
/**
|
|
333
|
+
* A chord timeline to analyse against, instead of inferring one from the
|
|
334
|
+
* notes. Supply it to analyse a hand-written progression, or to reuse the
|
|
335
|
+
* timeline of an earlier call rather than re-running chord inference.
|
|
336
|
+
*/
|
|
337
|
+
timeline?: ChordTimeline;
|
|
338
|
+
/**
|
|
339
|
+
* Indices of the tracks the harmony is inferred from. Defaults to every
|
|
340
|
+
* pitched track. Percussion tracks are excluded either way.
|
|
341
|
+
*/
|
|
342
|
+
harmonyTracks?: number[];
|
|
343
|
+
/**
|
|
344
|
+
* Lowest severity reported in `conflicts`.
|
|
345
|
+
*
|
|
346
|
+
* @defaultValue {@link NoteSafety.Warning}
|
|
347
|
+
*/
|
|
348
|
+
minSeverity?: NoteSafety;
|
|
235
349
|
/**
|
|
236
350
|
* Time signature; defaults to 4/4.
|
|
237
351
|
*
|
|
@@ -250,16 +364,31 @@ type ArrangementOptions = {
|
|
|
250
364
|
* @defaultValue `'pop'`
|
|
251
365
|
*/
|
|
252
366
|
profile?: SafetyProfile;
|
|
367
|
+
/**
|
|
368
|
+
* Upper bound on the work this call may do — note counts, windows, and
|
|
369
|
+
* candidate counts are each checked against it before anything is allocated.
|
|
370
|
+
*
|
|
371
|
+
* Raise it to analyse a piece larger than the default allows; the default is
|
|
372
|
+
* {@link DEFAULT_GENERATION_BUDGET}, chosen so a runaway input fails fast
|
|
373
|
+
* rather than blocking the thread.
|
|
374
|
+
*
|
|
375
|
+
* @defaultValue {@link DEFAULT_GENERATION_BUDGET}
|
|
376
|
+
*/
|
|
377
|
+
budget?: number;
|
|
253
378
|
};
|
|
254
379
|
/**
|
|
255
380
|
* Analyse a whole arrangement against a single inferred harmony.
|
|
256
381
|
*
|
|
257
|
-
* The chord timeline and key are inferred from the pooled notes of every
|
|
258
|
-
* (see {@link chordTimelineFromNotes}); pooling all voices is
|
|
259
|
-
* roles are absent or a track doubles the harmony, so it is
|
|
260
|
-
* deriving the harmony from a subset.
|
|
261
|
-
*
|
|
262
|
-
*
|
|
382
|
+
* The chord timeline and key are inferred from the pooled notes of every
|
|
383
|
+
* pitched track (see {@link chordTimelineFromNotes}); pooling all voices is
|
|
384
|
+
* robust even when roles are absent or a track doubles the harmony, so it is
|
|
385
|
+
* preferred over deriving the harmony from a subset. A track marked
|
|
386
|
+
* `role: 'drums'` is excluded — its pitches name instruments, not harmony, and
|
|
387
|
+
* pooling them would corrupt the key, the timeline and every reading built on
|
|
388
|
+
* them. Pass `harmonyTracks` to restrict inference further, or `timeline` to
|
|
389
|
+
* analyse against a progression you already have. Zero- and negative-length
|
|
390
|
+
* notes never sound, so they are dropped at ingest and appear in neither the
|
|
391
|
+
* annotations nor the conflicts.
|
|
263
392
|
*
|
|
264
393
|
* Voice analysis assumes one monophonic voice at a time, so each track is
|
|
265
394
|
* first partitioned into monophonic sub-voices (a polyphonic block-chord track
|
|
@@ -272,6 +401,13 @@ type ArrangementOptions = {
|
|
|
272
401
|
* evaluations that are not {@link NoteSafety.Safe} become conflicts, one per
|
|
273
402
|
* clashing beat, sorted worst severity first and then by beat.
|
|
274
403
|
*
|
|
404
|
+
* Every ordinary non-chord tone — a passing note, a neighbour, a prepared
|
|
405
|
+
* suspension — is by definition unsafe against the chord under it, so the
|
|
406
|
+
* conflict list is a report, not a fault list. Each conflict carries the note's
|
|
407
|
+
* `labels` and its `trackIndex`/`originalIndex`, so a caller can tell those
|
|
408
|
+
* apart and map a conflict back to the note it passed in; `minSeverity` narrows
|
|
409
|
+
* the list to outright dissonance.
|
|
410
|
+
*
|
|
275
411
|
* @param tracks The tracks to analyse.
|
|
276
412
|
* @param opts Analysis options; see {@link ArrangementOptions}.
|
|
277
413
|
* @returns The inferred harmony, per-track annotations, cadences, and conflicts.
|
|
@@ -311,12 +447,12 @@ type TensionPoint = {
|
|
|
311
447
|
*
|
|
312
448
|
* At each sample beat the tension combines three normalized terms:
|
|
313
449
|
* - the sounding chord's harmonic function (dominant `1`, subdominant `0.5`,
|
|
314
|
-
* tonic or no chord `0`), weighted
|
|
450
|
+
* tonic or no chord `0`), weighted `FUNCTION_WEIGHT`;
|
|
315
451
|
* - the dissonance of the sounding notes — the larger of the share of sounding
|
|
316
452
|
* pitches that are not chord tones and the share that {@link evaluateSafety}
|
|
317
|
-
* rates {@link NoteSafety.Dissonant} — weighted
|
|
453
|
+
* rates {@link NoteSafety.Dissonant} — weighted `DISSONANCE_WEIGHT`;
|
|
318
454
|
* - the registral span of the sounding notes, saturating at
|
|
319
|
-
*
|
|
455
|
+
* `SPAN_SATURATION` semitones, weighted `SPAN_WEIGHT`.
|
|
320
456
|
*
|
|
321
457
|
* The weighted sum is clamped to [0, 1]. The harmony is inferred from all tracks
|
|
322
458
|
* pooled together, so the result is deterministic and self-contained.
|
|
@@ -337,5 +473,29 @@ type TensionPoint = {
|
|
|
337
473
|
declare function tensionCurve(tracks: ArrangementTrack[], opts?: ArrangementOptions & {
|
|
338
474
|
step?: number;
|
|
339
475
|
}): TensionPoint[];
|
|
476
|
+
/**
|
|
477
|
+
* Sample the tension of an arrangement already analysed by
|
|
478
|
+
* {@link analyzeArrangement}, reusing its harmony instead of inferring it again.
|
|
479
|
+
*
|
|
480
|
+
* `analyzeArrangement` followed by `tensionCurve` runs chord and key inference
|
|
481
|
+
* twice over the same notes. This takes the analysis it already produced, so
|
|
482
|
+
* the curve and the annotations describe the same harmony by construction.
|
|
483
|
+
*
|
|
484
|
+
* @param tracks The same tracks that were analysed.
|
|
485
|
+
* @param analysis The result of {@link analyzeArrangement} for those tracks.
|
|
486
|
+
* @param opts Analysis options plus an optional `step` (default one beat).
|
|
487
|
+
* @returns One {@link TensionPoint} per sampled beat, in beat order.
|
|
488
|
+
* @example
|
|
489
|
+
* ```ts
|
|
490
|
+
* import { analyzeArrangement, tensionCurveFrom } from '@libraz/libcantus';
|
|
491
|
+
* const tracks = [{ notes: [{ pitch: 60, startBeat: 0, durationBeat: 4 }] }];
|
|
492
|
+
* const analysis = analyzeArrangement(tracks);
|
|
493
|
+
* tensionCurveFrom(tracks, analysis, { step: 1 });
|
|
494
|
+
* ```
|
|
495
|
+
* @category Arrangement & Analysis
|
|
496
|
+
*/
|
|
497
|
+
declare function tensionCurveFrom(tracks: ArrangementTrack[], analysis: ArrangementAnalysis, opts?: ArrangementOptions & {
|
|
498
|
+
step?: number;
|
|
499
|
+
}): TensionPoint[];
|
|
340
500
|
|
|
341
|
-
export { type AnalyzedNote, type ArrangementAnalysis, type ArrangementOptions, type ArrangementTrack, CadenceHit, ChordTimeline, type Conflict, type TensionPoint, type TheoryLabel, type TrackAnalysis, type TrackRole, type VoiceNote, analyzeArrangement, analyzeVoice, chordToRoman, romanToChord, tensionCurve };
|
|
501
|
+
export { type AnalyzedNote, type ArrangementAnalysis, type ArrangementOptions, type ArrangementTrack, CadenceHit, Chord as ChordData, ChordTimeline, type ChordToRomanOptions, ChordToneRole, type Conflict, type IdentifiedVoiceNote, KeyScale, NoteEvent, NoteSafety, SafetyProfile, type SuspensionFigure, type TensionPoint, type TheoryLabel, TimeSignature, type TrackAnalysis, type TrackRole, type VoiceNote, VoiceSnapshot, analyzeArrangement, analyzeVoice, chordToRoman, romanToChord, tensionCurve, tensionCurveFrom, toVoiceNotes };
|