@libraz/libcantus 1.1.0 → 1.3.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 +4 -0
- package/README_ja.md +4 -0
- package/dist/analyze/index.cjs +31 -7
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +155 -9
- package/dist/analyze/index.d.ts +155 -9
- package/dist/analyze/index.js +37 -13
- package/dist/{chunk-TT6PKMPR.cjs → chunk-35NBV2FT.cjs} +16 -16
- package/dist/{chunk-TT6PKMPR.cjs.map → chunk-35NBV2FT.cjs.map} +1 -1
- package/dist/{chunk-YPB3A3EY.cjs → chunk-3R3QVKY5.cjs} +314 -285
- package/dist/chunk-3R3QVKY5.cjs.map +1 -0
- package/dist/{chunk-GDKE6RQW.cjs → chunk-4R2LWV7E.cjs} +691 -413
- package/dist/chunk-4R2LWV7E.cjs.map +1 -0
- package/dist/{chunk-RVS4G4MR.cjs → chunk-76ZBTRG2.cjs} +198 -198
- package/dist/{chunk-RVS4G4MR.cjs.map → chunk-76ZBTRG2.cjs.map} +1 -1
- package/dist/{chunk-X6RJAHII.js → chunk-7KG3RTYS.js} +2 -2
- package/dist/{chunk-PQL7E5F6.js → chunk-AGOVW7U6.js} +1 -1
- package/dist/{chunk-PQL7E5F6.js.map → chunk-AGOVW7U6.js.map} +1 -1
- package/dist/{chunk-5KW7DNCJ.cjs → chunk-B2PW6EHN.cjs} +2423 -453
- package/dist/chunk-B2PW6EHN.cjs.map +1 -0
- package/dist/{chunk-J772DL3B.cjs → chunk-CGBADIO5.cjs} +53 -53
- package/dist/{chunk-J772DL3B.cjs.map → chunk-CGBADIO5.cjs.map} +1 -1
- package/dist/{chunk-R5VUXQMP.js → chunk-CPMB7P75.js} +1978 -8
- package/dist/chunk-CPMB7P75.js.map +1 -0
- package/dist/{chunk-VLE5R7PF.js → chunk-GNVN4PPJ.js} +1874 -8
- package/dist/chunk-GNVN4PPJ.js.map +1 -0
- package/dist/{chunk-Q6R3QAZD.cjs → chunk-IFZDWIKM.cjs} +2199 -333
- package/dist/chunk-IFZDWIKM.cjs.map +1 -0
- package/dist/{chunk-DKICR7AN.js → chunk-IPEF6NWB.js} +296 -18
- package/dist/chunk-IPEF6NWB.js.map +1 -0
- package/dist/{chunk-AWEMD747.js → chunk-M5RYMAFI.js} +3 -3
- package/dist/{chunk-HSY2VQXZ.js → chunk-MLBPXA4Z.js} +330 -728
- package/dist/chunk-MLBPXA4Z.js.map +1 -0
- package/dist/{chunk-H66ARFU5.js → chunk-NB25P3EH.js} +3 -3
- package/dist/{chunk-5JJ6EHEZ.cjs → chunk-NM7UAMC3.cjs} +62 -62
- package/dist/{chunk-5JJ6EHEZ.cjs.map → chunk-NM7UAMC3.cjs.map} +1 -1
- package/dist/{chunk-R7B5N2JK.cjs → chunk-PM4XJE2Y.cjs} +47 -47
- package/dist/{chunk-R7B5N2JK.cjs.map → chunk-PM4XJE2Y.cjs.map} +1 -1
- package/dist/{chunk-7GOKQJTQ.js → chunk-PUKJP2Z5.js} +2 -2
- package/dist/{chunk-QCXYKSZS.cjs → chunk-PWC4CRWT.cjs} +19 -19
- package/dist/{chunk-QCXYKSZS.cjs.map → chunk-PWC4CRWT.cjs.map} +1 -1
- package/dist/{chunk-FPBZFNCD.js → chunk-RFIBF2RR.js} +47 -18
- package/dist/{chunk-FPBZFNCD.js.map → chunk-RFIBF2RR.js.map} +1 -1
- package/dist/{chunk-XKSO2V5I.cjs → chunk-S5BKZZGM.cjs} +1 -1
- package/dist/{chunk-XKSO2V5I.cjs.map → chunk-S5BKZZGM.cjs.map} +1 -1
- package/dist/{chunk-HOHFYGKW.js → chunk-UMWZ4ZET.js} +2 -2
- package/dist/{chunk-XVMJO3QF.cjs → chunk-YFA7X2F6.cjs} +489 -887
- package/dist/chunk-YFA7X2F6.cjs.map +1 -0
- package/dist/{chunk-57WB2EDF.js → chunk-ZBUROTJQ.js} +3 -3
- package/dist/{coerce-wwdELNYS.d.ts → coerce-DP0vYu-x.d.ts} +77 -1
- package/dist/{coerce-CJlgULrQ.d.cts → coerce-DRERzdve.d.cts} +77 -1
- package/dist/core/index.cjs +5 -5
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- 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 +87 -9
- package/dist/generate/index.d.ts +87 -9
- package/dist/generate/index.js +19 -7
- package/dist/{index-BaoKVVhE.d.cts → index-B9QLziDe.d.cts} +2 -2
- package/dist/{index-CnHQgqNh.d.ts → index-BHIUyjhZ.d.ts} +2 -2
- package/dist/{index-CBCP84rv.d.cts → index-BL5N2Oyz.d.cts} +1 -1
- package/dist/{index-D_hzxD8w.d.cts → index-BMweUlm5.d.cts} +3 -0
- package/dist/{index-Ci3xyows.d.ts → index-CL4b4gUQ.d.ts} +3 -0
- package/dist/{index-BzLNkmA7.d.cts → index-CY-3NVfy.d.cts} +486 -5
- package/dist/{index-CnIdP4EZ.d.ts → index-Dw2DP7vm.d.ts} +1 -1
- package/dist/{index-DpC-mDlV.d.ts → index-zaZdmnU4.d.ts} +486 -5
- package/dist/index.cjs +49 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +55 -19
- package/dist/{masks-O73Rhj5d.d.ts → masks-Cc7-MzzY.d.ts} +1 -1
- package/dist/{masks-C8TWLFIi.d.cts → masks-pADfTOiD.d.cts} +1 -1
- package/dist/model/index.cjs +12 -12
- package/dist/model/index.d.cts +213 -16
- package/dist/model/index.d.ts +213 -16
- package/dist/model/index.js +11 -11
- package/dist/{index-DTsKaPaC.d.cts → profile-CQMEqdH9.d.cts} +88 -601
- package/dist/{index-BUtIf2go.d.ts → profile-DLdlIpS9.d.ts} +88 -601
- package/dist/theory/index.cjs +5 -5
- package/dist/theory/index.d.cts +7 -7
- package/dist/theory/index.d.ts +7 -7
- package/dist/theory/index.js +4 -4
- package/dist/{index-BpWOhkkE.d.ts → types-D-XgxGvp.d.cts} +1170 -14
- package/dist/{index-B3WCj_Hm.d.cts → types-Dh7C064C.d.ts} +1170 -14
- package/package.json +6 -5
- package/dist/chunk-5KW7DNCJ.cjs.map +0 -1
- package/dist/chunk-DKICR7AN.js.map +0 -1
- package/dist/chunk-GDKE6RQW.cjs.map +0 -1
- package/dist/chunk-HSY2VQXZ.js.map +0 -1
- package/dist/chunk-Q6R3QAZD.cjs.map +0 -1
- package/dist/chunk-R5VUXQMP.js.map +0 -1
- package/dist/chunk-VLE5R7PF.js.map +0 -1
- package/dist/chunk-XVMJO3QF.cjs.map +0 -1
- package/dist/chunk-YPB3A3EY.cjs.map +0 -1
- /package/dist/{chunk-X6RJAHII.js.map → chunk-7KG3RTYS.js.map} +0 -0
- /package/dist/{chunk-AWEMD747.js.map → chunk-M5RYMAFI.js.map} +0 -0
- /package/dist/{chunk-H66ARFU5.js.map → chunk-NB25P3EH.js.map} +0 -0
- /package/dist/{chunk-7GOKQJTQ.js.map → chunk-PUKJP2Z5.js.map} +0 -0
- /package/dist/{chunk-HOHFYGKW.js.map → chunk-UMWZ4ZET.js.map} +0 -0
- /package/dist/{chunk-57WB2EDF.js.map → chunk-ZBUROTJQ.js.map} +0 -0
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
analyzeArrangement,
|
|
3
3
|
analyzePolyphony,
|
|
4
|
+
analyzeReference,
|
|
4
5
|
createArrangementSession,
|
|
5
|
-
extractMotifs,
|
|
6
6
|
hypermeter,
|
|
7
|
-
melodicContour,
|
|
8
|
-
melodicSimilarity,
|
|
9
|
-
motifFromNotes,
|
|
10
7
|
phrasesFromTimeline,
|
|
11
|
-
|
|
12
|
-
relateMotifs,
|
|
8
|
+
referenceFromReadings,
|
|
13
9
|
sectionsFromNotes,
|
|
14
10
|
structuralCadences,
|
|
15
11
|
tensionCurveFrom,
|
|
16
12
|
trackRoleOf
|
|
17
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-MLBPXA4Z.js";
|
|
18
14
|
import {
|
|
19
15
|
TWELVE_TET,
|
|
20
16
|
beatsToDuration,
|
|
@@ -38,18 +34,21 @@ import {
|
|
|
38
34
|
tempoAt,
|
|
39
35
|
tempoReader,
|
|
40
36
|
ticksToBeats
|
|
41
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-UMWZ4ZET.js";
|
|
42
38
|
import {
|
|
43
39
|
STEP_BEATS,
|
|
44
40
|
applyGrooveTemplate,
|
|
45
41
|
cellSpan,
|
|
46
42
|
deform,
|
|
43
|
+
deriveCompositionPlan,
|
|
47
44
|
developMotif,
|
|
48
45
|
doubleTime,
|
|
46
|
+
evaluateComposition,
|
|
49
47
|
extractGrooveTemplate,
|
|
50
48
|
generateBassLine,
|
|
51
49
|
generateCounterMelody,
|
|
52
50
|
generateDrums,
|
|
51
|
+
generateMelody,
|
|
53
52
|
generateMotif,
|
|
54
53
|
generateProgression,
|
|
55
54
|
generateRhythm,
|
|
@@ -69,9 +68,10 @@ import {
|
|
|
69
68
|
thin,
|
|
70
69
|
transformMotif,
|
|
71
70
|
withinCeiling
|
|
72
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-CPMB7P75.js";
|
|
73
72
|
import {
|
|
74
73
|
analyzeChord,
|
|
74
|
+
analyzeRhythm,
|
|
75
75
|
augmentedSixthChord,
|
|
76
76
|
borrowedSource,
|
|
77
77
|
chordAtBeat,
|
|
@@ -87,17 +87,24 @@ import {
|
|
|
87
87
|
detectKeyFromNotes,
|
|
88
88
|
detectModulations,
|
|
89
89
|
explainRoman,
|
|
90
|
+
extractMotifs,
|
|
90
91
|
functionOf,
|
|
91
92
|
isBorrowedChord,
|
|
92
93
|
isMinorKey,
|
|
93
94
|
keyLookup,
|
|
94
95
|
keyTimelineFromNotes,
|
|
96
|
+
melodicContour,
|
|
97
|
+
melodicSimilarity,
|
|
98
|
+
motifFromNotes,
|
|
99
|
+
motifGraph,
|
|
95
100
|
pivotChords,
|
|
96
101
|
prevailingKeyOf,
|
|
102
|
+
reduceProgression,
|
|
103
|
+
relateMotifs,
|
|
97
104
|
romanToChord,
|
|
98
105
|
secondaryDominantOf,
|
|
99
106
|
toVoiceNotes
|
|
100
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-GNVN4PPJ.js";
|
|
101
108
|
import {
|
|
102
109
|
BASS_4_STRING,
|
|
103
110
|
BASS_5_STRING,
|
|
@@ -110,10 +117,10 @@ import {
|
|
|
110
117
|
soundsIn,
|
|
111
118
|
toInstrumentProfile,
|
|
112
119
|
toStringedProfile
|
|
113
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-7KG3RTYS.js";
|
|
114
121
|
import {
|
|
115
122
|
createNoteEventIndex
|
|
116
|
-
} from "./chunk-
|
|
123
|
+
} from "./chunk-PUKJP2Z5.js";
|
|
117
124
|
import {
|
|
118
125
|
SATB_RANGES,
|
|
119
126
|
checkPartWriting,
|
|
@@ -128,14 +135,14 @@ import {
|
|
|
128
135
|
voiceChordStyled,
|
|
129
136
|
voiceLeadingCost,
|
|
130
137
|
voiceProgression
|
|
131
|
-
} from "./chunk-
|
|
138
|
+
} from "./chunk-M5RYMAFI.js";
|
|
132
139
|
import {
|
|
133
140
|
availableTensions,
|
|
134
141
|
avoidNotes,
|
|
135
142
|
chordScaleReport,
|
|
136
143
|
chordScales,
|
|
137
144
|
scalesForChanges
|
|
138
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-NB25P3EH.js";
|
|
139
146
|
import {
|
|
140
147
|
NAMED_SCALES,
|
|
141
148
|
assertChordQuality,
|
|
@@ -191,7 +198,7 @@ import {
|
|
|
191
198
|
tryResolveKeyName,
|
|
192
199
|
variantOfMask,
|
|
193
200
|
voiceIndependence
|
|
194
|
-
} from "./chunk-
|
|
201
|
+
} from "./chunk-RFIBF2RR.js";
|
|
195
202
|
import {
|
|
196
203
|
InvalidInputError,
|
|
197
204
|
MAX_NAME_ACCIDENTALS,
|
|
@@ -235,7 +242,7 @@ import {
|
|
|
235
242
|
tryParseTimeSignature,
|
|
236
243
|
tuplet,
|
|
237
244
|
unwrapParse
|
|
238
|
-
} from "./chunk-
|
|
245
|
+
} from "./chunk-AGOVW7U6.js";
|
|
239
246
|
|
|
240
247
|
// src/model/interval.ts
|
|
241
248
|
var INVERSION_SUM = 9;
|
|
@@ -4411,6 +4418,8 @@ var Score = class _Score {
|
|
|
4411
4418
|
#chords;
|
|
4412
4419
|
/** The key regions, made on the first member that needs them. */
|
|
4413
4420
|
#regions;
|
|
4421
|
+
/** The reference profile asked for with no options, made on first read. */
|
|
4422
|
+
#profile;
|
|
4414
4423
|
/**
|
|
4415
4424
|
* Wrap plain score data.
|
|
4416
4425
|
*
|
|
@@ -4898,6 +4907,143 @@ var Score = class _Score {
|
|
|
4898
4907
|
contour() {
|
|
4899
4908
|
return melodicContour(this.#data.notes);
|
|
4900
4909
|
}
|
|
4910
|
+
/**
|
|
4911
|
+
* The score's structural fingerprint: form, phrase shape, harmonic function
|
|
4912
|
+
* and rhythm, and how its motifs derive from one another.
|
|
4913
|
+
*
|
|
4914
|
+
* The harmony is the score's own kept chord analysis, read once whether this
|
|
4915
|
+
* is asked before or after {@link Score.timeline} — unless `opts.timeline`
|
|
4916
|
+
* gives the harmony directly, in which case the reading runs fresh through
|
|
4917
|
+
* {@link analyzeReference} rather than the harmony this score already holds.
|
|
4918
|
+
* The meter, the key and the span are the score's own and are not on offer
|
|
4919
|
+
* here: a caller wanting another meter reads through {@link
|
|
4920
|
+
* Score.withMeters}, and one wanting another key or span calls {@link
|
|
4921
|
+
* analyzeReference} directly.
|
|
4922
|
+
*
|
|
4923
|
+
* Asked with no options, the answer is kept and a copy of it handed back, as
|
|
4924
|
+
* {@link Score.timeline} keeps its own reading; asked with options, the
|
|
4925
|
+
* answer is read afresh and not kept.
|
|
4926
|
+
*
|
|
4927
|
+
* @param opts The harmony, the melody, and the budget; see {@link
|
|
4928
|
+
* ReferenceProfileOptions}. Meter, key and span are the score's own.
|
|
4929
|
+
* @returns The profile.
|
|
4930
|
+
* @example
|
|
4931
|
+
* ```ts
|
|
4932
|
+
* import { Score } from '@libraz/libcantus';
|
|
4933
|
+
* const triad = (pitches: number[], startBeat: number) =>
|
|
4934
|
+
* pitches.map((pitch) => ({ pitch, startBeat, durationBeat: 4 }));
|
|
4935
|
+
* const score = Score.of(
|
|
4936
|
+
* [
|
|
4937
|
+
* ...triad([60, 64, 67], 0),
|
|
4938
|
+
* ...triad([65, 69, 72], 4),
|
|
4939
|
+
* ...triad([67, 71, 74], 8),
|
|
4940
|
+
* ...triad([60, 64, 67], 12),
|
|
4941
|
+
* ],
|
|
4942
|
+
* { key: 'C major' },
|
|
4943
|
+
* );
|
|
4944
|
+
* score.reference().harmony.chords.map((chord) => chord.roman); // ['I', 'IV', 'V', 'I']
|
|
4945
|
+
* ```
|
|
4946
|
+
*/
|
|
4947
|
+
reference(opts) {
|
|
4948
|
+
if (opts === void 0 && this.#profile !== void 0) {
|
|
4949
|
+
return copyPlain(this.#profile, "reference profile");
|
|
4950
|
+
}
|
|
4951
|
+
const keyed = this.#key === void 0 ? {} : { key: keyIdentity(this.#key) };
|
|
4952
|
+
const asked = {
|
|
4953
|
+
meters: this.#data.meters,
|
|
4954
|
+
totalBeats: this.totalBeats,
|
|
4955
|
+
...keyed,
|
|
4956
|
+
...opts
|
|
4957
|
+
};
|
|
4958
|
+
const profile = opts?.timeline === void 0 ? referenceFromReadings(this.#data.notes, this.#chordAnalysis(), asked) : analyzeReference(this.#data.notes, asked);
|
|
4959
|
+
if (opts === void 0) {
|
|
4960
|
+
this.#profile = profile;
|
|
4961
|
+
return copyPlain(profile, "reference profile");
|
|
4962
|
+
}
|
|
4963
|
+
return profile;
|
|
4964
|
+
}
|
|
4965
|
+
/**
|
|
4966
|
+
* The onset placement of the score's melodic line.
|
|
4967
|
+
*
|
|
4968
|
+
* A melody is one line, so a score holding several is read as its top voice,
|
|
4969
|
+
* as {@link Score.motifs} and {@link Score.contour} are.
|
|
4970
|
+
*
|
|
4971
|
+
* @param opts The span's end and the budget; see {@link
|
|
4972
|
+
* RhythmAnalysisOptions}. The meter is the score's own.
|
|
4973
|
+
* @returns The rhythm reading.
|
|
4974
|
+
* @example
|
|
4975
|
+
* ```ts
|
|
4976
|
+
* import { Score } from '@libraz/libcantus';
|
|
4977
|
+
* const score = Score.of([
|
|
4978
|
+
* { pitch: 60, startBeat: 0, durationBeat: 1 },
|
|
4979
|
+
* { pitch: 62, startBeat: 1, durationBeat: 1 },
|
|
4980
|
+
* { pitch: 64, startBeat: 2, durationBeat: 1 },
|
|
4981
|
+
* { pitch: 65, startBeat: 3, durationBeat: 1 },
|
|
4982
|
+
* ]);
|
|
4983
|
+
* score.rhythm().onsetDensity; // 4
|
|
4984
|
+
* ```
|
|
4985
|
+
*/
|
|
4986
|
+
rhythm(opts) {
|
|
4987
|
+
return analyzeRhythm(this.#data.notes, {
|
|
4988
|
+
meters: this.#data.meters,
|
|
4989
|
+
totalBeats: this.totalBeats,
|
|
4990
|
+
...opts
|
|
4991
|
+
});
|
|
4992
|
+
}
|
|
4993
|
+
/**
|
|
4994
|
+
* How the score's motifs derive from one another: which statement grew out
|
|
4995
|
+
* of which, and by what transformation.
|
|
4996
|
+
*
|
|
4997
|
+
* {@link Score.motifs} finds the cells; this reads across their occurrences
|
|
4998
|
+
* and names, for every statement after the first, the earlier one it most
|
|
4999
|
+
* plausibly grew out of. A melody is one line, so a score holding several is
|
|
5000
|
+
* read as its top voice, as {@link Score.motifs} is.
|
|
5001
|
+
*
|
|
5002
|
+
* @param opts Cell-length bounds and the recurrence threshold {@link
|
|
5003
|
+
* Score.motifs} takes, plus the variation threshold and the budget; see
|
|
5004
|
+
* {@link MotifGraphOptions} and {@link ExtractMotifsOptions}.
|
|
5005
|
+
* @returns The derivation forest.
|
|
5006
|
+
* @example
|
|
5007
|
+
* ```ts
|
|
5008
|
+
* import { Score } from '@libraz/libcantus';
|
|
5009
|
+
* const score = Score.of([
|
|
5010
|
+
* { pitch: 60, startBeat: 0, durationBeat: 1 },
|
|
5011
|
+
* { pitch: 62, startBeat: 1, durationBeat: 1 },
|
|
5012
|
+
* { pitch: 64, startBeat: 2, durationBeat: 1 },
|
|
5013
|
+
* { pitch: 60, startBeat: 3, durationBeat: 1 },
|
|
5014
|
+
* { pitch: 62, startBeat: 4, durationBeat: 1 },
|
|
5015
|
+
* { pitch: 64, startBeat: 5, durationBeat: 1 },
|
|
5016
|
+
* ]);
|
|
5017
|
+
* score.motifGraph().edges.length; // 1
|
|
5018
|
+
* ```
|
|
5019
|
+
*/
|
|
5020
|
+
motifGraph(opts) {
|
|
5021
|
+
return motifGraph(this.#data.notes, extractMotifs(this.#data.notes, opts), {
|
|
5022
|
+
key: this.key(),
|
|
5023
|
+
...opts
|
|
5024
|
+
});
|
|
5025
|
+
}
|
|
5026
|
+
/**
|
|
5027
|
+
* How this score, read as a melody, keeps to a composition plan.
|
|
5028
|
+
*
|
|
5029
|
+
* @param plan The plan the melody was written for.
|
|
5030
|
+
* @param opts The budget; see {@link EvaluateCompositionOptions}.
|
|
5031
|
+
* @returns The violations found and the fit reading; see {@link
|
|
5032
|
+
* evaluateComposition}.
|
|
5033
|
+
* @example
|
|
5034
|
+
* ```ts
|
|
5035
|
+
* import { Composer, Score } from '@libraz/libcantus';
|
|
5036
|
+
* const notes = [60, 62, 64, 65, 67, 65, 64, 62, 60, 62, 64, 65, 67, 65, 64, 60].map(
|
|
5037
|
+
* (pitch, startBeat) => ({ pitch, startBeat, durationBeat: 1 }),
|
|
5038
|
+
* );
|
|
5039
|
+
* const composer = Composer.of({ key: 'C major', seed: 5 });
|
|
5040
|
+
* const plan = composer.plan(Score.of(notes, { key: 'C major' }).reference());
|
|
5041
|
+
* composer.melody(plan).evaluate(plan).violations.some((v) => v.severity === 'error'); // false
|
|
5042
|
+
* ```
|
|
5043
|
+
*/
|
|
5044
|
+
evaluate(plan, opts) {
|
|
5045
|
+
return evaluateComposition(this.#data.notes, plan, opts);
|
|
5046
|
+
}
|
|
4901
5047
|
/**
|
|
4902
5048
|
* Each note's role in the harmony sounding under it.
|
|
4903
5049
|
*
|
|
@@ -5532,6 +5678,70 @@ var Arrangement = class _Arrangement {
|
|
|
5532
5678
|
keys: [...keys]
|
|
5533
5679
|
});
|
|
5534
5680
|
}
|
|
5681
|
+
/**
|
|
5682
|
+
* The arrangement's structural fingerprint: form, phrase shape, harmonic
|
|
5683
|
+
* function and rhythm, and how its melody's motifs derive from one another.
|
|
5684
|
+
*
|
|
5685
|
+
* The harmony reads the arrangement's own session analysis directly — the
|
|
5686
|
+
* tracks `settings.harmonyTracks` names, or else every track but the
|
|
5687
|
+
* percussion ones — so the harmony is never inferred a second time. The
|
|
5688
|
+
* melody is the notes of the tracks played with `role: 'melody'`, joined in
|
|
5689
|
+
* the order the tracks were given; an arrangement naming none reads the top
|
|
5690
|
+
* line of the harmony notes instead, as {@link analyzeReference} does
|
|
5691
|
+
* without a `melody` option. Meter, key, harmony and melody are the
|
|
5692
|
+
* arrangement's own and are not on offer here: a caller wanting others calls
|
|
5693
|
+
* {@link analyzeReference} directly, with the same notes {@link
|
|
5694
|
+
* Arrangement.tracks} hands out.
|
|
5695
|
+
*
|
|
5696
|
+
* @param opts The budget; see {@link ReferenceProfileOptions}.
|
|
5697
|
+
* @returns The profile.
|
|
5698
|
+
* @example
|
|
5699
|
+
* ```ts
|
|
5700
|
+
* import { Arrangement } from '@libraz/libcantus';
|
|
5701
|
+
* const triad = (pitches: number[], startBeat: number) =>
|
|
5702
|
+
* pitches.map((pitch) => ({ pitch, startBeat, durationBeat: 4 }));
|
|
5703
|
+
* const arrangement = Arrangement.of(
|
|
5704
|
+
* [
|
|
5705
|
+
* {
|
|
5706
|
+
* name: 'lead',
|
|
5707
|
+
* role: 'melody',
|
|
5708
|
+
* notes: [
|
|
5709
|
+
* ...triad([60, 64, 67], 0),
|
|
5710
|
+
* ...triad([65, 69, 72], 4),
|
|
5711
|
+
* ...triad([67, 71, 74], 8),
|
|
5712
|
+
* ...triad([60, 64, 67], 12),
|
|
5713
|
+
* ],
|
|
5714
|
+
* },
|
|
5715
|
+
* ],
|
|
5716
|
+
* { key: 'C major' },
|
|
5717
|
+
* );
|
|
5718
|
+
* arrangement.reference().harmony.chords.map((chord) => chord.roman); // ['I', 'IV', 'V', 'I']
|
|
5719
|
+
* ```
|
|
5720
|
+
*/
|
|
5721
|
+
reference(opts) {
|
|
5722
|
+
const tracks = this.#data.tracks;
|
|
5723
|
+
const harmonyTracks = this.#data.settings?.harmonyTracks;
|
|
5724
|
+
const harmony = [];
|
|
5725
|
+
const melody = [];
|
|
5726
|
+
for (let index = 0; index < tracks.length; index += 1) {
|
|
5727
|
+
const track = tracks[index];
|
|
5728
|
+
if (track === void 0) {
|
|
5729
|
+
continue;
|
|
5730
|
+
}
|
|
5731
|
+
if (track.role !== "drums" && (harmonyTracks === void 0 || harmonyTracks.includes(index))) {
|
|
5732
|
+
harmony.push(...track.notes);
|
|
5733
|
+
}
|
|
5734
|
+
if (track.role === "melody") {
|
|
5735
|
+
melody.push(...track.notes);
|
|
5736
|
+
}
|
|
5737
|
+
}
|
|
5738
|
+
return referenceFromReadings(harmony, this.#session().analysis, {
|
|
5739
|
+
meters: this.#data.settings?.meters,
|
|
5740
|
+
totalBeats: this.timeline().totalBeats,
|
|
5741
|
+
...melody.length === 0 ? {} : { melody },
|
|
5742
|
+
...opts
|
|
5743
|
+
});
|
|
5744
|
+
}
|
|
5535
5745
|
/**
|
|
5536
5746
|
* Whether another arrangement holds the same tracks under the same settings.
|
|
5537
5747
|
*
|
|
@@ -6228,6 +6438,73 @@ var Composer = class _Composer {
|
|
|
6228
6438
|
transposeSemitones: result.transposeSemitones
|
|
6229
6439
|
};
|
|
6230
6440
|
}
|
|
6441
|
+
/**
|
|
6442
|
+
* A composition plan derived from a reference profile.
|
|
6443
|
+
*
|
|
6444
|
+
* The composer's key is the plan's home key unless `opts.key` names another,
|
|
6445
|
+
* and its seed and algorithm version are the ones the plan records, so the
|
|
6446
|
+
* plan is written under the same recipe as the composer's other parts.
|
|
6447
|
+
*
|
|
6448
|
+
* @param reference The reference profile to derive from.
|
|
6449
|
+
* @param opts Everything {@link deriveCompositionPlan} takes but the context,
|
|
6450
|
+
* which is the composer's.
|
|
6451
|
+
* @returns The plan.
|
|
6452
|
+
* @throws If the composer draws from a caller-held `rng`: a plan records its
|
|
6453
|
+
* seed, and a source cannot be written into it.
|
|
6454
|
+
* @example
|
|
6455
|
+
* ```ts
|
|
6456
|
+
* import { Composer, Score } from '@libraz/libcantus';
|
|
6457
|
+
* const notes = [60, 62, 64, 65, 67, 65, 64, 62, 60, 62, 64, 65, 67, 65, 64, 60].map(
|
|
6458
|
+
* (pitch, startBeat) => ({ pitch, startBeat, durationBeat: 1 }),
|
|
6459
|
+
* );
|
|
6460
|
+
* const reference = Score.of(notes, { key: 'C major' }).reference();
|
|
6461
|
+
* const plan = Composer.of({ key: 'D major', seed: 5 }).plan(reference);
|
|
6462
|
+
* plan.seed; // 5
|
|
6463
|
+
* plan.keys[0].scale.rootPc; // 2
|
|
6464
|
+
* ```
|
|
6465
|
+
*/
|
|
6466
|
+
plan(reference, opts) {
|
|
6467
|
+
const ctx = this.context;
|
|
6468
|
+
if (ctx.rng !== void 0) {
|
|
6469
|
+
throw new InvalidInputError(
|
|
6470
|
+
"composer plan cannot record a caller-held rng; give the composer a seed instead"
|
|
6471
|
+
);
|
|
6472
|
+
}
|
|
6473
|
+
return deriveCompositionPlan(reference, {
|
|
6474
|
+
...this.#key === void 0 ? {} : { key: this.#key },
|
|
6475
|
+
...opts,
|
|
6476
|
+
ctx
|
|
6477
|
+
});
|
|
6478
|
+
}
|
|
6479
|
+
/**
|
|
6480
|
+
* A melody written to a composition plan.
|
|
6481
|
+
*
|
|
6482
|
+
* The plan is the reproduction recipe, so its seed and algorithm version are
|
|
6483
|
+
* the ones the melody is drawn under, not the composer's. The score is read
|
|
6484
|
+
* in the plan's meter and home key, at the composer's tempo.
|
|
6485
|
+
*
|
|
6486
|
+
* @param plan The plan to follow.
|
|
6487
|
+
* @param opts The budget; see {@link MelodyOptions}.
|
|
6488
|
+
* @returns The melody, as a score.
|
|
6489
|
+
* @example
|
|
6490
|
+
* ```ts
|
|
6491
|
+
* import { Composer, Score } from '@libraz/libcantus';
|
|
6492
|
+
* const notes = [60, 62, 64, 65, 67, 65, 64, 62, 60, 62, 64, 65, 67, 65, 64, 60].map(
|
|
6493
|
+
* (pitch, startBeat) => ({ pitch, startBeat, durationBeat: 1 }),
|
|
6494
|
+
* );
|
|
6495
|
+
* const composer = Composer.of({ key: 'C major', seed: 5 });
|
|
6496
|
+
* const plan = composer.plan(Score.of(notes, { key: 'C major' }).reference());
|
|
6497
|
+
* composer.melody(plan).notes.length > 0; // true
|
|
6498
|
+
* ```
|
|
6499
|
+
*/
|
|
6500
|
+
melody(plan, opts) {
|
|
6501
|
+
const notes = generateMelody(plan, opts);
|
|
6502
|
+
const score = { meters: plan.meters, key: plan.keys[0] };
|
|
6503
|
+
if (this.#options.bpm !== void 0) {
|
|
6504
|
+
score.tempo = this.#options.bpm;
|
|
6505
|
+
}
|
|
6506
|
+
return Score.of(notes, score);
|
|
6507
|
+
}
|
|
6231
6508
|
/**
|
|
6232
6509
|
* Whether another composer holds the same settings.
|
|
6233
6510
|
*
|
|
@@ -8106,7 +8383,8 @@ var Voicing = class _Voicing {
|
|
|
8106
8383
|
* @param pitch The candidate MIDI pitch.
|
|
8107
8384
|
* @param query The candidate's harmonic and voice-leading context.
|
|
8108
8385
|
* @param opts Set `suggestions: false` to skip the search for safe
|
|
8109
|
-
* replacements when the verdict is not safe
|
|
8386
|
+
* replacements when the verdict is not safe, and `partners: true` to learn
|
|
8387
|
+
* which voice of this voicing, by index, raised each pairwise flag.
|
|
8110
8388
|
* @returns The verdict, reason bitmask, and optional resolution guidance.
|
|
8111
8389
|
* @throws If the profile is unknown, a value names no chord or key, or a
|
|
8112
8390
|
* pitch is not a MIDI pitch in 0..127.
|
|
@@ -8249,4 +8527,4 @@ export {
|
|
|
8249
8527
|
Tuning,
|
|
8250
8528
|
Voicing
|
|
8251
8529
|
};
|
|
8252
|
-
//# sourceMappingURL=chunk-
|
|
8530
|
+
//# sourceMappingURL=chunk-IPEF6NWB.js.map
|