@libraz/libcantus 0.9.4 → 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.
Files changed (120) hide show
  1. package/README.md +27 -18
  2. package/README_ja.md +268 -0
  3. package/dist/analyze/index.cjs +7 -7
  4. package/dist/analyze/index.d.cts +9 -99
  5. package/dist/analyze/index.d.ts +9 -99
  6. package/dist/analyze/index.js +6 -6
  7. package/dist/{chunk-36N73KZ3.cjs → chunk-2A2QMA74.cjs} +80 -65
  8. package/dist/chunk-2A2QMA74.cjs.map +1 -0
  9. package/dist/{chunk-YLEMGEFH.js → chunk-2PTFGVD7.js} +50 -35
  10. package/dist/chunk-2PTFGVD7.js.map +1 -0
  11. package/dist/{chunk-ZEJR4TKL.cjs → chunk-357ZDPVU.cjs} +36 -47
  12. package/dist/chunk-357ZDPVU.cjs.map +1 -0
  13. package/dist/{chunk-EHVEBWM5.js → chunk-3KX76RLG.js} +136 -37
  14. package/dist/chunk-3KX76RLG.js.map +1 -0
  15. package/dist/{chunk-RC6GBMCD.cjs → chunk-4VZ5MZAM.cjs} +155 -111
  16. package/dist/chunk-4VZ5MZAM.cjs.map +1 -0
  17. package/dist/{chunk-RK35RIN7.js → chunk-7EONYVI5.js} +115 -28
  18. package/dist/chunk-7EONYVI5.js.map +1 -0
  19. package/dist/{chunk-GQSGS2N4.js → chunk-7JEP3MFY.js} +5 -16
  20. package/dist/chunk-7JEP3MFY.js.map +1 -0
  21. package/dist/{chunk-7NKDPF74.js → chunk-AID75RN3.js} +203 -104
  22. package/dist/chunk-AID75RN3.js.map +1 -0
  23. package/dist/{chunk-FNDWXRRI.cjs → chunk-BSLTLGM3.cjs} +55 -37
  24. package/dist/chunk-BSLTLGM3.cjs.map +1 -0
  25. package/dist/{chunk-NP4NA2FB.cjs → chunk-CU6VG2YM.cjs} +39 -36
  26. package/dist/chunk-CU6VG2YM.cjs.map +1 -0
  27. package/dist/{chunk-NYYWMV2C.js → chunk-DZMHIGI4.js} +27 -17
  28. package/dist/chunk-DZMHIGI4.js.map +1 -0
  29. package/dist/{chunk-I24MV65U.js → chunk-EDOTEABK.js} +18 -15
  30. package/dist/{chunk-I24MV65U.js.map → chunk-EDOTEABK.js.map} +1 -1
  31. package/dist/{chunk-NKIBQ6PT.js → chunk-HN2OEUN2.js} +7 -4
  32. package/dist/chunk-HN2OEUN2.js.map +1 -0
  33. package/dist/{chunk-D2FAJBYL.js → chunk-KBTTEX7Q.js} +30 -12
  34. package/dist/chunk-KBTTEX7Q.js.map +1 -0
  35. package/dist/{chunk-CAN76NCU.cjs → chunk-KQN2ZYND.cjs} +147 -102
  36. package/dist/chunk-KQN2ZYND.cjs.map +1 -0
  37. package/dist/{chunk-4HLLZPXT.cjs → chunk-MPTVJIVG.cjs} +350 -251
  38. package/dist/chunk-MPTVJIVG.cjs.map +1 -0
  39. package/dist/{chunk-RUMU3UA6.cjs → chunk-MTMZTMWM.cjs} +12 -12
  40. package/dist/{chunk-RUMU3UA6.cjs.map → chunk-MTMZTMWM.cjs.map} +1 -1
  41. package/dist/{chunk-KMHOICIY.js → chunk-NNB67XA2.js} +90 -45
  42. package/dist/chunk-NNB67XA2.js.map +1 -0
  43. package/dist/{chunk-LW53AHQU.cjs → chunk-OL3IHHSJ.cjs} +228 -141
  44. package/dist/chunk-OL3IHHSJ.cjs.map +1 -0
  45. package/dist/{chunk-7MGZ7D62.cjs → chunk-PI3UXRWK.cjs} +43 -13
  46. package/dist/chunk-PI3UXRWK.cjs.map +1 -0
  47. package/dist/{chunk-XEBG3G53.js → chunk-R2VVFAIN.js} +42 -12
  48. package/dist/chunk-R2VVFAIN.js.map +1 -0
  49. package/dist/{chunk-Q6OP4U43.cjs → chunk-WFDXOLUB.cjs} +50 -40
  50. package/dist/chunk-WFDXOLUB.cjs.map +1 -0
  51. package/dist/{chunk-NVE34YGZ.cjs → chunk-WTAN4ACG.cjs} +212 -113
  52. package/dist/chunk-WTAN4ACG.cjs.map +1 -0
  53. package/dist/{chunk-FCANXBAT.cjs → chunk-YFJXS3AU.cjs} +8 -5
  54. package/dist/chunk-YFJXS3AU.cjs.map +1 -0
  55. package/dist/{chunk-Q2XUP227.js → chunk-YUE6TJ4M.js} +89 -45
  56. package/dist/chunk-YUE6TJ4M.js.map +1 -0
  57. package/dist/{chunk-HKGYCQ34.js → chunk-ZGLJM4A4.js} +2 -2
  58. package/dist/core/index.cjs +15 -5
  59. package/dist/core/index.cjs.map +1 -1
  60. package/dist/core/index.d.cts +14 -4
  61. package/dist/core/index.d.ts +14 -4
  62. package/dist/core/index.js +14 -4
  63. package/dist/{function-DNugAOrt.d.cts → function-CxixTB02.d.cts} +98 -7
  64. package/dist/{function-BtiZb9i9.d.ts → function-DTCt675z.d.ts} +98 -7
  65. package/dist/generate/index.cjs +10 -10
  66. package/dist/generate/index.d.cts +21 -21
  67. package/dist/generate/index.d.ts +21 -21
  68. package/dist/generate/index.js +9 -9
  69. package/dist/{index-tJhkmQgE.d.cts → index-B2Ulxxpo.d.cts} +3 -2
  70. package/dist/{index-Be74mcon.d.cts → index-BkYJ0xMq.d.cts} +2 -2
  71. package/dist/{index-6VR8-kit.d.ts → index-BuaB-ypt.d.ts} +3 -2
  72. package/dist/{index-70p168VM.d.ts → index-CAN7v-kw.d.ts} +9 -2
  73. package/dist/{index-C83mZI1P.d.ts → index-COw1Ky9g.d.ts} +1 -1
  74. package/dist/{index-tSQh-xwY.d.ts → index-Cfx8xgH0.d.ts} +1 -1
  75. package/dist/{index-C5UBbQ4G.d.ts → index-DRtIhlJj.d.ts} +2 -2
  76. package/dist/{index-BtXT6UQ0.d.cts → index-alrRninU.d.cts} +9 -2
  77. package/dist/{index-y_ak9_Hi.d.cts → index-oTQbYYIs.d.cts} +1 -1
  78. package/dist/{index-OG65ocOr.d.ts → index-tR9jTn26.d.cts} +4 -1
  79. package/dist/{index-OG65ocOr.d.cts → index-tR9jTn26.d.ts} +4 -1
  80. package/dist/{index-D6b6na69.d.cts → index-x2vcsduE.d.cts} +1 -1
  81. package/dist/index.cjs +24 -14
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.d.cts +11 -11
  84. package/dist/index.d.ts +11 -11
  85. package/dist/index.js +23 -13
  86. package/dist/model/index.cjs +7 -7
  87. package/dist/model/index.d.cts +48 -16
  88. package/dist/model/index.d.ts +48 -16
  89. package/dist/model/index.js +6 -6
  90. package/dist/{styled-DIRkk9Uz.d.ts → styled-Bl0ZK28h.d.ts} +40 -3
  91. package/dist/{styled-DJbkJQfj.d.cts → styled-Crv6SA4S.d.cts} +40 -3
  92. package/dist/theory/index.cjs +6 -6
  93. package/dist/theory/index.d.cts +9 -9
  94. package/dist/theory/index.d.ts +9 -9
  95. package/dist/theory/index.js +5 -5
  96. package/package.json +12 -9
  97. package/dist/chunk-36N73KZ3.cjs.map +0 -1
  98. package/dist/chunk-4HLLZPXT.cjs.map +0 -1
  99. package/dist/chunk-7MGZ7D62.cjs.map +0 -1
  100. package/dist/chunk-7NKDPF74.js.map +0 -1
  101. package/dist/chunk-CAN76NCU.cjs.map +0 -1
  102. package/dist/chunk-D2FAJBYL.js.map +0 -1
  103. package/dist/chunk-EHVEBWM5.js.map +0 -1
  104. package/dist/chunk-FCANXBAT.cjs.map +0 -1
  105. package/dist/chunk-FNDWXRRI.cjs.map +0 -1
  106. package/dist/chunk-GQSGS2N4.js.map +0 -1
  107. package/dist/chunk-KMHOICIY.js.map +0 -1
  108. package/dist/chunk-LW53AHQU.cjs.map +0 -1
  109. package/dist/chunk-NKIBQ6PT.js.map +0 -1
  110. package/dist/chunk-NP4NA2FB.cjs.map +0 -1
  111. package/dist/chunk-NVE34YGZ.cjs.map +0 -1
  112. package/dist/chunk-NYYWMV2C.js.map +0 -1
  113. package/dist/chunk-Q2XUP227.js.map +0 -1
  114. package/dist/chunk-Q6OP4U43.cjs.map +0 -1
  115. package/dist/chunk-RC6GBMCD.cjs.map +0 -1
  116. package/dist/chunk-RK35RIN7.js.map +0 -1
  117. package/dist/chunk-XEBG3G53.js.map +0 -1
  118. package/dist/chunk-YLEMGEFH.js.map +0 -1
  119. package/dist/chunk-ZEJR4TKL.cjs.map +0 -1
  120. /package/dist/{chunk-HKGYCQ34.js.map → chunk-ZGLJM4A4.js.map} +0 -0
package/README.md CHANGED
@@ -1,9 +1,16 @@
1
1
  # @libraz/libcantus
2
2
 
3
- Pure-TypeScript toolkit for working with music: name notes and chords, analyze
4
- harmony, recognize what you're hearing, voice and reharmonize progressions, and
5
- generate parts (bass, countermelody, drums, rhythm) — all with no runtime
6
- dependencies.
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
  [![CI](https://img.shields.io/github/actions/workflow/status/libraz/libcantus/ci.yml?branch=main&label=CI)](https://github.com/libraz/libcantus/actions)
9
16
  [![npm](https://img.shields.io/npm/v/@libraz/libcantus)](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 what you hear** — notes in, chord or key out (the inverse of the
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
- - **Arrange from a DAW / MIDI file** — feed raw multi-track notes, recover the
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 musical **values** — notes, chords, keys, progressions — come in two
38
- interchangeable styles: a **fluent, immutable class API** (`Note`, `Chord`,
39
- `Key`, `Progression`) that reads like music theory, and the underlying
40
- **tree-shakeable pure functions**. Operations over **collections and timelines**
41
- (part generation and whole-arrangement analysis) work on arrays of note events,
42
- so — like `rhythm`, `drums`, and `detectKey` — they are exposed as functions.
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); // IntervalQuality.PerfectConsonance
103
+ classifyInterval(7); // ConsonanceClass.PerfectConsonance
96
104
  chordPitchClasses(chordFromDegree(4, 'dom7', cMajor)); // [2, 5, 7, 11] (G7)
97
105
  ```
98
106
 
@@ -160,7 +168,7 @@ Chord.of('F', 'min').analyze(Key.major('C'));
160
168
  // { function: 'subdominant', borrowed: true, source: 'parallelMinor', roman: 'iv' }
161
169
  ```
162
170
 
163
- ## Recognize what you hear
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
- ## Arrange from a DAW or MIDI file
267
+ ## Analyze and extend an arrangement
260
268
 
261
- The arrangement layer takes raw multi-track `NoteEvent`s, recovers the harmony,
262
- then analyses and generates against it:
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 {
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
+ [![CI](https://img.shields.io/github/actions/workflow/status/libraz/libcantus/ci.yml?branch=main&label=CI)](https://github.com/libraz/libcantus/actions)
8
+ [![npm](https://img.shields.io/npm/v/@libraz/libcantus)](https://www.npmjs.com/package/@libraz/libcantus)
9
+ [![codecov](https://codecov.io/gh/libraz/libcantus/branch/main/graph/badge.svg)](https://codecov.io/gh/libraz/libcantus)
10
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/libraz/libcantus/blob/main/LICENSE)
11
+ [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
12
+ [![Node.js](https://img.shields.io/badge/Node.js-22.x-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
13
+ [![docs](https://img.shields.io/badge/docs-API%20reference-b5892e)](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
@@ -7,8 +7,8 @@
7
7
 
8
8
 
9
9
 
10
- var _chunkRC6GBMCDcjs = require('../chunk-RC6GBMCD.cjs');
11
- require('../chunk-36N73KZ3.cjs');
10
+ var _chunk4VZ5MZAMcjs = require('../chunk-4VZ5MZAM.cjs');
11
+ require('../chunk-2A2QMA74.cjs');
12
12
 
13
13
 
14
14
 
@@ -26,12 +26,12 @@ require('../chunk-36N73KZ3.cjs');
26
26
 
27
27
 
28
28
 
29
- var _chunkCAN76NCUcjs = require('../chunk-CAN76NCU.cjs');
29
+ var _chunkKQN2ZYNDcjs = require('../chunk-KQN2ZYND.cjs');
30
30
 
31
31
 
32
- var _chunkQ6OP4U43cjs = require('../chunk-Q6OP4U43.cjs');
33
- require('../chunk-FNDWXRRI.cjs');
34
- require('../chunk-7MGZ7D62.cjs');
32
+ var _chunkWFDXOLUBcjs = require('../chunk-WFDXOLUB.cjs');
33
+ require('../chunk-BSLTLGM3.cjs');
34
+ require('../chunk-PI3UXRWK.cjs');
35
35
 
36
36
 
37
37
 
@@ -58,5 +58,5 @@ require('../chunk-7MGZ7D62.cjs');
58
58
 
59
59
 
60
60
 
61
- exports.NoteSafety = _chunkQ6OP4U43cjs.NoteSafety; exports.analyzeArrangement = _chunkRC6GBMCDcjs.analyzeArrangement; exports.analyzeChord = _chunkCAN76NCUcjs.analyzeChord; exports.analyzeVoice = _chunkRC6GBMCDcjs.analyzeVoice; exports.borrowedSource = _chunkCAN76NCUcjs.borrowedSource; exports.chordTimelineFromChords = _chunkRC6GBMCDcjs.chordTimelineFromChords; exports.chordTimelineFromNotes = _chunkRC6GBMCDcjs.chordTimelineFromNotes; exports.chordToRoman = _chunkCAN76NCUcjs.chordToRoman; exports.detectCadence = _chunkCAN76NCUcjs.detectCadence; exports.detectCadences = _chunkRC6GBMCDcjs.detectCadences; exports.detectChord = _chunkCAN76NCUcjs.detectChord; exports.detectChordBest = _chunkCAN76NCUcjs.detectChordBest; exports.detectKey = _chunkCAN76NCUcjs.detectKey; exports.detectKeyBest = _chunkCAN76NCUcjs.detectKeyBest; exports.detectKeyFromNotes = _chunkCAN76NCUcjs.detectKeyFromNotes; exports.functionOf = _chunkCAN76NCUcjs.functionOf; exports.isBorrowedChord = _chunkCAN76NCUcjs.isBorrowedChord; exports.isDiatonic = _chunkCAN76NCUcjs.isDiatonic; exports.isMinorKey = _chunkCAN76NCUcjs.isMinorKey; exports.parallelKey = _chunkCAN76NCUcjs.parallelKey; exports.romanToChord = _chunkCAN76NCUcjs.romanToChord; exports.secondaryDominant = _chunkCAN76NCUcjs.secondaryDominant; exports.tensionCurve = _chunkRC6GBMCDcjs.tensionCurve; exports.tensionCurveFrom = _chunkRC6GBMCDcjs.tensionCurveFrom; exports.toVoiceNotes = _chunkRC6GBMCDcjs.toVoiceNotes;
61
+ exports.NoteSafety = _chunkWFDXOLUBcjs.NoteSafety; exports.analyzeArrangement = _chunk4VZ5MZAMcjs.analyzeArrangement; exports.analyzeChord = _chunkKQN2ZYNDcjs.analyzeChord; exports.analyzeVoice = _chunk4VZ5MZAMcjs.analyzeVoice; exports.borrowedSource = _chunkKQN2ZYNDcjs.borrowedSource; exports.chordTimelineFromChords = _chunk4VZ5MZAMcjs.chordTimelineFromChords; exports.chordTimelineFromNotes = _chunk4VZ5MZAMcjs.chordTimelineFromNotes; exports.chordToRoman = _chunkKQN2ZYNDcjs.chordToRoman; exports.detectCadence = _chunkKQN2ZYNDcjs.detectCadence; exports.detectCadences = _chunk4VZ5MZAMcjs.detectCadences; exports.detectChord = _chunkKQN2ZYNDcjs.detectChord; exports.detectChordBest = _chunkKQN2ZYNDcjs.detectChordBest; exports.detectKey = _chunkKQN2ZYNDcjs.detectKey; exports.detectKeyBest = _chunkKQN2ZYNDcjs.detectKeyBest; exports.detectKeyFromNotes = _chunkKQN2ZYNDcjs.detectKeyFromNotes; exports.functionOf = _chunkKQN2ZYNDcjs.functionOf; exports.isBorrowedChord = _chunkKQN2ZYNDcjs.isBorrowedChord; exports.isDiatonic = _chunkKQN2ZYNDcjs.isDiatonic; exports.isMinorKey = _chunkKQN2ZYNDcjs.isMinorKey; exports.parallelKey = _chunkKQN2ZYNDcjs.parallelKey; exports.romanToChord = _chunkKQN2ZYNDcjs.romanToChord; exports.secondaryDominant = _chunkKQN2ZYNDcjs.secondaryDominant; exports.tensionCurve = _chunk4VZ5MZAMcjs.tensionCurve; exports.tensionCurveFrom = _chunk4VZ5MZAMcjs.tensionCurveFrom; exports.toVoiceNotes = _chunk4VZ5MZAMcjs.toVoiceNotes;
62
62
  //# sourceMappingURL=index.cjs.map
@@ -1,102 +1,12 @@
1
1
  import { T as TimeSignature } from '../index-DXd9JikN.cjs';
2
- import { K as KeyScale, N as NoteEvent } from '../types-BN6_Q9Kl.cjs';
3
- import { C as Chord, d as ChordToneRole } from '../index-y_ak9_Hi.cjs';
4
- export { a as ChordQuality, b as ChordSegment, c as ChordSpan, P as PitchSpelling } from '../index-y_ak9_Hi.cjs';
5
- import { V as VoiceSnapshot, N as NoteSafety, S as SafetyProfile } from '../index-tJhkmQgE.cjs';
6
- import { a as ChordTimeline, C as CadenceHit } from '../index-Be74mcon.cjs';
7
- export { b as ChordTimelineOptions, c as ChordTimelineResult, d as chordTimelineFromChords, e as chordTimelineFromNotes, f as detectCadences } from '../index-Be74mcon.cjs';
8
- export { C as ChordMatch, D as DetectChordOptions, a as DetectKeyOptions, K as KeyMatch, b as KeyVariant, d as detectChord, c as detectChordBest, e as detectKey, f as detectKeyBest, g as detectKeyFromNotes } from '../index-BtXT6UQ0.cjs';
9
- export { B as BorrowedSource, C as Cadence, a as ChordAnalysis, H as HarmonicFunction, b as analyzeChord, c as borrowedSource, d as detectCadence, f as functionOf, i as isBorrowedChord, e as isDiatonic, g as isMinorKey, p as parallelKey, s as secondaryDominant } from '../function-DNugAOrt.cjs';
10
-
11
- /**
12
- * Roman-numeral parsing and formatting.
13
- *
14
- * The {@link ROMAN_STYLE} table is the single source of truth for both
15
- * directions, so {@link chordToRoman} and {@link romanToChord} stay mutual
16
- * inverses by construction.
17
- */
18
-
19
- /**
20
- * Build the chord denoted by a Roman numeral in a key.
21
- *
22
- * Supports accidentals (`bVII`, `#iv`), case-based triad quality, the `o`/`ø`/`+`
23
- * suffixes, sevenths (`V7`, `viio7`, `Imaj7`), figured-bass inversions
24
- * (`V6`, `V64`, `V65`, `V43`, `V42`), and applied/secondary chords via a slash
25
- * (`V7/V`, `viio/ii`). The target after the slash is read as a scale degree
26
- * whose root becomes a local major tonic for the applied chord. Inverted chords
27
- * carry a `bassPc`.
28
- *
29
- * The `ø` glyph always denotes the half-diminished seventh (`iiø` == `iiø7` ==
30
- * `m7b5`), since no half-diminished triad exists. Extension and added-tone
31
- * suffixes are the canonical case-sensitive forms emitted by
32
- * {@link chordToRoman} and honor the numeral case: `V9` -> `dom9`, `ii9` ->
33
- * `min9`, `Imaj9` -> `maj9`, `V11` -> `11`, `V13` -> `13`, `Iadd6`/`iadd6` ->
34
- * `6`/`min6`, `I69` -> `6/9`, `Isus2`/`Isus4`, `Iadd9`/`Iadd11`, `Ib5` ->
35
- * `majb5`, `I5` -> `5`, and the altered dominants `V7b9`/`V7#9`/`V7#11`/`V7b13`.
36
- * A figure string that is neither a recognized inversion nor a supported
37
- * quality suffix throws rather than silently degrading to a triad.
38
- *
39
- * @param text The Roman numeral.
40
- * @param key The prevailing key.
41
- * @returns The chord.
42
- * @example
43
- * ```ts
44
- * import { romanToChord, majorKey } from '@libraz/libcantus';
45
- * romanToChord('V7', majorKey(0)); // G7 in C major: { rootPc: 7, quality: 'dom7', ... }
46
- * ```
47
- * @category Functional Harmony
48
- */
49
- declare function romanToChord(text: string, key: KeyScale): Chord;
50
- /**
51
- * Options for {@link chordToRoman}.
52
- *
53
- * @category Functional Harmony
54
- */
55
- type ChordToRomanOptions = {
56
- /**
57
- * Render a tonicizing chord as an applied numeral (`V7/V`, `viio7/ii`)
58
- * instead of naming its root against the home key (`II7`, `#ivo7`).
59
- *
60
- * Off by default: naming the root is always a correct spelling, whereas
61
- * whether a chromatic dominant is genuinely applied is a reading only the
62
- * caller can make. Turning it on makes {@link chordToRoman} the exact inverse
63
- * of {@link romanToChord} for the chords {@link secondaryDominant} builds.
64
- */
65
- applied?: boolean;
66
- };
67
- /**
68
- * Render a chord as a Roman numeral relative to a key.
69
- *
70
- * Diatonic roots take their scale-degree numeral directly, so numerals are
71
- * correct in both major and minor keys (and any custom scale). The quality
72
- * selects the case and suffix; chromatic roots receive a flat/sharp spelling by
73
- * convention. A key that is not heptatonic has no numeral of its own for every
74
- * degree, so its roots are named against its parallel major.
75
- *
76
- * When the chord carries a `bassPc` on a chord tone, a figured-bass inversion
77
- * (`6`, `64`, `65`, `43`, `42`) is emitted for plain triads and true seventh
78
- * chords; added-tone and extended qualities have no lossless figure and render
79
- * in root position instead (the bass is dropped, pitch classes are preserved).
80
- *
81
- * A `bassPc` that is *not* a chord tone — a pedal or passing bass such as
82
- * `C/D` — is likewise dropped, and the numeral names the upper chord alone.
83
- * Roman-numeral notation spends its slash on applied chords (`V7/V`), so there
84
- * is no unambiguous way to write such a bass; a caller that must keep it should
85
- * read `chord.bassPc` alongside the numeral.
86
- *
87
- * @param chord The chord to name.
88
- * @param key The prevailing key.
89
- * @param opts `applied` renders tonicizing chords as `V7/V`-style numerals.
90
- * @returns The Roman numeral string.
91
- * @example
92
- * ```ts
93
- * import { chordToRoman, makeChord, majorKey } from '@libraz/libcantus';
94
- * chordToRoman(makeChord(7, 'dom7'), majorKey(0)); // => 'V7' (G7 in C major)
95
- * chordToRoman(makeChord(2, 'dom7'), majorKey(0), { applied: true }); // => 'V7/V'
96
- * ```
97
- * @category Functional Harmony
98
- */
99
- declare function chordToRoman(chord: Chord, key: KeyScale, opts?: ChordToRomanOptions): string;
2
+ import { N as NoteEvent, K as KeyScale } from '../types-BN6_Q9Kl.cjs';
3
+ import { d as ChordToneRole, C as Chord } from '../index-oTQbYYIs.cjs';
4
+ export { a as ChordQuality, b as ChordSegment, c as ChordSpan, P as PitchSpelling } from '../index-oTQbYYIs.cjs';
5
+ import { V as VoiceSnapshot, N as NoteSafety, S as SafetyProfile } from '../index-B2Ulxxpo.cjs';
6
+ import { a as ChordTimeline, C as CadenceHit } from '../index-BkYJ0xMq.cjs';
7
+ export { b as ChordTimelineOptions, c as ChordTimelineResult, d as chordTimelineFromChords, e as chordTimelineFromNotes, f as detectCadences } from '../index-BkYJ0xMq.cjs';
8
+ export { C as ChordMatch, D as DetectChordOptions, a as DetectKeyOptions, K as KeyMatch, b as KeyVariant, d as detectChord, c as detectChordBest, e as detectKey, f as detectKeyBest, g as detectKeyFromNotes } from '../index-alrRninU.cjs';
9
+ export { B as BorrowedSource, C as Cadence, a as ChordAnalysis, b as ChordToRomanOptions, H as HarmonicFunction, c as analyzeChord, d as borrowedSource, e as chordToRoman, f as detectCadence, g as functionOf, i as isBorrowedChord, h as isDiatonic, j as isMinorKey, p as parallelKey, r as romanToChord, s as secondaryDominant } from '../function-CxixTB02.cjs';
100
10
 
101
11
  /**
102
12
  * A suspension figure, named by the interval above the bass and the interval it
@@ -498,4 +408,4 @@ declare function tensionCurveFrom(tracks: ArrangementTrack[], analysis: Arrangem
498
408
  step?: number;
499
409
  }): TensionPoint[];
500
410
 
501
- export { type AnalyzedNote, type ArrangementAnalysis, type ArrangementOptions, type ArrangementTrack, CadenceHit, Chord as ChordData, ChordTimeline, type ChordToRomanOptions, ChordToneRole, type Conflict, type IdentifiedVoiceNote, KeyScale, NoteEvent, NoteSafety, SafetyProfile, type SuspensionFigure, type TensionPoint, type TheoryLabel, TimeSignature, type TrackAnalysis, type TrackRole, type VoiceNote, VoiceSnapshot, analyzeArrangement, analyzeVoice, chordToRoman, romanToChord, tensionCurve, tensionCurveFrom, toVoiceNotes };
411
+ export { type AnalyzedNote, type ArrangementAnalysis, type ArrangementOptions, type ArrangementTrack, CadenceHit, Chord as ChordData, ChordTimeline, ChordToneRole, type Conflict, type IdentifiedVoiceNote, KeyScale, NoteEvent, NoteSafety, SafetyProfile, type SuspensionFigure, type TensionPoint, type TheoryLabel, TimeSignature, type TrackAnalysis, type TrackRole, type VoiceNote, VoiceSnapshot, analyzeArrangement, analyzeVoice, tensionCurve, tensionCurveFrom, toVoiceNotes };
@@ -1,102 +1,12 @@
1
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, d as ChordToneRole } from '../index-C83mZI1P.js';
4
- export { a as ChordQuality, b as ChordSegment, c as ChordSpan, P as PitchSpelling } from '../index-C83mZI1P.js';
5
- import { V as VoiceSnapshot, N as NoteSafety, S as SafetyProfile } from '../index-6VR8-kit.js';
6
- import { a as ChordTimeline, C as CadenceHit } from '../index-C5UBbQ4G.js';
7
- export { b as ChordTimelineOptions, c as ChordTimelineResult, d as chordTimelineFromChords, e as chordTimelineFromNotes, f as detectCadences } from '../index-C5UBbQ4G.js';
8
- export { C as ChordMatch, D as DetectChordOptions, a as DetectKeyOptions, K as KeyMatch, b as KeyVariant, d as detectChord, c as detectChordBest, e as detectKey, f as detectKeyBest, g as detectKeyFromNotes } from '../index-70p168VM.js';
9
- export { B as BorrowedSource, C as Cadence, a as ChordAnalysis, H as HarmonicFunction, b as analyzeChord, c as borrowedSource, d as detectCadence, f as functionOf, i as isBorrowedChord, e as isDiatonic, g as isMinorKey, p as parallelKey, s as secondaryDominant } from '../function-BtiZb9i9.js';
10
-
11
- /**
12
- * Roman-numeral parsing and formatting.
13
- *
14
- * The {@link ROMAN_STYLE} table is the single source of truth for both
15
- * directions, so {@link chordToRoman} and {@link romanToChord} stay mutual
16
- * inverses by construction.
17
- */
18
-
19
- /**
20
- * Build the chord denoted by a Roman numeral in a key.
21
- *
22
- * Supports accidentals (`bVII`, `#iv`), case-based triad quality, the `o`/`ø`/`+`
23
- * suffixes, sevenths (`V7`, `viio7`, `Imaj7`), figured-bass inversions
24
- * (`V6`, `V64`, `V65`, `V43`, `V42`), and applied/secondary chords via a slash
25
- * (`V7/V`, `viio/ii`). The target after the slash is read as a scale degree
26
- * whose root becomes a local major tonic for the applied chord. Inverted chords
27
- * carry a `bassPc`.
28
- *
29
- * The `ø` glyph always denotes the half-diminished seventh (`iiø` == `iiø7` ==
30
- * `m7b5`), since no half-diminished triad exists. Extension and added-tone
31
- * suffixes are the canonical case-sensitive forms emitted by
32
- * {@link chordToRoman} and honor the numeral case: `V9` -> `dom9`, `ii9` ->
33
- * `min9`, `Imaj9` -> `maj9`, `V11` -> `11`, `V13` -> `13`, `Iadd6`/`iadd6` ->
34
- * `6`/`min6`, `I69` -> `6/9`, `Isus2`/`Isus4`, `Iadd9`/`Iadd11`, `Ib5` ->
35
- * `majb5`, `I5` -> `5`, and the altered dominants `V7b9`/`V7#9`/`V7#11`/`V7b13`.
36
- * A figure string that is neither a recognized inversion nor a supported
37
- * quality suffix throws rather than silently degrading to a triad.
38
- *
39
- * @param text The Roman numeral.
40
- * @param key The prevailing key.
41
- * @returns The chord.
42
- * @example
43
- * ```ts
44
- * import { romanToChord, majorKey } from '@libraz/libcantus';
45
- * romanToChord('V7', majorKey(0)); // G7 in C major: { rootPc: 7, quality: 'dom7', ... }
46
- * ```
47
- * @category Functional Harmony
48
- */
49
- declare function romanToChord(text: string, key: KeyScale): Chord;
50
- /**
51
- * Options for {@link chordToRoman}.
52
- *
53
- * @category Functional Harmony
54
- */
55
- type ChordToRomanOptions = {
56
- /**
57
- * Render a tonicizing chord as an applied numeral (`V7/V`, `viio7/ii`)
58
- * instead of naming its root against the home key (`II7`, `#ivo7`).
59
- *
60
- * Off by default: naming the root is always a correct spelling, whereas
61
- * whether a chromatic dominant is genuinely applied is a reading only the
62
- * caller can make. Turning it on makes {@link chordToRoman} the exact inverse
63
- * of {@link romanToChord} for the chords {@link secondaryDominant} builds.
64
- */
65
- applied?: boolean;
66
- };
67
- /**
68
- * Render a chord as a Roman numeral relative to a key.
69
- *
70
- * Diatonic roots take their scale-degree numeral directly, so numerals are
71
- * correct in both major and minor keys (and any custom scale). The quality
72
- * selects the case and suffix; chromatic roots receive a flat/sharp spelling by
73
- * convention. A key that is not heptatonic has no numeral of its own for every
74
- * degree, so its roots are named against its parallel major.
75
- *
76
- * When the chord carries a `bassPc` on a chord tone, a figured-bass inversion
77
- * (`6`, `64`, `65`, `43`, `42`) is emitted for plain triads and true seventh
78
- * chords; added-tone and extended qualities have no lossless figure and render
79
- * in root position instead (the bass is dropped, pitch classes are preserved).
80
- *
81
- * A `bassPc` that is *not* a chord tone — a pedal or passing bass such as
82
- * `C/D` — is likewise dropped, and the numeral names the upper chord alone.
83
- * Roman-numeral notation spends its slash on applied chords (`V7/V`), so there
84
- * is no unambiguous way to write such a bass; a caller that must keep it should
85
- * read `chord.bassPc` alongside the numeral.
86
- *
87
- * @param chord The chord to name.
88
- * @param key The prevailing key.
89
- * @param opts `applied` renders tonicizing chords as `V7/V`-style numerals.
90
- * @returns The Roman numeral string.
91
- * @example
92
- * ```ts
93
- * import { chordToRoman, makeChord, majorKey } from '@libraz/libcantus';
94
- * chordToRoman(makeChord(7, 'dom7'), majorKey(0)); // => 'V7' (G7 in C major)
95
- * chordToRoman(makeChord(2, 'dom7'), majorKey(0), { applied: true }); // => 'V7/V'
96
- * ```
97
- * @category Functional Harmony
98
- */
99
- declare function chordToRoman(chord: Chord, key: KeyScale, opts?: ChordToRomanOptions): string;
2
+ import { N as NoteEvent, K as KeyScale } from '../types-BN6_Q9Kl.js';
3
+ import { d as ChordToneRole, C as Chord } from '../index-COw1Ky9g.js';
4
+ export { a as ChordQuality, b as ChordSegment, c as ChordSpan, P as PitchSpelling } from '../index-COw1Ky9g.js';
5
+ import { V as VoiceSnapshot, N as NoteSafety, S as SafetyProfile } from '../index-BuaB-ypt.js';
6
+ import { a as ChordTimeline, C as CadenceHit } from '../index-DRtIhlJj.js';
7
+ export { b as ChordTimelineOptions, c as ChordTimelineResult, d as chordTimelineFromChords, e as chordTimelineFromNotes, f as detectCadences } from '../index-DRtIhlJj.js';
8
+ export { C as ChordMatch, D as DetectChordOptions, a as DetectKeyOptions, K as KeyMatch, b as KeyVariant, d as detectChord, c as detectChordBest, e as detectKey, f as detectKeyBest, g as detectKeyFromNotes } from '../index-CAN7v-kw.js';
9
+ export { B as BorrowedSource, C as Cadence, a as ChordAnalysis, b as ChordToRomanOptions, H as HarmonicFunction, c as analyzeChord, d as borrowedSource, e as chordToRoman, f as detectCadence, g as functionOf, i as isBorrowedChord, h as isDiatonic, j as isMinorKey, p as parallelKey, r as romanToChord, s as secondaryDominant } from '../function-DTCt675z.js';
100
10
 
101
11
  /**
102
12
  * A suspension figure, named by the interval above the bass and the interval it
@@ -498,4 +408,4 @@ declare function tensionCurveFrom(tracks: ArrangementTrack[], analysis: Arrangem
498
408
  step?: number;
499
409
  }): TensionPoint[];
500
410
 
501
- export { type AnalyzedNote, type ArrangementAnalysis, type ArrangementOptions, type ArrangementTrack, CadenceHit, Chord as ChordData, ChordTimeline, type ChordToRomanOptions, ChordToneRole, type Conflict, type IdentifiedVoiceNote, KeyScale, NoteEvent, NoteSafety, SafetyProfile, type SuspensionFigure, type TensionPoint, type TheoryLabel, TimeSignature, type TrackAnalysis, type TrackRole, type VoiceNote, VoiceSnapshot, analyzeArrangement, analyzeVoice, chordToRoman, romanToChord, tensionCurve, tensionCurveFrom, toVoiceNotes };
411
+ export { type AnalyzedNote, type ArrangementAnalysis, type ArrangementOptions, type ArrangementTrack, CadenceHit, Chord as ChordData, ChordTimeline, ChordToneRole, type Conflict, type IdentifiedVoiceNote, KeyScale, NoteEvent, NoteSafety, SafetyProfile, type SuspensionFigure, type TensionPoint, type TheoryLabel, TimeSignature, type TrackAnalysis, type TrackRole, type VoiceNote, VoiceSnapshot, analyzeArrangement, analyzeVoice, tensionCurve, tensionCurveFrom, toVoiceNotes };