@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
package/README.md
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
# @libraz/libcantus
|
|
2
2
|
|
|
3
|
-
Pure-TypeScript
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Pure-TypeScript music theory engine. It takes MIDI note numbers and chord
|
|
4
|
+
symbols and gives back harmonic meaning (Roman numerals, function, cadence,
|
|
5
|
+
key), then generates new parts against that meaning. Built for the tools that
|
|
6
|
+
sit next to a DAW: analyzers, generators, and composition assistants.
|
|
7
|
+
|
|
8
|
+
It is a theory layer, not an I/O or audio layer. There is no MIDI file reader or
|
|
9
|
+
writer, no audio analysis, and no playback — bring your own parser and hand it
|
|
10
|
+
note events. No runtime dependencies. If you need that other layer as well,
|
|
11
|
+
[libsonare](https://github.com/libraz/libsonare) covers audio analysis,
|
|
12
|
+
mastering, synthesis, and SMF I/O, and its npm binding sits alongside this one;
|
|
13
|
+
the two share no code and neither requires the other.
|
|
7
14
|
|
|
8
15
|
[](https://github.com/libraz/libcantus/actions)
|
|
9
16
|
[](https://www.npmjs.com/package/@libraz/libcantus)
|
|
@@ -21,7 +28,7 @@ dependencies.
|
|
|
21
28
|
(`V7/V`), or lead-sheet symbols (`Cmaj7`, `F#m7b5`, `C/G`).
|
|
22
29
|
- **Analyze harmony** — Roman-numeral analysis, harmonic function, cadence
|
|
23
30
|
detection, and borrowed / modal-interchange chords.
|
|
24
|
-
- **Recognize
|
|
31
|
+
- **Recognize chords and keys** — notes in, chord or key out (the inverse of the
|
|
25
32
|
builders).
|
|
26
33
|
- **Reharmonize** — tritone subs, chromatic mediants, negative harmony, modal
|
|
27
34
|
interchange palettes.
|
|
@@ -29,17 +36,18 @@ dependencies.
|
|
|
29
36
|
rootless comping styles.
|
|
30
37
|
- **Generate parts** — bass lines, countermelodies, drums, rhythms, motifs, and
|
|
31
38
|
whole progressions; deterministic for a given seed.
|
|
32
|
-
- **
|
|
39
|
+
- **Analyze a whole arrangement** — feed raw multi-track note events, recover the
|
|
33
40
|
harmony, get a whole-piece analysis (with per-note conflicts), and generate the
|
|
34
41
|
missing parts against it.
|
|
35
42
|
- **Work with pitch as sound** — frequencies, cents, EDO, and just intonation.
|
|
36
43
|
|
|
37
|
-
The
|
|
38
|
-
|
|
39
|
-
`
|
|
40
|
-
**
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
The theory itself lives in **tree-shakeable pure functions**. On top of them sits
|
|
45
|
+
a **fluent, immutable class API** (`Note`, `Interval`, `Chord`, `Key`,
|
|
46
|
+
`Progression`) that reads like music theory. Which one you get follows a single
|
|
47
|
+
rule: the musical **values** — notes, chords, keys, progressions — have both
|
|
48
|
+
forms and interoperate freely, while operations over **collections and
|
|
49
|
+
timelines** (part generation, whole-arrangement analysis, key ranking) take
|
|
50
|
+
arrays of note events and are exposed as functions only.
|
|
43
51
|
|
|
44
52
|
## Install
|
|
45
53
|
|
|
@@ -88,11 +96,11 @@ pure functions, so the two styles interoperate freely. The same task with the
|
|
|
88
96
|
functional API:
|
|
89
97
|
|
|
90
98
|
```ts
|
|
91
|
-
import { chordFromDegree, chordPitchClasses, classifyInterval, majorKey } from '@libraz/libcantus';
|
|
99
|
+
import { chordFromDegree, chordPitchClasses, classifyInterval, ConsonanceClass, majorKey } from '@libraz/libcantus';
|
|
92
100
|
|
|
93
101
|
const cMajor = majorKey(0);
|
|
94
102
|
|
|
95
|
-
classifyInterval(7); //
|
|
103
|
+
classifyInterval(7); // ConsonanceClass.PerfectConsonance
|
|
96
104
|
chordPitchClasses(chordFromDegree(4, 'dom7', cMajor)); // [2, 5, 7, 11] (G7)
|
|
97
105
|
```
|
|
98
106
|
|
|
@@ -157,10 +165,10 @@ import { Chord, Key } from '@libraz/libcantus';
|
|
|
157
165
|
|
|
158
166
|
// A minor iv in a major key reads as a borrowed subdominant:
|
|
159
167
|
Chord.of('F', 'min').analyze(Key.major('C'));
|
|
160
|
-
// { function: 'subdominant', borrowed: true, source: '
|
|
168
|
+
// { function: 'subdominant', borrowed: true, source: 'parallelMinor', roman: 'iv' }
|
|
161
169
|
```
|
|
162
170
|
|
|
163
|
-
## Recognize
|
|
171
|
+
## Recognize chords and keys
|
|
164
172
|
|
|
165
173
|
Notes in, chord or key out — the inverse of the builders:
|
|
166
174
|
|
|
@@ -256,10 +264,11 @@ motif.notes.length > 0; // true — a deterministic short melodic cell
|
|
|
256
264
|
`humanize`, `extractGrooveTemplate`, and `applyGrooveTemplate` add a meter-aware
|
|
257
265
|
feel — or capture the feel of one performance and transplant it onto another.
|
|
258
266
|
|
|
259
|
-
##
|
|
267
|
+
## Analyze and extend an arrangement
|
|
260
268
|
|
|
261
|
-
The arrangement layer takes raw multi-track `NoteEvent`s
|
|
262
|
-
then analyses and generates
|
|
269
|
+
The arrangement layer takes raw multi-track `NoteEvent`s — whatever your DAW or
|
|
270
|
+
MIDI-file parser produced — recovers the harmony, then analyses and generates
|
|
271
|
+
against it:
|
|
263
272
|
|
|
264
273
|
```ts
|
|
265
274
|
import {
|
|
@@ -279,7 +288,7 @@ report.conflicts; // [{ beat, trackName, pitch, safety, reasons, rationale }, ..
|
|
|
279
288
|
|
|
280
289
|
// Generate the missing parts from the recovered timeline:
|
|
281
290
|
generateBassLine({ segments: timeline.segments, key, style: 'walking', seed: 1 });
|
|
282
|
-
generateCounterMelody({ melody: melodyNotes,
|
|
291
|
+
generateCounterMelody({ melody: melodyNotes, timeline, key, register: 'below' });
|
|
283
292
|
```
|
|
284
293
|
|
|
285
294
|
`harmonizeMelody` goes the other way — given a bare melody, it searches for the
|
package/README_ja.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# @libraz/libcantus
|
|
2
|
+
|
|
3
|
+
TypeScript だけで書かれた音楽理論エンジンです。MIDI ノート番号とコードネームを受け取り、和声的な意味(ローマ数字、和声機能、終止、キー)を返します。さらにその解析結果を土台にして新しいパートを生成します。DAW の隣に置くツール(解析器、ジェネレーター、作曲アシスタント)で使うことを想定しています。
|
|
4
|
+
|
|
5
|
+
扱うのは理論の層だけで、I/O やオーディオには踏み込みません。MIDI ファイルの読み書き、オーディオ解析、再生のいずれも持たないので、パースは呼び出し側で行い、ノートイベントとして渡してください。実行時依存はありません。その層も必要であれば、[libsonare](https://github.com/libraz/libsonare) が音声解析・マスタリング・音源合成・SMF の読み書きを担当していて、npm パッケージなので本ライブラリと並べて置けます。両者はコードを共有しておらず、どちらも単独で使えます。
|
|
6
|
+
|
|
7
|
+
[](https://github.com/libraz/libcantus/actions)
|
|
8
|
+
[](https://www.npmjs.com/package/@libraz/libcantus)
|
|
9
|
+
[](https://codecov.io/gh/libraz/libcantus)
|
|
10
|
+
[](https://github.com/libraz/libcantus/blob/main/LICENSE)
|
|
11
|
+
[](https://www.typescriptlang.org/)
|
|
12
|
+
[](https://nodejs.org/)
|
|
13
|
+
[](https://libraz.github.io/libcantus/)
|
|
14
|
+
|
|
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
|
+
スケール度数、ローマ数字、リードシート記号のいずれからでも組み立てられ、逆方向にも戻せます。
|
|
102
|
+
|
|
103
|
+
```ts
|
|
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
|
+
コードを、和声機能・終止・モーダルインターチェンジつきのローマ数字解析に変換します。長調と短調の双方に対応し、転回形も反映されます。
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import { Chord, Key } from '@libraz/libcantus';
|
|
130
|
+
|
|
131
|
+
// 長調に現れる短調の iv は、借用されたサブドミナントとして解釈される:
|
|
132
|
+
Chord.of('F', 'min').analyze(Key.major('C'));
|
|
133
|
+
// { function: 'subdominant', borrowed: true, source: 'parallelMinor', roman: 'iv' }
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## コードとキーを判定する
|
|
137
|
+
|
|
138
|
+
ノートを入れるとコードやキーが返ります。組み立てとちょうど逆方向の処理です。
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { Chord, detectKey } from '@libraz/libcantus';
|
|
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 メジャー (キーのランキングは関数として提供)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## コードとスケールを綴る
|
|
149
|
+
|
|
150
|
+
`Key` は綴りを持ったトニックを保持しているので、ピッチクラスで動くコア部分からでも音名の文字列が得られます。長調でも短調でも綴りは正しくなります。
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { Chord, Key } from '@libraz/libcantus';
|
|
154
|
+
|
|
155
|
+
Key.named('harmonicMinor', 'A').noteNames(); // ['A', 'B', 'C', 'D', 'E', 'F', 'G#']
|
|
156
|
+
Key.minor('E').noteNames(); // ['E', 'F#', 'G', 'A', 'B', 'C', 'D']
|
|
157
|
+
|
|
158
|
+
// コードもキーの文脈に沿って綴られる:
|
|
159
|
+
Key.major('C').chord(4, 'dom7').spell().map((n) => n.name); // ['G', 'B', 'D', 'F']
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## リハーモナイズする
|
|
163
|
+
|
|
164
|
+
クラス側ではネガティブハーモニーによる反転を、関数側では代理コードの候補(裏コード、平行調、借用、クロマチックメディアント、およびモーダルインターチェンジのパレット)の列挙を扱います。
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { Chord, Key, majorKey, parseChordSymbol, substituteChord } from '@libraz/libcantus';
|
|
168
|
+
|
|
169
|
+
Key.major('C').chord(4, 'dom7').negativeHarmony().symbol(); // 'Dm7b5'
|
|
170
|
+
|
|
171
|
+
// 代理コードやパレットの検索はリストを返すので関数として提供される:
|
|
172
|
+
substituteChord(parseChordSymbol('G7'), majorKey(0));
|
|
173
|
+
// [{ chord: Db7, type: 'tritone', ... }, ...]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## スケールとテンションを選ぶ
|
|
177
|
+
|
|
178
|
+
クラス側で、あるコードに使えるスケールと、そこで利用できるテンションおよびアボイドノートを求められます。`scalesForChanges` を使えば、コード進行全体を通して繋がりが最適になるスケール選択が得られます。
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { Chord } from '@libraz/libcantus';
|
|
182
|
+
|
|
183
|
+
Chord.of('C', 'dom7').scales()[0]; // { name: 'mixolydian', rootPc: 0 }
|
|
184
|
+
Chord.of('C', 'maj7').tensions('ionian'); // [2, 9] (9th と 13th。11th はアボイドノート)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## コードをボイシングする
|
|
188
|
+
|
|
189
|
+
進行全体を、声部の動きが最小になる 4 声(SATB)の MIDI ボイシングに展開できます。単体のコードをコンピングスタイル(drop-2/3、シェル、ルートレス)でボイシングすることもできます。
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
import { Chord, Key } from '@libraz/libcantus';
|
|
193
|
+
|
|
194
|
+
const c = Key.major('C');
|
|
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` の述語群(並行・隠伏の完全音程、音域の間隔、声部の交差、導音の解決など)を使います。
|
|
205
|
+
|
|
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 — 決定的に生成された短い旋律の断片
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
`humanize`, `extractGrooveTemplate`, `applyGrooveTemplate` は拍子を踏まえたノリを付け足します。ある演奏のノリを取り出して別の演奏に移植する使い方もできます。
|
|
222
|
+
|
|
223
|
+
## アレンジを解析して足す
|
|
224
|
+
|
|
225
|
+
アレンジ層は、DAW や MIDI ファイルのパーサーが吐いたマルチトラックの `NoteEvent` をそのまま受け取り、和声を復元してから解析と生成を行います。
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
import {
|
|
229
|
+
analyzeArrangement, chordTimelineFromNotes, generateBassLine, generateCounterMelody,
|
|
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' });
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
`harmonizeMelody` は逆方向を担当します。旋律だけを渡すと、それを和声づけするのに最適なキー・移調量・コードの経路を(必要ならリハーモナイズも含めて)探索します。
|
|
249
|
+
|
|
250
|
+
アレンジ層と生成層のあいだでやり取りするノートイベントは `NoteEvent`(`{ pitch, startBeat, durationBeat, velocity? }`。音高は MIDI ノート番号、時間は 4 分音符を 1 とする拍数)の一種類に統一されています。シードを取るジェネレーター(`bass`, `groove`, `countermelody`, `rhythm`, `drums`, `motif`, `progression`)は、同じシードに対して常に同じ結果を返します。
|
|
251
|
+
|
|
252
|
+
## 音高を音響として扱う
|
|
253
|
+
|
|
254
|
+
周波数、セント、EDO、純正律を扱えます。音律の設計、微分音、そして解析に使えます。
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
import { frequencyOf, edo, justDeviationCents } from '@libraz/libcantus';
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
拍子まわりのヘルパー(`TimeSignature`, `parseTimeSignature`, `beatsPerBar`, `metricWeight`, `isStrongBeat`, `tuplet`)は単純拍子と複合拍子の両方を扱い、アクセントを考慮するジェネレーター群の土台にもなっています。
|
|
261
|
+
|
|
262
|
+
## ドキュメント
|
|
263
|
+
|
|
264
|
+
すべてのエクスポートをシグネチャつきで、領域ごとに分類し、動かせる例を添えた API リファレンスをソースから生成して **[libraz.github.io/libcantus](https://libraz.github.io/libcantus/)** に公開しています。
|
|
265
|
+
|
|
266
|
+
## ライセンス
|
|
267
|
+
|
|
268
|
+
Apache-2.0
|