analyze_wav_samples
Analyze WAV files for drum kit samples to identify playback issues, metadata inconsistencies, and compatibility problems. Provides detailed reports and recommendations for fixes to ensure accurate sample integration.
Instructions
Analyze WAV files to detect common issues in drum kit samples.
This tool checks for:
Non-standard WAV headers that may cause playback issues
Metadata inconsistencies that could affect multi-mic setups
Sample rate and bit depth compatibility
Channel configuration issues
File size and format validation
Error Handling:
Reports detailed header format issues
Identifies metadata inconsistencies between related samples
Flags potential playback compatibility problems
Returns specific error messages for each issue type
Success Response: Returns detailed analysis including:
WAV header information
Sample metadata
Potential compatibility issues
Recommendations for fixes
IMPORTANT: Always use absolute paths (e.g., 'C:/Users/username/Documents/Samples/kick.wav') rather than relative paths.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| paths | Yes | Array of absolute paths to WAV files to analyze (e.g., ['C:/Users/username/Documents/Samples/kick.wav']) |
Input Schema (JSON Schema)
Implementation Reference
- src/wav-analysis.ts:122-157 (handler)The core handler function `analyzeWavFile` that reads the WAV file, parses its header, validates the format, calculates sample length, and returns structured analysis data including sample length, rate, channels, and bit depth.export async function analyzeWavFile(path: string): Promise<WavAnalysis> { try { const buffer = await fs.readFile(path); if (buffer.length < 44) { // Minimum size for WAV header throw new McpError( ErrorCode.InvalidRequest, 'File too small to be a valid WAV file' ); } const header = await parseWavHeader(buffer); // Calculate sample length from data chunk size const bytesPerSample = header.bitsPerSample / 8; const samplesPerChannel = header.dataSize! / (bytesPerSample * header.numChannels); return { path, sampleLength: Math.round(samplesPerChannel), sampleRate: header.sampleRate, channels: header.numChannels, bitDepth: header.bitsPerSample }; } catch (error: unknown) { if (error instanceof McpError) { throw error; // Re-throw validation errors } // Handle unexpected errors console.error('WAV analysis error:', error instanceof Error ? error.message : error); const message = error instanceof Error ? error.message : JSON.stringify(error); throw new McpError( ErrorCode.InternalError, `Failed to analyze WAV file ${path}: ${message}` ); } }
- src/index.ts:247-283 (registration)Tool registration in `ListToolsRequestSchema` handler, defining the tool name, description, and input schema (array of absolute paths to WAV files).{ name: "analyze_wav_samples", description: `Analyze WAV files to detect common issues in drum kit samples. This tool checks for: - Non-standard WAV headers that may cause playback issues - Metadata inconsistencies that could affect multi-mic setups - Sample rate and bit depth compatibility - Channel configuration issues - File size and format validation Error Handling: - Reports detailed header format issues - Identifies metadata inconsistencies between related samples - Flags potential playback compatibility problems - Returns specific error messages for each issue type Success Response: Returns detailed analysis including: - WAV header information - Sample metadata - Potential compatibility issues - Recommendations for fixes IMPORTANT: Always use absolute paths (e.g., 'C:/Users/username/Documents/Samples/kick.wav') rather than relative paths.`, inputSchema: { type: "object", properties: { paths: { type: "array", items: { type: "string" }, description: "Array of absolute paths to WAV files to analyze (e.g., ['C:/Users/username/Documents/Samples/kick.wav'])" } }, required: ["paths"] } },
- src/index.ts:600-628 (handler)MCP tool call handler in the switch statement that validates input arguments, calls `analyzeWavFile` on each path concurrently, and returns JSON-stringified analysis results.case "analyze_wav_samples": { const args = request.params.arguments; if (!args || !Array.isArray(args.paths)) { throw new McpError( ErrorCode.InvalidParams, "Invalid arguments: expected array of paths" ); } try { const analyses = await Promise.all( args.paths.map(path => analyzeWavFile(path)) ); return { content: [{ type: "text", text: JSON.stringify(analyses, null, 2) }] }; } catch (error: unknown) { if (error instanceof McpError) throw error; const message = error instanceof Error ? error.message : String(error); throw new McpError( ErrorCode.InternalError, `Failed to analyze WAV files: ${message}` ); } }
- src/wav-analysis.ts:5-11 (schema)TypeScript interface `WavAnalysis` defining the output structure returned by the analysis function.export interface WavAnalysis { path: string; sampleLength: number; // For end marker sampleRate: number; channels: number; bitDepth: number; }
- src/wav-analysis.ts:29-120 (helper)Helper function `parseWavHeader` that parses and validates the WAV file header, extracting format details and throwing detailed errors for invalid files.async function parseWavHeader(buffer: Buffer): Promise<WavHeader> { const invalidReasons: string[] = []; // RIFF header const riffHeader = buffer.toString('ascii', 0, 4); if (riffHeader !== 'RIFF') { invalidReasons.push('Missing RIFF header'); } // File size const fileSize = buffer.readUInt32LE(4); // WAVE header const waveHeader = buffer.toString('ascii', 8, 12); if (waveHeader !== 'WAVE') { invalidReasons.push('Missing WAVE format marker'); } // fmt chunk const fmtHeader = buffer.toString('ascii', 12, 16); if (fmtHeader !== 'fmt ') { invalidReasons.push('Missing fmt chunk'); } const fmtChunkSize = buffer.readUInt32LE(16); const audioFormat = buffer.readUInt16LE(20); if (audioFormat !== 1) { invalidReasons.push(`Unsupported audio format: ${audioFormat} (only PCM supported)`); } const numChannels = buffer.readUInt16LE(22); const sampleRate = buffer.readUInt32LE(24); const byteRate = buffer.readUInt32LE(28); const blockAlign = buffer.readUInt16LE(32); const bitsPerSample = buffer.readUInt16LE(34); // Validate format values if (numChannels === 0) { invalidReasons.push('Invalid number of channels: 0'); } if (sampleRate === 0) { invalidReasons.push('Invalid sample rate: 0'); } if (bitsPerSample === 0) { invalidReasons.push('Invalid bits per sample: 0'); } // Look for data chunk let dataHeader: string | undefined; let dataSize: number | undefined; let offset = 36; // Skip any non-data chunks while (offset < buffer.length - 8) { const chunkHeader = buffer.toString('ascii', offset, offset + 4); const chunkSize = buffer.readUInt32LE(offset + 4); if (chunkHeader === 'data') { dataHeader = chunkHeader; dataSize = chunkSize; break; } offset += 8 + chunkSize; } if (!dataHeader || !dataSize) { invalidReasons.push('Missing data chunk'); } if (invalidReasons.length > 0) { throw new McpError( ErrorCode.InvalidRequest, `WAV file validation failed: ${invalidReasons.join(', ')}` ); } return { riffHeader, fileSize, waveHeader, fmtHeader, fmtChunkSize, audioFormat, numChannels, sampleRate, byteRate, blockAlign, bitsPerSample, dataHeader, dataSize }; }