@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
package/dist/smoke.js ADDED
@@ -0,0 +1,512 @@
1
+ // ─── pianoai: Smoke Test ─────────────────────────────────────────────────────
2
+ //
3
+ // Quick integration smoke test — no MIDI hardware needed.
4
+ // Verifies: ai-music-sheets loads, note parser works, sessions run with mock,
5
+ // teaching hooks fire, key moments detected, voice/aside hooks produce output,
6
+ // speed control works, progress fires, safe parsing collects warnings,
7
+ // sing-along converts notes and produces blocking directives,
8
+ // MIDI parsing, position tracking, PlaybackController, sing-on-MIDI,
9
+ // voice filters, and live MIDI feedback.
10
+ //
11
+ // Usage: pnpm smoke (or: node --import tsx src/smoke.ts)
12
+ // ─────────────────────────────────────────────────────────────────────────────
13
+ import { getAllSongs, getSong, getStats, searchSongs, initializeRegistry, } from "./songs/index.js";
14
+ import { createSession } from "./session.js";
15
+ import { createMockVmpkConnector } from "./vmpk.js";
16
+ import { parseNoteToMidi, midiToNoteName, safeParseNoteToken } from "./note-parser.js";
17
+ import { createRecordingTeachingHook, createVoiceTeachingHook, createAsideTeachingHook, createSingAlongHook, createLiveFeedbackHook, composeTeachingHooks, detectKeyMoments, } from "./teaching.js";
18
+ import { noteToSingable, measureToSingableText } from "./note-parser.js";
19
+ import { parseMidiBuffer } from "./midi/parser.js";
20
+ import { PositionTracker } from "./playback/position.js";
21
+ import { PlaybackController } from "./playback/controls.js";
22
+ import { createSingOnMidiHook, midiNoteToSingable, filterClusterForVoice } from "./teaching/sing-on-midi.js";
23
+ import { createLiveMidiFeedbackHook } from "./teaching/live-midi-feedback.js";
24
+ import { writeMidi } from "midi-file";
25
+ let passed = 0;
26
+ let failed = 0;
27
+ const pending = [];
28
+ function test(name, fn) {
29
+ try {
30
+ const result = fn();
31
+ if (result instanceof Promise) {
32
+ pending.push(result
33
+ .then(() => {
34
+ passed++;
35
+ console.log(` ✓ ${name}`);
36
+ })
37
+ .catch((err) => {
38
+ failed++;
39
+ console.log(` ✗ ${name}: ${err}`);
40
+ }));
41
+ }
42
+ else {
43
+ passed++;
44
+ console.log(` ✓ ${name}`);
45
+ }
46
+ }
47
+ catch (err) {
48
+ failed++;
49
+ console.log(` ✗ ${name}: ${err}`);
50
+ }
51
+ }
52
+ function assert(condition, msg) {
53
+ if (!condition)
54
+ throw new Error(`Assertion failed: ${msg}`);
55
+ }
56
+ console.log("\n pianoai smoke test\n");
57
+ // ─── Initialize song registry from builtin JSON files ───────────────────────
58
+ import { dirname, join } from "node:path";
59
+ import { fileURLToPath } from "node:url";
60
+ const __dirname = dirname(fileURLToPath(import.meta.url));
61
+ const builtinDir = join(__dirname, "..", "songs", "builtin");
62
+ initializeRegistry(builtinDir);
63
+ // ─── Test 1: song library loads ─────────────────────────────────────────────
64
+ console.log("song library integration:");
65
+ test("registry loads 100 songs", () => {
66
+ assert(getAllSongs().length >= 100, `expected 100+ songs, got ${getAllSongs().length}`);
67
+ });
68
+ test("all 10 genres covered", () => {
69
+ const stats = getStats();
70
+ const covered = Object.values(stats.byGenre).filter((n) => n > 0).length;
71
+ assert(covered === 10, `expected 10 genres, got ${covered}`);
72
+ });
73
+ test("getSong finds moonlight sonata", () => {
74
+ const song = getSong("moonlight-sonata-mvt1");
75
+ assert(song !== undefined, "song not found");
76
+ assert(song.genre === "classical", "wrong genre");
77
+ });
78
+ test("searchSongs by genre works", () => {
79
+ const results = searchSongs({ genre: "jazz" });
80
+ assert(results.length >= 10, `expected 10+ jazz songs, got ${results.length}`);
81
+ assert(results.some(s => s.id === "autumn-leaves"), "autumn-leaves should be in jazz results");
82
+ });
83
+ // ─── Test 2: Note parser ────────────────────────────────────────────────────
84
+ console.log("\nNote parser:");
85
+ test("C4 = MIDI 60", () => {
86
+ assert(parseNoteToMidi("C4") === 60, "C4 should be 60");
87
+ });
88
+ test("A4 = MIDI 69", () => {
89
+ assert(parseNoteToMidi("A4") === 69, "A4 should be 69");
90
+ });
91
+ test("MIDI 60 = C4", () => {
92
+ assert(midiToNoteName(60) === "C4", "60 should be C4");
93
+ });
94
+ test("round-trip: C#4 -> 61 -> C#4", () => {
95
+ const midi = parseNoteToMidi("C#4");
96
+ assert(midi === 61, "C#4 should be 61");
97
+ assert(midiToNoteName(midi) === "C#4", "61 should be C#4");
98
+ });
99
+ test("safe parse returns null + warning for bad token", () => {
100
+ const warnings = [];
101
+ const result = safeParseNoteToken("GARBAGE:q", 120, "test", warnings);
102
+ assert(result === null, "should return null for bad token");
103
+ assert(warnings.length === 1, "should collect 1 warning");
104
+ });
105
+ // ─── Test 3: Session engine ─────────────────────────────────────────────────
106
+ console.log("\nSession engine:");
107
+ test("creates session in loaded state", () => {
108
+ const mock = createMockVmpkConnector();
109
+ const sc = createSession(getSong("let-it-be"), mock);
110
+ assert(sc.state === "loaded", "should be loaded");
111
+ });
112
+ test("plays full song through mock", async () => {
113
+ const mock = createMockVmpkConnector();
114
+ const song = getSong("basic-12-bar-blues");
115
+ const sc = createSession(song, mock);
116
+ await mock.connect();
117
+ await sc.play();
118
+ assert(sc.state === "finished", `expected finished, got ${sc.state}`);
119
+ assert(sc.session.measuresPlayed === 12, "12 measures");
120
+ });
121
+ test("measure mode plays one and pauses", async () => {
122
+ const mock = createMockVmpkConnector();
123
+ const song = getSong("autumn-leaves");
124
+ const sc = createSession(song, mock, { mode: "measure" });
125
+ await mock.connect();
126
+ await sc.play();
127
+ assert(sc.state === "paused", `expected paused, got ${sc.state}`);
128
+ assert(sc.session.measuresPlayed === 1, "1 measure");
129
+ });
130
+ // ─── Test 4: Speed + progress ───────────────────────────────────────────────
131
+ console.log("\nSpeed + progress:");
132
+ test("speed multiplier affects effective tempo", () => {
133
+ const mock = createMockVmpkConnector();
134
+ const song = getSong("basic-12-bar-blues");
135
+ const sc = createSession(song, mock, { speed: 0.5 });
136
+ assert(sc.effectiveTempo() === song.tempo * 0.5, "should be half tempo");
137
+ });
138
+ test("progress fires during playback", async () => {
139
+ const mock = createMockVmpkConnector();
140
+ const song = getSong("basic-12-bar-blues");
141
+ const events = [];
142
+ const sc = createSession(song, mock, {
143
+ onProgress: (p) => events.push({ ...p }),
144
+ progressInterval: 0,
145
+ });
146
+ await mock.connect();
147
+ await sc.play();
148
+ assert(events.length === 12, `expected 12 progress events, got ${events.length}`);
149
+ assert(events[11].percent === "100%", "last event should be 100%");
150
+ });
151
+ // ─── Test 5: Teaching hooks ─────────────────────────────────────────────────
152
+ console.log("\nTeaching hooks:");
153
+ test("detectKeyMoments finds bar 1 in moonlight", () => {
154
+ const song = getSong("moonlight-sonata-mvt1");
155
+ const moments = detectKeyMoments(song, 1);
156
+ assert(moments.length > 0, "should find key moment at bar 1");
157
+ });
158
+ test("recording hook captures events during playback", async () => {
159
+ const mock = createMockVmpkConnector();
160
+ const hook = createRecordingTeachingHook();
161
+ const song = getSong("let-it-be");
162
+ const sc = createSession(song, mock, { teachingHook: hook });
163
+ await mock.connect();
164
+ await sc.play();
165
+ const starts = hook.events.filter((e) => e.type === "measure-start");
166
+ assert(starts.length === 8, `expected 8 measure-start events, got ${starts.length}`);
167
+ });
168
+ test("song-complete fires after full playback", async () => {
169
+ const mock = createMockVmpkConnector();
170
+ const hook = createRecordingTeachingHook();
171
+ const song = getSong("basic-12-bar-blues");
172
+ const sc = createSession(song, mock, { teachingHook: hook });
173
+ await mock.connect();
174
+ await sc.play();
175
+ const complete = hook.events.filter((e) => e.type === "song-complete");
176
+ assert(complete.length === 1, "should fire song-complete once");
177
+ });
178
+ // ─── Test 6: Voice + aside hooks ────────────────────────────────────────────
179
+ console.log("\nVoice + aside hooks:");
180
+ test("voice hook produces directives during playback", async () => {
181
+ const mock = createMockVmpkConnector();
182
+ const directives = [];
183
+ const voiceHook = createVoiceTeachingHook(async (d) => { directives.push(d); });
184
+ const song = getSong("moonlight-sonata-mvt1");
185
+ const sc = createSession(song, mock, { teachingHook: voiceHook });
186
+ await mock.connect();
187
+ await sc.play();
188
+ assert(directives.length > 0, "should produce voice directives");
189
+ const completion = directives.find((d) => d.text.includes("Great work"));
190
+ assert(completion !== undefined, "should have completion directive");
191
+ });
192
+ test("aside hook produces directives during playback", async () => {
193
+ const mock = createMockVmpkConnector();
194
+ const directives = [];
195
+ const asideHook = createAsideTeachingHook(async (d) => { directives.push(d); });
196
+ const song = getSong("moonlight-sonata-mvt1");
197
+ const sc = createSession(song, mock, { teachingHook: asideHook });
198
+ await mock.connect();
199
+ await sc.play();
200
+ assert(directives.length > 0, "should produce aside directives");
201
+ assert(directives[0].tags.includes("piano-teacher"), "should have piano-teacher tag");
202
+ });
203
+ test("composed hooks dispatch to both voice and aside", async () => {
204
+ const mock = createMockVmpkConnector();
205
+ const voiceD = [];
206
+ const asideD = [];
207
+ const composed = composeTeachingHooks(createVoiceTeachingHook(async (d) => { voiceD.push(d); }), createAsideTeachingHook(async (d) => { asideD.push(d); }));
208
+ const song = getSong("let-it-be");
209
+ const sc = createSession(song, mock, { teachingHook: composed });
210
+ await mock.connect();
211
+ await sc.play();
212
+ assert(voiceD.length > 0, "voice should receive events");
213
+ assert(asideD.length > 0, "aside should receive events");
214
+ });
215
+ // ─── Test 7: Sing-along ─────────────────────────────────────────────────────
216
+ console.log("\nSing-along:");
217
+ test("noteToSingable converts C4 to note name", () => {
218
+ assert(noteToSingable("C4", "note-names") === "C", "C4 → C");
219
+ });
220
+ test("noteToSingable converts C4 to solfege", () => {
221
+ assert(noteToSingable("C4", "solfege") === "Do", "C4 → Do");
222
+ });
223
+ test("measureToSingableText produces singable output", () => {
224
+ const result = measureToSingableText({ rightHand: "C4:q E4:q G4:q", leftHand: "C3:h" }, { mode: "note-names", hand: "right" });
225
+ assert(result === "C... E... G", `expected "C... E... G", got "${result}"`);
226
+ });
227
+ test("sing-along hook produces blocking directives", async () => {
228
+ const directives = [];
229
+ const song = getSong("let-it-be");
230
+ const hook = createSingAlongHook(async (d) => { directives.push(d); }, song);
231
+ const mock = createMockVmpkConnector();
232
+ const sc = createSession(song, mock, { teachingHook: hook });
233
+ await mock.connect();
234
+ await sc.play();
235
+ assert(directives.length > 0, "should produce directives");
236
+ assert(directives[0].blocking === true, "first directive should be blocking");
237
+ });
238
+ test("composed sing-along + voice hooks both fire", async () => {
239
+ const singD = [];
240
+ const voiceD = [];
241
+ const song = getSong("let-it-be");
242
+ const composed = composeTeachingHooks(createSingAlongHook(async (d) => { singD.push(d); }, song), createVoiceTeachingHook(async (d) => { voiceD.push(d); }));
243
+ const mock = createMockVmpkConnector();
244
+ const sc = createSession(song, mock, { teachingHook: composed });
245
+ await mock.connect();
246
+ await sc.play();
247
+ assert(singD.length > 0, "sing-along should receive events");
248
+ assert(voiceD.length > 0, "voice should receive events");
249
+ });
250
+ // ─── Test 8: SyncMode ────────────────────────────────────────────────────────
251
+ console.log("\nSyncMode:");
252
+ test("concurrent sync completes without error", async () => {
253
+ const mock = createMockVmpkConnector();
254
+ const song = getSong("let-it-be");
255
+ const hook = createRecordingTeachingHook();
256
+ const sc = createSession(song, mock, { syncMode: "concurrent", teachingHook: hook });
257
+ await mock.connect();
258
+ await sc.play();
259
+ assert(sc.session.measuresPlayed === 8, "should play 8 measures");
260
+ assert(hook.events.filter(e => e.type === "measure-start").length === 8, "8 measure-start events");
261
+ });
262
+ test("before sync completes without error", async () => {
263
+ const mock = createMockVmpkConnector();
264
+ const song = getSong("let-it-be");
265
+ const hook = createRecordingTeachingHook();
266
+ const sc = createSession(song, mock, { syncMode: "before", teachingHook: hook });
267
+ await mock.connect();
268
+ await sc.play();
269
+ assert(sc.session.measuresPlayed === 8, "should play 8 measures");
270
+ });
271
+ // ─── Test 9: Live Feedback Hook ──────────────────────────────────────────────
272
+ console.log("\nLive feedback:");
273
+ test("live feedback hook fires during full playback", async () => {
274
+ const song = getSong("moonlight-sonata-mvt1");
275
+ const voiceD = [];
276
+ const asideD = [];
277
+ const hook = createLiveFeedbackHook(async (d) => { voiceD.push(d); }, async (d) => { asideD.push(d); }, song, { voiceInterval: 4 });
278
+ const mock = createMockVmpkConnector();
279
+ const sc = createSession(song, mock, { teachingHook: hook });
280
+ await mock.connect();
281
+ await sc.play();
282
+ assert(voiceD.length > 0, "should produce voice directives");
283
+ assert(asideD.length > 0, "should produce aside directives");
284
+ });
285
+ test("composed sing-along + live feedback fires", async () => {
286
+ const song = getSong("let-it-be");
287
+ const singD = [];
288
+ const feedbackVoiceD = [];
289
+ const feedbackAsideD = [];
290
+ const composed = composeTeachingHooks(createSingAlongHook(async (d) => { singD.push(d); }, song), createLiveFeedbackHook(async (d) => { feedbackVoiceD.push(d); }, async (d) => { feedbackAsideD.push(d); }, song, { voiceInterval: 4 }));
291
+ const mock = createMockVmpkConnector();
292
+ const sc = createSession(song, mock, { teachingHook: composed, syncMode: "concurrent" });
293
+ await mock.connect();
294
+ await sc.play();
295
+ assert(singD.length > 0, "sing-along should fire");
296
+ assert(feedbackVoiceD.length > 0 || feedbackAsideD.length > 0, "feedback should fire");
297
+ });
298
+ // ─── MIDI Helpers ──────────────────────────────────────────────────────────
299
+ function buildSmokeMidi(notes, bpm = 120, ticksPerBeat = 480) {
300
+ const usPerBeat = Math.round(60_000_000 / bpm);
301
+ const events = [];
302
+ events.push({ deltaTime: 0, type: "setTempo", meta: true, microsecondsPerBeat: usPerBeat });
303
+ const raw = [];
304
+ for (const n of notes) {
305
+ raw.push({ tick: n.startTick, event: { deltaTime: 0, type: "noteOn", channel: 0, noteNumber: n.note, velocity: n.velocity } });
306
+ raw.push({ tick: n.endTick, event: { deltaTime: 0, type: "noteOff", channel: 0, noteNumber: n.note, velocity: 0 } });
307
+ }
308
+ raw.sort((a, b) => a.tick - b.tick);
309
+ let prevTick = 0;
310
+ for (const r of raw) {
311
+ r.event.deltaTime = r.tick - prevTick;
312
+ prevTick = r.tick;
313
+ events.push(r.event);
314
+ }
315
+ events.push({ deltaTime: 0, type: "endOfTrack", meta: true });
316
+ return new Uint8Array(writeMidi({
317
+ header: { format: 0, numTracks: 1, ticksPerBeat },
318
+ tracks: [events],
319
+ }));
320
+ }
321
+ function createSmokeMockConnector() {
322
+ return {
323
+ async connect() { },
324
+ async disconnect() { },
325
+ status() { return "connected"; },
326
+ listPorts() { return ["Mock"]; },
327
+ noteOn(_n, _v, _c) { },
328
+ noteOff(_n, _c) { },
329
+ allNotesOff(_c) { },
330
+ async playNote(_m) { },
331
+ };
332
+ }
333
+ // ─── Test 10: MIDI file parsing ────────────────────────────────────────────
334
+ console.log("\nMIDI file parsing:");
335
+ test("parseMidiBuffer extracts note events", () => {
336
+ const buf = buildSmokeMidi([
337
+ { note: 60, velocity: 100, startTick: 0, endTick: 480 },
338
+ { note: 64, velocity: 90, startTick: 480, endTick: 960 },
339
+ ]);
340
+ const parsed = parseMidiBuffer(buf);
341
+ assert(parsed.events.length === 2, `expected 2 events, got ${parsed.events.length}`);
342
+ assert(parsed.events[0].note === 60, "first note should be 60");
343
+ assert(parsed.events[1].note === 64, "second note should be 64");
344
+ assert(parsed.bpm === 120, `expected 120 BPM, got ${parsed.bpm}`);
345
+ });
346
+ test("parseMidiBuffer computes duration", () => {
347
+ const buf = buildSmokeMidi([
348
+ { note: 60, velocity: 80, startTick: 0, endTick: 1920 },
349
+ ], 120, 480);
350
+ const parsed = parseMidiBuffer(buf);
351
+ // 1920 ticks at 480 ticks/beat at 120 BPM = 4 beats = 2 seconds
352
+ assert(parsed.durationSeconds > 1.5 && parsed.durationSeconds < 2.5, `expected ~2s duration, got ${parsed.durationSeconds}`);
353
+ });
354
+ // ─── Test 11: Position Tracker ─────────────────────────────────────────────
355
+ console.log("\nPosition tracker:");
356
+ test("PositionTracker computes measures from beats", () => {
357
+ const notes = [];
358
+ for (let i = 0; i < 8; i++) {
359
+ notes.push({ note: 60 + i, velocity: 80, startTick: i * 480, endTick: (i + 1) * 480 });
360
+ }
361
+ const buf = buildSmokeMidi(notes, 120, 480);
362
+ const parsed = parseMidiBuffer(buf);
363
+ const tracker = new PositionTracker(parsed);
364
+ assert(tracker.totalMeasures >= 2, `expected >= 2 measures, got ${tracker.totalMeasures}`);
365
+ });
366
+ test("snapshotAt returns measure 1 at time 0", () => {
367
+ const buf = buildSmokeMidi([{ note: 60, velocity: 80, startTick: 0, endTick: 480 }], 120, 480);
368
+ const parsed = parseMidiBuffer(buf);
369
+ const tracker = new PositionTracker(parsed);
370
+ const snap = tracker.snapshotAt(0);
371
+ assert(snap.measure === 1, `expected measure 1, got ${snap.measure}`);
372
+ assert(snap.bpm === 120, `expected 120 BPM, got ${snap.bpm}`);
373
+ });
374
+ test("timeForMeasure returns seek target", () => {
375
+ const buf = buildSmokeMidi([{ note: 60, velocity: 80, startTick: 0, endTick: 480 }], 120, 480);
376
+ const parsed = parseMidiBuffer(buf);
377
+ const tracker = new PositionTracker(parsed);
378
+ const t1 = tracker.timeForMeasure(1);
379
+ const t2 = tracker.timeForMeasure(2);
380
+ assert(Math.abs(t1) < 0.01, `measure 1 should start at ~0, got ${t1}`);
381
+ assert(Math.abs(t2 - 2.0) < 0.1, `measure 2 should start at ~2s, got ${t2}`);
382
+ });
383
+ test("eventsInMeasure partitions notes correctly", () => {
384
+ const notes = [];
385
+ for (let i = 0; i < 8; i++) {
386
+ notes.push({ note: 60 + i, velocity: 80, startTick: i * 480, endTick: (i + 1) * 480 });
387
+ }
388
+ const buf = buildSmokeMidi(notes, 120, 480);
389
+ const parsed = parseMidiBuffer(buf);
390
+ const tracker = new PositionTracker(parsed);
391
+ const m1 = tracker.eventsInMeasure(1);
392
+ assert(m1.length === 4, `expected 4 events in measure 1, got ${m1.length}`);
393
+ });
394
+ // ─── Test 12: PlaybackController ───────────────────────────────────────────
395
+ console.log("\nPlaybackController:");
396
+ test("PlaybackController emits noteOn events", async () => {
397
+ const buf = buildSmokeMidi([
398
+ { note: 60, velocity: 100, startTick: 0, endTick: 480 },
399
+ { note: 64, velocity: 90, startTick: 480, endTick: 960 },
400
+ ]);
401
+ const parsed = parseMidiBuffer(buf);
402
+ const connector = createSmokeMockConnector();
403
+ const controller = new PlaybackController(connector, parsed);
404
+ const noteOns = [];
405
+ controller.on("noteOn", (e) => { if (e.type === "noteOn")
406
+ noteOns.push(e.note); });
407
+ await controller.play({ speed: 100 });
408
+ assert(noteOns.length === 2, `expected 2 noteOn events, got ${noteOns.length}`);
409
+ assert(controller.state === "finished", `expected finished, got ${controller.state}`);
410
+ });
411
+ test("PlaybackController invokes teaching hook", async () => {
412
+ const buf = buildSmokeMidi([
413
+ { note: 60, velocity: 100, startTick: 0, endTick: 480 },
414
+ ]);
415
+ const parsed = parseMidiBuffer(buf);
416
+ const connector = createSmokeMockConnector();
417
+ const controller = new PlaybackController(connector, parsed);
418
+ const hook = createRecordingTeachingHook();
419
+ await controller.play({ speed: 100, teachingHook: hook });
420
+ const starts = hook.events.filter((e) => e.type === "measure-start");
421
+ assert(starts.length >= 1, `expected >= 1 measure-start, got ${starts.length}`);
422
+ const completions = hook.events.filter((e) => e.type === "song-complete");
423
+ assert(completions.length === 1, "should fire song-complete once");
424
+ });
425
+ // ─── Test 13: Sing-on-MIDI ─────────────────────────────────────────────────
426
+ console.log("\nSing-on-MIDI:");
427
+ test("midiNoteToSingable converts note-names", () => {
428
+ assert(midiNoteToSingable(60, "note-names") === "C4", "60 → C4");
429
+ assert(midiNoteToSingable(69, "note-names") === "A4", "69 → A4");
430
+ });
431
+ test("midiNoteToSingable converts solfege", () => {
432
+ assert(midiNoteToSingable(60, "solfege") === "Do", "60 → Do");
433
+ assert(midiNoteToSingable(64, "solfege") === "Mi", "64 → Mi");
434
+ });
435
+ test("createSingOnMidiHook produces directives", async () => {
436
+ const buf = buildSmokeMidi([
437
+ { note: 60, velocity: 100, startTick: 0, endTick: 480 },
438
+ { note: 64, velocity: 90, startTick: 480, endTick: 960 },
439
+ ]);
440
+ const parsed = parseMidiBuffer(buf);
441
+ const directives = [];
442
+ const hook = createSingOnMidiHook(async (d) => { directives.push(d); }, parsed, { mode: "note-names" });
443
+ await hook.onMeasureStart(1, undefined, undefined);
444
+ await hook.onMeasureStart(2, undefined, undefined);
445
+ assert(hook.directives.length === 2, `expected 2 directives, got ${hook.directives.length}`);
446
+ assert(hook.directives[0].text.includes("C4"), `first should contain C4, got ${hook.directives[0].text}`);
447
+ });
448
+ // ─── Test 14: Voice Filters ───────────────────────────────────────────────
449
+ console.log("\nVoice filters:");
450
+ test("melody-only picks highest note", () => {
451
+ const chord = [
452
+ { note: 48, velocity: 80, time: 0, duration: 0.5, channel: 0 },
453
+ { note: 60, velocity: 80, time: 0, duration: 0.5, channel: 0 },
454
+ { note: 72, velocity: 80, time: 0, duration: 0.5, channel: 0 },
455
+ ];
456
+ const filtered = filterClusterForVoice(chord, "melody-only");
457
+ assert(filtered.length === 1, `expected 1, got ${filtered.length}`);
458
+ assert(filtered[0].note === 72, `expected 72, got ${filtered[0].note}`);
459
+ });
460
+ test("harmony picks lowest note", () => {
461
+ const chord = [
462
+ { note: 48, velocity: 80, time: 0, duration: 0.5, channel: 0 },
463
+ { note: 72, velocity: 80, time: 0, duration: 0.5, channel: 0 },
464
+ ];
465
+ const filtered = filterClusterForVoice(chord, "harmony");
466
+ assert(filtered.length === 1, `expected 1, got ${filtered.length}`);
467
+ assert(filtered[0].note === 48, `expected 48, got ${filtered[0].note}`);
468
+ });
469
+ // ─── Test 15: Live MIDI Feedback ──────────────────────────────────────────
470
+ console.log("\nLive MIDI feedback:");
471
+ test("createLiveMidiFeedbackHook provides tracker", () => {
472
+ const buf = buildSmokeMidi([{ note: 60, velocity: 80, startTick: 0, endTick: 480 }], 120, 480);
473
+ const parsed = parseMidiBuffer(buf);
474
+ const hook = createLiveMidiFeedbackHook(async () => { }, async () => { }, parsed);
475
+ assert(hook.tracker instanceof PositionTracker, "should expose PositionTracker");
476
+ assert(hook.tracker.totalMeasures >= 1, "should have measures");
477
+ });
478
+ test("live feedback emits completion", async () => {
479
+ const buf = buildSmokeMidi([{ note: 60, velocity: 80, startTick: 0, endTick: 480 }], 120, 480);
480
+ const parsed = parseMidiBuffer(buf);
481
+ const voiceD = [];
482
+ const asideD = [];
483
+ const hook = createLiveMidiFeedbackHook(async (d) => { voiceD.push(d); }, async (d) => { asideD.push(d); }, parsed);
484
+ await hook.onSongComplete(10, "Smoke Song");
485
+ assert(voiceD.some(d => d.text.includes("Smoke Song")), "should mention song name");
486
+ assert(asideD.some(d => d.reason === "session-complete"), "should emit session-complete");
487
+ });
488
+ test("composed sing + live feedback on PlaybackController", async () => {
489
+ const buf = buildSmokeMidi([
490
+ { note: 60, velocity: 40, startTick: 0, endTick: 480 },
491
+ { note: 64, velocity: 110, startTick: 480, endTick: 960 },
492
+ ]);
493
+ const parsed = parseMidiBuffer(buf);
494
+ const connector = createSmokeMockConnector();
495
+ const controller = new PlaybackController(connector, parsed);
496
+ const singD = [];
497
+ const feedbackA = [];
498
+ const singHook = createSingOnMidiHook(async (d) => { singD.push(d); }, parsed, { mode: "solfege" });
499
+ const fbHook = createLiveMidiFeedbackHook(async () => { }, async (d) => { feedbackA.push(d); }, parsed, { voiceInterval: 100 });
500
+ const composed = composeTeachingHooks(singHook, fbHook);
501
+ await controller.play({ speed: 100, teachingHook: composed });
502
+ assert(singD.length > 0, "sing hook should produce directives");
503
+ });
504
+ // ─── Summary ────────────────────────────────────────────────────────────────
505
+ Promise.all(pending).then(() => {
506
+ console.log(`\n${"─".repeat(40)}`);
507
+ console.log(`Smoke: ${passed} passed, ${failed} failed`);
508
+ if (failed > 0)
509
+ process.exit(1);
510
+ console.log("All smoke tests passed\n");
511
+ });
512
+ //# sourceMappingURL=smoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke.js","sourceRoot":"","sources":["../src/smoke.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type SongConfig } from "./schema.js";
2
+ /**
3
+ * Load and validate all song configs from a directory.
4
+ */
5
+ export declare function loadSongConfigs(dir: string): SongConfig[];
6
+ /**
7
+ * Load a single song config by ID from a directory.
8
+ */
9
+ export declare function loadSongConfig(id: string, dir: string): SongConfig;
10
+ /**
11
+ * List available config IDs (slugs) in a directory.
12
+ */
13
+ export declare function listConfigIds(dir: string): string[];
14
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/songs/config/loader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhE;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAwBzD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAQlE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAKnD"}
@@ -0,0 +1,53 @@
1
+ // ─── Song Config Loader ──────────────────────────────────────────────────────
2
+ //
3
+ // Reads .json files from a config directory, validates each with Zod,
4
+ // and returns typed SongConfig objects.
5
+ // ─────────────────────────────────────────────────────────────────────────────
6
+ import { readdirSync, readFileSync, existsSync } from "node:fs";
7
+ import { join, basename } from "node:path";
8
+ import { SongConfigSchema } from "./schema.js";
9
+ /**
10
+ * Load and validate all song configs from a directory.
11
+ */
12
+ export function loadSongConfigs(dir) {
13
+ if (!existsSync(dir)) {
14
+ throw new Error(`Config directory not found: ${dir}`);
15
+ }
16
+ const files = readdirSync(dir).filter(f => f.endsWith(".json"));
17
+ const configs = [];
18
+ for (const file of files) {
19
+ const filePath = join(dir, file);
20
+ const raw = JSON.parse(readFileSync(filePath, "utf8"));
21
+ const result = SongConfigSchema.safeParse(raw);
22
+ if (!result.success) {
23
+ const issues = result.error.issues
24
+ .map(i => ` ${i.path.join(".")}: ${i.message}`)
25
+ .join("\n");
26
+ throw new Error(`Invalid config ${file}:\n${issues}`);
27
+ }
28
+ configs.push(result.data);
29
+ }
30
+ return configs;
31
+ }
32
+ /**
33
+ * Load a single song config by ID from a directory.
34
+ */
35
+ export function loadSongConfig(id, dir) {
36
+ const filePath = join(dir, `${id}.json`);
37
+ if (!existsSync(filePath)) {
38
+ throw new Error(`Config not found: ${filePath}`);
39
+ }
40
+ const raw = JSON.parse(readFileSync(filePath, "utf8"));
41
+ return SongConfigSchema.parse(raw);
42
+ }
43
+ /**
44
+ * List available config IDs (slugs) in a directory.
45
+ */
46
+ export function listConfigIds(dir) {
47
+ if (!existsSync(dir))
48
+ return [];
49
+ return readdirSync(dir)
50
+ .filter(f => f.endsWith(".json"))
51
+ .map(f => basename(f, ".json"));
52
+ }
53
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/songs/config/loader.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,sEAAsE;AACtE,wCAAwC;AACxC,gFAAgF;AAEhF,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAmB,MAAM,aAAa,CAAC;AAEhE;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAE/C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM;iBAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;iBAC/C,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,kBAAkB,IAAI,MAAM,MAAM,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,EAAU,EAAE,GAAW;IACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,OAAO,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SAChC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AACpC,CAAC"}