Skip to main content
Glama

analyze_spectrum

Analyze audio frequency content using FFT to support music pattern creation and audio processing in Strudel live coding environments.

Instructions

FFT spectrum analysis

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The main tool handler for 'analyze_spectrum'. Checks if browser is initialized, then delegates to StrudelController.analyzeAudio() and returns the spectrum features or full analysis result.
    case 'analyze_spectrum': if (!this.isInitialized) { return 'Browser not initialized. Run init first.'; } const spectrum = await this.controller.analyzeAudio(); return spectrum.features || spectrum;
  • Tool schema definition including name, description ('FFT spectrum analysis'), and input schema (no parameters required).
    name: 'analyze_spectrum', description: 'FFT spectrum analysis', inputSchema: { type: 'object', properties: {} }
  • Tool registration via setRequestHandler for ListToolsRequestSchema, which returns the full tools list including analyze_spectrum from getTools().
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: this.getTools() }));
  • StrudelController.analyzeAudio() method delegated by the tool handler, which forwards to AudioAnalyzer.getAnalysis().
    async analyzeAudio(): Promise<AudioAnalysisResult> { if (!this._page) throw new Error('Browser not initialized. Run init tool first.'); return await this.analyzer.getAnalysis(this._page); }
  • AudioAnalyzer.getAnalysis() retrieves the browser-side spectrum analysis by calling the injected analyzer.analyze() which performs FFT and computes features.
    async getAnalysis(page: Page): Promise<AudioAnalysisResult> { // Client-side caching with local fallback const now = Date.now(); if (this._analysisCache && (now - this._cacheTimestamp) < this.ANALYSIS_CACHE_TTL) { return this._analysisCache; } const result = await page.evaluate(() => { const analyzer = (window as any).strudelAudioAnalyzer; if (!analyzer) { return { connected: false, error: 'Analyzer not initialized. Audio context may not have started yet.', hint: 'Try playing a pattern first to initialize the audio context.' }; } if (!analyzer.isConnected) { return { connected: false, error: 'Analyzer not connected to audio output.', hint: 'Play a pattern to connect the analyzer to Strudel audio output.' }; } const analysis = analyzer.analyze(); // Add diagnostic info if no audio detected if (analysis.features && analysis.features.isSilent) { analysis.hint = 'Audio analyzer connected but no audio detected. Ensure pattern is playing.'; } return analysis; }); // Update cache this._analysisCache = result; this._cacheTimestamp = now; return result; }
  • Browser-injected analyzer.analyze() function: core FFT spectrum analysis using getByteFrequencyData, computes key spectrum features like average dB, peak freq, spectral centroid, EQ bands.
    analyze() { if (!this.analyser || !this.isConnected) { return { connected: false, error: 'Analyzer not connected' }; } // Cache-based throttling const now = Date.now(); if (this.lastAnalysis && (now - this.lastAnalysisTime) < 50) { return this.lastAnalysis; } this.analyser.getByteFrequencyData(this.dataArray); // Optimized analysis using typed array operations const dataArray = this.dataArray; const length = dataArray.length; // Single-pass computation for better performance let sum = 0; let peak = 0; let peakIndex = 0; let weightedSum = 0; // Frequency band accumulators let bassSum = 0, lowMidSum = 0, midSum = 0, highMidSum = 0, trebleSum = 0; for (let i = 0; i < length; i++) { const value = dataArray[i]; sum += value; weightedSum += i * value; if (value > peak) { peak = value; peakIndex = i; } // Frequency bands (adjusted for 1024 FFT) if (i < 4) bassSum += value; else if (i < 16) lowMidSum += value; else if (i < 64) midSum += value; else if (i < 128) highMidSum += value; else if (i < 256) trebleSum += value; } const average = sum / length; const centroid = sum > 0 ? weightedSum / sum : 0; const peakFreq = (peakIndex / length) * 22050; const bass = bassSum / 4; const lowMid = lowMidSum / 12; const mid = midSum / 48; const highMid = highMidSum / 64; const treble = trebleSum / 128; const result = { connected: true, timestamp: now, features: { average: Math.round(average * 10) / 10, peak, peakFrequency: Math.round(peakFreq), centroid: Math.round(centroid * 10) / 10, bass: Math.round(bass), lowMid: Math.round(lowMid), mid: Math.round(mid), highMid: Math.round(highMid), treble: Math.round(treble), isPlaying: average > 5, isSilent: average < 1, bassToTrebleRatio: treble > 0 ? (bass / treble).toFixed(2) : 'N/A', brightness: centroid > 500 ? 'bright' : centroid > 200 ? 'balanced' : 'dark' } }; // Cache result this.lastAnalysis = result; this.lastAnalysisTime = now; return result; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/williamzujkowski/strudel-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server