Custom Fader
This tutorial walks you through creating a custom fader for the Amplitude engine. You will build a Bounce Fader — a fade curve that overshoots the target and settles back, like a bouncing ball — and learn how to register it so sound objects and buses can use it for smooth transitions.
Architecture Overview¶
In Amplitude, a Fader defines a transition curve used to move a value (such as volume or gain) from one point to another over time. To create a custom fader, you need two classes:
- Fader — Defines the fader name and the control points of its transition curve.
- FaderInstance — Holds the runtime state and evaluates the curve at a given time.
classDiagram
class Fader {
+CreateInstance() shared_ptr~FaderInstance~
+GetControlPoints() BezierCurveControlPoints
}
class FaderInstance {
+Set(from, to, duration)
+Start(time)
+GetFromTime(time) AmReal64
+GetFromPercentage(t) AmReal64
}
Fader --> FaderInstance : creates Amplitude uses a fast one-dimensional cubic Bézier curve evaluator for all faders. The curve's first and last control points are fixed at (0, 0) and (1, 1). You only need to define the two middle control points to shape the curve.
Step 1: Define the Fader Classes¶
Create a header file for your custom fader:
// BounceFader.h
#pragma once
#include <SparkyStudios/Audio/Amplitude/Amplitude.h>
using namespace SparkyStudios::Audio::Amplitude;
// Control points for a bounce curve:
// The curve shoots past the target (y > 1) at around 40% progress,
// then settles back to 1.0 at 100%.
constexpr BezierCurveControlPoints gBounceFaderCurveControlPoints = {
0.30f, 1.20f, // First control point: overshoots to 120% at 30% time
0.65f, 0.90f // Second control point: dips to 90% at 65% time
};
class BounceFaderInstance final : public FaderInstance
{
public:
BounceFaderInstance()
{
// Initialize the transition curve with our custom control points
m_curve = Transition(gBounceFaderCurveControlPoints);
}
};
class BounceFader final : public Fader
{
public:
BounceFader()
: Fader("Bounce")
{}
std::shared_ptr<FaderInstance> CreateInstance() override
{
return ampoolshared(eMemoryPoolKind_Engine, BounceFaderInstance);
}
[[nodiscard]] BezierCurveControlPoints GetControlPoints() const override
{
return gBounceFaderCurveControlPoints;
}
};
Step 2: Register the Fader¶
Before initializing the engine, register your fader:
#include "BounceFader.h"
int main(int argc, char* argv[])
{
// ... initialize memory manager, file system, etc.
// Register the custom fader
Fader::Register(std::make_shared<BounceFader>());
// Now initialize the engine
amEngine->Initialize(AM_OS_STRING("pc.config.amconfig"));
}
Registration order
Faders must be registered before amEngine->Initialize() is called. Once the engine is initialized, the fader registry is locked.
Step 3: Use the Fader in a Project Asset¶
Create a sound object or bus asset that references your custom fader:
Or assign it to a bus for ducking transitions:
{
"id": 1,
"name": "master",
"gain": 1.0,
"child_buses": [
{
"id": 2,
"name": "sfx",
"gain": 1.0,
"duck_buses": [
{
"target_bus": "voices",
"target_gain": 0.3,
"fade_in": {
"duration": 200,
"fader": "Bounce"
},
"fade_out": {
"duration": 500,
"fader": "Bounce"
}
}
]
}
]
}
When the engine applies the fader, it will use your custom bounce curve instead of a linear or ease transition.
Understanding Bézier Curves¶
Amplitude faders are powered by cubic Bézier curves with fixed endpoints:
(0, 0) ← fixed start
╲
╲ P1 = (x1, y1) ← your first control point
╲
╲
╲ P2 = (x2, y2) ← your second control point
╲
● (1, 1) ← fixed end
The y coordinate of each control point determines the output value at that point in time. Values greater than 1.0 cause overshoot; values less than 1.0 cause undershoot.
Built-in Fader Curves¶
Amplitude ships with several built-in faders. You can use their control points as a reference:
| Fader | Control Points (x1, y1, x2, y2) | Description |
|---|---|---|
| Constant | (0, 0, 0, 0) | No transition; instant change. |
| Linear | (0, 0, 1, 1) | Straight line from start to end. |
| Ease | (0.25, 0.1, 0.25, 1.0) | Smooth start and end (default CSS ease). |
| EaseIn | (0.42, 0, 1.0, 1.0) | Slow start, fast end. |
| EaseOut | (0, 0, 0.58, 1.0) | Fast start, slow end. |
| EaseInOut | (0.42, 0, 0.58, 1.0) | Slow start and end, fast middle. |
| Exponential | (0.9, 0.05, 0.95, 0.95) | Sharp exponential curve. |
| SCurve | (0.4, 0.0, 0.6, 1.0) | S-shaped sigmoid curve. |
When to Use Custom Faders¶
Custom faders are useful when you want audio transitions to match your game's feel:
- Overshoot faders: Great for cartoon-style impacts or bouncy UI sounds.
- Slow-attack faders: Perfect for ambient music crossfades.
- Stepped faders: Simulate discrete volume steps for retro aesthetics.
- Asymmetric faders: Fast attack, slow release for reverb tails.
Runtime Behavior¶
When a fader is triggered (e.g., a bus starts ducking, a sound stops, or an RTPC value changes), the engine:
- Creates a
FaderInstancefrom the registeredFaderfactory. - Calls
Set(from, to, duration)to configure the transition. - Calls
Start(time)to begin the fade. - Each frame, calls
GetFromTime(currentTime)to get the interpolated value.
The fader instance is automatically destroyed when the transition completes or when the associated sound object is released.
Next Steps¶
- Learn how to write custom effects to process audio with DSP.
- Explore the Fader API Reference for the full interface.
- Experiment with the Bézier curve visualizer to design your own curves.