Adding a Transform Effect
Follow this checklist when adding a new transform effect to AudioJones. Each section lists required modifications with file paths relative to repository root.
Checklist Overview
Transform effects require changes to 11 locations across 8 files. Three steps are commonly missed:
- •TransformOrderConfig::order array - Effect won't appear in reorder UI
- •GetTransformCategory() case - Effect shows "???" badge in pipeline list
- •param_registry.cpp entries - Modulatable parameters won't respond to LFOs/audio
Phase 1: Config Header
Create src/config/{effect_name}_config.h:
#ifndef {EFFECT_NAME}_CONFIG_H
#define {EFFECT_NAME}_CONFIG_H
struct {EffectName}Config {
bool enabled = false;
// Add effect-specific parameters with defaults
};
#endif
Use snake_case for filename, PascalCase for struct name.
Phase 2: Effect Registration
Modify src/config/effect_config.h:
- •
Add include at top with other config headers:
cpp#include "{effect_name}_config.h" - •
Add enum entry in
TransformEffectTypebeforeTRANSFORM_EFFECT_COUNT:cppTRANSFORM_{EFFECT_NAME}, - •
Add name case in
TransformEffectName():cppcase TRANSFORM_{EFFECT_NAME}: return "Effect Name"; - •
Add to order array in
TransformOrderConfig::orderinitialization:cppTRANSFORM_{EFFECT_NAME}Place at end of array, before closing brace. COMMONLY MISSED.
- •
Add config member to
EffectConfigstruct:cpp{EffectName}Config {effectName}; - •
Add enabled case in
IsTransformEnabled():cppcase TRANSFORM_{EFFECT_NAME}: return e->{effectName}.enabled;
Phase 3: Shader
Create shaders/{effect_name}.fs:
#version 330
in vec2 fragTexCoord;
out vec4 finalColor;
uniform sampler2D texture0;
uniform vec2 resolution;
// Add effect-specific uniforms
void main() {
vec2 uv = fragTexCoord;
vec4 color = texture(texture0, uv);
// Effect algorithm here
finalColor = color;
}
Phase 4: PostEffect Integration
Modify src/render/post_effect.h:
- •
Add shader member in
PostEffectstruct:cppShader {effectName}Shader; - •
Add uniform location members:
cppint {effectName}ResolutionLoc; int {effectName}{ParamName}Loc; // One int per uniform
Modify src/render/post_effect.cpp:
- •
Load shader in
LoadPostEffectShaders():cpppe->{effectName}Shader = LoadShader(0, "shaders/{effect_name}.fs"); - •
Add to success check (same function):
cpp&& pe->{effectName}Shader.id != 0 - •
Get uniform locations in
GetShaderUniformLocations():cpppe->{effectName}ResolutionLoc = GetShaderLocation(pe->{effectName}Shader, "resolution"); pe->{effectName}{ParamName}Loc = GetShaderLocation(pe->{effectName}Shader, "{paramName}"); - •
Add to resolution uniforms in
SetResolutionUniforms()if shader uses resolution:cppSetShaderValue(pe->{effectName}Shader, pe->{effectName}ResolutionLoc, res, SHADER_UNIFORM_VEC2); - •
Unload shader in
PostEffectUninit():cppUnloadShader(pe->{effectName}Shader);
Phase 5: Shader Setup
Modify src/render/shader_setup.h:
- •Declare setup function:
cpp
void Setup{EffectName}(PostEffect* pe);
Modify src/render/shader_setup.cpp:
- •
Add dispatch case in
GetTransformEffect():cppcase TRANSFORM_{EFFECT_NAME}: return { &pe->{effectName}Shader, Setup{EffectName}, &pe->effects.{effectName}.enabled }; - •
Implement setup function:
cppvoid Setup{EffectName}(PostEffect* pe) { const {EffectName}Config* cfg = &pe->effects.{effectName}; SetShaderValue(pe->{effectName}Shader, pe->{effectName}{ParamName}Loc, &cfg->{paramName}, SHADER_UNIFORM_FLOAT); }
Phase 6: UI Panel
Modify src/ui/imgui_effects.cpp:
- •Add category mapping in
GetTransformCategory()switch statement. Match the category to whicheverDraw*Category()function contains your UI controls. COMMONLY MISSED.
Modify src/ui/imgui_effects_{category}.cpp:
- •
Add section state at file top with other static bools:
cppstatic bool section{EffectName} = false; - •
Add helper function before the appropriate
Draw*Category():cppstatic void Draw{Category}{EffectName}(EffectConfig* e, const ModSources* modSources, const ImU32 categoryGlow) { if (DrawSectionBegin("Effect Name", categoryGlow, §ion{EffectName})) { const bool wasEnabled = e->{effectName}.enabled; ImGui::Checkbox("Enabled##{id}", &e->{effectName}.enabled); if (!wasEnabled && e->{effectName}.enabled) { MoveTransformToEnd(&e->transformOrder, TRANSFORM_{EFFECT_NAME}); } if (e->{effectName}.enabled) { ModulatableSlider("Param", &e->{effectName}.param, "effectName.param", "%.2f", modSources); } DrawSectionEnd(); } } - •
Add helper call in the orchestrator with spacing:
cppImGui::Spacing(); Draw{Category}{EffectName}(e, modSources, categoryGlow);Use
ModulatableSliderfor parameters that should respond to modulation. UseModulatableSliderAngleDegfor angular parameters (displays degrees, stores radians).
Phase 7: Preset Serialization
Modify src/config/preset.cpp:
- •
Add JSON macro with other config macros:
cppNLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT({EffectName}Config, enabled, {param1}, {param2}) - •
Add to_json entry in
to_json(json& j, const EffectConfig& e):cppif (e.{effectName}.enabled) { j["{effectName}"] = e.{effectName}; } - •
Add from_json entry in
from_json(const json& j, EffectConfig& e):cppe.{effectName} = j.value("{effectName}", e.{effectName});
Phase 8: Parameter Registration (if modulatable)
Modify src/automation/param_registry.cpp:
- •
Add to PARAM_TABLE:
cpp{"{effectName}.{param}", {{min}f, {max}f}}, - •
Add to targets array (search for
float* targets[]):cpp&effects->{effectName}.{param},
Entries in PARAM_TABLE and targets array must be at matching indices. COMMONLY MISSED.
For angular parameters, use the constants from ui_units.h:
- •
ROTATION_SPEED_MAXfor speed fields (radians/second) - •
ROTATION_OFFSET_MAXfor angle/twist fields (radians)
Verification
After implementation, verify:
- • Effect appears in transform order pipeline
- • Effect shows correct category badge (not "???")
- • Effect can be reordered via drag-drop
- • Enabling effect adds it to the pipeline list
- • UI controls modify effect in real-time
- • Preset save/load preserves settings
- • Modulation routes to registered parameters (if applicable)
- • Build succeeds with no warnings
File Summary
| File | Changes |
|---|---|
src/config/{effect}_config.h | Create config struct |
src/config/effect_config.h | Include, enum, name, order array, member, IsTransformEnabled case |
shaders/{effect}.fs | Create fragment shader |
src/render/post_effect.h | Shader and uniform location members |
src/render/post_effect.cpp | Load, check, locations, resolution, unload |
src/render/shader_setup.h | Declare Setup function |
src/render/shader_setup.cpp | Dispatch case and Setup implementation |
src/ui/imgui_effects.cpp | GetTransformCategory case |
src/ui/imgui_effects_{category}.cpp | Section state and UI controls |
src/config/preset.cpp | JSON macro, to_json, from_json |
src/automation/param_registry.cpp | PARAM_TABLE and targets entries |