Skip to main content
Glama
BradA1878
by BradA1878

sc_play_synth

Generate synthesized audio from natural language descriptions. Create sounds like bells, bass tones, or plucked strings by describing them in English.

Instructions

Play a synthesized sound based on a natural language description. This is the primary tool for sound synthesis. Examples: "play a bell sound at C4", "play a low bass tone for 2 seconds", "play a plucked string sound"

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
descriptionYesNatural language description of the sound to create (e.g., "bell at C5", "deep bass", "short snare")

Implementation Reference

  • Main execution logic for the sc_play_synth tool: parses natural language input, generates and executes inline SuperCollider synthesis code for various sound types.
    case 'sc_play_synth': {
      const schema = z.object({ description: z.string() });
      const { description } = schema.parse(args);
    
      if (!scServer.getBooted() || !synthDefsLoaded) {
        return {
          content: [{ type: 'text', text: 'Error: SuperCollider server is not running. Call sc_boot first.' }],
          isError: true,
        };
      }
    
      const { synthName, params } = parseSynthDescription(description);
    
      // Use inline function syntax for simple sounds
      let code = '';
    
      if (synthName === 'bell') {
        code = `{ var sig = SinOsc.ar(${params.freq} + SinOsc.ar(${params.freq! * 2.4}, 0, ${params.freq! * 0.8}), 0, ${params.amp}) * EnvGen.kr(Env.perc(0.01, ${params.duration}, 1, -4), doneAction: 2); Pan2.ar(sig, ${params.pan}) }.play;`;
      } else if (synthName === 'kick') {
        code = `{ var sig = SinOsc.ar(EnvGen.kr(Env.perc(0.001, 0.3), 1, 60, 50), 0, ${params.amp}) * EnvGen.kr(Env.perc(0.001, 0.5), doneAction: 2); Pan2.ar(sig, ${params.pan || 0}) }.play;`;
      } else if (synthName === 'snare') {
        code = `{ var sig = (WhiteNoise.ar(${params.amp}) + SinOsc.ar(180, 0, ${params.amp})) * EnvGen.kr(Env.perc(0.001, 0.2), doneAction: 2); Pan2.ar(sig, ${params.pan || 0}) }.play;`;
      } else if (synthName === 'hihat') {
        code = `{ var sig = HPF.ar(WhiteNoise.ar(${params.amp}), 8000) * EnvGen.kr(Env.perc(0.001, 0.1), doneAction: 2); Pan2.ar(sig, ${params.pan || 0}) }.play;`;
      } else {
        // Default to simple sine wave
        code = `{ SinOsc.ar(${params.freq}, 0, ${params.amp}) * EnvGen.kr(Env.perc(0.01, ${params.duration}), doneAction: 2) }.play;`;
      }
    
      await scServer.executeCode(code);
    
      return {
        content: [
          {
            type: 'text',
            text: `Playing ${synthName} synth: ${JSON.stringify(params)}`,
          },
        ],
      };
    }
  • src/index.ts:82-94 (registration)
    Tool registration in the tools list, including name, description, and input schema.
    {
      name: 'sc_play_synth',
      description: 'Play a synthesized sound based on a natural language description. This is the primary tool for sound synthesis. Examples: "play a bell sound at C4", "play a low bass tone for 2 seconds", "play a plucked string sound"',
      inputSchema: {
        type: 'object',
        properties: {
          description: {
            type: 'string',
            description: 'Natural language description of the sound to create (e.g., "bell at C5", "deep bass", "short snare")',
          },
        },
        required: ['description'],
      },
  • JSON schema defining the input parameters for the sc_play_synth tool.
    inputSchema: {
      type: 'object',
      properties: {
        description: {
          type: 'string',
          description: 'Natural language description of the sound to create (e.g., "bell at C5", "deep bass", "short snare")',
        },
      },
      required: ['description'],
    },
  • Helper function parseSynthDescription that interprets the natural language description to select synth type and extract parameters like frequency, duration, amplitude, etc.
    export function parseSynthDescription(description: string): {
      synthName: string;
      params: SynthParams;
    } {
      const lowerDesc = description.toLowerCase();
    
      // Default params
      const params: SynthParams = {
        freq: 440,
        amp: 0.3,
        duration: 1,
        pan: 0,
      };
    
      // Determine synth type
      let synthName = 'sine';
    
      if (lowerDesc.includes('bell') || lowerDesc.includes('chime')) {
        synthName = 'bell';
      } else if (lowerDesc.includes('pluck') || lowerDesc.includes('guitar') || lowerDesc.includes('string')) {
        synthName = 'pluck';
        params.decay = 2;
      } else if (lowerDesc.includes('bass') || lowerDesc.includes('low')) {
        synthName = 'bass';
        params.freq = 110;
        params.cutoff = 800;
      } else if (lowerDesc.includes('pad') || lowerDesc.includes('ambient') || lowerDesc.includes('warm')) {
        synthName = 'pad';
        params.freq = 220;
        params.cutoff = 2000;
      } else if (lowerDesc.includes('kick') || lowerDesc.includes('drum')) {
        synthName = 'kick';
      } else if (lowerDesc.includes('snare')) {
        synthName = 'snare';
      } else if (lowerDesc.includes('hihat') || lowerDesc.includes('hi-hat')) {
        synthName = 'hihat';
      } else if (lowerDesc.includes('atmosphere') || lowerDesc.includes('noise') || lowerDesc.includes('wind')) {
        synthName = 'atmosphere';
      } else if (lowerDesc.includes('sweep') || lowerDesc.includes('riser') || lowerDesc.includes('swell')) {
        synthName = 'sweep';
      }
    
      // Parse frequency/pitch
      const noteMatch = lowerDesc.match(/\b([a-g]#?)\s*(\d+)\b/i);
      if (noteMatch) {
        const note = noteMatch[1];
        const octave = parseInt(noteMatch[2]);
        params.freq = noteToFreq(note, octave);
      } else {
        // Look for frequency in Hz
        const freqMatch = lowerDesc.match(/(\d+)\s*hz/i);
        if (freqMatch) {
          params.freq = parseInt(freqMatch[1]);
        }
      }
    
      // Parse descriptive pitch terms
      if (lowerDesc.includes('high') || lowerDesc.includes('bright')) {
        params.freq = (params.freq || 440) * 2;
      } else if (lowerDesc.includes('low') || lowerDesc.includes('deep')) {
        params.freq = (params.freq || 440) / 2;
      }
    
      // Parse duration
      const durMatch = lowerDesc.match(/(\d+(?:\.\d+)?)\s*(?:second|sec|s)\b/i);
      if (durMatch) {
        params.duration = parseFloat(durMatch[1]);
      } else if (lowerDesc.includes('short')) {
        params.duration = 0.3;
      } else if (lowerDesc.includes('long')) {
        params.duration = 3;
      }
    
      // Parse amplitude/volume
      if (lowerDesc.includes('loud') || lowerDesc.includes('forte')) {
        params.amp = 0.6;
      } else if (lowerDesc.includes('quiet') || lowerDesc.includes('soft') || lowerDesc.includes('piano')) {
        params.amp = 0.15;
      }
    
      // Parse panning
      if (lowerDesc.includes('left')) {
        params.pan = -0.7;
      } else if (lowerDesc.includes('right')) {
        params.pan = 0.7;
      }
    
      return { synthName, params };
    }

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/BradA1878/mcp-wave'

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