@libraz/libcantus 0.9.5 → 1.0.1

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 (185) hide show
  1. package/README.md +61 -270
  2. package/README_ja.md +61 -214
  3. package/dist/analyze/index.cjs +54 -7
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +200 -353
  6. package/dist/analyze/index.d.ts +200 -353
  7. package/dist/analyze/index.js +56 -9
  8. package/dist/chunk-2LCPM3EG.js +3224 -0
  9. package/dist/chunk-2LCPM3EG.js.map +1 -0
  10. package/dist/chunk-6XH6QZYQ.cjs +7647 -0
  11. package/dist/chunk-6XH6QZYQ.cjs.map +1 -0
  12. package/dist/chunk-6XPTBE7Y.cjs +49 -0
  13. package/dist/chunk-6XPTBE7Y.cjs.map +1 -0
  14. package/dist/chunk-AFM2ULJH.cjs +5121 -0
  15. package/dist/chunk-AFM2ULJH.cjs.map +1 -0
  16. package/dist/chunk-B6XNKWZV.cjs +3224 -0
  17. package/dist/chunk-B6XNKWZV.cjs.map +1 -0
  18. package/dist/chunk-E3F4AHAH.cjs +690 -0
  19. package/dist/chunk-E3F4AHAH.cjs.map +1 -0
  20. package/dist/{chunk-2PTFGVD7.js → chunk-ELCTZUJJ.js} +250 -132
  21. package/dist/chunk-ELCTZUJJ.js.map +1 -0
  22. package/dist/chunk-FVSI36UV.js +690 -0
  23. package/dist/chunk-FVSI36UV.js.map +1 -0
  24. package/dist/chunk-GEDTJHAC.cjs +1 -0
  25. package/dist/chunk-GEDTJHAC.cjs.map +1 -0
  26. package/dist/chunk-H3VORETI.js +2243 -0
  27. package/dist/chunk-H3VORETI.js.map +1 -0
  28. package/dist/chunk-H42UHPYW.js +1577 -0
  29. package/dist/chunk-H42UHPYW.js.map +1 -0
  30. package/dist/chunk-HFPS7JFD.js +1 -0
  31. package/dist/chunk-INHVXP6Z.js +3053 -0
  32. package/dist/chunk-INHVXP6Z.js.map +1 -0
  33. package/dist/chunk-K4ZJUGF4.cjs +379 -0
  34. package/dist/chunk-K4ZJUGF4.cjs.map +1 -0
  35. package/dist/chunk-KNJEKLKV.js +49 -0
  36. package/dist/chunk-KNJEKLKV.js.map +1 -0
  37. package/dist/chunk-MXO72PLY.cjs +211 -0
  38. package/dist/chunk-MXO72PLY.cjs.map +1 -0
  39. package/dist/chunk-NLEU4QSE.cjs +360 -0
  40. package/dist/chunk-NLEU4QSE.cjs.map +1 -0
  41. package/dist/chunk-OE6WK2Y2.cjs +1577 -0
  42. package/dist/chunk-OE6WK2Y2.cjs.map +1 -0
  43. package/dist/chunk-PKFNUHDY.js +7647 -0
  44. package/dist/chunk-PKFNUHDY.js.map +1 -0
  45. package/dist/chunk-Q2WGKJNN.cjs +1064 -0
  46. package/dist/chunk-Q2WGKJNN.cjs.map +1 -0
  47. package/dist/chunk-QYQQ5J6E.js +1 -0
  48. package/dist/chunk-QYQQ5J6E.js.map +1 -0
  49. package/dist/chunk-RHIJ3S4I.cjs +1 -0
  50. package/dist/chunk-RHIJ3S4I.cjs.map +1 -0
  51. package/dist/chunk-TTCLJX6D.js +211 -0
  52. package/dist/chunk-TTCLJX6D.js.map +1 -0
  53. package/dist/chunk-UADYAYAT.cjs +3053 -0
  54. package/dist/chunk-UADYAYAT.cjs.map +1 -0
  55. package/dist/chunk-VOHZB45S.js +5121 -0
  56. package/dist/chunk-VOHZB45S.js.map +1 -0
  57. package/dist/chunk-VTI6FOLB.js +1064 -0
  58. package/dist/chunk-VTI6FOLB.js.map +1 -0
  59. package/dist/chunk-WWURE4XT.cjs +2243 -0
  60. package/dist/chunk-WWURE4XT.cjs.map +1 -0
  61. package/dist/chunk-YH3BIKHH.js +360 -0
  62. package/dist/chunk-YH3BIKHH.js.map +1 -0
  63. package/dist/core/index.cjs +93 -6
  64. package/dist/core/index.cjs.map +1 -1
  65. package/dist/core/index.d.cts +87 -346
  66. package/dist/core/index.d.ts +87 -346
  67. package/dist/core/index.js +94 -7
  68. package/dist/generate/index.cjs +89 -10
  69. package/dist/generate/index.cjs.map +1 -1
  70. package/dist/generate/index.d.cts +436 -1094
  71. package/dist/generate/index.d.ts +436 -1094
  72. package/dist/generate/index.js +94 -15
  73. package/dist/index-9wcMhG73.d.ts +1095 -0
  74. package/dist/{index-Cfx8xgH0.d.ts → index-B4o55NDr.d.cts} +13 -9
  75. package/dist/index-B9MNZboQ.d.cts +770 -0
  76. package/dist/index-B9MNZboQ.d.ts +770 -0
  77. package/dist/index-BGFW-8P2.d.cts +2307 -0
  78. package/dist/index-BO6xE9YU.d.cts +1804 -0
  79. package/dist/index-BkGmlyI3.d.cts +470 -0
  80. package/dist/index-CCNJRG-P.d.cts +1095 -0
  81. package/dist/index-CGpRv5sl.d.cts +643 -0
  82. package/dist/index-C_8o--VE.d.cts +1242 -0
  83. package/dist/index-CgHqxdps.d.ts +2307 -0
  84. package/dist/index-Chbst3Jx.d.ts +1343 -0
  85. package/dist/index-Cj49F892.d.ts +470 -0
  86. package/dist/{index-x2vcsduE.d.cts → index-CunYKLiu.d.ts} +13 -9
  87. package/dist/index-D57QRbVn.d.ts +1804 -0
  88. package/dist/index-DInQqT8Q.d.cts +66 -0
  89. package/dist/index-DInQqT8Q.d.ts +66 -0
  90. package/dist/index-Dzr13q3d.d.cts +1343 -0
  91. package/dist/index-G1uwGGWQ.d.ts +643 -0
  92. package/dist/index-szBv3496.d.ts +1242 -0
  93. package/dist/index.cjs +348 -15
  94. package/dist/index.cjs.map +1 -1
  95. package/dist/index.d.cts +17 -15
  96. package/dist/index.d.ts +17 -15
  97. package/dist/index.js +397 -64
  98. package/dist/masks-DYbE485J.d.cts +445 -0
  99. package/dist/masks-DYbE485J.d.ts +445 -0
  100. package/dist/model/index.cjs +39 -7
  101. package/dist/model/index.cjs.map +1 -1
  102. package/dist/model/index.d.cts +4659 -249
  103. package/dist/model/index.d.ts +4659 -249
  104. package/dist/model/index.js +40 -8
  105. package/dist/positional-Cptlj-xs.d.ts +287 -0
  106. package/dist/positional-DvH_sd8u.d.cts +287 -0
  107. package/dist/theory/index.cjs +101 -7
  108. package/dist/theory/index.cjs.map +1 -1
  109. package/dist/theory/index.d.cts +511 -171
  110. package/dist/theory/index.d.ts +511 -171
  111. package/dist/theory/index.js +118 -24
  112. package/package.json +6 -4
  113. package/dist/chunk-2A2QMA74.cjs +0 -261
  114. package/dist/chunk-2A2QMA74.cjs.map +0 -1
  115. package/dist/chunk-2PTFGVD7.js.map +0 -1
  116. package/dist/chunk-357ZDPVU.cjs +0 -162
  117. package/dist/chunk-357ZDPVU.cjs.map +0 -1
  118. package/dist/chunk-3KX76RLG.js +0 -1548
  119. package/dist/chunk-3KX76RLG.js.map +0 -1
  120. package/dist/chunk-4VZ5MZAM.cjs +0 -889
  121. package/dist/chunk-4VZ5MZAM.cjs.map +0 -1
  122. package/dist/chunk-7EONYVI5.js +0 -1204
  123. package/dist/chunk-7EONYVI5.js.map +0 -1
  124. package/dist/chunk-7JEP3MFY.js +0 -162
  125. package/dist/chunk-7JEP3MFY.js.map +0 -1
  126. package/dist/chunk-AID75RN3.js +0 -3176
  127. package/dist/chunk-AID75RN3.js.map +0 -1
  128. package/dist/chunk-BSLTLGM3.cjs +0 -497
  129. package/dist/chunk-BSLTLGM3.cjs.map +0 -1
  130. package/dist/chunk-CU6VG2YM.cjs +0 -109
  131. package/dist/chunk-CU6VG2YM.cjs.map +0 -1
  132. package/dist/chunk-DZMHIGI4.js +0 -337
  133. package/dist/chunk-DZMHIGI4.js.map +0 -1
  134. package/dist/chunk-EDOTEABK.js +0 -109
  135. package/dist/chunk-EDOTEABK.js.map +0 -1
  136. package/dist/chunk-HN2OEUN2.js +0 -33
  137. package/dist/chunk-HN2OEUN2.js.map +0 -1
  138. package/dist/chunk-KBTTEX7Q.js +0 -497
  139. package/dist/chunk-KBTTEX7Q.js.map +0 -1
  140. package/dist/chunk-KQN2ZYND.cjs +0 -724
  141. package/dist/chunk-KQN2ZYND.cjs.map +0 -1
  142. package/dist/chunk-MPTVJIVG.cjs +0 -3176
  143. package/dist/chunk-MPTVJIVG.cjs.map +0 -1
  144. package/dist/chunk-MTMZTMWM.cjs +0 -53
  145. package/dist/chunk-MTMZTMWM.cjs.map +0 -1
  146. package/dist/chunk-N6IHQUOX.js +0 -1
  147. package/dist/chunk-NNB67XA2.js +0 -724
  148. package/dist/chunk-NNB67XA2.js.map +0 -1
  149. package/dist/chunk-OL3IHHSJ.cjs +0 -1204
  150. package/dist/chunk-OL3IHHSJ.cjs.map +0 -1
  151. package/dist/chunk-PI3UXRWK.cjs +0 -528
  152. package/dist/chunk-PI3UXRWK.cjs.map +0 -1
  153. package/dist/chunk-R2VVFAIN.js +0 -528
  154. package/dist/chunk-R2VVFAIN.js.map +0 -1
  155. package/dist/chunk-T64C7ZD7.cjs +0 -1
  156. package/dist/chunk-T64C7ZD7.cjs.map +0 -1
  157. package/dist/chunk-WFDXOLUB.cjs +0 -337
  158. package/dist/chunk-WFDXOLUB.cjs.map +0 -1
  159. package/dist/chunk-WTAN4ACG.cjs +0 -1548
  160. package/dist/chunk-WTAN4ACG.cjs.map +0 -1
  161. package/dist/chunk-YFJXS3AU.cjs +0 -33
  162. package/dist/chunk-YFJXS3AU.cjs.map +0 -1
  163. package/dist/chunk-YUE6TJ4M.js +0 -889
  164. package/dist/chunk-YUE6TJ4M.js.map +0 -1
  165. package/dist/chunk-ZGLJM4A4.js +0 -53
  166. package/dist/chunk-ZGLJM4A4.js.map +0 -1
  167. package/dist/function-CxixTB02.d.cts +0 -299
  168. package/dist/function-DTCt675z.d.ts +0 -299
  169. package/dist/index-B2Ulxxpo.d.cts +0 -144
  170. package/dist/index-BkYJ0xMq.d.cts +0 -152
  171. package/dist/index-BuaB-ypt.d.ts +0 -144
  172. package/dist/index-CAN7v-kw.d.ts +0 -199
  173. package/dist/index-COw1Ky9g.d.ts +0 -242
  174. package/dist/index-DRtIhlJj.d.ts +0 -152
  175. package/dist/index-DXd9JikN.d.cts +0 -246
  176. package/dist/index-DXd9JikN.d.ts +0 -246
  177. package/dist/index-alrRninU.d.cts +0 -199
  178. package/dist/index-oTQbYYIs.d.cts +0 -242
  179. package/dist/index-tR9jTn26.d.cts +0 -275
  180. package/dist/index-tR9jTn26.d.ts +0 -275
  181. package/dist/styled-Bl0ZK28h.d.ts +0 -543
  182. package/dist/styled-Crv6SA4S.d.cts +0 -543
  183. package/dist/types-BN6_Q9Kl.d.cts +0 -39
  184. package/dist/types-BN6_Q9Kl.d.ts +0 -39
  185. /package/dist/{chunk-N6IHQUOX.js.map → chunk-HFPS7JFD.js.map} +0 -0
@@ -1,275 +0,0 @@
1
- /**
2
- * Pitch spelling: letter-name notes, enharmonic-aware conversion, and spelled
3
- * intervals.
4
- *
5
- * The rest of the library works in pitch classes (0..11), which cannot tell a
6
- * G# from an Ab or an augmented fourth from a diminished fifth. This module adds
7
- * an explicit spelling layer — a note is a diatonic letter plus a chromatic
8
- * alteration — so interval quality (P/M/m/A/d) and enharmonic identity are
9
- * preserved.
10
- */
11
- /**
12
- * A spelled note: a diatonic letter, a chromatic alteration, and an optional
13
- * octave.
14
- *
15
- * - `letter` is 0..6 for C..B.
16
- * - `alter` is the number of semitones of alteration: -2 double-flat, -1 flat,
17
- * 0 natural, +1 sharp, +2 double-sharp.
18
- * - `octave` follows scientific pitch notation (middle C = C4 = MIDI 60). When
19
- * absent, the note denotes a bare pitch class.
20
- *
21
- * @category Pitch & Intervals
22
- */
23
- type Note = {
24
- letter: number;
25
- alter: number;
26
- octave?: number;
27
- };
28
- /**
29
- * The quality label of a spelled interval: perfect, major, minor, or one or
30
- * more augmentations or diminutions.
31
- *
32
- * This names how an interval is *spelled*. It is a different notion from
33
- * {@link ConsonanceClass}, which classifies how an interval *sounds* against
34
- * another voice.
35
- *
36
- * @see {@link ConsonanceClass}
37
- * @category Pitch & Intervals
38
- */
39
- type IntervalQualityLabel = 'P' | 'M' | 'm' | `A${string}` | `d${string}`;
40
- /**
41
- * A spelled interval: a diatonic number, a quality label, and its semitone span.
42
- *
43
- * @category Pitch & Intervals
44
- */
45
- type SpelledInterval = {
46
- /** Diatonic size: 1 = unison, 2 = second, ... 8 = octave, and beyond. */
47
- number: number;
48
- /** Quality label: 'P', 'M', 'm', or repeated 'A'/'d' for (multiply) aug/dim. */
49
- quality: IntervalQualityLabel;
50
- /** Signed semitone distance from the first note to the second. */
51
- semitones: number;
52
- /** True when the diatonic letter movement is descending despite a zero span. */
53
- descending?: boolean;
54
- };
55
- /**
56
- * Reduce a MIDI pitch, a bare pitch class, or any signed offset to a pitch
57
- * class in [0, 11].
58
- *
59
- * This is the library's single definition of pitch-class arithmetic: every
60
- * layer routes through it so a fractional pitch reduces the same way
61
- * everywhere. A non-integral input is rounded to the nearest semitone first, so
62
- * a microtonal 60.6 reads as C# rather than C.
63
- *
64
- * @param value A MIDI pitch, pitch class, or signed semitone offset.
65
- * @returns The pitch class in [0, 11].
66
- * @example
67
- * ```ts
68
- * import { pitchClassOf } from '@libraz/libcantus';
69
- * pitchClassOf(61); // 1
70
- * pitchClassOf(-1); // 11
71
- * pitchClassOf(60.6); // 1
72
- * ```
73
- * @category Pitch & Intervals
74
- */
75
- declare function pitchClassOf(value: number): number;
76
- /**
77
- * Reduce a letter number or letter offset to a diatonic letter in [0, 6]
78
- * (0 = C .. 6 = B).
79
- *
80
- * @param value A letter number or signed letter offset.
81
- * @returns The diatonic letter in [0, 6].
82
- * @category Pitch & Intervals
83
- */
84
- declare function diatonicLetterOf(value: number): number;
85
- /**
86
- * The pitch class of a diatonic letter with no accidental (C = 0, D = 2, ...).
87
- *
88
- * @param letter A letter number or signed letter offset; reduced to [0, 6].
89
- * @returns The natural pitch class of that letter.
90
- * @category Pitch & Intervals
91
- */
92
- declare function naturalPitchClassOf(letter: number): number;
93
- /**
94
- * Parse scientific pitch notation into a {@link Note}.
95
- *
96
- * Accepts a letter (case-insensitive) followed by any number of same-direction
97
- * accidentals and an optional octave, e.g. `"C"`, `"C#4"`, `"Bb"`, `"F##3"`,
98
- * `"Ebb2"`. Both `#` and `x` (double-sharp) are accepted for sharps; `b` for
99
- * flats. Mixing sharps and flats (e.g. `"C#b"`) is rejected.
100
- *
101
- * @param text The note text.
102
- * @returns The parsed note.
103
- * @throws If the text is not a valid note.
104
- * @example
105
- * ```ts
106
- * import { parseNote, noteToMidi } from '@libraz/libcantus';
107
- * const n = parseNote('C#4');
108
- * noteToMidi(n); // 61
109
- * ```
110
- * @category Pitch & Intervals
111
- */
112
- declare function parseNote(text: string): Note;
113
- /**
114
- * Render a {@link Note} as scientific pitch notation.
115
- *
116
- * @param note The note to format.
117
- * @returns The note text, including the octave when present.
118
- * @example
119
- * ```ts
120
- * import { formatNote, parseNote } from '@libraz/libcantus';
121
- * formatNote(parseNote('C#4')); // 'C#4'
122
- * ```
123
- * @category Pitch & Intervals
124
- */
125
- declare function formatNote(note: Note): string;
126
- /**
127
- * Pitch class (0..11) of a note, ignoring octave.
128
- *
129
- * @param note The note.
130
- * @returns The pitch class.
131
- * @example
132
- * ```ts
133
- * import { noteToPitchClass, parseNote } from '@libraz/libcantus';
134
- * noteToPitchClass(parseNote('Db')); // 1
135
- * ```
136
- * @category Pitch & Intervals
137
- */
138
- declare function noteToPitchClass(note: Note): number;
139
- /**
140
- * MIDI number of a note (middle C = C4 = 60).
141
- *
142
- * @param note The note; must carry an octave.
143
- * @returns The MIDI number.
144
- * @throws If the note has no octave.
145
- * @example
146
- * ```ts
147
- * import { noteToMidi, parseNote } from '@libraz/libcantus';
148
- * noteToMidi(parseNote('A4')); // 69
149
- * ```
150
- * @category Pitch & Intervals
151
- */
152
- declare function noteToMidi(note: Note): number;
153
- /**
154
- * Name a MIDI number as a {@link Note}, choosing sharp or flat spelling.
155
- *
156
- * The input is rounded to the nearest integer but is not clamped to the MIDI
157
- * range 0..127: out-of-range values extrapolate linearly (e.g. `-1` -> `B-2`,
158
- * `128` -> `G#9`) and remain an exact inverse of {@link noteToMidi}.
159
- *
160
- * @param midi The MIDI number.
161
- * @param spelling Whether to prefer sharps or flats for black keys.
162
- * @returns The spelled note, with octave.
163
- * @example
164
- * ```ts
165
- * import { midiToNote, formatNote } from '@libraz/libcantus';
166
- * formatNote(midiToNote(61)); // 'C#4'
167
- * formatNote(midiToNote(61, 'flat')); // 'Db4'
168
- * ```
169
- * @category Pitch & Intervals
170
- */
171
- declare function midiToNote(midi: number, spelling?: 'sharp' | 'flat'): Note;
172
- /**
173
- * Transpose a note by a signed number of semitones, keeping its spelling.
174
- *
175
- * The letter moves by the diatonic distance of the conventional interval for
176
- * that many semitones and the accidental is recomputed for the new letter, so
177
- * enharmonic identity survives: `Ab4` up a major second is `Bb4`, not `A#4`, and
178
- * the operation is an exact inverse of itself. An octave-less note stays
179
- * octave-less.
180
- *
181
- * A bare semitone count cannot distinguish an augmented fourth from a diminished
182
- * fifth; pass `spelling` to override the letter distance when the enharmonic
183
- * choice matters.
184
- *
185
- * @param note The note to transpose.
186
- * @param semitones The signed semitone offset.
187
- * @param opts `spelling` forces the result onto the sharp or flat side instead
188
- * of following the source note's letter.
189
- * @returns The transposed note.
190
- * @example
191
- * ```ts
192
- * import { transposeNote, formatNote, parseNote } from '@libraz/libcantus';
193
- * formatNote(transposeNote(parseNote('Ab4'), 2)); // 'Bb4'
194
- * formatNote(transposeNote(parseNote('Ab4'), 2, { spelling: 'sharp' })); // 'A#4'
195
- * ```
196
- * @category Pitch & Intervals
197
- */
198
- declare function transposeNote(note: Note, semitones: number, opts?: {
199
- spelling?: 'sharp' | 'flat';
200
- }): Note;
201
- /**
202
- * The semitone span of the interval named by a diatonic number and a quality.
203
- *
204
- * The inverse of the quality derivation in {@link spelledInterval}: it turns a
205
- * name back into a distance, which is what transposing by a named interval or
206
- * parsing one from text needs.
207
- *
208
- * @param numberValue Diatonic size: 1 = unison, 2 = second, ... 8 = octave.
209
- * @param quality Quality label: `'P'`, `'M'`, `'m'`, or repeated `'A'`/`'d'`.
210
- * @returns The unsigned semitone span.
211
- * @throws If the quality cannot apply to the number, such as a major fifth.
212
- * @example
213
- * ```ts
214
- * import { intervalSemitones } from '@libraz/libcantus';
215
- * intervalSemitones(5, 'P'); // 7
216
- * ```
217
- * @category Pitch & Intervals
218
- */
219
- declare function intervalSemitones(numberValue: number, quality: IntervalQualityLabel): number;
220
- /**
221
- * Parse an interval name such as `'P5'`, `'m3'`, or `'AA4'`.
222
- *
223
- * @param name The interval name: a quality label followed by a diatonic number.
224
- * @returns The spelled interval. Diminished unisons have a descending
225
- * (negative) semitone span; all other supported names are ascending.
226
- * @throws If the name is not a quality label followed by a number, or the two
227
- * cannot describe the same interval.
228
- * @example
229
- * ```ts
230
- * import { parseInterval } from '@libraz/libcantus';
231
- * parseInterval('m3'); // { number: 3, quality: 'm', semitones: 3 }
232
- * ```
233
- * @category Pitch & Intervals
234
- */
235
- declare function parseInterval(name: string): SpelledInterval;
236
- /**
237
- * Transpose a note by a spelled interval, keeping the spelling the interval
238
- * names.
239
- *
240
- * Unlike {@link transposeNote}, which picks a letter from the semitone count,
241
- * the diatonic number decides the letter here: transposing C by an augmented
242
- * second gives D#, not Eb.
243
- *
244
- * @param note The note to transpose.
245
- * @param interval The interval to apply; a negative span transposes downward.
246
- * @returns The transposed note, octave-less if the source was.
247
- * @example
248
- * ```ts
249
- * import { formatNote, parseInterval, parseNote, transposeByInterval } from '@libraz/libcantus';
250
- * formatNote(transposeByInterval(parseNote('C4'), parseInterval('A2'))); // 'D#4'
251
- * ```
252
- * @category Pitch & Intervals
253
- */
254
- declare function transposeByInterval(note: Note, interval: SpelledInterval): Note;
255
- /**
256
- * The spelled interval from one note to another.
257
- *
258
- * When both notes carry octaves, the interval reflects their full signed
259
- * distance (so `C4 -> C5` is a perfect octave). When either lacks an octave the
260
- * interval is measured within a single ascending octave from `a` to `b`.
261
- *
262
- * @param a The lower/first note.
263
- * @param b The upper/second note.
264
- * @returns The diatonic number, quality, and semitone span.
265
- * @example
266
- * ```ts
267
- * import { spelledInterval, parseNote } from '@libraz/libcantus';
268
- * spelledInterval(parseNote('C4'), parseNote('G4'));
269
- * // { number: 5, quality: 'P', semitones: 7 }
270
- * ```
271
- * @category Pitch & Intervals
272
- */
273
- declare function spelledInterval(a: Note, b: Note): SpelledInterval;
274
-
275
- export { type IntervalQualityLabel as I, type Note as N, type SpelledInterval as S, noteToMidi as a, noteToPitchClass as b, parseNote as c, diatonicLetterOf as d, pitchClassOf as e, formatNote as f, transposeNote as g, intervalSemitones as i, midiToNote as m, naturalPitchClassOf as n, parseInterval as p, spelledInterval as s, transposeByInterval as t };
@@ -1,275 +0,0 @@
1
- /**
2
- * Pitch spelling: letter-name notes, enharmonic-aware conversion, and spelled
3
- * intervals.
4
- *
5
- * The rest of the library works in pitch classes (0..11), which cannot tell a
6
- * G# from an Ab or an augmented fourth from a diminished fifth. This module adds
7
- * an explicit spelling layer — a note is a diatonic letter plus a chromatic
8
- * alteration — so interval quality (P/M/m/A/d) and enharmonic identity are
9
- * preserved.
10
- */
11
- /**
12
- * A spelled note: a diatonic letter, a chromatic alteration, and an optional
13
- * octave.
14
- *
15
- * - `letter` is 0..6 for C..B.
16
- * - `alter` is the number of semitones of alteration: -2 double-flat, -1 flat,
17
- * 0 natural, +1 sharp, +2 double-sharp.
18
- * - `octave` follows scientific pitch notation (middle C = C4 = MIDI 60). When
19
- * absent, the note denotes a bare pitch class.
20
- *
21
- * @category Pitch & Intervals
22
- */
23
- type Note = {
24
- letter: number;
25
- alter: number;
26
- octave?: number;
27
- };
28
- /**
29
- * The quality label of a spelled interval: perfect, major, minor, or one or
30
- * more augmentations or diminutions.
31
- *
32
- * This names how an interval is *spelled*. It is a different notion from
33
- * {@link ConsonanceClass}, which classifies how an interval *sounds* against
34
- * another voice.
35
- *
36
- * @see {@link ConsonanceClass}
37
- * @category Pitch & Intervals
38
- */
39
- type IntervalQualityLabel = 'P' | 'M' | 'm' | `A${string}` | `d${string}`;
40
- /**
41
- * A spelled interval: a diatonic number, a quality label, and its semitone span.
42
- *
43
- * @category Pitch & Intervals
44
- */
45
- type SpelledInterval = {
46
- /** Diatonic size: 1 = unison, 2 = second, ... 8 = octave, and beyond. */
47
- number: number;
48
- /** Quality label: 'P', 'M', 'm', or repeated 'A'/'d' for (multiply) aug/dim. */
49
- quality: IntervalQualityLabel;
50
- /** Signed semitone distance from the first note to the second. */
51
- semitones: number;
52
- /** True when the diatonic letter movement is descending despite a zero span. */
53
- descending?: boolean;
54
- };
55
- /**
56
- * Reduce a MIDI pitch, a bare pitch class, or any signed offset to a pitch
57
- * class in [0, 11].
58
- *
59
- * This is the library's single definition of pitch-class arithmetic: every
60
- * layer routes through it so a fractional pitch reduces the same way
61
- * everywhere. A non-integral input is rounded to the nearest semitone first, so
62
- * a microtonal 60.6 reads as C# rather than C.
63
- *
64
- * @param value A MIDI pitch, pitch class, or signed semitone offset.
65
- * @returns The pitch class in [0, 11].
66
- * @example
67
- * ```ts
68
- * import { pitchClassOf } from '@libraz/libcantus';
69
- * pitchClassOf(61); // 1
70
- * pitchClassOf(-1); // 11
71
- * pitchClassOf(60.6); // 1
72
- * ```
73
- * @category Pitch & Intervals
74
- */
75
- declare function pitchClassOf(value: number): number;
76
- /**
77
- * Reduce a letter number or letter offset to a diatonic letter in [0, 6]
78
- * (0 = C .. 6 = B).
79
- *
80
- * @param value A letter number or signed letter offset.
81
- * @returns The diatonic letter in [0, 6].
82
- * @category Pitch & Intervals
83
- */
84
- declare function diatonicLetterOf(value: number): number;
85
- /**
86
- * The pitch class of a diatonic letter with no accidental (C = 0, D = 2, ...).
87
- *
88
- * @param letter A letter number or signed letter offset; reduced to [0, 6].
89
- * @returns The natural pitch class of that letter.
90
- * @category Pitch & Intervals
91
- */
92
- declare function naturalPitchClassOf(letter: number): number;
93
- /**
94
- * Parse scientific pitch notation into a {@link Note}.
95
- *
96
- * Accepts a letter (case-insensitive) followed by any number of same-direction
97
- * accidentals and an optional octave, e.g. `"C"`, `"C#4"`, `"Bb"`, `"F##3"`,
98
- * `"Ebb2"`. Both `#` and `x` (double-sharp) are accepted for sharps; `b` for
99
- * flats. Mixing sharps and flats (e.g. `"C#b"`) is rejected.
100
- *
101
- * @param text The note text.
102
- * @returns The parsed note.
103
- * @throws If the text is not a valid note.
104
- * @example
105
- * ```ts
106
- * import { parseNote, noteToMidi } from '@libraz/libcantus';
107
- * const n = parseNote('C#4');
108
- * noteToMidi(n); // 61
109
- * ```
110
- * @category Pitch & Intervals
111
- */
112
- declare function parseNote(text: string): Note;
113
- /**
114
- * Render a {@link Note} as scientific pitch notation.
115
- *
116
- * @param note The note to format.
117
- * @returns The note text, including the octave when present.
118
- * @example
119
- * ```ts
120
- * import { formatNote, parseNote } from '@libraz/libcantus';
121
- * formatNote(parseNote('C#4')); // 'C#4'
122
- * ```
123
- * @category Pitch & Intervals
124
- */
125
- declare function formatNote(note: Note): string;
126
- /**
127
- * Pitch class (0..11) of a note, ignoring octave.
128
- *
129
- * @param note The note.
130
- * @returns The pitch class.
131
- * @example
132
- * ```ts
133
- * import { noteToPitchClass, parseNote } from '@libraz/libcantus';
134
- * noteToPitchClass(parseNote('Db')); // 1
135
- * ```
136
- * @category Pitch & Intervals
137
- */
138
- declare function noteToPitchClass(note: Note): number;
139
- /**
140
- * MIDI number of a note (middle C = C4 = 60).
141
- *
142
- * @param note The note; must carry an octave.
143
- * @returns The MIDI number.
144
- * @throws If the note has no octave.
145
- * @example
146
- * ```ts
147
- * import { noteToMidi, parseNote } from '@libraz/libcantus';
148
- * noteToMidi(parseNote('A4')); // 69
149
- * ```
150
- * @category Pitch & Intervals
151
- */
152
- declare function noteToMidi(note: Note): number;
153
- /**
154
- * Name a MIDI number as a {@link Note}, choosing sharp or flat spelling.
155
- *
156
- * The input is rounded to the nearest integer but is not clamped to the MIDI
157
- * range 0..127: out-of-range values extrapolate linearly (e.g. `-1` -> `B-2`,
158
- * `128` -> `G#9`) and remain an exact inverse of {@link noteToMidi}.
159
- *
160
- * @param midi The MIDI number.
161
- * @param spelling Whether to prefer sharps or flats for black keys.
162
- * @returns The spelled note, with octave.
163
- * @example
164
- * ```ts
165
- * import { midiToNote, formatNote } from '@libraz/libcantus';
166
- * formatNote(midiToNote(61)); // 'C#4'
167
- * formatNote(midiToNote(61, 'flat')); // 'Db4'
168
- * ```
169
- * @category Pitch & Intervals
170
- */
171
- declare function midiToNote(midi: number, spelling?: 'sharp' | 'flat'): Note;
172
- /**
173
- * Transpose a note by a signed number of semitones, keeping its spelling.
174
- *
175
- * The letter moves by the diatonic distance of the conventional interval for
176
- * that many semitones and the accidental is recomputed for the new letter, so
177
- * enharmonic identity survives: `Ab4` up a major second is `Bb4`, not `A#4`, and
178
- * the operation is an exact inverse of itself. An octave-less note stays
179
- * octave-less.
180
- *
181
- * A bare semitone count cannot distinguish an augmented fourth from a diminished
182
- * fifth; pass `spelling` to override the letter distance when the enharmonic
183
- * choice matters.
184
- *
185
- * @param note The note to transpose.
186
- * @param semitones The signed semitone offset.
187
- * @param opts `spelling` forces the result onto the sharp or flat side instead
188
- * of following the source note's letter.
189
- * @returns The transposed note.
190
- * @example
191
- * ```ts
192
- * import { transposeNote, formatNote, parseNote } from '@libraz/libcantus';
193
- * formatNote(transposeNote(parseNote('Ab4'), 2)); // 'Bb4'
194
- * formatNote(transposeNote(parseNote('Ab4'), 2, { spelling: 'sharp' })); // 'A#4'
195
- * ```
196
- * @category Pitch & Intervals
197
- */
198
- declare function transposeNote(note: Note, semitones: number, opts?: {
199
- spelling?: 'sharp' | 'flat';
200
- }): Note;
201
- /**
202
- * The semitone span of the interval named by a diatonic number and a quality.
203
- *
204
- * The inverse of the quality derivation in {@link spelledInterval}: it turns a
205
- * name back into a distance, which is what transposing by a named interval or
206
- * parsing one from text needs.
207
- *
208
- * @param numberValue Diatonic size: 1 = unison, 2 = second, ... 8 = octave.
209
- * @param quality Quality label: `'P'`, `'M'`, `'m'`, or repeated `'A'`/`'d'`.
210
- * @returns The unsigned semitone span.
211
- * @throws If the quality cannot apply to the number, such as a major fifth.
212
- * @example
213
- * ```ts
214
- * import { intervalSemitones } from '@libraz/libcantus';
215
- * intervalSemitones(5, 'P'); // 7
216
- * ```
217
- * @category Pitch & Intervals
218
- */
219
- declare function intervalSemitones(numberValue: number, quality: IntervalQualityLabel): number;
220
- /**
221
- * Parse an interval name such as `'P5'`, `'m3'`, or `'AA4'`.
222
- *
223
- * @param name The interval name: a quality label followed by a diatonic number.
224
- * @returns The spelled interval. Diminished unisons have a descending
225
- * (negative) semitone span; all other supported names are ascending.
226
- * @throws If the name is not a quality label followed by a number, or the two
227
- * cannot describe the same interval.
228
- * @example
229
- * ```ts
230
- * import { parseInterval } from '@libraz/libcantus';
231
- * parseInterval('m3'); // { number: 3, quality: 'm', semitones: 3 }
232
- * ```
233
- * @category Pitch & Intervals
234
- */
235
- declare function parseInterval(name: string): SpelledInterval;
236
- /**
237
- * Transpose a note by a spelled interval, keeping the spelling the interval
238
- * names.
239
- *
240
- * Unlike {@link transposeNote}, which picks a letter from the semitone count,
241
- * the diatonic number decides the letter here: transposing C by an augmented
242
- * second gives D#, not Eb.
243
- *
244
- * @param note The note to transpose.
245
- * @param interval The interval to apply; a negative span transposes downward.
246
- * @returns The transposed note, octave-less if the source was.
247
- * @example
248
- * ```ts
249
- * import { formatNote, parseInterval, parseNote, transposeByInterval } from '@libraz/libcantus';
250
- * formatNote(transposeByInterval(parseNote('C4'), parseInterval('A2'))); // 'D#4'
251
- * ```
252
- * @category Pitch & Intervals
253
- */
254
- declare function transposeByInterval(note: Note, interval: SpelledInterval): Note;
255
- /**
256
- * The spelled interval from one note to another.
257
- *
258
- * When both notes carry octaves, the interval reflects their full signed
259
- * distance (so `C4 -> C5` is a perfect octave). When either lacks an octave the
260
- * interval is measured within a single ascending octave from `a` to `b`.
261
- *
262
- * @param a The lower/first note.
263
- * @param b The upper/second note.
264
- * @returns The diatonic number, quality, and semitone span.
265
- * @example
266
- * ```ts
267
- * import { spelledInterval, parseNote } from '@libraz/libcantus';
268
- * spelledInterval(parseNote('C4'), parseNote('G4'));
269
- * // { number: 5, quality: 'P', semitones: 7 }
270
- * ```
271
- * @category Pitch & Intervals
272
- */
273
- declare function spelledInterval(a: Note, b: Note): SpelledInterval;
274
-
275
- export { type IntervalQualityLabel as I, type Note as N, type SpelledInterval as S, noteToMidi as a, noteToPitchClass as b, parseNote as c, diatonicLetterOf as d, pitchClassOf as e, formatNote as f, transposeNote as g, intervalSemitones as i, midiToNote as m, naturalPitchClassOf as n, parseInterval as p, spelledInterval as s, transposeByInterval as t };