AudioLab Preset System: Morphing Engine¶
Overview¶
The Morphing Engine provides smooth interpolation between presets, enabling seamless transitions, creative sound design, and dynamic preset evolution. It supports multiple interpolation strategies and real-time morphing control.
Features¶
Core Capabilities¶
- ✅ Parameter Interpolation - Smooth transitions between parameter values
- ✅ Multiple Strategies - Linear, exponential, S-curve, cubic spline interpolation
- ✅ Type-Aware Morphing - Intelligent handling of different parameter types
- ✅ Multi-Preset Paths - Morph through sequences of multiple presets
- ✅ Real-Time Control - Dynamic morphing with position control
- ✅ Easing Functions - Professional animation curves (ease-in, ease-out, etc.)
Advanced Features¶
- ✅ Weighted Morphing - Blend multiple presets with custom weights
- ✅ Selective Morphing - Control which parameters participate
- ✅ Crossfade Curves - Audio-quality crossfading for smooth transitions
- ✅ Automation Support - Time-based morphing automation
- ✅ Morphing Presets - Save morphing configurations
- ✅ Undo/Redo Support - Full history tracking
Architecture¶
┌─────────────────────────────────────────────────────────────┐
│ Morphing Engine │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ ParameterMorpher │◄─────┤ MorphingStrategy │ │
│ └────────┬─────────┘ └──────────────────┘ │
│ │ │ │
│ │ Strategies: │
│ │ • Linear │
│ │ • Exponential │
│ │ • SCurve │
│ │ • CubicSpline │
│ │ • CustomEasing │
│ │ │
│ │ │
│ ┌────────▼─────────┐ ┌──────────────────┐ │
│ │ PresetMorpher │◄─────┤ MorphingPath │ │
│ └────────┬─────────┘ └──────────────────┘ │
│ │ │
│ │ │
│ ┌────────▼─────────┐ ┌──────────────────┐ │
│ │ MorphingController│◄────┤ MorphingPreset │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Components¶
1. ParameterMorpher¶
Purpose: Interpolates individual parameter values with type awareness.
Features: - Float interpolation (linear, exponential, logarithmic) - Integer interpolation (round, floor, ceil strategies) - Boolean interpolation (threshold-based) - Enum interpolation (nearest or weighted blend) - String interpolation (discrete switch at threshold) - Range clamping and validation
Example:
ParameterMorpher morpher;
// Float interpolation
float result = morpher.morphFloat(
1.0f, // From value
10.0f, // To value
0.5f, // Position (0-1)
InterpolationType::Linear
);
// result = 5.5f
// Exponential curve
float exp_result = morpher.morphFloat(
1.0f, 10.0f, 0.5f,
InterpolationType::Exponential
);
// result ≈ 3.16f (square root behavior)
2. MorphingStrategy¶
Purpose: Defines how parameter values transition over time.
Built-in Strategies:
- Linear
- Constant rate interpolation
- f(t) = a + (b - a) * t
-
Best for: Simple, predictable transitions
-
Exponential
- Exponential curve interpolation
- f(t) = a * (b/a)^t
-
Best for: Frequency, gain, time-based parameters
-
SCurve (Sigmoid)
- S-shaped transition curve
- f(t) = a + (b - a) * (3t² - 2t³)
-
Best for: Smooth, natural-feeling transitions
-
CubicSpline
- Cubic Hermite spline interpolation
- Smooth first derivative
-
Best for: Multi-point paths, complex curves
-
CustomEasing
- User-defined easing functions
- Supports common animation curves
- Best for: UI animations, artistic control
Easing Functions: - Ease-In (Quadratic, Cubic, Quartic, Quintic) - Ease-Out (Quadratic, Cubic, Quartic, Quintic) - Ease-In-Out (Quadratic, Cubic, Quartic, Quintic) - Bounce, Elastic, Back, Circ
3. PresetMorpher¶
Purpose: Main morphing engine that interpolates entire presets.
Capabilities: - Two-preset morphing - Multi-preset morphing (weighted blend) - Selective parameter morphing (include/exclude lists) - Metadata preservation - Resource handling - Version compatibility checking
Example:
PresetMorpher morpher;
// Simple two-preset morph
PresetSchema result = morpher.morph(
preset_a, // Source preset
preset_b, // Target preset
0.5f, // Position (50% blend)
InterpolationType::SCurve
);
// Multi-preset weighted morph
std::vector<PresetSchema> presets = {preset_a, preset_b, preset_c};
std::vector<float> weights = {0.5f, 0.3f, 0.2f};
PresetSchema blended = morpher.morphWeighted(presets, weights);
4. MorphingPath¶
Purpose: Defines multi-stage morphing sequences.
Features: - Sequence of presets with positions - Automatic position calculation - Custom segment timing - Path validation - Looping support
Example:
MorphingPath path;
// Add presets to path
path.addPreset(preset_bass, 0.0f); // Start
path.addPreset(preset_lead, 0.5f); // Midpoint
path.addPreset(preset_pad, 1.0f); // End
// Morph along path
PresetSchema result = path.morphAt(0.25f); // 25% = halfway between bass and lead
5. MorphingController¶
Purpose: Real-time morphing control with automation.
Features: - Position control (0.0 - 1.0) - Speed control - Direction control (forward/reverse) - Time-based automation - Trigger-based morphing - Preset recall during morph
Example:
MorphingController controller(preset_a, preset_b);
// Real-time control
controller.setPosition(0.0f); // Start at preset A
controller.setSpeed(0.1f); // 10% per second
controller.setDirection(Direction::Forward);
// Update in audio callback
while (processing) {
controller.update(delta_time);
PresetSchema current = controller.getCurrentPreset();
// Apply current to audio engine
}
Interpolation Types¶
Parameter Type Handling¶
| Parameter Type | Default Strategy | Options |
|---|---|---|
| Float | Linear | Linear, Exponential, SCurve, Spline |
| Integer | Round | Round, Floor, Ceil, Nearest |
| Boolean | Threshold | Threshold (0.5 default) |
| Enum | Nearest | Nearest, Weighted |
| String | Switch | Discrete switch at threshold |
| Array | Element-wise | Per-element interpolation |
Interpolation Curves¶
Linear:
Exponential:
S-Curve:
Use Cases¶
1. Seamless Preset Transitions¶
// Crossfade between two presets over 2 seconds
MorphingController controller(current_preset, next_preset);
controller.setDuration(2.0f);
controller.start();
// In audio callback:
controller.update(delta_time);
applyPreset(controller.getCurrentPreset());
2. Performance Control¶
// Map MIDI CC to morphing position
void onMidiCC(int cc, int value) {
if (cc == 1) { // Mod wheel
float position = value / 127.0f;
controller.setPosition(position);
}
}
3. Sound Design Exploration¶
// Create variations by morphing with random targets
PresetSchema base = loadPreset("bass_001");
PresetSchema random_variation = morpher.morphRandom(
base,
0.2f, // 20% randomization
{"cutoff", "resonance"} // Only morph these params
);
4. Automation Sequences¶
// Create evolving pad that morphs through 4 presets
MorphingPath path;
path.addPreset(dark_pad, 0.0f);
path.addPreset(bright_pad, 0.25f);
path.addPreset(warm_pad, 0.5f);
path.addPreset(cold_pad, 0.75f);
path.setLooping(true);
// Automate position over time
controller.setPath(path);
controller.setSpeed(0.05f); // Complete cycle every 20 seconds
API Reference¶
ParameterMorpher¶
class ParameterMorpher {
public:
// Float interpolation
float morphFloat(float from, float to, float position,
InterpolationType type = InterpolationType::Linear);
// Integer interpolation
int morphInt(int from, int to, float position,
IntegerMorphMode mode = IntegerMorphMode::Round);
// Boolean interpolation
bool morphBool(bool from, bool to, float position,
float threshold = 0.5f);
// Custom easing
float applyEasing(float position, EasingFunction easing);
};
PresetMorpher¶
class PresetMorpher {
public:
// Two-preset morph
PresetSchema morph(const PresetSchema& from,
const PresetSchema& to,
float position,
InterpolationType type = InterpolationType::Linear);
// Weighted multi-preset morph
PresetSchema morphWeighted(const std::vector<PresetSchema>& presets,
const std::vector<float>& weights);
// Selective morphing
PresetSchema morphSelective(const PresetSchema& from,
const PresetSchema& to,
float position,
const std::vector<std::string>& include_params);
// Configuration
void setInterpolationType(InterpolationType type);
void setExcludeParameters(const std::vector<std::string>& params);
};
MorphingPath¶
class MorphingPath {
public:
// Path construction
void addPreset(const PresetSchema& preset, float position);
void insertPreset(const PresetSchema& preset, float position, size_t index);
void removePreset(size_t index);
void clear();
// Morphing
PresetSchema morphAt(float position) const;
// Configuration
void setLooping(bool loop);
void setInterpolationType(InterpolationType type);
// Query
size_t getPresetCount() const;
float getLength() const;
};
MorphingController¶
class MorphingController {
public:
// Construction
MorphingController(const PresetSchema& from, const PresetSchema& to);
// Control
void setPosition(float position);
void setSpeed(float speed);
void setDirection(Direction direction);
void start();
void stop();
void reset();
// Update
void update(float delta_time);
// Query
PresetSchema getCurrentPreset() const;
float getPosition() const;
bool isActive() const;
};
Performance Characteristics¶
| Operation | Time Complexity | Notes |
|---|---|---|
| Two-preset morph | O(n) | n = number of parameters |
| Weighted morph (k presets) | O(k*n) | Linear in presets and params |
| Path morph | O(log k + n) | Binary search + interpolation |
| Position update | O(1) | Controller state update |
| Easing function | O(1) | Mathematical function |
Memory Usage: - ParameterMorpher: ~64 bytes - PresetMorpher: ~256 bytes + config - MorphingPath: ~128 bytes + (k * preset_size) - MorphingController: ~512 bytes + current preset
Real-Time Safety: - ✅ Lock-free parameter interpolation - ✅ No memory allocation in audio thread - ✅ Deterministic execution time - ⚠️ Path/preset changes require synchronization
Best Practices¶
1. Choose Appropriate Interpolation¶
// Frequency: Use exponential
morpher.morphFloat(100.0f, 10000.0f, pos, InterpolationType::Exponential);
// Volume/Gain: Use exponential or dB-linear
float db_morph = morpher.morphFloat(-60.0f, 0.0f, pos, InterpolationType::Linear);
float linear_gain = std::pow(10.0f, db_morph / 20.0f);
// Time/Delay: Use linear or exponential
morpher.morphFloat(0.001f, 1.0f, pos, InterpolationType::Exponential);
// Mix/Blend: Use S-curve for smooth transitions
morpher.morphFloat(0.0f, 1.0f, pos, InterpolationType::SCurve);
2. Handle Incompatible Presets¶
// Check compatibility before morphing
if (!morpher.areCompatible(preset_a, preset_b)) {
// Handle gracefully: skip, use default, or log warning
return preset_a; // Fallback
}
PresetSchema result = morpher.morph(preset_a, preset_b, position);
3. Optimize for Real-Time¶
// Pre-calculate morphing path
MorphingPath path = buildPath(presets);
// In audio callback: only update position
void audioCallback(float delta_time) {
controller.update(delta_time);
preset = controller.getCurrentPreset(); // Fast lookup
// No heavy computation here
}
4. Smooth Automation¶
// Use S-curve for natural-feeling automation
controller.setEasing(EasingFunction::EaseInOutCubic);
controller.setDuration(5.0f);
controller.start();
// Avoid jarring transitions
controller.setSmoothing(true, 0.1f); // 100ms smoothing
Integration¶
With Preset Browser¶
// Morph between search results
auto results = browser.search("bass");
PresetSchema morphed = morpher.morph(results[0], results[1], 0.5f);
With Validation System¶
// Validate morphed preset
PresetSchema morphed = morpher.morph(preset_a, preset_b, position);
ValidationReport report = validator.validate(morphed);
if (report.isValid()) {
applyPreset(morphed);
}
With Version Management¶
// Morph between different versions
PresetSchema v1 = loadPreset("sound_v1.json");
PresetSchema v2 = versionManager.migrate(v1, {2, 0, 0});
PresetSchema blend = morpher.morph(v1, v2, 0.5f);
Testing¶
Run tests:
Run examples:
./build/examples/morph_example
./build/examples/morphing_path_example
./build/examples/real_time_morph_example
Future Enhancements¶
- GPU-accelerated morphing for complex presets
- Machine learning-guided parameter mapping
- Spectral morphing for audio-based interpolation
- Morphing presets marketplace (cloud integration)
- Visual morphing editor (GUI)
- MIDI learn for morphing control
- Morphing automation recording/playback
Dependencies¶
- audiolab_preset_schemas - Preset data structures
- nlohmann/json - JSON serialization
- Catch2 (testing) - Unit test framework
License¶
Part of the AudioLab Preset System.