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
TableJSON 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 }; } }); }