@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
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// ─── Sing-Along for MIDI Files ──────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Teaching hook that generates singable text from raw MIDI note events.
|
|
4
|
+
// Unlike the library sing-along hook (which reads measure data from SongEntry),
|
|
5
|
+
// this hook reads the actual MidiNoteEvent stream and converts MIDI note numbers
|
|
6
|
+
// to singable syllables (note-names, solfege, contour, or syllables).
|
|
7
|
+
//
|
|
8
|
+
// Supports voice filters:
|
|
9
|
+
// - "all" — sing every note/chord (default)
|
|
10
|
+
// - "melody-only" — pick the highest note per cluster (typical melody line)
|
|
11
|
+
// - "harmony" — pick the lowest note per cluster (bass/harmony line)
|
|
12
|
+
//
|
|
13
|
+
// Designed to work with PlaybackController — listens to note events in real time.
|
|
14
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
15
|
+
import { midiToNoteName } from "../note-parser.js";
|
|
16
|
+
import { clusterEvents } from "../playback/timing.js";
|
|
17
|
+
// ─── MIDI Note → Singable Conversion ────────────────────────────────────────
|
|
18
|
+
/** Solfege mapping from pitch class (0–11) to syllable. */
|
|
19
|
+
const SOLFEGE_BY_PITCH_CLASS = [
|
|
20
|
+
"Do", "Di", "Re", "Me", "Mi", "Fa",
|
|
21
|
+
"Fi", "Sol", "Le", "La", "Te", "Ti",
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* Convert a MIDI note number to a singable syllable.
|
|
25
|
+
*
|
|
26
|
+
* - "note-names": "C4", "F#5", "Bb3"
|
|
27
|
+
* - "solfege": "Do", "Re", "Mi" (based on pitch class, not key)
|
|
28
|
+
* - "syllables": always "da"
|
|
29
|
+
* - "contour": not applicable for individual notes (returns note name)
|
|
30
|
+
*/
|
|
31
|
+
export function midiNoteToSingable(note, mode) {
|
|
32
|
+
switch (mode) {
|
|
33
|
+
case "note-names":
|
|
34
|
+
return midiToNoteName(note);
|
|
35
|
+
case "solfege":
|
|
36
|
+
return SOLFEGE_BY_PITCH_CLASS[note % 12];
|
|
37
|
+
case "syllables":
|
|
38
|
+
return "da";
|
|
39
|
+
case "contour":
|
|
40
|
+
return midiToNoteName(note);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Convert a cluster (chord or single note) to singable text.
|
|
45
|
+
*
|
|
46
|
+
* - Single note: just the syllable
|
|
47
|
+
* - Chord: syllables joined with " and " (e.g. "Do and Mi and Sol")
|
|
48
|
+
* - Contour mode between clusters: "up", "down", "same"
|
|
49
|
+
*/
|
|
50
|
+
export function clusterToSingable(events, mode) {
|
|
51
|
+
if (events.length === 0)
|
|
52
|
+
return "";
|
|
53
|
+
if (mode === "syllables") {
|
|
54
|
+
return events.length === 1 ? "da" : "da".repeat(1); // single syllable per cluster
|
|
55
|
+
}
|
|
56
|
+
const syllables = events.map((e) => midiNoteToSingable(e.note, mode));
|
|
57
|
+
// Remove duplicates (same note in a chord)
|
|
58
|
+
const unique = [...new Set(syllables)];
|
|
59
|
+
return unique.join(" and ");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Generate contour direction between two clusters.
|
|
63
|
+
* Compares the highest note of each cluster.
|
|
64
|
+
*/
|
|
65
|
+
export function contourDirection(prev, curr) {
|
|
66
|
+
if (prev.length === 0 || curr.length === 0)
|
|
67
|
+
return "";
|
|
68
|
+
const prevMax = Math.max(...prev.map((e) => e.note));
|
|
69
|
+
const currMax = Math.max(...curr.map((e) => e.note));
|
|
70
|
+
if (currMax > prevMax)
|
|
71
|
+
return "up";
|
|
72
|
+
if (currMax < prevMax)
|
|
73
|
+
return "down";
|
|
74
|
+
return "same";
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Filter a cluster of events based on the voice filter.
|
|
78
|
+
* Returns a subset of events to sing.
|
|
79
|
+
*/
|
|
80
|
+
export function filterClusterForVoice(events, filter) {
|
|
81
|
+
if (events.length === 0)
|
|
82
|
+
return [];
|
|
83
|
+
if (filter === "all")
|
|
84
|
+
return [...events];
|
|
85
|
+
if (filter === "melody-only") {
|
|
86
|
+
// Pick the highest note (typical melody line is on top)
|
|
87
|
+
let highest = events[0];
|
|
88
|
+
for (const e of events) {
|
|
89
|
+
if (e.note > highest.note)
|
|
90
|
+
highest = e;
|
|
91
|
+
}
|
|
92
|
+
return [highest];
|
|
93
|
+
}
|
|
94
|
+
// "harmony" — pick the lowest note
|
|
95
|
+
let lowest = events[0];
|
|
96
|
+
for (const e of events) {
|
|
97
|
+
if (e.note < lowest.note)
|
|
98
|
+
lowest = e;
|
|
99
|
+
}
|
|
100
|
+
return [lowest];
|
|
101
|
+
}
|
|
102
|
+
// ─── Sing-On-MIDI Hook ──────────────────────────────────────────────────────
|
|
103
|
+
/**
|
|
104
|
+
* Create a teaching hook that sings along with MIDI file playback.
|
|
105
|
+
*
|
|
106
|
+
* Pre-processes the ParsedMidi events into time clusters (chords/single notes),
|
|
107
|
+
* then emits singable text as each cluster is reached during playback.
|
|
108
|
+
*
|
|
109
|
+
* The hook implements TeachingHook so it can be composed with other hooks
|
|
110
|
+
* via composeTeachingHooks.
|
|
111
|
+
*
|
|
112
|
+
* @param sink - Voice sink to emit speech directives.
|
|
113
|
+
* @param midi - Parsed MIDI file data.
|
|
114
|
+
* @param options - Configuration.
|
|
115
|
+
* @returns Teaching hook with `.directives` for inspection.
|
|
116
|
+
*/
|
|
117
|
+
export function createSingOnMidiHook(sink, midi, options = {}) {
|
|
118
|
+
const { mode = "note-names", voiceFilter = "all", voice, speechSpeed = 1.0, announcePosition = false, batchSize = 8, chordThresholdMs = 10, blocking = true, } = options;
|
|
119
|
+
const directives = [];
|
|
120
|
+
// Pre-cluster all events by time proximity
|
|
121
|
+
const clusters = clusterEvents(midi.events, chordThresholdMs);
|
|
122
|
+
// Track which cluster we've announced (for onMeasureStart which fires per-note)
|
|
123
|
+
let lastAnnouncedCluster = -1;
|
|
124
|
+
let prevCluster = [];
|
|
125
|
+
// Build a lookup: event index → cluster index
|
|
126
|
+
const eventToCluster = new Map();
|
|
127
|
+
let eventOffset = 0;
|
|
128
|
+
for (let ci = 0; ci < clusters.length; ci++) {
|
|
129
|
+
for (let ei = 0; ei < clusters[ci].length; ei++) {
|
|
130
|
+
eventToCluster.set(eventOffset + ei, ci);
|
|
131
|
+
}
|
|
132
|
+
eventOffset += clusters[ci].length;
|
|
133
|
+
}
|
|
134
|
+
async function emit(directive) {
|
|
135
|
+
directives.push(directive);
|
|
136
|
+
await sink(directive);
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
directives,
|
|
140
|
+
clusters,
|
|
141
|
+
async onMeasureStart(eventIndex, _teachingNote, _dynamics) {
|
|
142
|
+
// eventIndex from PlaybackController is the note index (1-based)
|
|
143
|
+
const clusterIndex = eventToCluster.get(eventIndex - 1);
|
|
144
|
+
if (clusterIndex === undefined || clusterIndex === lastAnnouncedCluster)
|
|
145
|
+
return;
|
|
146
|
+
lastAnnouncedCluster = clusterIndex;
|
|
147
|
+
const rawCluster = clusters[clusterIndex];
|
|
148
|
+
// Apply voice filter (melody-only picks highest, harmony picks lowest)
|
|
149
|
+
const cluster = filterClusterForVoice(rawCluster, voiceFilter);
|
|
150
|
+
// Build singable text
|
|
151
|
+
let text;
|
|
152
|
+
if (mode === "contour" && prevCluster.length > 0) {
|
|
153
|
+
text = contourDirection(prevCluster, cluster);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
text = clusterToSingable(cluster, mode);
|
|
157
|
+
}
|
|
158
|
+
if (!text)
|
|
159
|
+
return;
|
|
160
|
+
// Optional position prefix
|
|
161
|
+
const prefix = announcePosition ? `${clusterIndex + 1}: ` : "";
|
|
162
|
+
await emit({
|
|
163
|
+
text: `${prefix}${text}`,
|
|
164
|
+
voice,
|
|
165
|
+
speed: speechSpeed,
|
|
166
|
+
blocking,
|
|
167
|
+
});
|
|
168
|
+
prevCluster = cluster;
|
|
169
|
+
},
|
|
170
|
+
async onKeyMoment(_moment) {
|
|
171
|
+
// Sing-on-MIDI does not speak key moments (MIDI files don't have them)
|
|
172
|
+
},
|
|
173
|
+
async onSongComplete(eventsPlayed, songTitle) {
|
|
174
|
+
await emit({
|
|
175
|
+
text: `Finished: ${songTitle}. ${eventsPlayed} notes.`,
|
|
176
|
+
voice,
|
|
177
|
+
speed: speechSpeed,
|
|
178
|
+
blocking: false,
|
|
179
|
+
});
|
|
180
|
+
},
|
|
181
|
+
async push(_interjection) {
|
|
182
|
+
// Sing-on-MIDI does not handle push interjections
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=sing-on-midi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sing-on-midi.js","sourceRoot":"","sources":["../../src/teaching/sing-on-midi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { TeachingHook, TeachingInterjection, VoiceDirective, VoiceSink, AsideDirective, AsideSink, LiveFeedbackHookOptions } from "./types.js";
|
|
2
|
+
import type { SongEntry } from "./songs/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Logs teaching interjections to the console.
|
|
5
|
+
* Good for CLI mode and development.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createConsoleTeachingHook(): TeachingHook;
|
|
8
|
+
/**
|
|
9
|
+
* No-op hook — swallows all interjections.
|
|
10
|
+
* Use in tests where you don't want console noise.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createSilentTeachingHook(): TeachingHook;
|
|
13
|
+
/** A recorded teaching event for assertions. */
|
|
14
|
+
export interface TeachingEvent {
|
|
15
|
+
type: "measure-start" | "key-moment" | "song-complete" | "push";
|
|
16
|
+
measureNumber?: number;
|
|
17
|
+
teachingNote?: string;
|
|
18
|
+
dynamics?: string;
|
|
19
|
+
moment?: string;
|
|
20
|
+
measuresPlayed?: number;
|
|
21
|
+
songTitle?: string;
|
|
22
|
+
interjection?: TeachingInterjection;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Records all teaching events for test assertions.
|
|
26
|
+
* Use: `const hook = createRecordingTeachingHook(); ... hook.events`
|
|
27
|
+
*/
|
|
28
|
+
export declare function createRecordingTeachingHook(): TeachingHook & {
|
|
29
|
+
events: TeachingEvent[];
|
|
30
|
+
};
|
|
31
|
+
/** Callbacks for a custom teaching hook. All optional — unset = no-op. */
|
|
32
|
+
export interface TeachingCallbacks {
|
|
33
|
+
onMeasureStart?: (measureNumber: number, teachingNote?: string, dynamics?: string) => Promise<void>;
|
|
34
|
+
onKeyMoment?: (moment: string) => Promise<void>;
|
|
35
|
+
onSongComplete?: (measuresPlayed: number, songTitle: string) => Promise<void>;
|
|
36
|
+
onPush?: (interjection: TeachingInterjection) => Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Routes teaching events to custom callbacks.
|
|
40
|
+
* Use this to wire to mcp-voice-soundboard, mcp-aside, or any other sink.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createCallbackTeachingHook(callbacks: TeachingCallbacks): TeachingHook;
|
|
43
|
+
/** Options for the voice teaching hook. */
|
|
44
|
+
export interface VoiceHookOptions {
|
|
45
|
+
/** Voice preset name for teaching (default: undefined = server default). */
|
|
46
|
+
voice?: string;
|
|
47
|
+
/** Speech speed (default: 1.0). */
|
|
48
|
+
speechSpeed?: number;
|
|
49
|
+
/** Speak teaching notes at measure start (default: true). */
|
|
50
|
+
speakTeachingNotes?: boolean;
|
|
51
|
+
/** Speak key moments (default: true). */
|
|
52
|
+
speakKeyMoments?: boolean;
|
|
53
|
+
/** Speak completion message (default: true). */
|
|
54
|
+
speakCompletion?: boolean;
|
|
55
|
+
/** Block playback while speaking (default: false for notes, true for key moments). */
|
|
56
|
+
blockOnKeyMoments?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Voice teaching hook — produces VoiceDirective objects routed to a VoiceSink.
|
|
60
|
+
*
|
|
61
|
+
* The sink can be:
|
|
62
|
+
* - A real mcp-voice-soundboard call (via LLM tool routing)
|
|
63
|
+
* - A console.log wrapper (for CLI testing)
|
|
64
|
+
* - A recording array (for unit tests)
|
|
65
|
+
*
|
|
66
|
+
* Also records all directives for inspection.
|
|
67
|
+
*/
|
|
68
|
+
export declare function createVoiceTeachingHook(sink: VoiceSink, options?: VoiceHookOptions): TeachingHook & {
|
|
69
|
+
directives: VoiceDirective[];
|
|
70
|
+
};
|
|
71
|
+
/** Options for the aside teaching hook. */
|
|
72
|
+
export interface AsideHookOptions {
|
|
73
|
+
/** Push teaching notes to aside (default: true). */
|
|
74
|
+
pushTeachingNotes?: boolean;
|
|
75
|
+
/** Push key moments to aside (default: true). */
|
|
76
|
+
pushKeyMoments?: boolean;
|
|
77
|
+
/** Push completion to aside (default: true). */
|
|
78
|
+
pushCompletion?: boolean;
|
|
79
|
+
/** Base tags added to all directives. */
|
|
80
|
+
baseTags?: string[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Aside teaching hook — produces AsideDirective objects routed to an AsideSink.
|
|
84
|
+
*
|
|
85
|
+
* The sink can be:
|
|
86
|
+
* - A real mcp-aside push (via aside_push tool)
|
|
87
|
+
* - A recording array (for tests)
|
|
88
|
+
*
|
|
89
|
+
* Records all directives for inspection.
|
|
90
|
+
*/
|
|
91
|
+
export declare function createAsideTeachingHook(sink: AsideSink, options?: AsideHookOptions): TeachingHook & {
|
|
92
|
+
directives: AsideDirective[];
|
|
93
|
+
};
|
|
94
|
+
import { type SingAlongMode } from "./note-parser.js";
|
|
95
|
+
/** Options for the sing-along teaching hook. */
|
|
96
|
+
export interface SingAlongHookOptions {
|
|
97
|
+
/** Sing-along mode (default: "note-names"). */
|
|
98
|
+
mode?: SingAlongMode;
|
|
99
|
+
/** Which hand(s) to narrate (default: "right"). */
|
|
100
|
+
hand?: "right" | "left" | "both";
|
|
101
|
+
/** Voice preset (default: undefined = server default). */
|
|
102
|
+
voice?: string;
|
|
103
|
+
/** Speech speed (default: 1.0). */
|
|
104
|
+
speechSpeed?: number;
|
|
105
|
+
/** Announce the measure number before notes (default: true). */
|
|
106
|
+
announceMeasureNumber?: boolean;
|
|
107
|
+
/** Speak completion message (default: true). */
|
|
108
|
+
speakCompletion?: boolean;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Sing-along teaching hook — narrates note names/solfege/contour/syllables
|
|
112
|
+
* from the actual measure data, synchronized with playback.
|
|
113
|
+
*
|
|
114
|
+
* Requires the full SongEntry to look up measure note data by measure number.
|
|
115
|
+
* Emits blocking VoiceDirectives on onMeasureStart so the voice speaks BEFORE
|
|
116
|
+
* the piano plays each measure.
|
|
117
|
+
*
|
|
118
|
+
* Composable with other hooks via composeTeachingHooks.
|
|
119
|
+
*/
|
|
120
|
+
export declare function createSingAlongHook(sink: VoiceSink, song: SongEntry, options?: SingAlongHookOptions): TeachingHook & {
|
|
121
|
+
directives: VoiceDirective[];
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Live feedback teaching hook — pushes context-aware encouragement and tips
|
|
125
|
+
* during singing/playback sessions via both voice and aside sinks.
|
|
126
|
+
*
|
|
127
|
+
* - Voice: periodic encouragement every N measures + key moment reactions
|
|
128
|
+
* - Aside: dynamics tips, fingering warnings, deeper contextual notes
|
|
129
|
+
*
|
|
130
|
+
* Composable with other hooks via composeTeachingHooks.
|
|
131
|
+
*/
|
|
132
|
+
export declare function createLiveFeedbackHook(voiceSink: VoiceSink, asideSink: AsideSink, song: SongEntry, options?: LiveFeedbackHookOptions): TeachingHook & {
|
|
133
|
+
voiceDirectives: VoiceDirective[];
|
|
134
|
+
asideDirectives: AsideDirective[];
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Compose multiple teaching hooks into one.
|
|
138
|
+
* Events are dispatched to all hooks in order (serially, not parallel).
|
|
139
|
+
*
|
|
140
|
+
* Example: combine a voice hook + aside hook + recording hook for full coverage.
|
|
141
|
+
*/
|
|
142
|
+
export declare function composeTeachingHooks(...hooks: TeachingHook[]): TeachingHook;
|
|
143
|
+
/**
|
|
144
|
+
* Check if the current measure matches any key moments in the song.
|
|
145
|
+
* Key moments in ai-music-sheets reference bars like "Bar 1:", "Bars 3-4:", etc.
|
|
146
|
+
*/
|
|
147
|
+
export declare function detectKeyMoments(song: SongEntry, measureNumber: number): string[];
|
|
148
|
+
//# sourceMappingURL=teaching.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teaching.d.ts","sourceRoot":"","sources":["../src/teaching.ts"],"names":[],"mappings":"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"}
|