🎛️ Modulation Matrix¶
📖 Overview¶
The Modulation Matrix provides flexible N-to-M modulation routing with advanced depth control, polyphonic support, and visualization capabilities.
📂 Components¶
08_03_02_modulation_matrix/
├── include/
│ ├── ModulationRouter.hpp ← N-to-M modulation routing
│ ├── ModulationDepthControl.hpp ← Curve shaping & ranges
│ ├── PolyphonicModulation.hpp ← Per-voice modulation
│ └── ModulationVisualizer.hpp ← UI visualization data
│
└── CMakeLists.txt ← Build configuration
🎯 Quick Start¶
Basic Modulation Routing¶
#include "ModulationRouter.hpp"
ModulationRouter router;
// Register LFO as modulation source
class MyLFO : public ModulationRouter::IModulationSource {
float getValue() const override { return sin(phase); }
void process(uint32_t samples) override { phase += freq * samples; }
float phase = 0.0f;
float freq = 0.01f;
};
MyLFO lfo;
router.registerSource("lfo1", &lfo);
// Create modulation connection
router.addConnection("lfo1", "filter_cutoff");
router.setDepth("lfo1", "filter_cutoff", 0.5f); // 50% depth
router.setBipolar("lfo1", "filter_cutoff", true); // -1 to +1
// Process modulation (audio thread)
router.process(bufferSize);
// Get modulated value
float modAmount = router.getModulatedValue("filter_cutoff");
Advanced Depth Control¶
#include "ModulationDepthControl.hpp"
ModulationDepthControl depthCtrl;
// Configure shaping
depthCtrl.setDepth(0.5f); // 50% depth
depthCtrl.setRange(-12.0f, 12.0f); // ±12 dB
depthCtrl.setCurve(ModulationCurve::Exponential); // Exponential curve
depthCtrl.setInvert(false); // No inversion
// Apply to modulation signal
float rawMod = lfo.getValue(); // [-1, 1]
float shapedMod = depthCtrl.apply(rawMod);
// Result: Exponentially curved, scaled to [-6, 6] dB
// Use in parameter calculation
float baseCutoff = 1000.0f;
float finalCutoff = baseCutoff * pow(2.0f, shapedMod / 12.0f); // Convert dB to ratio
Polyphonic Modulation¶
#include "PolyphonicModulation.hpp"
PolyphonicModulation polyMod(8); // 8 voices
// Note on
int voice = polyMod.allocateVoice(60, 100); // MIDI note 60, velocity 100
// Set per-voice modulation
polyMod.setModulationValue(voice, "filter_cutoff", 0.5f);
polyMod.setModulationValue(voice, "resonance", 0.3f);
// Process all voices
polyMod.process(bufferSize);
// Get modulated value for specific voice
float cutoff = polyMod.getModulatedValue(voice, "filter_cutoff");
// Note off
polyMod.releaseVoice(voice);
Modulation Visualization¶
#include "ModulationVisualizer.hpp"
ModulationVisualizer visualizer;
visualizer.setHistoryLength(100);
// In audio callback
visualizer.capture(router);
// In UI update (30-60 Hz)
auto connections = visualizer.getConnectionData();
for (const auto& conn : connections) {
// Draw connection line
drawLine(conn.sourceId, conn.targetId, conn.active);
// Draw activity meter
drawMeter(conn.peakValue);
// Draw current value
drawValue(conn.currentValue);
}
// Get waveform trace
auto history = visualizer.getHistory("lfo1", "filter_cutoff");
drawWaveform(history);
// Reset peaks
visualizer.resetPeaks();
🏗️ Architecture¶
ModulationRouter¶
N-to-M routing with per-connection control.
[LFO 1] ───┬──→ Filter Cutoff (50% depth)
└──→ Resonance (30% depth)
[LFO 2] ───┬──→ Filter Cutoff (20% depth)
└──→ Pitch (10% depth)
[Envelope] ───→ Filter Cutoff (80% depth)
Features: - N sources → M targets - Per-connection depth - Bipolar/unipolar modes - Smooth depth interpolation - Enable/disable per connection
ModulationDepthControl¶
Curve shaping and range control.
Curve Types: - Linear: No shaping - Exponential: Slow start, fast end - Logarithmic: Fast start, slow end - S-Curve: Smooth acceleration/deceleration - Parabolic: Symmetrical around center
Range Mapping:
// Map LFO [-1, 1] to frequency range [100 Hz, 10 kHz]
depthCtrl.setRange(100.0f, 10000.0f);
depthCtrl.setCurve(ModulationCurve::Exponential);
PolyphonicModulation¶
Per-voice modulation for synthesizers.
Voice 0 (Note 60):
Envelope → Cutoff (1.0)
LFO → Cutoff (0.5)
Voice 1 (Note 64):
Envelope → Cutoff (1.0)
LFO → Cutoff (0.5)
Voice 2 (Note 67):
Envelope → Cutoff (1.0)
LFO → Cutoff (0.5)
Features: - Voice allocation with stealing - Per-voice mod values - MIDI note/velocity tracking - Voice age tracking
ModulationVisualizer¶
UI visualization data generator.
Data Types: - Connection diagrams (source → target) - Activity meters (current, peak, average) - Historical traces (waveform display) - Matrix view (sources × targets grid)
🎮 Usage Patterns¶
LFO to Multiple Parameters¶
router.addConnection("lfo1", "filter_cutoff");
router.setDepth("lfo1", "filter_cutoff", 0.8f);
router.addConnection("lfo1", "resonance");
router.setDepth("lfo1", "resonance", 0.3f);
router.addConnection("lfo1", "pan");
router.setDepth("lfo1", "pan", 0.5f);
router.setBipolar("lfo1", "pan", true); // Pan needs bipolar
Multiple Sources to One Parameter¶
// LFO
router.addConnection("lfo1", "filter_cutoff");
router.setDepth("lfo1", "filter_cutoff", 0.3f);
// Envelope
router.addConnection("env1", "filter_cutoff");
router.setDepth("env1", "filter_cutoff", 0.7f);
// Mod wheel
router.addConnection("modwheel", "filter_cutoff");
router.setDepth("modwheel", "filter_cutoff", 0.5f);
// All three modulate cutoff simultaneously (additive)
Polyphonic Synth Example¶
PolyphonicModulation polyMod(16); // 16 voices
PolyphonicDepthControl depthCtrl(16);
// Configure depth per voice (slight variation)
for (int v = 0; v < 16; ++v) {
float variation = 1.0f + (v * 0.02f); // ±2% per voice
depthCtrl.setDepth(v, 0.8f * variation);
depthCtrl.setCurve(v, ModulationCurve::Exponential);
}
// MIDI note on
int voice = polyMod.allocateVoice(note, velocity);
// Apply envelope to cutoff
float envValue = envelope.process();
float shapedEnv = depthCtrl.apply(voice, envValue);
polyMod.setModulationValue(voice, "cutoff", shapedEnv);
⚡ Performance¶
| Operation | Complexity | Typical Time |
|---|---|---|
router.process() |
O(n) | ~100ns per connection |
getModulatedValue() |
O(1) | ~20ns |
depthCtrl.apply() |
O(1) | ~30ns |
visualizer.capture() |
O(n) | ~500ns per 10 connections |
polyMod.allocateVoice() |
O(v) | ~200ns per 8 voices |
🔗 Dependencies¶
- 08_00 - Plugin Infrastructure
- 08_02 - DSP Integration Layer (ModulationMatrix)
- 08_03_00 - Aggregation System
📚 Related¶
- 08_03_00_aggregation_system - Parameter organization
- 08_03_01_l5_hierarchy - L5 hierarchy
- 08_02_02_modulation_system - DSP modulation
Status: ✅ Complete Version: 1.0.0 Last Updated: 2025-10-09