polyphon 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +374 -2
  3. package/README.zh-TW.md +375 -0
  4. package/dist/engine/automation.d.ts +24 -0
  5. package/dist/engine/automation.d.ts.map +1 -0
  6. package/dist/engine/automation.js +55 -0
  7. package/dist/engine/automation.js.map +1 -0
  8. package/dist/engine/compile.d.ts +36 -0
  9. package/dist/engine/compile.d.ts.map +1 -0
  10. package/dist/engine/compile.js +103 -0
  11. package/dist/engine/compile.js.map +1 -0
  12. package/dist/engine/jukebox.d.ts +113 -0
  13. package/dist/engine/jukebox.d.ts.map +1 -0
  14. package/dist/engine/jukebox.js +287 -0
  15. package/dist/engine/jukebox.js.map +1 -0
  16. package/dist/engine/mixer.d.ts +29 -0
  17. package/dist/engine/mixer.d.ts.map +1 -0
  18. package/dist/engine/mixer.js +141 -0
  19. package/dist/engine/mixer.js.map +1 -0
  20. package/dist/engine/output.d.ts +14 -0
  21. package/dist/engine/output.d.ts.map +1 -0
  22. package/dist/engine/output.js +51 -0
  23. package/dist/engine/output.js.map +1 -0
  24. package/dist/engine/playback.d.ts +97 -0
  25. package/dist/engine/playback.d.ts.map +1 -0
  26. package/dist/engine/playback.js +311 -0
  27. package/dist/engine/playback.js.map +1 -0
  28. package/dist/engine/prepare.d.ts +6 -0
  29. package/dist/engine/prepare.d.ts.map +1 -0
  30. package/dist/engine/prepare.js +12 -0
  31. package/dist/engine/prepare.js.map +1 -0
  32. package/dist/engine/render.d.ts +14 -0
  33. package/dist/engine/render.d.ts.map +1 -0
  34. package/dist/engine/render.js +60 -0
  35. package/dist/engine/render.js.map +1 -0
  36. package/dist/index.d.ts +17 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +25 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/instruments/bowed.d.ts +357 -0
  41. package/dist/instruments/bowed.d.ts.map +1 -0
  42. package/dist/instruments/bowed.js +502 -0
  43. package/dist/instruments/bowed.js.map +1 -0
  44. package/dist/instruments/builtin.d.ts +261 -0
  45. package/dist/instruments/builtin.d.ts.map +1 -0
  46. package/dist/instruments/builtin.js +160 -0
  47. package/dist/instruments/builtin.js.map +1 -0
  48. package/dist/instruments/definition.d.ts +46 -0
  49. package/dist/instruments/definition.d.ts.map +1 -0
  50. package/dist/instruments/definition.js +5 -0
  51. package/dist/instruments/definition.js.map +1 -0
  52. package/dist/instruments/dsp/ambience.d.ts +17 -0
  53. package/dist/instruments/dsp/ambience.d.ts.map +1 -0
  54. package/dist/instruments/dsp/ambience.js +146 -0
  55. package/dist/instruments/dsp/ambience.js.map +1 -0
  56. package/dist/instruments/dsp/core.d.ts +22 -0
  57. package/dist/instruments/dsp/core.d.ts.map +1 -0
  58. package/dist/instruments/dsp/core.js +100 -0
  59. package/dist/instruments/dsp/core.js.map +1 -0
  60. package/dist/instruments/dsp/drums.d.ts +112 -0
  61. package/dist/instruments/dsp/drums.d.ts.map +1 -0
  62. package/dist/instruments/dsp/drums.js +566 -0
  63. package/dist/instruments/dsp/drums.js.map +1 -0
  64. package/dist/instruments/dsp/modal.d.ts +30 -0
  65. package/dist/instruments/dsp/modal.d.ts.map +1 -0
  66. package/dist/instruments/dsp/modal.js +54 -0
  67. package/dist/instruments/dsp/modal.js.map +1 -0
  68. package/dist/instruments/dsp/piano.d.ts +9 -0
  69. package/dist/instruments/dsp/piano.d.ts.map +1 -0
  70. package/dist/instruments/dsp/piano.js +230 -0
  71. package/dist/instruments/dsp/piano.js.map +1 -0
  72. package/dist/instruments/dsp/pluck.d.ts +53 -0
  73. package/dist/instruments/dsp/pluck.d.ts.map +1 -0
  74. package/dist/instruments/dsp/pluck.js +195 -0
  75. package/dist/instruments/dsp/pluck.js.map +1 -0
  76. package/dist/instruments/dsp/reverb.d.ts +16 -0
  77. package/dist/instruments/dsp/reverb.d.ts.map +1 -0
  78. package/dist/instruments/dsp/reverb.js +47 -0
  79. package/dist/instruments/dsp/reverb.js.map +1 -0
  80. package/dist/instruments/dsp/staccato.d.ts +18 -0
  81. package/dist/instruments/dsp/staccato.d.ts.map +1 -0
  82. package/dist/instruments/dsp/staccato.js +147 -0
  83. package/dist/instruments/dsp/staccato.js.map +1 -0
  84. package/dist/instruments/play.d.ts +21 -0
  85. package/dist/instruments/play.d.ts.map +1 -0
  86. package/dist/instruments/play.js +140 -0
  87. package/dist/instruments/play.js.map +1 -0
  88. package/dist/instruments/registry.d.ts +63 -0
  89. package/dist/instruments/registry.d.ts.map +1 -0
  90. package/dist/instruments/registry.js +50 -0
  91. package/dist/instruments/registry.js.map +1 -0
  92. package/dist/instruments/samples.d.ts +30 -0
  93. package/dist/instruments/samples.d.ts.map +1 -0
  94. package/dist/instruments/samples.js +109 -0
  95. package/dist/instruments/samples.js.map +1 -0
  96. package/dist/instruments/voices.d.ts +76 -0
  97. package/dist/instruments/voices.d.ts.map +1 -0
  98. package/dist/instruments/voices.js +1061 -0
  99. package/dist/instruments/voices.js.map +1 -0
  100. package/dist/midi.d.ts +15 -0
  101. package/dist/midi.d.ts.map +1 -0
  102. package/dist/midi.js +280 -0
  103. package/dist/midi.js.map +1 -0
  104. package/dist/notation/format.d.ts +12 -0
  105. package/dist/notation/format.d.ts.map +1 -0
  106. package/dist/notation/format.js +102 -0
  107. package/dist/notation/format.js.map +1 -0
  108. package/dist/notation/harmony.d.ts +83 -0
  109. package/dist/notation/harmony.d.ts.map +1 -0
  110. package/dist/notation/harmony.js +191 -0
  111. package/dist/notation/harmony.js.map +1 -0
  112. package/dist/notation/melody.d.ts +25 -0
  113. package/dist/notation/melody.d.ts.map +1 -0
  114. package/dist/notation/melody.js +138 -0
  115. package/dist/notation/melody.js.map +1 -0
  116. package/dist/notation/part.d.ts +34 -0
  117. package/dist/notation/part.d.ts.map +1 -0
  118. package/dist/notation/part.js +15 -0
  119. package/dist/notation/part.js.map +1 -0
  120. package/dist/notation/transform.d.ts +28 -0
  121. package/dist/notation/transform.d.ts.map +1 -0
  122. package/dist/notation/transform.js +67 -0
  123. package/dist/notation/transform.js.map +1 -0
  124. package/dist/song.d.ts +140 -0
  125. package/dist/song.d.ts.map +1 -0
  126. package/dist/song.js +45 -0
  127. package/dist/song.js.map +1 -0
  128. package/dist/tempo.d.ts +36 -0
  129. package/dist/tempo.d.ts.map +1 -0
  130. package/dist/tempo.js +81 -0
  131. package/dist/tempo.js.map +1 -0
  132. package/dist/theory.d.ts +70 -0
  133. package/dist/theory.d.ts.map +1 -0
  134. package/dist/theory.js +183 -0
  135. package/dist/theory.js.map +1 -0
  136. package/dist/transcribe.d.ts +81 -0
  137. package/dist/transcribe.d.ts.map +1 -0
  138. package/dist/transcribe.js +433 -0
  139. package/dist/transcribe.js.map +1 -0
  140. package/package.json +57 -4
  141. package/src/engine/automation.ts +65 -0
  142. package/src/engine/compile.ts +124 -0
  143. package/src/engine/jukebox.ts +322 -0
  144. package/src/engine/mixer.ts +166 -0
  145. package/src/engine/output.ts +59 -0
  146. package/src/engine/playback.ts +349 -0
  147. package/src/engine/prepare.ts +15 -0
  148. package/src/engine/render.ts +71 -0
  149. package/src/index.ts +28 -0
  150. package/src/instruments/bowed.ts +660 -0
  151. package/src/instruments/builtin.ts +180 -0
  152. package/src/instruments/definition.ts +52 -0
  153. package/src/instruments/dsp/ambience.ts +142 -0
  154. package/src/instruments/dsp/core.ts +97 -0
  155. package/src/instruments/dsp/drums.ts +565 -0
  156. package/src/instruments/dsp/modal.ts +76 -0
  157. package/src/instruments/dsp/piano.ts +226 -0
  158. package/src/instruments/dsp/pluck.ts +240 -0
  159. package/src/instruments/dsp/reverb.ts +56 -0
  160. package/src/instruments/dsp/staccato.ts +141 -0
  161. package/src/instruments/play.ts +151 -0
  162. package/src/instruments/registry.ts +100 -0
  163. package/src/instruments/samples.ts +119 -0
  164. package/src/instruments/voices.ts +1168 -0
  165. package/src/midi.ts +285 -0
  166. package/src/notation/format.ts +96 -0
  167. package/src/notation/harmony.ts +233 -0
  168. package/src/notation/melody.ts +133 -0
  169. package/src/notation/part.ts +42 -0
  170. package/src/notation/transform.ts +78 -0
  171. package/src/song.ts +170 -0
  172. package/src/tempo.ts +108 -0
  173. package/src/theory.ts +208 -0
  174. package/src/transcribe.ts +487 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/notation/transform.ts"],"names":[],"mappings":"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"}
package/dist/song.d.ts ADDED
@@ -0,0 +1,140 @@
1
+ import type { Room } from './instruments/dsp/reverb.ts';
2
+ import type { InstrumentName } from './instruments/registry.ts';
3
+ import { type Meter, type Part } from './notation/part.ts';
4
+ import { type TempoChange } from './tempo.ts';
5
+ export interface Song {
6
+ title: string;
7
+ /** One line on the mood and the instrumentation */
8
+ description?: string;
9
+ /** Beats (quarter notes) per minute: the tempo the song starts at */
10
+ bpm: number;
11
+ /** Changes of tempo along the way: at once (a new section) or gliding (ritardando, accelerando) */
12
+ tempo?: TempoChange[];
13
+ /** Dead stops: moments where everything falls silent, the room's echo too, before the music crashes back in */
14
+ silences?: Silence[];
15
+ /** Time signature (default '4/4') */
16
+ meter?: Meter;
17
+ /** Eighth-note swing 0-0.5 (0.33 is roughly a triplet feel) */
18
+ swing?: number;
19
+ /** Sixteenth-note swing 0-0.5 */
20
+ swing16?: number;
21
+ /** The room (default: a medium hall) */
22
+ reverb?: Reverb;
23
+ /** A tempo-synced stereo ping-pong delay that tracks can send to */
24
+ delay?: Delay;
25
+ /** Level of the whole song (linear, default 1) */
26
+ gain?: number;
27
+ /** Mastering: EQ, glue compression and, for loud genres, a limiter */
28
+ master?: Master;
29
+ /** Plays once before the tracks start looping */
30
+ intro?: Track[];
31
+ /** The body of the song; loops unless `loop` is false */
32
+ tracks: Track[];
33
+ /** false: play the body once and end (jingles, fanfares). Default true */
34
+ loop?: boolean;
35
+ }
36
+ export interface Track {
37
+ /** Shown in mixers; defaults to the instrument name */
38
+ name?: string;
39
+ instrument: InstrumentName;
40
+ /** The notes: a part, or a melody string read in the song's meter */
41
+ part: Part | string;
42
+ /** Level (linear, default 1) */
43
+ gain?: number;
44
+ /** -1 left to 1 right */
45
+ pan?: number;
46
+ /** How much goes to the reverb, 0-1 (default 0.25) */
47
+ reverb?: number;
48
+ /** How much goes to the delay, 0-1 (default 0) */
49
+ delay?: number;
50
+ /** Duck under another track's hits, the pumping of house and EDM: that track's name (usually 'Kick'), or how deep and how long too */
51
+ duck?: string | Duck;
52
+ /** Low-pass filter: a cutoff in Hz, or a sweep */
53
+ lowpass?: number | Sweep;
54
+ /** High-pass filter: a cutoff in Hz, or a sweep */
55
+ highpass?: number | Sweep;
56
+ /** Semitones */
57
+ transpose?: number;
58
+ /** Timing looseness: the most a note may land early or late, in seconds (default 0.008, drums 0.003) */
59
+ humanize?: number;
60
+ /** Instrument settings, such as attack, release, bright, glide */
61
+ params?: Record<string, number>;
62
+ /** false: play once at the start of the section instead of repeating to fill it. Default true */
63
+ repeat?: boolean;
64
+ }
65
+ /**
66
+ * A dead stop from `bar` (counted from 1 at the start of the song, the intro's bars first; fractional to start mid-bar, so 32.75 is the
67
+ * last beat of bar 32) for `beats` quarter notes. Everything falls silent, the reverb and delay tails too, as if the room were switched off,
68
+ * and comes back at full level when it ends. A silence in the body happens on every pass.
69
+ */
70
+ export interface Silence {
71
+ bar: number;
72
+ beats: number;
73
+ }
74
+ export interface Reverb extends Room {
75
+ /** Level of the reverb return (default 1) */
76
+ mix?: number;
77
+ }
78
+ export interface Delay {
79
+ /** Delay time, in sixteenth-note steps at the song's opening tempo */
80
+ steps: number;
81
+ /** Echo feedback 0-1 (default 0.35) */
82
+ feedback?: number;
83
+ /** Low-pass on the echoes, Hz (default 2800) */
84
+ tone?: number;
85
+ /** Level of the delay return (default 0.8) */
86
+ mix?: number;
87
+ }
88
+ /** Sidechain pumping: at every hit of another track (usually the kick) the level dips, then swells back */
89
+ export interface Duck {
90
+ /** The name of the track whose hits duck this one, in the same section (it pumps even while that track is muted) */
91
+ by: string;
92
+ /** How far the level dips, 0-1 (default 0.7) */
93
+ depth?: number;
94
+ /** Steps until it is back up, at the song's opening tempo (default 4: a beat) */
95
+ release?: number;
96
+ }
97
+ /**
98
+ * A filter sweep, { step: Hz }, counted from the start of the section: the cutoff glides from one to the next (evenly in pitch) and
99
+ * holds before the first and after the last. `{ 0: 400, 128: 400, 256: 18000 }` stays dark for eight bars, then opens over eight more.
100
+ */
101
+ export type Sweep = Record<number, number>;
102
+ export interface Master {
103
+ /** Body at 150 Hz, dB */
104
+ warm?: number;
105
+ /** Pulls 1.3 kHz down, dB */
106
+ cut?: number;
107
+ /** Level of the mix, dB */
108
+ trim?: number;
109
+ /** Bus compression that glues the mix together, 0-1 (0.3 gentle, 0.6 firm) */
110
+ glue?: number;
111
+ /** Master loud: dB pushed into a brickwall limiter that keeps the peaks under -1 dBFS, between the samples too (EDM: about 6-10). The song then bypasses the gentle limiter other songs share */
112
+ loud?: number;
113
+ }
114
+ export declare const DEFAULT_REVERB: Reverb;
115
+ /**
116
+ * Declare a song. It returns the song unchanged; it exists so editors can type-check and autocomplete it.
117
+ *
118
+ * @example
119
+ * export default defineSong({
120
+ * title: 'Morning Market',
121
+ * bpm: 112,
122
+ * tracks: [
123
+ * { instrument: 'marimba', part: 'C5:2 E5 G5 E5 | D5:4 B4:4 G4:8 |' },
124
+ * { instrument: 'pizzBass', part: bassline(chords('C | G'), 'x...x...x...x...', '1 5') },
125
+ * ],
126
+ * });
127
+ */
128
+ export declare function defineSong(song: Song): Song;
129
+ /** A track's name: its own, or its instrument's */
130
+ export declare function trackName(track: Track): string;
131
+ /** The part a track plays (melody strings are read in the song's meter) */
132
+ export declare function trackPart(track: Track, meter: Meter): Part;
133
+ /** Length of a section whose tracks have these parts: the longest, rounded up to whole bars (at least one bar) */
134
+ export declare function sectionSteps(parts: Part[], meter: Meter): number;
135
+ /** How long the intro and one pass of the body last, in seconds */
136
+ export declare function songDuration(song: Song): {
137
+ intro: number;
138
+ loop: number;
139
+ };
140
+ //# sourceMappingURL=song.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"song.d.ts","sourceRoot":"","sources":["../src/song.ts"],"names":[],"mappings":"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"}
package/dist/song.js ADDED
@@ -0,0 +1,45 @@
1
+ // A song is plain data: tempo, the room it plays in, and tracks that pair an instrument with a part.
2
+ import { melody } from './notation/melody.js';
3
+ import { stepsPerBar } from './notation/part.js';
4
+ import { tempoClock } from './tempo.js';
5
+ export const DEFAULT_REVERB = { size: 1.8, damp: 0.45 };
6
+ /**
7
+ * Declare a song. It returns the song unchanged; it exists so editors can type-check and autocomplete it.
8
+ *
9
+ * @example
10
+ * export default defineSong({
11
+ * title: 'Morning Market',
12
+ * bpm: 112,
13
+ * tracks: [
14
+ * { instrument: 'marimba', part: 'C5:2 E5 G5 E5 | D5:4 B4:4 G4:8 |' },
15
+ * { instrument: 'pizzBass', part: bassline(chords('C | G'), 'x...x...x...x...', '1 5') },
16
+ * ],
17
+ * });
18
+ */
19
+ export function defineSong(song) {
20
+ return song;
21
+ }
22
+ /** A track's name: its own, or its instrument's */
23
+ export function trackName(track) {
24
+ return track.name ?? track.instrument;
25
+ }
26
+ /** The part a track plays (melody strings are read in the song's meter) */
27
+ export function trackPart(track, meter) {
28
+ return typeof track.part === 'string' ? melody(track.part, meter) : track.part;
29
+ }
30
+ /** Length of a section whose tracks have these parts: the longest, rounded up to whole bars (at least one bar) */
31
+ export function sectionSteps(parts, meter) {
32
+ const bar = stepsPerBar(meter);
33
+ const longest = Math.max(bar, ...parts.map((p) => p.duration));
34
+ return Math.ceil(longest / bar - 1e-6) * bar;
35
+ }
36
+ /** How long the intro and one pass of the body last, in seconds */
37
+ export function songDuration(song) {
38
+ const meter = song.meter ?? 16;
39
+ const steps = (tracks) => sectionSteps(tracks.map((t) => trackPart(t, meter)), meter);
40
+ const clock = tempoClock(song);
41
+ const introSteps = song.intro?.length ? steps(song.intro) : 0;
42
+ const intro = clock.seconds(introSteps);
43
+ return { intro, loop: clock.seconds(introSteps + steps(song.tracks)) - intro };
44
+ }
45
+ //# sourceMappingURL=song.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"song.js","sourceRoot":"","sources":["../src/song.ts"],"names":[],"mappings":"AAAA,qGAAqG;AAIrG,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAyB,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAoB,MAAM,YAAY,CAAC;AAuH1D,MAAM,CAAC,MAAM,cAAc,GAAW,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAEhE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,IAAU;IACnC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,SAAS,CAAC,KAAY;IACpC,OAAO,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC;AACxC,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,SAAS,CAAC,KAAY,EAAE,KAAY;IAClD,OAAO,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AACjF,CAAC;AAED,kHAAkH;AAClH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,KAAY;IACtD,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC;AAC/C,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,CAAC,MAAe,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/F,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACxC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC;AACjF,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { type Meter } from './notation/part.ts';
2
+ /**
3
+ * A change of tempo at the start of a bar, counted from 1 at the start of the song (the intro's bars first, then the body's).
4
+ * `{ bar: 90, bpm: 66 }` is a new tempo from bar 90; `{ bar: 120, bpm: 80, over: 4 }` slows down evenly to 80 across bars 120 to 123.
5
+ * A bar may be fractional to change mid-bar: 12.5 is halfway through bar 12.
6
+ */
7
+ export interface TempoChange {
8
+ bar: number;
9
+ /** Beats (quarter notes) per minute */
10
+ bpm: number;
11
+ /** How many bars the change takes, gliding evenly from the tempo before it (default 0: at once) */
12
+ over?: number;
13
+ }
14
+ /** A song's tempo through its score: positions in steps from the start of the song, as seconds and back */
15
+ export interface TempoClock {
16
+ /** Seconds from the start of the song to a step */
17
+ seconds(step: number): number;
18
+ /** The step the song has reached after `seconds` */
19
+ step(seconds: number): number;
20
+ /** Beats per minute at a step */
21
+ bpm(step: number): number;
22
+ }
23
+ /**
24
+ * The clock of a song (its `bpm`, `tempo` and `meter`). Each pass of a looping body plays the same changes: the body's steps follow
25
+ * the intro's, so a body step's time within its pass is `seconds(introSteps + step) - seconds(introSteps)`.
26
+ *
27
+ * @example
28
+ * const clock = tempoClock({ bpm: 120, meter: '3/4', tempo: [{ bar: 9, bpm: 60 }] });
29
+ * clock.seconds(8 * 12 + 4); // 12 + 0.25 * 4 = 13: eight bars at 120, then a beat at 60
30
+ */
31
+ export declare function tempoClock({ bpm, tempo, meter }: {
32
+ bpm: number;
33
+ tempo?: readonly TempoChange[];
34
+ meter?: Meter;
35
+ }): TempoClock;
36
+ //# sourceMappingURL=tempo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tempo.d.ts","sourceRoot":"","sources":["../src/tempo.ts"],"names":[],"mappings":"AAGA,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE7D;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,mGAAmG;IACnG,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,2GAA2G;AAC3G,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,oDAAoD;IACpD,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,iCAAiC;IACjC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAeD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,EAAE,GAAG,EAAE,KAAU,EAAE,KAAK,EAAE,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG,UAAU,CA8CjI"}
package/dist/tempo.js ADDED
@@ -0,0 +1,81 @@
1
+ // Tempo through a song: changes at once (a new section) or gradually (ritardando, accelerando), and the clock that turns positions in
2
+ // the score into seconds.
3
+ import { stepsPerBar } from './notation/part.js';
4
+ /** Seconds a step lasts at a tempo: 60 / bpm / 4 */
5
+ const stepSeconds = (bpm) => 15 / bpm;
6
+ /**
7
+ * The clock of a song (its `bpm`, `tempo` and `meter`). Each pass of a looping body plays the same changes: the body's steps follow
8
+ * the intro's, so a body step's time within its pass is `seconds(introSteps + step) - seconds(introSteps)`.
9
+ *
10
+ * @example
11
+ * const clock = tempoClock({ bpm: 120, meter: '3/4', tempo: [{ bar: 9, bpm: 60 }] });
12
+ * clock.seconds(8 * 12 + 4); // 12 + 0.25 * 4 = 13: eight bars at 120, then a beat at 60
13
+ */
14
+ export function tempoClock({ bpm, tempo = [], meter }) {
15
+ const bar = stepsPerBar(meter);
16
+ if (!(bpm > 0))
17
+ throw new Error(`Invalid tempo: ${bpm} bpm`);
18
+ const spans = [{ step: 0, bpm, seconds: 0, slope: 0 }];
19
+ /** Hold or glide from the end of the last span to `step`, arriving at `target` bpm */
20
+ const to = (step, target) => {
21
+ const last = spans[spans.length - 1];
22
+ if (step <= last.step)
23
+ return;
24
+ last.slope = (target - last.bpm) / (step - last.step);
25
+ spans.push({ step, bpm: target, seconds: last.seconds + within(last, step - last.step), slope: 0 });
26
+ };
27
+ for (const change of [...tempo].sort((a, b) => a.bar - b.bar)) {
28
+ const start = (change.bar - 1) * bar;
29
+ const end = start + (change.over ?? 0) * bar;
30
+ const before = spans[spans.length - 1];
31
+ if (!(change.bpm > 0) || !(change.bar >= 1) || !(end >= start))
32
+ throw new Error(`Invalid tempo change: ${JSON.stringify(change)}`);
33
+ if (start < before.step - 1e-9)
34
+ throw new Error(`The tempo change at bar ${change.bar} starts before the change before it has finished`);
35
+ to(start, before.bpm);
36
+ if (end > start)
37
+ to(end, change.bpm);
38
+ else
39
+ spans[spans.length - 1].bpm = change.bpm;
40
+ }
41
+ /** The last span starting at or before `value` (a MIDI file's rubato can make thousands) */
42
+ const spanAt = (key, value) => {
43
+ let lo = 0;
44
+ let hi = spans.length - 1;
45
+ while (lo < hi) {
46
+ const mid = (lo + hi + 1) >> 1;
47
+ if (spans[mid][key] <= value)
48
+ lo = mid;
49
+ else
50
+ hi = mid - 1;
51
+ }
52
+ return spans[lo];
53
+ };
54
+ return {
55
+ seconds: (step) => {
56
+ const span = spanAt('step', step);
57
+ return span.seconds + within(span, step - span.step);
58
+ },
59
+ step: (seconds) => {
60
+ const span = spanAt('seconds', seconds);
61
+ return span.step + stepsWithin(span, seconds - span.seconds);
62
+ },
63
+ bpm: (step) => {
64
+ const span = spanAt('step', step);
65
+ return span.bpm + span.slope * Math.max(0, step - span.step);
66
+ },
67
+ };
68
+ }
69
+ /** Seconds for the first `steps` of a span: the tempo glides linearly, so the time is the integral of 15 / bpm(step) */
70
+ function within({ bpm, slope }, steps) {
71
+ if (Math.abs(slope) < 1e-12 || steps <= 0)
72
+ return steps * stepSeconds(bpm);
73
+ return (15 / slope) * Math.log(1 + (slope * steps) / bpm);
74
+ }
75
+ /** Steps a span covers in its first `seconds` (the inverse of `within`) */
76
+ function stepsWithin({ bpm, slope }, seconds) {
77
+ if (Math.abs(slope) < 1e-12 || seconds <= 0)
78
+ return seconds / stepSeconds(bpm);
79
+ return (bpm / slope) * Math.expm1((slope * seconds) / 15);
80
+ }
81
+ //# sourceMappingURL=tempo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tempo.js","sourceRoot":"","sources":["../src/tempo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /** A pitch: a note name such as 'C4', 'F#3', 'Bb5', or a MIDI number (C4 = 60) */
2
+ export type Pitch = string | number;
3
+ /** Note name (or MIDI number) to MIDI: C4 = 60. Supports #, b, ##, bb */
4
+ export declare function midi(pitch: Pitch): number;
5
+ /** Frequency in Hz (A4 = 440) */
6
+ export declare const frequency: (pitch: Pitch) => number;
7
+ /** MIDI to a note name: 61 → 'C#4' */
8
+ export declare const noteName: (m: number) => string;
9
+ /** Modes and scales (semitones relative to the tonic) */
10
+ export declare const MODES: {
11
+ readonly ionian: readonly [0, 2, 4, 5, 7, 9, 11];
12
+ readonly dorian: readonly [0, 2, 3, 5, 7, 9, 10];
13
+ readonly phrygian: readonly [0, 1, 3, 5, 7, 8, 10];
14
+ readonly lydian: readonly [0, 2, 4, 6, 7, 9, 11];
15
+ readonly mixolydian: readonly [0, 2, 4, 5, 7, 9, 10];
16
+ readonly aeolian: readonly [0, 2, 3, 5, 7, 8, 10];
17
+ readonly locrian: readonly [0, 1, 3, 5, 6, 8, 10];
18
+ readonly harmonicMinor: readonly [0, 2, 3, 5, 7, 8, 11];
19
+ readonly melodicMinor: readonly [0, 2, 3, 5, 7, 9, 11];
20
+ /** Phrygian dominant scale (Spanish / Middle Eastern flavour) */
21
+ readonly phrygianDom: readonly [0, 1, 4, 5, 7, 8, 10];
22
+ /** Hungarian minor (the Gypsy flavour of the augmented fourth) */
23
+ readonly hungarianMinor: readonly [0, 2, 3, 6, 7, 8, 11];
24
+ readonly lydianDom: readonly [0, 2, 4, 6, 7, 9, 10];
25
+ /** Double harmonic (Byzantine) scale */
26
+ readonly doubleHarmonic: readonly [0, 1, 4, 5, 7, 8, 11];
27
+ readonly majorPent: readonly [0, 2, 4, 7, 9];
28
+ readonly minorPent: readonly [0, 3, 5, 7, 10];
29
+ /** Japanese miyako-bushi (the In scale), used only to give the Rift an alien feel */
30
+ readonly inSen: readonly [0, 1, 5, 7, 10];
31
+ readonly wholeTone: readonly [0, 2, 4, 6, 8, 10];
32
+ /** Half-whole diminished scale */
33
+ readonly octatonic: readonly [0, 1, 3, 4, 6, 7, 9, 10];
34
+ };
35
+ export type Mode = keyof typeof MODES;
36
+ /** A parsed chord symbol */
37
+ export interface ChordInfo {
38
+ symbol: string;
39
+ /** Root pitch class 0-11 */
40
+ root: number;
41
+ /** Semitones relative to the root (sorted, may be > 12) */
42
+ intervals: number[];
43
+ /** Bass pitch class (differs from the root for slash chords) */
44
+ bass: number;
45
+ /** Third: minor third 3, major third 4, no third 0 (used when a bass line writes "3") */
46
+ third: number;
47
+ }
48
+ /** Parse a chord symbol: Am7, F#m7b5, Bb/D, Gsus4, C5, Ebmaj7s11, Dq4... */
49
+ export declare function parseChord(symbol: string): ChordInfo;
50
+ export interface VoicingOptions {
51
+ /** The register to center the chord around (default C4) */
52
+ center?: Pitch;
53
+ /** The previous voicing: pick the inversion that moves the least from it */
54
+ previous?: number[];
55
+ /** Number of notes (default: every chord tone, at least 3) */
56
+ size?: number;
57
+ }
58
+ /** Voice a chord in close position around a center; with a previous voicing, pick the smoothest inversion */
59
+ export declare function voiceChord(chord: ChordInfo, { center, previous, size }?: VoicingOptions): number[];
60
+ /** The note at a degree of a mode (0-based, may be negative or exceed 7) above a tonic */
61
+ export declare function scaleDegree(tonic: Pitch, mode: Mode, degree: number): number;
62
+ /**
63
+ * Mode remapping: map a note written on C's natural notes (white keys) to the same scale degree of tonic + mode.
64
+ * Accidentals are kept as a "semitone offset", so a C major melody can be written once and dropped into Phrygian or harmonic minor.
65
+ * base is the written tonic (by default the C at C4 = 60).
66
+ */
67
+ export declare function remapToMode(m: number, tonic: Pitch, mode: Mode, base?: Pitch): number;
68
+ /** Roman-numeral chord in a key, as a chord symbol: romanChord('bVII', 'D4', 'aeolian') → 'C' ('i', 'IV', 'bVII', 'v7', 'ii°') */
69
+ export declare function romanChord(numeral: string, tonic: Pitch, mode: Mode): string;
70
+ //# sourceMappingURL=theory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theory.d.ts","sourceRoot":"","sources":["../src/theory.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpC,yEAAyE;AACzE,wBAAgB,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAOzC;AAED,iCAAiC;AACjC,eAAO,MAAM,SAAS,UAAW,KAAK,KAAG,MAAoD,CAAC;AAG9F,sCAAsC;AACtC,eAAO,MAAM,QAAQ,MAAO,MAAM,KAAG,MAAmE,CAAC;AAEzG,yDAAyD;AACzD,eAAO,MAAM,KAAK;;;;;;;;;;IAUhB,iEAAiE;;IAEjE,kEAAkE;;;IAGlE,wCAAwC;;;;IAIxC,qFAAqF;;;IAGrF,kCAAkC;;CAEkB,CAAC;AACvD,MAAM,MAAM,IAAI,GAAG,MAAM,OAAO,KAAK,CAAC;AAuCtC,4BAA4B;AAC5B,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,KAAK,EAAE,MAAM,CAAC;CACf;AASD,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CASpD;AAED,MAAM,WAAW,cAAc;IAC7B,2DAA2D;IAC3D,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,6GAA6G;AAC7G,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,MAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAE,cAAmB,GAAG,MAAM,EAAE,CA8B3G;AAED,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM5E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAE,KAAU,GAAG,MAAM,CAmBzF;AAED,kIAAkI;AAClI,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAU5E"}
package/dist/theory.js ADDED
@@ -0,0 +1,183 @@
1
+ // Music theory: note names, modes, chord symbols, voicing and mode remapping. Pure functions only.
2
+ /** Note name (or MIDI number) to MIDI: C4 = 60. Supports #, b, ##, bb */
3
+ export function midi(pitch) {
4
+ if (typeof pitch === 'number')
5
+ return pitch;
6
+ const m = /^([A-Ga-g])(##|bb|#|b)?(-?\d)$/.exec(pitch.trim());
7
+ if (!m)
8
+ throw new Error(`Unrecognized note name: ${pitch}`);
9
+ const base = { C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11 }[m[1].toUpperCase()];
10
+ const acc = m[2] === '#' ? 1 : m[2] === '##' ? 2 : m[2] === 'b' ? -1 : m[2] === 'bb' ? -2 : 0;
11
+ return 12 * (Number(m[3]) + 1) + base + acc;
12
+ }
13
+ /** Frequency in Hz (A4 = 440) */
14
+ export const frequency = (pitch) => 440 * Math.pow(2, (midi(pitch) - 69) / 12);
15
+ const NAMES = ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'];
16
+ /** MIDI to a note name: 61 → 'C#4' */
17
+ export const noteName = (m) => `${NAMES[((m % 12) + 12) % 12]}${Math.floor(m / 12) - 1}`;
18
+ /** Modes and scales (semitones relative to the tonic) */
19
+ export const MODES = {
20
+ ionian: [0, 2, 4, 5, 7, 9, 11],
21
+ dorian: [0, 2, 3, 5, 7, 9, 10],
22
+ phrygian: [0, 1, 3, 5, 7, 8, 10],
23
+ lydian: [0, 2, 4, 6, 7, 9, 11],
24
+ mixolydian: [0, 2, 4, 5, 7, 9, 10],
25
+ aeolian: [0, 2, 3, 5, 7, 8, 10],
26
+ locrian: [0, 1, 3, 5, 6, 8, 10],
27
+ harmonicMinor: [0, 2, 3, 5, 7, 8, 11],
28
+ melodicMinor: [0, 2, 3, 5, 7, 9, 11],
29
+ /** Phrygian dominant scale (Spanish / Middle Eastern flavour) */
30
+ phrygianDom: [0, 1, 4, 5, 7, 8, 10],
31
+ /** Hungarian minor (the Gypsy flavour of the augmented fourth) */
32
+ hungarianMinor: [0, 2, 3, 6, 7, 8, 11],
33
+ lydianDom: [0, 2, 4, 6, 7, 9, 10],
34
+ /** Double harmonic (Byzantine) scale */
35
+ doubleHarmonic: [0, 1, 4, 5, 7, 8, 11],
36
+ majorPent: [0, 2, 4, 7, 9],
37
+ minorPent: [0, 3, 5, 7, 10],
38
+ /** Japanese miyako-bushi (the In scale), used only to give the Rift an alien feel */
39
+ inSen: [0, 1, 5, 7, 10],
40
+ wholeTone: [0, 2, 4, 6, 8, 10],
41
+ /** Half-whole diminished scale */
42
+ octatonic: [0, 1, 3, 4, 6, 7, 9, 10],
43
+ };
44
+ /** Chord qualities (semitones relative to the root; slash-chord bass not included) */
45
+ const QUALITIES = {
46
+ '': [0, 4, 7],
47
+ maj: [0, 4, 7],
48
+ m: [0, 3, 7],
49
+ dim: [0, 3, 6],
50
+ aug: [0, 4, 8],
51
+ '+': [0, 4, 8],
52
+ sus2: [0, 2, 7],
53
+ sus4: [0, 5, 7],
54
+ sus: [0, 5, 7],
55
+ '5': [0, 7],
56
+ '6': [0, 4, 7, 9],
57
+ m6: [0, 3, 7, 9],
58
+ '7': [0, 4, 7, 10],
59
+ maj7: [0, 4, 7, 11],
60
+ m7: [0, 3, 7, 10],
61
+ mmaj7: [0, 3, 7, 11],
62
+ m7b5: [0, 3, 6, 10],
63
+ dim7: [0, 3, 6, 9],
64
+ '7sus4': [0, 5, 7, 10],
65
+ add9: [0, 4, 7, 14],
66
+ madd9: [0, 3, 7, 14],
67
+ '9': [0, 4, 7, 10, 14],
68
+ maj9: [0, 4, 7, 11, 14],
69
+ m9: [0, 3, 7, 10, 14],
70
+ '7b9': [0, 4, 7, 10, 13],
71
+ '7#9': [0, 4, 7, 10, 15],
72
+ m11: [0, 3, 7, 10, 14, 17],
73
+ '11': [0, 7, 10, 14, 17],
74
+ maj7s11: [0, 4, 7, 11, 18],
75
+ '6/9': [0, 4, 7, 9, 14],
76
+ /** Stacked fourths (ethereal, floating) */
77
+ q: [0, 5, 10],
78
+ q4: [0, 5, 10, 15],
79
+ };
80
+ const PC = { C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11 };
81
+ const pcOf = (s) => {
82
+ const m = /^([A-G])(#|b)?$/.exec(s);
83
+ if (!m)
84
+ throw new Error(`Unrecognized root note: ${s}`);
85
+ return (PC[m[1]] + (m[2] === '#' ? 1 : m[2] === 'b' ? -1 : 0) + 12) % 12;
86
+ };
87
+ /** Parse a chord symbol: Am7, F#m7b5, Bb/D, Gsus4, C5, Ebmaj7s11, Dq4... */
88
+ export function parseChord(symbol) {
89
+ const m = /^([A-G](?:#|b)?)([^/]*)(?:\/([A-G](?:#|b)?))?$/.exec(symbol.trim());
90
+ if (!m)
91
+ throw new Error(`Unrecognized chord: ${symbol}`);
92
+ const root = pcOf(m[1]);
93
+ const q = m[2];
94
+ const iv = QUALITIES[q];
95
+ if (!iv)
96
+ throw new Error(`Unrecognized chord quality "${q}" (${symbol})`);
97
+ const third = iv.includes(4) ? 4 : iv.includes(3) ? 3 : 0;
98
+ return { symbol, root, intervals: [...iv], bass: m[3] ? pcOf(m[3]) : root, third };
99
+ }
100
+ /** Voice a chord in close position around a center; with a previous voicing, pick the smoothest inversion */
101
+ export function voiceChord(chord, { center = 60, previous, size } = {}) {
102
+ const mid0 = midi(center);
103
+ const pcs = chord.intervals.map((i) => (chord.root + i) % 12);
104
+ const uniq = [...new Set(pcs)];
105
+ const n = size ?? Math.max(3, uniq.length);
106
+ // List every inversion: starting from the first note above center-9 or center-3, stack upward
107
+ const cands = [];
108
+ for (let inv = 0; inv < uniq.length; inv++) {
109
+ for (const lo of [mid0 - 9, mid0 - 3]) {
110
+ const out = [];
111
+ let p = lo;
112
+ for (let k = 0; k < n; k++) {
113
+ const pc = uniq[(inv + k) % uniq.length];
114
+ while (((p % 12) + 12) % 12 !== pc)
115
+ p++;
116
+ out.push(p);
117
+ p++;
118
+ }
119
+ cands.push(out);
120
+ }
121
+ }
122
+ const score = (v) => {
123
+ const mid = (v[0] + v[v.length - 1]) / 2;
124
+ let s = Math.abs(mid - mid0) * 0.6;
125
+ if (previous && previous.length) {
126
+ for (let i = 0; i < v.length; i++)
127
+ s += Math.abs(v[i] - previous[Math.min(i, previous.length - 1)]);
128
+ }
129
+ return s;
130
+ };
131
+ cands.sort((a, b) => score(a) - score(b));
132
+ return cands[0];
133
+ }
134
+ /** The note at a degree of a mode (0-based, may be negative or exceed 7) above a tonic */
135
+ export function scaleDegree(tonic, mode, degree) {
136
+ const sc = MODES[mode];
137
+ const n = sc.length;
138
+ const oct = Math.floor(degree / n);
139
+ const i = ((degree % n) + n) % n;
140
+ return midi(tonic) + oct * 12 + sc[i];
141
+ }
142
+ /**
143
+ * Mode remapping: map a note written on C's natural notes (white keys) to the same scale degree of tonic + mode.
144
+ * Accidentals are kept as a "semitone offset", so a C major melody can be written once and dropped into Phrygian or harmonic minor.
145
+ * base is the written tonic (by default the C at C4 = 60).
146
+ */
147
+ export function remapToMode(m, tonic, mode, base = 60) {
148
+ const WHITE = [0, 2, 4, 5, 7, 9, 11];
149
+ const rel = m - midi(base);
150
+ const oct = Math.floor(rel / 12);
151
+ const pc = ((rel % 12) + 12) % 12;
152
+ let idx = WHITE.indexOf(pc);
153
+ let off = 0;
154
+ if (idx < 0) {
155
+ idx = WHITE.indexOf(pc - 1);
156
+ off = 1;
157
+ }
158
+ const t = midi(tonic);
159
+ const sc = MODES[mode];
160
+ if (sc.length === 7)
161
+ return t + oct * 12 + sc[idx] + off;
162
+ // Pentatonic and other non-heptatonic scales: take the nearest scale note
163
+ const target = MODES.ionian[idx];
164
+ let best = sc[0];
165
+ for (const s of sc)
166
+ if (Math.abs(s - target) < Math.abs(best - target))
167
+ best = s;
168
+ return t + oct * 12 + best + off;
169
+ }
170
+ /** Roman-numeral chord in a key, as a chord symbol: romanChord('bVII', 'D4', 'aeolian') → 'C' ('i', 'IV', 'bVII', 'v7', 'ii°') */
171
+ export function romanChord(numeral, tonic, mode) {
172
+ const m = /^(b|#)?(iv|vi{0,2}|i{1,3}|IV|VI{0,2}|I{1,3})(°|\+)?(.*)$/.exec(numeral);
173
+ if (!m)
174
+ throw new Error(`Unrecognized scale degree: ${numeral}`);
175
+ const ROM = ['i', 'ii', 'iii', 'iv', 'v', 'vi', 'vii'];
176
+ const deg = ROM.indexOf(m[2].toLowerCase());
177
+ const sc = MODES[mode];
178
+ const pc = (midi(tonic) + sc[deg % sc.length] + (m[1] === 'b' ? -1 : m[1] === '#' ? 1 : 0) + 120) % 12;
179
+ const minor = m[2] === m[2].toLowerCase();
180
+ const q = m[3] === '°' ? 'dim' : m[3] === '+' ? 'aug' : minor ? 'm' : '';
181
+ return NAMES[pc] + q + (m[4] ?? '');
182
+ }
183
+ //# sourceMappingURL=theory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theory.js","sourceRoot":"","sources":["../src/theory.ts"],"names":[],"mappings":"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"}