audio_analyze
Analyze audio files by extracting fingerprints, tracking pitch, generating spectrograms, and comparing audio iterations. Supports batch operations for multiple files.
Instructions
Analyze audio. ops: fingerprint|formants|compare|diff|spectrogram|waveform|waterfall|pitch|onsets|batch
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Audio file path (or array for batch) | |
| op | Yes | Operation to perform | |
| path2 | No | Second file for compare/diff |
Implementation Reference
- src/audio_analysis_mcp/server.py:280-306 (registration)Registration of the 'audio_analyze' MCP tool via @server.list_tools() decorator, defining the tool name, description, and input schema.
@server.list_tools() async def list_tools() -> list[Tool]: return [ Tool( name="audio_analyze", description="Analyze audio. ops: fingerprint|formants|compare|diff|spectrogram|waveform|waterfall|pitch|onsets|batch", inputSchema={ "type": "object", "properties": { "path": { "type": ["string", "array"], "description": "Audio file path (or array for batch)", }, "op": { "type": "string", "enum": list(OPERATIONS.keys()), "description": "Operation to perform", }, "path2": { "type": "string", "description": "Second file for compare/diff", }, }, "required": ["path", "op"], }, ) ] - src/audio_analysis_mcp/server.py:309-325 (handler)Handler function that executes the 'audio_analyze' tool logic via @server.call_tool(), dispatching to OPERATIONS based on the 'op' argument.
@server.call_tool() async def call_tool(name: str, arguments: dict) -> list[TextContent]: if name != "audio_analyze": return [TextContent(type="text", text=json.dumps({"error": f"unknown tool: {name}"}))] path = arguments.get("path") op = arguments.get("op") path2 = arguments.get("path2") if op not in OPERATIONS: return [TextContent(type="text", text=json.dumps({"error": f"unknown op: {op}"}))] try: result = OPERATIONS[op](path, path2) return [TextContent(type="text", text=json.dumps(result))] except Exception as e: return [TextContent(type="text", text=json.dumps({"error": str(e)}))] - Input schema for the audio_analyze tool, defining path (string|array), op (enum of operations), and optional path2 parameters.
inputSchema={ "type": "object", "properties": { "path": { "type": ["string", "array"], "description": "Audio file path (or array for batch)", }, "op": { "type": "string", "enum": list(OPERATIONS.keys()), "description": "Operation to perform", }, "path2": { "type": "string", "description": "Second file for compare/diff", }, }, "required": ["path", "op"], }, - OPERATIONS dictionary that maps operation names to lambda functions dispatching to the actual analysis functions (fingerprint, formants, compare, diff, spectrogram, waveform, waterfall, pitch, onsets, batch).
OPERATIONS = { "fingerprint": lambda p, p2: fingerprint(p), "formants": lambda p, p2: formants(p), "compare": lambda p, p2: compare(p, p2), "diff": lambda p, p2: diff(p, p2), "spectrogram": lambda p, p2: save_spectrogram(p), "waveform": lambda p, p2: save_waveform(p), "waterfall": lambda p, p2: save_waterfall(p), "pitch": lambda p, p2: pitch_track(p), "onsets": lambda p, p2: detect_onsets(p), "batch": lambda p, p2: batch_analyze(p if isinstance(p, list) else [p]), } - The 'fingerprint' helper function - one of the core analysis functions dispatched by the OPERATIONS dict when op='fingerprint'.
def fingerprint(path: str) -> dict: """Compute numerical fingerprint of audio file.""" y, sr = librosa.load(path, sr=None) return { "rms": round(float(np.sqrt(np.mean(y**2))), 4), "peak": round(float(np.max(np.abs(y))), 4), "zcr": round(float(np.mean(librosa.feature.zero_crossing_rate(y))), 4), "centroid": round(float(np.mean(librosa.feature.spectral_centroid(y=y, sr=sr))), 1), "bandwidth": round(float(np.mean(librosa.feature.spectral_bandwidth(y=y, sr=sr))), 1), "rolloff": round(float(np.mean(librosa.feature.spectral_rolloff(y=y, sr=sr))), 1), "duration": round(len(y) / sr, 3), }