@libraz/libcantus 0.9.3 → 0.9.5
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 +29 -20
- package/README_ja.md +268 -0
- package/dist/analyze/index.cjs +39 -1947
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +161 -91
- package/dist/analyze/index.d.ts +161 -91
- package/dist/analyze/index.js +19 -8
- package/dist/chunk-2A2QMA74.cjs +261 -0
- package/dist/chunk-2A2QMA74.cjs.map +1 -0
- package/dist/chunk-2PTFGVD7.js +261 -0
- package/dist/chunk-2PTFGVD7.js.map +1 -0
- package/dist/chunk-357ZDPVU.cjs +162 -0
- package/dist/chunk-357ZDPVU.cjs.map +1 -0
- package/dist/chunk-3KX76RLG.js +1548 -0
- package/dist/chunk-3KX76RLG.js.map +1 -0
- package/dist/chunk-4VZ5MZAM.cjs +889 -0
- package/dist/chunk-4VZ5MZAM.cjs.map +1 -0
- package/dist/{chunk-C5XYKUVG.js → chunk-7EONYVI5.js} +471 -171
- package/dist/chunk-7EONYVI5.js.map +1 -0
- package/dist/{chunk-IT2O4XFE.js → chunk-7JEP3MFY.js} +42 -34
- package/dist/chunk-7JEP3MFY.js.map +1 -0
- package/dist/{chunk-4MHA432G.js → chunk-AID75RN3.js} +572 -250
- package/dist/chunk-AID75RN3.js.map +1 -0
- package/dist/chunk-BSLTLGM3.cjs +497 -0
- package/dist/chunk-BSLTLGM3.cjs.map +1 -0
- package/dist/chunk-CU6VG2YM.cjs +109 -0
- package/dist/chunk-CU6VG2YM.cjs.map +1 -0
- package/dist/{chunk-EH6EM37U.js → chunk-DZMHIGI4.js} +81 -59
- package/dist/chunk-DZMHIGI4.js.map +1 -0
- package/dist/{chunk-AKLYPWIN.js → chunk-EDOTEABK.js} +45 -19
- package/dist/chunk-EDOTEABK.js.map +1 -0
- package/dist/{chunk-2ZWMSJH6.js → chunk-HN2OEUN2.js} +7 -4
- package/dist/chunk-HN2OEUN2.js.map +1 -0
- package/dist/{chunk-MIWO425M.js → chunk-KBTTEX7Q.js} +128 -43
- package/dist/chunk-KBTTEX7Q.js.map +1 -0
- package/dist/chunk-KQN2ZYND.cjs +724 -0
- package/dist/chunk-KQN2ZYND.cjs.map +1 -0
- package/dist/chunk-MPTVJIVG.cjs +3176 -0
- package/dist/chunk-MPTVJIVG.cjs.map +1 -0
- package/dist/chunk-MTMZTMWM.cjs +53 -0
- package/dist/chunk-MTMZTMWM.cjs.map +1 -0
- package/dist/{chunk-CHMXELDS.js → chunk-NNB67XA2.js} +372 -197
- package/dist/chunk-NNB67XA2.js.map +1 -0
- package/dist/chunk-OL3IHHSJ.cjs +1204 -0
- package/dist/chunk-OL3IHHSJ.cjs.map +1 -0
- package/dist/chunk-PI3UXRWK.cjs +528 -0
- package/dist/chunk-PI3UXRWK.cjs.map +1 -0
- package/dist/chunk-R2VVFAIN.js +528 -0
- package/dist/chunk-R2VVFAIN.js.map +1 -0
- package/dist/chunk-T64C7ZD7.cjs +1 -0
- package/dist/chunk-T64C7ZD7.cjs.map +1 -0
- package/dist/chunk-WFDXOLUB.cjs +337 -0
- package/dist/chunk-WFDXOLUB.cjs.map +1 -0
- package/dist/chunk-WTAN4ACG.cjs +1548 -0
- package/dist/chunk-WTAN4ACG.cjs.map +1 -0
- package/dist/chunk-YFJXS3AU.cjs +33 -0
- package/dist/chunk-YFJXS3AU.cjs.map +1 -0
- package/dist/{chunk-GOAW4VYL.js → chunk-YUE6TJ4M.js} +315 -145
- package/dist/chunk-YUE6TJ4M.js.map +1 -0
- package/dist/{chunk-62QZKCJQ.js → chunk-ZGLJM4A4.js} +10 -6
- package/dist/chunk-ZGLJM4A4.js.map +1 -0
- package/dist/core/index.cjs +140 -647
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +313 -41
- package/dist/core/index.d.ts +313 -41
- package/dist/core/index.js +64 -16
- package/dist/{function-DVH4Eusr.d.ts → function-CxixTB02.d.cts} +122 -10
- package/dist/{function-DYt4iKsn.d.cts → function-DTCt675z.d.ts} +122 -10
- package/dist/generate/index.cjs +28 -4085
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +374 -66
- package/dist/generate/index.d.ts +374 -66
- package/dist/generate/index.js +23 -9
- package/dist/{index-Jc0Ryi79.d.ts → index-B2Ulxxpo.d.cts} +21 -5
- package/dist/{index-CpOsP1y9.d.cts → index-BkYJ0xMq.d.cts} +18 -17
- package/dist/{index-CxqBQtH1.d.cts → index-BuaB-ypt.d.ts} +21 -5
- package/dist/index-CAN7v-kw.d.ts +199 -0
- package/dist/{index-Bt4tOUD9.d.ts → index-COw1Ky9g.d.ts} +93 -8
- package/dist/{index-Dikst44v.d.cts → index-Cfx8xgH0.d.ts} +14 -11
- package/dist/{index-DxvARIP2.d.ts → index-DRtIhlJj.d.ts} +18 -17
- package/dist/{index-Cl7mhOFM.d.cts → index-DXd9JikN.d.cts} +92 -10
- package/dist/{index-Cl7mhOFM.d.ts → index-DXd9JikN.d.ts} +92 -10
- package/dist/index-alrRninU.d.cts +199 -0
- package/dist/{index-BNlGP86A.d.cts → index-oTQbYYIs.d.cts} +93 -8
- package/dist/index-tR9jTn26.d.cts +275 -0
- package/dist/index-tR9jTn26.d.ts +275 -0
- package/dist/{index-Bg5dYMmZ.d.ts → index-x2vcsduE.d.cts} +14 -11
- package/dist/index.cjs +429 -7383
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -15
- package/dist/index.d.ts +15 -15
- package/dist/index.js +121 -27
- package/dist/model/index.cjs +8 -2562
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +471 -81
- package/dist/model/index.d.ts +471 -81
- package/dist/model/index.js +6 -7
- package/dist/styled-Bl0ZK28h.d.ts +543 -0
- package/dist/styled-Crv6SA4S.d.cts +543 -0
- package/dist/theory/index.cjs +172 -1822
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +151 -233
- package/dist/theory/index.d.ts +151 -233
- package/dist/theory/index.js +30 -7
- package/dist/{types-MGP29r3t.d.cts → types-BN6_Q9Kl.d.cts} +11 -2
- package/dist/{types-MGP29r3t.d.ts → types-BN6_Q9Kl.d.ts} +11 -2
- package/package.json +34 -13
- package/dist/chunk-2ZWMSJH6.js.map +0 -1
- package/dist/chunk-4MHA432G.js.map +0 -1
- package/dist/chunk-62QZKCJQ.js.map +0 -1
- package/dist/chunk-AKLYPWIN.js.map +0 -1
- package/dist/chunk-C5XYKUVG.js.map +0 -1
- package/dist/chunk-CHMXELDS.js.map +0 -1
- package/dist/chunk-DYWFNC4A.js +0 -152
- package/dist/chunk-DYWFNC4A.js.map +0 -1
- package/dist/chunk-EH6EM37U.js.map +0 -1
- package/dist/chunk-FBQK3ZQN.js +0 -131
- package/dist/chunk-FBQK3ZQN.js.map +0 -1
- package/dist/chunk-GOAW4VYL.js.map +0 -1
- package/dist/chunk-I5R7ZBJS.js +0 -202
- package/dist/chunk-I5R7ZBJS.js.map +0 -1
- package/dist/chunk-IT2O4XFE.js.map +0 -1
- package/dist/chunk-MIWO425M.js.map +0 -1
- package/dist/chunk-SGU7SPLK.js +0 -924
- package/dist/chunk-SGU7SPLK.js.map +0 -1
- package/dist/index-CGMZNCx6.d.cts +0 -140
- package/dist/index-CGMZNCx6.d.ts +0 -140
- package/dist/index-CnZCo29u.d.cts +0 -108
- package/dist/index-JnF4v9bx.d.ts +0 -108
- package/dist/styled-DZ7GjShb.d.ts +0 -282
- package/dist/styled-ZTbdaVFM.d.cts +0 -282
- package/src/analyze/arrange/index.ts +0 -21
- package/src/analyze/arrange/internal.ts +0 -127
- package/src/analyze/arrange/tension.ts +0 -199
- package/src/analyze/arrange/tracks.ts +0 -312
- package/src/analyze/detect/index.ts +0 -272
- package/src/analyze/functional/borrowed.ts +0 -84
- package/src/analyze/functional/cadence.ts +0 -66
- package/src/analyze/functional/function.ts +0 -184
- package/src/analyze/functional/index.ts +0 -23
- package/src/analyze/functional/internal.ts +0 -29
- package/src/analyze/functional/roman.ts +0 -402
- package/src/analyze/index.ts +0 -49
- package/src/analyze/timeline/index.ts +0 -451
- package/src/analyze/voice/index.ts +0 -339
- package/src/core/event-index/index.ts +0 -104
- package/src/core/index.ts +0 -61
- package/src/core/interval/index.ts +0 -81
- package/src/core/meter/index.ts +0 -302
- package/src/core/pitch/index.ts +0 -311
- package/src/core/random/index.ts +0 -76
- package/src/core/tuning/index.ts +0 -186
- package/src/core/types.ts +0 -29
- package/src/core/validation/index.ts +0 -119
- package/src/generate/bass/index.ts +0 -373
- package/src/generate/countermelody/index.ts +0 -470
- package/src/generate/drums/beat.ts +0 -266
- package/src/generate/drums/euclid.ts +0 -65
- package/src/generate/drums/fills.ts +0 -356
- package/src/generate/drums/ghost.ts +0 -119
- package/src/generate/drums/hihat.ts +0 -285
- package/src/generate/drums/hit.ts +0 -31
- package/src/generate/drums/index.ts +0 -361
- package/src/generate/drums/internal.ts +0 -257
- package/src/generate/drums/kick.ts +0 -160
- package/src/generate/drums/percussion.ts +0 -121
- package/src/generate/drums/rng.ts +0 -7
- package/src/generate/drums/swing.ts +0 -71
- package/src/generate/groove/index.ts +0 -351
- package/src/generate/harmonize/index.ts +0 -451
- package/src/generate/index.ts +0 -58
- package/src/generate/motif/index.ts +0 -422
- package/src/generate/progression/index.ts +0 -362
- package/src/generate/reharmony/index.ts +0 -323
- package/src/generate/rhythm/index.ts +0 -175
- package/src/index.ts +0 -13
- package/src/model/chord.ts +0 -442
- package/src/model/index.ts +0 -15
- package/src/model/interval.ts +0 -82
- package/src/model/key.ts +0 -266
- package/src/model/note.ts +0 -176
- package/src/model/progression.ts +0 -161
- package/src/model/shared.ts +0 -12
- package/src/theory/chord/index.ts +0 -375
- package/src/theory/chordscale/index.ts +0 -374
- package/src/theory/counterpoint/index.ts +0 -230
- package/src/theory/harmony/index.ts +0 -77
- package/src/theory/index.ts +0 -112
- package/src/theory/safety/index.ts +0 -488
- package/src/theory/scale/degrees.ts +0 -123
- package/src/theory/scale/index.ts +0 -28
- package/src/theory/scale/key.ts +0 -56
- package/src/theory/scale/masks.ts +0 -153
- package/src/theory/spelling/index.ts +0 -249
- package/src/theory/symbol/index.ts +0 -268
- package/src/theory/voicing/index.ts +0 -5
- package/src/theory/voicing/internal.ts +0 -168
- package/src/theory/voicing/leading.ts +0 -112
- package/src/theory/voicing/satb.ts +0 -216
- package/src/theory/voicing/styled.ts +0 -199
- package/tsconfig.json +0 -23
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
import { T as TimeSignature } from './index-
|
|
2
|
-
import { K as KeyScale, N as NoteEvent } from './types-
|
|
3
|
-
import { C as Chord, b as ChordSpan } from './index-
|
|
4
|
-
import { C as Cadence } from './function-
|
|
1
|
+
import { T as TimeSignature } from './index-DXd9JikN.js';
|
|
2
|
+
import { K as KeyScale, N as NoteEvent } from './types-BN6_Q9Kl.js';
|
|
3
|
+
import { C as Chord, b as ChordSegment, c as ChordSpan } from './index-COw1Ky9g.js';
|
|
4
|
+
import { C as Cadence } from './function-DTCt675z.js';
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* A chord occupying a half-open beat span.
|
|
8
|
-
*
|
|
9
|
-
* @category Arrangement & Analysis
|
|
10
|
-
*/
|
|
11
|
-
type ChordSegment = {
|
|
12
|
-
startBeat: number;
|
|
13
|
-
endBeat: number;
|
|
14
|
-
chord: Chord;
|
|
15
|
-
};
|
|
16
6
|
/**
|
|
17
7
|
* A beat-indexed sequence of chord segments.
|
|
18
8
|
*
|
|
@@ -36,14 +26,14 @@ type ChordTimeline = {
|
|
|
36
26
|
* @returns A queryable chord timeline.
|
|
37
27
|
* @category Arrangement & Analysis
|
|
38
28
|
*/
|
|
39
|
-
declare function chordTimelineFromChords(chords: ChordSpan[], totalBeats: number): ChordTimeline;
|
|
29
|
+
declare function chordTimelineFromChords(chords: readonly ChordSpan[], totalBeats: number): ChordTimeline;
|
|
40
30
|
/**
|
|
41
31
|
* Options controlling {@link chordTimelineFromNotes}.
|
|
42
32
|
*
|
|
43
33
|
* @category Arrangement & Analysis
|
|
44
34
|
*/
|
|
45
35
|
type ChordTimelineOptions = {
|
|
46
|
-
/** Key context; inferred from the notes with {@link
|
|
36
|
+
/** Key context; inferred from the notes with {@link detectKeyFromNotes} when omitted. */
|
|
47
37
|
key?: KeyScale;
|
|
48
38
|
/**
|
|
49
39
|
* Time signature used for metric accents; defaults to 4/4.
|
|
@@ -63,6 +53,17 @@ type ChordTimelineOptions = {
|
|
|
63
53
|
* @defaultValue the end of the last note
|
|
64
54
|
*/
|
|
65
55
|
totalBeats?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Upper bound on the work this call may do — note counts, windows, and
|
|
58
|
+
* candidate counts are each checked against it before anything is allocated.
|
|
59
|
+
*
|
|
60
|
+
* Raise it to analyse a piece larger than the default allows; the default is
|
|
61
|
+
* {@link DEFAULT_GENERATION_BUDGET}, chosen so a runaway input fails fast
|
|
62
|
+
* rather than blocking the thread.
|
|
63
|
+
*
|
|
64
|
+
* @defaultValue {@link DEFAULT_GENERATION_BUDGET}
|
|
65
|
+
*/
|
|
66
|
+
budget?: number;
|
|
66
67
|
};
|
|
67
68
|
/**
|
|
68
69
|
* The result of {@link chordTimelineFromNotes}.
|
|
@@ -148,4 +149,4 @@ type CadenceHit = {
|
|
|
148
149
|
*/
|
|
149
150
|
declare function detectCadences(timeline: ChordTimeline, key: KeyScale): CadenceHit[];
|
|
150
151
|
|
|
151
|
-
export { type CadenceHit as C, type
|
|
152
|
+
export { type CadenceHit as C, type ChordTimeline as a, type ChordTimelineOptions as b, type ChordTimelineResult as c, chordTimelineFromChords as d, chordTimelineFromNotes as e, detectCadences as f };
|
|
@@ -16,9 +16,17 @@ type TimeSignature = {
|
|
|
16
16
|
/**
|
|
17
17
|
* Optional additive grouping of the bar's main pulses, as the felt-beat
|
|
18
18
|
* lengths in pulses — e.g. `[2, 2, 3]` for a 2+2+3 reading of 7/8, or
|
|
19
|
-
* `[3, 2]` for 5/8. The entries must be positive integers summing to
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* `[3, 2]` for 5/8. The entries must be positive integers summing to the
|
|
20
|
+
* numerator.
|
|
21
|
+
*
|
|
22
|
+
* A compound numerator accepts both readings. 9/8 groups its three dotted
|
|
23
|
+
* pulses as `[1, 1, 1]`, or reads additively as `[2, 2, 2, 3]` quavers; a
|
|
24
|
+
* grouping that sums to the numerator selects the additive reading, so
|
|
25
|
+
* aksak and other additive metres are expressible. {@link pulsesPerBar}
|
|
26
|
+
* and {@link isCompound} follow whichever reading the grouping selects.
|
|
27
|
+
*
|
|
28
|
+
* When present, the head pulse of each group (other than the downbeat) is
|
|
29
|
+
* treated as a secondary strong pulse by
|
|
22
30
|
* {@link metricWeight}/{@link isStrongBeat}; when absent, all main pulses
|
|
23
31
|
* are weighted equally as flat, evenly divided pulses.
|
|
24
32
|
*/
|
|
@@ -30,8 +38,13 @@ type TimeSignature = {
|
|
|
30
38
|
* @category Rhythm & Meter
|
|
31
39
|
*/
|
|
32
40
|
type BarPosition = {
|
|
41
|
+
/** 0-based bar index. {@link formatBarPosition} renders it 1-based. */
|
|
33
42
|
bar: number;
|
|
34
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Quarter-note offset from the start of the bar — not the felt beat. In 6/8
|
|
45
|
+
* the second felt beat is at `beat: 1.5`; {@link barPositionToPulse} converts
|
|
46
|
+
* to felt-beat numbering.
|
|
47
|
+
*/
|
|
35
48
|
beat: number;
|
|
36
49
|
};
|
|
37
50
|
/**
|
|
@@ -49,16 +62,34 @@ type BarPosition = {
|
|
|
49
62
|
*/
|
|
50
63
|
declare function parseTimeSignature(text: string): TimeSignature;
|
|
51
64
|
/**
|
|
52
|
-
* Render a time signature as `"n/d"
|
|
65
|
+
* Render a time signature as `"n/d"`, or as `"a+b+c/d"` when it carries an
|
|
66
|
+
* additive grouping and `grouping` is requested.
|
|
67
|
+
*
|
|
68
|
+
* The plain form drops the grouping, so a round trip through it reads 7/8 as
|
|
69
|
+
* flat rather than as 2+2+3; ask for the additive form to keep it.
|
|
53
70
|
*
|
|
71
|
+
* @param ts The time signature.
|
|
72
|
+
* @param opts Set `grouping: true` to render an additive grouping.
|
|
73
|
+
* @returns The formatted signature.
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* import { formatTimeSignature } from '@libraz/libcantus';
|
|
77
|
+
* const aksak = { numerator: 7, denominator: 8, grouping: [2, 2, 3] };
|
|
78
|
+
* formatTimeSignature(aksak); // '7/8'
|
|
79
|
+
* formatTimeSignature(aksak, { grouping: true }); // '2+2+3/8'
|
|
80
|
+
* ```
|
|
54
81
|
* @category Rhythm & Meter
|
|
55
82
|
*/
|
|
56
|
-
declare function formatTimeSignature(ts: TimeSignature
|
|
83
|
+
declare function formatTimeSignature(ts: TimeSignature, opts?: {
|
|
84
|
+
grouping?: boolean;
|
|
85
|
+
}): string;
|
|
57
86
|
/**
|
|
58
87
|
* Whether a meter is compound: its main pulses each divide into three, as in
|
|
59
88
|
* 6/8, 9/8, 12/8, or 6/4. Compound meters are those whose numerator is a
|
|
60
89
|
* multiple of three greater than three, independent of the denominator. Meters
|
|
61
|
-
* like 3/8 and 3/4 (simple triples, numerator 3) are not compound
|
|
90
|
+
* like 3/8 and 3/4 (simple triples, numerator 3) are not compound, and neither
|
|
91
|
+
* is a signature whose {@link TimeSignature.grouping} selects the additive
|
|
92
|
+
* reading (9/8 as 2+2+2+3).
|
|
62
93
|
*
|
|
63
94
|
* @param ts The time signature.
|
|
64
95
|
* @returns True for compound meters.
|
|
@@ -103,6 +134,57 @@ declare function pulsesPerBar(ts: TimeSignature): number;
|
|
|
103
134
|
* @category Rhythm & Meter
|
|
104
135
|
*/
|
|
105
136
|
declare function beatToBarPosition(beatInQuarters: number, ts: TimeSignature): BarPosition;
|
|
137
|
+
/**
|
|
138
|
+
* Length of one felt beat (main pulse) in quarter-note beats.
|
|
139
|
+
*
|
|
140
|
+
* A quarter note in simple meters, a dotted quarter in compound ones, and one
|
|
141
|
+
* denominator unit in an additive metre. Position displays, click tracks, and
|
|
142
|
+
* score export are all written against this length.
|
|
143
|
+
*
|
|
144
|
+
* @param ts The time signature.
|
|
145
|
+
* @returns The pulse length in quarter-note beats.
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* import { parseTimeSignature, pulseBeats } from '@libraz/libcantus';
|
|
149
|
+
* pulseBeats(parseTimeSignature('6/8')); // 1.5
|
|
150
|
+
* ```
|
|
151
|
+
* @category Rhythm & Meter
|
|
152
|
+
*/
|
|
153
|
+
declare function pulseBeats(ts: TimeSignature): number;
|
|
154
|
+
/**
|
|
155
|
+
* The felt-beat number of a bar position, 1-based.
|
|
156
|
+
*
|
|
157
|
+
* {@link BarPosition.beat} is a quarter-note offset, so in 6/8 the second felt
|
|
158
|
+
* beat reads as 1.5. This is the number a musician says and a position display
|
|
159
|
+
* shows.
|
|
160
|
+
*
|
|
161
|
+
* @param pos The bar position.
|
|
162
|
+
* @param ts The time signature.
|
|
163
|
+
* @returns The 1-based felt-beat number, fractional between pulses.
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* import { barPositionToPulse, parseTimeSignature } from '@libraz/libcantus';
|
|
167
|
+
* barPositionToPulse({ bar: 0, beat: 1.5 }, parseTimeSignature('6/8')); // 2
|
|
168
|
+
* ```
|
|
169
|
+
* @category Rhythm & Meter
|
|
170
|
+
*/
|
|
171
|
+
declare function barPositionToPulse(pos: BarPosition, ts: TimeSignature): number;
|
|
172
|
+
/**
|
|
173
|
+
* Render an absolute position as the `bar.beat` a DAW or a score shows:
|
|
174
|
+
* 1-based bar, 1-based felt beat.
|
|
175
|
+
*
|
|
176
|
+
* @param beatInQuarters Absolute position in quarter-note beats.
|
|
177
|
+
* @param ts The time signature.
|
|
178
|
+
* @param decimals Digits of the fractional beat to keep.
|
|
179
|
+
* @returns The formatted position, e.g. `'3.2'` for bar 3, felt beat 2.
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* import { formatBarPosition, parseTimeSignature } from '@libraz/libcantus';
|
|
183
|
+
* formatBarPosition(7.5, parseTimeSignature('6/8')); // '3.2'
|
|
184
|
+
* ```
|
|
185
|
+
* @category Rhythm & Meter
|
|
186
|
+
*/
|
|
187
|
+
declare function formatBarPosition(beatInQuarters: number, ts: TimeSignature, decimals?: number): string;
|
|
106
188
|
/**
|
|
107
189
|
* Convert a bar index and in-bar offset back to an absolute quarter-note
|
|
108
190
|
* position.
|
|
@@ -128,8 +210,8 @@ declare function barPositionToBeat(pos: BarPosition, ts: TimeSignature): number;
|
|
|
128
210
|
* @param beatInQuarters Absolute or in-bar quarter-note position.
|
|
129
211
|
* @param ts The time signature.
|
|
130
212
|
* @returns The metric weight (0–3).
|
|
131
|
-
* @throws If
|
|
132
|
-
* summing to
|
|
213
|
+
* @throws If the time signature is malformed, including a grouping that is not
|
|
214
|
+
* a positive-integer list summing to the pulse count or the numerator.
|
|
133
215
|
* @example
|
|
134
216
|
* ```ts
|
|
135
217
|
* import { parseTimeSignature, metricWeight } from '@libraz/libcantus';
|
|
@@ -161,4 +243,4 @@ declare function isStrongBeat(beatInQuarters: number, ts: TimeSignature): boolea
|
|
|
161
243
|
*/
|
|
162
244
|
declare function tuplet(totalBeats: number, count: number): number[];
|
|
163
245
|
|
|
164
|
-
export { type BarPosition as B, type TimeSignature as T,
|
|
246
|
+
export { type BarPosition as B, type TimeSignature as T, barPositionToPulse as a, barPositionToBeat as b, beatToBarPosition as c, beatsPerBar as d, formatTimeSignature as e, formatBarPosition as f, isStrongBeat as g, pulseBeats as h, isCompound as i, pulsesPerBar as j, metricWeight as m, parseTimeSignature as p, tuplet as t };
|
|
@@ -16,9 +16,17 @@ type TimeSignature = {
|
|
|
16
16
|
/**
|
|
17
17
|
* Optional additive grouping of the bar's main pulses, as the felt-beat
|
|
18
18
|
* lengths in pulses — e.g. `[2, 2, 3]` for a 2+2+3 reading of 7/8, or
|
|
19
|
-
* `[3, 2]` for 5/8. The entries must be positive integers summing to
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* `[3, 2]` for 5/8. The entries must be positive integers summing to the
|
|
20
|
+
* numerator.
|
|
21
|
+
*
|
|
22
|
+
* A compound numerator accepts both readings. 9/8 groups its three dotted
|
|
23
|
+
* pulses as `[1, 1, 1]`, or reads additively as `[2, 2, 2, 3]` quavers; a
|
|
24
|
+
* grouping that sums to the numerator selects the additive reading, so
|
|
25
|
+
* aksak and other additive metres are expressible. {@link pulsesPerBar}
|
|
26
|
+
* and {@link isCompound} follow whichever reading the grouping selects.
|
|
27
|
+
*
|
|
28
|
+
* When present, the head pulse of each group (other than the downbeat) is
|
|
29
|
+
* treated as a secondary strong pulse by
|
|
22
30
|
* {@link metricWeight}/{@link isStrongBeat}; when absent, all main pulses
|
|
23
31
|
* are weighted equally as flat, evenly divided pulses.
|
|
24
32
|
*/
|
|
@@ -30,8 +38,13 @@ type TimeSignature = {
|
|
|
30
38
|
* @category Rhythm & Meter
|
|
31
39
|
*/
|
|
32
40
|
type BarPosition = {
|
|
41
|
+
/** 0-based bar index. {@link formatBarPosition} renders it 1-based. */
|
|
33
42
|
bar: number;
|
|
34
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Quarter-note offset from the start of the bar — not the felt beat. In 6/8
|
|
45
|
+
* the second felt beat is at `beat: 1.5`; {@link barPositionToPulse} converts
|
|
46
|
+
* to felt-beat numbering.
|
|
47
|
+
*/
|
|
35
48
|
beat: number;
|
|
36
49
|
};
|
|
37
50
|
/**
|
|
@@ -49,16 +62,34 @@ type BarPosition = {
|
|
|
49
62
|
*/
|
|
50
63
|
declare function parseTimeSignature(text: string): TimeSignature;
|
|
51
64
|
/**
|
|
52
|
-
* Render a time signature as `"n/d"
|
|
65
|
+
* Render a time signature as `"n/d"`, or as `"a+b+c/d"` when it carries an
|
|
66
|
+
* additive grouping and `grouping` is requested.
|
|
67
|
+
*
|
|
68
|
+
* The plain form drops the grouping, so a round trip through it reads 7/8 as
|
|
69
|
+
* flat rather than as 2+2+3; ask for the additive form to keep it.
|
|
53
70
|
*
|
|
71
|
+
* @param ts The time signature.
|
|
72
|
+
* @param opts Set `grouping: true` to render an additive grouping.
|
|
73
|
+
* @returns The formatted signature.
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* import { formatTimeSignature } from '@libraz/libcantus';
|
|
77
|
+
* const aksak = { numerator: 7, denominator: 8, grouping: [2, 2, 3] };
|
|
78
|
+
* formatTimeSignature(aksak); // '7/8'
|
|
79
|
+
* formatTimeSignature(aksak, { grouping: true }); // '2+2+3/8'
|
|
80
|
+
* ```
|
|
54
81
|
* @category Rhythm & Meter
|
|
55
82
|
*/
|
|
56
|
-
declare function formatTimeSignature(ts: TimeSignature
|
|
83
|
+
declare function formatTimeSignature(ts: TimeSignature, opts?: {
|
|
84
|
+
grouping?: boolean;
|
|
85
|
+
}): string;
|
|
57
86
|
/**
|
|
58
87
|
* Whether a meter is compound: its main pulses each divide into three, as in
|
|
59
88
|
* 6/8, 9/8, 12/8, or 6/4. Compound meters are those whose numerator is a
|
|
60
89
|
* multiple of three greater than three, independent of the denominator. Meters
|
|
61
|
-
* like 3/8 and 3/4 (simple triples, numerator 3) are not compound
|
|
90
|
+
* like 3/8 and 3/4 (simple triples, numerator 3) are not compound, and neither
|
|
91
|
+
* is a signature whose {@link TimeSignature.grouping} selects the additive
|
|
92
|
+
* reading (9/8 as 2+2+2+3).
|
|
62
93
|
*
|
|
63
94
|
* @param ts The time signature.
|
|
64
95
|
* @returns True for compound meters.
|
|
@@ -103,6 +134,57 @@ declare function pulsesPerBar(ts: TimeSignature): number;
|
|
|
103
134
|
* @category Rhythm & Meter
|
|
104
135
|
*/
|
|
105
136
|
declare function beatToBarPosition(beatInQuarters: number, ts: TimeSignature): BarPosition;
|
|
137
|
+
/**
|
|
138
|
+
* Length of one felt beat (main pulse) in quarter-note beats.
|
|
139
|
+
*
|
|
140
|
+
* A quarter note in simple meters, a dotted quarter in compound ones, and one
|
|
141
|
+
* denominator unit in an additive metre. Position displays, click tracks, and
|
|
142
|
+
* score export are all written against this length.
|
|
143
|
+
*
|
|
144
|
+
* @param ts The time signature.
|
|
145
|
+
* @returns The pulse length in quarter-note beats.
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* import { parseTimeSignature, pulseBeats } from '@libraz/libcantus';
|
|
149
|
+
* pulseBeats(parseTimeSignature('6/8')); // 1.5
|
|
150
|
+
* ```
|
|
151
|
+
* @category Rhythm & Meter
|
|
152
|
+
*/
|
|
153
|
+
declare function pulseBeats(ts: TimeSignature): number;
|
|
154
|
+
/**
|
|
155
|
+
* The felt-beat number of a bar position, 1-based.
|
|
156
|
+
*
|
|
157
|
+
* {@link BarPosition.beat} is a quarter-note offset, so in 6/8 the second felt
|
|
158
|
+
* beat reads as 1.5. This is the number a musician says and a position display
|
|
159
|
+
* shows.
|
|
160
|
+
*
|
|
161
|
+
* @param pos The bar position.
|
|
162
|
+
* @param ts The time signature.
|
|
163
|
+
* @returns The 1-based felt-beat number, fractional between pulses.
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* import { barPositionToPulse, parseTimeSignature } from '@libraz/libcantus';
|
|
167
|
+
* barPositionToPulse({ bar: 0, beat: 1.5 }, parseTimeSignature('6/8')); // 2
|
|
168
|
+
* ```
|
|
169
|
+
* @category Rhythm & Meter
|
|
170
|
+
*/
|
|
171
|
+
declare function barPositionToPulse(pos: BarPosition, ts: TimeSignature): number;
|
|
172
|
+
/**
|
|
173
|
+
* Render an absolute position as the `bar.beat` a DAW or a score shows:
|
|
174
|
+
* 1-based bar, 1-based felt beat.
|
|
175
|
+
*
|
|
176
|
+
* @param beatInQuarters Absolute position in quarter-note beats.
|
|
177
|
+
* @param ts The time signature.
|
|
178
|
+
* @param decimals Digits of the fractional beat to keep.
|
|
179
|
+
* @returns The formatted position, e.g. `'3.2'` for bar 3, felt beat 2.
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* import { formatBarPosition, parseTimeSignature } from '@libraz/libcantus';
|
|
183
|
+
* formatBarPosition(7.5, parseTimeSignature('6/8')); // '3.2'
|
|
184
|
+
* ```
|
|
185
|
+
* @category Rhythm & Meter
|
|
186
|
+
*/
|
|
187
|
+
declare function formatBarPosition(beatInQuarters: number, ts: TimeSignature, decimals?: number): string;
|
|
106
188
|
/**
|
|
107
189
|
* Convert a bar index and in-bar offset back to an absolute quarter-note
|
|
108
190
|
* position.
|
|
@@ -128,8 +210,8 @@ declare function barPositionToBeat(pos: BarPosition, ts: TimeSignature): number;
|
|
|
128
210
|
* @param beatInQuarters Absolute or in-bar quarter-note position.
|
|
129
211
|
* @param ts The time signature.
|
|
130
212
|
* @returns The metric weight (0–3).
|
|
131
|
-
* @throws If
|
|
132
|
-
* summing to
|
|
213
|
+
* @throws If the time signature is malformed, including a grouping that is not
|
|
214
|
+
* a positive-integer list summing to the pulse count or the numerator.
|
|
133
215
|
* @example
|
|
134
216
|
* ```ts
|
|
135
217
|
* import { parseTimeSignature, metricWeight } from '@libraz/libcantus';
|
|
@@ -161,4 +243,4 @@ declare function isStrongBeat(beatInQuarters: number, ts: TimeSignature): boolea
|
|
|
161
243
|
*/
|
|
162
244
|
declare function tuplet(totalBeats: number, count: number): number[];
|
|
163
245
|
|
|
164
|
-
export { type BarPosition as B, type TimeSignature as T,
|
|
246
|
+
export { type BarPosition as B, type TimeSignature as T, barPositionToPulse as a, barPositionToBeat as b, beatToBarPosition as c, beatsPerBar as d, formatTimeSignature as e, formatBarPosition as f, isStrongBeat as g, pulseBeats as h, isCompound as i, pulsesPerBar as j, metricWeight as m, parseTimeSignature as p, tuplet as t };
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { K as KeyScale, N as NoteEvent } from './types-BN6_Q9Kl.cjs';
|
|
2
|
+
import { a as ChordQuality, C as Chord } from './index-oTQbYYIs.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Recognition: infer a chord name from a set of pitches, or a key from a set of
|
|
6
|
+
* pitch classes. This is the inverse direction of the chord/scale builders,
|
|
7
|
+
* which only go name -> notes.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A candidate chord interpretation of a pitch set.
|
|
12
|
+
*
|
|
13
|
+
* @category Recognition
|
|
14
|
+
*/
|
|
15
|
+
type ChordMatch = {
|
|
16
|
+
rootPc: number;
|
|
17
|
+
quality: ChordQuality;
|
|
18
|
+
/** Chord tones absent from the input (an incomplete voicing). */
|
|
19
|
+
missingPcs: number[];
|
|
20
|
+
/** Input pitch classes not belonging to the chord. */
|
|
21
|
+
extraPcs: number[];
|
|
22
|
+
/** True when the input pitch-class set equals the chord exactly. */
|
|
23
|
+
exact: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Inversion implied by a known bass: 0 for root position, 1..n for an
|
|
26
|
+
* inversion. Null when no inversion can be named — either the input is an
|
|
27
|
+
* unordered pitch-class set with no bass, or the bass is not a chord tone (a
|
|
28
|
+
* pedal or passing bass), in which case `bassPc` still reports it.
|
|
29
|
+
*/
|
|
30
|
+
inversion: number | null;
|
|
31
|
+
/** Bass pitch class when the lowest note is not the root. */
|
|
32
|
+
bassPc?: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Input interpretation for {@link detectChord} and {@link detectChordBest}.
|
|
36
|
+
*
|
|
37
|
+
* @category Recognition
|
|
38
|
+
*/
|
|
39
|
+
type DetectChordOptions = {
|
|
40
|
+
/**
|
|
41
|
+
* `midi` uses the numerically lowest pitch as bass; `pitchClass` treats the
|
|
42
|
+
* input as unordered. `auto` (default) selects pitch-class mode only when all
|
|
43
|
+
* values lie in 0..11.
|
|
44
|
+
*/
|
|
45
|
+
input?: 'auto' | 'midi' | 'pitchClass';
|
|
46
|
+
/** Explicit bass pitch class, including for an unordered pitch-class set. */
|
|
47
|
+
bassPc?: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* A candidate key interpretation of a pitch-class set.
|
|
51
|
+
*
|
|
52
|
+
* @category Recognition
|
|
53
|
+
*/
|
|
54
|
+
type KeyMatch = {
|
|
55
|
+
/** The scale that scored best for this tonic and mode, `variant` included. */
|
|
56
|
+
key: KeyScale;
|
|
57
|
+
mode: 'major' | 'minor';
|
|
58
|
+
/** Which scale form `key` uses; minor keys pick the best-scoring of the three. */
|
|
59
|
+
variant: KeyVariant;
|
|
60
|
+
/**
|
|
61
|
+
* Fraction of the distinct input pitch classes that belong to `key`, in
|
|
62
|
+
* [0, 1]. Measured against the returned scale, so it always agrees with
|
|
63
|
+
* `isScaleTone(pc, match.key)`. This is a coverage figure, not the ranking:
|
|
64
|
+
* see `score`.
|
|
65
|
+
*/
|
|
66
|
+
fit: number;
|
|
67
|
+
/**
|
|
68
|
+
* The value the results are ranked by, in [0, 1.5]. Unlike `fit` it counts
|
|
69
|
+
* every occurrence rather than every distinct pitch class, so a repeated tone
|
|
70
|
+
* weighs more, and it adds half a count per sounding of the tonic itself to
|
|
71
|
+
* break ties between keys that contain the same notes.
|
|
72
|
+
*/
|
|
73
|
+
score: number;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Which form of a scale a {@link KeyMatch} settled on.
|
|
77
|
+
*
|
|
78
|
+
* @category Recognition
|
|
79
|
+
*/
|
|
80
|
+
type KeyVariant = 'major' | 'natural' | 'harmonic' | 'melodic';
|
|
81
|
+
/**
|
|
82
|
+
* Input weighting for {@link detectKey}.
|
|
83
|
+
*
|
|
84
|
+
* @category Recognition
|
|
85
|
+
*/
|
|
86
|
+
type DetectKeyOptions = {
|
|
87
|
+
/**
|
|
88
|
+
* How much each pitch counts toward the histogram, one entry per pitch.
|
|
89
|
+
* Defaults to one per pitch, which weighs a thirty-second-note ornament as
|
|
90
|
+
* heavily as the whole note under it. {@link detectKeyFromNotes} supplies
|
|
91
|
+
* duration times velocity, matching how chord inference weighs its own
|
|
92
|
+
* histogram.
|
|
93
|
+
*/
|
|
94
|
+
weights?: readonly number[];
|
|
95
|
+
/**
|
|
96
|
+
* Upper bound on the input pitches processed by this detection call.
|
|
97
|
+
*
|
|
98
|
+
* @defaultValue {@link DEFAULT_GENERATION_BUDGET}
|
|
99
|
+
*/
|
|
100
|
+
budget?: number;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Identify chords matching a set of pitches.
|
|
104
|
+
*
|
|
105
|
+
* Every input pitch class is tried as a root against every known chord quality.
|
|
106
|
+
* A match is reported when all of the chord's tones are present in the input, or
|
|
107
|
+
* when the only absent tone is the perfect fifth (a common omission in shell
|
|
108
|
+
* voicings); matches are ranked best-first by fewest extra notes, then fewest
|
|
109
|
+
* missing notes, then most specific (largest) chord. An exact match (no extras,
|
|
110
|
+
* no missing) is flagged and ranked first.
|
|
111
|
+
*
|
|
112
|
+
* @param pitches MIDI pitches or bare pitch classes (octave-agnostic).
|
|
113
|
+
* @returns Ranked chord interpretations (may be empty).
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* import { detectChord } from '@libraz/libcantus';
|
|
117
|
+
* const matches = detectChord([60, 64, 67]); // C E G
|
|
118
|
+
* matches[0]; // { rootPc: 0, quality: 'maj', exact: true, ... }
|
|
119
|
+
* ```
|
|
120
|
+
* @category Recognition
|
|
121
|
+
*/
|
|
122
|
+
declare function detectChord(pitches: readonly number[], opts?: DetectChordOptions): ChordMatch[];
|
|
123
|
+
/**
|
|
124
|
+
* The single best chord interpretation of a pitch set, or null if none.
|
|
125
|
+
*
|
|
126
|
+
* @param pitches MIDI pitches or bare pitch classes.
|
|
127
|
+
* @returns The top-ranked chord, or null when nothing matches.
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* import { detectChordBest } from '@libraz/libcantus';
|
|
131
|
+
* detectChordBest([60, 64, 67]); // C major triad: { rootPc: 0, quality: 'maj', ... }
|
|
132
|
+
* ```
|
|
133
|
+
* @category Recognition
|
|
134
|
+
*/
|
|
135
|
+
declare function detectChordBest(pitches: readonly number[], opts?: DetectChordOptions): Chord | null;
|
|
136
|
+
/**
|
|
137
|
+
* Rank major and minor keys by how well they contain a set of pitch classes.
|
|
138
|
+
*
|
|
139
|
+
* Ranking is by `score`, which counts repetitions and adds a tonic weight so
|
|
140
|
+
* that, among equally-fitting keys, the one whose root is actually sounded is
|
|
141
|
+
* preferred. Minor candidates are scored against the natural, harmonic, and
|
|
142
|
+
* melodic minor variants and keep the best of the three, so a minor cadence
|
|
143
|
+
* containing the leading tone still resolves to its own tonic; the winning
|
|
144
|
+
* variant is what `key` and `variant` report, so `fit` describes the scale the
|
|
145
|
+
* caller receives. Returns all 24 keys ranked best-first, or an empty array for
|
|
146
|
+
* an empty input (mirroring {@link detectChord}).
|
|
147
|
+
*
|
|
148
|
+
* @param pitches MIDI pitches or bare pitch classes.
|
|
149
|
+
* @returns Ranked key interpretations (empty for an empty input).
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* import { detectKey } from '@libraz/libcantus';
|
|
153
|
+
* const keys = detectKey([60, 62, 64, 65, 67, 69, 71]); // C major scale
|
|
154
|
+
* keys[0].mode; // 'major', with keys[0].key.rootPc === 0
|
|
155
|
+
* ```
|
|
156
|
+
* @category Recognition
|
|
157
|
+
*/
|
|
158
|
+
declare function detectKey(pitches: readonly number[], opts?: DetectKeyOptions): KeyMatch[];
|
|
159
|
+
/**
|
|
160
|
+
* Rank keys by how well they contain a set of note events, weighting each note
|
|
161
|
+
* by how much of the music it actually occupies.
|
|
162
|
+
*
|
|
163
|
+
* {@link detectKey} counts every pitch once, which lets a run of fast ornamental
|
|
164
|
+
* notes outvote the sustained harmony that establishes the key. This weighs
|
|
165
|
+
* each note by duration times velocity, the same measure chord inference uses,
|
|
166
|
+
* so the two agree on what the music emphasises. Notes that never sound (zero
|
|
167
|
+
* or negative duration) are ignored.
|
|
168
|
+
*
|
|
169
|
+
* @param notes The note events to weigh.
|
|
170
|
+
* @param opts Budget for processing imported note events.
|
|
171
|
+
* @returns Ranked key interpretations (empty when nothing sounds).
|
|
172
|
+
* @example
|
|
173
|
+
* ```ts
|
|
174
|
+
* import { detectKeyFromNotes } from '@libraz/libcantus';
|
|
175
|
+
* detectKeyFromNotes([{ pitch: 60, startBeat: 0, durationBeat: 4 }])[0]?.key.rootPc; // 0
|
|
176
|
+
* ```
|
|
177
|
+
* @category Recognition
|
|
178
|
+
*/
|
|
179
|
+
declare function detectKeyFromNotes(notes: readonly NoteEvent[], opts?: Omit<DetectKeyOptions, 'weights'>): KeyMatch[];
|
|
180
|
+
/**
|
|
181
|
+
* The single best key interpretation of a pitch set.
|
|
182
|
+
*
|
|
183
|
+
* The counterpart of {@link detectChordBest}: the ranked list is the general
|
|
184
|
+
* answer, but a caller that just wants "what key is this" should not have to
|
|
185
|
+
* index into it and assert the result is there.
|
|
186
|
+
*
|
|
187
|
+
* @param pitches MIDI pitches or bare pitch classes.
|
|
188
|
+
* @param opts How to weigh the input; see {@link DetectKeyOptions}.
|
|
189
|
+
* @returns The top-ranked key, or null when nothing sounds.
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* import { detectKeyBest } from '@libraz/libcantus';
|
|
193
|
+
* detectKeyBest([0, 2, 4, 5, 7, 9, 11])?.mode; // 'major'
|
|
194
|
+
* ```
|
|
195
|
+
* @category Recognition
|
|
196
|
+
*/
|
|
197
|
+
declare function detectKeyBest(pitches: readonly number[], opts?: DetectKeyOptions): KeyMatch | null;
|
|
198
|
+
|
|
199
|
+
export { type ChordMatch as C, type DetectChordOptions as D, type KeyMatch as K, type DetectKeyOptions as a, type KeyVariant as b, detectChordBest as c, detectChord as d, detectKey as e, detectKeyBest as f, detectKeyFromNotes as g };
|