is it possible to play(or get the reference of) a sound by it’s path/filename?
more info: i have around 300 sound files each with a specific name that are all stored inside an array of strings, i need to take a string from the array and play the sound with that name, i come from unity where you can just do
AudioClip clip = Resources.Load(stringVariable);
That is not really the Unreal engine way to do it. I mean you can find the object using the string, sure, but tbh you would be better storing the actual object. But as it is a very big list, what you would want to do is
USoundBase* Sound = LoadObject<USoundBase*>(NULL, StringVariable, NULL, LOAD_None, NULL);
or something similar.
You can make that a bit better.
template <typename ObjClass>
static FORCEINLINE ObjClass * LoadObjFromPath(const FName &Path)
{
if (Path == NAME_None) return NULL;
if (Path.ToString().Contains("None")) return NULL;
return Cast<ObjClass>(StaticLoadObject(ObjClass::StaticClass(), NULL, *Path.ToString()));
}
FString Path = FString::Printf(TEXT("/Game/PoppyAndBuddy/Stories/%s/Audio/%s/%s"), *BookName, *Language, *Word);
USoundWave* Loaded = LoadObjFromPath<USoundWave>(FName(*Path));
e.g. an actual, exact example path is /Game/PoppyAndBuddy/Stories/MyStory/Audio/English/hello
So not a typical asset reference, it’s just straight up a normal path using /Game as the root.
2 Likes
You can also use ConstructorHelpers:FObjectFinder<> to snag a sound from a file path. The only thing to note based on your post descriptions is you currently have an array of strings with each path name, and you would need to use TCHAR* or wchar_t ] to store your paths. Here is some code to grab a single sound by path using two acceptable types:
in your .h
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Ammo)
class USoundBase* AmmoPickupSound;
in your .cpp’s constructor
TCHAR* SoundPath = L"SoundCue'/Game/SciFiWeapLight/Sound/GrenadeLauncher/GL_AmmoPickup_Cue.GL_AmmoPickup_Cue'";
auto AmmoPickupSoundAsset = ConstructorHelpers::FObjectFinder<USoundBase>(SoundPath);
if (AmmoPickupSoundAsset.Object != nullptr)
{
AmmoPickupSound = AmmoPickupSoundAsset.Object;
}
or
wchar_t SoundPath] = L"SoundCue'/Game/SciFiWeapLight/Sound/GrenadeLauncher/GL_AmmoPickup_Cue.GL_AmmoPickup_Cue'";
auto AmmoPickupSoundAsset = ConstructorHelpers::FObjectFinder<USoundBase>(SoundPath);
if (AmmoPickupSoundAsset.Object != nullptr)
{
AmmoPickupSound = AmmoPickupSoundAsset.Object;
}
Then when you want to play a sound somewhere you can use something like:
if (AmmoPickupSound != nullptr)
{
UGameplayStatics::PlaySoundAtLocation(this, AmmoPickupSound, GetActorLocation());
}
Hope this helps, have a lovely day!
Issue with Constructor helper is you need to load them ALL in the constructor. not very memory effecient and you would need an array to hold all the pointers, and then loop through to pick the sound you want.
2 Likes
The method I posted works outside of the constructor, so it has that going for it which is nice.
We have a similar requirement in one of our projects.
- thousands of lines of recorded dialog
- each dialog line is referenced by a unique string which maps to a sound cue asset
- a TMap<FString, FString> associates unique dialog cue name to an asset path
We use the same loading method as Antidamage posted above. Though we just directly play the sound cue through a player controller reference.
USoundCue* chatSound = Cast<USoundCue>(StaticLoadObject(USoundCue::StaticClass(), NULL, *soundCuePath));
if (chatSound != nullptr && _playerController != nullptr)
{
_playerController->ClientPlaySound(chatSound);
}
2 Likes