Download

Implementing Presets for a custom UComponent's default variables

Hi,

I’ve created a custom USynthComponent class to generate sound. The sound generator has a few parameters to allow manipulating the output sound, e.g. things like filters, frequencies, amplitudes etc. These parameters have default values that are specified in the declaration of the USynthComponent class. Here’s what that looks like:

UCLASS(ClassGroup = Synth, meta = (BlueprintSpawnableComponent))
class MYAUDIOPLUGIN_API UTestSFX : public USynthComponent
{
    // Constructor
    GENERATED_BODY()
        UTestSFX(const FObjectInitializer& ObjInitializer);
    // Destructor
    virtual ~UTestSFX();

public:
    // The frequency (in hz) of the tone generator.
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings", meta = (ClampMin = "10.0", ClampMax = "20000.0"))
        float Frequency = 80.0;

    // The volume of the tone generator.
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings", meta = (ClampMin = "0.0", ClampMax = "1.0"))
        float Volume = 0.8;

    // The Attack time of the envelope.
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings", meta = (ClampMin = "0.01", ClampMax = "5.0"))
        float Attack = 0.5;

    // The Decay time of the envelope.
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings", meta = (ClampMin = "0.01", ClampMax = "5.0"))
        float Decay = 0.3;

    // The cut-off frequency of the filter.
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings", meta = (ClampMin = "50.0", ClampMax = "15000.0"))
        float Cutoff = 3000.0;

    // Override USynthComponent's CreateSoundGenerator function with our own
    virtual ISoundGeneratorPtr CreateSoundGenerator(int32 InSampleRate, int32 InNumChannels) override;

protected:
    // The runtime instance of the sound generator
    ISoundGeneratorPtr MyOsc;
};

As you can see, the default values are specified as UProperties. When dragging this component in a blueprint, these properties appear in the “Details” panel as sliders:

Capture

And you can see that the default position of the sliders matches the values in the code. Now for my problem: I would like to implement a preset system that would allow the user to load another set of default values. For example here the preset is (80, 0.8, 0.5, 0.3, 3000) and maybe I’d like a “flute” preset where the values are (250, 0.2, 0.6, 0.7, 9000).
I haven’t found any way of doing this yet. Is there a way to save the settings of a Ucomponent as a preset? How would you implement this?

The first thing that comes to mind is subclassing the component and changing the presets there. So you’d have UFluteSFXComponent, UFiddleSFXComponent etc. which inherit from your base component and change the presets in their constructors.

Another idea: Create a new class that inherits from UDataAsset or UPrimaryDataAsset. This class is what actually holds the parameters. Your UTestSFX would have only one property and its type would be that of your newly created data asset. You can then create a bunch of blueprints that inherit from this data assets and represent different presets.

Thanks for your help. I’ve thought of the first solution too, but I can’t find a way to make it work without a huge amount of duplicate code. In the end I’m planning to have about a dozen presets, so I will have 12 class declarations that are almost exactly the same, and 12 constructors/destructors in my .cpp files that are the same but with different names. Your second idea sounds more efficient, so I’ll give it a go. Thanks again!

Worth noting that if you make your class Blueprintable, you can derive blueprint versions of the class which do nothing but change the default values. These are known as “data-only” blueprints. So it’s actually fairly easy to create a set of classes with different defaults without bloating your codebase.

Hi, thanks for your reply. Can this “blueprint versions of the class” be added to other blueprints? One important feature I’d like to keep in my system is the ability to quickly drag & drop the USynthComponent into a blueprint so any actor can quickly have its own sound-generator. With this solution, it sounds like you’d have to change the actor’s parent class to the data-only blueprints, is this correct?

You can add objects/blueprints to other blueprints using the EditInlineNew system, which might be overkill here but is one option. It’s neat because you can actually customize the subobject in-place. However I’ve been running into problems using EditInlineNew inside components, I think there’s some engine bugs there. So not sure I’d recommend that.

What I was suggesting is basically to derive blueprints from UTestSFX (make it Blueprintable) and name those e.g. FluteSFX or TestSFX_Flute. Edit the defaults on those BPs. Then you’d add e.g. a TestSFX_Flute component rather than just a TestSFX component, and you’d get the defaults from the Flute version of the class. That’s not going to let you easily switch between presets, but you’d be able to further customize the values on an instance of the component (reset to default to get the preset’s values).

The other suggestion with data assets also makes sense, you’d just have something like a UPROPERTY “UTestSFXPresetDataAsset” (or whatever) pointer on the component. That’ll give you a dropdown of the available presets (data assets created in the editor). That makes it easy to switch between presets, but you can’t customize the values per-component - you’d have to make a new preset. A hacky solution to that would be to add “adjustment” properties to the component that default to zero and can go positive or negative, and you could just just add those adjustments to the selected preset’s values.