@libraz/libcantus 1.2.0 → 1.4.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/NOTICE +63 -0
- package/README.md +7 -1
- package/README_ja.md +17 -11
- package/dist/analyze/index.cjs +31 -7
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +161 -13
- package/dist/analyze/index.d.ts +161 -13
- package/dist/analyze/index.js +37 -13
- package/dist/{chunk-NB25P3EH.js → chunk-2G5MCGYU.js} +33 -11
- package/dist/chunk-2G5MCGYU.js.map +1 -0
- package/dist/{chunk-NM7UAMC3.cjs → chunk-3FDBMIPR.cjs} +64 -64
- package/dist/chunk-3FDBMIPR.cjs.map +1 -0
- package/dist/{chunk-HPVSH7SF.cjs → chunk-3MDOEFIQ.cjs} +618 -954
- package/dist/chunk-3MDOEFIQ.cjs.map +1 -0
- package/dist/{chunk-FBH75DAY.js → chunk-5MWRBYAT.js} +560 -159
- package/dist/chunk-5MWRBYAT.js.map +1 -0
- package/dist/{chunk-J7FHVZII.cjs → chunk-6TTBEON3.cjs} +3074 -740
- package/dist/chunk-6TTBEON3.cjs.map +1 -0
- package/dist/{chunk-UMWZ4ZET.js → chunk-7NQ6AL3H.js} +4 -4
- package/dist/chunk-7NQ6AL3H.js.map +1 -0
- package/dist/{chunk-HWHGOVO6.cjs → chunk-E3QO3UET.cjs} +31 -23
- package/dist/chunk-E3QO3UET.cjs.map +1 -0
- package/dist/{chunk-H2KJHBW4.js → chunk-FJFULJZE.js} +2375 -191
- package/dist/chunk-FJFULJZE.js.map +1 -0
- package/dist/{chunk-Q6LFSAKV.js → chunk-FK3DGAIZ.js} +2657 -323
- package/dist/chunk-FK3DGAIZ.js.map +1 -0
- package/dist/chunk-GEDTJHAC.cjs.map +1 -1
- package/dist/{chunk-RFIBF2RR.js → chunk-H7FVMBUC.js} +138 -65
- package/dist/chunk-H7FVMBUC.js.map +1 -0
- package/dist/{chunk-DSMJRXCZ.cjs → chunk-HYSVSFNI.cjs} +931 -530
- package/dist/chunk-HYSVSFNI.cjs.map +1 -0
- package/dist/{chunk-35NBV2FT.cjs → chunk-KMYGRFZ6.cjs} +47 -24
- package/dist/chunk-KMYGRFZ6.cjs.map +1 -0
- package/dist/chunk-LQZQDBCD.cjs +5513 -0
- package/dist/chunk-LQZQDBCD.cjs.map +1 -0
- package/dist/{chunk-PM4XJE2Y.cjs → chunk-P3CPXAJ5.cjs} +76 -54
- package/dist/chunk-P3CPXAJ5.cjs.map +1 -0
- package/dist/{chunk-S5BKZZGM.cjs → chunk-S3QELJUE.cjs} +72 -56
- package/dist/chunk-S3QELJUE.cjs.map +1 -0
- package/dist/{chunk-PUKJP2Z5.js → chunk-TXFWSU5D.js} +31 -8
- package/dist/chunk-TXFWSU5D.js.map +1 -0
- package/dist/{chunk-76ZBTRG2.cjs → chunk-U4EQTDGN.cjs} +258 -218
- package/dist/chunk-U4EQTDGN.cjs.map +1 -0
- package/dist/chunk-UGLFDG7L.cjs.map +1 -1
- package/dist/{chunk-HYJJ2V2I.js → chunk-UTE5A36R.js} +483 -819
- package/dist/chunk-UTE5A36R.js.map +1 -0
- package/dist/{chunk-NFJ4P6ZZ.js → chunk-UZKQISRF.js} +17 -9
- package/dist/chunk-UZKQISRF.js.map +1 -0
- package/dist/{chunk-7KG3RTYS.js → chunk-VL5NXVCN.js} +281 -155
- package/dist/chunk-VL5NXVCN.js.map +1 -0
- package/dist/{chunk-CGBADIO5.cjs → chunk-WOMCXN2W.cjs} +328 -202
- package/dist/chunk-WOMCXN2W.cjs.map +1 -0
- package/dist/{chunk-3R3QVKY5.cjs → chunk-YDGMWH43.cjs} +397 -324
- package/dist/chunk-YDGMWH43.cjs.map +1 -0
- package/dist/{chunk-AGOVW7U6.js → chunk-YYVXRV3V.js} +72 -56
- package/dist/chunk-YYVXRV3V.js.map +1 -0
- package/dist/{chunk-M5RYMAFI.js → chunk-ZLNSH4UL.js} +71 -31
- package/dist/chunk-ZLNSH4UL.js.map +1 -0
- package/dist/{coerce-DRERzdve.d.cts → coerce-CUhHc3Tu.d.ts} +16 -8
- package/dist/{coerce-DP0vYu-x.d.ts → coerce-Ytt2Eiq9.d.cts} +16 -8
- package/dist/core/index.cjs +5 -5
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +9 -8
- package/dist/core/index.d.ts +9 -8
- package/dist/core/index.js +4 -4
- package/dist/generate/index.cjs +20 -8
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +105 -17
- package/dist/generate/index.d.ts +105 -17
- package/dist/generate/index.js +19 -7
- package/dist/{index-CL4b4gUQ.d.ts → index-5VJgKz_Q.d.cts} +6 -2
- package/dist/{index-B9QLziDe.d.cts → index-BLuDesVG.d.ts} +20 -13
- package/dist/{index-BHIUyjhZ.d.ts → index-BV6APVa6.d.cts} +20 -13
- package/dist/{index-BMweUlm5.d.cts → index-Bf0Sv8a9.d.ts} +6 -2
- package/dist/{index-Dw2DP7vm.d.ts → index-BkT21EMv.d.cts} +3 -2
- package/dist/{index-BL5N2Oyz.d.cts → index-C7KCaTRz.d.ts} +3 -2
- package/dist/{index-Cy15oTvh.d.ts → index-C9MYbuKS.d.cts} +7 -3
- package/dist/{index-Cy15oTvh.d.cts → index-C9MYbuKS.d.ts} +7 -3
- package/dist/{index-BNSM-DSk.d.cts → index-DVInzCDS.d.cts} +533 -28
- package/dist/{index-9eoQs2C1.d.ts → index-Dg-SAfhz.d.ts} +6 -4
- package/dist/{index-BJgP97N1.d.ts → index-jgeug9EA.d.ts} +533 -28
- package/dist/{index-cHvbYgJI.d.cts → index-pQihL4z7.d.cts} +6 -4
- package/dist/index.cjs +49 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -13
- package/dist/index.d.ts +13 -13
- package/dist/index.js +55 -19
- package/dist/{masks-Cc7-MzzY.d.ts → masks-BnzXnBj0.d.cts} +3 -2
- package/dist/{masks-pADfTOiD.d.cts → masks-tycmkrgs.d.ts} +3 -2
- package/dist/model/index.cjs +12 -12
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +259 -48
- package/dist/model/index.d.ts +259 -48
- package/dist/model/index.js +11 -11
- package/dist/{positional-DJgs6ltD.d.ts → positional-CscpxtlE.d.cts} +3 -2
- package/dist/{positional-DMZer-FM.d.cts → positional-DLnfUgqG.d.ts} +3 -2
- package/dist/{index-BRMbPkHE.d.ts → profile-B4WqcM4H.d.ts} +85 -610
- package/dist/{index-DGCNKAUr.d.cts → profile-BJd1XkPB.d.cts} +85 -610
- package/dist/theory/index.cjs +5 -5
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +18 -14
- package/dist/theory/index.d.ts +18 -14
- package/dist/theory/index.js +4 -4
- package/dist/{index-CJBBiAmU.d.ts → types-7mGFwvMm.d.ts} +1210 -31
- package/dist/{index-BBWNZS0f.d.cts → types-_ofpb2be.d.cts} +1210 -31
- package/package.json +13 -13
- package/dist/chunk-35NBV2FT.cjs.map +0 -1
- package/dist/chunk-3R3QVKY5.cjs.map +0 -1
- package/dist/chunk-76ZBTRG2.cjs.map +0 -1
- package/dist/chunk-7KG3RTYS.js.map +0 -1
- package/dist/chunk-AGOVW7U6.js.map +0 -1
- package/dist/chunk-CGBADIO5.cjs.map +0 -1
- package/dist/chunk-DSMJRXCZ.cjs.map +0 -1
- package/dist/chunk-FBH75DAY.js.map +0 -1
- package/dist/chunk-H2KJHBW4.js.map +0 -1
- package/dist/chunk-HPVSH7SF.cjs.map +0 -1
- package/dist/chunk-HWHGOVO6.cjs.map +0 -1
- package/dist/chunk-HYJJ2V2I.js.map +0 -1
- package/dist/chunk-J7FHVZII.cjs.map +0 -1
- package/dist/chunk-M5RYMAFI.js.map +0 -1
- package/dist/chunk-NB25P3EH.js.map +0 -1
- package/dist/chunk-NFJ4P6ZZ.js.map +0 -1
- package/dist/chunk-NM7UAMC3.cjs.map +0 -1
- package/dist/chunk-PM4XJE2Y.cjs.map +0 -1
- package/dist/chunk-PUKJP2Z5.js.map +0 -1
- package/dist/chunk-Q6LFSAKV.js.map +0 -1
- package/dist/chunk-RFIBF2RR.js.map +0 -1
- package/dist/chunk-S5BKZZGM.cjs.map +0 -1
- package/dist/chunk-SGLEQVJH.cjs +0 -3329
- package/dist/chunk-SGLEQVJH.cjs.map +0 -1
- package/dist/chunk-UMWZ4ZET.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { T as TimeSignature, b as MeterLike } from './index-
|
|
2
|
-
import { a as Articulation, h as NoteEvent } from './index-
|
|
3
|
-
import { S as SeedPath, d as PositionalRng, I as InstrumentProfile, f as StringedProfile } from './positional-
|
|
4
|
-
import { d as ChordQuality, e as ChordSegment, c as ChordLike, K as KeyLike, b as Chord, m as ProfileWeights, g as ChordSpan, n as ResolvedKey, r as SpelledKeyLike } from './coerce-
|
|
5
|
-
import {
|
|
6
|
-
import { H as HarmonyRole } from './index-
|
|
1
|
+
import { T as TimeSignature, b as MeterLike, c as MeterMap } from './index-Bf0Sv8a9.js';
|
|
2
|
+
import { a as Articulation, h as NoteEvent } from './index-C9MYbuKS.js';
|
|
3
|
+
import { S as SeedPath, d as PositionalRng, I as InstrumentProfile, f as StringedProfile } from './positional-DLnfUgqG.js';
|
|
4
|
+
import { d as ChordQuality, e as ChordSegment, c as ChordLike, K as KeyLike, b as Chord, m as ProfileWeights, g as ChordSpan, n as ResolvedKey, r as SpelledKeyLike } from './coerce-CUhHc3Tu.js';
|
|
5
|
+
import { h as ChordTimeline, e as CadenceType, v as MelodicContourShape, P as MotifRelationSummary, a5 as ReferenceProfile, b as BorrowedSource, o as HarmonicFunction } from './types-7mGFwvMm.js';
|
|
6
|
+
import { H as HarmonyRole } from './index-C7KCaTRz.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* The samplers a generator needs, each addressed by the position it is drawing
|
|
@@ -547,8 +547,9 @@ declare function thin<T extends GridEvent>(events: readonly T[], amount: number,
|
|
|
547
547
|
* Fill in the gaps of a figure, one note per gap.
|
|
548
548
|
*
|
|
549
549
|
* Doubling is what a player does when asked for more of the same rather than
|
|
550
|
-
* for something different: the added note sits halfway between two
|
|
551
|
-
*
|
|
550
|
+
* for something different: the added note sits halfway between two onsets of
|
|
551
|
+
* one stream (the limb, else the voice), takes its predecessor's identity, and
|
|
552
|
+
* is played softer. A gap between two limbs is no gap for either of them.
|
|
552
553
|
*
|
|
553
554
|
* @param events The figure, which need not be sorted.
|
|
554
555
|
* @param spanSteps Length of the figure in sixteenths.
|
|
@@ -574,6 +575,9 @@ declare function halfTime<T extends GridEvent>(events: readonly T[], spanSteps?:
|
|
|
574
575
|
* The repeat is what makes this the mirror of {@link halfTime} rather than a
|
|
575
576
|
* figure with a hole in it: the bar stays full.
|
|
576
577
|
*
|
|
578
|
+
* A whole step halves onto the nearest sixteenth; an onset off the straight
|
|
579
|
+
* grid, a triplet, halves exactly and stays on its own grid.
|
|
580
|
+
*
|
|
577
581
|
* Halving brings positions together, and two onsets of one stream landing on
|
|
578
582
|
* the same step are one stroke played louder rather than two: a drum struck
|
|
579
583
|
* twice at the same instant is a pair of note-ons a reader turns into a hung or
|
|
@@ -713,8 +717,8 @@ type DeformOptions = {
|
|
|
713
717
|
* const busier = deform(figure, { rhythmic: 0.9 }, draw, 'bar', 0);
|
|
714
718
|
* // Above the neutral middle the figure is syncopated: onsets are added off
|
|
715
719
|
* // the beat, and the result comes back sorted by position.
|
|
716
|
-
* busier.length; //
|
|
717
|
-
* busier.map((event) => event.step); // [0, 3, 4,
|
|
720
|
+
* busier.length; // 6
|
|
721
|
+
* busier.map((event) => event.step); // [0, 3, 4, 8, 11, 12]
|
|
718
722
|
* ```
|
|
719
723
|
*
|
|
720
724
|
* @category Composition
|
|
@@ -747,9 +751,12 @@ declare function withinCeiling(events: readonly GridEvent[], bpm: number | undef
|
|
|
747
751
|
* Given a sequence of chord segments and a key, this builds a monophonic bass
|
|
748
752
|
* line in a chosen low register. Several idiomatic styles are supported, from a
|
|
749
753
|
* single held root per segment to a quarter-note walking line that leads by
|
|
750
|
-
* step into each chord change.
|
|
751
|
-
*
|
|
752
|
-
*
|
|
754
|
+
* step into each chord change. Root-position chord tones are kept in an
|
|
755
|
+
* octave-wide bass band `[low, low + 12]`. A slash chord's other tones sit up to
|
|
756
|
+
* an octave above its placed bass, so they can rise past the top of the band,
|
|
757
|
+
* and the `pop` octave pickup and the walking approach notes leave the band by
|
|
758
|
+
* design; consecutive notes can therefore lie more than an octave apart. Given
|
|
759
|
+
* a seed the output is fully reproducible.
|
|
753
760
|
*
|
|
754
761
|
* Positions and durations are measured in quarter-note beats, matching the
|
|
755
762
|
* library-wide convention.
|
|
@@ -847,9 +854,12 @@ type BassLineOptions = {
|
|
|
847
854
|
* Generate a bass line following a chord placement.
|
|
848
855
|
*
|
|
849
856
|
* Each segment contributes notes in the chosen bass register per the selected
|
|
850
|
-
* style
|
|
851
|
-
*
|
|
852
|
-
*
|
|
857
|
+
* style. Root-position chord tones lie in the `[low, low + 12]` band; a slash
|
|
858
|
+
* chord's other tones sit up to an octave above its placed bass, and the `pop`
|
|
859
|
+
* octave pickup and the walking approach notes leave the band, so consecutive
|
|
860
|
+
* notes can be more than an octave apart. Every note's duration extends to the
|
|
861
|
+
* next onset (the final note extends to the last segment's end). Given a seed
|
|
862
|
+
* the output is fully reproducible.
|
|
853
863
|
*
|
|
854
864
|
* The `pop` style's pickups are drawn per position, so raising
|
|
855
865
|
* `complexity.rhythmic` adds pickups without moving the notes already written.
|
|
@@ -1247,6 +1257,8 @@ declare function generateDrums(opts: DrumsOptions): DrumHit[];
|
|
|
1247
1257
|
type HumanizeOptions = {
|
|
1248
1258
|
/**
|
|
1249
1259
|
* Time signature used to derive metric accents, in any form that names one.
|
|
1260
|
+
* A meter map is read bar by bar, so a note after a change is accented in the
|
|
1261
|
+
* signature in force where it sounds.
|
|
1250
1262
|
*
|
|
1251
1263
|
* @defaultValue 4/4
|
|
1252
1264
|
*/
|
|
@@ -1374,11 +1386,13 @@ type GrooveTemplate = {
|
|
|
1374
1386
|
* template so {@link applyGrooveTemplate} can verify the meter matches.
|
|
1375
1387
|
*
|
|
1376
1388
|
* @param events The (typically "groovy", human-played) events to analyze.
|
|
1377
|
-
* @param ts The time signature, used to compute the bar length.
|
|
1389
|
+
* @param ts The time signature, used to compute the bar length. A meter map
|
|
1390
|
+
* is accepted while it keeps one signature throughout.
|
|
1378
1391
|
* @param subdivision Grid resolution: equal grid steps per quarter-note beat.
|
|
1379
1392
|
* Defaults to a sixteenth-note grid, which is where the timing deviations a
|
|
1380
1393
|
* template records — swing, push, drag — are audible.
|
|
1381
1394
|
* @returns The extracted groove template.
|
|
1395
|
+
* @throws If `ts` changes signature.
|
|
1382
1396
|
* @category Rhythm & Meter
|
|
1383
1397
|
*/
|
|
1384
1398
|
declare function extractGrooveTemplate(events: readonly NoteEvent[], ts: MeterLike, subdivision?: number): GrooveTemplate;
|
|
@@ -1403,11 +1417,13 @@ declare function extractGrooveTemplate(events: readonly NoteEvent[], ts: MeterLi
|
|
|
1403
1417
|
*
|
|
1404
1418
|
* @param events The events to reshape.
|
|
1405
1419
|
* @param template The groove template, from {@link extractGrooveTemplate}.
|
|
1406
|
-
* @param ts The time signature, used to compute the bar length.
|
|
1420
|
+
* @param ts The time signature, used to compute the bar length. A meter map
|
|
1421
|
+
* is accepted while it keeps one signature throughout.
|
|
1407
1422
|
* @returns Reshaped copies of `events`, in input order.
|
|
1408
|
-
* @throws If `template.ts` is set and does not
|
|
1409
|
-
* not the number of slots a bar of `ts` holds
|
|
1410
|
-
* or if a slot carries a non-finite offset or
|
|
1423
|
+
* @throws If `ts` changes signature, if `template.ts` is set and does not
|
|
1424
|
+
* match `ts`, if `slotsPerBar` is not the number of slots a bar of `ts` holds
|
|
1425
|
+
* at the template's subdivision, or if a slot carries a non-finite offset or
|
|
1426
|
+
* a velocity outside [0, 127].
|
|
1411
1427
|
* @example
|
|
1412
1428
|
* ```ts
|
|
1413
1429
|
* import { extractGrooveTemplate, applyGrooveTemplate, parseTimeSignature } from '@libraz/libcantus';
|
|
@@ -1603,7 +1619,10 @@ declare function pickProgressionPreset(style: ProgStyle, ctx?: GenerationContext
|
|
|
1603
1619
|
* the secondary dominant (V7) of the following chord, flagged with
|
|
1604
1620
|
* `secondaryDominant`. Only a chord the key can make a local tonic is given one:
|
|
1605
1621
|
* nothing tonicizes a diminished triad, so the supertonic of a minor key takes
|
|
1606
|
-
* no dominant of its own
|
|
1622
|
+
* no dominant of its own, and a dominant seventh the key already contains
|
|
1623
|
+
* (the tonic seventh of mixolydian) is a native chord rather than an applied
|
|
1624
|
+
* one, so it is not inserted. A chord that already sounds a dominant seventh
|
|
1625
|
+
* onto the next one is left as written.
|
|
1607
1626
|
*
|
|
1608
1627
|
* @param opts Generation options.
|
|
1609
1628
|
* @returns One chord per bar in timeline order.
|
|
@@ -1674,7 +1693,7 @@ type HarmonizePlacement = {
|
|
|
1674
1693
|
* @category Reharmonization
|
|
1675
1694
|
*/
|
|
1676
1695
|
type HarmonizeOptions = {
|
|
1677
|
-
/** The melody to harmonize, in
|
|
1696
|
+
/** The melody to harmonize, in any order; it is read in onset order. */
|
|
1678
1697
|
melody: readonly MelodyNote[];
|
|
1679
1698
|
/**
|
|
1680
1699
|
* The key to harmonize in, or `'infer'` to estimate it from the melody's
|
|
@@ -1805,6 +1824,267 @@ type HarmonizeResult = {
|
|
|
1805
1824
|
}[];
|
|
1806
1825
|
};
|
|
1807
1826
|
|
|
1827
|
+
/**
|
|
1828
|
+
* A composition plan: what a piece is going to be, before any note is chosen.
|
|
1829
|
+
*
|
|
1830
|
+
* Where a {@link ReferenceProfile} records what an existing piece did, a plan
|
|
1831
|
+
* records what a new one will do — the same structural dimensions (form,
|
|
1832
|
+
* harmony, motif derivation, rhythm), stated as targets a generator can hit
|
|
1833
|
+
* exactly rather than as a reading to approximate. A plan is plain data,
|
|
1834
|
+
* JSON-serializable end to end, and it carries the seed and algorithm version
|
|
1835
|
+
* a generator needs to reproduce the piece it describes: the plan is the
|
|
1836
|
+
* recipe, not a cache of one run of it.
|
|
1837
|
+
*/
|
|
1838
|
+
|
|
1839
|
+
/**
|
|
1840
|
+
* Schema version {@link CompositionPlan} is written at.
|
|
1841
|
+
*
|
|
1842
|
+
* {@link assertCompositionPlan} rejects any other value outright rather than
|
|
1843
|
+
* guess at an older shape a caller's stored JSON might be in.
|
|
1844
|
+
*
|
|
1845
|
+
* @category Composition
|
|
1846
|
+
*/
|
|
1847
|
+
declare const COMPOSITION_PLAN_VERSION = 1;
|
|
1848
|
+
/**
|
|
1849
|
+
* What a new piece is going to be: its keys, meter and span, the sections and
|
|
1850
|
+
* phrases it is built from, the harmony and motif derivations a generator
|
|
1851
|
+
* fills those phrases with, and the rhythmic target it aims for.
|
|
1852
|
+
*
|
|
1853
|
+
* @category Composition
|
|
1854
|
+
*/
|
|
1855
|
+
type CompositionPlan = {
|
|
1856
|
+
/** Schema version this record is written at; see {@link COMPOSITION_PLAN_VERSION}. */
|
|
1857
|
+
planVersion: number;
|
|
1858
|
+
/** The project seed a generator following this plan draws from. */
|
|
1859
|
+
seed: number;
|
|
1860
|
+
/** The algorithm version a generator following this plan runs under. */
|
|
1861
|
+
algorithmVersion: number;
|
|
1862
|
+
/** Keys the piece passes through; index 0 is the home key harmony is read against by default. */
|
|
1863
|
+
keys: ResolvedKey[];
|
|
1864
|
+
/** The piece's meter across the planned span. */
|
|
1865
|
+
meters: MeterMap;
|
|
1866
|
+
/** The planned span. */
|
|
1867
|
+
span: {
|
|
1868
|
+
startBeat: number;
|
|
1869
|
+
endBeat: number;
|
|
1870
|
+
bars: number;
|
|
1871
|
+
};
|
|
1872
|
+
/** Sections, in time order. */
|
|
1873
|
+
sections: PlannedSection[];
|
|
1874
|
+
/** Phrases, in time order. */
|
|
1875
|
+
phrases: PlannedPhrase[];
|
|
1876
|
+
/** The harmonic progression, as a partition of the span. */
|
|
1877
|
+
harmony: PlannedChord[];
|
|
1878
|
+
/** Motifs and how they derive from one another. */
|
|
1879
|
+
motifs: PlannedMotif[];
|
|
1880
|
+
/** The rhythmic target a generator's onset placement aims for. */
|
|
1881
|
+
rhythm: PlannedRhythm;
|
|
1882
|
+
};
|
|
1883
|
+
/**
|
|
1884
|
+
* One planned section: a labelled span of the piece.
|
|
1885
|
+
*
|
|
1886
|
+
* @category Composition
|
|
1887
|
+
*/
|
|
1888
|
+
type PlannedSection = {
|
|
1889
|
+
/** The section's label. */
|
|
1890
|
+
label: string;
|
|
1891
|
+
/** First beat of the section. */
|
|
1892
|
+
startBeat: number;
|
|
1893
|
+
/** End of the section, exclusive. */
|
|
1894
|
+
endBeat: number;
|
|
1895
|
+
};
|
|
1896
|
+
/**
|
|
1897
|
+
* One planned phrase: its span, the section it opens in, the cadence and
|
|
1898
|
+
* melodic shape it targets, and the motifs it carries.
|
|
1899
|
+
*
|
|
1900
|
+
* @category Composition
|
|
1901
|
+
*/
|
|
1902
|
+
type PlannedPhrase = {
|
|
1903
|
+
/** First beat of the phrase. */
|
|
1904
|
+
startBeat: number;
|
|
1905
|
+
/** End of the phrase, exclusive. */
|
|
1906
|
+
endBeat: number;
|
|
1907
|
+
/** Index into `plan.sections` of the section this phrase's start beat falls in. */
|
|
1908
|
+
section: number | null;
|
|
1909
|
+
/** The cadence the phrase is to end on, or null for none. */
|
|
1910
|
+
cadence: CadenceType | null;
|
|
1911
|
+
/** The phrase's targeted melodic shape. */
|
|
1912
|
+
shape: MelodicContourShape;
|
|
1913
|
+
/** Onset of the phrase's targeted peak, as a fraction of the phrase's length, in [0, 1]. */
|
|
1914
|
+
peakPosition: number;
|
|
1915
|
+
/** The phrase's targeted pitch range and mean, as absolute MIDI pitches. */
|
|
1916
|
+
register: {
|
|
1917
|
+
low: number;
|
|
1918
|
+
high: number;
|
|
1919
|
+
mean: number;
|
|
1920
|
+
};
|
|
1921
|
+
/** Targeted onsets per bar within the phrase; see {@link RhythmAnalysis.onsetDensity}. */
|
|
1922
|
+
onsetDensity: number;
|
|
1923
|
+
/** Indices into `plan.motifs` of every motif statement placed in this phrase. */
|
|
1924
|
+
motifs: number[];
|
|
1925
|
+
};
|
|
1926
|
+
/**
|
|
1927
|
+
* One planned chord, placed against one of the plan's keys.
|
|
1928
|
+
*
|
|
1929
|
+
* @category Composition
|
|
1930
|
+
*/
|
|
1931
|
+
type PlannedChord = {
|
|
1932
|
+
/** First beat of the chord. */
|
|
1933
|
+
startBeat: number;
|
|
1934
|
+
/** End of the chord, exclusive. */
|
|
1935
|
+
endBeat: number;
|
|
1936
|
+
/** Index into `plan.keys` of the key this chord is named against. */
|
|
1937
|
+
key: number;
|
|
1938
|
+
/** The chord, as a Roman numeral in that key. */
|
|
1939
|
+
roman: string;
|
|
1940
|
+
};
|
|
1941
|
+
/**
|
|
1942
|
+
* One planned motif statement: a root the generator writes new notes for, or a
|
|
1943
|
+
* derivation the generator obtains from an earlier statement by a named
|
|
1944
|
+
* transformation.
|
|
1945
|
+
*
|
|
1946
|
+
* @category Composition
|
|
1947
|
+
*/
|
|
1948
|
+
type PlannedMotif = {
|
|
1949
|
+
/** Index into `plan.phrases` of the phrase this statement is placed in. */
|
|
1950
|
+
phrase: number;
|
|
1951
|
+
/** First beat of the statement. */
|
|
1952
|
+
startBeat: number;
|
|
1953
|
+
/** End of the statement, exclusive. */
|
|
1954
|
+
endBeat: number;
|
|
1955
|
+
/** How many notes the statement carries; a root's generated length, a derivation's inherited from its source. */
|
|
1956
|
+
notes: number;
|
|
1957
|
+
/**
|
|
1958
|
+
* A root's onset-to-onset gaps in beats, `notes - 1` of them, summing to
|
|
1959
|
+
* less than the statement's length: its reference motif's ratios times
|
|
1960
|
+
* {@link ReferenceMotif.unitBeats}. The first note sounds at `startBeat`
|
|
1961
|
+
* and the last lasts to `endBeat`. Null for a root whose onsets a generator
|
|
1962
|
+
* draws from `plan.rhythm`; always null for a derivation, whose rhythm is
|
|
1963
|
+
* its source's under the named transformation.
|
|
1964
|
+
*/
|
|
1965
|
+
rhythm: number[] | null;
|
|
1966
|
+
/** Index into `plan.motifs` of the statement this one derives from; null for a root. Always less than this statement's own index. */
|
|
1967
|
+
from: number | null;
|
|
1968
|
+
/**
|
|
1969
|
+
* The named transformation from `from`, or null for a root, or for a
|
|
1970
|
+
* derivation with no named transformation (a variation). Its `semitones`
|
|
1971
|
+
* and `degrees` are the preferred pitch level: a generator may place the
|
|
1972
|
+
* derivation at another level to keep it inside the register and the harmony.
|
|
1973
|
+
*/
|
|
1974
|
+
relation: MotifRelationSummary | null;
|
|
1975
|
+
};
|
|
1976
|
+
/**
|
|
1977
|
+
* The rhythmic target a generator's onset placement aims for.
|
|
1978
|
+
*
|
|
1979
|
+
* @category Composition
|
|
1980
|
+
*/
|
|
1981
|
+
type PlannedRhythm = {
|
|
1982
|
+
/** Targeted distribution of onsets across metric levels; see {@link RhythmAnalysis.onsetLevels}. */
|
|
1983
|
+
onsetLevels: number[];
|
|
1984
|
+
/** Targeted distribution of inter-onset intervals; see {@link RhythmAnalysis.interOnsetShares}. */
|
|
1985
|
+
interOnsetShares: number[];
|
|
1986
|
+
/** Targeted syncopation, in [0, 1]; see {@link RhythmAnalysis.syncopation}. */
|
|
1987
|
+
syncopation: number;
|
|
1988
|
+
};
|
|
1989
|
+
|
|
1990
|
+
/**
|
|
1991
|
+
* Melody generation from a {@link CompositionPlan}.
|
|
1992
|
+
*
|
|
1993
|
+
* The plan is a hard constraint where the generator is free: every root, every
|
|
1994
|
+
* span no motif covers and every closing note keeps its phrase's register and
|
|
1995
|
+
* offers only the pitches its position class admits — a chord tone on a strong
|
|
1996
|
+
* pulse, a scale tone on a weak one or on a strong one where no chord is
|
|
1997
|
+
* planned, anything in the register off the pulses.
|
|
1998
|
+
* A derived statement is its source replayed through the named relation at the
|
|
1999
|
+
* pitch level that suits its phrase best; there the transformation outranks
|
|
2000
|
+
* the harmony, and the register outranks both. A root takes its plan's onset
|
|
2001
|
+
* gaps, or onsets drawn toward the plan's onset levels and gap shares, and pitches from a
|
|
2002
|
+
* chain search toward the phrase's target curve; each phrase closes on a note
|
|
2003
|
+
* held from its final bar to its end, bent onto its cadence.
|
|
2004
|
+
*
|
|
2005
|
+
* Every draw is addressed by phrase index and absolute beat, and a phrase
|
|
2006
|
+
* reads only its own plan entries and the statements its derivations lead
|
|
2007
|
+
* back to, so changing one phrase's plan leaves every phrase that does not
|
|
2008
|
+
* derive from it sounding as it did.
|
|
2009
|
+
*/
|
|
2010
|
+
|
|
2011
|
+
/**
|
|
2012
|
+
* Options controlling {@link generateMelody}.
|
|
2013
|
+
*
|
|
2014
|
+
* @category Composition
|
|
2015
|
+
*/
|
|
2016
|
+
type MelodyOptions = {
|
|
2017
|
+
/**
|
|
2018
|
+
* The generation context. Its `seed` and `algorithmVersion` take precedence
|
|
2019
|
+
* over the plan's; whatever it leaves out is read from the plan. A supplied
|
|
2020
|
+
* `rng` is rejected: every onset and tie-break is drawn at an address of
|
|
2021
|
+
* phrase and beat under a seed, which a caller-held source cannot provide.
|
|
2022
|
+
*
|
|
2023
|
+
* @defaultValue the plan's seed and algorithm version
|
|
2024
|
+
*/
|
|
2025
|
+
ctx?: GenerationContextInput;
|
|
2026
|
+
/** Upper bound on the onset grid and on the pitch search. */
|
|
2027
|
+
budget?: number;
|
|
2028
|
+
};
|
|
2029
|
+
/**
|
|
2030
|
+
* Write a melody that follows a composition plan.
|
|
2031
|
+
*
|
|
2032
|
+
* Each phrase is written inside its planned register, and every note the
|
|
2033
|
+
* generator chooses freely takes a pitch its position class admits: a chord
|
|
2034
|
+
* tone on a strong pulse, a scale tone on a weak one, any pitch off the pulses.
|
|
2035
|
+
* A root motif takes the onset gaps its plan carries from its start, its last
|
|
2036
|
+
* note lasting to its end, or onsets drawn one after another on the sixteenth
|
|
2037
|
+
* grid toward the plan's onset levels and gap shares; its pitches come from a chain
|
|
2038
|
+
* search that moves by step, recovers from leaps and follows the phrase's
|
|
2039
|
+
* target shape. A derived motif replays its planned relation on the statement
|
|
2040
|
+
* it derives from, starting on its planned beat, at the pitch level inside the
|
|
2041
|
+
* register that best fits the harmony, the target curve and the planned level;
|
|
2042
|
+
* a harmony misfit it keeps is left, and only notes no level brings inside the
|
|
2043
|
+
* register are replaced. A variation keeps its source's rhythm and outer
|
|
2044
|
+
* pitches. The spans no motif covers get drawn onsets at the phrase's density
|
|
2045
|
+
* and searched pitches. In each phrase's final bar, the note sounding at the
|
|
2046
|
+
* downbeat (or the first onset after it) is held to the phrase's end, later
|
|
2047
|
+
* onsets are dropped, and that note is bent onto the tones the phrase's
|
|
2048
|
+
* cadence asks for; a note sounding across the downbeat is cut there, and the
|
|
2049
|
+
* downbeat becomes the held onset, re-chosen from the pitches the downbeat
|
|
2050
|
+
* admits unless a cadence or a derived statement decides it. Onsets fall on the sixteenth grid only, so
|
|
2051
|
+
* triplets never appear.
|
|
2052
|
+
*
|
|
2053
|
+
* Harmony is read from the plan alone, through {@link planTimeline}.
|
|
2054
|
+
*
|
|
2055
|
+
* @param plan The plan to follow; validated first.
|
|
2056
|
+
* @param opts Context and budget.
|
|
2057
|
+
* @returns The melody, in time order.
|
|
2058
|
+
* @throws {InvalidInputError} If the plan, the options or the context are
|
|
2059
|
+
* malformed, or the context supplies an `rng`.
|
|
2060
|
+
* @throws {NoSolutionError} If a phrase's register admits no line, no pitch a
|
|
2061
|
+
* position asks for, no pitch that ends its cadence, or a span more onsets
|
|
2062
|
+
* than its grid holds; `at` is the phrase's start beat.
|
|
2063
|
+
* @throws {BudgetExceededError} If the onset grid or the pitch search would
|
|
2064
|
+
* exceed the budget.
|
|
2065
|
+
* @example
|
|
2066
|
+
* ```ts
|
|
2067
|
+
* import { generateMelody, resolveKey } from '@libraz/libcantus';
|
|
2068
|
+
* import type { CompositionPlan } from '@libraz/libcantus';
|
|
2069
|
+
* const plan: CompositionPlan = {
|
|
2070
|
+
* planVersion: 1, seed: 7, algorithmVersion: 1,
|
|
2071
|
+
* keys: [resolveKey('C major')], meters: [{ startBeat: 0, ts: { numerator: 4, denominator: 4 } }],
|
|
2072
|
+
* span: { startBeat: 0, endBeat: 8, bars: 2 },
|
|
2073
|
+
* sections: [{ label: 'A', startBeat: 0, endBeat: 8 }],
|
|
2074
|
+
* phrases: [{
|
|
2075
|
+
* startBeat: 0, endBeat: 8, section: 0, cadence: 'authentic', shape: 'arch', peakPosition: 0.6,
|
|
2076
|
+
* register: { low: 60, high: 72, mean: 66 }, onsetDensity: 4, motifs: [0],
|
|
2077
|
+
* }],
|
|
2078
|
+
* harmony: [{ startBeat: 0, endBeat: 4, key: 0, roman: 'V' }, { startBeat: 4, endBeat: 8, key: 0, roman: 'I' }],
|
|
2079
|
+
* motifs: [{ phrase: 0, startBeat: 0, endBeat: 4, notes: 4, rhythm: [1, 1, 1], from: null, relation: null }],
|
|
2080
|
+
* rhythm: { onsetLevels: [0, 0, 0, 0, 0, 1], interOnsetShares: new Array(17).fill(0).fill(1, 8, 9), syncopation: 0 },
|
|
2081
|
+
* };
|
|
2082
|
+
* generateMelody(plan); // the same notes on every call
|
|
2083
|
+
* ```
|
|
2084
|
+
* @category Composition
|
|
2085
|
+
*/
|
|
2086
|
+
declare function generateMelody(plan: CompositionPlan, opts?: MelodyOptions): NoteEvent[];
|
|
2087
|
+
|
|
1808
2088
|
/**
|
|
1809
2089
|
* A transformation applicable to a motif cell.
|
|
1810
2090
|
*
|
|
@@ -2058,7 +2338,8 @@ type OrnamentOptions = {
|
|
|
2058
2338
|
amount?: number;
|
|
2059
2339
|
/**
|
|
2060
2340
|
* Time signature, in any form that names one, used to tell strong positions
|
|
2061
|
-
* from weak ones.
|
|
2341
|
+
* from weak ones. A meter map is read bar by bar, so a note after a change
|
|
2342
|
+
* is weighed in the signature in force where it sounds.
|
|
2062
2343
|
*
|
|
2063
2344
|
* @defaultValue 4/4
|
|
2064
2345
|
*/
|
|
@@ -2109,6 +2390,227 @@ type OrnamentOptions = {
|
|
|
2109
2390
|
*/
|
|
2110
2391
|
declare function ornament(notes: readonly NoteEvent[], opts?: OrnamentOptions): NoteEvent[];
|
|
2111
2392
|
|
|
2393
|
+
/**
|
|
2394
|
+
* Deriving a {@link CompositionPlan} from a {@link ReferenceProfile}.
|
|
2395
|
+
*
|
|
2396
|
+
* Each structural dimension of the reference is either carried into the plan
|
|
2397
|
+
* or replaced, weighted per dimension by {@link PreserveWeights}. A discrete
|
|
2398
|
+
* item (a section label, a phrase length, a structural chord, a motif
|
|
2399
|
+
* derivation) is kept or replaced whole by a positional draw addressed by that
|
|
2400
|
+
* item's index, so changing one weight or one item never redraws another; a
|
|
2401
|
+
* replacement follows a fixed rule. A continuous item (harmonic rhythm,
|
|
2402
|
+
* register and contour, onset placement) is interpolated between the
|
|
2403
|
+
* reference's value and a neutral one.
|
|
2404
|
+
*
|
|
2405
|
+
* The reference's melodic surface — its motif intervals and phrase outlines —
|
|
2406
|
+
* never reaches the plan: a plan says how motifs derive from one another and
|
|
2407
|
+
* carries a root's onset gaps, not the pitches it sounds.
|
|
2408
|
+
*/
|
|
2409
|
+
|
|
2410
|
+
/**
|
|
2411
|
+
* How much of each structural dimension of a reference a derived plan keeps,
|
|
2412
|
+
* each in [0, 1]; an omitted weight is 1.
|
|
2413
|
+
*
|
|
2414
|
+
* @category Composition
|
|
2415
|
+
*/
|
|
2416
|
+
type PreserveWeights = {
|
|
2417
|
+
/** Section labels; a replaced section takes its neighbour's label. */
|
|
2418
|
+
form?: number;
|
|
2419
|
+
/** Phrase lengths; a replaced phrase is rounded to a power-of-two bar count. */
|
|
2420
|
+
phraseLengths?: number;
|
|
2421
|
+
/** Structural chords; a replaced chord is another numeral of the same function. */
|
|
2422
|
+
harmonicFunction?: number;
|
|
2423
|
+
/** Where the chords change, interpolated toward one change per bar line. */
|
|
2424
|
+
harmonicRhythm?: number;
|
|
2425
|
+
/** Motif derivations; a replaced derivation becomes a variation of the same source. */
|
|
2426
|
+
motifRelations?: number;
|
|
2427
|
+
/** Phrase contour, peak and register, interpolated toward a neutral arch. */
|
|
2428
|
+
registerShape?: number;
|
|
2429
|
+
/**
|
|
2430
|
+
* Each root's onset gaps, kept per root by a positional draw, and the
|
|
2431
|
+
* onset placement, interpolated toward a level-proportional distribution
|
|
2432
|
+
* without syncopation.
|
|
2433
|
+
*/
|
|
2434
|
+
rhythm?: number;
|
|
2435
|
+
};
|
|
2436
|
+
/**
|
|
2437
|
+
* Options for {@link deriveCompositionPlan}.
|
|
2438
|
+
*
|
|
2439
|
+
* @category Composition
|
|
2440
|
+
*/
|
|
2441
|
+
type CompositionPlanOptions = {
|
|
2442
|
+
/**
|
|
2443
|
+
* The home key of the plan. Every reference key moves by the interval from
|
|
2444
|
+
* the reference's home tonic to this one, keeping its own variant. Defaults
|
|
2445
|
+
* to the reference's home key; a key of another variant is rejected.
|
|
2446
|
+
*/
|
|
2447
|
+
key?: KeyLike;
|
|
2448
|
+
/**
|
|
2449
|
+
* The melody range the plan's phrase registers are mapped onto. Defaults to
|
|
2450
|
+
* the reference's melody range, moved by the nearest shift to the new key.
|
|
2451
|
+
*/
|
|
2452
|
+
register?: {
|
|
2453
|
+
low: number;
|
|
2454
|
+
high: number;
|
|
2455
|
+
};
|
|
2456
|
+
/** How much of each dimension of the reference to keep; see {@link PreserveWeights}. */
|
|
2457
|
+
preserve?: PreserveWeights;
|
|
2458
|
+
/**
|
|
2459
|
+
* The seed and algorithm version the plan records. A caller-supplied `rng`
|
|
2460
|
+
* is rejected: a plan has to carry its source as a seed to be reproducible.
|
|
2461
|
+
*/
|
|
2462
|
+
ctx?: GenerationContextInput;
|
|
2463
|
+
/** Upper bound on the motif selection. */
|
|
2464
|
+
budget?: number;
|
|
2465
|
+
};
|
|
2466
|
+
/**
|
|
2467
|
+
* Derive a composition plan from a reference profile.
|
|
2468
|
+
*
|
|
2469
|
+
* The plan keeps the reference's meter and span. Its keys are the reference's,
|
|
2470
|
+
* moved to `opts.key` with each key's variant kept, and its phrase registers
|
|
2471
|
+
* are the reference's mapped onto `opts.register`. Each dimension named in
|
|
2472
|
+
* `opts.preserve` is kept, replaced or interpolated by its weight; a draw for
|
|
2473
|
+
* a discrete item is addressed by the dimension and the item's index, so the
|
|
2474
|
+
* same reference, options and seed always give the same plan. The resolved
|
|
2475
|
+
* seed and algorithm version are recorded in the plan.
|
|
2476
|
+
*
|
|
2477
|
+
* @param reference The reference profile to derive from.
|
|
2478
|
+
* @param opts The key, register, preserve weights, generation context and budget.
|
|
2479
|
+
* @returns A plan that passes {@link assertCompositionPlan}.
|
|
2480
|
+
* @throws {InvalidInputError} If the reference is not a valid profile or has
|
|
2481
|
+
* no melody onsets, an option is out of range, `opts.key` is of another
|
|
2482
|
+
* variant than the reference's home key, `opts.ctx` carries an `rng`, or the
|
|
2483
|
+
* default register moved to the new key leaves the MIDI range.
|
|
2484
|
+
* @throws {BudgetExceededError} If the motif selection would exceed the budget.
|
|
2485
|
+
* @category Composition
|
|
2486
|
+
*/
|
|
2487
|
+
declare function deriveCompositionPlan(reference: ReferenceProfile, opts?: CompositionPlanOptions): CompositionPlan;
|
|
2488
|
+
|
|
2489
|
+
/**
|
|
2490
|
+
* Checking a candidate melody against the plan it was written for.
|
|
2491
|
+
*
|
|
2492
|
+
* The candidate is read against the plan itself, never re-analyzed: its
|
|
2493
|
+
* phrases are the plan's phrases, its harmony is the plan's through
|
|
2494
|
+
* `planTimeline`, and its derivations are replayed from the candidate's own
|
|
2495
|
+
* source statements. What comes back is never one score: a list of concrete
|
|
2496
|
+
* violations (which are errors and which are only warnings), and a fit reading
|
|
2497
|
+
* per dimension, each measured the way {@link compareReferences} measures two
|
|
2498
|
+
* profiles against each other. Whether the piece is any good is left to the ear.
|
|
2499
|
+
*/
|
|
2500
|
+
|
|
2501
|
+
/**
|
|
2502
|
+
* One way a candidate melody departs from its plan.
|
|
2503
|
+
*
|
|
2504
|
+
* @category Composition
|
|
2505
|
+
*/
|
|
2506
|
+
type CompositionViolation = {
|
|
2507
|
+
/** What kind of departure this is. */
|
|
2508
|
+
kind: 'span' | 'phraseBoundary' | 'cadence' | 'harmony' | 'motifDerivation' | 'motifDisplaced' | 'register' | 'peakPosition';
|
|
2509
|
+
/** Whether this rules the candidate out, or only flags it. */
|
|
2510
|
+
severity: 'error' | 'warning';
|
|
2511
|
+
/** Where in the candidate this was found. */
|
|
2512
|
+
atBeat: number;
|
|
2513
|
+
/** What the plan called for. */
|
|
2514
|
+
expected: string;
|
|
2515
|
+
/** What the candidate did instead. */
|
|
2516
|
+
actual: string;
|
|
2517
|
+
/** Why this counts as a departure. */
|
|
2518
|
+
rationale: string;
|
|
2519
|
+
};
|
|
2520
|
+
/**
|
|
2521
|
+
* How a candidate melody measures up against its plan: violations that judge
|
|
2522
|
+
* it, and a fit reading per structural dimension.
|
|
2523
|
+
*
|
|
2524
|
+
* There is no aggregate: the fields never fold into one score, the same way
|
|
2525
|
+
* {@link ReferenceComparison} does not.
|
|
2526
|
+
*
|
|
2527
|
+
* @category Composition
|
|
2528
|
+
*/
|
|
2529
|
+
type CompositionEvaluation = {
|
|
2530
|
+
/** Concrete departures from the plan, error and warning alike. */
|
|
2531
|
+
violations: CompositionViolation[];
|
|
2532
|
+
/** Likeness of the candidate to the plan, one field per dimension, each phrase read over its planned span. */
|
|
2533
|
+
fit: {
|
|
2534
|
+
/** Likeness of the phrases' melodic outlines to their planned shapes. */
|
|
2535
|
+
contour: number | null;
|
|
2536
|
+
/** Likeness of the phrases' registers to the planned ones. */
|
|
2537
|
+
register: number | null;
|
|
2538
|
+
/** Likeness of where the melody's onsets fall. */
|
|
2539
|
+
onset: number | null;
|
|
2540
|
+
/** Likeness of the melody's inter-onset-interval distribution. */
|
|
2541
|
+
duration: number | null;
|
|
2542
|
+
/** Likeness of the melody's syncopation. */
|
|
2543
|
+
syncopation: number | null;
|
|
2544
|
+
/** Likeness of the melody's onsets per bar to the phrases' planned densities. */
|
|
2545
|
+
density: number | null;
|
|
2546
|
+
};
|
|
2547
|
+
};
|
|
2548
|
+
/** Options for {@link evaluateComposition}. */
|
|
2549
|
+
type EvaluateCompositionOptions = {
|
|
2550
|
+
/**
|
|
2551
|
+
* Upper bound on the work each analysis may do.
|
|
2552
|
+
*
|
|
2553
|
+
* @defaultValue {@link DEFAULT_GENERATION_BUDGET}
|
|
2554
|
+
*/
|
|
2555
|
+
budget?: number;
|
|
2556
|
+
};
|
|
2557
|
+
/**
|
|
2558
|
+
* Check a candidate melody against the plan it was written for.
|
|
2559
|
+
*
|
|
2560
|
+
* The candidate is read against the plan itself — its phrases, its harmony
|
|
2561
|
+
* through {@link planTimeline}, its derivations — rather than re-analyzed into
|
|
2562
|
+
* a profile, so every violation and fit reading judges the melody against what
|
|
2563
|
+
* the plan actually calls for.
|
|
2564
|
+
*
|
|
2565
|
+
* Violations name concrete departures at a beat. `span`, `phraseBoundary`,
|
|
2566
|
+
* `cadence`, `register` and `motifDerivation` are errors. `harmony` is an
|
|
2567
|
+
* error, or a warning for a note inside a derived statement, where the
|
|
2568
|
+
* transformation takes precedence. A derived statement passes at any pitch
|
|
2569
|
+
* level its relation admits, with its durations free and its closing and
|
|
2570
|
+
* out-of-register notes excused; `motifDisplaced` warns when that level is not
|
|
2571
|
+
* the planned one or a note was excused. `peakPosition` is a warning. The fit
|
|
2572
|
+
* fields, one per dimension, read each planned phrase of the candidate the way
|
|
2573
|
+
* a reference profile reads its phrases and measure it as
|
|
2574
|
+
* {@link compareReferences} would — never folded into one score.
|
|
2575
|
+
*
|
|
2576
|
+
* @param melody The candidate melody.
|
|
2577
|
+
* @param plan The plan it was written for.
|
|
2578
|
+
* @param opts The work budget.
|
|
2579
|
+
* @returns The violations found and the fit reading.
|
|
2580
|
+
* @throws {InvalidInputError} If the plan or the melody cannot be read.
|
|
2581
|
+
* @throws {BudgetExceededError} If an analysis would exceed the budget.
|
|
2582
|
+
* @example
|
|
2583
|
+
* ```ts
|
|
2584
|
+
* import { evaluateComposition, planTimeline, resolveKey } from '@libraz/libcantus';
|
|
2585
|
+
* import type { CompositionPlan } from '@libraz/libcantus';
|
|
2586
|
+
* const plan: CompositionPlan = {
|
|
2587
|
+
* planVersion: 1, seed: 0, algorithmVersion: 1,
|
|
2588
|
+
* keys: [resolveKey('C major')],
|
|
2589
|
+
* meters: [{ startBeat: 0, ts: { numerator: 4, denominator: 4 } }],
|
|
2590
|
+
* span: { startBeat: 0, endBeat: 4, bars: 1 },
|
|
2591
|
+
* sections: [{ label: 'A', startBeat: 0, endBeat: 4 }],
|
|
2592
|
+
* phrases: [
|
|
2593
|
+
* {
|
|
2594
|
+
* startBeat: 0, endBeat: 4, section: 0, cadence: null, shape: 'ascending',
|
|
2595
|
+
* peakPosition: 0.5, register: { low: 60, high: 67, mean: 64 }, onsetDensity: 4, motifs: [],
|
|
2596
|
+
* },
|
|
2597
|
+
* ],
|
|
2598
|
+
* harmony: [{ startBeat: 0, endBeat: 4, key: 0, roman: 'I' }],
|
|
2599
|
+
* motifs: [],
|
|
2600
|
+
* rhythm: { onsetLevels: [0, 0, 0, 1, 0, 0], interOnsetShares: new Array(17).fill(0).fill(1, 8, 9), syncopation: 0 },
|
|
2601
|
+
* };
|
|
2602
|
+
* const melody = [
|
|
2603
|
+
* { pitch: 60, startBeat: 0, durationBeat: 1 },
|
|
2604
|
+
* { pitch: 64, startBeat: 1, durationBeat: 1 },
|
|
2605
|
+
* { pitch: 67, startBeat: 2, durationBeat: 1 },
|
|
2606
|
+
* { pitch: 60, startBeat: 3, durationBeat: 1 },
|
|
2607
|
+
* ];
|
|
2608
|
+
* evaluateComposition(melody, plan).violations; // []
|
|
2609
|
+
* ```
|
|
2610
|
+
* @category Composition
|
|
2611
|
+
*/
|
|
2612
|
+
declare function evaluateComposition(melody: readonly NoteEvent[], plan: CompositionPlan, opts?: EvaluateCompositionOptions): CompositionEvaluation;
|
|
2613
|
+
|
|
2112
2614
|
/**
|
|
2113
2615
|
* Reharmonization: chord substitution, modal-interchange palettes, and negative
|
|
2114
2616
|
* harmony. These transforms take an existing chord (or a key) and propose
|
|
@@ -2182,8 +2684,9 @@ type SubstituteOptions = {
|
|
|
2182
2684
|
* tritone substitute of G7 formats as `Db7` and its chromatic mediants as `Bb`
|
|
2183
2685
|
* and `Eb`. Where the substitution's function and the bare pitch class disagree,
|
|
2184
2686
|
* the function decides — a tritone substitute is a bII7 and so is written on the
|
|
2185
|
-
* flattened supertonic of the chord it resolves to,
|
|
2186
|
-
*
|
|
2687
|
+
* flattened supertonic of the chord it resolves to, a borrowed chord takes the
|
|
2688
|
+
* spelling of the mode it is borrowed from, and a chromatic mediant is written
|
|
2689
|
+
* on the letter a third from the source root (E's mediants are G#, not Ab).
|
|
2187
2690
|
*
|
|
2188
2691
|
* @param chord The chord to reharmonize, as a chord symbol or as chord data.
|
|
2189
2692
|
* @param key The prevailing key, as a key name or as a key/scale.
|
|
@@ -2300,7 +2803,8 @@ type RhythmEvent = {
|
|
|
2300
2803
|
* @param pitch The MIDI pitch to give every note.
|
|
2301
2804
|
* @param velocity Velocity for every note; defaults to a mezzo-forte 96.
|
|
2302
2805
|
* @returns The note events, in the order given.
|
|
2303
|
-
* @throws If the pitch or the velocity is not a whole MIDI value in [0, 127]
|
|
2806
|
+
* @throws If the pitch or the velocity is not a whole MIDI value in [0, 127], or an event is not
|
|
2807
|
+
* a record with a finite position and duration.
|
|
2304
2808
|
* @example
|
|
2305
2809
|
* ```ts
|
|
2306
2810
|
* import { generateRhythm, humanize, rhythmToNoteEvents } from '@libraz/libcantus';
|
|
@@ -2386,4 +2890,5 @@ declare function generateRhythm(ts: MeterLike, opts?: RhythmOptions): RhythmEven
|
|
|
2386
2890
|
*/
|
|
2387
2891
|
declare function rhythmDensity(events: RhythmEvent[], ts: MeterLike): number;
|
|
2388
2892
|
|
|
2389
|
-
export {
|
|
2893
|
+
export { BAR_STEPS as B, COMPOSITION_PLAN_VERSION as C, DRUM_NOTES as D, GENRES as G, ORNAMENT_STYLES as T, PROVENANCE_BASES as W, BASS_STYLES as a, generateRhythm as aA, gridMetricWeight as aB, halfTime as aC, humanize as aD, mergeVocabulary as aE, modalInterchangePalette as aF, motifToNoteEvents as aG, negativeHarmonyMirror as aH, onsetWeightCurve as aI, ornament as aJ, ornamentBy as aK, pickProgressionPreset as aL, pickVocabulary as aM, progressions as aN, progressionsByStyle as aO, resolveContext as aP, rhythmDensity as aQ, rhythmToNoteEvents as aR, selectVocabulary as aS, substituteChord as aT, syncopate as aU, thin as aV, transformMotif as aW, vocabularyOfKind as aX, withinCeiling as aY, STEP_BEATS as ab, applyGrooveTemplate as aj, assertVocabulary as ak, deform as al, deriveCompositionPlan as am, developMotif as an, double as ao, doubleTime as ap, drumVoiceOf as aq, evaluateComposition as ar, extractGrooveTemplate as as, fitsQuery as at, generateBassLine as au, generateCounterMelody as av, generateDrums as aw, generateMelody as ax, generateMotif as ay, generateProgression as az, BEAT_STEPS as b, BORROWED_DEGREES as c };
|
|
2894
|
+
export type { PlannedSection as $, GrooveSlot as A, EuclideanKick as E, GrooveStyle as F, GrooveTemplate as H, HarmonizeOptions as I, HarmonizePlacement as J, HarmonizeResult as K, HumanizeOptions as L, MelodyNote as M, MelodyOptions as N, MotifCell as O, MotifContour as P, MotifNote as Q, MotifOptions as R, MotifTransform as S, OrnamentOptions as U, OrnamentStyle as V, PlannedChord as X, PlannedMotif as Y, PlannedPhrase as Z, PlannedRhythm as _, PreserveWeights as a0, ProgFunction as a1, ProgStyle as a2, ProgressionDegree as a3, ProgressionOptions as a4, ProgressionPreset as a5, Provenance as a6, ProvenanceBasis as a7, ResolvedContext as a8, RhythmEvent as a9, RhythmOptions as aa, Section as ac, SubstituteOptions as ad, Substitution as ae, SubstitutionType as af, SyncopateOptions as ag, Vocabulary as ah, VocabularyQuery as ai, BassLineOptions as d, BassSegment as e, BassStyle as f, BorrowedChord as g, Complexity as h, CompositionEvaluation as i, CompositionPlan as j, CompositionPlanOptions as k, CompositionViolation as l, CounterMelodyOptions as m, DeformOptions as n, Draw as o, DrumHit as p, DrumRole as q, DrumStyle as r, DrumVoice as s, DrumsOptions as t, EvaluateCompositionOptions as u, GenerationContext as v, GenerationContextInput as w, Genre as x, GridEvent as y, GrooveFeel as z };
|