@mcptoolshop/ai_jam_session 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 (246) hide show
  1. package/LICENSE +21 -0
  2. package/README.es.md +212 -0
  3. package/README.fr.md +212 -0
  4. package/README.hi.md +212 -0
  5. package/README.it.md +212 -0
  6. package/README.ja.md +214 -0
  7. package/README.md +214 -0
  8. package/README.pt-BR.md +212 -0
  9. package/dist/audio-engine.d.ts +9 -0
  10. package/dist/audio-engine.d.ts.map +1 -0
  11. package/dist/audio-engine.js +422 -0
  12. package/dist/audio-engine.js.map +1 -0
  13. package/dist/cli.d.ts +3 -0
  14. package/dist/cli.d.ts.map +1 -0
  15. package/dist/cli.js +551 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/index.d.ts +32 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +41 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/mcp-server.d.ts +3 -0
  22. package/dist/mcp-server.d.ts.map +1 -0
  23. package/dist/mcp-server.js +903 -0
  24. package/dist/mcp-server.js.map +1 -0
  25. package/dist/midi/parser.d.ts +16 -0
  26. package/dist/midi/parser.d.ts.map +1 -0
  27. package/dist/midi/parser.js +192 -0
  28. package/dist/midi/parser.js.map +1 -0
  29. package/dist/midi/types.d.ts +44 -0
  30. package/dist/midi/types.d.ts.map +1 -0
  31. package/dist/midi/types.js +8 -0
  32. package/dist/midi/types.js.map +1 -0
  33. package/dist/note-parser.d.ts +105 -0
  34. package/dist/note-parser.d.ts.map +1 -0
  35. package/dist/note-parser.js +278 -0
  36. package/dist/note-parser.js.map +1 -0
  37. package/dist/playback/controls.d.ts +124 -0
  38. package/dist/playback/controls.d.ts.map +1 -0
  39. package/dist/playback/controls.js +252 -0
  40. package/dist/playback/controls.js.map +1 -0
  41. package/dist/playback/midi-engine.d.ts +68 -0
  42. package/dist/playback/midi-engine.d.ts.map +1 -0
  43. package/dist/playback/midi-engine.js +227 -0
  44. package/dist/playback/midi-engine.js.map +1 -0
  45. package/dist/playback/position.d.ts +95 -0
  46. package/dist/playback/position.d.ts.map +1 -0
  47. package/dist/playback/position.js +223 -0
  48. package/dist/playback/position.js.map +1 -0
  49. package/dist/playback/timing.d.ts +31 -0
  50. package/dist/playback/timing.d.ts.map +1 -0
  51. package/dist/playback/timing.js +57 -0
  52. package/dist/playback/timing.js.map +1 -0
  53. package/dist/sample-engine.d.ts +17 -0
  54. package/dist/sample-engine.d.ts.map +1 -0
  55. package/dist/sample-engine.js +428 -0
  56. package/dist/sample-engine.js.map +1 -0
  57. package/dist/schemas.d.ts +40 -0
  58. package/dist/schemas.d.ts.map +1 -0
  59. package/dist/schemas.js +42 -0
  60. package/dist/schemas.js.map +1 -0
  61. package/dist/session.d.ts +106 -0
  62. package/dist/session.d.ts.map +1 -0
  63. package/dist/session.js +361 -0
  64. package/dist/session.js.map +1 -0
  65. package/dist/sfz-parser.d.ts +36 -0
  66. package/dist/sfz-parser.d.ts.map +1 -0
  67. package/dist/sfz-parser.js +95 -0
  68. package/dist/sfz-parser.js.map +1 -0
  69. package/dist/smoke.d.ts +2 -0
  70. package/dist/smoke.d.ts.map +1 -0
  71. package/dist/smoke.js +512 -0
  72. package/dist/smoke.js.map +1 -0
  73. package/dist/songs/config/loader.d.ts +14 -0
  74. package/dist/songs/config/loader.d.ts.map +1 -0
  75. package/dist/songs/config/loader.js +53 -0
  76. package/dist/songs/config/loader.js.map +1 -0
  77. package/dist/songs/config/schema.d.ts +70 -0
  78. package/dist/songs/config/schema.d.ts.map +1 -0
  79. package/dist/songs/config/schema.js +53 -0
  80. package/dist/songs/config/schema.js.map +1 -0
  81. package/dist/songs/index.d.ts +16 -0
  82. package/dist/songs/index.d.ts.map +1 -0
  83. package/dist/songs/index.js +20 -0
  84. package/dist/songs/index.js.map +1 -0
  85. package/dist/songs/jam.d.ts +48 -0
  86. package/dist/songs/jam.d.ts.map +1 -0
  87. package/dist/songs/jam.js +324 -0
  88. package/dist/songs/jam.js.map +1 -0
  89. package/dist/songs/loader.d.ts +27 -0
  90. package/dist/songs/loader.d.ts.map +1 -0
  91. package/dist/songs/loader.js +90 -0
  92. package/dist/songs/loader.js.map +1 -0
  93. package/dist/songs/midi/hands.d.ts +46 -0
  94. package/dist/songs/midi/hands.d.ts.map +1 -0
  95. package/dist/songs/midi/hands.js +134 -0
  96. package/dist/songs/midi/hands.js.map +1 -0
  97. package/dist/songs/midi/ingest.d.ts +8 -0
  98. package/dist/songs/midi/ingest.d.ts.map +1 -0
  99. package/dist/songs/midi/ingest.js +191 -0
  100. package/dist/songs/midi/ingest.js.map +1 -0
  101. package/dist/songs/midi/measures.d.ts +41 -0
  102. package/dist/songs/midi/measures.d.ts.map +1 -0
  103. package/dist/songs/midi/measures.js +64 -0
  104. package/dist/songs/midi/measures.js.map +1 -0
  105. package/dist/songs/midi/types.d.ts +25 -0
  106. package/dist/songs/midi/types.d.ts.map +1 -0
  107. package/dist/songs/midi/types.js +8 -0
  108. package/dist/songs/midi/types.js.map +1 -0
  109. package/dist/songs/registry.d.ts +37 -0
  110. package/dist/songs/registry.d.ts.map +1 -0
  111. package/dist/songs/registry.js +197 -0
  112. package/dist/songs/registry.js.map +1 -0
  113. package/dist/songs/types.d.ts +99 -0
  114. package/dist/songs/types.d.ts.map +1 -0
  115. package/dist/songs/types.js +27 -0
  116. package/dist/songs/types.js.map +1 -0
  117. package/dist/teaching/live-midi-feedback.d.ts +36 -0
  118. package/dist/teaching/live-midi-feedback.d.ts.map +1 -0
  119. package/dist/teaching/live-midi-feedback.js +259 -0
  120. package/dist/teaching/live-midi-feedback.js.map +1 -0
  121. package/dist/teaching/midi-feedback.d.ts +33 -0
  122. package/dist/teaching/midi-feedback.d.ts.map +1 -0
  123. package/dist/teaching/midi-feedback.js +208 -0
  124. package/dist/teaching/midi-feedback.js.map +1 -0
  125. package/dist/teaching/sing-on-midi.d.ts +77 -0
  126. package/dist/teaching/sing-on-midi.d.ts.map +1 -0
  127. package/dist/teaching/sing-on-midi.js +186 -0
  128. package/dist/teaching/sing-on-midi.js.map +1 -0
  129. package/dist/teaching.d.ts +148 -0
  130. package/dist/teaching.d.ts.map +1 -0
  131. package/dist/teaching.js +453 -0
  132. package/dist/teaching.js.map +1 -0
  133. package/dist/test-sound.d.ts +3 -0
  134. package/dist/test-sound.d.ts.map +1 -0
  135. package/dist/test-sound.js +41 -0
  136. package/dist/test-sound.js.map +1 -0
  137. package/dist/types.d.ts +229 -0
  138. package/dist/types.d.ts.map +1 -0
  139. package/dist/types.js +22 -0
  140. package/dist/types.js.map +1 -0
  141. package/dist/vmpk.d.ts +23 -0
  142. package/dist/vmpk.d.ts.map +1 -0
  143. package/dist/vmpk.js +236 -0
  144. package/dist/vmpk.js.map +1 -0
  145. package/logo.png +0 -0
  146. package/package.json +70 -0
  147. package/songs/builtin/a-change-is-gonna-come.json +95 -0
  148. package/songs/builtin/a-thousand-years.json +93 -0
  149. package/songs/builtin/aint-no-sunshine.json +98 -0
  150. package/songs/builtin/all-blues.json +92 -0
  151. package/songs/builtin/autumn-leaves.json +100 -0
  152. package/songs/builtin/baba-oriley.json +91 -0
  153. package/songs/builtin/bach-invention-no1.json +70 -0
  154. package/songs/builtin/bach-prelude-c-major-bwv846.json +1282 -0
  155. package/songs/builtin/basic-12-bar-blues.json +119 -0
  156. package/songs/builtin/beethoven-waldstein-mvt1.json +7766 -0
  157. package/songs/builtin/bennie-and-the-jets.json +92 -0
  158. package/songs/builtin/besame-mucho.json +93 -0
  159. package/songs/builtin/black-orpheus.json +92 -0
  160. package/songs/builtin/blue-bossa.json +94 -0
  161. package/songs/builtin/blues-in-g.json +92 -0
  162. package/songs/builtin/bohemian-rhapsody-intro.json +94 -0
  163. package/songs/builtin/boogie-woogie-basics.json +93 -0
  164. package/songs/builtin/bossa-nova-basic.json +95 -0
  165. package/songs/builtin/chopin-nocturne-op9-no2.json +70 -0
  166. package/songs/builtin/cinema-paradiso.json +94 -0
  167. package/songs/builtin/clair-de-lune.json +11511 -0
  168. package/songs/builtin/clocks.json +91 -0
  169. package/songs/builtin/crystal-stream.json +70 -0
  170. package/songs/builtin/desafinado.json +93 -0
  171. package/songs/builtin/dont-stop-believin.json +91 -0
  172. package/songs/builtin/dream-on.json +100 -0
  173. package/songs/builtin/easy-winners.json +70 -0
  174. package/songs/builtin/el-condor-pasa.json +93 -0
  175. package/songs/builtin/elite-syncopations.json +70 -0
  176. package/songs/builtin/evening-calm.json +70 -0
  177. package/songs/builtin/everyday-blues.json +93 -0
  178. package/songs/builtin/fly-me-to-the-moon.json +91 -0
  179. package/songs/builtin/forrest-gump-suite.json +93 -0
  180. package/songs/builtin/fur-elise.json +20094 -0
  181. package/songs/builtin/georgia-on-my-mind.json +93 -0
  182. package/songs/builtin/girl-from-ipanema.json +92 -0
  183. package/songs/builtin/gladiolus-rag.json +70 -0
  184. package/songs/builtin/great-balls-of-fire.json +92 -0
  185. package/songs/builtin/guantanamera.json +92 -0
  186. package/songs/builtin/hallelujah.json +92 -0
  187. package/songs/builtin/hedwigs-theme.json +93 -0
  188. package/songs/builtin/hotel-california.json +92 -0
  189. package/songs/builtin/imagine.json +92 -0
  190. package/songs/builtin/just-the-two-of-us.json +92 -0
  191. package/songs/builtin/la-bamba.json +92 -0
  192. package/songs/builtin/layla-piano-coda.json +93 -0
  193. package/songs/builtin/lean-on-me.json +91 -0
  194. package/songs/builtin/let-it-be.json +101 -0
  195. package/songs/builtin/lets-stay-together.json +93 -0
  196. package/songs/builtin/magnetic-rag.json +70 -0
  197. package/songs/builtin/maple-leaf-rag.json +99 -0
  198. package/songs/builtin/mia-and-sebastians-theme.json +93 -0
  199. package/songs/builtin/minor-blues-in-a.json +94 -0
  200. package/songs/builtin/misty.json +94 -0
  201. package/songs/builtin/moon-river.json +93 -0
  202. package/songs/builtin/moonlight-sonata-mvt1.json +101 -0
  203. package/songs/builtin/morning-light.json +70 -0
  204. package/songs/builtin/mountain-dawn.json +70 -0
  205. package/songs/builtin/mozart-k545-mvt1.json +2956 -0
  206. package/songs/builtin/my-girl.json +92 -0
  207. package/songs/builtin/night-train.json +92 -0
  208. package/songs/builtin/november-rain.json +93 -0
  209. package/songs/builtin/ocean-waves.json +70 -0
  210. package/songs/builtin/over-the-rainbow.json +93 -0
  211. package/songs/builtin/oye-como-va.json +93 -0
  212. package/songs/builtin/peacherine-rag.json +70 -0
  213. package/songs/builtin/piano-man.json +92 -0
  214. package/songs/builtin/pineapple-rag.json +70 -0
  215. package/songs/builtin/pink-panther.json +94 -0
  216. package/songs/builtin/ragtime-dance.json +70 -0
  217. package/songs/builtin/river-flows-in-you.json +102 -0
  218. package/songs/builtin/rocket-man.json +92 -0
  219. package/songs/builtin/satie-gymnopedie-no1.json +70 -0
  220. package/songs/builtin/satin-doll.json +93 -0
  221. package/songs/builtin/schindlers-list.json +96 -0
  222. package/songs/builtin/schumann-traumerei.json +70 -0
  223. package/songs/builtin/sitting-on-the-dock.json +91 -0
  224. package/songs/builtin/slow-blues-in-bb.json +98 -0
  225. package/songs/builtin/snowfall.json +70 -0
  226. package/songs/builtin/so-what.json +92 -0
  227. package/songs/builtin/solace.json +70 -0
  228. package/songs/builtin/someone-like-you.json +92 -0
  229. package/songs/builtin/spirited-away.json +94 -0
  230. package/songs/builtin/st-louis-blues.json +93 -0
  231. package/songs/builtin/stairway-intro.json +93 -0
  232. package/songs/builtin/starlight-waltz.json +70 -0
  233. package/songs/builtin/stay-with-me.json +93 -0
  234. package/songs/builtin/stormy-monday.json +94 -0
  235. package/songs/builtin/superstition.json +93 -0
  236. package/songs/builtin/sweet-home-chicago.json +93 -0
  237. package/songs/builtin/take-five.json +92 -0
  238. package/songs/builtin/take-the-a-train.json +93 -0
  239. package/songs/builtin/the-entertainer.json +98 -0
  240. package/songs/builtin/the-godfather-waltz.json +93 -0
  241. package/songs/builtin/thrill-is-gone.json +94 -0
  242. package/songs/builtin/twilight-garden.json +70 -0
  243. package/songs/builtin/watermark.json +70 -0
  244. package/songs/builtin/wave.json +93 -0
  245. package/songs/builtin/whats-going-on.json +93 -0
  246. package/songs/builtin/yesterday.json +92 -0
@@ -0,0 +1,31 @@
1
+ import type { MidiNoteEvent } from "../midi/types.js";
2
+ /** A scheduled event with wall-clock time in milliseconds. */
3
+ export interface ScheduledEvent extends MidiNoteEvent {
4
+ /** When to fire noteOn, in ms from playback start. */
5
+ scheduledOnMs: number;
6
+ /** When to fire noteOff, in ms from playback start. */
7
+ scheduledOffMs: number;
8
+ }
9
+ /**
10
+ * Calculate scheduled wall-clock times for all events.
11
+ *
12
+ * @param events Sorted note events with absolute time in seconds.
13
+ * @param speed Speed multiplier (1.0 = normal).
14
+ * @returns Events with scheduledOnMs and scheduledOffMs.
15
+ */
16
+ export declare function calculateSchedule(events: readonly MidiNoteEvent[], speed?: number): ScheduledEvent[];
17
+ /**
18
+ * Get the total playback duration in milliseconds at a given speed.
19
+ */
20
+ export declare function totalDurationMs(events: readonly MidiNoteEvent[], speed?: number): number;
21
+ /**
22
+ * Group events into time clusters (events within `thresholdMs` of each other).
23
+ * Useful for chord detection or batch scheduling.
24
+ */
25
+ export declare function clusterEvents(events: readonly MidiNoteEvent[], thresholdMs?: number): MidiNoteEvent[][];
26
+ /**
27
+ * Slice events to a time range (in seconds, at speed 1.0).
28
+ * Returns events where time >= startSec and time < endSec.
29
+ */
30
+ export declare function sliceEventsByTime(events: readonly MidiNoteEvent[], startSec: number, endSec: number): MidiNoteEvent[];
31
+ //# sourceMappingURL=timing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../../src/playback/timing.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,8DAA8D;AAC9D,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,KAAK,GAAE,MAAY,GAClB,cAAc,EAAE,CAMlB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,KAAK,GAAE,MAAY,GAClB,MAAM,CAIR;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,WAAW,GAAE,MAAU,GACtB,aAAa,EAAE,EAAE,CAkBnB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,aAAa,EAAE,CAEjB"}
@@ -0,0 +1,57 @@
1
+ // ─── Timing & Scheduling Utilities ──────────────────────────────────────────
2
+ //
3
+ // Helpers for MIDI playback timing calculations.
4
+ // ─────────────────────────────────────────────────────────────────────────────
5
+ /**
6
+ * Calculate scheduled wall-clock times for all events.
7
+ *
8
+ * @param events Sorted note events with absolute time in seconds.
9
+ * @param speed Speed multiplier (1.0 = normal).
10
+ * @returns Events with scheduledOnMs and scheduledOffMs.
11
+ */
12
+ export function calculateSchedule(events, speed = 1.0) {
13
+ return events.map((e) => ({
14
+ ...e,
15
+ scheduledOnMs: (e.time / speed) * 1000,
16
+ scheduledOffMs: ((e.time + e.duration) / speed) * 1000,
17
+ }));
18
+ }
19
+ /**
20
+ * Get the total playback duration in milliseconds at a given speed.
21
+ */
22
+ export function totalDurationMs(events, speed = 1.0) {
23
+ if (events.length === 0)
24
+ return 0;
25
+ const last = events[events.length - 1];
26
+ return ((last.time + last.duration) / speed) * 1000;
27
+ }
28
+ /**
29
+ * Group events into time clusters (events within `thresholdMs` of each other).
30
+ * Useful for chord detection or batch scheduling.
31
+ */
32
+ export function clusterEvents(events, thresholdMs = 5) {
33
+ if (events.length === 0)
34
+ return [];
35
+ const thresholdSec = thresholdMs / 1000;
36
+ const clusters = [];
37
+ let current = [events[0]];
38
+ for (let i = 1; i < events.length; i++) {
39
+ if (events[i].time - events[i - 1].time <= thresholdSec) {
40
+ current.push(events[i]);
41
+ }
42
+ else {
43
+ clusters.push(current);
44
+ current = [events[i]];
45
+ }
46
+ }
47
+ clusters.push(current);
48
+ return clusters;
49
+ }
50
+ /**
51
+ * Slice events to a time range (in seconds, at speed 1.0).
52
+ * Returns events where time >= startSec and time < endSec.
53
+ */
54
+ export function sliceEventsByTime(events, startSec, endSec) {
55
+ return events.filter((e) => e.time >= startSec && e.time < endSec);
56
+ }
57
+ //# sourceMappingURL=timing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing.js","sourceRoot":"","sources":["../../src/playback/timing.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,iDAAiD;AACjD,gFAAgF;AAYhF;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAgC,EAChC,QAAgB,GAAG;IAEnB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxB,GAAG,CAAC;QACJ,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,IAAI;QACtC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI;KACvD,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAgC,EAChC,QAAgB,GAAG;IAEnB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAgC,EAChC,cAAsB,CAAC;IAEvB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,MAAM,YAAY,GAAG,WAAW,GAAG,IAAI,CAAC;IACxC,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,IAAI,OAAO,GAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,YAAY,EAAE,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IACD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEvB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAgC,EAChC,QAAgB,EAChB,MAAc;IAEd,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,QAAQ,IAAI,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;AACrE,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { VmpkConnector } from "./types.js";
2
+ export interface SampleEngineOptions {
3
+ /** Path to the AccurateSalamander directory (contains sfz_minimum/, 48khz24bit/). */
4
+ samplesDir: string;
5
+ /** SFZ profile to use. Default: "sfz_minimum". */
6
+ sfzProfile?: "sfz_minimum" | "sfz_daw" | "sfz_live";
7
+ /** Maximum simultaneous voices. Default: 48. */
8
+ maxPolyphony?: number;
9
+ }
10
+ /**
11
+ * Create a sample-based piano engine using Accurate-Salamander samples.
12
+ *
13
+ * Implements VmpkConnector so it's a drop-in replacement for the old
14
+ * oscillator engine.
15
+ */
16
+ export declare function createSampleEngine(options: SampleEngineOptions): VmpkConnector;
17
+ //# sourceMappingURL=sample-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample-engine.d.ts","sourceRoot":"","sources":["../src/sample-engine.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,YAAY,CAAC;AAKtE,MAAM,WAAW,mBAAmB;IAClC,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,UAAU,CAAC,EAAE,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;IACpD,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAwFD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,aAAa,CAmY9E"}
@@ -0,0 +1,428 @@
1
+ // ─── pianoai: Sample-Based Piano Engine ─────────────────────────────────────
2
+ //
3
+ // Plays real piano samples from the Accurate-Salamander Grand Piano library.
4
+ // 480 WAV samples (48kHz/24-bit), 16 velocity layers, 88 keys.
5
+ //
6
+ // This replaces the oscillator-based engine with actual recorded sound.
7
+ //
8
+ // Usage:
9
+ // const piano = createSampleEngine({ samplesDir: "samples/AccurateSalamander" });
10
+ // await piano.connect(); // loads SFZ + WAV files (~1.6GB)
11
+ // piano.noteOn(60, 100); // middle C, forte — real piano sound
12
+ // piano.noteOff(60);
13
+ // await piano.disconnect();
14
+ // ─────────────────────────────────────────────────────────────────────────────
15
+ import { readFileSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { parseSfzFile } from "./sfz-parser.js";
18
+ function buildRegionMap(regions) {
19
+ const map = new Map();
20
+ for (const r of regions) {
21
+ for (let key = r.lokey; key <= r.hikey; key++) {
22
+ let slots = map.get(key);
23
+ if (!slots) {
24
+ slots = [];
25
+ map.set(key, slots);
26
+ }
27
+ slots.push({ lovel: r.lovel, hivel: r.hivel, region: r });
28
+ }
29
+ }
30
+ // Sort by lovel for binary search
31
+ for (const [, slots] of map) {
32
+ slots.sort((a, b) => a.lovel - b.lovel);
33
+ }
34
+ return map;
35
+ }
36
+ /** Find the matching region for a given MIDI note + velocity. */
37
+ function findRegion(regionMap, note, velocity) {
38
+ const slots = regionMap.get(note);
39
+ if (!slots || slots.length === 0)
40
+ return null;
41
+ for (const slot of slots) {
42
+ if (velocity >= slot.lovel && velocity <= slot.hivel)
43
+ return slot.region;
44
+ }
45
+ // Fallback: closest velocity
46
+ return slots[slots.length - 1].region;
47
+ }
48
+ // ─── Audio Helpers ──────────────────────────────────────────────────────────
49
+ /** Stereo pan: bass left, treble right (player perspective). */
50
+ function noteToPan(note) {
51
+ return Math.max(-0.7, Math.min(0.7, ((note - 21) / 87) * 1.4 - 0.7));
52
+ }
53
+ /** Convert dB to linear gain. */
54
+ function dbToGain(db) {
55
+ return Math.pow(10, db / 20);
56
+ }
57
+ /** Compute playback rate for pitch shifting: cents from sample's pitch center. */
58
+ function centsToRate(cents) {
59
+ return Math.pow(2, cents / 1200);
60
+ }
61
+ // ─── Lazy Import ────────────────────────────────────────────────────────────
62
+ let _AudioContext = null;
63
+ async function loadAudioContext() {
64
+ if (!_AudioContext) {
65
+ const mod = await import("node-web-audio-api");
66
+ _AudioContext = mod.AudioContext;
67
+ }
68
+ return _AudioContext;
69
+ }
70
+ // ─── Engine ─────────────────────────────────────────────────────────────────
71
+ /**
72
+ * Create a sample-based piano engine using Accurate-Salamander samples.
73
+ *
74
+ * Implements VmpkConnector so it's a drop-in replacement for the old
75
+ * oscillator engine.
76
+ */
77
+ export function createSampleEngine(options) {
78
+ const { samplesDir, sfzProfile = "sfz_minimum", maxPolyphony = 48, } = options;
79
+ let ctx = null;
80
+ let currentStatus = "disconnected";
81
+ let compressor = null;
82
+ let master = null;
83
+ // Sample data
84
+ let sfzData = null;
85
+ let regionMap = null;
86
+ const audioBuffers = new Map(); // sample path → AudioBuffer
87
+ // Voice management
88
+ const activeVoices = new Map();
89
+ const voiceOrder = [];
90
+ // ── WAV Parsing ──
91
+ /**
92
+ * Parse a WAV file into an AudioBuffer manually.
93
+ * Handles 16-bit and 24-bit PCM (the Accurate-Salamander set is 24-bit/48kHz).
94
+ * This avoids needing the async decodeAudioData call for 480+ files.
95
+ */
96
+ function parseWavToAudioBuffer(filePath) {
97
+ const fileData = readFileSync(filePath);
98
+ const view = new DataView(fileData.buffer, fileData.byteOffset, fileData.byteLength);
99
+ // ── Find 'fmt ' chunk ──
100
+ let offset = 12; // skip RIFF header (4 RIFF + 4 size + 4 WAVE)
101
+ let fmtOffset = -1;
102
+ let dataOffset = -1;
103
+ let dataSize = 0;
104
+ while (offset < view.byteLength - 8) {
105
+ const chunkId = String.fromCharCode(view.getUint8(offset)) +
106
+ String.fromCharCode(view.getUint8(offset + 1)) +
107
+ String.fromCharCode(view.getUint8(offset + 2)) +
108
+ String.fromCharCode(view.getUint8(offset + 3));
109
+ const chunkSize = view.getUint32(offset + 4, true);
110
+ if (chunkId === "fmt ") {
111
+ fmtOffset = offset + 8;
112
+ }
113
+ else if (chunkId === "data") {
114
+ dataOffset = offset + 8;
115
+ dataSize = chunkSize;
116
+ }
117
+ if (fmtOffset >= 0 && dataOffset >= 0)
118
+ break;
119
+ // Next chunk (aligned to 2 bytes)
120
+ offset += 8 + chunkSize + (chunkSize % 2);
121
+ }
122
+ if (fmtOffset < 0)
123
+ throw new Error(`No 'fmt ' chunk in ${filePath}`);
124
+ if (dataOffset < 0)
125
+ throw new Error(`No 'data' chunk in ${filePath}`);
126
+ // ── Parse format ──
127
+ let audioFormat = view.getUint16(fmtOffset, true);
128
+ const numChannels = view.getUint16(fmtOffset + 2, true);
129
+ const sampleRate = view.getUint32(fmtOffset + 4, true);
130
+ let bitsPerSample = view.getUint16(fmtOffset + 14, true);
131
+ // WAVE_FORMAT_EXTENSIBLE (0xFFFE / 65534): real format is in SubFormat GUID
132
+ if (audioFormat === 0xFFFE) {
133
+ // cbSize at offset 16 (should be 22), wValidBitsPerSample at offset 18
134
+ const validBits = view.getUint16(fmtOffset + 18, true);
135
+ if (validBits > 0)
136
+ bitsPerSample = validBits;
137
+ // SubFormat GUID starts at offset 24, first 2 bytes = actual format tag
138
+ audioFormat = view.getUint16(fmtOffset + 24, true);
139
+ }
140
+ if (audioFormat !== 1 && audioFormat !== 3) {
141
+ throw new Error(`Unsupported WAV format ${audioFormat} (need PCM=1 or IEEE_FLOAT=3) in ${filePath}`);
142
+ }
143
+ const isFloat = audioFormat === 3;
144
+ const bytesPerSample = bitsPerSample / 8;
145
+ const numFrames = Math.floor(dataSize / (numChannels * bytesPerSample));
146
+ // ── Create AudioBuffer ──
147
+ const audioBuffer = ctx.createBuffer(numChannels, numFrames, sampleRate);
148
+ // ── Decode PCM data into Float32 channel arrays ──
149
+ for (let ch = 0; ch < numChannels; ch++) {
150
+ const channelData = new Float32Array(numFrames);
151
+ for (let i = 0; i < numFrames; i++) {
152
+ const sampleOffset = dataOffset + (i * numChannels + ch) * bytesPerSample;
153
+ let sample;
154
+ if (isFloat && bitsPerSample === 32) {
155
+ // 32-bit IEEE float — already -1..1
156
+ sample = view.getFloat32(sampleOffset, true);
157
+ }
158
+ else if (isFloat && bitsPerSample === 64) {
159
+ // 64-bit IEEE float
160
+ sample = view.getFloat64(sampleOffset, true);
161
+ }
162
+ else if (bitsPerSample === 24) {
163
+ // 24-bit signed little-endian → float
164
+ const b0 = view.getUint8(sampleOffset);
165
+ const b1 = view.getUint8(sampleOffset + 1);
166
+ const b2 = view.getUint8(sampleOffset + 2);
167
+ const raw = b0 | (b1 << 8) | (b2 << 16);
168
+ // Sign extend from 24-bit
169
+ sample = (raw > 0x7FFFFF ? raw - 0x1000000 : raw) / 8388608; // 2^23
170
+ }
171
+ else if (bitsPerSample === 16) {
172
+ // 16-bit signed little-endian → float
173
+ sample = view.getInt16(sampleOffset, true) / 32768; // 2^15
174
+ }
175
+ else {
176
+ throw new Error(`Unsupported bit depth ${bitsPerSample} in ${filePath}`);
177
+ }
178
+ channelData[i] = sample;
179
+ }
180
+ audioBuffer.copyToChannel(channelData, ch);
181
+ }
182
+ return audioBuffer;
183
+ }
184
+ // ── Sample Loading ──
185
+ /** Load all unique sample files referenced by the SFZ regions. */
186
+ function loadSamples() {
187
+ if (!sfzData)
188
+ return;
189
+ const sfzDir = join(samplesDir, sfzProfile);
190
+ const uniqueSamples = new Set();
191
+ for (const r of sfzData.regions) {
192
+ uniqueSamples.add(r.sample);
193
+ }
194
+ console.error(`Loading ${uniqueSamples.size} piano samples...`);
195
+ const startTime = Date.now();
196
+ let loaded = 0;
197
+ for (const samplePath of uniqueSamples) {
198
+ // Resolve relative path from SFZ file location
199
+ const fullPath = join(sfzDir, samplePath);
200
+ try {
201
+ const audioBuffer = parseWavToAudioBuffer(fullPath);
202
+ audioBuffers.set(samplePath, audioBuffer);
203
+ loaded++;
204
+ if (loaded % 50 === 0) {
205
+ console.error(` ${loaded}/${uniqueSamples.size} samples loaded`);
206
+ }
207
+ }
208
+ catch (err) {
209
+ console.error(` SKIP ${samplePath}: ${err instanceof Error ? err.message : String(err)}`);
210
+ }
211
+ }
212
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
213
+ console.error(`Loaded ${loaded}/${uniqueSamples.size} samples in ${elapsed}s`);
214
+ }
215
+ // ── Voice Management ──
216
+ function stealOldest() {
217
+ if (voiceOrder.length === 0)
218
+ return;
219
+ const oldestNote = voiceOrder.shift();
220
+ const voice = activeVoices.get(oldestNote);
221
+ if (voice) {
222
+ killVoice(voice);
223
+ activeVoices.delete(oldestNote);
224
+ }
225
+ }
226
+ function removeFromOrder(note) {
227
+ const idx = voiceOrder.indexOf(note);
228
+ if (idx >= 0)
229
+ voiceOrder.splice(idx, 1);
230
+ }
231
+ function killVoice(voice) {
232
+ if (voice.cleanupTimer) {
233
+ clearTimeout(voice.cleanupTimer);
234
+ voice.cleanupTimer = null;
235
+ }
236
+ try {
237
+ voice.source.stop();
238
+ }
239
+ catch { /* already stopped */ }
240
+ try {
241
+ voice.source.disconnect();
242
+ }
243
+ catch { /* ok */ }
244
+ try {
245
+ voice.gain.disconnect();
246
+ }
247
+ catch { /* ok */ }
248
+ try {
249
+ voice.panner.disconnect();
250
+ }
251
+ catch { /* ok */ }
252
+ }
253
+ function releaseVoice(voice) {
254
+ if (voice.released)
255
+ return;
256
+ voice.released = true;
257
+ const now = ctx.currentTime;
258
+ const releaseTime = sfzData?.ampegRelease ?? 1.0;
259
+ // Fade out over release time
260
+ voice.gain.gain.cancelScheduledValues(now);
261
+ voice.gain.gain.setValueAtTime(voice.gain.gain.value, now);
262
+ voice.gain.gain.exponentialRampToValueAtTime(0.001, now + releaseTime);
263
+ // Cleanup after release
264
+ voice.cleanupTimer = setTimeout(() => killVoice(voice), (releaseTime + 0.1) * 1000);
265
+ }
266
+ // ── VmpkConnector Implementation ──
267
+ return {
268
+ async connect() {
269
+ if (currentStatus === "connected")
270
+ return;
271
+ currentStatus = "connecting";
272
+ try {
273
+ // 1. Create audio context
274
+ const AC = await loadAudioContext();
275
+ ctx = new AC({ sampleRate: 48000, latencyHint: "playback" });
276
+ // 2. Master chain: compressor → gain → speakers
277
+ compressor = ctx.createDynamicsCompressor();
278
+ compressor.threshold.value = -12;
279
+ compressor.knee.value = 10;
280
+ compressor.ratio.value = 4;
281
+ compressor.attack.value = 0.003;
282
+ compressor.release.value = 0.25;
283
+ master = ctx.createGain();
284
+ master.gain.value = 0.85;
285
+ compressor.connect(master);
286
+ master.connect(ctx.destination);
287
+ // 3. Parse SFZ
288
+ const sfzFile = join(samplesDir, sfzProfile, sfzProfile === "sfz_minimum"
289
+ ? "Accurate-SalamanderGrandPiano_flat.Recommended.sfz"
290
+ : sfzProfile === "sfz_daw"
291
+ ? "Accurate-SalamanderGrandPiano_flat.Recommended.sfz"
292
+ : "Accurate-SalamanderGrandPiano_flat.Recommended.sfz");
293
+ sfzData = parseSfzFile(sfzFile);
294
+ regionMap = buildRegionMap(sfzData.regions);
295
+ // 4. Load all WAV samples
296
+ loadSamples();
297
+ currentStatus = "connected";
298
+ console.error(`Piano engine connected (sample-based, ${audioBuffers.size} samples)`);
299
+ }
300
+ catch (err) {
301
+ currentStatus = "error";
302
+ throw new Error(`Failed to start sample engine: ${err instanceof Error ? err.message : String(err)}`);
303
+ }
304
+ },
305
+ async disconnect() {
306
+ for (const [, voice] of activeVoices) {
307
+ try {
308
+ killVoice(voice);
309
+ }
310
+ catch { /* ok */ }
311
+ }
312
+ activeVoices.clear();
313
+ voiceOrder.length = 0;
314
+ audioBuffers.clear();
315
+ sfzData = null;
316
+ regionMap = null;
317
+ if (ctx) {
318
+ try {
319
+ await ctx.close();
320
+ }
321
+ catch { /* ok */ }
322
+ ctx = null;
323
+ compressor = null;
324
+ master = null;
325
+ }
326
+ currentStatus = "disconnected";
327
+ },
328
+ status() {
329
+ return currentStatus;
330
+ },
331
+ listPorts() {
332
+ return ["Accurate-Salamander Grand Piano"];
333
+ },
334
+ noteOn(note, velocity, channel) {
335
+ if (!ctx || currentStatus !== "connected" || !regionMap)
336
+ return;
337
+ // Clamp
338
+ velocity = Math.max(1, Math.min(127, velocity));
339
+ note = Math.max(21, Math.min(108, note));
340
+ // Kill existing voice on same note (retrigger)
341
+ const existing = activeVoices.get(note);
342
+ if (existing) {
343
+ killVoice(existing);
344
+ activeVoices.delete(note);
345
+ removeFromOrder(note);
346
+ }
347
+ // Voice stealing
348
+ while (activeVoices.size >= maxPolyphony) {
349
+ stealOldest();
350
+ }
351
+ // Find the right sample
352
+ const region = findRegion(regionMap, note, velocity);
353
+ if (!region)
354
+ return;
355
+ const audioBuffer = audioBuffers.get(region.sample);
356
+ if (!audioBuffer)
357
+ return;
358
+ const now = ctx.currentTime;
359
+ // Create buffer source
360
+ const source = ctx.createBufferSource();
361
+ source.buffer = audioBuffer;
362
+ // Pitch shift: difference between target note and sample's recorded pitch
363
+ const semitoneDiff = note - region.pitchKeycenter;
364
+ const tuneCents = region.tune; // additional fine tuning from SFZ
365
+ const totalCents = semitoneDiff * 100 + tuneCents;
366
+ source.playbackRate.value = centsToRate(totalCents);
367
+ // Volume: SFZ volume offset + velocity scaling
368
+ const velocity01 = velocity / 127;
369
+ const velTrack = (sfzData?.ampVeltrack ?? 97) / 100;
370
+ // SFZ velocity tracking: gain = (1 - velTrack) + velTrack * velocity01
371
+ const velGain = (1 - velTrack) + velTrack * velocity01;
372
+ const volumeGain = dbToGain(region.volume);
373
+ const gain = ctx.createGain();
374
+ gain.gain.value = velGain * volumeGain * 0.5; // 0.5 = headroom factor
375
+ // Stereo position
376
+ const panner = ctx.createStereoPanner();
377
+ panner.pan.value = noteToPan(note);
378
+ // Connect: source → gain → panner → compressor → master → speakers
379
+ source.connect(gain);
380
+ gain.connect(panner);
381
+ panner.connect(compressor);
382
+ source.start(now);
383
+ const voice = {
384
+ note,
385
+ source,
386
+ gain,
387
+ panner,
388
+ released: false,
389
+ cleanupTimer: null,
390
+ };
391
+ activeVoices.set(note, voice);
392
+ voiceOrder.push(note);
393
+ },
394
+ noteOff(note, channel) {
395
+ if (!ctx || currentStatus !== "connected")
396
+ return;
397
+ const voice = activeVoices.get(note);
398
+ if (voice) {
399
+ releaseVoice(voice);
400
+ activeVoices.delete(note);
401
+ removeFromOrder(note);
402
+ }
403
+ },
404
+ allNotesOff(channel) {
405
+ if (!ctx)
406
+ return;
407
+ for (const [, voice] of activeVoices) {
408
+ killVoice(voice);
409
+ }
410
+ activeVoices.clear();
411
+ voiceOrder.length = 0;
412
+ },
413
+ async playNote(midiNote) {
414
+ if (midiNote.note < 0) {
415
+ await sleep(midiNote.durationMs);
416
+ return;
417
+ }
418
+ this.noteOn(midiNote.note, midiNote.velocity, midiNote.channel);
419
+ await sleep(midiNote.durationMs);
420
+ this.noteOff(midiNote.note, midiNote.channel);
421
+ },
422
+ };
423
+ }
424
+ // ─── Helpers ────────────────────────────────────────────────────────────────
425
+ function sleep(ms) {
426
+ return new Promise((resolve) => setTimeout(resolve, ms));
427
+ }
428
+ //# sourceMappingURL=sample-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample-engine.js","sourceRoot":"","sources":["../src/sample-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ /** Play a song from the built-in library by ID. */
3
+ export declare const LibraryPlaySchema: z.ZodObject<{
4
+ songId: z.ZodString;
5
+ }, z.core.$strip>;
6
+ /** Play a local MIDI file. */
7
+ export declare const FilePlaySchema: z.ZodObject<{
8
+ midiPath: z.ZodString;
9
+ }, z.core.$strip>;
10
+ /** Play a remote MIDI file by URL. */
11
+ export declare const UrlPlaySchema: z.ZodObject<{
12
+ midiUrl: z.ZodString;
13
+ }, z.core.$strip>;
14
+ /**
15
+ * Unified play source — one of: library song, local file, or remote URL.
16
+ */
17
+ export declare const PlaySourceSchema: z.ZodUnion<readonly [z.ZodObject<{
18
+ songId: z.ZodString;
19
+ }, z.core.$strip>, z.ZodObject<{
20
+ midiPath: z.ZodString;
21
+ }, z.core.$strip>, z.ZodObject<{
22
+ midiUrl: z.ZodString;
23
+ }, z.core.$strip>]>;
24
+ /** Infer the TypeScript type. */
25
+ export type PlaySource = z.infer<typeof PlaySourceSchema>;
26
+ /** Shared playback options (apply to all sources). */
27
+ export declare const PlaybackOptionsSchema: z.ZodObject<{
28
+ speed: z.ZodOptional<z.ZodNumber>;
29
+ tempo: z.ZodOptional<z.ZodNumber>;
30
+ mode: z.ZodOptional<z.ZodEnum<{
31
+ full: "full";
32
+ measure: "measure";
33
+ hands: "hands";
34
+ loop: "loop";
35
+ }>>;
36
+ startMeasure: z.ZodOptional<z.ZodNumber>;
37
+ endMeasure: z.ZodOptional<z.ZodNumber>;
38
+ }, z.core.$strip>;
39
+ export type PlaybackOptions = z.infer<typeof PlaybackOptionsSchema>;
40
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,mDAAmD;AACnD,eAAO,MAAM,iBAAiB;;iBAE5B,CAAC;AAEH,8BAA8B;AAC9B,eAAO,MAAM,cAAc;;iBAEzB,CAAC;AAEH,sCAAsC;AACtC,eAAO,MAAM,aAAa;;iBAExB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;mBAI3B,CAAC;AAEH,iCAAiC;AACjC,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,sDAAsD;AACtD,eAAO,MAAM,qBAAqB;;;;;;;;;;;iBAWhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
@@ -0,0 +1,42 @@
1
+ // ─── Playback Schemas ───────────────────────────────────────────────────────
2
+ //
3
+ // Zod schemas for play_song input. Supports three playback sources:
4
+ // 1. songId — play from the built-in song library
5
+ // 2. midiPath — play a local .mid file
6
+ // 3. midiUrl — play a remote .mid file (downloaded on demand)
7
+ // ─────────────────────────────────────────────────────────────────────────────
8
+ import { z } from "zod";
9
+ /** Play a song from the built-in library by ID. */
10
+ export const LibraryPlaySchema = z.object({
11
+ songId: z.string().describe("Song ID from the built-in library (e.g. 'autumn-leaves')"),
12
+ });
13
+ /** Play a local MIDI file. */
14
+ export const FilePlaySchema = z.object({
15
+ midiPath: z.string().describe("Absolute path to a local .mid file"),
16
+ });
17
+ /** Play a remote MIDI file by URL. */
18
+ export const UrlPlaySchema = z.object({
19
+ midiUrl: z.string().url().describe("URL to a .mid file (downloaded on demand)"),
20
+ });
21
+ /**
22
+ * Unified play source — one of: library song, local file, or remote URL.
23
+ */
24
+ export const PlaySourceSchema = z.union([
25
+ LibraryPlaySchema,
26
+ FilePlaySchema,
27
+ UrlPlaySchema,
28
+ ]);
29
+ /** Shared playback options (apply to all sources). */
30
+ export const PlaybackOptionsSchema = z.object({
31
+ speed: z.number().min(0.1).max(4).optional()
32
+ .describe("Speed multiplier (0.5 = half, 1.0 = normal, 2.0 = double)"),
33
+ tempo: z.number().int().min(10).max(400).optional()
34
+ .describe("Override tempo in BPM (10-400)"),
35
+ mode: z.enum(["full", "measure", "hands", "loop"]).optional()
36
+ .describe("Playback mode"),
37
+ startMeasure: z.number().int().min(1).optional()
38
+ .describe("Start measure for loop mode (1-based)"),
39
+ endMeasure: z.number().int().min(1).optional()
40
+ .describe("End measure for loop mode (1-based)"),
41
+ });
42
+ //# sourceMappingURL=schemas.js.map