@ray0404/zig-audio-mcp 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/src/index.ts ADDED
@@ -0,0 +1,1281 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
4
+ import { z } from "zod";
5
+
6
+ // Library information database
7
+ const ZIG_AUDIO_LIBRARIES = {
8
+ zang: {
9
+ name: "zang",
10
+ description: "Audio synthesis library with generators, effects, and filters. Low-level, no dynamic allocations.",
11
+ repo: "https://github.com/dbandstra/zang",
12
+ license: "MIT",
13
+ features: ["oscillators", "envelopes", "filters", "effects", "no-allocations"],
14
+ categories: ["synthesis", "effects", "filters"],
15
+ installation: "git clone https://github.com/dbandstra/zang.git && cd zang && zig build",
16
+ version: "0.12+ compatible",
17
+ examples: ["SineOsc", "Envelope", "Filter", "Sampler"],
18
+ api_docs: "https://github.com/dbandstra/zang#features",
19
+ use_cases: ["Game audio", "Real-time synthesis", "Embedded audio"]
20
+ },
21
+ zaudio: {
22
+ name: "zaudio",
23
+ description: "Zig wrapper for miniaudio. Supports playback, recording, and node graph audio processing.",
24
+ repo: "https://github.com/MasterQ32/zaudio",
25
+ license: "MIT",
26
+ features: ["playback", "recording", "node-graph", "streaming"],
27
+ categories: ["playback", "recording", "wrapper"],
28
+ installation: "Add to build.zig.zon: .url = \"git+https://github.com/MasterQ32/zaudio#master\"",
29
+ version: "Zig 0.11+",
30
+ examples: ["Device playback", "Recording", "Node graphs"],
31
+ api_docs: "https://github.com/MasterQ32/zaudio",
32
+ use_cases: ["Desktop audio apps", "Cross-platform playback", "Audio processing pipelines"]
33
+ },
34
+ bonk: {
35
+ name: "bonk",
36
+ description: "DSP objects including filters and delay lines. MPL-2.0 licensed.",
37
+ repo: "https://github.com/chr15m/bonk",
38
+ license: "MPL-2.0",
39
+ features: ["filters", "delay-lines", "waveshapers"],
40
+ categories: ["dsp", "effects"],
41
+ installation: "Add to build.zig.zon: .url = \"git+https://github.com/chr15m/bonk#master\"",
42
+ version: "Zig 0.10+",
43
+ examples: ["IIR filters", "Delay effects", "Waveshaping"],
44
+ api_docs: "https://github.com/chr15m/bonk",
45
+ use_cases: ["Audio effects processing", "Real-time DSP", "Creative coding"]
46
+ },
47
+ pcm: {
48
+ name: "pcm",
49
+ description: "PCM audio file handling for WAV and AIFF formats.",
50
+ repo: "https://github.com/Hejsil/pcm",
51
+ license: "MIT",
52
+ features: ["wav", "aiff", "io", "encoding"],
53
+ categories: ["file-io", "encoding"],
54
+ installation: "Add to build.zig.zon: .url = \"git+https://github.com/Hejsil/pcm#master\"",
55
+ version: "Zig 0.9+",
56
+ examples: ["WAV reading/writing", "AIFF support", "Sample format conversion"],
57
+ api_docs: "https://github.com/Hejsil/pcm",
58
+ use_cases: ["Audio file processing", "Sample libraries", "Format conversion"]
59
+ },
60
+ "zig-liquid-dsp": {
61
+ name: "zig-liquid-dsp",
62
+ description: "DSP library for software-defined radio. Complex signal processing.",
63
+ repo: "https://github.com/ggerard/zig-liquid-dsp",
64
+ license: "MIT",
65
+ features: ["filters", "modulation", "fourier", "sdr"],
66
+ categories: ["sdr", "dsp"],
67
+ installation: "Add to build.zig.zon: .url = \"git+https://github.com/ggerard/zig-liquid-dsp#master\"",
68
+ version: "Zig 0.11+",
69
+ examples: ["FIR/IIR filters", "Modulation schemes", "FFT processing"],
70
+ api_docs: "https://github.com/ggerard/zig-liquid-dsp",
71
+ use_cases: ["SDR applications", "Signal analysis", "Communications"]
72
+ },
73
+ dalek: {
74
+ name: "dalek",
75
+ description: "Experimental data-oriented audio engine.",
76
+ repo: "https://github.com/chr15m/dalek",
77
+ license: "MIT",
78
+ features: ["data-oriented", "performance", "audio-engine"],
79
+ categories: ["engine", "experimental"],
80
+ installation: "Add to build.zig.zon: .url = \"git+https://github.com/chr15m/dalek#master\"",
81
+ version: "Zig 0.10+",
82
+ examples: ["Entity-component audio", "High-performance mixing", "Modular processing"],
83
+ api_docs: "https://github.com/chr15m/dalek",
84
+ use_cases: ["Game engines", "High-performance audio", "Large-scale audio processing"]
85
+ }
86
+ };
87
+
88
+ // Filter information for DSP explanations
89
+ const DSP_FILTERS = {
90
+ lowpass: {
91
+ name: "Low Pass Filter",
92
+ description: "Allows frequencies below the cutoff to pass through, attenuating higher frequencies.",
93
+ formula: "y[n] = a0 * x[n] + a1 * x[n-1] + a2 * x[n-2] - b1 * y[n-1] - b2 * y[n-2]",
94
+ useCases: ["sub-bass smoothing", "removing high-frequency noise", "warmth/room modeling"],
95
+ zigLibraries: ["zang", "bonk", "zig-liquid-dsp"]
96
+ },
97
+ highpass: {
98
+ name: "High Pass Filter",
99
+ description: "Allows frequencies above the cutoff to pass through, attenuating lower frequencies.",
100
+ formula: "y[n] = a0 * x[n] + a1 * x[n-1] + a2 * x[n-2] - b1 * y[n-1] - b2 * y[n-2]",
101
+ useCases: ["DC offset removal", "rumble removal", "clarifying midrange"],
102
+ zigLibraries: ["zang", "bonk", "zig-liquid-dsp"]
103
+ },
104
+ bandpass: {
105
+ name: "Band Pass Filter",
106
+ description: "Allows frequencies within a specific band to pass through.",
107
+ formula: "y[n] = a0 * x[n] + a1 * x[n-1] + a2 * x[n-2] - b1 * y[n-1] - b2 * y[n-2]",
108
+ useCases: ["isolating instrument frequencies", "telephone effect", " formant simulation"],
109
+ zigLibraries: ["zang", "bonk", "zig-liquid-dsp"]
110
+ },
111
+ notch: {
112
+ name: "Notch Filter",
113
+ description: "Attenuates a specific frequency band while allowing others to pass.",
114
+ formula: "y[n] = a0 * x[n] + a1 * x[n-1] + a2 * x[n-2] - b1 * y[n-1] - b2 * y[n-2]",
115
+ useCases: ["hum removal", "feedback suppression", "EQ notching"],
116
+ zigLibraries: ["bonk", "zig-liquid-dsp"]
117
+ },
118
+ "biquad": {
119
+ name: "Biquad Filter",
120
+ description: "Second-order IIR filter using two poles and two zeros. Generic form for many filter types.",
121
+ formula: "y[n] = (b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]) / a0",
122
+ useCases: ["parametric EQ", "crossover filters", "tone control"],
123
+ zigLibraries: ["zang", "bonk"]
124
+ },
125
+ "one-pole": {
126
+ name: "One-Pole Filter",
127
+ description: "Simple first-order filter with single pole. Good for smoothing and DC removal.",
128
+ formula: "y[n] = alpha * x[n] + (1 - alpha) * y[n-1]",
129
+ useCases: ["smoothing", "DC removal", "simple envelopes"],
130
+ zigLibraries: ["zang"]
131
+ }
132
+ };
133
+
134
+ // Tool input validation schemas
135
+ const ListLibrariesInput = z.object({
136
+ category: z.enum(["synthesis", "effects", "filters", "dsp", "playback", "recording", "file-io", "encoding", "sdr", "engine", "wrapper", "experimental", "all"]).optional(),
137
+ feature: z.string().optional()
138
+ });
139
+
140
+ const GetLibraryInfoInput = z.object({
141
+ library: z.enum(["zang", "zaudio", "bonk", "pcm", "zig-liquid-dsp", "dalek"])
142
+ });
143
+
144
+ const ExplainFilterInput = z.object({
145
+ filter_type: z.enum(["lowpass", "highpass", "bandpass", "notch", "biquad", "one-pole"])
146
+ });
147
+
148
+ const GenerateCodeInput = z.object({
149
+ task: z.enum(["oscillator", "envelope", "filter", "delay", "mixer", "player", "recorder", "file-write", "file-read"]),
150
+ parameters: z.record(z.union([z.string(), z.number(), z.boolean()])).optional()
151
+ });
152
+
153
+ const ListResourcesInput = z.object({
154
+ resource_type: z.enum(["tutorial", "reference", "example", "article"]).optional()
155
+ });
156
+
157
+ const RecommendLibraryInput = z.object({
158
+ use_case: z.string().describe("Describe what you want to build (e.g., 'synthesizer', 'audio player', 'DSP effects')"),
159
+ requirements: z.array(z.string()).optional().describe("Specific requirements like 'low latency', 'no allocations', 'cross-platform'")
160
+ });
161
+
162
+ const DesignFilterInput = z.object({
163
+ filter_type: z.enum(["lowpass", "highpass", "bandpass", "notch", "biquad"]),
164
+ parameters: z.object({
165
+ sample_rate: z.number().min(1).max(192000),
166
+ cutoff: z.number().optional().describe("Cutoff frequency in Hz"),
167
+ q: z.number().optional().describe("Quality factor (resonance)"),
168
+ gain: z.number().optional().describe("Gain in dB for peaking/shelving filters")
169
+ })
170
+ });
171
+
172
+ const VerifyCodeInput = z.object({
173
+ code: z.string().describe("Zig code to verify for basic syntax and imports"),
174
+ libraries: z.array(z.string()).optional().describe("Expected libraries that should be imported")
175
+ });
176
+
177
+ const ProjectTemplateInput = z.object({
178
+ project_type: z.enum(["synthesizer", "audio-player", "dsp-processor", "file-processor", "game-audio"]),
179
+ features: z.array(z.string()).optional().describe("Additional features to include")
180
+ });
181
+
182
+ // Tool handlers
183
+ async function handleListLibraries(args: unknown) {
184
+ const input = ListLibrariesInput.parse(args);
185
+
186
+ let libraries = Object.values(ZIG_AUDIO_LIBRARIES);
187
+
188
+ if (input.category && input.category !== "all") {
189
+ libraries = libraries.filter(lib => lib.categories.includes(input.category!));
190
+ }
191
+
192
+ if (input.feature) {
193
+ libraries = libraries.filter(lib =>
194
+ lib.features.some(f => f.toLowerCase().includes(input.feature!.toLowerCase()))
195
+ );
196
+ }
197
+
198
+ return {
199
+ content: [{
200
+ type: "text",
201
+ text: JSON.stringify(libraries, null, 2)
202
+ }]
203
+ };
204
+ }
205
+
206
+ async function handleVerifyCode(args: unknown) {
207
+ const input = VerifyCodeInput.parse(args);
208
+
209
+ const issues: string[] = [];
210
+ const suggestions: string[] = [];
211
+
212
+ // Check for missing std import
213
+ if (input.code.includes("std.math") && !input.code.includes('const std = @import("std");')) {
214
+ issues.push("Missing std import but using std.math");
215
+ suggestions.push('Add: const std = @import("std");');
216
+ }
217
+
218
+ // Check for common library imports
219
+ const libraryChecks = [
220
+ { lib: "zang", pattern: /zang\./, import: 'const zang = @import("zang");' },
221
+ { lib: "zaudio", pattern: /zaudio\./, import: 'const zaudio = @import("zaudio");' },
222
+ { lib: "bonk", pattern: /bonk\./, import: 'const bonk = @import("bonk");' },
223
+ { lib: "pcm", pattern: /pcm\./, import: 'const pcm = @import("pcm");' }
224
+ ];
225
+
226
+ for (const check of libraryChecks) {
227
+ if (input.code.match(check.pattern) && !input.code.includes(check.import)) {
228
+ issues.push(`Using ${check.lib} but missing import`);
229
+ suggestions.push(`Add: ${check.import}`);
230
+ }
231
+ }
232
+
233
+ // Check for basic syntax issues
234
+ if (input.code.includes("main()") && !input.code.includes("pub fn main")) {
235
+ issues.push("main function should be declared as 'pub fn main'");
236
+ }
237
+
238
+ // Check for common mistakes
239
+ if (input.code.includes("try ") && !input.code.includes("!void")) {
240
+ suggestions.push("Consider using error return types (!void) for functions with try");
241
+ }
242
+
243
+ const verificationResult = {
244
+ code_length: input.code.length,
245
+ issues: issues.length > 0 ? issues : ["No obvious issues detected"],
246
+ suggestions: suggestions.length > 0 ? suggestions : ["Code looks good"],
247
+ libraries_found: libraryChecks.filter(check => input.code.includes(check.lib)).map(check => check.lib)
248
+ };
249
+
250
+ return {
251
+ content: [{
252
+ type: "text",
253
+ text: JSON.stringify(verificationResult, null, 2)
254
+ }]
255
+ };
256
+ }
257
+
258
+ async function handleProjectTemplate(args: unknown) {
259
+ const input = ProjectTemplateInput.parse(args);
260
+
261
+ const templates = {
262
+ synthesizer: {
263
+ build_zig: `const std = @import("std");
264
+
265
+ pub fn build(b: *std.Build) void {
266
+ const target = b.standardTargetOptions(.{});
267
+ const optimize = b.standardOptimizeOption(.{});
268
+
269
+ const exe = b.addExecutable(.{
270
+ .name = "synth",
271
+ .root_source_file = .{ .path = "src/main.zig" },
272
+ .target = target,
273
+ .optimize = optimize,
274
+ });
275
+
276
+ // Add zang dependency
277
+ const zang = b.dependency("zang", .{});
278
+ exe.root_module.addImport("zang", zang.module("zang"));
279
+
280
+ b.installArtifact(exe);
281
+ }`,
282
+ main_zig: `const std = @import("std");
283
+ const zang = @import("zang");
284
+
285
+ pub fn main() !void {
286
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
287
+ defer _ = gpa.deinit();
288
+ const allocator = gpa.allocator();
289
+
290
+ // Initialize synthesizer components
291
+ var sine_osc = zang.SineOsc.init(.{
292
+ .sample_rate = 44100,
293
+ .frequency = 440.0,
294
+ });
295
+
296
+ var envelope = zang.Envelope.init(.{
297
+ .attack = 0.1,
298
+ .decay = 0.2,
299
+ .sustain = 0.7,
300
+ .release = 0.3,
301
+ .sample_rate = 44100,
302
+ });
303
+
304
+ // Audio processing loop would go here
305
+ std.debug.print("Synthesizer initialized\\n", .{});
306
+ }`,
307
+ build_zig_zon: `.{ .name = "synth", .version = "0.1.0", .dependencies = .{
308
+ .zang = .{
309
+ .url = "https://github.com/dbandstra/zang/archive/master.tar.gz",
310
+ .hash = "1220...", // Get actual hash from zig fetch
311
+ },
312
+ } }`
313
+ },
314
+ "audio-player": {
315
+ build_zig: `const std = @import("std");
316
+
317
+ pub fn build(b: *std.Build) void {
318
+ const target = b.standardTargetOptions(.{});
319
+ const optimize = b.standardOptimizeOption(.{});
320
+
321
+ const exe = b.addExecutable(.{
322
+ .name = "player",
323
+ .root_source_file = .{ .path = "src/main.zig" },
324
+ .target = target,
325
+ .optimize = optimize,
326
+ });
327
+
328
+ // Add zaudio dependency
329
+ const zaudio = b.dependency("zaudio", .{});
330
+ exe.root_module.addImport("zaudio", zaudio.module("zaudio"));
331
+
332
+ b.installArtifact(exe);
333
+ }`,
334
+ main_zig: `const std = @import("std");
335
+ const zaudio = @import("zaudio");
336
+
337
+ pub fn main() !void {
338
+ // Initialize audio device
339
+ var device = try zaudio.Device.init(.{
340
+ .direction = .playback,
341
+ .sample_rate = 44100,
342
+ .channels = 2,
343
+ .format = .f32,
344
+ });
345
+ defer device.deinit();
346
+
347
+ // Start playback
348
+ try device.start();
349
+
350
+ std.debug.print("Audio player initialized\\n", .{});
351
+ }`,
352
+ build_zig_zon: `.{ .name = "player", .version = "0.1.0", .dependencies = .{
353
+ .zaudio = .{
354
+ .url = "https://github.com/MasterQ32/zaudio/archive/master.tar.gz",
355
+ .hash = "1220...", // Get actual hash
356
+ },
357
+ } }`
358
+ }
359
+ };
360
+
361
+ const template = (templates as any)[input.project_type] || templates.synthesizer;
362
+
363
+ const result = {
364
+ project_type: input.project_type,
365
+ files: {
366
+ "build.zig": template.build_zig,
367
+ "src/main.zig": template.main_zig,
368
+ "build.zig.zon": template.build_zig_zon
369
+ },
370
+ setup_instructions: [
371
+ "mkdir project-name && cd project-name",
372
+ "Copy the files above to their respective locations",
373
+ "Run 'zig build' to compile",
374
+ "Run 'zig build run' to execute"
375
+ ]
376
+ };
377
+
378
+ return {
379
+ content: [{
380
+ type: "text",
381
+ text: JSON.stringify(result, null, 2)
382
+ }]
383
+ };
384
+ }
385
+
386
+ async function handleGetLibraryInfo(args: unknown) {
387
+ const input = GetLibraryInfoInput.parse(args);
388
+ const lib = ZIG_AUDIO_LIBRARIES[input.library];
389
+
390
+ return {
391
+ content: [{
392
+ type: "text",
393
+ text: JSON.stringify(lib, null, 2)
394
+ }]
395
+ };
396
+ }
397
+
398
+ async function handleExplainFilter(args: unknown) {
399
+ const input = ExplainFilterInput.parse(args);
400
+ const filter = DSP_FILTERS[input.filter_type];
401
+
402
+ return {
403
+ content: [{
404
+ type: "text",
405
+ text: JSON.stringify(filter, null, 2)
406
+ }]
407
+ };
408
+ }
409
+
410
+ async function handleGenerateCode(args: unknown) {
411
+ const input = GenerateCodeInput.parse(args);
412
+
413
+ const codeTemplates: Record<string, string> = {
414
+ oscillator: `// Zig oscillator using zang
415
+ const std = @import("std");
416
+ const zang = @import("zang");
417
+
418
+ pub fn main() !void {
419
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
420
+ defer _ = gpa.deinit();
421
+ const allocator = gpa.allocator();
422
+
423
+ // Initialize zang modules
424
+ var modules = zang.modules;
425
+ var sine_osc = zang.SineOsc.init(.{
426
+ .sample_rate = 44100,
427
+ .frequency = 440.0,
428
+ });
429
+
430
+ // Create audio buffer
431
+ var buffer: [1024]f32 = undefined;
432
+
433
+ // Paint audio into buffer
434
+ sine_osc.paint(buffer[0..]);
435
+
436
+ std.debug.print("Generated {} samples of sine wave\\n", .{buffer.len});
437
+ }`,
438
+ envelope: `// ADSR envelope using zang
439
+ const std = @import("std");
440
+ const zang = @import("zang");
441
+
442
+ pub fn main() !void {
443
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
444
+ defer _ = gpa.deinit();
445
+ const allocator = gpa.allocator();
446
+
447
+ // Initialize zang envelope
448
+ var envelope = zang.Envelope.init(.{
449
+ .attack = 0.1,
450
+ .decay = 0.2,
451
+ .sustain = 0.7,
452
+ .release = 0.3,
453
+ .sample_rate = 44100,
454
+ });
455
+
456
+ // Create audio buffer
457
+ var buffer: [1024]f32 = undefined;
458
+
459
+ // Trigger note on
460
+ envelope.setGate(true);
461
+
462
+ // Paint envelope into buffer
463
+ envelope.paint(buffer[0..]);
464
+
465
+ // After some time, trigger note off
466
+ envelope.setGate(false);
467
+
468
+ std.debug.print("Generated ADSR envelope with {} samples\\n", .{buffer.len});
469
+ }`,
470
+ filter: `// Low-pass filter using zang
471
+ const std = @import("std");
472
+ const zang = @import("zang");
473
+
474
+ pub fn main() !void {
475
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
476
+ defer _ = gpa.deinit();
477
+ const allocator = gpa.allocator();
478
+
479
+ // Initialize zang low-pass filter
480
+ var filter = zang.Filter.init(.{
481
+ .type = .lowpass,
482
+ .cutoff = 1000.0,
483
+ .resonance = 0.7,
484
+ .sample_rate = 44100,
485
+ });
486
+
487
+ // Create input and output buffers
488
+ var input: [1024]f32 = undefined;
489
+ var output: [1024]f32 = undefined;
490
+
491
+ // Fill input with noise or signal
492
+ for (&input, 0..) |*sample, i| {
493
+ sample.* = std.rand.float(f32) * 2.0 - 1.0; // White noise
494
+ }
495
+
496
+ // Process through filter
497
+ filter.process(input[0..], output[0..]);
498
+
499
+ std.debug.print("Applied low-pass filter to {} samples\\n", .{input.len});
500
+ }`,
501
+ delay: `// Delay effect using bonk
502
+ const std = @import("std");
503
+ const bonk = @import("bonk");
504
+
505
+ pub fn main() !void {
506
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
507
+ defer _ = gpa.deinit();
508
+ const allocator = gpa.allocator();
509
+
510
+ // Initialize bonk delay
511
+ var delay = bonk.Delay.init(.{
512
+ .delay_time = 0.3, // 300ms delay
513
+ .feedback = 0.5,
514
+ .mix = 0.3,
515
+ .sample_rate = 44100,
516
+ });
517
+
518
+ // Create input and output buffers
519
+ var input: [1024]f32 = undefined;
520
+ var output: [1024]f32 = undefined;
521
+
522
+ // Fill input with some signal
523
+ for (&input, 0..) |*sample, i| {
524
+ sample.* = std.math.sin(@as(f32, @floatFromInt(i)) * 0.01); // Simple tone
525
+ }
526
+
527
+ // Process through delay
528
+ delay.process(input[0..], output[0..]);
529
+
530
+ std.debug.print("Applied delay effect to {} samples\\n", .{input.len});
531
+ }`,
532
+ mixer: `// Simple audio mixer
533
+ pub fn Mixer(comptime T: type, num_channels: usize) type {
534
+ return struct {
535
+ gains: [num_channels]f32 = .{0} ** num_channels,
536
+
537
+ pub fn setGain(self: *@This(), channel: usize, gain: f32) void {
538
+ if (channel < num_channels) {
539
+ self.gains[channel] = gain;
540
+ }
541
+ }
542
+
543
+ pub fn mix(self: *@This(), inputs: [num_channels]f32) f32 {
544
+ var result: f32 = 0;
545
+ for (inputs, self.gains) |input, gain| {
546
+ result += input * gain;
547
+ }
548
+ return result;
549
+ }
550
+ };
551
+ }`,
552
+ player: `// Audio playback using zaudio
553
+ const std = @import("std");
554
+ const zaudio = @import("zaudio");
555
+
556
+ pub fn main() !void {
557
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
558
+ defer _ = gpa.deinit();
559
+ const allocator = gpa.allocator();
560
+
561
+ // Initialize zaudio device
562
+ var device = try zaudio.Device.init(.{
563
+ .direction = .playback,
564
+ .sample_rate = 44100,
565
+ .channels = 2,
566
+ .format = .f32,
567
+ });
568
+ defer device.deinit();
569
+
570
+ // Start playback
571
+ try device.start();
572
+
573
+ // Create audio buffer with a sine wave
574
+ var buffer: [4410]f32 = undefined; // 0.1 seconds at 44100 Hz
575
+ for (&buffer, 0..) |*sample, i| {
576
+ const t = @as(f32, @floatFromInt(i)) / 44100.0;
577
+ sample.* = std.math.sin(t * 440.0 * 2.0 * std.math.pi) * 0.3;
578
+ }
579
+
580
+ // Play the buffer
581
+ try device.writeInterleaved(buffer[0..]);
582
+
583
+ // Wait a bit
584
+ std.time.sleep(100 * std.time.ns_per_ms);
585
+
586
+ std.debug.print("Played sine wave for 0.1 seconds\\n", .{});
587
+ }`,
588
+ recorder: `// Audio recording using zaudio
589
+ const std = @import("std");
590
+ const zaudio = @import("zaudio");
591
+
592
+ pub fn main() !void {
593
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
594
+ defer _ = gpa.deinit();
595
+ const allocator = gpa.allocator();
596
+
597
+ // Initialize zaudio device for recording
598
+ var device = try zaudio.Device.init(.{
599
+ .direction = .capture,
600
+ .sample_rate = 44100,
601
+ .channels = 1,
602
+ .format = .f32,
603
+ });
604
+ defer device.deinit();
605
+
606
+ // Start recording
607
+ try device.start();
608
+
609
+ // Record for 1 second
610
+ var buffer: [44100]f32 = undefined;
611
+ const frames_read = try device.readInterleaved(buffer[0..]);
612
+
613
+ std.debug.print("Recorded {} samples from microphone\\n", .{frames_read});
614
+ }`,
615
+ "file-write": `// Write WAV file using pcm
616
+ const std = @import("std");
617
+ const pcm = @import("pcm");
618
+
619
+ pub fn main() !void {
620
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
621
+ defer _ = gpa.deinit();
622
+ const allocator = gpa.allocator();
623
+
624
+ // Create some sample audio data
625
+ var samples = try allocator.alloc(f32, 44100); // 1 second at 44100 Hz
626
+ defer allocator.free(samples);
627
+
628
+ // Fill with a sine wave
629
+ for (samples, 0..) |*sample, i| {
630
+ const t = @as(f32, @floatFromInt(i)) / 44100.0;
631
+ sample.* = std.math.sin(t * 440.0 * 2.0 * std.math.pi) * 0.5;
632
+ }
633
+
634
+ // Write to WAV file
635
+ var wav_writer = try pcm.WavWriter.init(.{
636
+ .filename = "output.wav",
637
+ .channels = .mono,
638
+ .sample_rate = 44100,
639
+ .format = .f32,
640
+ });
641
+ defer wav_writer.deinit();
642
+
643
+ try wav_writer.write(samples);
644
+
645
+ std.debug.print("Wrote {} samples to output.wav\\n", .{samples.len});
646
+ }`,
647
+ "file-read": `// Read WAV file using pcm
648
+ const std = @import("std");
649
+ const pcm = @import("pcm");
650
+
651
+ pub fn main() !void {
652
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
653
+ defer _ = gpa.deinit();
654
+ const allocator = gpa.allocator();
655
+
656
+ // Read WAV file
657
+ var wav_reader = try pcm.WavReader.init("input.wav", allocator);
658
+ defer wav_reader.deinit();
659
+
660
+ std.debug.print("WAV file: {} Hz, {} channels, {} frames\\n",
661
+ .{wav_reader.sampleRate(), wav_reader.channels(), wav_reader.frameCount()});
662
+
663
+ // Read all samples
664
+ var samples = try wav_reader.readSamples(allocator);
665
+ defer allocator.free(samples);
666
+
667
+ std.debug.print("Read {} samples from input.wav\\n", .{samples.len});
668
+ }`
669
+ };
670
+
671
+ return {
672
+ content: [{
673
+ type: "text",
674
+ text: codeTemplates[input.task] || "Template not available"
675
+ }]
676
+ };
677
+ }
678
+
679
+ async function handleListResources(args: unknown) {
680
+ const input = ListResourcesInput.parse(args);
681
+
682
+ const resources = [
683
+ {
684
+ type: "tutorial",
685
+ title: "Zig Audio Ecosystem Overview",
686
+ url: "https://github.com/topics/zig-audio",
687
+ description: "Overview of audio libraries in Zig ecosystem"
688
+ },
689
+ {
690
+ type: "tutorial",
691
+ title: "Getting Started with Zang",
692
+ url: "https://github.com/dbandstra/zang",
693
+ description: "Complete guide to zang synthesis library with examples"
694
+ },
695
+ {
696
+ type: "tutorial",
697
+ title: "Audio Programming in Zig",
698
+ url: "https://ziglang.org/learn/samples/#audio",
699
+ description: "Official Zig language audio programming samples"
700
+ },
701
+ {
702
+ type: "example",
703
+ title: "Zang Examples Repository",
704
+ url: "https://github.com/dbandstra/zang/tree/master/examples",
705
+ description: "Complete examples for oscillators, effects, and synthesis"
706
+ },
707
+ {
708
+ type: "example",
709
+ title: "Zaudio Usage Examples",
710
+ url: "https://github.com/MasterQ32/zaudio/tree/master/examples",
711
+ description: "Cross-platform audio I/O examples with miniaudio"
712
+ },
713
+ {
714
+ type: "reference",
715
+ title: "Zaudio API Documentation",
716
+ url: "https://github.com/MasterQ32/zaudio",
717
+ description: "Complete API reference for miniaudio wrapper"
718
+ },
719
+ {
720
+ type: "reference",
721
+ title: "Digital Signal Processing Fundamentals",
722
+ url: "https://www.dspguide.com/",
723
+ description: "Comprehensive DSP theory and algorithms reference"
724
+ },
725
+ {
726
+ type: "reference",
727
+ title: "PCM File Format Specification",
728
+ url: "https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html",
729
+ description: "WAV file format technical specification"
730
+ },
731
+ {
732
+ type: "article",
733
+ title: "Building Real-time Audio Apps in Zig",
734
+ url: "https://christine.website/blog/zig-dsp-01-2024",
735
+ description: "In-depth tutorial on DSP effects and real-time processing"
736
+ },
737
+ {
738
+ type: "article",
739
+ title: "Zig Audio Libraries Comparison",
740
+ url: "https://zig.news/spectral/zig-audio-libraries-comparison-2024",
741
+ description: "Performance and feature comparison of Zig audio libraries"
742
+ },
743
+ {
744
+ type: "article",
745
+ title: "Low-Latency Audio Programming",
746
+ url: "https://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing",
747
+ description: "Essential guide to real-time audio programming concepts"
748
+ },
749
+ {
750
+ type: "tutorial",
751
+ title: "Software-Defined Radio with Zig",
752
+ url: "https://github.com/ggerard/zig-liquid-dsp",
753
+ description: "SDR programming tutorial using zig-liquid-dsp"
754
+ },
755
+ {
756
+ type: "example",
757
+ title: "Bonk DSP Effects",
758
+ url: "https://github.com/chr15m/bonk/tree/master/examples",
759
+ description: "Creative DSP effects and filter examples"
760
+ },
761
+ {
762
+ type: "reference",
763
+ title: "Audio EQ Cookbook",
764
+ url: "https://www.w3.org/TR/audio-eq-cookbook/",
765
+ description: "Standard biquad filter coefficient calculations"
766
+ },
767
+ {
768
+ type: "tutorial",
769
+ title: "Cross-Platform Audio Development",
770
+ url: "https://miniaud.io/docs/manual/index.html",
771
+ description: "Miniaudio documentation (used by zaudio)"
772
+ }
773
+ ];
774
+
775
+ let filtered = resources;
776
+ if (input.resource_type) {
777
+ filtered = resources.filter(r => r.type === input.resource_type);
778
+ }
779
+
780
+ return {
781
+ content: [{
782
+ type: "text",
783
+ text: JSON.stringify(filtered, null, 2)
784
+ }]
785
+ };
786
+ }
787
+
788
+ async function handleGetConcepts(args: unknown) {
789
+ const concepts = {
790
+ "sample-rate": {
791
+ description: "Number of samples captured per second (e.g., 44100 Hz, 48000 Hz)",
792
+ typicalValues: [44100, 48000, 96000],
793
+ impact: "Higher rates = more accurate audio but more CPU/memory"
794
+ },
795
+ "bit-depth": {
796
+ description: "Number of bits per sample for amplitude resolution",
797
+ typicalValues: [16, 24, 32],
798
+ impact: "Higher depth = more dynamic range, less quantization noise"
799
+ },
800
+ "buffer-size": {
801
+ description: "Number of samples processed per callback cycle",
802
+ typicalValues: [64, 128, 256, 512, 1024],
803
+ impact: "Smaller = lower latency, higher CPU; larger = more stable, more latency"
804
+ },
805
+ "nyquist-frequency": {
806
+ description: "Maximum representable frequency (sample_rate / 2)",
807
+ formula: "f_nyquist = sample_rate / 2"
808
+ },
809
+ "aliasing": {
810
+ description: "Distortion from sampling frequencies above Nyquist",
811
+ prevention: "Use anti-aliasing filters before downsampling"
812
+ }
813
+ };
814
+
815
+ return {
816
+ content: [{
817
+ type: "text",
818
+ text: JSON.stringify(concepts, null, 2)
819
+ }]
820
+ };
821
+ }
822
+
823
+ async function handleRecommendLibrary(args: unknown) {
824
+ const input = RecommendLibraryInput.parse(args);
825
+
826
+ const recommendations = {
827
+ synthesizer: {
828
+ primary: "zang",
829
+ reason: "Purpose-built for audio synthesis with oscillators, envelopes, and filters. No dynamic allocations makes it ideal for real-time performance.",
830
+ alternatives: ["dalek", "bonk"],
831
+ considerations: "If you need more complex synthesis, consider dalek for data-oriented approaches."
832
+ },
833
+ "audio-player": {
834
+ primary: "zaudio",
835
+ reason: "Direct wrapper around miniaudio provides cross-platform playback with minimal overhead.",
836
+ alternatives: ["zang", "dalek"],
837
+ considerations: "For synthesis + playback, combine zaudio with zang."
838
+ },
839
+ "dsp-effects": {
840
+ primary: "bonk",
841
+ reason: "Specializes in DSP objects like filters, delays, and waveshapers.",
842
+ alternatives: ["zig-liquid-dsp", "zang"],
843
+ considerations: "For SDR/communications DSP, use zig-liquid-dsp instead."
844
+ },
845
+ "file-processing": {
846
+ primary: "pcm",
847
+ reason: "Simple, efficient WAV/AIFF file I/O with multiple sample formats.",
848
+ alternatives: ["zaudio"],
849
+ considerations: "zaudio includes some file support but pcm is more comprehensive for file operations."
850
+ },
851
+ "sdr-radio": {
852
+ primary: "zig-liquid-dsp",
853
+ reason: "Comprehensive DSP library specifically for software-defined radio applications.",
854
+ alternatives: ["bonk"],
855
+ considerations: "For general DSP (not SDR-specific), bonk may be more appropriate."
856
+ },
857
+ "game-audio": {
858
+ primary: "zang",
859
+ reason: "Low-latency, no-allocation design perfect for games. Includes all essential synthesis components.",
860
+ alternatives: ["dalek", "zaudio"],
861
+ considerations: "Combine with zaudio for playback if zang's output isn't sufficient."
862
+ },
863
+ "embedded-audio": {
864
+ primary: "zang",
865
+ reason: "No dynamic allocations and low-level control make it ideal for embedded systems.",
866
+ alternatives: ["bonk"],
867
+ considerations: "Ensure your target platform supports Zig compilation."
868
+ }
869
+ };
870
+
871
+ // Find best match based on use case keywords
872
+ const useCase = input.use_case.toLowerCase();
873
+ let bestMatch = null;
874
+ let score = 0;
875
+
876
+ for (const [key, rec] of Object.entries(recommendations)) {
877
+ if (useCase.includes(key) || key.split('-').some(k => useCase.includes(k))) {
878
+ bestMatch = rec;
879
+ score = 1;
880
+ break;
881
+ }
882
+ }
883
+
884
+ // If no direct match, try partial matches
885
+ if (!bestMatch) {
886
+ for (const [key, rec] of Object.entries(recommendations)) {
887
+ const keywords = key.split('-');
888
+ const matchScore = keywords.filter(k => useCase.includes(k)).length / keywords.length;
889
+ if (matchScore > score) {
890
+ bestMatch = rec;
891
+ score = matchScore;
892
+ }
893
+ }
894
+ }
895
+
896
+ // Default recommendation if nothing matches
897
+ if (!bestMatch) {
898
+ bestMatch = {
899
+ primary: "zang",
900
+ reason: "General-purpose audio synthesis library suitable for most applications.",
901
+ alternatives: ["zaudio", "bonk"],
902
+ considerations: "Consider your specific requirements - playback, effects, file I/O, etc."
903
+ };
904
+ }
905
+
906
+ // Apply requirement filters
907
+ if (input.requirements) {
908
+ const reqs = input.requirements.map(r => r.toLowerCase());
909
+
910
+ if (reqs.includes("low latency") || reqs.includes("real-time")) {
911
+ if (bestMatch.primary !== "zang") {
912
+ bestMatch.primary = "zang";
913
+ bestMatch.reason = "Zang's no-allocation design provides the lowest latency.";
914
+ }
915
+ }
916
+
917
+ if (reqs.includes("cross-platform") || reqs.includes("playback")) {
918
+ bestMatch.primary = "zaudio";
919
+ bestMatch.reason = "Zaudio provides the most reliable cross-platform audio I/O.";
920
+ }
921
+
922
+ if (reqs.includes("no allocations") || reqs.includes("embedded")) {
923
+ bestMatch.primary = "zang";
924
+ bestMatch.reason = "Zang is specifically designed with zero dynamic allocations.";
925
+ }
926
+ }
927
+
928
+ const result = {
929
+ use_case: input.use_case,
930
+ recommendation: bestMatch,
931
+ library_details: ZIG_AUDIO_LIBRARIES[bestMatch.primary as keyof typeof ZIG_AUDIO_LIBRARIES]
932
+ };
933
+
934
+ return {
935
+ content: [{
936
+ type: "text",
937
+ text: JSON.stringify(result, null, 2)
938
+ }]
939
+ };
940
+ }
941
+
942
+ async function handleDesignFilter(args: unknown) {
943
+ const input = DesignFilterInput.parse(args);
944
+
945
+ // Basic filter coefficient calculation
946
+ function calculateBiquadCoefficients(type: string, fs: number, fc: number, q: number = 0.707, gain: number = 0) {
947
+ const omega = 2 * Math.PI * fc / fs;
948
+ const alpha = Math.sin(omega) / (2 * q);
949
+ const cos_omega = Math.cos(omega);
950
+ const A = Math.pow(10, gain / 40);
951
+
952
+ let b0, b1, b2, a0, a1, a2;
953
+
954
+ switch (type) {
955
+ case "lowpass":
956
+ b0 = (1 - cos_omega) / 2;
957
+ b1 = 1 - cos_omega;
958
+ b2 = (1 - cos_omega) / 2;
959
+ a0 = 1 + alpha;
960
+ a1 = -2 * cos_omega;
961
+ a2 = 1 - alpha;
962
+ break;
963
+ case "highpass":
964
+ b0 = (1 + cos_omega) / 2;
965
+ b1 = -(1 + cos_omega);
966
+ b2 = (1 + cos_omega) / 2;
967
+ a0 = 1 + alpha;
968
+ a1 = -2 * cos_omega;
969
+ a2 = 1 - alpha;
970
+ break;
971
+ case "bandpass":
972
+ b0 = alpha;
973
+ b1 = 0;
974
+ b2 = -alpha;
975
+ a0 = 1 + alpha;
976
+ a1 = -2 * cos_omega;
977
+ a2 = 1 - alpha;
978
+ break;
979
+ case "notch":
980
+ b0 = 1;
981
+ b1 = -2 * cos_omega;
982
+ b2 = 1;
983
+ a0 = 1 + alpha;
984
+ a1 = -2 * cos_omega;
985
+ a2 = 1 - alpha;
986
+ break;
987
+ default:
988
+ throw new Error(`Unsupported filter type: ${type}`);
989
+ }
990
+
991
+ // Normalize by a0
992
+ return {
993
+ b: [b0 / a0, b1 / a0, b2 / a0],
994
+ a: [1, a1 / a0, a2 / a0]
995
+ };
996
+ }
997
+
998
+ const params = input.parameters;
999
+ const coeffs = calculateBiquadCoefficients(
1000
+ input.filter_type,
1001
+ params.sample_rate,
1002
+ params.cutoff || 1000,
1003
+ params.q || 0.707,
1004
+ params.gain || 0
1005
+ );
1006
+
1007
+ const result = {
1008
+ filter_type: input.filter_type,
1009
+ parameters: params,
1010
+ coefficients: coeffs,
1011
+ stability_check: Math.abs(coeffs.a[1]) + Math.abs(coeffs.a[2]) < 1,
1012
+ zig_code: `// ${input.filter_type} filter coefficients
1013
+ const coeffs = struct {
1014
+ b: [3]f32 = .{${coeffs.b.map((x: number) => x.toFixed(6)).join(", ")}},
1015
+ a: [3]f32 = .{${coeffs.a.map((x: number) => x.toFixed(6)).join(", ")}},
1016
+ };
1017
+
1018
+ // Apply to signal using difference equation:
1019
+ // y[n] = b[0]*x[n] + b[1]*x[n-1] + b[2]*x[n-2] - a[1]*y[n-1] - a[2]*y[n-2]`
1020
+ };
1021
+
1022
+ return {
1023
+ content: [{
1024
+ type: "text",
1025
+ text: JSON.stringify(result, null, 2)
1026
+ }]
1027
+ };
1028
+ }
1029
+
1030
+ // Create and configure the MCP server
1031
+ const server = new Server(
1032
+ {
1033
+ name: "mcp-zig-audio",
1034
+ version: "0.1.0"
1035
+ },
1036
+ {
1037
+ capabilities: {
1038
+ tools: {}
1039
+ }
1040
+ }
1041
+ );
1042
+
1043
+ // Set up request handlers
1044
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
1045
+ return {
1046
+ tools: [
1047
+ {
1048
+ name: "zig_audio_list_libraries",
1049
+ description: "List available Zig audio/DSP libraries with optional filtering",
1050
+ inputSchema: {
1051
+ type: "object",
1052
+ properties: {
1053
+ category: {
1054
+ type: "string",
1055
+ enum: ["synthesis", "effects", "filters", "dsp", "playback", "recording", "file-io", "encoding", "sdr", "engine", "wrapper", "experimental", "all"],
1056
+ description: "Filter by category"
1057
+ },
1058
+ feature: {
1059
+ type: "string",
1060
+ description: "Filter by feature keyword"
1061
+ }
1062
+ }
1063
+ }
1064
+ },
1065
+ {
1066
+ name: "zig_audio_library_info",
1067
+ "description": "Get detailed information about a specific Zig audio library",
1068
+ inputSchema: {
1069
+ type: "object",
1070
+ properties: {
1071
+ library: {
1072
+ type: "string",
1073
+ enum: ["zang", "zaudio", "bonk", "pcm", "zig-liquid-dsp", "dalek"],
1074
+ description: "Library name"
1075
+ }
1076
+ },
1077
+ required: ["library"]
1078
+ }
1079
+ },
1080
+ {
1081
+ name: "zig_dsp_explain_filter",
1082
+ "description": "Explain a DSP filter type with formula and use cases",
1083
+ inputSchema: {
1084
+ type: "object",
1085
+ properties: {
1086
+ filter_type: {
1087
+ type: "string",
1088
+ enum: ["lowpass", "highpass", "bandpass", "notch", "biquad", "one-pole"],
1089
+ description: "Filter type to explain"
1090
+ }
1091
+ },
1092
+ required: ["filter_type"]
1093
+ }
1094
+ },
1095
+ {
1096
+ name: "zig_audio_generate_code",
1097
+ "description": "Generate starter code for common audio/DSP tasks",
1098
+ inputSchema: {
1099
+ type: "object",
1100
+ properties: {
1101
+ task: {
1102
+ type: "string",
1103
+ enum: ["oscillator", "envelope", "filter", "delay", "mixer", "player", "recorder", "file-write", "file-read"],
1104
+ description: "Type of code to generate"
1105
+ },
1106
+ parameters: {
1107
+ type: "object",
1108
+ description: "Optional parameters for code generation"
1109
+ }
1110
+ },
1111
+ required: ["task"]
1112
+ }
1113
+ },
1114
+ {
1115
+ name: "zig_audio_list_resources",
1116
+ "description": "List learning resources for Zig audio development",
1117
+ inputSchema: {
1118
+ type: "object",
1119
+ properties: {
1120
+ resource_type: {
1121
+ type: "string",
1122
+ enum: ["tutorial", "reference", "example", "article"],
1123
+ description: "Filter by resource type"
1124
+ }
1125
+ }
1126
+ }
1127
+ },
1128
+ {
1129
+ name: "zig_dsp_get_concepts",
1130
+ "description": "Get explanations of fundamental audio/DSP concepts",
1131
+ inputSchema: {
1132
+ type: "object",
1133
+ properties: {}
1134
+ }
1135
+ },
1136
+ {
1137
+ name: "zig_audio_recommend_library",
1138
+ description: "Get library recommendations based on your audio programming needs",
1139
+ inputSchema: {
1140
+ type: "object",
1141
+ properties: {
1142
+ use_case: {
1143
+ type: "string",
1144
+ description: "Describe what you want to build (e.g., 'synthesizer', 'audio player', 'DSP effects')"
1145
+ },
1146
+ requirements: {
1147
+ type: "array",
1148
+ items: { type: "string" },
1149
+ description: "Specific requirements like 'low latency', 'no allocations', 'cross-platform'"
1150
+ }
1151
+ },
1152
+ required: ["use_case"]
1153
+ }
1154
+ },
1155
+ {
1156
+ name: "zig_dsp_design_filter",
1157
+ description: "Design DSP filters and calculate biquad coefficients",
1158
+ inputSchema: {
1159
+ type: "object",
1160
+ properties: {
1161
+ filter_type: {
1162
+ type: "string",
1163
+ enum: ["lowpass", "highpass", "bandpass", "notch", "biquad"],
1164
+ description: "Type of filter to design"
1165
+ },
1166
+ parameters: {
1167
+ type: "object",
1168
+ properties: {
1169
+ sample_rate: {
1170
+ type: "number",
1171
+ description: "Sample rate in Hz"
1172
+ },
1173
+ cutoff: {
1174
+ type: "number",
1175
+ description: "Cutoff frequency in Hz"
1176
+ },
1177
+ q: {
1178
+ type: "number",
1179
+ description: "Quality factor (resonance)"
1180
+ },
1181
+ gain: {
1182
+ type: "number",
1183
+ description: "Gain in dB for parametric filters"
1184
+ }
1185
+ },
1186
+ required: ["sample_rate"]
1187
+ }
1188
+ },
1189
+ required: ["filter_type", "parameters"]
1190
+ }
1191
+ },
1192
+ {
1193
+ name: "zig_audio_verify_code",
1194
+ description: "Verify Zig code for basic syntax and common issues",
1195
+ inputSchema: {
1196
+ type: "object",
1197
+ properties: {
1198
+ code: {
1199
+ type: "string",
1200
+ description: "Zig code to verify"
1201
+ },
1202
+ libraries: {
1203
+ type: "array",
1204
+ items: { type: "string" },
1205
+ description: "Expected libraries that should be imported"
1206
+ }
1207
+ },
1208
+ required: ["code"]
1209
+ }
1210
+ },
1211
+ {
1212
+ name: "zig_audio_project_template",
1213
+ description: "Generate project templates for different audio application types",
1214
+ inputSchema: {
1215
+ type: "object",
1216
+ properties: {
1217
+ project_type: {
1218
+ type: "string",
1219
+ enum: ["synthesizer", "audio-player", "dsp-processor", "file-processor", "game-audio"],
1220
+ description: "Type of audio project"
1221
+ },
1222
+ features: {
1223
+ type: "array",
1224
+ items: { type: "string" },
1225
+ description: "Additional features to include"
1226
+ }
1227
+ },
1228
+ required: ["project_type"]
1229
+ }
1230
+ }
1231
+ ]
1232
+ };
1233
+ });
1234
+
1235
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1236
+ const { name, arguments: args } = request.params;
1237
+
1238
+ try {
1239
+ switch (name) {
1240
+ case "zig_audio_list_libraries":
1241
+ return await handleListLibraries(args);
1242
+ case "zig_audio_library_info":
1243
+ return await handleGetLibraryInfo(args);
1244
+ case "zig_dsp_explain_filter":
1245
+ return await handleExplainFilter(args);
1246
+ case "zig_audio_generate_code":
1247
+ return await handleGenerateCode(args);
1248
+ case "zig_audio_list_resources":
1249
+ return await handleListResources(args);
1250
+ case "zig_dsp_get_concepts":
1251
+ return await handleGetConcepts(args);
1252
+ case "zig_audio_recommend_library":
1253
+ return await handleRecommendLibrary(args);
1254
+ case "zig_dsp_design_filter":
1255
+ return await handleDesignFilter(args);
1256
+ case "zig_audio_verify_code":
1257
+ return await handleVerifyCode(args);
1258
+ case "zig_audio_project_template":
1259
+ return await handleProjectTemplate(args);
1260
+ default:
1261
+ throw new Error(`Unknown tool: ${name}`);
1262
+ }
1263
+ } catch (error) {
1264
+ return {
1265
+ content: [{
1266
+ type: "text",
1267
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`
1268
+ }],
1269
+ isError: true
1270
+ };
1271
+ }
1272
+ });
1273
+
1274
+ // Start the server with stdio transport
1275
+ async function main() {
1276
+ const transport = new StdioServerTransport();
1277
+ await server.connect(transport);
1278
+ console.error("MCP Zig Audio server running on stdio");
1279
+ }
1280
+
1281
+ main().catch(console.error);