@hraness/dawg 0.5.0 → 0.6.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 (124) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/DAWG.md +592 -49
  3. package/README.md +4 -4
  4. package/core/chords.ts +492 -4
  5. package/core/diff.ts +9 -0
  6. package/core/expression.ts +143 -6
  7. package/core/fx.ts +689 -2
  8. package/core/granular.ts +619 -0
  9. package/core/instruments.ts +442 -0
  10. package/core/keys.ts +955 -0
  11. package/core/resonators.ts +862 -0
  12. package/core/score.ts +529 -8
  13. package/core/sdk/eval-child.ts +2 -0
  14. package/core/sdk/print.ts +247 -16
  15. package/core/sdk/sync-instruments.ts +58 -0
  16. package/core/sdk/v1.ts +2417 -40
  17. package/core/sections.ts +44 -10
  18. package/core/strings.ts +1080 -0
  19. package/core/winds.ts +652 -0
  20. package/guides/automation.md +1 -0
  21. package/guides/chords.md +3 -1
  22. package/guides/effects.md +5 -2
  23. package/guides/media.md +1 -1
  24. package/guides/performance.md +3 -0
  25. package/guides/resample.md +26 -0
  26. package/guides/sounds.md +7 -2
  27. package/guides/tempo.md +1 -0
  28. package/package.json +1 -1
  29. package/src/agent/agent.ts +13 -0
  30. package/src/agent/chord-tools.ts +153 -1
  31. package/src/agent/expression-tools.ts +91 -0
  32. package/src/agent/granular-tools.ts +138 -0
  33. package/src/agent/models.ts +4 -4
  34. package/src/agent/ops.ts +42 -2
  35. package/src/agent/preview-tool.ts +7 -1
  36. package/src/agent/resample-tool.ts +131 -0
  37. package/src/agent/tools.ts +726 -17
  38. package/src/agent/xcb-agent.ts +13 -0
  39. package/src/audio/arrange.ts +42 -3
  40. package/src/audio/dsp/bank.ts +233 -0
  41. package/src/audio/dsp/envelope.ts +161 -0
  42. package/src/audio/dsp/fft.ts +6 -0
  43. package/src/audio/dsp/filters.ts +57 -0
  44. package/src/audio/dsp/interp.ts +112 -0
  45. package/src/audio/dsp/modal.ts +684 -0
  46. package/src/audio/dsp/onset.ts +197 -0
  47. package/src/audio/dsp/oversample.ts +202 -0
  48. package/src/audio/dsp/rng.ts +37 -0
  49. package/src/audio/dsp/shape.ts +81 -0
  50. package/src/audio/dsp/shift.ts +256 -0
  51. package/src/audio/dsp/stft.ts +73 -0
  52. package/src/audio/dsp/window.ts +77 -0
  53. package/src/audio/effects/chain.ts +23 -3
  54. package/src/audio/effects/common.ts +14 -0
  55. package/src/audio/effects/convolution.ts +106 -1
  56. package/src/audio/effects/gaze.ts +354 -0
  57. package/src/audio/effects/rig/cab.ts +99 -0
  58. package/src/audio/effects/rig/filters.ts +152 -0
  59. package/src/audio/effects/rig/gate.ts +39 -0
  60. package/src/audio/effects/rig/head.ts +487 -0
  61. package/src/audio/effects/rig/index.ts +170 -0
  62. package/src/audio/effects/rig/section.ts +78 -0
  63. package/src/audio/effects/rig/stomp.ts +238 -0
  64. package/src/audio/engine.ts +56 -6
  65. package/src/audio/fit.ts +447 -0
  66. package/src/audio/granular.ts +995 -0
  67. package/src/audio/instrument-check.ts +137 -0
  68. package/src/audio/instruments.ts +140 -0
  69. package/src/audio/keys/dsp.ts +323 -0
  70. package/src/audio/keys/electric.ts +420 -0
  71. package/src/audio/keys/engine.ts +485 -0
  72. package/src/audio/keys/organ.ts +1335 -0
  73. package/src/audio/keys/piano.ts +476 -0
  74. package/src/audio/keys/sympathetic.ts +127 -0
  75. package/src/audio/live-worker.ts +56 -0
  76. package/src/audio/live.ts +361 -15
  77. package/src/audio/loudness.ts +65 -20
  78. package/src/audio/preview.ts +17 -1
  79. package/src/audio/resample.ts +285 -0
  80. package/src/audio/resonators.ts +295 -0
  81. package/src/audio/sampler.ts +328 -35
  82. package/src/audio/samples.ts +56 -8
  83. package/src/audio/strings/body.ts +263 -0
  84. package/src/audio/strings/bow.ts +656 -0
  85. package/src/audio/strings/engine.ts +615 -0
  86. package/src/audio/strings/loop.ts +119 -0
  87. package/src/audio/strings/measure.test-helpers.ts +200 -0
  88. package/src/audio/strings/pluck.ts +354 -0
  89. package/src/audio/warp.ts +61 -0
  90. package/src/audio/wav.ts +191 -19
  91. package/src/audio/winds/engine.ts +302 -0
  92. package/src/audio/winds/filters.ts +153 -0
  93. package/src/audio/winds/pitch.ts +104 -0
  94. package/src/audio/winds/trim.ts +80 -0
  95. package/src/audio/winds/trims.ts +917 -0
  96. package/src/audio/winds/voice.ts +479 -0
  97. package/src/commands/expression.ts +111 -23
  98. package/src/commands/fit.ts +135 -0
  99. package/src/commands/fx.ts +35 -1
  100. package/src/commands/granular.ts +432 -0
  101. package/src/commands/help.ts +159 -5
  102. package/src/commands/keys.ts +629 -0
  103. package/src/commands/modal.ts +310 -0
  104. package/src/commands/resample.ts +281 -0
  105. package/src/commands/rig.ts +264 -0
  106. package/src/commands/sample.ts +52 -2
  107. package/src/commands/shift.ts +119 -0
  108. package/src/commands/string.ts +201 -0
  109. package/src/commands/strum.ts +473 -0
  110. package/src/commands/time.ts +4 -1
  111. package/src/commands/wind.ts +244 -0
  112. package/src/main.ts +339 -15
  113. package/src/project/check.ts +17 -0
  114. package/src/render.ts +49 -4
  115. package/src/session/presence.ts +16 -3
  116. package/src/tui/audition.ts +2 -2
  117. package/src/tui/granular-menu.ts +278 -0
  118. package/src/tui/menu.ts +934 -9
  119. package/src/tui/modal-menu.ts +145 -0
  120. package/src/tui/performance-menu.ts +42 -0
  121. package/src/tui/play-chords.ts +104 -3
  122. package/src/tui/play-mode.ts +1 -0
  123. package/src/tui/play-session.ts +70 -2
  124. package/src/tui/wind-menu.ts +144 -0
@@ -0,0 +1,442 @@
1
+ /**
2
+ * Instrument words for 0.6: the one place a typed, menu, agent or SDK
3
+ * instrument word turns into what a track stores. Pure and import-free;
4
+ * `core/sdk/v1.ts` carries an exact copy of the section below (run
5
+ * `bun core/sdk/sync-instruments.ts`).
6
+ *
7
+ * Lanes add rows to `INSTRUMENT_WORDS` (one block each, appended). A legacy
8
+ * word always resolves to itself, so stored and typed `piano`, `marimba`,
9
+ * `sitar` keep today's voice; a row can never claim one. With no rows,
10
+ * every word resolves exactly as it did before 0.6.
11
+ */
12
+
13
+ // ---- instrument words (copied into core/sdk/v1.ts) ----
14
+
15
+ /** What an instrument word stores on a track. */
16
+ type InstrumentWord = Readonly<{
17
+ /** The `Track.instrument` value. */
18
+ instrument: string;
19
+ /** The optional Track field the engine reads (created with defaults). */
20
+ field?: string;
21
+ /** A preset of that engine to apply. */
22
+ preset?: string;
23
+ /** An insert-effect preset to apply with it (rig aliases). */
24
+ fx?: string;
25
+ }>;
26
+
27
+ /** A word and what it means. */
28
+ type InstrumentWordRow = Readonly<{
29
+ word: string;
30
+ /**
31
+ * Borrow the voice (instrument, field, preset) of this other word's row
32
+ * when it exists; `instrument` is the fallback when it does not.
33
+ */
34
+ voice?: string;
35
+ }> &
36
+ InstrumentWord;
37
+
38
+ /**
39
+ * Words that keep their pre-0.6 meaning forever: they resolve to
40
+ * themselves, whatever rows the lanes add.
41
+ */
42
+ export const LEGACY_WORDS: readonly string[] = Object.freeze([
43
+ "piano",
44
+ "pluck",
45
+ "bass",
46
+ "saw",
47
+ "square",
48
+ "triangle",
49
+ "marimba",
50
+ "wind",
51
+ "cello",
52
+ "contrabass",
53
+ "ebass",
54
+ "sitar",
55
+ "organ",
56
+ "strings",
57
+ "bell",
58
+ "keys",
59
+ "lead",
60
+ ]);
61
+
62
+ /** 0.6 instrument words; each lane appends its own block. */
63
+ export const INSTRUMENT_WORDS: readonly InstrumentWordRow[] = Object.freeze([
64
+ // strings (f06-strings): plucked presets of the string engine. Legacy
65
+ // sitar/ebass keep today's voice (`string preset sitar` reaches the
66
+ // engine), jangle is the rig alias (the guitar lane maps its 12string to the
67
+ // preset; `string jangle` reaches it) and
68
+ // upright is the keys lane's piano (doublebass reaches the preset).
69
+ { word: "nylon", instrument: "string", field: "string", preset: "nylon" },
70
+ { word: "steel", instrument: "string", field: "string", preset: "steel" },
71
+ {
72
+ word: "electric",
73
+ instrument: "string",
74
+ field: "string",
75
+ preset: "electric",
76
+ },
77
+ { word: "slap", instrument: "string", field: "string", preset: "slap" },
78
+ { word: "motown", instrument: "string", field: "string", preset: "motown" },
79
+ { word: "tanpura", instrument: "string", field: "string", preset: "tanpura" },
80
+ {
81
+ word: "harpsichord",
82
+ instrument: "string",
83
+ field: "string",
84
+ preset: "harpsichord",
85
+ },
86
+ { word: "lute", instrument: "string", field: "string", preset: "lute" },
87
+ { word: "oud", instrument: "string", field: "string", preset: "oud" },
88
+ { word: "setar", instrument: "string", field: "string", preset: "setar" },
89
+ { word: "tar", instrument: "string", field: "string", preset: "tar" },
90
+ { word: "santur", instrument: "string", field: "string", preset: "santur" },
91
+ {
92
+ word: "dulcimer",
93
+ instrument: "string",
94
+ field: "string",
95
+ preset: "dulcimer",
96
+ },
97
+ { word: "koto", instrument: "string", field: "string", preset: "koto" },
98
+ { word: "harp", instrument: "string", field: "string", preset: "harp" },
99
+ { word: "banjo", instrument: "string", field: "string", preset: "banjo" },
100
+ { word: "tres", instrument: "string", field: "string", preset: "tres" },
101
+ {
102
+ word: "requinto",
103
+ instrument: "string",
104
+ field: "string",
105
+ preset: "requinto",
106
+ },
107
+ { word: "acoustic", instrument: "string", field: "string", preset: "steel" },
108
+ { word: "classical", instrument: "string", field: "string", preset: "nylon" },
109
+ {
110
+ word: "bassguitar",
111
+ instrument: "string",
112
+ field: "string",
113
+ preset: "ebass",
114
+ },
115
+ { word: "fender", instrument: "string", field: "string", preset: "ebass" },
116
+ {
117
+ word: "doublebass",
118
+ instrument: "string",
119
+ field: "string",
120
+ preset: "upright",
121
+ },
122
+ {
123
+ word: "cembalo",
124
+ instrument: "string",
125
+ field: "string",
126
+ preset: "harpsichord",
127
+ },
128
+ {
129
+ word: "hammered",
130
+ instrument: "string",
131
+ field: "string",
132
+ preset: "dulcimer",
133
+ },
134
+ { word: "sehtar", instrument: "string", field: "string", preset: "setar" },
135
+ // bowed (f061-bowed): bowed presets of the string engine. `cello`,
136
+ // `contrabass` and `strings` stay legacy words (today's voice);
137
+ // `bowed-cello`, `string cello` or `bowed cello` reach the engine.
138
+ { word: "violin", instrument: "string", field: "string", preset: "violin" },
139
+ { word: "viola", instrument: "string", field: "string", preset: "viola" },
140
+ { word: "fiddle", instrument: "string", field: "string", preset: "fiddle" },
141
+ { word: "erhu", instrument: "string", field: "string", preset: "erhu" },
142
+ {
143
+ word: "kamancheh",
144
+ instrument: "string",
145
+ field: "string",
146
+ preset: "kamancheh",
147
+ },
148
+ {
149
+ word: "kemence",
150
+ instrument: "string",
151
+ field: "string",
152
+ preset: "kamancheh",
153
+ },
154
+ { word: "violins", instrument: "string", field: "string", preset: "violins" },
155
+ { word: "violas", instrument: "string", field: "string", preset: "violas" },
156
+ { word: "cellos", instrument: "string", field: "string", preset: "cellos" },
157
+ {
158
+ word: "contrabasses",
159
+ instrument: "string",
160
+ field: "string",
161
+ preset: "contrabasses",
162
+ },
163
+ { word: "pizzicato", instrument: "string", field: "string", preset: "pizz" },
164
+ { word: "tremolo", instrument: "string", field: "string", preset: "trem" },
165
+ {
166
+ word: "bowed-cello",
167
+ instrument: "string",
168
+ field: "string",
169
+ preset: "cello",
170
+ },
171
+ // f06-rig: guitar track aliases, a guitar voice plus a whole rig. The
172
+ // voice is the strings lane's `electric` row (jangle: its 12-string
173
+ // `jangle` preset); the pluck only while that row is absent. Never `lead`
174
+ // or `bass`.
175
+ {
176
+ word: "jangle",
177
+ instrument: "string",
178
+ field: "string",
179
+ preset: "jangle",
180
+ fx: "jangle",
181
+ },
182
+ { word: "punk", instrument: "pluck", voice: "electric", fx: "punk" },
183
+ { word: "funk", instrument: "pluck", voice: "electric", fx: "funk" },
184
+ { word: "ragged", instrument: "pluck", voice: "electric", fx: "ragged" },
185
+ { word: "gtr-lead", instrument: "pluck", voice: "electric", fx: "lead" },
186
+ { word: "gtr-metal", instrument: "pluck", voice: "electric", fx: "metal" },
187
+ { word: "bachata", instrument: "pluck", voice: "electric", fx: "bachata" },
188
+ // granular (f06-granular): the instrument and its texture presets. Each
189
+ // starts from a built-in synth source, so nothing downloads.
190
+ {
191
+ word: "granular",
192
+ instrument: "granular",
193
+ field: "granular",
194
+ preset: "cloud",
195
+ },
196
+ {
197
+ word: "grains",
198
+ instrument: "granular",
199
+ field: "granular",
200
+ preset: "cloud",
201
+ },
202
+ { word: "cloud", instrument: "granular", field: "granular", preset: "cloud" },
203
+ {
204
+ word: "sparkle",
205
+ instrument: "granular",
206
+ field: "granular",
207
+ preset: "sparkle",
208
+ },
209
+ { word: "swarm", instrument: "granular", field: "granular", preset: "swarm" },
210
+ {
211
+ word: "microloop",
212
+ instrument: "granular",
213
+ field: "granular",
214
+ preset: "microloop",
215
+ },
216
+ // keys (f06-piano): modelled pianos. `piano` stays legacy here; the typed
217
+ // surfaces store a new `piano` as `grand` (core/keys.ts `pianoWrite`).
218
+ { word: "grand", instrument: "grand", field: "keys", preset: "grand" },
219
+ { word: "ballad", instrument: "grand", field: "keys", preset: "ballad" },
220
+ { word: "upright", instrument: "upright", field: "keys", preset: "upright" },
221
+ { word: "felt", instrument: "felt", field: "keys", preset: "felt" },
222
+ { word: "lofi", instrument: "felt", field: "keys", preset: "lofi" },
223
+ {
224
+ word: "honkytonk",
225
+ instrument: "honkytonk",
226
+ field: "keys",
227
+ preset: "honkytonk",
228
+ },
229
+ {
230
+ word: "prepared",
231
+ instrument: "prepared",
232
+ field: "keys",
233
+ preset: "prepared",
234
+ },
235
+ // keys (f061-organ): tonewheel, combo and pipe organs on the keys
236
+ // engine. `organ` stays legacy (the sine voice).
237
+ {
238
+ word: "tonewheel",
239
+ instrument: "tonewheel",
240
+ field: "keys",
241
+ preset: "tonewheel",
242
+ },
243
+ {
244
+ word: "hammond",
245
+ instrument: "tonewheel",
246
+ field: "keys",
247
+ preset: "tonewheel",
248
+ },
249
+ { word: "b3", instrument: "tonewheel", field: "keys", preset: "tonewheel" },
250
+ { word: "gospel", instrument: "tonewheel", field: "keys", preset: "gospel" },
251
+ {
252
+ word: "jazzorgan",
253
+ instrument: "tonewheel",
254
+ field: "keys",
255
+ preset: "jazzorgan",
256
+ },
257
+ { word: "combo", instrument: "combo", field: "keys", preset: "combo" },
258
+ { word: "farfisa", instrument: "combo", field: "keys", preset: "combo" },
259
+ { word: "vox", instrument: "combo", field: "keys", preset: "vox" },
260
+ { word: "pipe", instrument: "pipe", field: "keys", preset: "pipe" },
261
+ { word: "church", instrument: "pipe", field: "keys", preset: "pipe" },
262
+ { word: "pipeorgan", instrument: "pipe", field: "keys", preset: "pipe" },
263
+ { word: "churchorgan", instrument: "pipe", field: "keys", preset: "pipe" },
264
+ { word: "flutes", instrument: "pipe", field: "keys", preset: "flutes" },
265
+ { word: "cornet", instrument: "pipe", field: "keys", preset: "cornet" },
266
+ { word: "reeds", instrument: "pipe", field: "keys", preset: "reeds" },
267
+ { word: "celeste", instrument: "pipe", field: "keys", preset: "celeste" },
268
+ // f06-modal: mallets and bells (core/resonators.ts). `marimba` is legacy;
269
+ // `modal` alone gives the modal marimba.
270
+ { word: "modal", instrument: "modal", field: "modal", preset: "marimba" },
271
+ { word: "vibes", instrument: "modal", field: "modal", preset: "vibes" },
272
+ { word: "vibraphone", instrument: "modal", field: "modal", preset: "vibes" },
273
+ {
274
+ word: "xylophone",
275
+ instrument: "modal",
276
+ field: "modal",
277
+ preset: "xylophone",
278
+ },
279
+ { word: "glock", instrument: "modal", field: "modal", preset: "glock" },
280
+ {
281
+ word: "glockenspiel",
282
+ instrument: "modal",
283
+ field: "modal",
284
+ preset: "glock",
285
+ },
286
+ { word: "celesta", instrument: "modal", field: "modal", preset: "celesta" },
287
+ { word: "chimes", instrument: "modal", field: "modal", preset: "chimes" },
288
+ { word: "tubular", instrument: "modal", field: "modal", preset: "chimes" },
289
+ { word: "kalimba", instrument: "modal", field: "modal", preset: "kalimba" },
290
+ {
291
+ word: "thumbpiano",
292
+ instrument: "modal",
293
+ field: "modal",
294
+ preset: "kalimba",
295
+ },
296
+ { word: "mbira", instrument: "modal", field: "modal", preset: "mbira" },
297
+ { word: "steelpan", instrument: "modal", field: "modal", preset: "steelpan" },
298
+ { word: "bowl", instrument: "modal", field: "modal", preset: "bowl" },
299
+ { word: "gong", instrument: "modal", field: "modal", preset: "gong" },
300
+ { word: "gongageng", instrument: "modal", field: "modal", preset: "gong" },
301
+ { word: "timpani", instrument: "modal", field: "modal", preset: "timpani" },
302
+ {
303
+ word: "steeldrum",
304
+ instrument: "modal",
305
+ field: "modal",
306
+ preset: "steelpan",
307
+ },
308
+ { word: "singingbowl", instrument: "modal", field: "modal", preset: "bowl" },
309
+ {
310
+ word: "kettledrum",
311
+ instrument: "modal",
312
+ field: "modal",
313
+ preset: "timpani",
314
+ },
315
+ {
316
+ word: "tubularbells",
317
+ instrument: "modal",
318
+ field: "modal",
319
+ preset: "chimes",
320
+ },
321
+ // keys-electric (0.6.1): electric pianos and clavinet. `keys` stays legacy.
322
+ { word: "epiano", instrument: "epiano", field: "keys", preset: "epiano" },
323
+ { word: "rhodes", instrument: "epiano", field: "keys", preset: "epiano" },
324
+ {
325
+ word: "suitcase",
326
+ instrument: "epiano",
327
+ field: "keys",
328
+ preset: "suitcase",
329
+ },
330
+ { word: "dyno", instrument: "epiano", field: "keys", preset: "dyno" },
331
+ { word: "wurli", instrument: "wurli", field: "keys", preset: "wurli" },
332
+ { word: "wurlitzer", instrument: "wurli", field: "keys", preset: "wurli" },
333
+ { word: "clav", instrument: "clav", field: "keys", preset: "clav" },
334
+ { word: "clavinet", instrument: "clav", field: "keys", preset: "clav" },
335
+ { word: "funkclav", instrument: "clav", field: "keys", preset: "funkclav" },
336
+ // f061-guitar: the shoegaze alias, an electric guitar voice plus the
337
+ // shoegaze rig and its long wash.
338
+ { word: "shoegaze", instrument: "pluck", voice: "electric", fx: "shoegaze" },
339
+ // f061 integration: the two rig names that are free as instrument words
340
+ // (glide and swell are taken by commands; reach them with `rig glide`).
341
+ { word: "dreampop", instrument: "pluck", voice: "electric", fx: "dreampop" },
342
+ { word: "ebow", instrument: "pluck", voice: "electric", fx: "ebow" },
343
+ // f061-gamelan-winds: gamelan, small bells and frame drums.
344
+ { word: "crotales", instrument: "modal", field: "modal", preset: "crotales" },
345
+ { word: "crotale", instrument: "modal", field: "modal", preset: "crotales" },
346
+ { word: "musicbox", instrument: "modal", field: "modal", preset: "musicbox" },
347
+ { word: "toypiano", instrument: "modal", field: "modal", preset: "toypiano" },
348
+ { word: "saron", instrument: "modal", field: "modal", preset: "saron" },
349
+ { word: "demung", instrument: "modal", field: "modal", preset: "demung" },
350
+ { word: "slenthem", instrument: "modal", field: "modal", preset: "slenthem" },
351
+ { word: "gangsa", instrument: "modal", field: "modal", preset: "gangsa" },
352
+ { word: "gender", instrument: "modal", field: "modal", preset: "gender" },
353
+ { word: "bonang", instrument: "modal", field: "modal", preset: "bonang" },
354
+ { word: "kenong", instrument: "modal", field: "modal", preset: "kenong" },
355
+ { word: "kethuk", instrument: "modal", field: "modal", preset: "kethuk" },
356
+ { word: "kempul", instrument: "modal", field: "modal", preset: "kempul" },
357
+ { word: "daf", instrument: "modal", field: "modal", preset: "daf" },
358
+ { word: "bodhran", instrument: "modal", field: "modal", preset: "bodhran" },
359
+ { word: "framedrum", instrument: "modal", field: "modal", preset: "bodhran" },
360
+ { word: "tabla", instrument: "modal", field: "modal", preset: "tabla" },
361
+ // f061-gamelan-winds: blown waveguides (core/winds.ts). The legacy word
362
+ // `wind` keeps its tone; these words and their aliases pick a wind preset.
363
+ { word: "flute", instrument: "wind", field: "wind", preset: "flute" },
364
+ { word: "recorder", instrument: "wind", field: "wind", preset: "recorder" },
365
+ { word: "whistle", instrument: "wind", field: "wind", preset: "whistle" },
366
+ { word: "ney", instrument: "wind", field: "wind", preset: "ney" },
367
+ {
368
+ word: "shakuhachi",
369
+ instrument: "wind",
370
+ field: "wind",
371
+ preset: "shakuhachi",
372
+ },
373
+ { word: "panpipe", instrument: "wind", field: "wind", preset: "panpipe" },
374
+ { word: "suling", instrument: "wind", field: "wind", preset: "suling" },
375
+ { word: "bansuri", instrument: "wind", field: "wind", preset: "bansuri" },
376
+ { word: "clarinet", instrument: "wind", field: "wind", preset: "clarinet" },
377
+ {
378
+ word: "bassclarinet",
379
+ instrument: "wind",
380
+ field: "wind",
381
+ preset: "bassclarinet",
382
+ },
383
+ { word: "oboe", instrument: "wind", field: "wind", preset: "oboe" },
384
+ { word: "bassoon", instrument: "wind", field: "wind", preset: "bassoon" },
385
+ { word: "sax", instrument: "wind", field: "wind", preset: "sax" },
386
+ { word: "altosax", instrument: "wind", field: "wind", preset: "altosax" },
387
+ { word: "barisax", instrument: "wind", field: "wind", preset: "barisax" },
388
+ { word: "trumpet", instrument: "wind", field: "wind", preset: "trumpet" },
389
+ { word: "harmon", instrument: "wind", field: "wind", preset: "harmon" },
390
+ { word: "plunger", instrument: "wind", field: "wind", preset: "plunger" },
391
+ { word: "trombone", instrument: "wind", field: "wind", preset: "trombone" },
392
+ { word: "tuba", instrument: "wind", field: "wind", preset: "tuba" },
393
+ { word: "horn", instrument: "wind", field: "wind", preset: "horn" },
394
+ { word: "tinwhistle", instrument: "wind", field: "wind", preset: "whistle" },
395
+ {
396
+ word: "pennywhistle",
397
+ instrument: "wind",
398
+ field: "wind",
399
+ preset: "whistle",
400
+ },
401
+ { word: "nay", instrument: "wind", field: "wind", preset: "ney" },
402
+ { word: "panflute", instrument: "wind", field: "wind", preset: "panpipe" },
403
+ { word: "panpipes", instrument: "wind", field: "wind", preset: "panpipe" },
404
+ { word: "saxophone", instrument: "wind", field: "wind", preset: "sax" },
405
+ { word: "tenorsax", instrument: "wind", field: "wind", preset: "sax" },
406
+ { word: "tenor", instrument: "wind", field: "wind", preset: "sax" },
407
+ { word: "alto", instrument: "wind", field: "wind", preset: "altosax" },
408
+ { word: "bari", instrument: "wind", field: "wind", preset: "barisax" },
409
+ { word: "baritonesax", instrument: "wind", field: "wind", preset: "barisax" },
410
+ { word: "frenchhorn", instrument: "wind", field: "wind", preset: "horn" },
411
+ { word: "mutedtrumpet", instrument: "wind", field: "wind", preset: "harmon" },
412
+ { word: "wahtrumpet", instrument: "wind", field: "wind", preset: "plunger" },
413
+ ]);
414
+
415
+ /**
416
+ * What an instrument word means: a legacy word is itself, a row word is its
417
+ * row, anything else is undefined (callers keep the word as typed).
418
+ */
419
+ export function resolveInstrumentWord(
420
+ word: string,
421
+ ): InstrumentWord | undefined {
422
+ if (LEGACY_WORDS.includes(word)) return Object.freeze({ instrument: word });
423
+ const row = INSTRUMENT_WORDS.find((entry) => entry.word === word);
424
+ if (!row) return undefined;
425
+ const { word: _word, voice, ...meaning } = row;
426
+ const borrowed =
427
+ voice === undefined
428
+ ? undefined
429
+ : INSTRUMENT_WORDS.find((entry) => entry.word === voice && !entry.voice);
430
+ if (!borrowed) return Object.freeze(meaning);
431
+ return Object.freeze({
432
+ instrument: borrowed.instrument,
433
+ ...(borrowed.field === undefined ? {} : { field: borrowed.field }),
434
+ ...(borrowed.preset === undefined ? {} : { preset: borrowed.preset }),
435
+ ...(meaning.fx === undefined ? {} : { fx: meaning.fx }),
436
+ });
437
+ }
438
+
439
+ /** The `Track.instrument` value a word stores (the word itself if unknown). */
440
+ export function instrumentForWord(word: string): string {
441
+ return resolveInstrumentWord(word)?.instrument ?? word;
442
+ }