I have a MetaSound source with a doppler effect set up using SourceEffectSimpleDelayPreset. It works great most of the time; however, our game occasionally has players teleport, and when they do, the sound gets pitch shifted up really high as if the player had spent the tick speeding towards its new location. Is there any way to prevent this, and have the sound simply cut to what should be at the new location?
I ended up delving into SourceEffectSimpleDelay and creating a subclass that handles this. You’ll just need to convert all your SourceEffectSimpleDelayPreset assets into SourceEffectConfigurableDelayPreset and set TeleportDistance appropriately.
SourceEffectConfigurableDelay.h
#pragma once
#include <CoreMinimal.h>
#include <Synthesis/Classes/SourceEffects/SourceEffectSimpleDelay.h>
#include "SourceEffectConfigurableDelay.generated.h"
USTRUCT(BlueprintType)
struct FSourceEffectConfigurableDelaySettings : public FSourceEffectSimpleDelaySettings {
GENERATED_BODY()
// The minimum distance change (in meters) in one tick for a movement to be considered a teleport
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SourceEffect|Preset")
float TeleportDistance = INFINITY;
};
class FSourceEffectConfigurableDelay : public FSourceEffectSimpleDelay {
public:
// Process the input block of audio. Called on audio thread.
void ProcessAudio(const FSoundEffectSourceInputData& InData, float* OutAudioBufferData) override;
void OnPresetChanged() override;
protected:
// From settings
float TeleportDistance = INFINITY;
float PreviousDistance = 0;
};
UCLASS(ClassGroup = AudioSourceEffect, meta = (BlueprintSpawnableComponent))
class USourceEffectConfigurableDelayPreset : public USoundEffectSourcePreset {
GENERATED_BODY()
public:
EFFECT_PRESET_METHODS(SourceEffectConfigurableDelay)
virtual FColor GetPresetColor() const override { return FColor(100.0f, 165.0f, 85.0f); }
UFUNCTION(BlueprintCallable, Category = "Audio|Effects")
void SetSettings(const FSourceEffectConfigurableDelaySettings& InSettings);
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Audio|Effects")
FSourceEffectConfigurableDelaySettings Settings;
};
SourceEffectConfigurableDelay.cpp
#include "SourceEffectConfigurableDelay.h"
void USourceEffectConfigurableDelayPreset::SetSettings(const FSourceEffectConfigurableDelaySettings &InSettings) {
UpdateSettings(InSettings);
}
void FSourceEffectConfigurableDelay::OnPresetChanged(){
// Unfortunately this function must be copied wholesale due to how GET_EFFECT_SETTINGS works
GET_EFFECT_SETTINGS(SourceEffectConfigurableDelay);
SettingsCopy = Settings;
TeleportDistance = Settings.TeleportDistance;
// If we are manually setting the delay, lets set it now on the delay line
if (!SettingsCopy.bDelayBasedOnDistance)
{
for (Audio::FDelay& Delay : Delays)
{
Delay.SetEasedDelayMsec(SettingsCopy.DelayAmount * 1000.0f, bIsInit);
}
bIsInit = false;
}
}
void FSourceEffectConfigurableDelay::ProcessAudio(const FSoundEffectSourceInputData &InData, float *OutAudioBufferData) {
// Same way distance is calculated in SourceEffectSimpleDelay
const float DistanceMeters = SettingsCopy.bUseDistanceOverride ?
InData.SpatParams.AttenuationDistance * 0.1f
: InData.SpatParams.Distance * 0.01f;
if (FMath::Abs(DistanceMeters - PreviousDistance) >= TeleportDistance) {
bIsInit = true;
}
PreviousDistance = DistanceMeters;
FSourceEffectSimpleDelay::ProcessAudio(InData, OutAudioBufferData);
}
You’ll also need to add this to your Build.cs:
PublicDependencyModuleNames.AddRange(new string[] { "Synthesis" });