@hraness/dawg 0.6.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 (93) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/DAWG.md +338 -51
  3. package/README.md +4 -4
  4. package/core/chords.ts +492 -4
  5. package/core/diff.ts +5 -0
  6. package/core/expression.ts +143 -6
  7. package/core/fx.ts +258 -6
  8. package/core/granular.ts +91 -0
  9. package/core/instruments.ts +161 -0
  10. package/core/keys.ts +573 -4
  11. package/core/resonators.ts +291 -3
  12. package/core/score.ts +349 -3
  13. package/core/sdk/print.ts +78 -3
  14. package/core/sdk/v1.ts +1320 -36
  15. package/core/sections.ts +12 -4
  16. package/core/strings.ts +237 -2
  17. package/core/winds.ts +652 -0
  18. package/guides/automation.md +1 -0
  19. package/guides/chords.md +3 -1
  20. package/guides/effects.md +3 -2
  21. package/guides/media.md +1 -1
  22. package/guides/performance.md +3 -0
  23. package/guides/resample.md +26 -0
  24. package/guides/sounds.md +7 -6
  25. package/package.json +1 -1
  26. package/src/agent/agent.ts +8 -2
  27. package/src/agent/chord-tools.ts +153 -1
  28. package/src/agent/expression-tools.ts +91 -0
  29. package/src/agent/ops.ts +4 -1
  30. package/src/agent/preview-tool.ts +2 -1
  31. package/src/agent/resample-tool.ts +131 -0
  32. package/src/agent/tools.ts +200 -15
  33. package/src/agent/xcb-agent.ts +8 -2
  34. package/src/audio/arrange.ts +21 -0
  35. package/src/audio/dsp/envelope.ts +161 -0
  36. package/src/audio/dsp/shift.ts +256 -0
  37. package/src/audio/effects/chain.ts +18 -3
  38. package/src/audio/effects/common.ts +14 -0
  39. package/src/audio/effects/convolution.ts +106 -1
  40. package/src/audio/effects/gaze.ts +354 -0
  41. package/src/audio/engine.ts +46 -5
  42. package/src/audio/fit.ts +45 -0
  43. package/src/audio/granular.ts +352 -21
  44. package/src/audio/instrument-check.ts +9 -5
  45. package/src/audio/instruments.ts +32 -3
  46. package/src/audio/keys/electric.ts +420 -0
  47. package/src/audio/keys/engine.ts +143 -19
  48. package/src/audio/keys/organ.ts +1335 -0
  49. package/src/audio/keys/piano.ts +50 -6
  50. package/src/audio/keys/sympathetic.ts +127 -0
  51. package/src/audio/live-worker.ts +3 -1
  52. package/src/audio/live.ts +136 -9
  53. package/src/audio/preview.ts +15 -1
  54. package/src/audio/resample.ts +285 -0
  55. package/src/audio/resonators.ts +10 -2
  56. package/src/audio/sampler.ts +168 -21
  57. package/src/audio/samples.ts +26 -1
  58. package/src/audio/strings/body.ts +29 -16
  59. package/src/audio/strings/bow.ts +656 -0
  60. package/src/audio/strings/engine.ts +266 -20
  61. package/src/audio/strings/measure.test-helpers.ts +2 -0
  62. package/src/audio/wav.ts +119 -19
  63. package/src/audio/winds/engine.ts +302 -0
  64. package/src/audio/winds/filters.ts +153 -0
  65. package/src/audio/winds/pitch.ts +104 -0
  66. package/src/audio/winds/trim.ts +80 -0
  67. package/src/audio/winds/trims.ts +917 -0
  68. package/src/audio/winds/voice.ts +479 -0
  69. package/src/commands/expression.ts +103 -22
  70. package/src/commands/fx.ts +4 -1
  71. package/src/commands/granular.ts +7 -2
  72. package/src/commands/help.ts +91 -8
  73. package/src/commands/keys.ts +287 -11
  74. package/src/commands/modal.ts +67 -4
  75. package/src/commands/resample.ts +281 -0
  76. package/src/commands/rig.ts +5 -1
  77. package/src/commands/sample.ts +49 -2
  78. package/src/commands/shift.ts +119 -0
  79. package/src/commands/string.ts +28 -2
  80. package/src/commands/strum.ts +473 -0
  81. package/src/commands/wind.ts +244 -0
  82. package/src/main.ts +129 -7
  83. package/src/project/check.ts +5 -1
  84. package/src/render.ts +16 -0
  85. package/src/session/presence.ts +16 -3
  86. package/src/tui/audition.ts +1 -1
  87. package/src/tui/menu.ts +637 -35
  88. package/src/tui/modal-menu.ts +34 -7
  89. package/src/tui/performance-menu.ts +42 -0
  90. package/src/tui/play-chords.ts +104 -3
  91. package/src/tui/play-mode.ts +1 -0
  92. package/src/tui/play-session.ts +34 -9
  93. package/src/tui/wind-menu.ts +144 -0
package/core/sections.ts CHANGED
@@ -14,7 +14,8 @@
14
14
  import { DRUM_VOICES, isDrumInstrument } from "./drums.ts";
15
15
  import { FX_LANES } from "./fx.ts";
16
16
  import { resolveString } from "./strings.ts";
17
- import { modalSettings } from "./resonators.ts";
17
+ import { modalSettings, windSettings } from "./resonators.ts";
18
+ import { slicePedals } from "./expression.ts";
18
19
  import {
19
20
  SCORE_LIMITS,
20
21
  withNoteCap,
@@ -432,7 +433,10 @@ export function sectionScore(score: TrackScore, section: Section): TrackScore {
432
433
  time: timed.time ?? null,
433
434
  bars: section.bars,
434
435
  tracks: score.tracks.map((track) =>
435
- mapAutomation(track, (points) => cropPoints(points, from, to)),
436
+ slicePedals(
437
+ mapAutomation(track, (points) => cropPoints(points, from, to)),
438
+ [{ from, to, offset: 0 }],
439
+ ),
436
440
  ),
437
441
  notes,
438
442
  sections: [],
@@ -1251,7 +1255,9 @@ export function arrangedSlice(
1251
1255
  tempoBpm: timed.tempoBpm,
1252
1256
  time: timed.time ?? null,
1253
1257
  bars,
1254
- tracks: score.tracks.map((track) => sliceLanes(track, pieces)),
1258
+ tracks: score.tracks.map((track) =>
1259
+ slicePedals(sliceLanes(track, pieces), pieces),
1260
+ ),
1255
1261
  notes: arrangedNotes(score, fromBar, fromBar + noteBars).map((note) => ({
1256
1262
  ...note,
1257
1263
  startTick: note.startTick - shift,
@@ -1333,7 +1339,9 @@ function laneFallback(track: Track, lane: string): number | undefined {
1333
1339
  ? track.keys
1334
1340
  : spec.effect === "modal"
1335
1341
  ? track.modal && modalSettings(track.modal)
1336
- : (track.fx as Record<string, unknown> | undefined)?.[spec.effect]
1342
+ : spec.effect === "wind"
1343
+ ? track.wind && windSettings(track.wind)
1344
+ : (track.fx as Record<string, unknown> | undefined)?.[spec.effect]
1337
1345
  ) as Record<string, unknown> | undefined;
1338
1346
  const stored = source?.[spec.param];
1339
1347
  return typeof stored === "number" ? stored : spec.spec.default;
package/core/strings.ts CHANGED
@@ -31,9 +31,9 @@ export const STRING_PARAMS: Readonly<Record<string, ParamSpec>> = Object.freeze(
31
31
  {
32
32
  exciter: {
33
33
  kind: "enum",
34
- values: ["pick", "finger", "hammer", "noise"],
34
+ values: ["pick", "finger", "hammer", "noise", "bow"],
35
35
  default: "pick",
36
- doc: "how the string is set in motion",
36
+ doc: "how the string is set in motion (bow: the bowed voice)",
37
37
  },
38
38
  ring: {
39
39
  kind: "number",
@@ -276,6 +276,63 @@ export const STRING_PARAMS: Readonly<Record<string, ParamSpec>> = Object.freeze(
276
276
  doc: "output level (presets carry a calibrated trim)",
277
277
  strudel: ["gain"],
278
278
  },
279
+ // ---- bowed (f061-bowed): read only when exciter is bow ----
280
+ pressure: {
281
+ kind: "number",
282
+ min: 0,
283
+ max: 1,
284
+ default: 0.5,
285
+ step: 0.05,
286
+ automate: true,
287
+ doc: "bow force within the playable range: flautando at 0, gritty at 1",
288
+ },
289
+ speed: {
290
+ kind: "number",
291
+ min: 0,
292
+ max: 1,
293
+ default: 0.6,
294
+ step: 0.05,
295
+ automate: true,
296
+ doc: "bow speed at full dynamics (loudness)",
297
+ },
298
+ attack: {
299
+ kind: "number",
300
+ min: 0.005,
301
+ max: 4,
302
+ default: 0.08,
303
+ step: log,
304
+ unit: "s",
305
+ doc: "bow-speed ramp at the start of a stroke (swells)",
306
+ strudel: ["attack"],
307
+ },
308
+ tremhz: {
309
+ kind: "number",
310
+ min: 0,
311
+ max: 16,
312
+ default: 0,
313
+ step: 0.5,
314
+ unit: "Hz",
315
+ doc: "tremolo bowing: rapid up and down strokes per second (0 off)",
316
+ },
317
+ sord: {
318
+ kind: "number",
319
+ min: 0,
320
+ max: 1,
321
+ default: 0,
322
+ step: 0.05,
323
+ automate: true,
324
+ doc: "con sordino: the practice mute, darker and softer",
325
+ },
326
+ dyn: {
327
+ kind: "number",
328
+ min: 0,
329
+ max: 1,
330
+ default: 1,
331
+ step: 0.05,
332
+ automate: true,
333
+ doc: "dynamics on top of velocity, drives bow speed and pressure (swells)",
334
+ strudel: ["expression"],
335
+ },
279
336
  },
280
337
  );
281
338
 
@@ -291,6 +348,21 @@ export const STRING_SIMPLE_PARAMS: readonly string[] = Object.freeze([
291
348
  "sym",
292
349
  ]);
293
350
 
351
+ /** Simple menu rows of a bowed track (exciter bow, 0.6.1). */
352
+ export const BOW_SIMPLE_PARAMS: readonly string[] = Object.freeze([
353
+ "pressure",
354
+ "speed",
355
+ "attack",
356
+ "pos",
357
+ "vib",
358
+ "tremhz",
359
+ "sord",
360
+ "dyn",
361
+ "bright",
362
+ "ring",
363
+ "body",
364
+ ]);
365
+
294
366
  /** Parameter name for a Strudel alias (`decay` -> `ring`), or the name. */
295
367
  export function stringParamName(word: string): string | undefined {
296
368
  if (STRING_PARAMS[word]) return word;
@@ -358,6 +430,37 @@ function preset(
358
430
  });
359
431
  }
360
432
 
433
+ // Bowed base (proto/strings/presets.ts `B`, 0.6.1): the bowed rows start
434
+ // here, so BASE and every plucked row stay byte-identical.
435
+ const BOW_BASE: StringValues = {
436
+ ...BASE,
437
+ exciter: "bow",
438
+ ring: 0.6,
439
+ damp: 0.5,
440
+ pos: 0.12,
441
+ release: 0.15,
442
+ pressure: 0.5,
443
+ speed: 0.6,
444
+ attack: 0.08,
445
+ vib: 5.5,
446
+ vibmod: 0.18,
447
+ vibdelay: 0.25,
448
+ body: "violin",
449
+ voices: 4,
450
+ };
451
+
452
+ function bowed(
453
+ doc: string,
454
+ styles: string,
455
+ values: StringValues,
456
+ ): StringPreset {
457
+ return Object.freeze({
458
+ doc,
459
+ styles,
460
+ values: Object.freeze({ ...BOW_BASE, ...values }),
461
+ });
462
+ }
463
+
361
464
  /**
362
465
  * The plucked presets, ported from the prototype (stiffness rewritten from
363
466
  * B = 0.002 s^2 to the 1e-6 x 400^stiff scale, `gain` is the per-preset
@@ -738,6 +841,122 @@ export const STRING_PRESETS: Readonly<Record<string, StringPreset>> =
738
841
  gain: 0.36,
739
842
  },
740
843
  ),
844
+ // ---- bowed (0.6.1, f061-bowed): appended, earlier rows unchanged ----
845
+ violin: bowed("solo violin", "Bach, Brahms, Shostakovich, cantatas", {
846
+ gain: 0.393,
847
+ }),
848
+ viola: bowed("solo viola", "orchestral, chamber", {
849
+ vib: 5.2,
850
+ size: 1.22,
851
+ gain: 0.537,
852
+ }),
853
+ cello: bowed(
854
+ "solo cello",
855
+ "Bach suites, Brahms, Shostakovich, Mitski ballads",
856
+ { ring: 0.9, pos: 0.1, vib: 5, vibmod: 0.2, size: 2.4, gain: 0.415 },
857
+ ),
858
+ contrabass: bowed("arco double bass", "orchestral bass", {
859
+ ring: 1.2,
860
+ pos: 0.1,
861
+ vib: 4.5,
862
+ vibmod: 0.12,
863
+ body: "bass",
864
+ size: 1.2,
865
+ voices: 2,
866
+ gain: 0.316,
867
+ }),
868
+ fiddle: bowed("folk fiddle, straight tone, firm bow", "celtic, bluegrass", {
869
+ pressure: 0.65,
870
+ pos: 0.1,
871
+ attack: 0.03,
872
+ vib: 0,
873
+ gain: 0.504,
874
+ }),
875
+ erhu: bowed("erhu, skin body, wide vibrato", "Chinese, film", {
876
+ pressure: 0.45,
877
+ pos: 0.1,
878
+ vib: 6,
879
+ vibmod: 0.35,
880
+ vibdelay: 0.15,
881
+ body: "skin",
882
+ size: 0.77,
883
+ voices: 2,
884
+ gain: 0.347,
885
+ }),
886
+ kamancheh: bowed("kamancheh spike fiddle", "Persian", {
887
+ pressure: 0.55,
888
+ pos: 0.1,
889
+ vib: 6.5,
890
+ vibmod: 0.25,
891
+ vibdelay: 0.1,
892
+ body: "skin",
893
+ voices: 2,
894
+ gain: 0.43,
895
+ }),
896
+ violins: bowed(
897
+ "violin section",
898
+ "orchestral, Shostakovich, Beethoven, Brahms",
899
+ { vibmod: 0.15, unison: 6, detune: 0.12, spread: 0.7, gain: 0.399 },
900
+ ),
901
+ violas: bowed("viola section", "orchestral", {
902
+ vib: 5.2,
903
+ vibmod: 0.15,
904
+ size: 1.22,
905
+ unison: 4,
906
+ detune: 0.12,
907
+ spread: 0.6,
908
+ gain: 0.57,
909
+ }),
910
+ cellos: bowed("cello section", "orchestral, cantatas", {
911
+ ring: 0.9,
912
+ pos: 0.1,
913
+ vib: 5,
914
+ vibmod: 0.17,
915
+ size: 2.4,
916
+ unison: 4,
917
+ detune: 0.1,
918
+ spread: 0.6,
919
+ gain: 0.46,
920
+ }),
921
+ contrabasses: bowed("double bass section", "orchestral", {
922
+ ring: 1.2,
923
+ pos: 0.1,
924
+ vib: 4.5,
925
+ vibmod: 0.1,
926
+ body: "bass",
927
+ size: 1.2,
928
+ unison: 3,
929
+ detune: 0.08,
930
+ spread: 0.4,
931
+ voices: 2,
932
+ gain: 0.315,
933
+ }),
934
+ pizz: preset(
935
+ "pizzicato string section, plucked with the finger",
936
+ "orchestral, Motown strings, film",
937
+ {
938
+ exciter: "finger",
939
+ ring: 0.6,
940
+ damp: 0.5,
941
+ pos: 0.2,
942
+ bright: 0.45,
943
+ release: 0.08,
944
+ body: "violin",
945
+ unison: 4,
946
+ detune: 0.1,
947
+ spread: 0.6,
948
+ voices: 6,
949
+ gain: 0.497,
950
+ },
951
+ ),
952
+ trem: bowed("tremolo string section, rapid bowing", "film, orchestral", {
953
+ tremhz: 13,
954
+ vibmod: 0.1,
955
+ unison: 4,
956
+ detune: 0.12,
957
+ spread: 0.6,
958
+ gain: 0.507,
959
+ }),
741
960
  });
742
961
 
743
962
  /** Preset names in table order. */
@@ -745,6 +964,17 @@ export const STRING_PRESET_NAMES: readonly string[] = Object.freeze(
745
964
  Object.keys(STRING_PRESETS),
746
965
  );
747
966
 
967
+ /**
968
+ * The bowed-family presets (0.6.1): the rows appended from `violin` on,
969
+ * `pizz` included (a plucked violin section, listed with its family).
970
+ */
971
+ export const BOWED_PRESET_NAMES: readonly string[] = Object.freeze(
972
+ STRING_PRESET_NAMES.slice(STRING_PRESET_NAMES.indexOf("violin")),
973
+ );
974
+
975
+ /** The preset `bowed` with no name plays. */
976
+ export const DEFAULT_BOWED_PRESET = "cello";
977
+
748
978
  /** The preset a bare `string: {}` plays. */
749
979
  export const DEFAULT_STRING_PRESET = "nylon";
750
980
 
@@ -760,6 +990,11 @@ export const STRING_ALIASES: Readonly<Record<string, string>> = Object.freeze({
760
990
  cembalo: "harpsichord",
761
991
  hammered: "dulcimer",
762
992
  sehtar: "setar",
993
+ // bowed (0.6.1); `strings`, `cello` and `contrabass` stay legacy words
994
+ kemence: "kamancheh",
995
+ pizzicato: "pizz",
996
+ tremolo: "trem",
997
+ "bowed-cello": "cello",
763
998
  });
764
999
 
765
1000
  /** A preset name for a word or alias, or undefined. */