@libraz/libcantus 0.9.5 → 1.0.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 +61 -270
- package/README_ja.md +61 -214
- package/dist/analyze/index.cjs +54 -7
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +200 -353
- package/dist/analyze/index.d.ts +200 -353
- package/dist/analyze/index.js +56 -9
- package/dist/chunk-3JXCW6DX.cjs +3220 -0
- package/dist/chunk-3JXCW6DX.cjs.map +1 -0
- package/dist/chunk-4A2RMUCC.js +7647 -0
- package/dist/chunk-4A2RMUCC.js.map +1 -0
- package/dist/chunk-6XPTBE7Y.cjs +49 -0
- package/dist/chunk-6XPTBE7Y.cjs.map +1 -0
- package/dist/chunk-AFM2ULJH.cjs +5121 -0
- package/dist/chunk-AFM2ULJH.cjs.map +1 -0
- package/dist/chunk-E3F4AHAH.cjs +690 -0
- package/dist/chunk-E3F4AHAH.cjs.map +1 -0
- package/dist/{chunk-2PTFGVD7.js → chunk-ELCTZUJJ.js} +250 -132
- package/dist/chunk-ELCTZUJJ.js.map +1 -0
- package/dist/chunk-FVSI36UV.js +690 -0
- package/dist/chunk-FVSI36UV.js.map +1 -0
- package/dist/chunk-GEDTJHAC.cjs +1 -0
- package/dist/chunk-GEDTJHAC.cjs.map +1 -0
- package/dist/chunk-GOZG57ER.js +3220 -0
- package/dist/chunk-GOZG57ER.js.map +1 -0
- package/dist/chunk-H3VORETI.js +2243 -0
- package/dist/chunk-H3VORETI.js.map +1 -0
- package/dist/chunk-H42UHPYW.js +1577 -0
- package/dist/chunk-H42UHPYW.js.map +1 -0
- package/dist/chunk-HFPS7JFD.js +1 -0
- package/dist/chunk-INHVXP6Z.js +3053 -0
- package/dist/chunk-INHVXP6Z.js.map +1 -0
- package/dist/chunk-K4ZJUGF4.cjs +379 -0
- package/dist/chunk-K4ZJUGF4.cjs.map +1 -0
- package/dist/chunk-KNJEKLKV.js +49 -0
- package/dist/chunk-KNJEKLKV.js.map +1 -0
- package/dist/chunk-M4CWTJWJ.cjs +7647 -0
- package/dist/chunk-M4CWTJWJ.cjs.map +1 -0
- package/dist/chunk-MXO72PLY.cjs +211 -0
- package/dist/chunk-MXO72PLY.cjs.map +1 -0
- package/dist/chunk-NLEU4QSE.cjs +360 -0
- package/dist/chunk-NLEU4QSE.cjs.map +1 -0
- package/dist/chunk-OE6WK2Y2.cjs +1577 -0
- package/dist/chunk-OE6WK2Y2.cjs.map +1 -0
- package/dist/chunk-Q2WGKJNN.cjs +1064 -0
- package/dist/chunk-Q2WGKJNN.cjs.map +1 -0
- package/dist/chunk-QYQQ5J6E.js +1 -0
- package/dist/chunk-QYQQ5J6E.js.map +1 -0
- package/dist/chunk-RHIJ3S4I.cjs +1 -0
- package/dist/chunk-RHIJ3S4I.cjs.map +1 -0
- package/dist/chunk-TTCLJX6D.js +211 -0
- package/dist/chunk-TTCLJX6D.js.map +1 -0
- package/dist/chunk-UADYAYAT.cjs +3053 -0
- package/dist/chunk-UADYAYAT.cjs.map +1 -0
- package/dist/chunk-VOHZB45S.js +5121 -0
- package/dist/chunk-VOHZB45S.js.map +1 -0
- package/dist/chunk-VTI6FOLB.js +1064 -0
- package/dist/chunk-VTI6FOLB.js.map +1 -0
- package/dist/chunk-WWURE4XT.cjs +2243 -0
- package/dist/chunk-WWURE4XT.cjs.map +1 -0
- package/dist/chunk-YH3BIKHH.js +360 -0
- package/dist/chunk-YH3BIKHH.js.map +1 -0
- package/dist/core/index.cjs +93 -6
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +87 -346
- package/dist/core/index.d.ts +87 -346
- package/dist/core/index.js +94 -7
- package/dist/generate/index.cjs +89 -10
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +436 -1094
- package/dist/generate/index.d.ts +436 -1094
- package/dist/generate/index.js +94 -15
- package/dist/index-9wcMhG73.d.ts +1095 -0
- package/dist/{index-Cfx8xgH0.d.ts → index-B4o55NDr.d.cts} +13 -9
- package/dist/index-B9MNZboQ.d.cts +770 -0
- package/dist/index-B9MNZboQ.d.ts +770 -0
- package/dist/index-BGFW-8P2.d.cts +2307 -0
- package/dist/index-BO6xE9YU.d.cts +1804 -0
- package/dist/index-BkGmlyI3.d.cts +470 -0
- package/dist/index-CCNJRG-P.d.cts +1095 -0
- package/dist/index-CGpRv5sl.d.cts +643 -0
- package/dist/index-C_8o--VE.d.cts +1242 -0
- package/dist/index-CgHqxdps.d.ts +2307 -0
- package/dist/index-Chbst3Jx.d.ts +1343 -0
- package/dist/index-Cj49F892.d.ts +470 -0
- package/dist/{index-x2vcsduE.d.cts → index-CunYKLiu.d.ts} +13 -9
- package/dist/index-D57QRbVn.d.ts +1804 -0
- package/dist/index-DInQqT8Q.d.cts +66 -0
- package/dist/index-DInQqT8Q.d.ts +66 -0
- package/dist/index-Dzr13q3d.d.cts +1343 -0
- package/dist/index-G1uwGGWQ.d.ts +643 -0
- package/dist/index-szBv3496.d.ts +1242 -0
- package/dist/index.cjs +348 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -15
- package/dist/index.d.ts +17 -15
- package/dist/index.js +397 -64
- package/dist/masks-DYbE485J.d.cts +445 -0
- package/dist/masks-DYbE485J.d.ts +445 -0
- package/dist/model/index.cjs +39 -7
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +4659 -249
- package/dist/model/index.d.ts +4659 -249
- package/dist/model/index.js +40 -8
- package/dist/positional-Cptlj-xs.d.ts +287 -0
- package/dist/positional-DvH_sd8u.d.cts +287 -0
- package/dist/theory/index.cjs +101 -7
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +511 -171
- package/dist/theory/index.d.ts +511 -171
- package/dist/theory/index.js +118 -24
- package/package.json +6 -4
- package/dist/chunk-2A2QMA74.cjs +0 -261
- package/dist/chunk-2A2QMA74.cjs.map +0 -1
- package/dist/chunk-2PTFGVD7.js.map +0 -1
- package/dist/chunk-357ZDPVU.cjs +0 -162
- package/dist/chunk-357ZDPVU.cjs.map +0 -1
- package/dist/chunk-3KX76RLG.js +0 -1548
- package/dist/chunk-3KX76RLG.js.map +0 -1
- package/dist/chunk-4VZ5MZAM.cjs +0 -889
- package/dist/chunk-4VZ5MZAM.cjs.map +0 -1
- package/dist/chunk-7EONYVI5.js +0 -1204
- package/dist/chunk-7EONYVI5.js.map +0 -1
- package/dist/chunk-7JEP3MFY.js +0 -162
- package/dist/chunk-7JEP3MFY.js.map +0 -1
- package/dist/chunk-AID75RN3.js +0 -3176
- package/dist/chunk-AID75RN3.js.map +0 -1
- package/dist/chunk-BSLTLGM3.cjs +0 -497
- package/dist/chunk-BSLTLGM3.cjs.map +0 -1
- package/dist/chunk-CU6VG2YM.cjs +0 -109
- package/dist/chunk-CU6VG2YM.cjs.map +0 -1
- package/dist/chunk-DZMHIGI4.js +0 -337
- package/dist/chunk-DZMHIGI4.js.map +0 -1
- package/dist/chunk-EDOTEABK.js +0 -109
- package/dist/chunk-EDOTEABK.js.map +0 -1
- package/dist/chunk-HN2OEUN2.js +0 -33
- package/dist/chunk-HN2OEUN2.js.map +0 -1
- package/dist/chunk-KBTTEX7Q.js +0 -497
- package/dist/chunk-KBTTEX7Q.js.map +0 -1
- package/dist/chunk-KQN2ZYND.cjs +0 -724
- package/dist/chunk-KQN2ZYND.cjs.map +0 -1
- package/dist/chunk-MPTVJIVG.cjs +0 -3176
- package/dist/chunk-MPTVJIVG.cjs.map +0 -1
- package/dist/chunk-MTMZTMWM.cjs +0 -53
- package/dist/chunk-MTMZTMWM.cjs.map +0 -1
- package/dist/chunk-N6IHQUOX.js +0 -1
- package/dist/chunk-NNB67XA2.js +0 -724
- package/dist/chunk-NNB67XA2.js.map +0 -1
- package/dist/chunk-OL3IHHSJ.cjs +0 -1204
- package/dist/chunk-OL3IHHSJ.cjs.map +0 -1
- package/dist/chunk-PI3UXRWK.cjs +0 -528
- package/dist/chunk-PI3UXRWK.cjs.map +0 -1
- package/dist/chunk-R2VVFAIN.js +0 -528
- package/dist/chunk-R2VVFAIN.js.map +0 -1
- package/dist/chunk-T64C7ZD7.cjs +0 -1
- package/dist/chunk-T64C7ZD7.cjs.map +0 -1
- package/dist/chunk-WFDXOLUB.cjs +0 -337
- package/dist/chunk-WFDXOLUB.cjs.map +0 -1
- package/dist/chunk-WTAN4ACG.cjs +0 -1548
- package/dist/chunk-WTAN4ACG.cjs.map +0 -1
- package/dist/chunk-YFJXS3AU.cjs +0 -33
- package/dist/chunk-YFJXS3AU.cjs.map +0 -1
- package/dist/chunk-YUE6TJ4M.js +0 -889
- package/dist/chunk-YUE6TJ4M.js.map +0 -1
- package/dist/chunk-ZGLJM4A4.js +0 -53
- package/dist/chunk-ZGLJM4A4.js.map +0 -1
- package/dist/function-CxixTB02.d.cts +0 -299
- package/dist/function-DTCt675z.d.ts +0 -299
- package/dist/index-B2Ulxxpo.d.cts +0 -144
- package/dist/index-BkYJ0xMq.d.cts +0 -152
- package/dist/index-BuaB-ypt.d.ts +0 -144
- package/dist/index-CAN7v-kw.d.ts +0 -199
- package/dist/index-COw1Ky9g.d.ts +0 -242
- package/dist/index-DRtIhlJj.d.ts +0 -152
- package/dist/index-DXd9JikN.d.cts +0 -246
- package/dist/index-DXd9JikN.d.ts +0 -246
- package/dist/index-alrRninU.d.cts +0 -199
- package/dist/index-oTQbYYIs.d.cts +0 -242
- package/dist/index-tR9jTn26.d.cts +0 -275
- package/dist/index-tR9jTn26.d.ts +0 -275
- package/dist/styled-Bl0ZK28h.d.ts +0 -543
- package/dist/styled-Crv6SA4S.d.cts +0 -543
- package/dist/types-BN6_Q9Kl.d.cts +0 -39
- package/dist/types-BN6_Q9Kl.d.ts +0 -39
- /package/dist/{chunk-N6IHQUOX.js.map → chunk-HFPS7JFD.js.map} +0 -0
package/README_ja.md
CHANGED
|
@@ -1,268 +1,115 @@
|
|
|
1
1
|
# @libraz/libcantus
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
扱うのは理論の層だけで、I/O やオーディオには踏み込みません。MIDI ファイルの読み書き、オーディオ解析、再生のいずれも持たないので、パースは呼び出し側で行い、ノートイベントとして渡してください。実行時依存はありません。その層も必要であれば、[libsonare](https://github.com/libraz/libsonare) が音声解析・マスタリング・音源合成・SMF の読み書きを担当していて、npm パッケージなので本ライブラリと並べて置けます。両者はコードを共有しておらず、どちらも単独で使えます。
|
|
3
|
+
MIDI ノートイベントを扱う、TypeScript 製の音楽理論ライブラリです。コードの組み立てと綴り、和声とキーの解析、曲の形式の読み取り、パート生成を同じデータモデルで行えます。実行時依存はありません。
|
|
6
4
|
|
|
7
5
|
[](https://github.com/libraz/libcantus/actions)
|
|
8
6
|
[](https://www.npmjs.com/package/@libraz/libcantus)
|
|
9
7
|
[](https://codecov.io/gh/libraz/libcantus)
|
|
10
8
|
[](https://github.com/libraz/libcantus/blob/main/LICENSE)
|
|
11
9
|
[](https://www.typescriptlang.org/)
|
|
12
|
-
[](https://nodejs.org/)
|
|
13
11
|
[](https://libraz.github.io/libcantus/)
|
|
14
12
|
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
- **音名を扱う** — `C4` のパース、移調、MIDI との相互変換、異名同音を区別した音程の綴り(`F#` と `Gb`)。
|
|
18
|
-
- **コードと進行を組み立てる** — スケール度数、ローマ数字(`V7/V`)、リードシート記号(`Cmaj7`, `F#m7b5`, `C/G`)のいずれからでも。
|
|
19
|
-
- **和声を解析する** — ローマ数字解析、和声機能、終止形の検出、借用和音とモーダルインターチェンジ。
|
|
20
|
-
- **コードとキーを判定する** — ノートを入れるとコードやキーが返る、組み立ての逆方向の処理。
|
|
21
|
-
- **リハーモナイズする** — 裏コード、クロマチックメディアント、ネガティブハーモニー、モーダルインターチェンジのパレット。
|
|
22
|
-
- **コードをボイシングする** — 声部の動きを最小化した 4 声(SATB)に加えて、drop-2/3、シェル、ルートレスのコンピングスタイル。
|
|
23
|
-
- **パートを生成する** — ベースライン、対旋律、ドラム、リズム、モチーフ、進行全体。シードを与えれば結果は決定的になります。
|
|
24
|
-
- **アレンジ全体を解析する** — マルチトラックのノートイベントを渡すと和声を復元し、曲全体の解析(ノート単位の衝突検出つき)を返します。そこから足りないパートを生成できます。
|
|
25
|
-
- **音高を音響として扱う** — 周波数、セント、EDO、純正律。
|
|
26
|
-
|
|
27
|
-
理論の本体は tree-shaking の効く純粋関数として実装してあります。その上に、音楽理論の記述に近い形で書ける不変(immutable)なクラス API(`Note`, `Interval`, `Chord`, `Key`, `Progression`)が乗ります。どちらの形で提供されるかは一つの規則で決まります。音符・コード・キー・進行といった値は両方の形を持ち、相互に行き来できます。一方でコレクションやタイムラインを対象とする操作(パート生成、アレンジ全体の解析、キーのランキング)はノートイベントの配列を受け取るため、関数としてのみ公開されます。
|
|
28
|
-
|
|
29
|
-
## インストール
|
|
30
|
-
|
|
31
|
-
```sh
|
|
32
|
-
yarn add @libraz/libcantus
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## サブパスインポート
|
|
36
|
-
|
|
37
|
-
パッケージのルートからはすべてがエクスポートされます。特定の層だけを取り込みたい場合は、その層のサブパスからインポートしてください。
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
import { Chord, Key, Note } from '@libraz/libcantus/model'; // クラス API
|
|
41
|
-
import { majorKey, makeChord } from '@libraz/libcantus/theory'; // スケール、コード
|
|
42
|
-
import { generateDrums, generateProgression } from '@libraz/libcantus/generate';
|
|
43
|
-
import { analyzeArrangement, detectKey } from '@libraz/libcantus/analyze';
|
|
44
|
-
import { parseNote, edo } from '@libraz/libcantus/core'; // 音高、拍子、音律
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
層は `core`, `theory`, `analyze`, `generate`, `model` の 5 つです。
|
|
48
|
-
|
|
49
|
-
## クイックスタート
|
|
50
|
-
|
|
51
|
-
クラス API は不変のままメソッドチェーンでき、キーの文脈を持ち回るので、解析のたびにキーを渡し直す必要はありません。
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
import { Chord, Key, Note } from '@libraz/libcantus';
|
|
55
|
-
|
|
56
|
-
const c = Key.major('C');
|
|
57
|
-
|
|
58
|
-
c.chord(4, 'dom7').pitchClasses(); // [2, 5, 7, 11] (G7)
|
|
59
|
-
c.roman('V7/V').voice(); // [ ...SATB の MIDI ノート ] (セカンダリードミナントをボイシング)
|
|
60
|
-
Note.of('C4').transpose(7).name; // 'G4'
|
|
61
|
-
|
|
62
|
-
// ii–V–I を組み立てて、そのまま 1 行で解析する:
|
|
63
|
-
c.chord(1, 'min').progressionTo(c.chord(4, 'dom7'), c.chord(0, 'maj')).analyze();
|
|
64
|
-
// { chords: [...機能和声の解析...], cadence: 'authentic' }
|
|
65
|
-
|
|
66
|
-
Chord.detect([60, 64, 67])[0].quality; // 'maj'
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
どのクラスもプレーンなオブジェクト(`Chord.data`, `Note.data`)を包んでいるだけで、処理は純粋関数に委譲されます。そのため二つのスタイルは自由に混ぜられます。同じ処理を関数 API で書くとこうなります。
|
|
70
|
-
|
|
71
|
-
```ts
|
|
72
|
-
import { chordFromDegree, chordPitchClasses, classifyInterval, ConsonanceClass, majorKey } from '@libraz/libcantus';
|
|
73
|
-
|
|
74
|
-
const cMajor = majorKey(0);
|
|
75
|
-
|
|
76
|
-
classifyInterval(7); // ConsonanceClass.PerfectConsonance
|
|
77
|
-
chordPitchClasses(chordFromDegree(4, 'dom7', cMajor)); // [2, 5, 7, 11] (G7)
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## 音名を扱う
|
|
81
|
-
|
|
82
|
-
音名のパースと整形、MIDI への変換、そしてピッチクラスの層では区別できない異名同音を正しく綴り分ける音程計算ができます。
|
|
83
|
-
|
|
84
|
-
```ts
|
|
85
|
-
import { Interval, Note } from '@libraz/libcantus';
|
|
86
|
-
|
|
87
|
-
Note.of('C4').transpose(7).name; // 'G4'
|
|
88
|
-
Note.of('C4').midi; // 60
|
|
89
|
-
Interval.between(Note.of('C4'), Note.of('F#4')).name; // 'A4' (増四度)
|
|
90
|
-
Interval.between(Note.of('C4'), Note.of('Gb4')).name; // 'd5' (減五度)
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## キーとスケール
|
|
94
|
-
|
|
95
|
-
`KeyScale` はルートのピッチクラスと 12 ビットの `modeMask12` の組です(ビット `n` が立っていれば、ピッチクラス `(rootPc + n) % 12` がスケールに含まれます)。`majorKey`, `minorKey`, `scaleByName` が教会旋法・ペンタトニック・ブルース・ホールトーン・オクタトニックをカバーし、`MAJOR_MASK` と `NATURAL_MINOR_MASK` を使えば独自のキーも定義できます。
|
|
96
|
-
|
|
97
|
-
`nearestScaleTone` は与えた音高を最も近いスケール構成音の MIDI ノートにスナップします(同距離なら低い方を優先)。生成した音をキーに収める場面で使えます。
|
|
98
|
-
|
|
99
|
-
## コードと進行を組み立てる
|
|
100
|
-
|
|
101
|
-
スケール度数、ローマ数字、リードシート記号のいずれからでも組み立てられ、逆方向にも戻せます。
|
|
13
|
+
## できること
|
|
102
14
|
|
|
103
|
-
|
|
104
|
-
import { Chord, Key } from '@libraz/libcantus';
|
|
105
|
-
|
|
106
|
-
const c = Key.major('C');
|
|
107
|
-
|
|
108
|
-
c.roman('V7/V').symbol(); // 'D7' (セカンダリードミナント)
|
|
109
|
-
c.chord(4, 'dom7').roman(); // 'V7'
|
|
110
|
-
Chord.parse('F#m7b5').pitchClasses(); // [0, 4, 6, 9]
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
コードの語彙は三和音から 13th までを網羅していて、`dim7`, `m7b5`, `minMaj7`, `aug7`、6th 系、オルタードドミナントも含みます。
|
|
114
|
-
|
|
115
|
-
スタイルのプリセットから進行そのものを生成することもできます(コレクション単位の操作なので関数として提供されます)。
|
|
116
|
-
|
|
117
|
-
```ts
|
|
118
|
-
import { generateProgression, majorKey } from '@libraz/libcantus';
|
|
119
|
-
|
|
120
|
-
// 1 小節につき 1 コード。収まる箇所にはセカンダリードミナントを挿入する:
|
|
121
|
-
generateProgression({ key: majorKey(0), style: 'idol', bars: 8, reharmonize: true, seed: 1 });
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## 和声を解析する
|
|
125
|
-
|
|
126
|
-
コードを、和声機能・終止・モーダルインターチェンジつきのローマ数字解析に変換します。長調と短調の双方に対応し、転回形も反映されます。
|
|
15
|
+
すでにノートやコード記号を持っているソフトウェア(DAW のプロジェクト、MIDI パーサー、練習支援ツールなど)と、その音が和声的に何を意味するかとの間を埋めます。ノートイベントを渡せば和声が求まり、その和声を渡せばそれに沿ったパートが書けます。
|
|
127
16
|
|
|
128
17
|
```ts
|
|
129
|
-
import {
|
|
18
|
+
import { Composer, Score } from '@libraz/libcantus';
|
|
130
19
|
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
## コードとキーを判定する
|
|
20
|
+
// DAW から渡ってくる形の、4 小節のブロックコード:
|
|
21
|
+
const harmony = [[48, 60, 64, 67], [41, 60, 65, 69], [43, 59, 62, 65], [48, 60, 64, 67]].flatMap(
|
|
22
|
+
(pitches, bar) => pitches.map((pitch) => ({ pitch, startBeat: bar * 4, durationBeat: 4 })),
|
|
23
|
+
);
|
|
137
24
|
|
|
138
|
-
|
|
25
|
+
const chords = Score.of(harmony).timeline();
|
|
26
|
+
chords.roman().map((entry) => entry.roman); // ['I', 'IV', 'V7', 'I']
|
|
27
|
+
chords.cadences().at(-1)?.cadence.type; // 'authentic'
|
|
139
28
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
Chord.detect([60, 64, 67])[0].symbol(); // 'C'
|
|
144
|
-
Chord.detectBest([60, 63, 67, 70])?.symbol(); // 'Cm7'
|
|
145
|
-
detectKey([0, 0, 0, 4, 7])[0]; // 最も適合する C メジャー (キーのランキングは関数として提供)
|
|
29
|
+
// 求まった和声の上に、ウォーキングベースを書く:
|
|
30
|
+
Composer.of({ key: chords.key, bpm: 120, seed: 1 }).bass(chords, { style: 'walking' }).notes;
|
|
31
|
+
// 16 音: [{ pitch: 36, startBeat: 0, durationBeat: 1, velocity: 100 }, ...]
|
|
146
32
|
```
|
|
147
33
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
`Key` は綴りを持ったトニックを保持しているので、ピッチクラスで動くコア部分からでも音名の文字列が得られます。長調でも短調でも綴りは正しくなります。
|
|
151
|
-
|
|
152
|
-
```ts
|
|
153
|
-
import { Chord, Key } from '@libraz/libcantus';
|
|
34
|
+
コードの境界は決め打ちせずに探索し、キーも同様に探します。転調する曲を、冒頭のキーのまま読み続けることはありません。
|
|
154
35
|
|
|
155
|
-
|
|
156
|
-
Key.minor('E').noteNames(); // ['E', 'F#', 'G', 'A', 'B', 'C', 'D']
|
|
36
|
+
各レイヤーが受け持つ範囲は次のとおりです。
|
|
157
37
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
38
|
+
- **[音高と記譜](docs/ja/pitch-and-notation.md)** — 綴りを保った音名と音程、MIDI 変換、英語・ドイツ語・日本語・イタリア語・固定ドでの読み書き、そして 1 音ずつではなく声部全体を 1 本の経路として解く綴り付け。テキストのパーサーにはいずれも例外を投げない対 (`tryParseNote`、`tryParseInterval`、`tryParseChordSymbol`、`tryParseKeyName`、`tryParseTimeSignature`、および `Note`・`Interval`・`Key`・`Chord`・`Meter` の `tryParse`) があるので、入力欄の 1 打鍵ごとに `try`/`catch` を書く必要はありません。
|
|
39
|
+
- **[和声](docs/ja/harmony.md)** — 構造を持つ値としてのコード、教会旋法やペンタトニックに加えて `WORLD_SCALES` を含むスケール、ローマ数字と和声機能、ヴォイシング、数字付き低音、そして違反した声部と理由まで返す声部書法・種目対位法のチェッカー。
|
|
40
|
+
- **[解析](docs/ja/analysis.md)** — ノートイベントからのコード・キー検出、タイムラインとカデンツ、和声的な還元、フレーズ、セクション、ハイパーメーター、モチーフ、アレンジ全体のレポート。
|
|
41
|
+
- **[生成](docs/ja/generation.md)** — プログレッション、モチーフ、リズム、ドラム、ベース、対旋律。いずれも 1 つの `GenerationContext` を参照します。プロジェクトのシード、加算的な 3 つの複雑さのダイヤル(リズム・和声・装飾)、それとは別枠の難易度の上限、テンポ、各パートの対象楽器がそこに入ります。同じコンテキストからは同じ結果が出ます。
|
|
42
|
+
- **[時間とアレンジ](docs/ja/time-and-arrangement.md)** — 拍子、テンポ、小節と拍による位置、複数トラックをまたぐ解析。
|
|
43
|
+
- **[クラス API](docs/ja/api-reference.md)** — 同じ理論を、ライブラリが扱う対象ごとの不変クラスとして提供します。`Score`、`Timeline`、`Composer` も含め、いずれも上記の関数の薄い外皮です。呼び出し側の都合で関数とクラスのどちらを使ってもよく、返る答えは同じです。
|
|
161
44
|
|
|
162
|
-
|
|
45
|
+
答えには、そう読んだ理由が付きます。`analyzeChord`、`detectCadence`、`explainRoman` は `rationale` を必ず返し、`detectKey` は要求があれば付けます。いずれも、退けた解釈を `alternatives` として報告できます。渡された情報だけでは決まらない場合、それらしい答えを作らずに `null` を返します。カデンツが完全か不完全かはヴォイシングがなければ決まりません。ソプラノに何があるかはヴォイシングだけが答えられるからです。
|
|
163
46
|
|
|
164
|
-
|
|
47
|
+
答えを左右する場面では、綴りの情報を落としません。減 5 度と増 4 度はピッチクラス上の距離が同じでも同じ音程ではないので、声部書法と対位法のチェッカーは数値ではなく綴られた音を受け取ります。
|
|
165
48
|
|
|
166
|
-
|
|
167
|
-
import { Chord, Key, majorKey, parseChordSymbol, substituteChord } from '@libraz/libcantus';
|
|
49
|
+
アプリケーションが手元に持っているデータから始まるガイドが 7 本あります。[DAW との連携](docs/ja/use-cases/daw-workflow.md)、[曲の解析](docs/ja/use-cases/piece-analysis.md)、[転調レポート](docs/ja/use-cases/modulation-report.md)、[和声課題のチェック](docs/ja/use-cases/harmony-exercise-checker.md)、[生成によるアレンジ](docs/ja/use-cases/generative-arrangement.md)、[コード譜の取り込み](docs/ja/use-cases/chord-chart-import.md)、[パートの準備](docs/ja/use-cases/part-preparation.md)です。
|
|
168
50
|
|
|
169
|
-
|
|
51
|
+
## やらないこと
|
|
170
52
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
53
|
+
- **入出力・記譜・音声を扱いません。** MIDI ファイルの読み書き、楽譜の描画、音声解析、再生はありません。パーサーは各自で用意し、ノートイベントとして渡してください。その層こそが必要なら、[libsonare](https://github.com/libraz/libsonare) が音声解析、マスタリング、合成、SMF 入出力を扱います。両者はコードを共有せず、どちらも相手を必要としません。
|
|
54
|
+
- **微分音の解析はしません。** 周波数、セント、オクターブの等分割、純正律の比は `core` にありますが、音高より上の層はすべて 12 のピッチクラスで動きます。半音より細かい単位で組み立てられた音楽は範囲外です。半フラットの音度を持つマカームを 12 音の近い音で代用せず `WORLD_SCALES` から外しているのも、同じ理由です。
|
|
55
|
+
- **旋法体系そのものは扱いません。** `WORLD_SCALES` が収録するのは、thāt やマカーム、日本の音階といった伝統が名を与えた音組織であって、その上に立つ体系ではありません。上行形と下行形、フレーズが寄りかかる音、旋律型の文法は、マスクには入りません。
|
|
56
|
+
- **調性を前提にしません。** ローマ数字と機能和声は西洋の慣習を前提とします。その読み方が適用できるスケールかどうかは `supportsFunctionalHarmony` が答えます(`'dorian'` は真、`'miyakoBushi'` は偽)。
|
|
57
|
+
- **コーパスは持ちません。** 統計を取るためのデータは同梱していません。
|
|
58
|
+
- **機能和声には既知の穴があります。** `functionOf` は和音と調だけから答えるため、終止四六の和音はその層では主和音の転回として読まれます。属和音としての読みは時間軸を見る層のものであり、属和音の前の和音を `approach` として渡したときに `detectCadence` がそれを示します。
|
|
175
59
|
|
|
176
|
-
##
|
|
60
|
+
## 要件
|
|
177
61
|
|
|
178
|
-
|
|
62
|
+
Node.js >= 22。
|
|
179
63
|
|
|
180
|
-
|
|
181
|
-
import { Chord } from '@libraz/libcantus';
|
|
64
|
+
## インストール
|
|
182
65
|
|
|
183
|
-
|
|
184
|
-
|
|
66
|
+
```sh
|
|
67
|
+
yarn add @libraz/libcantus
|
|
185
68
|
```
|
|
186
69
|
|
|
187
|
-
##
|
|
70
|
+
## 最初の例
|
|
188
71
|
|
|
189
|
-
|
|
72
|
+
理論の本体はツリーシェイク可能な純粋関数にあります。その上に、理論を語るときの言い方に近い不変のクラス API が乗っています。ライブラリが扱う対象ごとに1つのクラスがあり、単体の `Note`、`Interval`、`Chord` から、曲全体を受け持つ `Score`、`Timeline`、`Arrangement`、`Composer` までが揃います。
|
|
190
73
|
|
|
191
74
|
```ts
|
|
192
75
|
import { Chord, Key } from '@libraz/libcantus';
|
|
193
76
|
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
// 進行全体を、動きが最小になるようボイシングする:
|
|
197
|
-
c.chord(0, 'maj').progressionTo(c.chord(5, 'maj'), c.chord(4, 'dom7'), c.chord(0, 'maj')).voice();
|
|
198
|
-
// [[...], [...], [...], [...]] (各声部の音高が昇順に並ぶ)
|
|
199
|
-
|
|
200
|
-
// 単体のコードをシェルボイシングで:
|
|
201
|
-
Chord.of('C', 'maj7').styledVoicing({ style: 'shell' }); // ルート、3rd、7th
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
声部の進行を細かく制御したい場合は `voiceLeadingCost` と `nextVoicing` を、結果を検証したい場合は `counterpoint` の述語群(並行・隠伏の完全音程、音域の間隔、声部の交差、導音の解決など)を使います。
|
|
77
|
+
const key = Key.major('C');
|
|
78
|
+
const dominant = key.chord(5, 'dom7');
|
|
205
79
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
```ts
|
|
211
|
-
import {
|
|
212
|
-
generateBassLine, generateCounterMelody, generateDrums, generateRhythm,
|
|
213
|
-
generateMotif, majorKey, parseTimeSignature,
|
|
214
|
-
} from '@libraz/libcantus';
|
|
215
|
-
|
|
216
|
-
generateRhythm(parseTimeSignature('4/4'), { seed: 1, density: 0.5 }); // 強拍に重みを置いた発音位置
|
|
217
|
-
const motif = generateMotif({ key: majorKey(0), bars: 2, contour: 'arch', seed: 1 });
|
|
218
|
-
motif.notes.length > 0; // true — 決定的に生成された短い旋律の断片
|
|
80
|
+
dominant.symbol(); // 'G7'
|
|
81
|
+
dominant.analyze(key).roman; // 'V7'
|
|
82
|
+
Chord.parse('C7(b9,#11)').pitchClasses(); // [0, 1, 4, 6, 7, 10]
|
|
219
83
|
```
|
|
220
84
|
|
|
221
|
-
`
|
|
85
|
+
本体は関数で、クラスはいずれもその薄い外皮です。クラスは `.data` でプレーンな値を公開し、関数が返したデータからクラスを作れます。どちらかが閉じた世界になることはなく、返す答えも同じです。クラスが足すのは、値とその文脈をひとまとめに保持することです。呼び出しを連ねるときに同じ事実を書き直さずに済みます。`Score` は音符と拍子・テンポ・調をまとめて持ち、`Composer` は 1 曲を書くときの調・テンポ・シードを持ちます。
|
|
222
86
|
|
|
223
|
-
##
|
|
87
|
+
## インポートパス
|
|
224
88
|
|
|
225
|
-
|
|
89
|
+
ルートからすべてを export しています。1 つのレイヤーだけを取り込みたい場合は、サブパスを使ってください。
|
|
226
90
|
|
|
227
91
|
```ts
|
|
228
|
-
import {
|
|
229
|
-
|
|
230
|
-
} from '@libraz/libcantus';
|
|
231
|
-
|
|
232
|
-
//
|
|
233
|
-
const { timeline, key } = chordTimelineFromNotes(melodyAndChordNotes);
|
|
234
|
-
|
|
235
|
-
// 曲全体の解析。推定されたコード、終止、ノート単位の理論ラベル、そして
|
|
236
|
-
// 鳴っている和声とぶつかるノート(理由と修正候補つき)が得られる:
|
|
237
|
-
const report = analyzeArrangement([
|
|
238
|
-
{ role: 'melody', notes: melodyNotes },
|
|
239
|
-
{ role: 'harmony', notes: chordNotes },
|
|
240
|
-
]);
|
|
241
|
-
report.conflicts; // [{ beat, trackName, pitch, safety, reasons, rationale }, ...]
|
|
242
|
-
|
|
243
|
-
// 復元されたタイムラインから、足りないパートを生成する:
|
|
244
|
-
generateBassLine({ segments: timeline.segments, key, style: 'walking', seed: 1 });
|
|
245
|
-
generateCounterMelody({ melody: melodyNotes, timeline, key, register: 'below' });
|
|
92
|
+
import { parseNote, edo } from '@libraz/libcantus/core'; // 音高、拍子、テンポ、音律
|
|
93
|
+
import { majorKey, makeChord } from '@libraz/libcantus/theory'; // スケール、コード、ヴォイシング、規則
|
|
94
|
+
import { analyzeArrangement, detectKey } from '@libraz/libcantus/analyze';
|
|
95
|
+
import { generateDrums, generateProgression } from '@libraz/libcantus/generate';
|
|
96
|
+
import { Chord, Key, Note } from '@libraz/libcantus/model'; // クラス API
|
|
246
97
|
```
|
|
247
98
|
|
|
248
|
-
|
|
99
|
+
いずれのパスにも ESM と CommonJS の両方のビルドがあります。
|
|
249
100
|
|
|
250
|
-
|
|
101
|
+
## ドキュメント
|
|
251
102
|
|
|
252
|
-
|
|
103
|
+
最初に読むページ: [概要](docs/ja/introduction.md)、[使い始める](docs/ja/getting-started.md)、[ユースケース](docs/ja/use-cases/index.md)。
|
|
253
104
|
|
|
254
|
-
|
|
105
|
+
各領域のガイド: [音高と記譜](docs/ja/pitch-and-notation.md)、[スケールとモード](docs/ja/scales-and-modes.md)、[和声](docs/ja/harmony.md)、[調関係と転調](docs/ja/key-relations-and-modulation.md)、[ボイシング](docs/ja/voicing.md)、[対位法と和声課題](docs/ja/counterpoint-and-part-writing.md)、[時間とアレンジ](docs/ja/time-and-arrangement.md)、[解析](docs/ja/analysis.md)、[旋律とモチーフ](docs/ja/melody-and-motifs.md)、[リズムとグルーヴ](docs/ja/rhythm-and-groove.md)、[生成](docs/ja/generation.md)、[リハーモナイズ](docs/ja/reharmonization.md)、[楽器と演奏可能性](docs/ja/instruments-and-playability.md)、[音律と周波数](docs/ja/tuning-and-frequency.md)。
|
|
255
106
|
|
|
256
|
-
|
|
257
|
-
import { frequencyOf, edo, justDeviationCents } from '@libraz/libcantus';
|
|
258
|
-
```
|
|
107
|
+
横断的な話題: [決定性とシード](docs/ja/determinism-and-seeding.md)、[エラーと検証](docs/ja/errors-and-validation.md)、[パフォーマンス](docs/ja/performance.md)、[相互運用](docs/ja/interoperability.md)。
|
|
259
108
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
## ドキュメント
|
|
109
|
+
リファレンス: [API リファレンス](docs/ja/api-reference.md)、[用語集](docs/ja/glossary.md)、[FAQ と制限](docs/ja/faq.md)。
|
|
263
110
|
|
|
264
|
-
|
|
111
|
+
これらのガイドの `ts` の例はすべてテストスイートで実行され、末尾コメントに書いた期待値は実際の返り値と照合されます。生成される TypeDoc のリファレンスは `docs/api` に出力され、手書きガイドとは分かれています。
|
|
265
112
|
|
|
266
113
|
## ライセンス
|
|
267
114
|
|
|
268
|
-
Apache
|
|
115
|
+
[@libraz/libcantus](https://github.com/libraz/libcantus) は [Apache License 2.0](LICENSE) で提供します。
|
package/dist/analyze/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
+
var _chunkMXO72PLYcjs = require('../chunk-MXO72PLY.cjs');
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
|
|
@@ -7,8 +8,6 @@
|
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
var _chunk4VZ5MZAMcjs = require('../chunk-4VZ5MZAM.cjs');
|
|
11
|
-
require('../chunk-2A2QMA74.cjs');
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
|
|
@@ -26,12 +25,9 @@ require('../chunk-2A2QMA74.cjs');
|
|
|
26
25
|
|
|
27
26
|
|
|
28
27
|
|
|
29
|
-
var
|
|
28
|
+
var _chunk3JXCW6DXcjs = require('../chunk-3JXCW6DX.cjs');
|
|
30
29
|
|
|
31
30
|
|
|
32
|
-
var _chunkWFDXOLUBcjs = require('../chunk-WFDXOLUB.cjs');
|
|
33
|
-
require('../chunk-BSLTLGM3.cjs');
|
|
34
|
-
require('../chunk-PI3UXRWK.cjs');
|
|
35
31
|
|
|
36
32
|
|
|
37
33
|
|
|
@@ -54,9 +50,60 @@ require('../chunk-PI3UXRWK.cjs');
|
|
|
54
50
|
|
|
55
51
|
|
|
56
52
|
|
|
53
|
+
var _chunkOE6WK2Y2cjs = require('../chunk-OE6WK2Y2.cjs');
|
|
54
|
+
require('../chunk-K4ZJUGF4.cjs');
|
|
57
55
|
|
|
58
56
|
|
|
57
|
+
var _chunkUADYAYATcjs = require('../chunk-UADYAYAT.cjs');
|
|
58
|
+
require('../chunk-Q2WGKJNN.cjs');
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
exports.MODAL_SCALE_NAMES = _chunkOE6WK2Y2cjs.MODAL_SCALE_NAMES; exports.NoteSafety = _chunkUADYAYATcjs.NoteSafety; exports.analyzeArrangement = _chunk3JXCW6DXcjs.analyzeArrangement; exports.analyzeChord = _chunkOE6WK2Y2cjs.analyzeChord; exports.analyzeVoice = _chunk3JXCW6DXcjs.analyzeVoice; exports.augmentedSixthChord = _chunkOE6WK2Y2cjs.augmentedSixthChord; exports.augmentedSixthFromPitchClasses = _chunkOE6WK2Y2cjs.augmentedSixthFromPitchClasses; exports.augmentedSixthKind = _chunkOE6WK2Y2cjs.augmentedSixthKind; exports.borrowedSource = _chunkOE6WK2Y2cjs.borrowedSource; exports.chordTimelineFromChords = _chunk3JXCW6DXcjs.chordTimelineFromChords; exports.chordTimelineFromNotes = _chunk3JXCW6DXcjs.chordTimelineFromNotes; exports.chordToRoman = _chunkOE6WK2Y2cjs.chordToRoman; exports.compareMelodies = _chunk3JXCW6DXcjs.compareMelodies; exports.createArrangementSession = _chunk3JXCW6DXcjs.createArrangementSession; exports.detectCadence = _chunkOE6WK2Y2cjs.detectCadence; exports.detectCadences = _chunk3JXCW6DXcjs.detectCadences; exports.detectChord = _chunkOE6WK2Y2cjs.detectChord; exports.detectChordBest = _chunkOE6WK2Y2cjs.detectChordBest; exports.detectKey = _chunkOE6WK2Y2cjs.detectKey; exports.detectKeyBest = _chunkOE6WK2Y2cjs.detectKeyBest; exports.detectKeyFromNotes = _chunkOE6WK2Y2cjs.detectKeyFromNotes; exports.detectModulations = _chunk3JXCW6DXcjs.detectModulations; exports.explainRoman = _chunkOE6WK2Y2cjs.explainRoman; exports.extractMotifs = _chunk3JXCW6DXcjs.extractMotifs; exports.functionOf = _chunkOE6WK2Y2cjs.functionOf; exports.hypermeter = _chunk3JXCW6DXcjs.hypermeter; exports.isBorrowedChord = _chunkOE6WK2Y2cjs.isBorrowedChord; exports.isDiatonic = _chunkOE6WK2Y2cjs.isDiatonic; exports.isMinorKey = _chunkOE6WK2Y2cjs.isMinorKey; exports.keyTimelineFromNotes = _chunk3JXCW6DXcjs.keyTimelineFromNotes; exports.melodicContour = _chunk3JXCW6DXcjs.melodicContour; exports.melodicSimilarity = _chunk3JXCW6DXcjs.melodicSimilarity; exports.motifFromNotes = _chunk3JXCW6DXcjs.motifFromNotes; exports.phrasesFromTimeline = _chunk3JXCW6DXcjs.phrasesFromTimeline; exports.pivotChords = _chunkOE6WK2Y2cjs.pivotChords; exports.prevailingKeyOf = _chunk3JXCW6DXcjs.prevailingKeyOf; exports.reduceProgression = _chunk3JXCW6DXcjs.reduceProgression; exports.relateMotifs = _chunk3JXCW6DXcjs.relateMotifs; exports.romanToChord = _chunkOE6WK2Y2cjs.romanToChord; exports.secondaryDominant = _chunkOE6WK2Y2cjs.secondaryDominant; exports.secondaryDominantOf = _chunkOE6WK2Y2cjs.secondaryDominantOf; exports.sectionsFromNotes = _chunk3JXCW6DXcjs.sectionsFromNotes; exports.spellAugmentedSixth = _chunkOE6WK2Y2cjs.spellAugmentedSixth; exports.spellLine = _chunkMXO72PLYcjs.spellLine; exports.structuralCadences = _chunk3JXCW6DXcjs.structuralCadences; exports.tensionCurve = _chunk3JXCW6DXcjs.tensionCurve; exports.tensionCurveFrom = _chunk3JXCW6DXcjs.tensionCurveFrom; exports.toVoiceNotes = _chunk3JXCW6DXcjs.toVoiceNotes;
|
|
62
109
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/libcantus/libcantus/dist/analyze/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/libcantus/libcantus/dist/analyze/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B,iCAA8B;AAC9B;AACE;AACF,yDAA8B;AAC9B,iCAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,23FAAC","file":"/home/runner/work/libcantus/libcantus/dist/analyze/index.cjs"}
|