@libraz/libcantus 1.0.1 → 1.2.0
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 +27 -65
- package/README_ja.md +28 -66
- package/dist/analyze/index.cjs +11 -7
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +79 -144
- package/dist/analyze/index.d.ts +79 -144
- package/dist/analyze/index.js +20 -16
- package/dist/chunk-35NBV2FT.cjs +145 -0
- package/dist/chunk-35NBV2FT.cjs.map +1 -0
- package/dist/{chunk-UADYAYAT.cjs → chunk-3R3QVKY5.cjs} +1353 -580
- package/dist/chunk-3R3QVKY5.cjs.map +1 -0
- package/dist/{chunk-WWURE4XT.cjs → chunk-76ZBTRG2.cjs} +624 -729
- package/dist/chunk-76ZBTRG2.cjs.map +1 -0
- package/dist/{chunk-FVSI36UV.js → chunk-7KG3RTYS.js} +197 -110
- package/dist/chunk-7KG3RTYS.js.map +1 -0
- package/dist/{chunk-VTI6FOLB.js → chunk-AGOVW7U6.js} +709 -133
- package/dist/chunk-AGOVW7U6.js.map +1 -0
- package/dist/{chunk-E3F4AHAH.cjs → chunk-CGBADIO5.cjs} +221 -134
- package/dist/chunk-CGBADIO5.cjs.map +1 -0
- package/dist/{chunk-6XH6QZYQ.cjs → chunk-DSMJRXCZ.cjs} +1455 -849
- package/dist/chunk-DSMJRXCZ.cjs.map +1 -0
- package/dist/{chunk-PKFNUHDY.js → chunk-FBH75DAY.js} +1218 -612
- package/dist/chunk-FBH75DAY.js.map +1 -0
- package/dist/chunk-H2KJHBW4.js +3329 -0
- package/dist/chunk-H2KJHBW4.js.map +1 -0
- package/dist/chunk-HPVSH7SF.cjs +2294 -0
- package/dist/chunk-HPVSH7SF.cjs.map +1 -0
- package/dist/{chunk-MXO72PLY.cjs → chunk-HWHGOVO6.cjs} +21 -19
- package/dist/chunk-HWHGOVO6.cjs.map +1 -0
- package/dist/chunk-HYJJ2V2I.js +2294 -0
- package/dist/chunk-HYJJ2V2I.js.map +1 -0
- package/dist/{chunk-AFM2ULJH.cjs → chunk-J7FHVZII.cjs} +1567 -1067
- package/dist/chunk-J7FHVZII.cjs.map +1 -0
- package/dist/chunk-K6OZXIR6.js +1 -0
- package/dist/{chunk-H3VORETI.js → chunk-M5RYMAFI.js} +487 -592
- package/dist/chunk-M5RYMAFI.js.map +1 -0
- package/dist/chunk-NB25P3EH.js +363 -0
- package/dist/chunk-NB25P3EH.js.map +1 -0
- package/dist/{chunk-TTCLJX6D.js → chunk-NFJ4P6ZZ.js} +10 -8
- package/dist/chunk-NFJ4P6ZZ.js.map +1 -0
- package/dist/chunk-NM7UAMC3.cjs +457 -0
- package/dist/chunk-NM7UAMC3.cjs.map +1 -0
- package/dist/chunk-PM4XJE2Y.cjs +363 -0
- package/dist/chunk-PM4XJE2Y.cjs.map +1 -0
- package/dist/chunk-PUKJP2Z5.js +145 -0
- package/dist/chunk-PUKJP2Z5.js.map +1 -0
- package/dist/{chunk-VOHZB45S.js → chunk-Q6LFSAKV.js} +1321 -821
- package/dist/chunk-Q6LFSAKV.js.map +1 -0
- package/dist/{chunk-INHVXP6Z.js → chunk-RFIBF2RR.js} +1203 -430
- package/dist/chunk-RFIBF2RR.js.map +1 -0
- package/dist/{chunk-Q2WGKJNN.cjs → chunk-S5BKZZGM.cjs} +699 -123
- package/dist/chunk-S5BKZZGM.cjs.map +1 -0
- package/dist/chunk-SGLEQVJH.cjs +3329 -0
- package/dist/chunk-SGLEQVJH.cjs.map +1 -0
- package/dist/chunk-UGLFDG7L.cjs +1 -0
- package/dist/chunk-UGLFDG7L.cjs.map +1 -0
- package/dist/{chunk-YH3BIKHH.js → chunk-UMWZ4ZET.js} +146 -49
- package/dist/chunk-UMWZ4ZET.js.map +1 -0
- package/dist/{index-szBv3496.d.ts → coerce-DP0vYu-x.d.ts} +286 -199
- package/dist/{index-C_8o--VE.d.cts → coerce-DRERzdve.d.cts} +286 -199
- package/dist/core/index.cjs +9 -5
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +122 -108
- package/dist/core/index.d.ts +122 -108
- package/dist/core/index.js +32 -28
- package/dist/generate/index.cjs +8 -8
- package/dist/generate/index.d.cts +168 -84
- package/dist/generate/index.d.ts +168 -84
- package/dist/generate/index.js +7 -7
- package/dist/{index-CGpRv5sl.d.cts → index-9eoQs2C1.d.ts} +34 -19
- package/dist/{index-CCNJRG-P.d.cts → index-B9QLziDe.d.cts} +293 -56
- package/dist/{index-Dzr13q3d.d.cts → index-BBWNZS0f.d.cts} +135 -58
- package/dist/{index-9wcMhG73.d.ts → index-BHIUyjhZ.d.ts} +293 -56
- package/dist/{index-BGFW-8P2.d.cts → index-BJgP97N1.d.ts} +196 -114
- package/dist/{index-CunYKLiu.d.ts → index-BL5N2Oyz.d.cts} +1 -1
- package/dist/{index-Cj49F892.d.ts → index-BMweUlm5.d.cts} +63 -23
- package/dist/{index-CgHqxdps.d.ts → index-BNSM-DSk.d.cts} +196 -114
- package/dist/{index-D57QRbVn.d.ts → index-BRMbPkHE.d.ts} +480 -254
- package/dist/{index-Chbst3Jx.d.ts → index-CJBBiAmU.d.ts} +135 -58
- package/dist/{index-BkGmlyI3.d.cts → index-CL4b4gUQ.d.ts} +63 -23
- package/dist/{index-B9MNZboQ.d.ts → index-Cy15oTvh.d.cts} +52 -22
- package/dist/{index-B9MNZboQ.d.cts → index-Cy15oTvh.d.ts} +52 -22
- package/dist/{index-BO6xE9YU.d.cts → index-DGCNKAUr.d.cts} +480 -254
- package/dist/{index-B4o55NDr.d.cts → index-Dw2DP7vm.d.ts} +1 -1
- package/dist/{index-G1uwGGWQ.d.ts → index-cHvbYgJI.d.cts} +34 -19
- package/dist/index.cjs +42 -14
- 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 +82 -54
- package/dist/{masks-DYbE485J.d.cts → masks-Cc7-MzzY.d.ts} +49 -2
- package/dist/{masks-DYbE485J.d.ts → masks-pADfTOiD.d.cts} +49 -2
- package/dist/model/index.cjs +19 -12
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +504 -182
- package/dist/model/index.d.ts +504 -182
- package/dist/model/index.js +18 -11
- package/dist/{positional-Cptlj-xs.d.ts → positional-DJgs6ltD.d.ts} +85 -8
- package/dist/{positional-DvH_sd8u.d.cts → positional-DMZer-FM.d.cts} +85 -8
- package/dist/theory/index.cjs +35 -6
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +257 -62
- package/dist/theory/index.d.ts +257 -62
- package/dist/theory/index.js +41 -12
- package/package.json +7 -5
- package/dist/chunk-2LCPM3EG.js +0 -3224
- package/dist/chunk-2LCPM3EG.js.map +0 -1
- package/dist/chunk-6XH6QZYQ.cjs.map +0 -1
- package/dist/chunk-6XPTBE7Y.cjs +0 -49
- package/dist/chunk-6XPTBE7Y.cjs.map +0 -1
- package/dist/chunk-AFM2ULJH.cjs.map +0 -1
- package/dist/chunk-B6XNKWZV.cjs +0 -3224
- package/dist/chunk-B6XNKWZV.cjs.map +0 -1
- package/dist/chunk-E3F4AHAH.cjs.map +0 -1
- package/dist/chunk-ELCTZUJJ.js +0 -379
- package/dist/chunk-ELCTZUJJ.js.map +0 -1
- package/dist/chunk-FVSI36UV.js.map +0 -1
- package/dist/chunk-H3VORETI.js.map +0 -1
- package/dist/chunk-H42UHPYW.js +0 -1577
- package/dist/chunk-H42UHPYW.js.map +0 -1
- package/dist/chunk-HFPS7JFD.js +0 -1
- package/dist/chunk-INHVXP6Z.js.map +0 -1
- package/dist/chunk-K4ZJUGF4.cjs +0 -379
- package/dist/chunk-K4ZJUGF4.cjs.map +0 -1
- package/dist/chunk-KNJEKLKV.js +0 -49
- package/dist/chunk-KNJEKLKV.js.map +0 -1
- package/dist/chunk-MXO72PLY.cjs.map +0 -1
- package/dist/chunk-NLEU4QSE.cjs +0 -360
- package/dist/chunk-NLEU4QSE.cjs.map +0 -1
- package/dist/chunk-OE6WK2Y2.cjs +0 -1577
- package/dist/chunk-OE6WK2Y2.cjs.map +0 -1
- package/dist/chunk-PKFNUHDY.js.map +0 -1
- package/dist/chunk-Q2WGKJNN.cjs.map +0 -1
- package/dist/chunk-RHIJ3S4I.cjs +0 -1
- package/dist/chunk-RHIJ3S4I.cjs.map +0 -1
- package/dist/chunk-TTCLJX6D.js.map +0 -1
- package/dist/chunk-UADYAYAT.cjs.map +0 -1
- package/dist/chunk-VOHZB45S.js.map +0 -1
- package/dist/chunk-VTI6FOLB.js.map +0 -1
- package/dist/chunk-WWURE4XT.cjs.map +0 -1
- package/dist/chunk-YH3BIKHH.js.map +0 -1
- /package/dist/{chunk-HFPS7JFD.js.map → chunk-K6OZXIR6.js.map} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { d as ChordQuality, b as Chord, N as NoteSafety,
|
|
3
|
-
import { r as ScaleName } from './masks-
|
|
4
|
-
import { i as KeyProfileName, j as KeyProfilePair, R as RejectedCandidate, k as KeyRegion, e as ChordTimeline, C as CadenceHit, a as AnalyzedNote, T as TheoryLabel, K as KeyContext, b as CadenceResult } from './index-
|
|
5
|
-
import {
|
|
1
|
+
import { e as KeyScale, h as NoteEvent, i as NoteLike, g as Note, S as SpelledInterval } from './index-Cy15oTvh.js';
|
|
2
|
+
import { d as ChordQuality, k as KeyVariant, b as Chord, r as SpelledKeyLike, c as ChordLike, K as KeyLike, n as ResolvedKey, N as NoteSafety, o as SafetyProfile } from './coerce-DP0vYu-x.js';
|
|
3
|
+
import { r as ScaleName } from './masks-Cc7-MzzY.js';
|
|
4
|
+
import { i as KeyProfileName, j as KeyProfilePair, R as RejectedCandidate, k as KeyRegion, e as ChordTimeline, C as CadenceHit, a as AnalyzedNote, T as TheoryLabel, K as KeyContext, b as CadenceResult } from './index-CJBBiAmU.js';
|
|
5
|
+
import { b as MeterLike } from './index-CL4b4gUQ.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Church-mode candidates for {@link detectKey}.
|
|
@@ -164,12 +164,7 @@ type KeyMatch = {
|
|
|
164
164
|
*/
|
|
165
165
|
alternatives?: RejectedCandidate[];
|
|
166
166
|
};
|
|
167
|
-
|
|
168
|
-
* Which form of a scale a {@link KeyMatch} settled on.
|
|
169
|
-
*
|
|
170
|
-
* @category Recognition
|
|
171
|
-
*/
|
|
172
|
-
type KeyVariant = 'major' | 'natural' | 'harmonic' | 'melodic' | 'modal';
|
|
167
|
+
|
|
173
168
|
/**
|
|
174
169
|
* Input weighting for {@link detectKey}.
|
|
175
170
|
*
|
|
@@ -249,8 +244,13 @@ type DetectKeyOptions = {
|
|
|
249
244
|
* A match is reported when all of the chord's tones are present in the input, or
|
|
250
245
|
* when the only absent tone is the perfect fifth (a common omission in shell
|
|
251
246
|
* voicings); matches are ranked best-first by fewest extra notes, then fewest
|
|
252
|
-
* missing notes, then
|
|
253
|
-
* no missing) is flagged and ranked
|
|
247
|
+
* missing notes, then root position over an inversion, then most specific
|
|
248
|
+
* (largest) chord. An exact match (no extras, no missing) is flagged and ranked
|
|
249
|
+
* first.
|
|
250
|
+
*
|
|
251
|
+
* The root-position step decides between readings of the same pitches that are
|
|
252
|
+
* otherwise equally good: `[55, 59, 62, 64]` is read as G6 rather than Em7,
|
|
253
|
+
* because G is in the bass.
|
|
254
254
|
*
|
|
255
255
|
* @param pitches MIDI pitches or bare pitch classes (octave-agnostic).
|
|
256
256
|
* @returns Ranked chord interpretations (may be empty).
|
|
@@ -329,7 +329,7 @@ declare function detectChordBest(pitches: readonly number[], opts?: DetectChordO
|
|
|
329
329
|
* import { detectKey } from '@libraz/libcantus';
|
|
330
330
|
* const keys = detectKey([60, 62, 64, 65, 67, 69, 71]); // C major scale
|
|
331
331
|
* keys[0].mode; // 'major', with keys[0].key.rootPc === 0
|
|
332
|
-
* keys[1].mode; // 'minor' on 9: A minor, the relative, ranked just below
|
|
332
|
+
* keys[1].mode; // 'minor' — on 9: A minor, the relative, ranked just below
|
|
333
333
|
* const riff = detectKey([62, 62, 65, 69, 71, 69, 65, 62], { modes: true });
|
|
334
334
|
* riff[0].scaleName; // 'dorian', on rootPc 2, still reported as mode 'minor'
|
|
335
335
|
* ```
|
|
@@ -342,11 +342,21 @@ declare function detectKey(pitches: readonly number[], opts?: DetectKeyOptions):
|
|
|
342
342
|
*
|
|
343
343
|
* {@link detectKey} counts every pitch once, which lets a run of fast ornamental
|
|
344
344
|
* notes outvote the sustained harmony that establishes the key. This weighs
|
|
345
|
-
* each note by
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
345
|
+
* each note by the same measure chord inference weighs its own histogram by, so
|
|
346
|
+
* the two agree on what the music emphasises: duration times
|
|
347
|
+
* velocity, with a note that carries no velocity counted at full weight rather
|
|
348
|
+
* than at an assumed one. Notes that never sound (zero or negative duration)
|
|
349
|
+
* are ignored. The weighted distribution is then ranked exactly as
|
|
350
|
+
* {@link detectKey} ranks it, by correlation against a key profile, so `score`
|
|
351
|
+
* is a finite correlation in [-1, 1].
|
|
352
|
+
*
|
|
353
|
+
* The one term of that measure this cannot share is the metric accent, which
|
|
354
|
+
* chord inference adds to an onset by the beat it falls on: the notes arrive
|
|
355
|
+
* here without the meter they are counted in, and reading them against an
|
|
356
|
+
* assumed one would rank the same notes differently under a signature the
|
|
357
|
+
* caller never named. Ranking a whole piece is the coarser question, and the
|
|
358
|
+
* accents are what separate one window from the next rather than one key from
|
|
359
|
+
* another.
|
|
350
360
|
*
|
|
351
361
|
* @param notes The note events to weigh.
|
|
352
362
|
* @param opts Which profile to rank with, whether the modes take part, and the
|
|
@@ -398,6 +408,158 @@ declare function detectKeyFromNotes(notes: readonly NoteEvent[], opts?: Omit<Det
|
|
|
398
408
|
*/
|
|
399
409
|
declare function detectKeyBest(pitches: readonly number[], opts?: DetectKeyOptions): KeyMatch | null;
|
|
400
410
|
|
|
411
|
+
/**
|
|
412
|
+
* Augmented-sixth chords: the Italian, French, and German sixths.
|
|
413
|
+
*
|
|
414
|
+
* All three stand on the lowered submediant (b6) in the bass and carry an
|
|
415
|
+
* augmented sixth above it, and all three are predominants whose two outer
|
|
416
|
+
* voices resolve outward onto the dominant. The family is defined by that bass
|
|
417
|
+
* and that interval rather than by a stack of thirds, so a chord is recognized
|
|
418
|
+
* here from the tones sounding over that bass rather than through the
|
|
419
|
+
* Roman-numeral degree tables.
|
|
420
|
+
*
|
|
421
|
+
* The interval is spelled, so recognition reads letters and not only pitch
|
|
422
|
+
* classes: over an Ab bass the augmented sixth is F# and the minor seventh of
|
|
423
|
+
* the bVI7 it otherwise sounds exactly like is Gb. A caller holding pitch
|
|
424
|
+
* classes alone — an analysis of a MIDI track, which names no accidentals —
|
|
425
|
+
* makes that reading with {@link augmentedSixthFromPitchClasses}, and the chord
|
|
426
|
+
* it hands back carries the spelling that decided it.
|
|
427
|
+
*/
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* The three augmented-sixth chords, under the nationalities convention gives
|
|
431
|
+
* them.
|
|
432
|
+
*
|
|
433
|
+
* Over an Ab bass in C: the Italian sixth is Ab C F#, the French sixth adds the
|
|
434
|
+
* supertonic (Ab C D F#), and the German sixth adds the lowered mediant
|
|
435
|
+
* (Ab C Eb F#).
|
|
436
|
+
*
|
|
437
|
+
* @category Functional Harmony
|
|
438
|
+
*/
|
|
439
|
+
type AugmentedSixthKind = 'italian' | 'french' | 'german';
|
|
440
|
+
/**
|
|
441
|
+
* Build an augmented-sixth chord in a key.
|
|
442
|
+
*
|
|
443
|
+
* The chord always carries an explicit `bassPc` on the lowered submediant,
|
|
444
|
+
* which is what makes it an augmented sixth rather than the dominant seventh or
|
|
445
|
+
* the altered supertonic seventh it shares pitch classes with, and an explicit
|
|
446
|
+
* interval template naming exactly the tones that sound.
|
|
447
|
+
*
|
|
448
|
+
* It also carries its spelling: the tones as `toneSpellings`, and the root and
|
|
449
|
+
* bass as the usual hints. Those are what let the ordinary chord speller and
|
|
450
|
+
* the symbol formatter name the chord — `Ab C Eb F#` and `Ab7` for the German
|
|
451
|
+
* sixth of C major — since a stack of thirds over that root would put a Gb
|
|
452
|
+
* where the augmented sixth belongs. The spelling is the one the key is written
|
|
453
|
+
* on, so a flat-side key takes the double flats it genuinely needs.
|
|
454
|
+
*
|
|
455
|
+
* The lowered submediant is taken as eight semitones above the tonic in every
|
|
456
|
+
* mode, since the chord is a chromatic alteration rather than a degree of the
|
|
457
|
+
* prevailing scale.
|
|
458
|
+
*
|
|
459
|
+
* @param kind Which of the three augmented sixths to build.
|
|
460
|
+
* @param key The prevailing key, as a key name, a key/scale, or a `Key`.
|
|
461
|
+
* @returns The chord, with its bass on the lowered submediant.
|
|
462
|
+
* @throws If `kind` is not one of the three, or the key's root is not finite.
|
|
463
|
+
* @see {@link spellAugmentedSixth} to spell the family from a tonic without
|
|
464
|
+
* building a chord at all.
|
|
465
|
+
* @example
|
|
466
|
+
* ```ts
|
|
467
|
+
* import { augmentedSixthChord, majorKey } from '@libraz/libcantus';
|
|
468
|
+
* augmentedSixthChord('german', majorKey(0));
|
|
469
|
+
* // Ab C Eb F# in C: { rootPc: 8, quality: 'dom7', intervals: [0, 4, 7, 10], bassPc: 8, ... }
|
|
470
|
+
* ```
|
|
471
|
+
* @category Functional Harmony
|
|
472
|
+
*/
|
|
473
|
+
declare function augmentedSixthChord(kind: AugmentedSixthKind, key: SpelledKeyLike): Chord;
|
|
474
|
+
/**
|
|
475
|
+
* Identify a chord as one of the augmented sixths, or null when it is none.
|
|
476
|
+
*
|
|
477
|
+
* A chord qualifies when it sounds the lowered submediant of `key` in the bass,
|
|
478
|
+
* its pitch classes are exactly one of the three sets built over that bass, and
|
|
479
|
+
* its own letters spell the augmented sixth above it. All three are needed: the
|
|
480
|
+
* same pitch classes over the same bass are an ordinary bVI7 when the tone ten
|
|
481
|
+
* semitones above the bass is written as a minor seventh, and the letters are
|
|
482
|
+
* the only place that distinction lives.
|
|
483
|
+
*
|
|
484
|
+
* A chord naming no `bassPc` sounds its root lowest, which is how the two
|
|
485
|
+
* conventions for that field — the sounding bass always, or only a bass that
|
|
486
|
+
* differs from the root — are read alike here.
|
|
487
|
+
*
|
|
488
|
+
* The root the chord is measured from is not consulted, so a chord voiced or
|
|
489
|
+
* rebuilt around any of its own tones still identifies as long as it keeps its
|
|
490
|
+
* spelling.
|
|
491
|
+
*
|
|
492
|
+
* @param chord The chord to test, as a chord symbol, chord data, or a `Chord`.
|
|
493
|
+
* @param key The prevailing key, as a key name, a key/scale, or a `Key`.
|
|
494
|
+
* @returns The kind of augmented sixth, or null.
|
|
495
|
+
* @see {@link augmentedSixthFromPitchClasses} to make the reading from pitch
|
|
496
|
+
* classes that carry no spelling at all.
|
|
497
|
+
* @example
|
|
498
|
+
* ```ts
|
|
499
|
+
* import { augmentedSixthKind, majorKey, romanToChord } from '@libraz/libcantus';
|
|
500
|
+
* augmentedSixthKind(romanToChord('Fr6', majorKey(0)), majorKey(0)); // 'french'
|
|
501
|
+
* ```
|
|
502
|
+
* @category Functional Harmony
|
|
503
|
+
*/
|
|
504
|
+
declare function augmentedSixthKind(chord: ChordLike, key: KeyLike): AugmentedSixthKind | null;
|
|
505
|
+
/**
|
|
506
|
+
* Read a set of sounding pitch classes over a sounding bass as an augmented
|
|
507
|
+
* sixth, or null when they are none.
|
|
508
|
+
*
|
|
509
|
+
* The reading a caller holding no spelling has to make for itself: pitch
|
|
510
|
+
* classes name no accidentals, so nothing downstream can tell the German sixth
|
|
511
|
+
* from the bVI7 it sounds like once the letters are gone. The chord returned is
|
|
512
|
+
* the one {@link augmentedSixthChord} builds, spelling and all, so it keeps
|
|
513
|
+
* identifying as an augmented sixth everywhere it travels.
|
|
514
|
+
*
|
|
515
|
+
* Not every b6-1-b3-#4 over a b6 bass is an augmented sixth, and this cannot
|
|
516
|
+
* know which one is: it answers what the tones would spell, and the caller
|
|
517
|
+
* decides whether that reading is the one the music supports.
|
|
518
|
+
*
|
|
519
|
+
* @param pcs The sounding pitch classes; duplicates and unreduced values are
|
|
520
|
+
* fine.
|
|
521
|
+
* @param bassPc The pitch class sounding in the bass.
|
|
522
|
+
* @param key The prevailing key, as a key name, a key/scale, or a `Key`.
|
|
523
|
+
* @returns The augmented-sixth chord, or null.
|
|
524
|
+
* @see {@link augmentedSixthKind} to read a chord that already carries its
|
|
525
|
+
* spelling.
|
|
526
|
+
* @example
|
|
527
|
+
* ```ts
|
|
528
|
+
* import { augmentedSixthFromPitchClasses, majorKey } from '@libraz/libcantus';
|
|
529
|
+
* // Ab C Eb Gb sounding over Ab in C: the German sixth, spelled with its F#.
|
|
530
|
+
* augmentedSixthFromPitchClasses([8, 0, 3, 6], 8, majorKey(0))?.quality; // 'dom7'
|
|
531
|
+
* ```
|
|
532
|
+
* @category Functional Harmony
|
|
533
|
+
*/
|
|
534
|
+
declare function augmentedSixthFromPitchClasses(pcs: readonly number[], bassPc: number, key: SpelledKeyLike): Chord | null;
|
|
535
|
+
/**
|
|
536
|
+
* Spell an augmented-sixth chord from a spelled tonic, lowest note first.
|
|
537
|
+
*
|
|
538
|
+
* This is the spelled counterpart of {@link augmentedSixthChord}, and the table
|
|
539
|
+
* the chord's own spelling is built from: every tone is placed by a named
|
|
540
|
+
* interval above the bass, so the outer interval is an augmented sixth in every
|
|
541
|
+
* key rather than the minor seventh its ten semitones would otherwise imply.
|
|
542
|
+
* Reach for it when a spelled tonic is all there is; spelling the chord itself
|
|
543
|
+
* with {@link spellChord} names the same notes, in the chord's own order.
|
|
544
|
+
*
|
|
545
|
+
* A tonic carrying an octave yields notes carrying octaves, ascending from the
|
|
546
|
+
* bass; an octave-less tonic yields octave-less notes.
|
|
547
|
+
*
|
|
548
|
+
* @param kind Which of the three augmented sixths to spell.
|
|
549
|
+
* @param tonic The spelled tonic of the key, as a note name, a MIDI number,
|
|
550
|
+
* note data, or a `Note`.
|
|
551
|
+
* @returns The spelled tones, bass first and ascending.
|
|
552
|
+
* @throws If `kind` is not one of the three, or `tonic` is not a note.
|
|
553
|
+
* @example
|
|
554
|
+
* ```ts
|
|
555
|
+
* import { noteNames, parseNote, spellAugmentedSixth } from '@libraz/libcantus';
|
|
556
|
+
* noteNames(spellAugmentedSixth('german', parseNote('C'))); // ['Ab', 'C', 'Eb', 'F#']
|
|
557
|
+
* noteNames(spellAugmentedSixth('italian', 'E')); // ['C', 'E', 'A#']
|
|
558
|
+
* ```
|
|
559
|
+
* @category Functional Harmony
|
|
560
|
+
*/
|
|
561
|
+
declare function spellAugmentedSixth(kind: AugmentedSixthKind, tonic: NoteLike): Note[];
|
|
562
|
+
|
|
401
563
|
/**
|
|
402
564
|
* Arrangement track-role analysis: a single harmony is inferred from every
|
|
403
565
|
* track's notes pooled together, each track is then analysed against that shared
|
|
@@ -441,6 +603,21 @@ type TrackAnalysis = {
|
|
|
441
603
|
/** One {@link AnalyzedNote} per note, labelled against the inferred chords. */
|
|
442
604
|
notes: AnalyzedNote[];
|
|
443
605
|
};
|
|
606
|
+
/**
|
|
607
|
+
* A note sounding with a {@link Conflict} that raises a pairwise flag against it.
|
|
608
|
+
*
|
|
609
|
+
* @category Arrangement & Analysis
|
|
610
|
+
*/
|
|
611
|
+
type ConflictPartner = {
|
|
612
|
+
/** The partner's track index in the caller's input array. */
|
|
613
|
+
trackIndex: number;
|
|
614
|
+
/** The partner note's index in that track's own note array. */
|
|
615
|
+
originalIndex?: number;
|
|
616
|
+
/** The id the partner note carries in {@link TrackAnalysis.notes}. */
|
|
617
|
+
noteId: number;
|
|
618
|
+
/** The pairwise flags this note raises, as {@link SafetyPartner.reasons}. */
|
|
619
|
+
reasons: number;
|
|
620
|
+
};
|
|
444
621
|
/**
|
|
445
622
|
* A note that clashes with the harmony sounding beneath it.
|
|
446
623
|
*
|
|
@@ -470,6 +647,11 @@ type Conflict = {
|
|
|
470
647
|
resolveTo?: number;
|
|
471
648
|
/** Nearby fully safe replacement pitches, nearest first. */
|
|
472
649
|
suggestions?: number[];
|
|
650
|
+
/**
|
|
651
|
+
* The notes behind the pairwise flags in `reasons` — a parallel fifth, a
|
|
652
|
+
* crossing, a vertical clash — when any are set.
|
|
653
|
+
*/
|
|
654
|
+
partners?: ConflictPartner[];
|
|
473
655
|
rationale?: string;
|
|
474
656
|
};
|
|
475
657
|
/**
|
|
@@ -485,8 +667,11 @@ type ArrangementAnalysis = {
|
|
|
485
667
|
* started in for every bar after it leaves.
|
|
486
668
|
*/
|
|
487
669
|
keys: KeyRegion[];
|
|
488
|
-
/**
|
|
489
|
-
|
|
670
|
+
/**
|
|
671
|
+
* The key held longest across {@link ArrangementAnalysis.keys}, whole: the
|
|
672
|
+
* pitch classes with the spelling and the scale form the regions carry.
|
|
673
|
+
*/
|
|
674
|
+
prevailingKey: ResolvedKey;
|
|
490
675
|
timeline: ChordTimeline;
|
|
491
676
|
segmentConfidence: number[];
|
|
492
677
|
cadences: CadenceHit[];
|
|
@@ -504,8 +689,11 @@ type ArrangementOptions = {
|
|
|
504
689
|
* A single key held across the whole arrangement. Omit it, and `keys` with
|
|
505
690
|
* it, to have the key searched for over time so a modulating piece is read
|
|
506
691
|
* against the key actually in force.
|
|
692
|
+
*
|
|
693
|
+
* Taken in whatever form the caller holds a key, and kept whole: the region
|
|
694
|
+
* built from it carries the spelling and the scale form it was named with.
|
|
507
695
|
*/
|
|
508
|
-
key?:
|
|
696
|
+
key?: KeyLike;
|
|
509
697
|
/**
|
|
510
698
|
* Key regions to judge against, when a previous pass already worked them out.
|
|
511
699
|
* Takes precedence over `key`; supplying both is answering the same question
|
|
@@ -536,14 +724,14 @@ type ArrangementOptions = {
|
|
|
536
724
|
*
|
|
537
725
|
* @defaultValue `4/4`
|
|
538
726
|
*/
|
|
539
|
-
ts?:
|
|
727
|
+
ts?: MeterLike;
|
|
540
728
|
/**
|
|
541
729
|
* The meter as it changes over the arrangement. Bar lines, downbeats and
|
|
542
730
|
* metric weight all follow the signature in force at the beat in question.
|
|
543
731
|
*
|
|
544
732
|
* @defaultValue 4/4 throughout
|
|
545
733
|
*/
|
|
546
|
-
meters?:
|
|
734
|
+
meters?: MeterLike;
|
|
547
735
|
/**
|
|
548
736
|
* Length of the pickup in beats, when the piece starts with one.
|
|
549
737
|
*
|
|
@@ -555,7 +743,13 @@ type ArrangementOptions = {
|
|
|
555
743
|
*/
|
|
556
744
|
pickupBeats?: number;
|
|
557
745
|
/**
|
|
558
|
-
*
|
|
746
|
+
* Expected chord length in beats; defaults to the length of the opening bar.
|
|
747
|
+
*
|
|
748
|
+
* A prior rather than a grid: the arrangement analysis infers its harmony
|
|
749
|
+
* with dynamic segmentation, where the longer a chord is expected to last the
|
|
750
|
+
* more evidence a change needs before the search will place one. A chord may
|
|
751
|
+
* still begin at any position the notes argue for. Supply `timeline` to
|
|
752
|
+
* analyse against boundaries you have fixed yourself.
|
|
559
753
|
*
|
|
560
754
|
* @defaultValue the length of the opening bar
|
|
561
755
|
*/
|
|
@@ -578,6 +772,26 @@ type ArrangementOptions = {
|
|
|
578
772
|
*/
|
|
579
773
|
budget?: number;
|
|
580
774
|
};
|
|
775
|
+
/**
|
|
776
|
+
* Label every note of one polyphonic passage against the harmony under it and
|
|
777
|
+
* the voices around it.
|
|
778
|
+
*
|
|
779
|
+
* {@link analyzeVoice} reads a single line: it takes the note before and the note
|
|
780
|
+
* after each note as that note's melodic neighbours, and it is given no other
|
|
781
|
+
* voices, so over a flat array of everything that sounds it invents figures
|
|
782
|
+
* across parts — the alto between two soprano notes becomes a passing tone —
|
|
783
|
+
* and can never find a suspension, which is by definition a dissonance against
|
|
784
|
+
* something else sounding. So the passage is partitioned into monophonic
|
|
785
|
+
* sub-voices first and each is read with the others handed to it, which is what
|
|
786
|
+
* {@link analyzeArrangement} does with the tracks it is given.
|
|
787
|
+
*
|
|
788
|
+
* @param notes The passage, in any order; the ids are indices into this array.
|
|
789
|
+
* @param chordAtBeat Chord sounding at a given beat, or null.
|
|
790
|
+
* @param key The key, or the key in force at a given beat.
|
|
791
|
+
* @returns One annotation per note, in the order the notes were given, each
|
|
792
|
+
* carrying its position in that array as its id.
|
|
793
|
+
*/
|
|
794
|
+
declare function analyzePolyphony(notes: readonly NoteEvent[], chordAtBeat: (beat: number) => Chord | null, key: KeyContext): AnalyzedNote[];
|
|
581
795
|
/**
|
|
582
796
|
* Analyse a whole arrangement against the harmony inferred from it.
|
|
583
797
|
*
|
|
@@ -622,7 +836,7 @@ type ArrangementOptions = {
|
|
|
622
836
|
* { pitch: 67, startBeat: 2, durationBeat: 2 },
|
|
623
837
|
* ];
|
|
624
838
|
* const { prevailingKey, conflicts } = analyzeArrangement([{ role: 'melody', notes: melody }]);
|
|
625
|
-
* prevailingKey.rootPc; // the key held longest across the analysis
|
|
839
|
+
* prevailingKey.scale.rootPc; // the key held longest across the analysis
|
|
626
840
|
* conflicts; // notes clashing with the inferred harmony, worst severity first
|
|
627
841
|
* ```
|
|
628
842
|
* @category Arrangement & Analysis
|
|
@@ -786,6 +1000,11 @@ declare function tensionCurve(tracks: ArrangementTrack[], opts?: ArrangementOpti
|
|
|
786
1000
|
* twice over the same notes. This takes the analysis it already produced, so
|
|
787
1001
|
* the curve and the annotations describe the same harmony by construction.
|
|
788
1002
|
*
|
|
1003
|
+
* The analysis is the harmony to fall back on rather than one laid over the
|
|
1004
|
+
* caller: `key`, `keys` and `harmonyTracks` each name a harmony the analysis
|
|
1005
|
+
* does not hold, so naming one is asking for a different reading, and the curve
|
|
1006
|
+
* is taken under it. Nothing else about the analysis is re-derived.
|
|
1007
|
+
*
|
|
789
1008
|
* @param tracks The same tracks that were analysed.
|
|
790
1009
|
* @param analysis The result of {@link analyzeArrangement} for those tracks.
|
|
791
1010
|
* @param opts Analysis options plus an optional `step` (default one beat).
|
|
@@ -875,9 +1094,11 @@ type HypermeterOptions = {
|
|
|
875
1094
|
* Groupings of 2, 3, 4, 6, and 8 bars are tried at every phase, and each
|
|
876
1095
|
* reading is scored on two counts: how much more harmonic change lands on the
|
|
877
1096
|
* bars it calls group heads than on the bars between them, and how many of the
|
|
878
|
-
*
|
|
879
|
-
*
|
|
880
|
-
*
|
|
1097
|
+
* hyperbar ends it predicts are closed by one of the cadences it is given.
|
|
1098
|
+
* Where cadences are given they settle the phase, since a hyperbar is what a
|
|
1099
|
+
* cadence ends; the harmony then chooses among the phases they agree with. The
|
|
1100
|
+
* commonest groupings are believed a little more readily than the rare ones,
|
|
1101
|
+
* which settles ties without letting a prior overrule the music.
|
|
881
1102
|
*
|
|
882
1103
|
* The meter is read at the beat in question rather than at the start, so a
|
|
883
1104
|
* piece that changes metre keeps being cut at its own bar lines. Bar 0 is the
|
|
@@ -989,15 +1210,17 @@ type PhraseOptions = {
|
|
|
989
1210
|
*
|
|
990
1211
|
* @defaultValue `4/4`
|
|
991
1212
|
*/
|
|
992
|
-
ts?:
|
|
1213
|
+
ts?: MeterLike;
|
|
993
1214
|
/**
|
|
994
|
-
* The meter as it changes over the span. Bar lines
|
|
995
|
-
*
|
|
996
|
-
*
|
|
1215
|
+
* The meter as it changes over the span. Bar lines and hypermetric downbeats
|
|
1216
|
+
* follow the signature in force at the beat in question, so a piece that
|
|
1217
|
+
* changes metre is cut at its own bar lines; the length defaults below are
|
|
1218
|
+
* lengths rather than positions, and each is taken once from the meter the
|
|
1219
|
+
* span opens in.
|
|
997
1220
|
*
|
|
998
1221
|
* @defaultValue 4/4 throughout
|
|
999
1222
|
*/
|
|
1000
|
-
meters?:
|
|
1223
|
+
meters?: MeterLike;
|
|
1001
1224
|
/**
|
|
1002
1225
|
* Key context for cadence detection: one key for the whole span, or the key
|
|
1003
1226
|
* in force at a given beat. Omit it to have the key searched for over time,
|
|
@@ -1084,7 +1307,10 @@ type StructuralCadence = {
|
|
|
1084
1307
|
*
|
|
1085
1308
|
* Three kinds of evidence are gathered independently and then reconciled. The
|
|
1086
1309
|
* harmony contributes its cadences, each closing at the end of the chord it
|
|
1087
|
-
* arrives on
|
|
1310
|
+
* arrives on, and at the bar line where that chord is held across one — a tonic
|
|
1311
|
+
* still sounding into the next phrase closed this one at the bar line. The
|
|
1312
|
+
* cadence reported for a phrase is always one that arrived inside it. The
|
|
1313
|
+
* melody contributes the rests it breathes at and the notes it
|
|
1088
1314
|
* holds long enough to read as arrivals. Repetition contributes the beats where
|
|
1089
1315
|
* the music restarts material it has just played. The metre contributes its
|
|
1090
1316
|
* hypermetric downbeats, which confirm a boundary but never declare one on
|
|
@@ -1107,18 +1333,25 @@ type StructuralCadence = {
|
|
|
1107
1333
|
* that never sound are dropped.
|
|
1108
1334
|
* @param opts Analysis options; see {@link PhraseOptions}.
|
|
1109
1335
|
* @returns The phrases, in time order; one phrase covering the whole span when
|
|
1110
|
-
* the span is too short to divide
|
|
1336
|
+
* the span is too short to divide, and none at all when nothing sounds —
|
|
1337
|
+
* silence is no material to hear a phrase in.
|
|
1111
1338
|
* @example
|
|
1112
1339
|
* ```ts
|
|
1113
1340
|
* import { chordTimelineFromNotes, phrasesFromTimeline } from '@libraz/libcantus';
|
|
1341
|
+
* // Four bars of C - F - G - C. Triads rather than single notes: one line at a
|
|
1342
|
+
* // time names no harmony, so nothing would cadence.
|
|
1343
|
+
* const triad = (pitches: number[], startBeat: number) =>
|
|
1344
|
+
* pitches.map((pitch) => ({ pitch, startBeat, durationBeat: 4 }));
|
|
1114
1345
|
* const notes = [
|
|
1115
|
-
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1346
|
+
* ...triad([60, 64, 67], 0),
|
|
1347
|
+
* ...triad([65, 69, 72], 4),
|
|
1348
|
+
* ...triad([67, 71, 74], 8),
|
|
1349
|
+
* ...triad([60, 64, 67], 12),
|
|
1118
1350
|
* ];
|
|
1119
1351
|
* const { timeline } = chordTimelineFromNotes(notes);
|
|
1120
1352
|
* const phrases = phrasesFromTimeline(timeline, notes);
|
|
1121
|
-
* phrases[phrases.length - 1]?.cadence?.cadence.type; // 'authentic'
|
|
1353
|
+
* phrases[phrases.length - 1]?.cadence?.cadence.type; // 'authentic'
|
|
1354
|
+
* phrases[phrases.length - 1]?.cadence?.atBeat; // 12, inside the phrase it closes
|
|
1122
1355
|
* ```
|
|
1123
1356
|
* @category Arrangement & Analysis
|
|
1124
1357
|
*/
|
|
@@ -1136,14 +1369,18 @@ declare function phrasesFromTimeline(timeline: ChordTimeline, notes: readonly No
|
|
|
1136
1369
|
* @example
|
|
1137
1370
|
* ```ts
|
|
1138
1371
|
* import { chordTimelineFromNotes, phrasesFromTimeline, structuralCadences } from '@libraz/libcantus';
|
|
1372
|
+
* const triad = (pitches: number[], startBeat: number) =>
|
|
1373
|
+
* pitches.map((pitch) => ({ pitch, startBeat, durationBeat: 4 }));
|
|
1139
1374
|
* const notes = [
|
|
1140
|
-
*
|
|
1141
|
-
*
|
|
1142
|
-
*
|
|
1375
|
+
* ...triad([60, 64, 67], 0),
|
|
1376
|
+
* ...triad([65, 69, 72], 4),
|
|
1377
|
+
* ...triad([67, 71, 74], 8),
|
|
1378
|
+
* ...triad([60, 64, 67], 12),
|
|
1143
1379
|
* ];
|
|
1144
1380
|
* const { timeline } = chordTimelineFromNotes(notes);
|
|
1145
1381
|
* const ranked = structuralCadences(phrasesFromTimeline(timeline, notes));
|
|
1146
|
-
* ranked[0]; // the cadence carrying the most
|
|
1382
|
+
* ranked[0]?.cadence.type; // 'authentic' — the cadence carrying the most weight
|
|
1383
|
+
* ranked[0]?.atBeat; // 12
|
|
1147
1384
|
* ```
|
|
1148
1385
|
* @category Arrangement & Analysis
|
|
1149
1386
|
*/
|
|
@@ -1206,14 +1443,14 @@ type FormSectionOptions = {
|
|
|
1206
1443
|
*
|
|
1207
1444
|
* @defaultValue `4/4`
|
|
1208
1445
|
*/
|
|
1209
|
-
ts?:
|
|
1446
|
+
ts?: MeterLike;
|
|
1210
1447
|
/**
|
|
1211
1448
|
* The meter as it changes over the span, so a piece that changes metre is cut
|
|
1212
1449
|
* at its own bar lines.
|
|
1213
1450
|
*
|
|
1214
1451
|
* @defaultValue 4/4 throughout
|
|
1215
1452
|
*/
|
|
1216
|
-
meters?:
|
|
1453
|
+
meters?: MeterLike;
|
|
1217
1454
|
/**
|
|
1218
1455
|
* Length of the unit spans are compared in, in bars; defaults to one hyperbar.
|
|
1219
1456
|
*
|
|
@@ -1278,58 +1515,15 @@ type FormSectionOptions = {
|
|
|
1278
1515
|
declare function sectionsFromNotes(notes: readonly NoteEvent[], opts?: FormSectionOptions): FormSection[];
|
|
1279
1516
|
|
|
1280
1517
|
/**
|
|
1281
|
-
*
|
|
1518
|
+
* The recurring cells a melody is built from.
|
|
1282
1519
|
*
|
|
1283
|
-
* A motif is
|
|
1284
|
-
*
|
|
1285
|
-
*
|
|
1286
|
-
*
|
|
1287
|
-
*
|
|
1288
|
-
* no such relation can still be scored for similarity.
|
|
1520
|
+
* A motif is the interval contour plus the rhythmic profile, so every statement
|
|
1521
|
+
* of it carries the same identity however far it has been transposed or however
|
|
1522
|
+
* wide its note values are written. What this module does is find them: every
|
|
1523
|
+
* window of the melody is reduced to that identity, windows that agree are
|
|
1524
|
+
* grouped, and a group stated often enough is a motif.
|
|
1289
1525
|
*/
|
|
1290
1526
|
|
|
1291
|
-
/**
|
|
1292
|
-
* Step direction between two consecutive notes.
|
|
1293
|
-
*
|
|
1294
|
-
* @category Arrangement & Analysis
|
|
1295
|
-
*/
|
|
1296
|
-
type ContourDirection = 'up' | 'down' | 'same';
|
|
1297
|
-
/**
|
|
1298
|
-
* The overall shape of a line.
|
|
1299
|
-
*
|
|
1300
|
-
* The first four names are the vocabulary the motif generator's contours are
|
|
1301
|
-
* written in, and mean the same here. `'static'` is the shape a generator never
|
|
1302
|
-
* asks for and an analysis regularly meets: a line that does not move. A line
|
|
1303
|
-
* that dips and comes back — an arch upside down — reads as `'wave'`, since the
|
|
1304
|
-
* shared vocabulary has no name of its own for it.
|
|
1305
|
-
*
|
|
1306
|
-
* A wave has to turn more than once to be heard as one, so a cell the generator
|
|
1307
|
-
* writes for `'wave'` reads back as `'wave'` only from three bars up; the one-
|
|
1308
|
-
* and two-bar cells turn once and read as `'arch'`. The other three shapes come
|
|
1309
|
-
* back under their own name at every length.
|
|
1310
|
-
*
|
|
1311
|
-
* @category Arrangement & Analysis
|
|
1312
|
-
*/
|
|
1313
|
-
type MelodicContourShape = 'arch' | 'ascending' | 'descending' | 'wave' | 'static';
|
|
1314
|
-
/**
|
|
1315
|
-
* The abstract shape of a line: its step directions and what they add up to.
|
|
1316
|
-
*
|
|
1317
|
-
* @category Arrangement & Analysis
|
|
1318
|
-
*/
|
|
1319
|
-
type MelodicContour = {
|
|
1320
|
-
/** One direction per adjacent pair of notes, in time order. */
|
|
1321
|
-
directions: ContourDirection[];
|
|
1322
|
-
/** What the directions add up to. */
|
|
1323
|
-
shape: MelodicContourShape;
|
|
1324
|
-
/** Index of the highest note; ties keep the earliest. */
|
|
1325
|
-
peakIndex: number;
|
|
1326
|
-
/** Index of the lowest note; ties keep the earliest. */
|
|
1327
|
-
troughIndex: number;
|
|
1328
|
-
/** Semitone distance from the lowest note to the highest. */
|
|
1329
|
-
range: number;
|
|
1330
|
-
/** Why the line was given that shape. */
|
|
1331
|
-
rationale: string;
|
|
1332
|
-
};
|
|
1333
1527
|
/**
|
|
1334
1528
|
* One statement of a motif, addressed in the melody it was found in.
|
|
1335
1529
|
*
|
|
@@ -1418,71 +1612,6 @@ type ExtractMotifsOptions = {
|
|
|
1418
1612
|
*/
|
|
1419
1613
|
budget?: number;
|
|
1420
1614
|
};
|
|
1421
|
-
/**
|
|
1422
|
-
* How one statement of a motif stands to another.
|
|
1423
|
-
*
|
|
1424
|
-
* `'transposition'` is the literal one — every interval preserved, which is what
|
|
1425
|
-
* makes a sequence built on it a *real* sequence. `'tonalTransposition'` shifts
|
|
1426
|
-
* by scale degrees instead and lets the key resize the intervals, which is what
|
|
1427
|
-
* makes a sequence built on it a *tonal* sequence; the two are different devices
|
|
1428
|
-
* and are never reported as one. `'augmentation'` and `'diminution'` name the
|
|
1429
|
-
* relation only when the pitches are untouched, so an inversion in doubled note
|
|
1430
|
-
* values reads as `'inversion'` with a `timeRatio` of 2 rather than losing the
|
|
1431
|
-
* inversion to the stretch.
|
|
1432
|
-
*
|
|
1433
|
-
* @category Arrangement & Analysis
|
|
1434
|
-
*/
|
|
1435
|
-
type MotifRelationKind = 'repetition' | 'transposition' | 'tonalTransposition' | 'inversion' | 'retrograde' | 'retrogradeInversion' | 'augmentation' | 'diminution';
|
|
1436
|
-
/**
|
|
1437
|
-
* The transformation that turns one motif into another.
|
|
1438
|
-
*
|
|
1439
|
-
* @category Arrangement & Analysis
|
|
1440
|
-
*/
|
|
1441
|
-
type MotifRelation = {
|
|
1442
|
-
/** The named transformation. */
|
|
1443
|
-
kind: MotifRelationKind;
|
|
1444
|
-
/**
|
|
1445
|
-
* Whether the second statement begins where the first ends, which is what
|
|
1446
|
-
* separates a sequence from a restatement elsewhere in the piece: a
|
|
1447
|
-
* `'transposition'` that is one is a real sequence, a `'tonalTransposition'`
|
|
1448
|
-
* that is one is a tonal sequence.
|
|
1449
|
-
*/
|
|
1450
|
-
sequence: boolean;
|
|
1451
|
-
/** Semitones from the first statement's first note to the second's. */
|
|
1452
|
-
semitones: number;
|
|
1453
|
-
/** The same distance named as a spelled interval. */
|
|
1454
|
-
interval: SpelledInterval;
|
|
1455
|
-
/** Scale degrees the second statement stands above the first, when tonal. */
|
|
1456
|
-
degrees?: number;
|
|
1457
|
-
/**
|
|
1458
|
-
* How much the second statement is stretched against the first: 2 for doubled
|
|
1459
|
-
* note values, 0.5 for halved, 1 for unchanged.
|
|
1460
|
-
*/
|
|
1461
|
-
timeRatio: number;
|
|
1462
|
-
/** Why the pair was given that name. */
|
|
1463
|
-
rationale: string;
|
|
1464
|
-
};
|
|
1465
|
-
/**
|
|
1466
|
-
* Anything that can be read as a melodic line: a motif, or plain note events.
|
|
1467
|
-
*
|
|
1468
|
-
* @category Arrangement & Analysis
|
|
1469
|
-
*/
|
|
1470
|
-
type MelodicPhrase = MotifData | readonly NoteEvent[];
|
|
1471
|
-
/**
|
|
1472
|
-
* How alike two lines are, and how the answer was reached.
|
|
1473
|
-
*
|
|
1474
|
-
* @category Arrangement & Analysis
|
|
1475
|
-
*/
|
|
1476
|
-
type MelodicComparison = {
|
|
1477
|
-
/** Overall likeness in [0, 1]; 1 for the same line, transposition included. */
|
|
1478
|
-
similarity: number;
|
|
1479
|
-
/** Likeness of the interval sequences alone, in [0, 1]. */
|
|
1480
|
-
pitchSimilarity: number;
|
|
1481
|
-
/** Likeness of the rhythmic profiles alone, in [0, 1]. */
|
|
1482
|
-
rhythmSimilarity: number;
|
|
1483
|
-
/** Why the lines scored what they did. */
|
|
1484
|
-
rationale: string;
|
|
1485
|
-
};
|
|
1486
1615
|
/**
|
|
1487
1616
|
* Find the cells a melody keeps coming back to.
|
|
1488
1617
|
*
|
|
@@ -1496,9 +1625,11 @@ type MelodicComparison = {
|
|
|
1496
1625
|
* rather than every fragment of it.
|
|
1497
1626
|
*
|
|
1498
1627
|
* The melody is expected to be monophonic, as {@link analyzeVoice} expects a
|
|
1499
|
-
* voice to be; split polyphonic material into lines first.
|
|
1500
|
-
*
|
|
1501
|
-
* as
|
|
1628
|
+
* voice to be; split polyphonic material into lines first. Notes struck together
|
|
1629
|
+
* are read as one event, the highest of them standing for it, so a chord is
|
|
1630
|
+
* reduced to its top voice rather than read as a line of its own. Onsets are
|
|
1631
|
+
* expected to be quantised, since two statements must agree on their rhythm to
|
|
1632
|
+
* be recognised as one motif.
|
|
1502
1633
|
*
|
|
1503
1634
|
* @param notes The melody, in time order. Notes that never sound are dropped.
|
|
1504
1635
|
* @param opts Cell-length bounds and the recurrence threshold; see
|
|
@@ -1529,7 +1660,13 @@ declare function extractMotifs(notes: readonly NoteEvent[], opts?: ExtractMotifs
|
|
|
1529
1660
|
* caller names one it already has — a subject, an answer, a phrase lifted out of
|
|
1530
1661
|
* a score — so that it can be handed to {@link relateMotifs}.
|
|
1531
1662
|
*
|
|
1532
|
-
*
|
|
1663
|
+
* The cell is expected to be monophonic, as {@link analyzeVoice} expects a voice
|
|
1664
|
+
* to be. Notes struck together are read as one event, the highest of them
|
|
1665
|
+
* standing for it, so a chord is reduced to its top voice rather than read as a
|
|
1666
|
+
* line of its own.
|
|
1667
|
+
*
|
|
1668
|
+
* @param notes The cell, in time order. Notes that never sound are dropped, and
|
|
1669
|
+
* notes sharing an onset are folded to their top voice.
|
|
1533
1670
|
* @returns The motif, carrying exactly one occurrence.
|
|
1534
1671
|
* @example
|
|
1535
1672
|
* ```ts
|
|
@@ -1549,102 +1686,74 @@ declare function extractMotifs(notes: readonly NoteEvent[], opts?: ExtractMotifs
|
|
|
1549
1686
|
* @category Arrangement & Analysis
|
|
1550
1687
|
*/
|
|
1551
1688
|
declare function motifFromNotes(notes: readonly NoteEvent[]): MotifData;
|
|
1689
|
+
|
|
1552
1690
|
/**
|
|
1553
|
-
*
|
|
1691
|
+
* What every reading of a melody has to agree on first.
|
|
1554
1692
|
*
|
|
1555
|
-
*
|
|
1556
|
-
*
|
|
1557
|
-
*
|
|
1558
|
-
*
|
|
1559
|
-
*
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
*
|
|
1564
|
-
* first moved by scale degrees rather than by semitones. That is the tonal
|
|
1565
|
-
* answer to the real one, and the two are kept apart: a real transposition keeps
|
|
1566
|
-
* every interval literally, a tonal one lets the key resize them, so a subject
|
|
1567
|
-
* answered a step higher reads as `'transposition'` when its major second stays
|
|
1568
|
-
* major and as `'tonalTransposition'` when the scale turns it minor.
|
|
1693
|
+
* A melody is compared, named and classified by three modules here, and all
|
|
1694
|
+
* three start from the same two questions: which notes sound, in what order,
|
|
1695
|
+
* and what the gaps between their onsets are. Answered separately they would
|
|
1696
|
+
* drift — one reading folding a chord to its top voice and another not — so
|
|
1697
|
+
* they are answered once, here.
|
|
1698
|
+
*/
|
|
1699
|
+
|
|
1700
|
+
/**
|
|
1701
|
+
* Anything that can be read as a melodic line: a motif, or plain note events.
|
|
1569
1702
|
*
|
|
1570
|
-
* @param a The model statement.
|
|
1571
|
-
* @param b The statement to name against it.
|
|
1572
|
-
* @param key Key context for the tonal reading; without it, a statement that
|
|
1573
|
-
* only holds diatonically is not recognised.
|
|
1574
|
-
* @returns The relation, or null when the two stand in none.
|
|
1575
|
-
* @example
|
|
1576
|
-
* ```ts
|
|
1577
|
-
* import { majorKey, motifFromNotes, relateMotifs } from '@libraz/libcantus';
|
|
1578
|
-
* const model = motifFromNotes([
|
|
1579
|
-
* { pitch: 60, startBeat: 0, durationBeat: 1 },
|
|
1580
|
-
* { pitch: 62, startBeat: 1, durationBeat: 1 },
|
|
1581
|
-
* { pitch: 64, startBeat: 2, durationBeat: 1 },
|
|
1582
|
-
* ]);
|
|
1583
|
-
* const answer = motifFromNotes([
|
|
1584
|
-
* { pitch: 62, startBeat: 3, durationBeat: 1 },
|
|
1585
|
-
* { pitch: 64, startBeat: 4, durationBeat: 1 },
|
|
1586
|
-
* { pitch: 65, startBeat: 5, durationBeat: 1 },
|
|
1587
|
-
* ]);
|
|
1588
|
-
* relateMotifs(model, answer, majorKey(0))?.kind; // 'tonalTransposition'
|
|
1589
|
-
* ```
|
|
1590
1703
|
* @category Arrangement & Analysis
|
|
1591
1704
|
*/
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
*
|
|
1596
|
-
*
|
|
1597
|
-
*
|
|
1598
|
-
*
|
|
1599
|
-
*
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
*
|
|
1604
|
-
*
|
|
1605
|
-
* its pitch shape, but a figure in a wholly different rhythm is a different
|
|
1606
|
-
* figure.
|
|
1607
|
-
*
|
|
1608
|
-
* @param a The first line: a motif, or plain note events.
|
|
1609
|
-
* @param b The second line.
|
|
1610
|
-
* @returns The overall likeness, the two terms behind it, and a rationale.
|
|
1611
|
-
* @example
|
|
1612
|
-
* ```ts
|
|
1613
|
-
* import { compareMelodies } from '@libraz/libcantus';
|
|
1614
|
-
* const line = [
|
|
1615
|
-
* { pitch: 60, startBeat: 0, durationBeat: 1 },
|
|
1616
|
-
* { pitch: 62, startBeat: 1, durationBeat: 1 },
|
|
1617
|
-
* { pitch: 64, startBeat: 2, durationBeat: 1 },
|
|
1618
|
-
* ];
|
|
1619
|
-
* compareMelodies(line, line).similarity; // 1
|
|
1620
|
-
* ```
|
|
1705
|
+
type MelodicPhrase = MotifData | readonly NoteEvent[];
|
|
1706
|
+
|
|
1707
|
+
/**
|
|
1708
|
+
* The shape of a line: which way it moves, and what that adds up to.
|
|
1709
|
+
*
|
|
1710
|
+
* A contour is the melody with its pitches forgotten — the sequence of ups and
|
|
1711
|
+
* downs alone — which is what lets a phrase be called an arch whatever key it
|
|
1712
|
+
* is in and whatever intervals it is built from.
|
|
1713
|
+
*/
|
|
1714
|
+
|
|
1715
|
+
/**
|
|
1716
|
+
* Step direction between two consecutive notes.
|
|
1717
|
+
*
|
|
1621
1718
|
* @category Arrangement & Analysis
|
|
1622
1719
|
*/
|
|
1623
|
-
|
|
1720
|
+
type ContourDirection = 'up' | 'down' | 'same';
|
|
1624
1721
|
/**
|
|
1625
|
-
*
|
|
1722
|
+
* The overall shape of a line.
|
|
1626
1723
|
*
|
|
1627
|
-
* The
|
|
1628
|
-
*
|
|
1629
|
-
*
|
|
1630
|
-
*
|
|
1724
|
+
* The first four names are the vocabulary the motif generator's contours are
|
|
1725
|
+
* written in, and mean the same here. `'static'` is the shape a generator never
|
|
1726
|
+
* asks for and an analysis regularly meets: a line that does not move. A line
|
|
1727
|
+
* that dips and comes back — an arch upside down — reads as `'wave'`, since the
|
|
1728
|
+
* shared vocabulary has no name of its own for it.
|
|
1729
|
+
*
|
|
1730
|
+
* A wave has to turn more than once to be heard as one, so a cell the generator
|
|
1731
|
+
* writes for `'wave'` reads back as `'wave'` only from three bars up; the one-
|
|
1732
|
+
* and two-bar cells turn once and read as `'arch'`. The other three shapes come
|
|
1733
|
+
* back under their own name at every length.
|
|
1734
|
+
*
|
|
1735
|
+
* @category Arrangement & Analysis
|
|
1736
|
+
*/
|
|
1737
|
+
type MelodicContourShape = 'arch' | 'ascending' | 'descending' | 'wave' | 'static';
|
|
1738
|
+
/**
|
|
1739
|
+
* The abstract shape of a line: its step directions and what they add up to.
|
|
1631
1740
|
*
|
|
1632
|
-
* @param a The first line: a motif, or plain note events.
|
|
1633
|
-
* @param b The second line.
|
|
1634
|
-
* @returns The likeness in [0, 1].
|
|
1635
|
-
* @example
|
|
1636
|
-
* ```ts
|
|
1637
|
-
* import { melodicSimilarity } from '@libraz/libcantus';
|
|
1638
|
-
* const line = [
|
|
1639
|
-
* { pitch: 60, startBeat: 0, durationBeat: 1 },
|
|
1640
|
-
* { pitch: 62, startBeat: 1, durationBeat: 1 },
|
|
1641
|
-
* { pitch: 64, startBeat: 2, durationBeat: 1 },
|
|
1642
|
-
* ];
|
|
1643
|
-
* melodicSimilarity(line, line); // 1
|
|
1644
|
-
* ```
|
|
1645
1741
|
* @category Arrangement & Analysis
|
|
1646
1742
|
*/
|
|
1647
|
-
|
|
1743
|
+
type MelodicContour = {
|
|
1744
|
+
/** One direction per adjacent pair of notes, in time order. */
|
|
1745
|
+
directions: ContourDirection[];
|
|
1746
|
+
/** What the directions add up to. */
|
|
1747
|
+
shape: MelodicContourShape;
|
|
1748
|
+
/** Index of the highest note; ties keep the earliest, and -1 for a line with no notes. */
|
|
1749
|
+
peakIndex: number;
|
|
1750
|
+
/** Index of the lowest note; ties keep the earliest, and -1 for a line with no notes. */
|
|
1751
|
+
troughIndex: number;
|
|
1752
|
+
/** Semitone distance from the lowest note to the highest. */
|
|
1753
|
+
range: number;
|
|
1754
|
+
/** Why the line was given that shape. */
|
|
1755
|
+
rationale: string;
|
|
1756
|
+
};
|
|
1648
1757
|
/**
|
|
1649
1758
|
* Read the shape of a line.
|
|
1650
1759
|
*
|
|
@@ -1655,9 +1764,17 @@ declare function melodicSimilarity(a: MelodicPhrase, b: MelodicPhrase): number;
|
|
|
1655
1764
|
* Anything that keeps changing direction is a wave, and a line that does not move
|
|
1656
1765
|
* is static.
|
|
1657
1766
|
*
|
|
1767
|
+
* The line is expected to be monophonic, as {@link analyzeVoice} expects a voice
|
|
1768
|
+
* to be; split polyphonic material into lines first. Notes struck together are
|
|
1769
|
+
* read as one event, the highest of them standing for it — a chord and the note
|
|
1770
|
+
* after it trace one step, not a climb through the chord — so a piano part read
|
|
1771
|
+
* whole answers for its top voice rather than for a line no one plays.
|
|
1772
|
+
*
|
|
1658
1773
|
* @param notes The line: a motif, or plain note events. Notes that never sound
|
|
1659
|
-
* are dropped.
|
|
1660
|
-
* @returns The directions, the shape, the peak and trough, and a rationale.
|
|
1774
|
+
* are dropped, and notes sharing an onset are folded to their top voice.
|
|
1775
|
+
* @returns The directions, the shape, the peak and trough, and a rationale. A
|
|
1776
|
+
* line with no sounding notes is static with a range of 0, and its peak and
|
|
1777
|
+
* trough are -1: there is no note for them to point at.
|
|
1661
1778
|
* @example
|
|
1662
1779
|
* ```ts
|
|
1663
1780
|
* import { melodicContour } from '@libraz/libcantus';
|
|
@@ -1672,6 +1789,113 @@ declare function melodicSimilarity(a: MelodicPhrase, b: MelodicPhrase): number;
|
|
|
1672
1789
|
*/
|
|
1673
1790
|
declare function melodicContour(notes: MelodicPhrase): MelodicContour;
|
|
1674
1791
|
|
|
1792
|
+
/**
|
|
1793
|
+
* The transformation between two statements of a motif, named.
|
|
1794
|
+
*
|
|
1795
|
+
* Two cells stand in a relation when one is the other put through a device the
|
|
1796
|
+
* repertoire has a name for — repetition, transposition, inversion, retrograde,
|
|
1797
|
+
* augmentation — and naming it is what turns a pair of similar phrases into an
|
|
1798
|
+
* account of how the second was made from the first.
|
|
1799
|
+
*/
|
|
1800
|
+
|
|
1801
|
+
/**
|
|
1802
|
+
* How one statement of a motif stands to another.
|
|
1803
|
+
*
|
|
1804
|
+
* `'transposition'` is the literal one — every interval preserved, which is what
|
|
1805
|
+
* makes a sequence built on it a *real* sequence. `'tonalTransposition'` shifts
|
|
1806
|
+
* by scale degrees instead and lets the key resize the intervals, which is what
|
|
1807
|
+
* makes a sequence built on it a *tonal* sequence; the two are different devices
|
|
1808
|
+
* and are never reported as one. `'augmentation'` and `'diminution'` name the
|
|
1809
|
+
* relation only when the pitches are untouched, so an inversion in doubled note
|
|
1810
|
+
* values reads as `'inversion'` with a `timeRatio` of 2 rather than losing the
|
|
1811
|
+
* inversion to the stretch.
|
|
1812
|
+
*
|
|
1813
|
+
* @category Arrangement & Analysis
|
|
1814
|
+
*/
|
|
1815
|
+
type MotifRelationKind = 'repetition' | 'transposition' | 'tonalTransposition' | 'inversion' | 'retrograde' | 'retrogradeInversion' | 'augmentation' | 'diminution';
|
|
1816
|
+
/**
|
|
1817
|
+
* The transformation that turns one motif into another.
|
|
1818
|
+
*
|
|
1819
|
+
* @category Arrangement & Analysis
|
|
1820
|
+
*/
|
|
1821
|
+
type MotifRelation = {
|
|
1822
|
+
/** The named transformation. */
|
|
1823
|
+
kind: MotifRelationKind;
|
|
1824
|
+
/**
|
|
1825
|
+
* Whether the second statement begins where the first ends, which is what
|
|
1826
|
+
* separates a sequence from a restatement elsewhere in the piece: a
|
|
1827
|
+
* `'transposition'` that is one is a real sequence, a `'tonalTransposition'`
|
|
1828
|
+
* that is one is a tonal sequence.
|
|
1829
|
+
*/
|
|
1830
|
+
sequence: boolean;
|
|
1831
|
+
/** Semitones from the first statement's first note to the second's. */
|
|
1832
|
+
semitones: number;
|
|
1833
|
+
/** The same distance named as a spelled interval. */
|
|
1834
|
+
interval: SpelledInterval;
|
|
1835
|
+
/** Scale degrees the second statement stands above the first, when tonal. */
|
|
1836
|
+
degrees?: number;
|
|
1837
|
+
/**
|
|
1838
|
+
* How much the second statement is stretched against the first: 2 for doubled
|
|
1839
|
+
* note values, 0.5 for halved, 1 for unchanged.
|
|
1840
|
+
*
|
|
1841
|
+
* Measured in the direction the relation names, so a retrograde that kept
|
|
1842
|
+
* every note value reports 1 however uneven those values are: it is compared
|
|
1843
|
+
* against the model played backwards, not against the model as written.
|
|
1844
|
+
*/
|
|
1845
|
+
timeRatio: number;
|
|
1846
|
+
/** Why the pair was given that name. */
|
|
1847
|
+
rationale: string;
|
|
1848
|
+
};
|
|
1849
|
+
/**
|
|
1850
|
+
* Name how two statements of a motif relate.
|
|
1851
|
+
*
|
|
1852
|
+
* The two are compared as shapes, not as pitches: the interval sequences say
|
|
1853
|
+
* which transformations could name the pair and the onset gaps say which of
|
|
1854
|
+
* them does, so a statement a fourth higher in doubled note values is
|
|
1855
|
+
* recognised for what it is, and a cell that reads as both an inversion and a
|
|
1856
|
+
* retrograde is named by the way its rhythm runs rather than by which name came
|
|
1857
|
+
* to hand first. A pair whose rhythms correspond in neither direction — the same
|
|
1858
|
+
* way round for a repetition or a transposition, the model played backwards for
|
|
1859
|
+
* a retrograde, note values and all — is not a transformation of the motif but a
|
|
1860
|
+
* different figure, and answers null; {@link melodicSimilarity} is what scores
|
|
1861
|
+
* those.
|
|
1862
|
+
*
|
|
1863
|
+
* With a `key` in hand the search also asks whether the second statement is the
|
|
1864
|
+
* first moved by scale degrees rather than by semitones. That is the tonal
|
|
1865
|
+
* answer to the real one, and the two are kept apart: a real transposition keeps
|
|
1866
|
+
* every interval literally, a tonal one lets the key resize them, so a subject
|
|
1867
|
+
* answered a step higher reads as `'transposition'` when its major second stays
|
|
1868
|
+
* major and as `'tonalTransposition'` when the scale turns it minor.
|
|
1869
|
+
*
|
|
1870
|
+
* @param a The model statement.
|
|
1871
|
+
* @param b The statement to name against it.
|
|
1872
|
+
* @param keyLike Key context for the tonal reading. Without one that reading is
|
|
1873
|
+
* unavailable, and a statement holding only diatonically is left unnamed
|
|
1874
|
+
* unless its interval pattern also fits a member of the retrograde family, in
|
|
1875
|
+
* which case it is named there: a triad restated a degree higher swaps two
|
|
1876
|
+
* adjacent interval sizes, which is what a retrograde inversion does to it as
|
|
1877
|
+
* well, and equal note values read the same way round in both directions, so
|
|
1878
|
+
* the notes alone cannot separate the two. A key separates them.
|
|
1879
|
+
* @returns The relation, or null when the two stand in none.
|
|
1880
|
+
* @example
|
|
1881
|
+
* ```ts
|
|
1882
|
+
* import { majorKey, motifFromNotes, relateMotifs } from '@libraz/libcantus';
|
|
1883
|
+
* const model = motifFromNotes([
|
|
1884
|
+
* { pitch: 60, startBeat: 0, durationBeat: 1 },
|
|
1885
|
+
* { pitch: 62, startBeat: 1, durationBeat: 1 },
|
|
1886
|
+
* { pitch: 64, startBeat: 2, durationBeat: 1 },
|
|
1887
|
+
* ]);
|
|
1888
|
+
* const answer = motifFromNotes([
|
|
1889
|
+
* { pitch: 62, startBeat: 3, durationBeat: 1 },
|
|
1890
|
+
* { pitch: 64, startBeat: 4, durationBeat: 1 },
|
|
1891
|
+
* { pitch: 65, startBeat: 5, durationBeat: 1 },
|
|
1892
|
+
* ]);
|
|
1893
|
+
* relateMotifs(model, answer, majorKey(0))?.kind; // 'tonalTransposition'
|
|
1894
|
+
* ```
|
|
1895
|
+
* @category Arrangement & Analysis
|
|
1896
|
+
*/
|
|
1897
|
+
declare function relateMotifs(a: MotifData, b: MotifData, keyLike?: SpelledKeyLike): MotifRelation | null;
|
|
1898
|
+
|
|
1675
1899
|
/**
|
|
1676
1900
|
* Harmonic reduction: which chords carry the progression and which decorate it.
|
|
1677
1901
|
*
|
|
@@ -1734,9 +1958,11 @@ type ReducedChord = {
|
|
|
1734
1958
|
* What a reduction treats as the frame.
|
|
1735
1959
|
*
|
|
1736
1960
|
* `'function'` is the functional reading: the tonic, the dominant and the
|
|
1737
|
-
* chords that cadence are the frame. `'duration'` is the salience reading:
|
|
1738
|
-
*
|
|
1739
|
-
*
|
|
1961
|
+
* chords that cadence are the frame. `'duration'` is the salience reading: a
|
|
1962
|
+
* chord is the frame when it outlasts the chords around it — its length beats
|
|
1963
|
+
* the median of the other chords' — whatever function it carries. Nothing
|
|
1964
|
+
* outlasts anything in an even harmonic rhythm, so a loop or a vamp protects no
|
|
1965
|
+
* chord by length and the two figures decide, as they do under either reading.
|
|
1740
1966
|
*
|
|
1741
1967
|
* @category Arrangement & Analysis
|
|
1742
1968
|
*/
|
|
@@ -1801,4 +2027,4 @@ type ReduceProgressionOptions = {
|
|
|
1801
2027
|
*/
|
|
1802
2028
|
declare function reduceProgression(timeline: ChordTimeline, key: KeyContext, opts?: ReduceProgressionOptions): ReducedChord[];
|
|
1803
2029
|
|
|
1804
|
-
export {
|
|
2030
|
+
export { motifFromNotes as $, type ArrangementAnalysis as A, type TrackRole as B, type ChordMatch as C, type DetectChordOptions as D, type ExtractMotifsOptions as E, type FormSection as F, analyzeArrangement as G, type Hypermeter as H, analyzePolyphony as I, augmentedSixthChord as J, type KeyMatch as K, augmentedSixthFromPitchClasses as L, MODAL_SCALE_NAMES as M, augmentedSixthKind as N, createArrangementSession as O, type Phrase as P, detectChord as Q, type ReduceProgressionOptions as R, type StructuralCadence as S, type TensionPoint as T, detectChordBest as U, detectKey as V, detectKeyBest as W, detectKeyFromNotes as X, extractMotifs as Y, hypermeter as Z, melodicContour as _, type ArrangementOptions as a, phrasesFromTimeline as a0, reduceProgression as a1, relateMotifs as a2, sectionsFromNotes as a3, spellAugmentedSixth as a4, structuralCadences as a5, tensionCurve as a6, tensionCurveFrom as a7, type ArrangementSession as b, type ArrangementTrack as c, type AugmentedSixthKind as d, type Conflict as e, type ConflictPartner as f, type ContourDirection as g, type DetectKeyOptions as h, type FormSectionOptions as i, type HypermeterOptions as j, type MelodicContour as k, type MelodicContourShape as l, type MelodicPhrase as m, type ModalCandidate as n, type ModalScaleName as o, type MotifData as p, type MotifOccurrence as q, type MotifRelation as r, type MotifRelationKind as s, type PhraseOptions as t, type PhraseSignal as u, type ReducedChord as v, type ReductionBasis as w, type ReductionLevel as x, type TrackAnalysis as y, type TrackEdit as z };
|