create_harmonics
Generate harmonic variations for audio files by adding octaves and musical intervals to create richer sound textures.
Instructions
Create harmonic variations by adding octaves and musical intervals
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| inputFile | Yes | Path to input audio file | |
| outputDirectory | Yes | Directory for harmonic variations | |
| octaveUp | No | Mix level for octave up (0-1) | |
| octaveDown | No | Mix level for octave down (0-1) | |
| fifthUp | No | Mix level for perfect fifth up (0-1) | |
| thirdUp | No | Mix level for major third up (0-1) | |
| overwrite | No | Whether to overwrite existing output files |
Implementation Reference
- src/tools/index.ts:263-313 (schema)Tool definition including name, description, and input schema for validating parameters like inputFile, outputDirectory, and harmonic mix levels.
export const createHarmonicsTool: Tool = { name: 'create_harmonics', description: 'Create harmonic variations by adding octaves and musical intervals', inputSchema: { type: 'object', properties: { inputFile: { type: 'string', description: 'Path to input audio file' }, outputDirectory: { type: 'string', description: 'Directory for harmonic variations' }, octaveUp: { type: 'number', description: 'Mix level for octave up (0-1)', minimum: 0, maximum: 1, optional: true }, octaveDown: { type: 'number', description: 'Mix level for octave down (0-1)', minimum: 0, maximum: 1, optional: true }, fifthUp: { type: 'number', description: 'Mix level for perfect fifth up (0-1)', minimum: 0, maximum: 1, optional: true }, thirdUp: { type: 'number', description: 'Mix level for major third up (0-1)', minimum: 0, maximum: 1, optional: true }, overwrite: { type: 'boolean', description: 'Whether to overwrite existing output files', default: false } }, required: ['inputFile', 'outputDirectory'] } }; - src/tools/index.ts:625-653 (handler)MCP tool handler that parses arguments, constructs harmonics config, calls AdvancedAudioProcessor.createHarmonicVariations, and returns formatted results.
case 'create_harmonics': { const input = args as any; const harmonics = { octaveUp: input.octaveUp, octaveDown: input.octaveDown, fifthUp: input.fifthUp, thirdUp: input.thirdUp }; const results = await advancedProcessor.createHarmonicVariations( input.inputFile, input.outputDirectory, harmonics, input.overwrite || false ); return { content: [ { type: 'text', text: JSON.stringify({ success: true, harmonicsCreated: results.length, results: results }, null, 2) } ] }; } - Core implementation generating harmonic files by pitch-shifting input and layering original with shifted version at specified mix levels using FFmpeg operations.
async createHarmonicVariations( inputFile: string, outputDirectory: string, harmonics: HarmonicsOperation, overwrite: boolean = false ): Promise<ProcessingResult[]> { const results: ProcessingResult[] = []; const baseName = path.parse(inputFile).name; const harmonicIntervals = [ { name: 'octave_up', semitones: 12, mix: harmonics.octaveUp }, { name: 'octave_down', semitones: -12, mix: harmonics.octaveDown }, { name: 'fifth_up', semitones: 7, mix: harmonics.fifthUp }, { name: 'third_up', semitones: 4, mix: harmonics.thirdUp } ]; for (const interval of harmonicIntervals) { if (interval.mix && interval.mix > 0) { const outputFile = path.join(outputDirectory, `${baseName}_${interval.name}${path.extname(inputFile)}` ); const operations: AudioOperations = { advanced: { pitch: { semitones: interval.semitones }, layering: { layers: [ { blend: 'mix', volume: 1 - interval.mix }, { blend: 'add', volume: interval.mix, pitch: interval.semitones } ] } } }; const result = await this.processAudioFile( inputFile, outputFile, operations, overwrite ); results.push(result); } } return results; } - src/tools/index.ts:732-742 (registration)Exports array of all tools including createHarmonicsTool for server registration.
export const tools = [ processAudioFileTool, batchProcessAudioTool, applyPresetTool, listPresetsTool, getQueueStatusTool, generateVariationsTool, createHarmonicsTool, advancedProcessTool, layerSoundsTool ]; - src/tools/index.ts:456-730 (registration)Registers the central tool request handler with switch statement covering create_harmonics case.
export function registerTools(server: Server): void { // Register process_audio_file tool server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'process_audio_file': { try { const input = ProcessAudioFileInputSchema.parse(args); const result = await audioProcessor.processAudioFile( input.inputFile, input.outputFile, input.operations, (args as any).overwrite || false ); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] }; } catch (validationError) { // If validation fails, try with the advanced processor const result = await advancedProcessor.processAudioFile( (args as any).inputFile, (args as any).outputFile, (args as any).operations, (args as any).overwrite || false ); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] }; } } case 'batch_process_audio': { try { const input = BatchProcessAudioInputSchema.parse(args); const result = await audioProcessor.batchProcessAudio( { directory: input.inputDirectory, pattern: input.filePattern }, { directory: input.outputDirectory }, input.operations, (args as any).overwrite || false ); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] }; } catch (validationError) { // If validation fails, try with the advanced processor const result = await advancedProcessor.batchProcessAudio( { directory: (args as any).inputDirectory, pattern: (args as any).filePattern }, { directory: (args as any).outputDirectory }, (args as any).operations, (args as any).overwrite || false ); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] }; } } case 'apply_preset': { const input = ApplyPresetInputSchema.parse(args); const preset = getPreset(input.preset); const result = await audioProcessor.processAudioFile( input.inputFile, input.outputFile, preset.operations, (args as any).overwrite || false ); return { content: [ { type: 'text', text: JSON.stringify({ ...result, presetUsed: preset.name, presetDescription: preset.description }, null, 2) } ] }; } case 'list_presets': { const { listPresets, getPresetsByCategory } = await import('../utils/presets.js'); const category = (args as any)?.category; const presets = category ? getPresetsByCategory(category) : listPresets(); return { content: [ { type: 'text', text: JSON.stringify(presets, null, 2) } ] }; } case 'get_queue_status': { const status = audioProcessor.getQueueStatus(); return { content: [ { type: 'text', text: JSON.stringify(status, null, 2) } ] }; } case 'generate_variations': { const input = args as any; const variations = { count: input.count || 5, pitchRange: input.pitchRange || 2, volumeRange: input.volumeRange || 3, spectralRange: input.spectralRange || 2, seed: input.seed }; const results = await advancedProcessor.generateVariations( input.inputFile, input.outputDirectory, variations, undefined, input.overwrite || false ); return { content: [ { type: 'text', text: JSON.stringify({ success: true, variationsGenerated: results.length, results: results }, null, 2) } ] }; } case 'create_harmonics': { const input = args as any; const harmonics = { octaveUp: input.octaveUp, octaveDown: input.octaveDown, fifthUp: input.fifthUp, thirdUp: input.thirdUp }; const results = await advancedProcessor.createHarmonicVariations( input.inputFile, input.outputDirectory, harmonics, input.overwrite || false ); return { content: [ { type: 'text', text: JSON.stringify({ success: true, harmonicsCreated: results.length, results: results }, null, 2) } ] }; } case 'advanced_process': { const input = args as any; const operations = { advanced: { pitch: input.pitch, tempo: input.tempo, spectral: input.spectral, dynamics: input.dynamics, spatial: input.spatial } }; const result = await advancedProcessor.processAudioFile( input.inputFile, input.outputFile, operations, input.overwrite || false ); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] }; } case 'layer_sounds': { const input = args as any; const layering = { layers: input.layers }; const result = await advancedProcessor.layerSounds( input.inputFiles, input.outputFile, layering, input.overwrite || false ); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { logger.error(`Tool execution failed: ${(error as Error).message}`); return { content: [ { type: 'text', text: JSON.stringify({ error: { code: 'TOOL_EXECUTION_FAILED', message: (error as Error).message, tool: name } }, null, 2) } ], isError: true }; } }); }