Skip to main content
Glama
williamzujkowski

Strudel MCP Server

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;
    }
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. 'FFT spectrum analysis' implies a read-only analytical operation but does not specify what it returns, any side effects, performance characteristics, or error conditions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise with a single phrase, 'FFT spectrum analysis', which is front-loaded and wastes no words. However, this conciseness comes at the cost of clarity and completeness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity implied by 'spectrum analysis' and the lack of annotations and output schema, the description is incomplete. It fails to explain what the tool returns, how it behaves, or its context among sibling tools, making it inadequate for effective use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters with 100% schema description coverage, so no parameter information is needed. The description does not add parameter details, which is appropriate given the lack of inputs, earning a baseline score of 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose2/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'FFT spectrum analysis' restates the tool name 'analyze_spectrum' in a tautological manner without specifying what it actually does. It lacks a clear verb and resource, failing to distinguish it from sibling tools like 'analyze', 'analyze_rhythm', or 'detect_tempo'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines1/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives. With many sibling tools for analysis and generation, the description offers no context, exclusions, or prerequisites for usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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