@hraness/dawg 0.6.1 → 0.7.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 (253) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/DAWG.md +343 -116
  3. package/README.md +27 -25
  4. package/core/autotune.ts +1119 -0
  5. package/core/chords.ts +271 -23
  6. package/core/clips.ts +499 -0
  7. package/core/diff.ts +182 -104
  8. package/core/expression.ts +15 -0
  9. package/core/fx.ts +99 -29
  10. package/core/instruments.ts +19 -0
  11. package/core/keys.ts +3 -3
  12. package/core/loop.ts +5 -0
  13. package/core/lyrics.ts +297 -0
  14. package/core/master.ts +3 -3
  15. package/core/resonators.ts +16 -2
  16. package/core/routing.ts +165 -0
  17. package/core/score.ts +832 -13
  18. package/core/sdk/eval-child.ts +7 -2
  19. package/core/sdk/eval.ts +35 -6
  20. package/core/sdk/print.ts +276 -3
  21. package/core/sdk/sync-lyrics.ts +49 -0
  22. package/core/sdk/v1.ts +1849 -42
  23. package/core/sections.ts +292 -26
  24. package/core/sing.ts +815 -0
  25. package/core/style-provenance.ts +80 -0
  26. package/core/styles/africa-mena-southasia.ts +2893 -0
  27. package/core/styles/americas.ts +3810 -0
  28. package/core/styles/art.ts +4993 -0
  29. package/core/styles/base.ts +123 -0
  30. package/core/styles/cycles.ts +106 -0
  31. package/core/styles/electronic.ts +2723 -0
  32. package/core/styles/europe-asia-pacific.ts +2838 -0
  33. package/core/styles/excerpt.ts +29 -0
  34. package/core/styles/gamelan.ts +283 -0
  35. package/core/styles/generate.ts +2199 -0
  36. package/core/styles/index.ts +515 -0
  37. package/core/styles/parts.ts +106 -0
  38. package/core/styles/pop.ts +3189 -0
  39. package/core/styles/rock.ts +2993 -0
  40. package/core/styles/roots.ts +4175 -0
  41. package/core/styles/schema.ts +429 -0
  42. package/core/styles/taxonomy.ts +940 -0
  43. package/core/styles/validate.ts +528 -0
  44. package/core/tempo.ts +32 -2
  45. package/core/tuning.ts +19 -3
  46. package/core/vocoder.ts +524 -0
  47. package/guides/agent.md +29 -0
  48. package/guides/arrange.md +30 -0
  49. package/guides/audition.md +20 -14
  50. package/guides/automation.md +12 -7
  51. package/guides/chords.md +15 -15
  52. package/guides/effects.md +17 -16
  53. package/guides/faders.md +20 -16
  54. package/guides/files.md +13 -9
  55. package/guides/getting-started.md +15 -11
  56. package/guides/keys.md +19 -15
  57. package/guides/media.md +17 -12
  58. package/guides/mix.md +12 -6
  59. package/guides/music.md +23 -8
  60. package/guides/notes.md +15 -9
  61. package/guides/performance.md +15 -13
  62. package/guides/play.md +21 -13
  63. package/guides/project.md +25 -8
  64. package/guides/providers.md +20 -14
  65. package/guides/resample.md +15 -9
  66. package/guides/rhythm.md +17 -13
  67. package/guides/sessions.md +17 -7
  68. package/guides/show-me.md +31 -0
  69. package/guides/sound.md +25 -9
  70. package/guides/sounds.md +15 -13
  71. package/guides/styles.md +31 -0
  72. package/guides/tempo.md +15 -10
  73. package/guides/tracks.md +15 -10
  74. package/guides/tuning.md +32 -0
  75. package/guides/voice.md +31 -0
  76. package/guides/web-search.md +18 -8
  77. package/native/prebuilt/darwin-arm64/libdawg_sink.dylib +0 -0
  78. package/native/prebuilt/darwin-x64/libdawg_sink.dylib +0 -0
  79. package/native/prebuilt/linux-arm64/libdawg_sink.so +0 -0
  80. package/native/prebuilt/linux-x64/libdawg_sink.so +0 -0
  81. package/native/prebuilt/manifest.json +21 -0
  82. package/package.json +5 -2
  83. package/src/agent/agent.ts +126 -14
  84. package/src/agent/calibration-tools.ts +53 -0
  85. package/src/agent/clip-tools.ts +453 -0
  86. package/src/agent/command-agent.ts +369 -0
  87. package/src/agent/drum-tools.ts +2 -2
  88. package/src/agent/expression-tools.ts +1 -1
  89. package/src/agent/gateway.ts +246 -60
  90. package/src/agent/models.ts +53 -12
  91. package/src/agent/ops.ts +12 -1
  92. package/src/agent/pack-tools.ts +1 -1
  93. package/src/agent/planner.ts +13 -0
  94. package/src/agent/portable-schema.ts +80 -0
  95. package/src/agent/preview-tool.ts +4 -1
  96. package/src/agent/provider.ts +22 -8
  97. package/src/agent/rhythm-tools.ts +1 -1
  98. package/src/agent/section-tools.ts +1 -1
  99. package/src/agent/show-me.ts +497 -0
  100. package/src/agent/steer.ts +15 -0
  101. package/src/agent/style-tools.ts +217 -0
  102. package/src/agent/tool-error.ts +12 -0
  103. package/src/agent/tools.ts +108 -23
  104. package/src/agent/usage.ts +2 -2
  105. package/src/agent/voice-tools.ts +925 -0
  106. package/src/agent/xcb-agent.ts +11 -7
  107. package/src/argv.ts +38 -0
  108. package/src/audio/analysis.ts +253 -0
  109. package/src/audio/arrange.ts +37 -3
  110. package/src/audio/autotune-engine.ts +101 -0
  111. package/src/audio/autotune.ts +640 -0
  112. package/src/audio/clips.ts +240 -0
  113. package/src/audio/doctor.ts +86 -0
  114. package/src/audio/dsp/bandbank.ts +138 -0
  115. package/src/audio/dsp/envelope.ts +10 -0
  116. package/src/audio/dsp/follow.ts +120 -0
  117. package/src/audio/dsp/formant.ts +427 -0
  118. package/src/audio/dsp/glottal.ts +243 -0
  119. package/src/audio/dsp/interp.ts +7 -2
  120. package/src/audio/dsp/lpc.ts +50 -0
  121. package/src/audio/dsp/periodicity.ts +59 -0
  122. package/src/audio/dsp/pitch.ts +995 -0
  123. package/src/audio/dsp/psola.ts +199 -0
  124. package/src/audio/effects/chain.ts +3 -1
  125. package/src/audio/effects/common.ts +43 -0
  126. package/src/audio/effects/convolution.ts +7 -4
  127. package/src/audio/effects/filter.ts +48 -69
  128. package/src/audio/effects/formant.ts +263 -0
  129. package/src/audio/engine.ts +160 -28
  130. package/src/audio/fit.ts +35 -3
  131. package/src/audio/instrument-check.ts +59 -43
  132. package/src/audio/instruments.ts +4 -0
  133. package/src/audio/keys/calibration.ts +56 -0
  134. package/src/audio/keys/electric.ts +8 -1
  135. package/src/audio/keys/engine.ts +13 -1
  136. package/src/audio/keys/piano.ts +22 -2
  137. package/src/audio/kits.ts +135 -6
  138. package/src/audio/live.ts +114 -20
  139. package/src/audio/native.ts +615 -0
  140. package/src/audio/preview.ts +30 -2
  141. package/src/audio/render-worker.ts +2 -0
  142. package/src/audio/renderer.ts +2 -0
  143. package/src/audio/resample.ts +2 -1
  144. package/src/audio/sampler.ts +85 -4
  145. package/src/audio/samples.ts +20 -2
  146. package/src/audio/sing/analysis.ts +193 -0
  147. package/src/audio/sing/engine.ts +949 -0
  148. package/src/audio/strings/bow.ts +48 -5
  149. package/src/audio/strings/engine.ts +8 -2
  150. package/src/audio/synth/oscillators.ts +31 -21
  151. package/src/audio/synth/voice.ts +34 -1
  152. package/src/audio/vocoder/bank.ts +314 -0
  153. package/src/audio/vocoder/carrier.ts +165 -0
  154. package/src/audio/vocoder/control.ts +68 -0
  155. package/src/audio/vocoder/detect.ts +50 -0
  156. package/src/audio/vocoder/index.ts +304 -0
  157. package/src/audio/vocoder/talkbox.ts +143 -0
  158. package/src/audio/wav.ts +500 -77
  159. package/src/audio/winds/engine.ts +5 -1
  160. package/src/audio/winds/trim.ts +28 -4
  161. package/src/audio/winds/trims1.ts +297 -0
  162. package/src/audio/winds/voice.ts +15 -2
  163. package/src/auth/cli.ts +38 -36
  164. package/src/auth/credentials.ts +30 -1
  165. package/src/auth/login.ts +15 -9
  166. package/src/auth/tui.ts +19 -10
  167. package/src/commands/arrange.ts +44 -29
  168. package/src/commands/autotune.ts +421 -0
  169. package/src/commands/calibration.ts +74 -0
  170. package/src/commands/clips.ts +887 -0
  171. package/src/commands/drums.ts +3 -2
  172. package/src/commands/edit.ts +11 -4
  173. package/src/commands/expression.ts +1 -1
  174. package/src/commands/formant.ts +221 -0
  175. package/src/commands/fx.ts +101 -32
  176. package/src/commands/grammar.ts +558 -0
  177. package/src/commands/help.ts +610 -380
  178. package/src/commands/history.ts +18 -0
  179. package/src/commands/keys.ts +8 -8
  180. package/src/commands/modal.ts +1 -1
  181. package/src/commands/music.ts +1 -1
  182. package/src/commands/nearest.ts +53 -0
  183. package/src/commands/pack.ts +9 -2
  184. package/src/commands/param-range.ts +56 -0
  185. package/src/commands/parses.ts +130 -0
  186. package/src/commands/progression.ts +170 -0
  187. package/src/commands/rhythm.ts +3 -0
  188. package/src/commands/rig.ts +3 -24
  189. package/src/commands/sing.ts +478 -0
  190. package/src/commands/strum.ts +13 -1
  191. package/src/commands/style.ts +415 -0
  192. package/src/commands/time.ts +6 -3
  193. package/src/commands/tuning.ts +3 -3
  194. package/src/commands/vocal-pitch.ts +616 -0
  195. package/src/commands/vocal.ts +147 -0
  196. package/src/commands/vocoder.ts +627 -0
  197. package/src/commands/wind.ts +2 -2
  198. package/src/fs/durable.ts +50 -0
  199. package/src/lang/glossary.ts +493 -0
  200. package/src/launch-args.ts +163 -0
  201. package/src/main.ts +1397 -253
  202. package/src/media/cli.ts +20 -3
  203. package/src/media/import.ts +3 -1
  204. package/src/project/check.ts +21 -2
  205. package/src/project/clip-pins.ts +72 -0
  206. package/src/project/init.ts +23 -8
  207. package/src/project/sync.ts +418 -86
  208. package/src/render.ts +20 -1
  209. package/src/session/daemon.ts +3 -0
  210. package/src/session/meta.ts +14 -0
  211. package/src/session/origin.ts +154 -0
  212. package/src/session/port.ts +22 -4
  213. package/src/session/presence.ts +34 -4
  214. package/src/session/protocol.ts +5 -1
  215. package/src/session/rebase.ts +18 -5
  216. package/src/session/receipt.ts +258 -0
  217. package/src/session/store.ts +65 -43
  218. package/src/tui/arrange-menu.ts +65 -31
  219. package/src/tui/audition.ts +1 -1
  220. package/src/tui/euclid.ts +18 -13
  221. package/src/tui/fader.ts +228 -41
  222. package/src/tui/granular-menu.ts +2 -4
  223. package/src/tui/menu-clips.ts +297 -0
  224. package/src/tui/menu-time.ts +20 -13
  225. package/src/tui/menu-voice.ts +405 -0
  226. package/src/tui/menu.ts +759 -177
  227. package/src/tui/modal-menu.ts +6 -6
  228. package/src/tui/performance-menu.ts +5 -2
  229. package/src/tui/play-chords.ts +4 -2
  230. package/src/tui/play-mode.ts +15 -1
  231. package/src/tui/play-session.ts +47 -7
  232. package/src/tui/sing-menu.ts +278 -0
  233. package/src/tui/style-menu.ts +104 -0
  234. package/src/tui/vocoder-menu.ts +244 -0
  235. package/src/tui/wind-menu.ts +3 -3
  236. package/src/version.ts +8 -0
  237. package/src/web/fetch.ts +115 -29
  238. package/tui/activity.ts +180 -9
  239. package/tui/app.ts +274 -40
  240. package/tui/clip-row.ts +132 -0
  241. package/tui/delight.ts +144 -0
  242. package/tui/drawer.ts +70 -22
  243. package/tui/frame-gate.ts +76 -0
  244. package/tui/grammar.ts +112 -63
  245. package/tui/guide.ts +42 -4
  246. package/tui/highway.ts +269 -25
  247. package/tui/hints.ts +192 -0
  248. package/tui/input.ts +60 -9
  249. package/tui/keys.ts +1 -1
  250. package/tui/play-strip.ts +68 -14
  251. package/tui/prompt.ts +1 -1
  252. package/tui/screen.ts +144 -14
  253. package/tui/theme.ts +27 -0
@@ -170,7 +170,11 @@ export function renderWindTrack(
170
170
  if (points) lanes.set(param, points);
171
171
  }
172
172
  const base = windSettings(track.wind);
173
- const trim = windTrim(windPresetOf(track.wind), sampleRate);
173
+ const trim = windTrim(
174
+ windPresetOf(track.wind),
175
+ sampleRate,
176
+ context.score.calibration ?? 0,
177
+ );
174
178
  const players = Math.max(1, Math.round(base.players));
175
179
  const seedTick = context.seedTick ?? 0;
176
180
  const volumeLane = track.volumeAutomation ?? [];
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import type { WindPresetName } from "../../../core/winds.ts";
13
13
  import { WIND_TRIM_TABLE } from "./trims.ts";
14
+ import { WIND_TRIM_TABLE_1 } from "./trims1.ts";
14
15
  import type { WindTrim } from "./voice.ts";
15
16
 
16
17
  /** House sustain level of every preset at velocity 0.8, dBFS RMS. */
@@ -44,8 +45,19 @@ function nearestRate(sampleRate: number): number {
44
45
  export function windTrimRow(
45
46
  preset: WindPresetName,
46
47
  sampleRate: number,
48
+ calibration = 0,
47
49
  ): WindTrimRow | undefined {
48
- return WIND_TRIM_TABLE[nearestRate(sampleRate)]?.[preset];
50
+ const rate = nearestRate(sampleRate);
51
+ if (calibration >= 1) {
52
+ const row = WIND_TRIM_TABLE_1[rate]?.[preset];
53
+ if (row) return row;
54
+ }
55
+ return WIND_TRIM_TABLE[rate]?.[preset];
56
+ }
57
+
58
+ /** True when `preset` has a calibration 1 row (the lip-model brass). */
59
+ export function windCalibrated(preset: WindPresetName): boolean {
60
+ return WIND_TRIM_TABLE_1[WIND_TRIM_RATES[0]!]?.[preset] !== undefined;
49
61
  }
50
62
 
51
63
  function interpolate(lo: number, grid: readonly number[], hz: number): number {
@@ -69,12 +81,24 @@ export function rowGain(row: WindTrimRow, hz: number): number {
69
81
  return row.gains ? 10 ** (interpolate(row.lo, row.gains, hz) / 20) : 1;
70
82
  }
71
83
 
72
- export function windTrim(preset: WindPresetName, sampleRate: number): WindTrim {
73
- const row = windTrimRow(preset, sampleRate);
74
- if (!row) return { cents: () => 0, level: 1 };
84
+ /**
85
+ * The voice trim of `preset` at `sampleRate`. Under calibration 1 the
86
+ * lip-model brass use the calibration 1 rows (`trims1.ts`) and the
87
+ * calibrated lips; everything else, and every legacy song, keeps the
88
+ * original table.
89
+ */
90
+ export function windTrim(
91
+ preset: WindPresetName,
92
+ sampleRate: number,
93
+ calibration = 0,
94
+ ): WindTrim {
95
+ const lips = calibration >= 1 && windCalibrated(preset);
96
+ const row = windTrimRow(preset, sampleRate, calibration);
97
+ if (!row) return { cents: () => 0, level: 1, ...(lips ? { lips: 1 } : {}) };
75
98
  return {
76
99
  cents: (hz) => rowCents(row, hz),
77
100
  level: row.level,
78
101
  gain: (hz) => rowGain(row, hz),
102
+ ...(lips ? { lips: 1 as const } : {}),
79
103
  };
80
104
  }
@@ -0,0 +1,297 @@
1
+ // Generated by scripts/calibrate-winds.ts --lips1; do not edit.
2
+ export const WIND_TRIM_TABLE_1: Readonly<
3
+ Record<
4
+ number,
5
+ Readonly<
6
+ Record<
7
+ string,
8
+ Readonly<{
9
+ lo: number;
10
+ cents: readonly number[];
11
+ level: number;
12
+ gains?: readonly number[];
13
+ }>
14
+ >
15
+ >
16
+ >
17
+ > = {
18
+ "22050": {
19
+ trumpet: {
20
+ lo: 50,
21
+ cents: [
22
+ -4225, -4228, -4232, -4238, -4246, -4256, -4267, -4281, -4296, -4313,
23
+ -4333, -4354, -4379, -4404, -4433, -4464, -4499, -4535, -4572, -4616,
24
+ -4665, -4713, -4767, -4823, -4878, -4948, -5019, -5091, -5177, -5257,
25
+ -5352, -5450, -5551, -5652, -5784,
26
+ ],
27
+ level: 0.9712,
28
+ gains: [
29
+ 138, 131, 124, 118, 111, 104, 97, 90, 83, 75, 67, 59, 50, 41, 32, 21,
30
+ 11, 0, -14, -25, -35, -48, -61, -74, -92, -101, -112, -126, -133, -147,
31
+ -153, -161, -169, -181, -176,
32
+ ],
33
+ },
34
+ harmon: {
35
+ lo: 50,
36
+ cents: [
37
+ -4225, -4228, -4232, -4238, -4246, -4256, -4267, -4281, -4296, -4313,
38
+ -4333, -4354, -4379, -4404, -4433, -4464, -4499, -4535, -4572, -4616,
39
+ -4665, -4713, -4767, -4823, -4878, -4948, -5019, -5091, -5177, -5257,
40
+ -5352, -5450, -5551, -5652, -5784,
41
+ ],
42
+ level: 0.6641,
43
+ gains: [
44
+ 1292, 1201, 1089, 1028, 939, 862, 750, 650, 454, 487, 509, 434, 300, 40,
45
+ -245, -50, 106, 79, -24, 39, 0, -165, -484, -728, -450, -232, -166,
46
+ -207, -357, -677, -924, -616, -345, -204, -117,
47
+ ],
48
+ },
49
+ plunger: {
50
+ lo: 50,
51
+ cents: [
52
+ -4235, -4238, -4243, -4249, -4256, -4267, -4278, -4292, -4307, -4324,
53
+ -4344, -4366, -4390, -4416, -4445, -4476, -4511, -4548, -4585, -4629,
54
+ -4678, -4726, -4781, -4837, -4892, -4963, -5034, -5107, -5194, -5274,
55
+ -5370, -5468, -5571, -5672, -5805,
56
+ ],
57
+ level: 0.798,
58
+ gains: [
59
+ 15, 0, -14, -27, -41, -56, -70, -84, -97, -108, -114, -116, -114, -110,
60
+ -106, -99, -86, -65, -33, 11, 62, 111, 157, 192, 216, 232, 240, 247,
61
+ 260, 284, 324, 382, 456, 543, 637,
62
+ ],
63
+ },
64
+ trombone: {
65
+ lo: 38,
66
+ cents: [
67
+ -4316, -4300, -4284, -4272, -4261, -4251, -4243, -4236, -4231, -4227,
68
+ -4225, -4224, -4225, -4228, -4232, -4238, -4246, -4256, -4267, -4281,
69
+ -4296, -4313, -4333, -4354, -4379, -4404, -4433, -4464, -4499, -4535,
70
+ -4572, -4616, -4665, -4713, -4767, -4823, -4878,
71
+ ],
72
+ level: 1.1414,
73
+ gains: [
74
+ 118, 110, 103, 99, 92, 84, 77, 72, 66, 59, 51, 44, 37, 31, 25, 19, 12,
75
+ 7, 0, -6, -13, -20, -26, -34, -42, -50, -58, -68, -77, -88, -101, -112,
76
+ -122, -135, -148, -162, -180,
77
+ ],
78
+ },
79
+ tuba: {
80
+ lo: 26,
81
+ cents: [
82
+ -4028, -3992, -4101, -4190, -4224, -4209, -4268, -4354, -4368, -4358,
83
+ -4338, -4329, -4316, -4300, -4286, -4272, -4261, -4251, -4243, -4236,
84
+ -4231, -4227, -4225, -4224, -4225, -4228, -4232, -4238, -4246, -4256,
85
+ -4267, -4281, -4296, -4313, -4333,
86
+ ],
87
+ level: 1.2795,
88
+ gains: [
89
+ 144, 115, 104, 96, 84, 70, 62, 72, 67, 56, 46, 36, 27, 20, 11, 9, 4, 0,
90
+ -3, -3, -6, -8, -14, -21, -28, -34, -40, -45, -51, -56, -62, -68, -74,
91
+ -80, -86,
92
+ ],
93
+ },
94
+ horn: {
95
+ lo: 39,
96
+ cents: [
97
+ -4278, -4265, -4251, -4240, -4230, -4222, -4215, -4210, -4207, -4204,
98
+ -4203, -4204, -4207, -4211, -4217, -4224, -4234, -4245, -4258, -4273,
99
+ -4290, -4310, -4331, -4355, -4380, -4409, -4439, -4473, -4509, -4545,
100
+ -4588, -4636, -4684, -4737, -4793, -4847, -4916, -4986, -5057, -5142,
101
+ -5220,
102
+ ],
103
+ level: 1.7422,
104
+ gains: [
105
+ 93, 84, 82, 78, 74, 72, 73, 71, 71, 65, 58, 51, 45, 39, 34, 29, 23, 17,
106
+ 12, 6, 0, -6, -12, -19, -26, -33, -42, -50, -60, -72, -82, -92, -105,
107
+ -118, -133, -150, -162, -176, -192, -203, -219,
108
+ ],
109
+ },
110
+ },
111
+ "44100": {
112
+ trumpet: {
113
+ lo: 50,
114
+ cents: [
115
+ -4106, -4101, -4097, -4094, -4092, -4091, -4092, -4094, -4097, -4101,
116
+ -4107, -4114, -4122, -4131, -4142, -4154, -4167, -4182, -4199, -4217,
117
+ -4238, -4259, -4282, -4308, -4335, -4365, -4397, -4432, -4469, -4508,
118
+ -4548, -4594, -4640, -4695, -4751,
119
+ ],
120
+ level: 0.9423,
121
+ gains: [
122
+ 160, 153, 145, 138, 131, 123, 115, 107, 98, 89, 80, 70, 60, 49, 38, 26,
123
+ 13, 0, -14, -28, -42, -57, -73, -88, -104, -119, -134, -149, -163, -176,
124
+ -190, -202, -214, -221, -228,
125
+ ],
126
+ },
127
+ harmon: {
128
+ lo: 50,
129
+ cents: [
130
+ -4106, -4101, -4097, -4094, -4092, -4091, -4092, -4094, -4097, -4101,
131
+ -4107, -4114, -4122, -4131, -4142, -4154, -4167, -4182, -4199, -4217,
132
+ -4238, -4259, -4282, -4308, -4335, -4365, -4397, -4432, -4469, -4508,
133
+ -4548, -4594, -4640, -4695, -4751,
134
+ ],
135
+ level: 0.617,
136
+ gains: [
137
+ 1335, 1242, 1130, 1064, 972, 893, 778, 669, 469, 500, 527, 453, 311, 43,
138
+ -240, -54, 99, 64, -44, 29, 0, -157, -469, -703, -437, -232, -173, -218,
139
+ -379, -699, -947, -655, -387, -236, -154,
140
+ ],
141
+ },
142
+ plunger: {
143
+ lo: 50,
144
+ cents: [
145
+ -4116, -4110, -4106, -4103, -4102, -4101, -4102, -4104, -4107, -4111,
146
+ -4117, -4124, -4132, -4141, -4152, -4164, -4178, -4193, -4210, -4228,
147
+ -4249, -4271, -4294, -4320, -4346, -4377, -4410, -4444, -4481, -4521,
148
+ -4561, -4607, -4654, -4709, -4765,
149
+ ],
150
+ level: 0.792,
151
+ gains: [
152
+ 16, 0, -14, -29, -43, -58, -72, -87, -101, -112, -118, -121, -121, -118,
153
+ -115, -109, -97, -76, -43, 1, 53, 107, 157, 200, 232, 255, 272, 287,
154
+ 307, 337, 381, 443, 521, 609, 705,
155
+ ],
156
+ },
157
+ trombone: {
158
+ lo: 38,
159
+ cents: [
160
+ -4263, -4243, -4223, -4206, -4191, -4176, -4163, -4151, -4139, -4129,
161
+ -4120, -4113, -4106, -4101, -4097, -4094, -4092, -4091, -4092, -4094,
162
+ -4097, -4101, -4107, -4114, -4122, -4131, -4142, -4154, -4167, -4182,
163
+ -4199, -4217, -4238, -4259, -4282, -4308, -4335,
164
+ ],
165
+ level: 1.1326,
166
+ gains: [
167
+ 126, 117, 111, 105, 98, 90, 83, 78, 71, 64, 56, 49, 41, 34, 27, 21, 14,
168
+ 7, 0, -8, -15, -23, -31, -39, -49, -58, -68, -79, -91, -103, -116, -130,
169
+ -144, -158, -174, -189, -206,
170
+ ],
171
+ },
172
+ tuba: {
173
+ lo: 26,
174
+ cents: [
175
+ -4009, -3969, -4075, -4161, -4193, -4176, -4232, -4316, -4327, -4314,
176
+ -4291, -4280, -4263, -4243, -4225, -4207, -4191, -4176, -4163, -4151,
177
+ -4139, -4129, -4120, -4113, -4106, -4101, -4097, -4094, -4092, -4091,
178
+ -4092, -4094, -4097, -4101, -4107,
179
+ ],
180
+ level: 1.2794,
181
+ gains: [
182
+ 146, 117, 106, 98, 86, 71, 64, 74, 69, 58, 47, 37, 28, 21, 12, 9, 4, 0,
183
+ -3, -4, -7, -9, -15, -22, -30, -36, -43, -49, -55, -61, -68, -74, -81,
184
+ -88, -95,
185
+ ],
186
+ },
187
+ horn: {
188
+ lo: 39,
189
+ cents: [
190
+ -4222, -4205, -4187, -4171, -4156, -4143, -4131, -4120, -4110, -4101,
191
+ -4093, -4087, -4081, -4077, -4074, -4072, -4071, -4072, -4073, -4076,
192
+ -4080, -4086, -4092, -4100, -4110, -4120, -4132, -4145, -4160, -4176,
193
+ -4195, -4214, -4236, -4259, -4284, -4310, -4341, -4372, -4406, -4442,
194
+ -4481,
195
+ ],
196
+ level: 1.7269,
197
+ gains: [
198
+ 102, 92, 90, 86, 82, 80, 80, 78, 78, 72, 64, 57, 50, 44, 38, 32, 26, 20,
199
+ 13, 7, 0, -7, -14, -22, -30, -39, -48, -59, -70, -82, -95, -108, -122,
200
+ -138, -153, -170, -186, -203, -220, -236, -252,
201
+ ],
202
+ },
203
+ },
204
+ "48000": {
205
+ trumpet: {
206
+ lo: 50,
207
+ cents: [
208
+ -4097, -4091, -4086, -4082, -4080, -4078, -4078, -4079, -4081, -4084,
209
+ -4089, -4094, -4101, -4109, -4119, -4129, -4141, -4155, -4170, -4186,
210
+ -4204, -4223, -4245, -4267, -4292, -4319, -4348, -4378, -4411, -4448,
211
+ -4487, -4527, -4572, -4618, -4665,
212
+ ],
213
+ level: 0.9403,
214
+ gains: [
215
+ 162, 155, 147, 140, 132, 124, 116, 108, 99, 90, 81, 71, 61, 50, 38, 26,
216
+ 13, 0, -14, -28, -43, -58, -74, -89, -105, -121, -136, -152, -167, -180,
217
+ -193, -206, -216, -225, -236,
218
+ ],
219
+ },
220
+ harmon: {
221
+ lo: 50,
222
+ cents: [
223
+ -4097, -4091, -4086, -4082, -4080, -4078, -4078, -4079, -4081, -4084,
224
+ -4089, -4094, -4101, -4109, -4119, -4129, -4141, -4155, -4170, -4186,
225
+ -4204, -4223, -4245, -4267, -4292, -4319, -4348, -4378, -4411, -4448,
226
+ -4487, -4527, -4572, -4618, -4665,
227
+ ],
228
+ level: 0.6137,
229
+ gains: [
230
+ 1339, 1245, 1133, 1066, 974, 895, 780, 671, 469, 501, 528, 454, 312, 43,
231
+ -240, -55, 99, 63, -46, 28, 0, -156, -467, -701, -436, -232, -173, -220,
232
+ -381, -701, -948, -657, -388, -239, -159,
233
+ ],
234
+ },
235
+ plunger: {
236
+ lo: 50,
237
+ cents: [
238
+ -4106, -4100, -4095, -4092, -4089, -4088, -4088, -4089, -4091, -4094,
239
+ -4099, -4104, -4111, -4119, -4129, -4140, -4152, -4165, -4180, -4196,
240
+ -4215, -4234, -4256, -4279, -4304, -4331, -4360, -4390, -4423, -4461,
241
+ -4499, -4539, -4585, -4632, -4679,
242
+ ],
243
+ level: 0.7915,
244
+ gains: [
245
+ 16, 0, -14, -29, -43, -58, -72, -87, -101, -112, -119, -122, -121, -119,
246
+ -116, -110, -98, -77, -44, 0, 53, 106, 157, 200, 233, 257, 275, 290,
247
+ 310, 341, 386, 448, 526, 615, 711,
248
+ ],
249
+ },
250
+ trombone: {
251
+ lo: 38,
252
+ cents: [
253
+ -4258, -4238, -4219, -4201, -4185, -4170, -4156, -4144, -4132, -4122,
254
+ -4112, -4104, -4097, -4091, -4086, -4082, -4080, -4078, -4078, -4079,
255
+ -4081, -4084, -4089, -4094, -4101, -4109, -4119, -4129, -4141, -4155,
256
+ -4170, -4186, -4204, -4223, -4245, -4267, -4292,
257
+ ],
258
+ level: 1.1319,
259
+ gains: [
260
+ 126, 118, 111, 106, 99, 91, 84, 78, 71, 64, 56, 49, 41, 34, 28, 21, 14,
261
+ 7, 0, -8, -15, -23, -31, -40, -49, -59, -69, -80, -92, -104, -117, -131,
262
+ -146, -160, -176, -192, -208,
263
+ ],
264
+ },
265
+ tuba: {
266
+ lo: 26,
267
+ cents: [
268
+ -4007, -3967, -4073, -4159, -4190, -4173, -4229, -4313, -4324, -4311,
269
+ -4287, -4276, -4258, -4238, -4220, -4202, -4185, -4170, -4156, -4144,
270
+ -4132, -4122, -4112, -4104, -4097, -4091, -4086, -4082, -4080, -4078,
271
+ -4078, -4079, -4081, -4084, -4089,
272
+ ],
273
+ level: 1.2794,
274
+ gains: [
275
+ 146, 117, 106, 98, 86, 72, 65, 74, 69, 58, 48, 38, 28, 21, 12, 9, 4, 0,
276
+ -3, -4, -7, -9, -15, -22, -30, -36, -43, -49, -55, -61, -68, -75, -81,
277
+ -89, -96,
278
+ ],
279
+ },
280
+ horn: {
281
+ lo: 39,
282
+ cents: [
283
+ -4218, -4200, -4182, -4165, -4151, -4137, -4124, -4113, -4102, -4093,
284
+ -4084, -4077, -4071, -4066, -4062, -4060, -4058, -4058, -4059, -4061,
285
+ -4064, -4068, -4073, -4080, -4088, -4097, -4108, -4119, -4133, -4147,
286
+ -4163, -4181, -4200, -4221, -4244, -4268, -4295, -4324, -4353, -4386,
287
+ -4422,
288
+ ],
289
+ level: 1.7256,
290
+ gains: [
291
+ 102, 93, 91, 86, 82, 80, 80, 79, 78, 72, 65, 57, 51, 44, 38, 33, 26, 20,
292
+ 13, 7, 0, -7, -14, -22, -31, -39, -49, -59, -71, -83, -96, -109, -124,
293
+ -139, -155, -172, -188, -205, -223, -240, -255,
294
+ ],
295
+ },
296
+ },
297
+ };
@@ -59,6 +59,13 @@ export type WindTrim = Readonly<{
59
59
  level: number;
60
60
  /** Loudness curve over the range: a gain factor at `hz` (default 1). */
61
61
  gain?: (hz: number) => number;
62
+ /**
63
+ * Calibration 1 lips (q08): the lip resonance sits on the sounding pitch
64
+ * at Q 40 and the lip opening saturates softly, so the lips lock to the
65
+ * bore's mode instead of beating against it (a 23-35% warble every 8 or
66
+ * 9 periods before). Only the calibration 1 trim rows set it.
67
+ */
68
+ lips?: 1;
62
69
  }>;
63
70
 
64
71
  const NO_TRIM: WindTrim = { cents: () => 0, level: 1 };
@@ -328,8 +335,11 @@ export class WindVoice {
328
335
  // STK Brass: a bore of two periods sounding its 2nd mode and a lip
329
336
  // resonance a little below f (constant Q 12, unit DC gain x 3 so
330
337
  // every register speaks); the trim removes the pull (+15..45 c).
338
+ // Calibration 1 tunes the lips to f at Q 40 (see WindTrim.lips).
331
339
  this.d0.set(2 * period - dcBlockDelay(this.dc.r, w), w);
332
- this.lip.set(f * (0.95 + 0.04 * (p.reed - 0.5)), 12, 3, rate);
340
+ if (this.trim.lips)
341
+ this.lip.set(f * (1 + 0.04 * (p.reed - 0.5)), 40, 3, rate);
342
+ else this.lip.set(f * (0.95 + 0.04 * (p.reed - 0.5)), 12, 3, rate);
333
343
  break;
334
344
  }
335
345
  // Brightness for the reed, sax and lip bores: a high shelf from about
@@ -416,7 +426,10 @@ export class WindVoice {
416
426
  const mouth = 0.3 * breath;
417
427
  let delta = this.lip.process(mouth - bore);
418
428
  delta *= delta;
419
- if (delta > 1) delta = 1;
429
+ // Calibration 1: a soft opening (x / (1 + x)) in place of the hard
430
+ // clamp, whose corner fed the warble.
431
+ if (this.trim.lips) delta = delta / (1 + delta);
432
+ else if (delta > 1) delta = 1;
420
433
  const frame = delta * mouth + (1 - delta) * bore;
421
434
  this.d0.push(this.dc.process(frame));
422
435
  return bore * 2;
package/src/auth/cli.ts CHANGED
@@ -24,19 +24,20 @@ import { selectProvider } from "../agent/provider.ts";
24
24
  import { audioStatusLine } from "../audio/engine.ts";
25
25
 
26
26
  export const AUTH_USAGE = `Usage:
27
- dawg login find existing setups and pick a provider (reuses a saved one)
28
- dawg login gateway Vercel AI Gateway: existing key, or create one with the Vercel CLI
29
- dawg login openrouter OpenRouter: sign in through your browser (OAuth PKCE)
30
- dawg login codex ChatGPT/Codex subscription through xcb
31
- dawg login claude Claude subscription through xcb
32
- dawg login --pick show the picker even when a provider is saved
33
- dawg login --key paste an AI Gateway key (hidden input)
34
- dawg login --xcb any xcb account (Devin included)
35
- dawg login gateway --budget <dollars> spend limit for a created key
36
- dawg login codex|claude [--account <id>] [--model <key>]
27
+ dawg model key find existing setups and pick a provider (reuses a saved one)
28
+ dawg model key gateway Vercel AI Gateway: existing key, or create one with the Vercel CLI
29
+ dawg model key openrouter OpenRouter: authorize in your browser (OAuth PKCE)
30
+ dawg model key codex ChatGPT/Codex subscription through xcb
31
+ dawg model key claude Claude subscription through xcb
32
+ dawg model key --pick show the picker even when a provider is saved
33
+ dawg model key --key paste an AI Gateway key (hidden input)
34
+ dawg model key --xcb any xcb account (Devin included)
35
+ dawg model key gateway --budget <dollars> spend limit for a created key
36
+ dawg model key codex|claude [--account <id>] [--model <key>]
37
37
  dawg model [<alias>|<vendor/model>] pick the model (cost per prompt shown)
38
38
  dawg logout [gateway|openrouter|codex|claude|xcb] forget keys and the saved choice
39
- dawg auth status [--check] every provider: detected, active, validated`;
39
+ dawg auth status [--check] every provider: detected, active, validated
40
+ The older spelling of \`model key\` still works as an alias.`;
40
41
 
41
42
  /** Entry for `dawg login|logout|auth|model`. Returns the process exit code. */
42
43
  export async function runAuthCommand(argv: readonly string[]): Promise<number> {
@@ -82,40 +83,41 @@ export async function runAuthCommand(argv: readonly string[]): Promise<number> {
82
83
  return login(parsed.target, deps, parsed.options);
83
84
  }
84
85
 
86
+ /** A one-time card the TUI shows at launch about the agent. */
87
+ export type FirstRunCard = Readonly<{
88
+ text: string;
89
+ tone: "info" | "warning";
90
+ }>;
91
+
85
92
  /**
86
- * The first run of `dawg` in a terminal: when nothing is configured (and the
87
- * picker was never dismissed), or a saved sign-in stopped working, show the
88
- * sign-in picker before the TUI starts. Dismissing it is remembered.
93
+ * The launch note about the agent. dawg opens straight into the TUI: music
94
+ * first, sign-in optional. The first session with no provider gets one
95
+ * faint card, `/model key adds an agent · optional`, and records that it was
96
+ * shown so later sessions stay quiet; a saved sign-in that stopped working
97
+ * says so. `dawg login` and `/login` keep the picker.
89
98
  */
90
- export async function runFirstRunLogin(
99
+ export async function firstRunCard(
91
100
  runner: CommandRunner = systemRunner,
92
- ): Promise<void> {
101
+ ): Promise<FirstRunCard | undefined> {
93
102
  const auth = defaultAuthEnv(runner);
94
103
  const config = await readConfig(auth).catch(() => ({}) as DawgConfig);
95
- if (auth.env.DAWG_PROVIDER) return;
96
- if (!config.provider && config.setup === "skipped") return;
104
+ if (auth.env.DAWG_PROVIDER) return undefined;
105
+ if (!config.provider && config.setup === "skipped") return undefined;
97
106
  const selection = await selectProvider(auth).catch(() => undefined);
98
- if (!selection || selection.kind !== "offline") return;
99
- if (config.provider && !selection.invalidSaved) return;
100
- const io = terminalIO();
101
- if (!io.interactive) return;
107
+ if (!selection || selection.kind !== "offline") return undefined;
102
108
  if (selection.invalidSaved)
103
- io.print(`Your saved sign-in stopped working: ${selection.reason}.`);
104
- else io.print("Welcome to dawg. Sign in to enable the agent (Esc to skip).");
105
- const code = await login("pick", {
106
- auth,
107
- io,
108
- hostname: hostname(),
109
- }).catch((error: unknown) => {
110
- io.print(
111
- `sign-in failed: ${error instanceof Error ? error.message : String(error)}`,
112
- );
113
- return 1;
114
- });
115
- if (code !== 0 && !config.provider)
116
- await writeConfig(auth, { setup: "skipped" }).catch(() => undefined);
109
+ return {
110
+ text: `saved sign-in stopped working: ${selection.reason} · /login`,
111
+ tone: "warning",
112
+ };
113
+ if (config.provider) return undefined;
114
+ await writeConfig(auth, { setup: "skipped" }).catch(() => undefined);
115
+ return { text: FIRST_RUN_CARD, tone: "info" };
117
116
  }
118
117
 
118
+ /** The first session's agent note. */
119
+ export const FIRST_RUN_CARD = "/model key adds an agent · optional";
120
+
119
121
  /** `/login` in the TUI, run while the screen is handed back to the shell. */
120
122
  export async function runTuiLogin(
121
123
  target: LoginTarget,
@@ -83,11 +83,29 @@ export type DawgConfig = Readonly<{
83
83
  openrouterModel?: string;
84
84
  /** Set when the first-run picker was dismissed, so it does not nag. */
85
85
  setup?: "skipped";
86
+ /** Show-me level of agent turns (`/showme`); absent is on. */
87
+ showMe?: "on" | "quiet" | "off";
86
88
  }>;
87
89
 
88
90
  /** `vendor/model` IDs as the AI Gateway and OpenRouter spell them. */
89
91
  export const PROVIDER_MODEL_ID_PATTERN =
90
92
  /^[a-z0-9][a-z0-9-]{0,63}\/[a-z0-9][a-z0-9._-]{0,127}$/i;
93
+ /**
94
+ * OpenRouter also takes a routing variant after a colon: `:nitro`
95
+ * (throughput first), `:floor` (price first), `:free`, `:online` and so on.
96
+ */
97
+ export const OPENROUTER_MODEL_ID_PATTERN =
98
+ /^[a-z0-9][a-z0-9-]{0,63}\/[a-z0-9][a-z0-9._-]{0,127}(?::[a-z0-9-]{1,32})?$/i;
99
+
100
+ /** True for an ID the given provider accepts; any provider when omitted. */
101
+ export function isProviderModelId(
102
+ id: string,
103
+ provider?: "gateway" | "openrouter",
104
+ ): boolean {
105
+ return provider === "gateway"
106
+ ? PROVIDER_MODEL_ID_PATTERN.test(id)
107
+ : OPENROUTER_MODEL_ID_PATTERN.test(id);
108
+ }
91
109
 
92
110
  export type CredentialSource = "env" | "keychain" | "file" | "oidc";
93
111
  export type ResolvedKey = Readonly<{ key: string; source: CredentialSource }>;
@@ -314,6 +332,7 @@ export function parseConfig(value: unknown): DawgConfig {
314
332
  gatewayModel?: string;
315
333
  openrouterModel?: string;
316
334
  setup?: "skipped";
335
+ showMe?: "on" | "quiet" | "off";
317
336
  } = {};
318
337
  if (PROVIDER_CHOICES.includes(record.provider as ProviderChoice))
319
338
  config.provider = record.provider as ProviderChoice;
@@ -323,10 +342,19 @@ export function parseConfig(value: unknown): DawgConfig {
323
342
  }
324
343
  for (const field of ["gatewayModel", "openrouterModel"] as const) {
325
344
  const id = record[field];
326
- if (typeof id === "string" && PROVIDER_MODEL_ID_PATTERN.test(id))
345
+ if (
346
+ typeof id === "string" &&
347
+ isProviderModelId(id, field === "gatewayModel" ? "gateway" : "openrouter")
348
+ )
327
349
  config[field] = id;
328
350
  }
329
351
  if (record.setup === "skipped") config.setup = "skipped";
352
+ if (
353
+ record.showMe === "on" ||
354
+ record.showMe === "quiet" ||
355
+ record.showMe === "off"
356
+ )
357
+ config.showMe = record.showMe;
330
358
  return config;
331
359
  }
332
360
 
@@ -350,6 +378,7 @@ export type ConfigPatch = Partial<{
350
378
  gatewayModel: string | undefined;
351
379
  openrouterModel: string | undefined;
352
380
  setup: "skipped" | undefined;
381
+ showMe: "on" | "quiet" | "off" | undefined;
353
382
  }>;
354
383
 
355
384
  export async function writeConfig(
package/src/auth/login.ts CHANGED
@@ -135,7 +135,7 @@ export async function login(
135
135
  const selection = await selectProvider(deps.auth);
136
136
  if (selection.kind !== "offline") {
137
137
  deps.io.print(
138
- `Signed in · ${providerLabel(selection)}. Switch with \`dawg login <gateway|openrouter|codex|claude>\` or \`dawg model\`.`,
138
+ `Agent key · ${providerLabel(selection)}. Switch with \`dawg model key <gateway|openrouter|codex|claude>\` or \`dawg model\`.`,
139
139
  );
140
140
  return 0;
141
141
  }
@@ -165,7 +165,7 @@ async function loginPick(
165
165
  if (!best) {
166
166
  io.print("No AI provider is set up, and this is not a terminal.");
167
167
  io.print(
168
- "Set AI_GATEWAY_API_KEY or OPENROUTER_API_KEY, or run `dawg login` in a terminal.",
168
+ "Set AI_GATEWAY_API_KEY or OPENROUTER_API_KEY, or run `dawg model key` in a terminal.",
169
169
  );
170
170
  return 1;
171
171
  }
@@ -269,7 +269,7 @@ async function loginGateway(
269
269
  if (!who) {
270
270
  if (!io.interactive) {
271
271
  io.print(
272
- "Not logged in to Vercel. Run `vercel login` first, or re-run `dawg login` in a terminal.",
272
+ "Not logged in to Vercel. Run `vercel login` first, or re-run `dawg model key` in a terminal.",
273
273
  );
274
274
  return 1;
275
275
  }
@@ -319,7 +319,7 @@ async function loginGateway(
319
319
  io.print(
320
320
  `Could not create a key${detail ? `: ${redactKeys(detail)}` : ` (exit ${created.code})`}.`,
321
321
  );
322
- io.print("You can paste one instead with `dawg login --key`.");
322
+ io.print("You can paste one instead with `dawg model key --key`.");
323
323
  return 1;
324
324
  }
325
325
  return saveAndReport(deps, "gateway", key, "created");
@@ -622,7 +622,7 @@ async function loginSubscription(
622
622
  );
623
623
  io.print(` Install: ${XCB_INSTALL}`);
624
624
  io.print(` Docs: ${XCB_DOC_URL}`);
625
- io.print(`Then run \`dawg login ${family}\` again (or set XCB_BIN).`);
625
+ io.print(`Then run \`dawg model key ${family}\` again (or set XCB_BIN).`);
626
626
  return 1;
627
627
  }
628
628
  const read = async (): Promise<XcbAccount[] | undefined> => {
@@ -657,7 +657,7 @@ async function loginSubscription(
657
657
  const setup = `xcb setup ${family}${mine.length > 0 ? " --new" : ""}`;
658
658
  if (!io.interactive) {
659
659
  io.print(
660
- `No ${FAMILY_TITLES[family]} is ready. Run \`${setup}\`, then \`dawg login ${family}\`.`,
660
+ `No ${FAMILY_TITLES[family]} is ready. Run \`${setup}\`, then \`dawg model key ${family}\`.`,
661
661
  );
662
662
  return 1;
663
663
  }
@@ -669,7 +669,9 @@ async function loginSubscription(
669
669
  .trim()
670
670
  .toLowerCase();
671
671
  if (answer !== "" && answer !== "y" && answer !== "yes") {
672
- io.print(`Run \`${setup}\` when ready, then \`dawg login ${family}\`.`);
672
+ io.print(
673
+ `Run \`${setup}\` when ready, then \`dawg model key ${family}\`.`,
674
+ );
673
675
  return 1;
674
676
  }
675
677
  const result = await auth.runner.run(bin, setup.split(" ").slice(1), {
@@ -809,7 +811,9 @@ async function loginXcb(deps: LoginDeps, preset?: XcbPreset): Promise<number> {
809
811
  );
810
812
  io.print(` Install: ${XCB_INSTALL}`);
811
813
  io.print(` Docs: ${XCB_DOC_URL}`);
812
- io.print("Then run `dawg login --xcb` again (or set XCB_BIN to its path).");
814
+ io.print(
815
+ "Then run `dawg model key --xcb` again (or set XCB_BIN to its path).",
816
+ );
813
817
  return 1;
814
818
  }
815
819
  let accounts: readonly XcbAccount[];
@@ -1065,7 +1069,9 @@ export async function logout(
1065
1069
  patch.provider = undefined;
1066
1070
  patch.gatewayModel = undefined;
1067
1071
  patch.openrouterModel = undefined;
1068
- io.print("Cleared the saved provider and model; `dawg login` asks again.");
1072
+ io.print(
1073
+ "Cleared the saved provider and model; `dawg model key` asks again.",
1074
+ );
1069
1075
  } else if (target === "gateway") patch.gatewayModel = undefined;
1070
1076
  else if (target === "openrouter") patch.openrouterModel = undefined;
1071
1077
  patch.setup = undefined;