generate_drum_groups
Create structured XML for drum kits in DecentSampler. Supports basic and advanced setups, including velocity layers, multi-mic configurations, and UI controls. Validates sample paths and MIDI notes for error-free output.
Instructions
Generate DecentSampler XML for drum kits.
This tool supports two configuration types:
BasicDrumKitConfig:
For simple presets with minimal features
No UI controls, effects, or routing
Only supports basic sample mapping and optional velocity layers
Recommended for straightforward drum kits
AdvancedDrumKitConfig:
For complex setups combining multiple features
Supports UI controls, effects, and routing
Integrates with other tools (configure_drum_controls, configure_mic_routing, etc.)
Use when you need advanced features like round robin or multi-mic setups
Best Practices:
IMPORTANT: Always use absolute paths (e.g., 'C:/Users/username/Documents/Samples/kick.wav')
Group all samples for a drum piece into a single group
When using multiple mic positions, include them all in the same group
Use velocity layers within a group to control dynamics
Error Handling:
Validates all sample paths exist
Checks for valid MIDI note numbers
Ensures velocity layers don't overlap
Verifies muting group configurations
Returns specific errors for any invalid settings
Example Configurations:
Basic Configuration (simple drum kit): { "globalSettings": { "velocityLayers": [ { "low": 1, "high": 42, "name": "soft" }, { "low": 43, "high": 85, "name": "medium" }, { "low": 86, "high": 127, "name": "hard" } ] }, "drumPieces": [{ "name": "Kick", "rootNote": 36, "samples": [ {"path": "C:/Samples/Kick_Soft.wav"}, {"path": "C:/Samples/Kick_Medium.wav"}, {"path": "C:/Samples/Kick_Hard.wav"} ] }] }
Advanced Configuration (multi-mic kit with controls): { "globalSettings": { "velocityLayers": [ { "low": 1, "high": 127, "name": "full" } ], "drumControls": { "kick": { "pitch": { "default": 0, "min": -12, "max": 12 }, "envelope": { "attack": 0.001, "decay": 0.5, "sustain": 0, "release": 0.1 } } }, "micBuses": [ { "name": "Close Mic", "outputTarget": "MAIN_OUTPUT", "volume": { "default": 0, "midiCC": 20 } } ] }, "drumPieces": [{ "name": "Kick", "rootNote": 36, "samples": [ { "path": "C:/Samples/Kick_Close.wav", "micConfig": { "position": "close", "busIndex": 0 } } ], "muting": { "tags": ["kick"], "silencedByTags": [] } }] }
Success Response: Returns complete XML structure with:
Organized sample groups
Velocity layer mappings
Muting group configurations
All sample references and settings
Advanced features when using AdvancedDrumKitConfig
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| drumPieces | Yes | ||
| globalSettings | Yes |
Implementation Reference
- src/index.ts:386-543 (registration)Registration of the generate_drum_groups tool in the MCP ListTools handler, including detailed description and input schema definition.{ name: "generate_drum_groups", description: `Generate DecentSampler <groups> XML for drum kits. This tool supports two configuration types: BasicDrumKitConfig: - For simple presets with minimal features - No UI controls, effects, or routing - Only supports basic sample mapping and optional velocity layers - Recommended for straightforward drum kits AdvancedDrumKitConfig: - For complex setups combining multiple features - Supports UI controls, effects, and routing - Integrates with other tools (configure_drum_controls, configure_mic_routing, etc.) - Use when you need advanced features like round robin or multi-mic setups Best Practices: - IMPORTANT: Always use absolute paths (e.g., 'C:/Users/username/Documents/Samples/kick.wav') - Group all samples for a drum piece into a single group - When using multiple mic positions, include them all in the same group - Use velocity layers within a group to control dynamics Error Handling: - Validates all sample paths exist - Checks for valid MIDI note numbers - Ensures velocity layers don't overlap - Verifies muting group configurations - Returns specific errors for any invalid settings Example Configurations: 1. Basic Configuration (simple drum kit): { "globalSettings": { "velocityLayers": [ { "low": 1, "high": 42, "name": "soft" }, { "low": 43, "high": 85, "name": "medium" }, { "low": 86, "high": 127, "name": "hard" } ] }, "drumPieces": [{ "name": "Kick", "rootNote": 36, "samples": [ {"path": "C:/Samples/Kick_Soft.wav"}, {"path": "C:/Samples/Kick_Medium.wav"}, {"path": "C:/Samples/Kick_Hard.wav"} ] }] } 2. Advanced Configuration (multi-mic kit with controls): { "globalSettings": { "velocityLayers": [ { "low": 1, "high": 127, "name": "full" } ], "drumControls": { "kick": { "pitch": { "default": 0, "min": -12, "max": 12 }, "envelope": { "attack": 0.001, "decay": 0.5, "sustain": 0, "release": 0.1 } } }, "micBuses": [ { "name": "Close Mic", "outputTarget": "MAIN_OUTPUT", "volume": { "default": 0, "midiCC": 20 } } ] }, "drumPieces": [{ "name": "Kick", "rootNote": 36, "samples": [ { "path": "C:/Samples/Kick_Close.wav", "micConfig": { "position": "close", "busIndex": 0 } } ], "muting": { "tags": ["kick"], "silencedByTags": [] } }] } Success Response: Returns complete XML structure with: - Organized sample groups - Velocity layer mappings - Muting group configurations - All sample references and settings - Advanced features when using AdvancedDrumKitConfig`, inputSchema: { type: "object", properties: { globalSettings: { type: "object", properties: { velocityLayers: { type: "array", items: { type: "object", properties: { low: { type: "number" }, high: { type: "number" }, name: { type: "string" } }, required: ["low", "high", "name"] } } }, required: [] }, drumPieces: { type: "array", items: { type: "object", properties: { name: { type: "string" }, rootNote: { type: "number" }, samples: { type: "array", items: { type: "object", properties: { path: { type: "string" }, volume: { type: "string" } }, required: ["path"] } }, muting: { type: "object", properties: { tags: { type: "array", items: { type: "string" } }, silencedByTags: { type: "array", items: { type: "string" } } }, required: ["tags", "silencedByTags"] } }, required: ["name", "rootNote", "samples"] } } }, required: ["globalSettings", "drumPieces"] }
- src/index.ts:676-713 (handler)Handler implementation in CallToolRequestSchema that validates arguments and calls generateGroupsXml to produce the output XML.case "generate_drum_groups": { // Validate input matches our expected type const args = request.params.arguments; if (!args || typeof args !== 'object') { throw new McpError( ErrorCode.InvalidParams, "Invalid arguments: expected object" ); } // Try advanced configuration first if (isAdvancedDrumKitConfig(args)) { const xml = generateGroupsXml(args); return { content: [{ type: "text", text: xml }] }; } // Fall back to basic configuration if (isBasicDrumKitConfig(args)) { const config: BasicDrumKitConfig = args; const xml = generateGroupsXml(config); return { content: [{ type: "text", text: xml }] }; } throw new McpError( ErrorCode.InvalidParams, "Invalid arguments: does not match either BasicDrumKitConfig or AdvancedDrumKitConfig schema" ); }
- src/xml-generation.ts:5-114 (handler)Core handler logic that generates complete <groups> XML structure supporting basic and advanced drum kit features including velocity layers, muting, round-robin, drum controls, and mic routing.export function generateGroupsXml(config: BasicDrumKitConfig | AdvancedDrumKitConfig): string { const { globalSettings, drumPieces } = config; // Generate buses XML if mic routing is configured (advanced only) const busesXml = 'micBuses' in globalSettings && globalSettings.micBuses ? configureMicBuses(globalSettings.micBuses) : ''; // Add round robin attributes to top-level groups if configured const roundRobinAttrs = 'roundRobin' in globalSettings && globalSettings.roundRobin ? ` seqMode="${globalSettings.roundRobin.mode}"${ globalSettings.roundRobin.length ? ` seqLength="${globalSettings.roundRobin.length}"` : '' }` : ''; const groups: string[] = []; for (const piece of drumPieces) { // Combine muting and round robin attributes for group (advanced only) let groupAttrs = 'muting' in piece && piece.muting ? ` tags="${piece.muting.tags.join(',')}" silencedByTags="${piece.muting.silencedByTags.join(',')}" silencingMode="fast"` : ''; // Add group-level round robin settings if present if ('seqMode' in piece && piece.seqMode) { groupAttrs += ` seqMode="${piece.seqMode}"`; } if ('seqLength' in piece && piece.seqLength) { groupAttrs += ` seqLength="${piece.seqLength}"`; } if ('seqPosition' in piece && piece.seqPosition) { groupAttrs += ` seqPosition="${piece.seqPosition}"`; } // Add drum controls if configured (advanced only) const drumControls = 'drumControls' in globalSettings && globalSettings.drumControls?.[piece.name]; let envelopeAttrs = ''; let pitchControl = ''; if (drumControls) { // Add envelope attributes if configured if (drumControls.envelope) { const env = drumControls.envelope; envelopeAttrs = ` attack="${env.attack}" decay="${env.decay}" sustain="${env.sustain}" release="${env.release}"`; if (env.attackCurve !== undefined) envelopeAttrs += ` attackCurve="${env.attackCurve}"`; if (env.decayCurve !== undefined) envelopeAttrs += ` decayCurve="${env.decayCurve}"`; if (env.releaseCurve !== undefined) envelopeAttrs += ` releaseCurve="${env.releaseCurve}"`; } // Add pitch control if configured if (drumControls.pitch) { const pitch = drumControls.pitch; groupAttrs += ` tuning="${pitch.default}"`; pitchControl = ` <control type="pitch" name="${piece.name} Pitch" default="${pitch.default}"` + (pitch.min !== undefined ? ` minimum="${pitch.min}"` : '') + (pitch.max !== undefined ? ` maximum="${pitch.max}"` : '') + `>\n <binding type="general" level="group" position="0" parameter="groupTuning" />\n </control>\n`; } } const sampleElements: string[] = []; for (const sample of piece.samples) { const volumeAttr = sample.volume ? ` volume="${sample.volume}"` : ''; let velocityAttrs = ''; if (globalSettings.velocityLayers) { const layerIndex = piece.samples.indexOf(sample); if (layerIndex < globalSettings.velocityLayers.length) { const layer = globalSettings.velocityLayers[layerIndex]; velocityAttrs = ` loVel="${layer.low}" hiVel="${layer.high}"`; } } // Add sample-level round robin settings let sampleRRAttrs = ''; if ('seqMode' in sample && sample.seqMode) { sampleRRAttrs += ` seqMode="${sample.seqMode}"`; } if ('seqLength' in sample && sample.seqLength) { sampleRRAttrs += ` seqLength="${sample.seqLength}"`; } if ('seqPosition' in sample && sample.seqPosition) { sampleRRAttrs += ` seqPosition="${sample.seqPosition}"`; } // Generate sample element with bus routing if configured (advanced only) const sampleXml = 'micConfig' in sample && sample.micConfig ? generateSampleBusRouting(sample.path, sample.micConfig.busIndex, sample.micConfig.volume) : ` <sample path="${sample.path}"${volumeAttr} rootNote="${piece.rootNote}" ` + `loNote="${piece.rootNote}" hiNote="${piece.rootNote}"${velocityAttrs}${sampleRRAttrs} />`; sampleElements.push(sampleXml); } groups.push( ` <group name="${piece.name}" ampVelTrack="1"${groupAttrs}${envelopeAttrs}>\n` + (pitchControl ? pitchControl : '') + `${sampleElements.join('\n')}\n` + ` </group>` ); } // Combine buses and groups XML const xml = []; if (busesXml) xml.push(busesXml); xml.push(`<groups${roundRobinAttrs}>\n${groups.join('\n\n')}\n</groups>`); return xml.join('\n\n'); }
- src/advanced-drum-kit.ts:25-47 (schema)Type definitions and validator (isAdvancedDrumKitConfig) for advanced drum kit configurations used by the tool.export interface AdvancedDrumPieceConfig { name: string; rootNote: number; seqMode?: RoundRobinMode; seqLength?: number; seqPosition?: number; muting?: MutingConfig; samples: AdvancedSampleConfig[]; } export interface AdvancedDrumKitConfig extends BasicDrumKitConfig { globalSettings: BasicDrumKitConfig["globalSettings"] & { roundRobin?: RoundRobinConfig; drumControls?: { [drumName: string]: { pitch?: DrumPitchConfig; envelope?: DrumEnvelopeConfig; }; }; micBuses?: MicBusConfig[]; }; drumPieces: AdvancedDrumPieceConfig[]; }
- src/basic-drum-kit.ts:3-15 (schema)Type definitions and validator (isBasicDrumKitConfig) for basic drum kit configurations used by the tool.export interface BasicDrumKitConfig { globalSettings: { velocityLayers?: VelocityLayer[]; }; drumPieces: { name: string; rootNote: number; samples: { path: string; volume?: string; }[]; }[]; }