@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.
- package/LICENSE +21 -0
- package/README.es.md +212 -0
- package/README.fr.md +212 -0
- package/README.hi.md +212 -0
- package/README.it.md +212 -0
- package/README.ja.md +214 -0
- package/README.md +214 -0
- package/README.pt-BR.md +212 -0
- package/dist/audio-engine.d.ts +9 -0
- package/dist/audio-engine.d.ts.map +1 -0
- package/dist/audio-engine.js +422 -0
- package/dist/audio-engine.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +551 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +903 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/midi/parser.d.ts +16 -0
- package/dist/midi/parser.d.ts.map +1 -0
- package/dist/midi/parser.js +192 -0
- package/dist/midi/parser.js.map +1 -0
- package/dist/midi/types.d.ts +44 -0
- package/dist/midi/types.d.ts.map +1 -0
- package/dist/midi/types.js +8 -0
- package/dist/midi/types.js.map +1 -0
- package/dist/note-parser.d.ts +105 -0
- package/dist/note-parser.d.ts.map +1 -0
- package/dist/note-parser.js +278 -0
- package/dist/note-parser.js.map +1 -0
- package/dist/playback/controls.d.ts +124 -0
- package/dist/playback/controls.d.ts.map +1 -0
- package/dist/playback/controls.js +252 -0
- package/dist/playback/controls.js.map +1 -0
- package/dist/playback/midi-engine.d.ts +68 -0
- package/dist/playback/midi-engine.d.ts.map +1 -0
- package/dist/playback/midi-engine.js +227 -0
- package/dist/playback/midi-engine.js.map +1 -0
- package/dist/playback/position.d.ts +95 -0
- package/dist/playback/position.d.ts.map +1 -0
- package/dist/playback/position.js +223 -0
- package/dist/playback/position.js.map +1 -0
- package/dist/playback/timing.d.ts +31 -0
- package/dist/playback/timing.d.ts.map +1 -0
- package/dist/playback/timing.js +57 -0
- package/dist/playback/timing.js.map +1 -0
- package/dist/sample-engine.d.ts +17 -0
- package/dist/sample-engine.d.ts.map +1 -0
- package/dist/sample-engine.js +428 -0
- package/dist/sample-engine.js.map +1 -0
- package/dist/schemas.d.ts +40 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +42 -0
- package/dist/schemas.js.map +1 -0
- package/dist/session.d.ts +106 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +361 -0
- package/dist/session.js.map +1 -0
- package/dist/sfz-parser.d.ts +36 -0
- package/dist/sfz-parser.d.ts.map +1 -0
- package/dist/sfz-parser.js +95 -0
- package/dist/sfz-parser.js.map +1 -0
- package/dist/smoke.d.ts +2 -0
- package/dist/smoke.d.ts.map +1 -0
- package/dist/smoke.js +512 -0
- package/dist/smoke.js.map +1 -0
- package/dist/songs/config/loader.d.ts +14 -0
- package/dist/songs/config/loader.d.ts.map +1 -0
- package/dist/songs/config/loader.js +53 -0
- package/dist/songs/config/loader.js.map +1 -0
- package/dist/songs/config/schema.d.ts +70 -0
- package/dist/songs/config/schema.d.ts.map +1 -0
- package/dist/songs/config/schema.js +53 -0
- package/dist/songs/config/schema.js.map +1 -0
- package/dist/songs/index.d.ts +16 -0
- package/dist/songs/index.d.ts.map +1 -0
- package/dist/songs/index.js +20 -0
- package/dist/songs/index.js.map +1 -0
- package/dist/songs/jam.d.ts +48 -0
- package/dist/songs/jam.d.ts.map +1 -0
- package/dist/songs/jam.js +324 -0
- package/dist/songs/jam.js.map +1 -0
- package/dist/songs/loader.d.ts +27 -0
- package/dist/songs/loader.d.ts.map +1 -0
- package/dist/songs/loader.js +90 -0
- package/dist/songs/loader.js.map +1 -0
- package/dist/songs/midi/hands.d.ts +46 -0
- package/dist/songs/midi/hands.d.ts.map +1 -0
- package/dist/songs/midi/hands.js +134 -0
- package/dist/songs/midi/hands.js.map +1 -0
- package/dist/songs/midi/ingest.d.ts +8 -0
- package/dist/songs/midi/ingest.d.ts.map +1 -0
- package/dist/songs/midi/ingest.js +191 -0
- package/dist/songs/midi/ingest.js.map +1 -0
- package/dist/songs/midi/measures.d.ts +41 -0
- package/dist/songs/midi/measures.d.ts.map +1 -0
- package/dist/songs/midi/measures.js +64 -0
- package/dist/songs/midi/measures.js.map +1 -0
- package/dist/songs/midi/types.d.ts +25 -0
- package/dist/songs/midi/types.d.ts.map +1 -0
- package/dist/songs/midi/types.js +8 -0
- package/dist/songs/midi/types.js.map +1 -0
- package/dist/songs/registry.d.ts +37 -0
- package/dist/songs/registry.d.ts.map +1 -0
- package/dist/songs/registry.js +197 -0
- package/dist/songs/registry.js.map +1 -0
- package/dist/songs/types.d.ts +99 -0
- package/dist/songs/types.d.ts.map +1 -0
- package/dist/songs/types.js +27 -0
- package/dist/songs/types.js.map +1 -0
- package/dist/teaching/live-midi-feedback.d.ts +36 -0
- package/dist/teaching/live-midi-feedback.d.ts.map +1 -0
- package/dist/teaching/live-midi-feedback.js +259 -0
- package/dist/teaching/live-midi-feedback.js.map +1 -0
- package/dist/teaching/midi-feedback.d.ts +33 -0
- package/dist/teaching/midi-feedback.d.ts.map +1 -0
- package/dist/teaching/midi-feedback.js +208 -0
- package/dist/teaching/midi-feedback.js.map +1 -0
- package/dist/teaching/sing-on-midi.d.ts +77 -0
- package/dist/teaching/sing-on-midi.d.ts.map +1 -0
- package/dist/teaching/sing-on-midi.js +186 -0
- package/dist/teaching/sing-on-midi.js.map +1 -0
- package/dist/teaching.d.ts +148 -0
- package/dist/teaching.d.ts.map +1 -0
- package/dist/teaching.js +453 -0
- package/dist/teaching.js.map +1 -0
- package/dist/test-sound.d.ts +3 -0
- package/dist/test-sound.d.ts.map +1 -0
- package/dist/test-sound.js +41 -0
- package/dist/test-sound.js.map +1 -0
- package/dist/types.d.ts +229 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +22 -0
- package/dist/types.js.map +1 -0
- package/dist/vmpk.d.ts +23 -0
- package/dist/vmpk.d.ts.map +1 -0
- package/dist/vmpk.js +236 -0
- package/dist/vmpk.js.map +1 -0
- package/logo.png +0 -0
- package/package.json +70 -0
- package/songs/builtin/a-change-is-gonna-come.json +95 -0
- package/songs/builtin/a-thousand-years.json +93 -0
- package/songs/builtin/aint-no-sunshine.json +98 -0
- package/songs/builtin/all-blues.json +92 -0
- package/songs/builtin/autumn-leaves.json +100 -0
- package/songs/builtin/baba-oriley.json +91 -0
- package/songs/builtin/bach-invention-no1.json +70 -0
- package/songs/builtin/bach-prelude-c-major-bwv846.json +1282 -0
- package/songs/builtin/basic-12-bar-blues.json +119 -0
- package/songs/builtin/beethoven-waldstein-mvt1.json +7766 -0
- package/songs/builtin/bennie-and-the-jets.json +92 -0
- package/songs/builtin/besame-mucho.json +93 -0
- package/songs/builtin/black-orpheus.json +92 -0
- package/songs/builtin/blue-bossa.json +94 -0
- package/songs/builtin/blues-in-g.json +92 -0
- package/songs/builtin/bohemian-rhapsody-intro.json +94 -0
- package/songs/builtin/boogie-woogie-basics.json +93 -0
- package/songs/builtin/bossa-nova-basic.json +95 -0
- package/songs/builtin/chopin-nocturne-op9-no2.json +70 -0
- package/songs/builtin/cinema-paradiso.json +94 -0
- package/songs/builtin/clair-de-lune.json +11511 -0
- package/songs/builtin/clocks.json +91 -0
- package/songs/builtin/crystal-stream.json +70 -0
- package/songs/builtin/desafinado.json +93 -0
- package/songs/builtin/dont-stop-believin.json +91 -0
- package/songs/builtin/dream-on.json +100 -0
- package/songs/builtin/easy-winners.json +70 -0
- package/songs/builtin/el-condor-pasa.json +93 -0
- package/songs/builtin/elite-syncopations.json +70 -0
- package/songs/builtin/evening-calm.json +70 -0
- package/songs/builtin/everyday-blues.json +93 -0
- package/songs/builtin/fly-me-to-the-moon.json +91 -0
- package/songs/builtin/forrest-gump-suite.json +93 -0
- package/songs/builtin/fur-elise.json +20094 -0
- package/songs/builtin/georgia-on-my-mind.json +93 -0
- package/songs/builtin/girl-from-ipanema.json +92 -0
- package/songs/builtin/gladiolus-rag.json +70 -0
- package/songs/builtin/great-balls-of-fire.json +92 -0
- package/songs/builtin/guantanamera.json +92 -0
- package/songs/builtin/hallelujah.json +92 -0
- package/songs/builtin/hedwigs-theme.json +93 -0
- package/songs/builtin/hotel-california.json +92 -0
- package/songs/builtin/imagine.json +92 -0
- package/songs/builtin/just-the-two-of-us.json +92 -0
- package/songs/builtin/la-bamba.json +92 -0
- package/songs/builtin/layla-piano-coda.json +93 -0
- package/songs/builtin/lean-on-me.json +91 -0
- package/songs/builtin/let-it-be.json +101 -0
- package/songs/builtin/lets-stay-together.json +93 -0
- package/songs/builtin/magnetic-rag.json +70 -0
- package/songs/builtin/maple-leaf-rag.json +99 -0
- package/songs/builtin/mia-and-sebastians-theme.json +93 -0
- package/songs/builtin/minor-blues-in-a.json +94 -0
- package/songs/builtin/misty.json +94 -0
- package/songs/builtin/moon-river.json +93 -0
- package/songs/builtin/moonlight-sonata-mvt1.json +101 -0
- package/songs/builtin/morning-light.json +70 -0
- package/songs/builtin/mountain-dawn.json +70 -0
- package/songs/builtin/mozart-k545-mvt1.json +2956 -0
- package/songs/builtin/my-girl.json +92 -0
- package/songs/builtin/night-train.json +92 -0
- package/songs/builtin/november-rain.json +93 -0
- package/songs/builtin/ocean-waves.json +70 -0
- package/songs/builtin/over-the-rainbow.json +93 -0
- package/songs/builtin/oye-como-va.json +93 -0
- package/songs/builtin/peacherine-rag.json +70 -0
- package/songs/builtin/piano-man.json +92 -0
- package/songs/builtin/pineapple-rag.json +70 -0
- package/songs/builtin/pink-panther.json +94 -0
- package/songs/builtin/ragtime-dance.json +70 -0
- package/songs/builtin/river-flows-in-you.json +102 -0
- package/songs/builtin/rocket-man.json +92 -0
- package/songs/builtin/satie-gymnopedie-no1.json +70 -0
- package/songs/builtin/satin-doll.json +93 -0
- package/songs/builtin/schindlers-list.json +96 -0
- package/songs/builtin/schumann-traumerei.json +70 -0
- package/songs/builtin/sitting-on-the-dock.json +91 -0
- package/songs/builtin/slow-blues-in-bb.json +98 -0
- package/songs/builtin/snowfall.json +70 -0
- package/songs/builtin/so-what.json +92 -0
- package/songs/builtin/solace.json +70 -0
- package/songs/builtin/someone-like-you.json +92 -0
- package/songs/builtin/spirited-away.json +94 -0
- package/songs/builtin/st-louis-blues.json +93 -0
- package/songs/builtin/stairway-intro.json +93 -0
- package/songs/builtin/starlight-waltz.json +70 -0
- package/songs/builtin/stay-with-me.json +93 -0
- package/songs/builtin/stormy-monday.json +94 -0
- package/songs/builtin/superstition.json +93 -0
- package/songs/builtin/sweet-home-chicago.json +93 -0
- package/songs/builtin/take-five.json +92 -0
- package/songs/builtin/take-the-a-train.json +93 -0
- package/songs/builtin/the-entertainer.json +98 -0
- package/songs/builtin/the-godfather-waltz.json +93 -0
- package/songs/builtin/thrill-is-gone.json +94 -0
- package/songs/builtin/twilight-garden.json +70 -0
- package/songs/builtin/watermark.json +70 -0
- package/songs/builtin/wave.json +93 -0
- package/songs/builtin/whats-going-on.json +93 -0
- package/songs/builtin/yesterday.json +92 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import type { SongEntry, Measure } from "./songs/types.js";
|
|
2
|
+
/** MIDI connection status. */
|
|
3
|
+
export type MidiStatus = "disconnected" | "connecting" | "connected" | "error";
|
|
4
|
+
/** Parsed note ready for MIDI output. */
|
|
5
|
+
export interface MidiNote {
|
|
6
|
+
/** MIDI note number (0-127). Middle C = 60. */
|
|
7
|
+
note: number;
|
|
8
|
+
/** Velocity (0-127). 0 = note off. */
|
|
9
|
+
velocity: number;
|
|
10
|
+
/** Duration in milliseconds. */
|
|
11
|
+
durationMs: number;
|
|
12
|
+
/** MIDI channel (0-15). Default 0. */
|
|
13
|
+
channel: number;
|
|
14
|
+
}
|
|
15
|
+
/** A parsed beat within a measure — one or more simultaneous notes. */
|
|
16
|
+
export interface Beat {
|
|
17
|
+
/** Notes to play simultaneously (chord or single note). */
|
|
18
|
+
notes: MidiNote[];
|
|
19
|
+
/** Which hand: "right" or "left". */
|
|
20
|
+
hand: "right" | "left";
|
|
21
|
+
}
|
|
22
|
+
/** A fully parsed measure ready for playback. */
|
|
23
|
+
export interface PlayableMeasure {
|
|
24
|
+
/** Original measure data from the song. */
|
|
25
|
+
source: Measure;
|
|
26
|
+
/** Right-hand beats in chronological order. */
|
|
27
|
+
rightBeats: Beat[];
|
|
28
|
+
/** Left-hand beats in chronological order. */
|
|
29
|
+
leftBeats: Beat[];
|
|
30
|
+
}
|
|
31
|
+
/** Session state machine. */
|
|
32
|
+
export type SessionState = "idle" | "loaded" | "playing" | "paused" | "finished";
|
|
33
|
+
/** Playback mode. */
|
|
34
|
+
export type PlaybackMode = "full" | "measure" | "hands" | "loop";
|
|
35
|
+
/** Sync mode for voice + piano coordination. */
|
|
36
|
+
export type SyncMode = "concurrent" | "before";
|
|
37
|
+
/** A practice session. */
|
|
38
|
+
export interface Session {
|
|
39
|
+
/** Unique session ID. */
|
|
40
|
+
id: string;
|
|
41
|
+
/** The song being practiced. */
|
|
42
|
+
song: SongEntry;
|
|
43
|
+
/** Current session state. */
|
|
44
|
+
state: SessionState;
|
|
45
|
+
/** Playback mode. */
|
|
46
|
+
mode: PlaybackMode;
|
|
47
|
+
/** Sync mode for voice + piano coordination. */
|
|
48
|
+
syncMode: SyncMode;
|
|
49
|
+
/** Current measure index (0-based). */
|
|
50
|
+
currentMeasure: number;
|
|
51
|
+
/** Tempo override (BPM). Null = use song's default tempo. */
|
|
52
|
+
tempoOverride: number | null;
|
|
53
|
+
/** Speed multiplier (0.5 = half, 1.0 = normal, 2.0 = double). */
|
|
54
|
+
speed: number;
|
|
55
|
+
/** Measure range for loop mode [start, end] (1-based, inclusive). */
|
|
56
|
+
loopRange: [number, number] | null;
|
|
57
|
+
/** Session start time. */
|
|
58
|
+
startedAt: Date;
|
|
59
|
+
/** Total measures played in this session. */
|
|
60
|
+
measuresPlayed: number;
|
|
61
|
+
/** Voice feedback enabled. */
|
|
62
|
+
voiceEnabled: boolean;
|
|
63
|
+
}
|
|
64
|
+
/** Progress update — emitted during playback. */
|
|
65
|
+
export interface PlaybackProgress {
|
|
66
|
+
/** Current measure (1-based). */
|
|
67
|
+
currentMeasure: number;
|
|
68
|
+
/** Total measures in the song. */
|
|
69
|
+
totalMeasures: number;
|
|
70
|
+
/** Completion ratio (0.0 – 1.0). */
|
|
71
|
+
ratio: number;
|
|
72
|
+
/** Percentage string (e.g. "50%"). */
|
|
73
|
+
percent: string;
|
|
74
|
+
/** Elapsed time since playback started (ms). */
|
|
75
|
+
elapsedMs: number;
|
|
76
|
+
}
|
|
77
|
+
/** Progress callback — called at configurable intervals during playback. */
|
|
78
|
+
export type ProgressCallback = (progress: PlaybackProgress) => void;
|
|
79
|
+
/** Options for creating a new session. */
|
|
80
|
+
export interface SessionOptions {
|
|
81
|
+
/** Playback mode (default: "full"). */
|
|
82
|
+
mode?: PlaybackMode;
|
|
83
|
+
/**
|
|
84
|
+
* Sync mode for voice + piano coordination (default: "concurrent").
|
|
85
|
+
* "concurrent" = voice and piano play simultaneously (duet feel).
|
|
86
|
+
* "before" = voice speaks notes before piano plays (lecture style).
|
|
87
|
+
*/
|
|
88
|
+
syncMode?: SyncMode;
|
|
89
|
+
/** Tempo override in BPM (default: song's tempo). */
|
|
90
|
+
tempo?: number;
|
|
91
|
+
/**
|
|
92
|
+
* Speed multiplier (default: 1.0).
|
|
93
|
+
* 0.5 = half speed (practice slow), 1.0 = normal, 2.0 = double speed.
|
|
94
|
+
* Stacks with tempo override: effective tempo = (override ?? song.tempo) * speed.
|
|
95
|
+
*/
|
|
96
|
+
speed?: number;
|
|
97
|
+
/** Loop range [start, end] for loop mode. */
|
|
98
|
+
loopRange?: [number, number];
|
|
99
|
+
/** Enable voice feedback (default: true). */
|
|
100
|
+
voice?: boolean;
|
|
101
|
+
/** Teaching hook for interjections during playback. */
|
|
102
|
+
teachingHook?: TeachingHook;
|
|
103
|
+
/** Progress callback — called after each measure completes. */
|
|
104
|
+
onProgress?: ProgressCallback;
|
|
105
|
+
/**
|
|
106
|
+
* Progress notification interval (0.0 – 1.0, default: 0.1 = every 10%).
|
|
107
|
+
* Set to 0 to fire after every measure. Set to 1 to only fire at completion.
|
|
108
|
+
*/
|
|
109
|
+
progressInterval?: number;
|
|
110
|
+
}
|
|
111
|
+
/** MIDI connection configuration. */
|
|
112
|
+
export interface VmpkConfig {
|
|
113
|
+
/** MIDI output port name, regex pattern, or "auto" to auto-detect. Default: "auto" */
|
|
114
|
+
portName: string | RegExp;
|
|
115
|
+
/** MIDI channel (0-15). Default: 0. */
|
|
116
|
+
channel: number;
|
|
117
|
+
/** Default velocity (0-127). Default: 80. */
|
|
118
|
+
velocity: number;
|
|
119
|
+
}
|
|
120
|
+
/** VMPK connector interface — for DI/testing. */
|
|
121
|
+
export interface VmpkConnector {
|
|
122
|
+
/** Connect to the MIDI output port. */
|
|
123
|
+
connect(): Promise<void>;
|
|
124
|
+
/** Disconnect from the MIDI output port. */
|
|
125
|
+
disconnect(): Promise<void>;
|
|
126
|
+
/** Get current connection status. */
|
|
127
|
+
status(): MidiStatus;
|
|
128
|
+
/** List available MIDI output ports. */
|
|
129
|
+
listPorts(): string[];
|
|
130
|
+
/** Send a note-on message. */
|
|
131
|
+
noteOn(note: number, velocity: number, channel?: number): void;
|
|
132
|
+
/** Send a note-off message. */
|
|
133
|
+
noteOff(note: number, channel?: number): void;
|
|
134
|
+
/** Send all-notes-off (panic). */
|
|
135
|
+
allNotesOff(channel?: number): void;
|
|
136
|
+
/** Play a single MidiNote (note-on, wait, note-off). */
|
|
137
|
+
playNote(note: MidiNote): Promise<void>;
|
|
138
|
+
}
|
|
139
|
+
/** Warning emitted when a note/measure can't be parsed. */
|
|
140
|
+
export interface ParseWarning {
|
|
141
|
+
/** Where the error occurred. */
|
|
142
|
+
location: string;
|
|
143
|
+
/** The offending token or string. */
|
|
144
|
+
token: string;
|
|
145
|
+
/** The error message. */
|
|
146
|
+
message: string;
|
|
147
|
+
}
|
|
148
|
+
/** Duration suffix → multiplier (relative to quarter note). */
|
|
149
|
+
export declare const DURATION_MAP: Record<string, number>;
|
|
150
|
+
/**
|
|
151
|
+
* Map from note name to semitone offset from C.
|
|
152
|
+
* Used for scientific pitch → MIDI number conversion.
|
|
153
|
+
*/
|
|
154
|
+
export declare const NOTE_OFFSETS: Record<string, number>;
|
|
155
|
+
/** Priority level for teaching interjections. */
|
|
156
|
+
export type TeachingPriority = "low" | "med" | "high";
|
|
157
|
+
/** A teaching interjection — something the AI teacher says during practice. */
|
|
158
|
+
export interface TeachingInterjection {
|
|
159
|
+
/** The text to speak/display. */
|
|
160
|
+
text: string;
|
|
161
|
+
/** Priority: low = ambient, med = useful, high = critical instruction. */
|
|
162
|
+
priority: TeachingPriority;
|
|
163
|
+
/** Why this interjection was triggered. */
|
|
164
|
+
reason: "measure-start" | "key-moment" | "style-tip" | "encouragement" | "correction" | "custom";
|
|
165
|
+
/** Source: which measure or song element triggered this. */
|
|
166
|
+
source?: string;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* A voice directive — structured request to speak via mcp-voice-soundboard.
|
|
170
|
+
* The hook produces these; the caller (CLI, LLM, test) routes them to voice_speak.
|
|
171
|
+
*/
|
|
172
|
+
export interface VoiceDirective {
|
|
173
|
+
/** Text to speak. */
|
|
174
|
+
text: string;
|
|
175
|
+
/** Voice preset name (e.g. "narrator", "teacher"). */
|
|
176
|
+
voice?: string;
|
|
177
|
+
/** Speed multiplier for speech (0.5–2.0). */
|
|
178
|
+
speed?: number;
|
|
179
|
+
/** Whether to wait for speech to finish before continuing playback. */
|
|
180
|
+
blocking: boolean;
|
|
181
|
+
}
|
|
182
|
+
/** Callback that receives voice directives. */
|
|
183
|
+
export type VoiceSink = (directive: VoiceDirective) => Promise<void>;
|
|
184
|
+
/**
|
|
185
|
+
* An aside directive — structured request to push to mcp-aside inbox.
|
|
186
|
+
*/
|
|
187
|
+
export interface AsideDirective {
|
|
188
|
+
/** The text to display. */
|
|
189
|
+
text: string;
|
|
190
|
+
/** Priority level. */
|
|
191
|
+
priority: "low" | "med" | "high";
|
|
192
|
+
/** Why this was triggered. */
|
|
193
|
+
reason: string;
|
|
194
|
+
/** Source context (e.g. "measure-3", "key-moment"). */
|
|
195
|
+
source?: string;
|
|
196
|
+
/** Tags for filtering. */
|
|
197
|
+
tags?: string[];
|
|
198
|
+
}
|
|
199
|
+
/** Callback that receives aside directives. */
|
|
200
|
+
export type AsideSink = (directive: AsideDirective) => Promise<void>;
|
|
201
|
+
/** Options for the live feedback teaching hook. */
|
|
202
|
+
export interface LiveFeedbackHookOptions {
|
|
203
|
+
/** Emit a voice encouragement every N measures (default: 4). */
|
|
204
|
+
voiceInterval?: number;
|
|
205
|
+
/** React to dynamics changes with aside tips (default: true). */
|
|
206
|
+
encourageOnDynamics?: boolean;
|
|
207
|
+
/** Warn about difficult passages with voice tips (default: true). */
|
|
208
|
+
warnOnDifficult?: boolean;
|
|
209
|
+
/** Voice preset name (default: undefined = server default). */
|
|
210
|
+
voice?: string;
|
|
211
|
+
/** Speech speed (default: 1.0). */
|
|
212
|
+
speechSpeed?: number;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Teaching hook interface — inject this into sessions to receive
|
|
216
|
+
* teaching interjections during playback. Implementations can route
|
|
217
|
+
* to mcp-voice-soundboard, mcp-aside, console, or anything else.
|
|
218
|
+
*/
|
|
219
|
+
export interface TeachingHook {
|
|
220
|
+
/** Called before a measure plays — opportunity to announce what's coming. */
|
|
221
|
+
onMeasureStart(measureNumber: number, teachingNote: string | undefined, dynamics: string | undefined): Promise<void>;
|
|
222
|
+
/** Called when a key moment in the song is reached. */
|
|
223
|
+
onKeyMoment(moment: string): Promise<void>;
|
|
224
|
+
/** Called when the song finishes. */
|
|
225
|
+
onSongComplete(measuresPlayed: number, songTitle: string): Promise<void>;
|
|
226
|
+
/** Push a custom interjection. */
|
|
227
|
+
push(interjection: TeachingInterjection): Promise<void>;
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// ─── pianoai: Core Types ────────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Session management, MIDI playback, and teaching interaction types.
|
|
4
|
+
// These bridge ai-music-sheets (the library) with the runtime (MIDI + voice).
|
|
5
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
6
|
+
// ─── Note Parsing Types ─────────────────────────────────────────────────────
|
|
7
|
+
/** Duration suffix → multiplier (relative to quarter note). */
|
|
8
|
+
export const DURATION_MAP = {
|
|
9
|
+
w: 4.0, // whole
|
|
10
|
+
h: 2.0, // half
|
|
11
|
+
q: 1.0, // quarter
|
|
12
|
+
e: 0.5, // eighth
|
|
13
|
+
s: 0.25, // sixteenth
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Map from note name to semitone offset from C.
|
|
17
|
+
* Used for scientific pitch → MIDI number conversion.
|
|
18
|
+
*/
|
|
19
|
+
export const NOTE_OFFSETS = {
|
|
20
|
+
C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11,
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,qEAAqE;AACrE,8EAA8E;AAC9E,gFAAgF;AA+NhF,+EAA+E;AAE/E,+DAA+D;AAC/D,MAAM,CAAC,MAAM,YAAY,GAA2B;IAClD,CAAC,EAAE,GAAG,EAAI,QAAQ;IAClB,CAAC,EAAE,GAAG,EAAI,OAAO;IACjB,CAAC,EAAE,GAAG,EAAI,UAAU;IACpB,CAAC,EAAE,GAAG,EAAI,SAAS;IACnB,CAAC,EAAE,IAAI,EAAG,YAAY;CACvB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAA2B;IAClD,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;CAC1C,CAAC"}
|
package/dist/vmpk.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { VmpkConnector, VmpkConfig } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create a MIDI connector.
|
|
4
|
+
*
|
|
5
|
+
* With no config (or portName: "auto"), auto-detects the best available
|
|
6
|
+
* MIDI output — no external software required on Windows.
|
|
7
|
+
*
|
|
8
|
+
* For testing, inject a mock VmpkConnector via the Session constructor.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createVmpkConnector(config?: Partial<VmpkConfig>): VmpkConnector;
|
|
11
|
+
/**
|
|
12
|
+
* Create a mock VMPK connector for testing.
|
|
13
|
+
* Records all note events without sending any MIDI.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createMockVmpkConnector(): VmpkConnector & {
|
|
16
|
+
events: Array<{
|
|
17
|
+
type: string;
|
|
18
|
+
note?: number;
|
|
19
|
+
velocity?: number;
|
|
20
|
+
channel?: number;
|
|
21
|
+
}>;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=vmpk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vmpk.d.ts","sourceRoot":"","sources":["../src/vmpk.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAC;AAqBlF;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,GAAE,OAAO,CAAC,UAAU,CAAM,GAC/B,aAAa,CA4If;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,aAAa,GAAG;IACzD,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrF,CAoDA"}
|
package/dist/vmpk.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// ─── pianoai: MIDI Connector ─────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Connects to any available MIDI output using the JZZ library.
|
|
4
|
+
// Auto-detects the best port: prefers loopMIDI/VMPK if present,
|
|
5
|
+
// falls back to the system's built-in MIDI synth (e.g. Microsoft GS
|
|
6
|
+
// Wavetable Synth on Windows). No external software required.
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// const midi = createVmpkConnector(); // auto-detect best port
|
|
10
|
+
// const midi = createVmpkConnector({ portName: /loop/i }); // force specific port
|
|
11
|
+
// await midi.connect();
|
|
12
|
+
// midi.noteOn(60, 100); // middle C
|
|
13
|
+
// midi.noteOff(60);
|
|
14
|
+
// await midi.disconnect();
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
import JZZ from "jzz";
|
|
17
|
+
/** Default configuration — auto-detect best available MIDI output. */
|
|
18
|
+
const DEFAULT_CONFIG = {
|
|
19
|
+
portName: "auto",
|
|
20
|
+
channel: 0,
|
|
21
|
+
velocity: 80,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Preferred port patterns, tried in order.
|
|
25
|
+
* loopMIDI/VMPK first (for users with a full setup), then system synths.
|
|
26
|
+
*/
|
|
27
|
+
const PORT_PREFERENCES = [
|
|
28
|
+
/loop/i, // loopMIDI Port
|
|
29
|
+
/vmpk/i, // VMPK direct
|
|
30
|
+
/wavetable/i, // Microsoft GS Wavetable Synth
|
|
31
|
+
/synth/i, // Any other software synth
|
|
32
|
+
/midi/i, // Any port with "MIDI" in the name
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Create a MIDI connector.
|
|
36
|
+
*
|
|
37
|
+
* With no config (or portName: "auto"), auto-detects the best available
|
|
38
|
+
* MIDI output — no external software required on Windows.
|
|
39
|
+
*
|
|
40
|
+
* For testing, inject a mock VmpkConnector via the Session constructor.
|
|
41
|
+
*/
|
|
42
|
+
export function createVmpkConnector(config = {}) {
|
|
43
|
+
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
44
|
+
let engine = null;
|
|
45
|
+
let port = null;
|
|
46
|
+
let currentStatus = "disconnected";
|
|
47
|
+
let connectedPortName = "";
|
|
48
|
+
return {
|
|
49
|
+
async connect() {
|
|
50
|
+
if (currentStatus === "connected")
|
|
51
|
+
return;
|
|
52
|
+
currentStatus = "connecting";
|
|
53
|
+
try {
|
|
54
|
+
engine = await JZZ();
|
|
55
|
+
const ports = listPortsInternal(engine);
|
|
56
|
+
if (cfg.portName === "auto") {
|
|
57
|
+
// Auto-detect: try preferred patterns in order
|
|
58
|
+
port = null;
|
|
59
|
+
for (const pattern of PORT_PREFERENCES) {
|
|
60
|
+
const match = ports.find((p) => pattern.test(p));
|
|
61
|
+
if (match) {
|
|
62
|
+
try {
|
|
63
|
+
port = engine.openMidiOut(match);
|
|
64
|
+
connectedPortName = match;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// This port didn't work, try next pattern
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Last resort: try the first available port
|
|
74
|
+
if (!port && ports.length > 0) {
|
|
75
|
+
port = engine.openMidiOut(ports[0]);
|
|
76
|
+
connectedPortName = ports[0];
|
|
77
|
+
}
|
|
78
|
+
if (!port) {
|
|
79
|
+
throw new Error("No MIDI output ports available");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Specific port requested
|
|
84
|
+
port = engine.openMidiOut(cfg.portName);
|
|
85
|
+
connectedPortName =
|
|
86
|
+
cfg.portName instanceof RegExp
|
|
87
|
+
? (ports.find((p) => cfg.portName.test(p)) ?? cfg.portName.toString())
|
|
88
|
+
: String(cfg.portName);
|
|
89
|
+
}
|
|
90
|
+
currentStatus = "connected";
|
|
91
|
+
console.error(`MIDI connected: ${connectedPortName}`);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
currentStatus = "error";
|
|
95
|
+
const portDesc = cfg.portName === "auto"
|
|
96
|
+
? "(auto-detect)"
|
|
97
|
+
: cfg.portName instanceof RegExp
|
|
98
|
+
? cfg.portName.toString()
|
|
99
|
+
: `"${cfg.portName}"`;
|
|
100
|
+
throw new Error(`Failed to connect to MIDI output ${portDesc}. ` +
|
|
101
|
+
`Available ports: ${listPortsInternal(engine).join(", ") || "(none)"}. ` +
|
|
102
|
+
`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
async disconnect() {
|
|
106
|
+
if (port) {
|
|
107
|
+
// Send all-notes-off on all channels before disconnecting
|
|
108
|
+
for (let ch = 0; ch < 16; ch++) {
|
|
109
|
+
try {
|
|
110
|
+
port.send([0xB0 + ch, 123, 0]); // CC 123 = All Notes Off
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// ignore — port might already be closed
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
port.close();
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// ignore
|
|
121
|
+
}
|
|
122
|
+
port = null;
|
|
123
|
+
}
|
|
124
|
+
if (engine) {
|
|
125
|
+
try {
|
|
126
|
+
engine.close();
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// ignore
|
|
130
|
+
}
|
|
131
|
+
engine = null;
|
|
132
|
+
}
|
|
133
|
+
currentStatus = "disconnected";
|
|
134
|
+
},
|
|
135
|
+
status() {
|
|
136
|
+
return currentStatus;
|
|
137
|
+
},
|
|
138
|
+
listPorts() {
|
|
139
|
+
return listPortsInternal(engine);
|
|
140
|
+
},
|
|
141
|
+
noteOn(note, velocity, channel) {
|
|
142
|
+
if (!port || currentStatus !== "connected") {
|
|
143
|
+
throw new Error("MIDI port not connected");
|
|
144
|
+
}
|
|
145
|
+
const ch = channel ?? cfg.channel;
|
|
146
|
+
port.send([0x90 + ch, note & 0x7F, velocity & 0x7F]);
|
|
147
|
+
},
|
|
148
|
+
noteOff(note, channel) {
|
|
149
|
+
if (!port || currentStatus !== "connected") {
|
|
150
|
+
throw new Error("MIDI port not connected");
|
|
151
|
+
}
|
|
152
|
+
const ch = channel ?? cfg.channel;
|
|
153
|
+
port.send([0x80 + ch, note & 0x7F, 0]);
|
|
154
|
+
},
|
|
155
|
+
allNotesOff(channel) {
|
|
156
|
+
if (!port || currentStatus !== "connected")
|
|
157
|
+
return;
|
|
158
|
+
const ch = channel ?? cfg.channel;
|
|
159
|
+
port.send([0xB0 + ch, 123, 0]); // CC 123 = All Notes Off
|
|
160
|
+
},
|
|
161
|
+
async playNote(midiNote) {
|
|
162
|
+
if (midiNote.note < 0) {
|
|
163
|
+
// Rest — just wait
|
|
164
|
+
await sleep(midiNote.durationMs);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
this.noteOn(midiNote.note, midiNote.velocity, midiNote.channel);
|
|
168
|
+
await sleep(midiNote.durationMs);
|
|
169
|
+
this.noteOff(midiNote.note, midiNote.channel);
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Create a mock VMPK connector for testing.
|
|
175
|
+
* Records all note events without sending any MIDI.
|
|
176
|
+
*/
|
|
177
|
+
export function createMockVmpkConnector() {
|
|
178
|
+
let status = "disconnected";
|
|
179
|
+
const events = [];
|
|
180
|
+
const connector = {
|
|
181
|
+
events,
|
|
182
|
+
async connect() {
|
|
183
|
+
status = "connected";
|
|
184
|
+
events.push({ type: "connect" });
|
|
185
|
+
},
|
|
186
|
+
async disconnect() {
|
|
187
|
+
status = "disconnected";
|
|
188
|
+
events.push({ type: "disconnect" });
|
|
189
|
+
},
|
|
190
|
+
status() {
|
|
191
|
+
return status;
|
|
192
|
+
},
|
|
193
|
+
listPorts() {
|
|
194
|
+
return ["Mock Port 1"];
|
|
195
|
+
},
|
|
196
|
+
noteOn(note, velocity, channel = 0) {
|
|
197
|
+
events.push({ type: "noteOn", note, velocity, channel });
|
|
198
|
+
},
|
|
199
|
+
noteOff(note, channel = 0) {
|
|
200
|
+
events.push({ type: "noteOff", note, channel });
|
|
201
|
+
},
|
|
202
|
+
allNotesOff(channel = 0) {
|
|
203
|
+
events.push({ type: "allNotesOff", channel });
|
|
204
|
+
},
|
|
205
|
+
async playNote(midiNote) {
|
|
206
|
+
if (midiNote.note < 0) {
|
|
207
|
+
events.push({ type: "rest", note: -1 });
|
|
208
|
+
return; // don't actually sleep in mocks
|
|
209
|
+
}
|
|
210
|
+
events.push({
|
|
211
|
+
type: "playNote",
|
|
212
|
+
note: midiNote.note,
|
|
213
|
+
velocity: midiNote.velocity,
|
|
214
|
+
channel: midiNote.channel,
|
|
215
|
+
});
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
return connector;
|
|
219
|
+
}
|
|
220
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
221
|
+
function listPortsInternal(engine) {
|
|
222
|
+
if (!engine)
|
|
223
|
+
return [];
|
|
224
|
+
try {
|
|
225
|
+
const info = engine.info();
|
|
226
|
+
const outputs = info.outputs || [];
|
|
227
|
+
return outputs.map((o) => o.name || o.id || "(unnamed)");
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
function sleep(ms) {
|
|
234
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=vmpk.js.map
|
package/dist/vmpk.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vmpk.js","sourceRoot":"","sources":["../src/vmpk.ts"],"names":[],"mappings":"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"}
|
package/logo.png
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mcptoolshop/ai_jam_session",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Piano player with built-in audio engine — plays through speakers, no external software required. MCP server + CLI.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"ai-jam-session": "dist/cli.js",
|
|
10
|
+
"ai-jam-session-mcp": "dist/mcp-server.js"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"songs/builtin",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE",
|
|
23
|
+
"logo.png"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc",
|
|
30
|
+
"dev": "tsc --watch",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"test:watch": "vitest",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"start": "node dist/cli.js",
|
|
35
|
+
"mcp": "node dist/mcp-server.js",
|
|
36
|
+
"smoke": "node --import tsx src/smoke.ts"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"piano",
|
|
40
|
+
"audio",
|
|
41
|
+
"midi",
|
|
42
|
+
"mcp",
|
|
43
|
+
"ai",
|
|
44
|
+
"music",
|
|
45
|
+
"voice",
|
|
46
|
+
"web-audio"
|
|
47
|
+
],
|
|
48
|
+
"author": "mcp-tool-shop",
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"repository": {
|
|
54
|
+
"type": "git",
|
|
55
|
+
"url": "https://github.com/mcp-tool-shop-org/ai_jam_session.git"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
59
|
+
"jzz": "^1.8.0",
|
|
60
|
+
"midi-file": "^1.2.4",
|
|
61
|
+
"node-web-audio-api": "^1.0.8",
|
|
62
|
+
"zod": "^4.3.6"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@types/node": "^22.0.0",
|
|
66
|
+
"tsx": "^4.19",
|
|
67
|
+
"typescript": "^5.7",
|
|
68
|
+
"vitest": "^3.0"
|
|
69
|
+
}
|
|
70
|
+
}
|