C++ Code project
The plugin nodes can be used in C++ Code Projects too.
Make an empty project
On the Epic Games Launcher go to Unreal Engine > Library and push the Launch button for your desired Engine Version
Now select Game an Blank Template
In Project Settings select C++ project. Set a name project and click on Create Project
Project Setup
Enable the Audio Analyzer plugin and restart the Unreal Editor
Now we can make a folder to contain the Non-assets files in the Content folder. This files don’t need to be imported by the engine we will use the file directly from the folder.
The audio files can be copy directly to this folder. We don’t need to import this files using the engine.
We need to include this folder explicity in our package build. Open the Project Settings > Project section > Packaging > Additional Non-Asset Directories to Package
Add the folder name to the list
Audio Analyzer Manager Setup
To be able to include the plugin classes in a C++ Project we need to copy the Folder of the Plugin inside the Project folder
Navigate to InstallattionFolder/EpicGames/UE_4.xx/Engine/Plugins/Marketplace and copy the plugin folder
The project will use the instance of the plugin located in their folder instead of the marketplace plugin so if the plugin is updated in the marketplace we need to copy the plugin again to tranfer the changes of each new version of the plugin.
Visual Studio
Now we need to add the includes to the plugin classes. To do that we need to open the project .Build.cs file and add ParallelcubeTaglib and ParallelcubeAudioAnalyzer into PrivateDependencyModuleNames list.
In this file we need to add the private includes used in the plugin too.
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PrivateDependencyModuleNames.AddRange(new string[] { "ParallelcubeTaglib", "ParallelcubeAudioAnalyzer" });
PrivateIncludePaths.Add("../Plugins/Marketplace/AudioAnalyzer/Source/AudioAnalyzer/Private");
PrivateIncludePaths.Add("../Plugins/Marketplace/AudioAnalyzer/Source/AudioAnalyzer/Thirdparty/KissFFT_130");
PrivateIncludePaths.Add("../Plugins/Marketplace/AudioAnalyzer/Source/AudioAnalyzer/Thirdparty/KissFFT_130/tools");
PrivateIncludePaths.Add("../Plugins/Marketplace/AudioAnalyzer/Source/Thirdparty/miniaudio/include");
PrivateIncludePaths.Add("../Plugins/Marketplace/AudioAnalyzer/Source/AudioAnalyzer/Thirdparty/stb");
An Actor Sample
Now we are going to create an Actor class to show how to use the plugin functions in a C++ Project.
We will name our class actor as AA_AudioSample. This actor will replicate the Blueprint Empty Project Sample behavior, so we can see how to translate some blueprint nodes to c++ code.
AA_AudioSample.h
1#pragma once
2
3#include "CoreMinimal.h"
4#include "GameFramework/Actor.h"
5#include "AA_AudioSample.generated.h"
6
7UCLASS()
8class AA_CODEPROJECT_API AAA_AudioSample : public AActor
9{
10 GENERATED_BODY()
11
12public:
13 // Sets default values for this actor's properties
14 AAA_AudioSample();
15
16protected:
17 // Called when the game starts or when spawned
18 virtual void BeginPlay() override;
19
20public:
21 // Called every frame
22 virtual void Tick(float DeltaTime) override;
23
24};
AA_AudioSample.cpp
1#include "AA_AudioSample.h"
2
3// Sets default values
4AAA_AudioSample::AAA_AudioSample()
5{
6 // Set this actor to call Tick() every frame.
7 // You can turn this off to improve performance if you don't need it.
8 PrimaryActorTick.bCanEverTick = true;
9}
10
11// Called when the game starts or when spawned
12void AAA_AudioSample::BeginPlay()
13{
14 Super::BeginPlay();
15}
16
17// Called every frame
18void AAA_AudioSample::Tick(float DeltaTime)
19{
20 Super::Tick(DeltaTime);
21}
First, we need to create an AudioAnalyzerManager instance and store it in a variable to use the reference to call the functions of the class
After that we can add the Player initialization. We need to construct the filename path to the audio file using FPaths::ProjectContentDir(), to retrieve the base path to the Content folder of our project.
If the initialization returns with no error then we can Play the sound.
AA_AudioSample.h (Version 2)
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "AA_AudioSample.generated.h"
class UAudioAnalyzerManager;
UCLASS()
class AA_CODEPROJECT_API AAA_AudioSample : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AAA_AudioSample();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
private:
UAudioAnalyzerManager* _AAManager;
};
AA_AudioSample.cpp (Version 2)
#include "AudioAnalyzerManager.h"
#include "Runtime/Core/Public/Misc/Paths.h"
...
// Called when the game starts or when spawned
void AAA_AudioSample::BeginPlay()
{
Super::BeginPlay();
//Construct AudioAnalyzerManager BP and Set
_AAManager = NewObject<UAudioAnalyzerManager>(this, TEXT("AAManager"));
//Init Player Audio and Play
FString AudioFileName = FPaths::ProjectContentDir() + "NonAssets/sample1.wav";
if (_AAManager->InitPlayerAudio(AudioFileName))
{
_AAManager->Play();
}
}
...
Now we can continue with the visualizer. We want to output the frequency value of the song in real time.
We need to initialize the spectrum visualizer before the Play call of the Player. We are going to use the same aparameters than the Blueprint Example
To retrieve the frequencies of the analysis we need to call GetSpectrum and take the data from the TArray of results.
AA_AudioSample.cpp (Version 3)
...
// Called when the game starts or when spawned
void AAA_AudioSample::BeginPlay()
{
Super::BeginPlay();
//Construct AudioAnalyzerManager BP and Set
_AAManager = NewObject<UAudioAnalyzerManager>(this, TEXT("AAManager"));
//Init Player audio and Play
FString AudioFileName = FPaths::ProjectContentDir() + "NonAssets/sample1.wav";
if (_AAManager->InitPlayerAudio(AudioFileName))
{
// Type: Linear
// Channel Mode: All in one
// Channel: 0
// Num Freq Bands: 1
// Time Window: 0.02s
// History Size: 30
// Use Peak Values: true
// Num Peaks: 1
_AAManager->InitSpectrumConfig(EAA_SpectrumType::ST_Linear, EAA_ChannelSelectionMode::All_in_one, 0, 1, 0.02, 30, true, 1);
_AAManager->Play();
}
}
// Called every frame
void AAA_AudioSample::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (_AAManager && _AAManager->IsPlaying())
{
TArray<float> Frequencies;
TArray<float> AverageFrequencies;
_AAManager->GetSpectrum(Frequencies, AverageFrequencies, false);
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, FString::Printf(TEXT("%f"), Frequencies[0]));
}
}
...
Asynchronous Initialization
Note
With big audio files is better to use asynchronous initialization node to avoid the app hang during the audio decode process.
With the asynchronous node an AsyncTask is generated to decode the file in other thread. When the decoding process end an event is triggered with the result of the operation.
To use asynchronous initialization we need to define the function that will be called when the initialization ends. This function must be linked before the asynchronous initialization call.
All the code after the InitPlayerAudio call will be transfered to the event callback function.
AA_AudioSample.h (Async Version)
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "AA_AudioSample.generated.h"
class UAudioAnalyzerManager;
UCLASS()
class AA_CODEPROJECT_API AAA_AudioSample : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AAA_AudioSample();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
private:
UAudioAnalyzerManager* _AAManager;
//Bind to delegate function
UFUNCTION()
void OnPlayerInitEnds(bool Result);
};
AA_AudioSample.cpp (Async Version)
...
//Bind to delegate
void AAA_AudioSample::OnPlayerInitEnds(bool Result)
{
if (Result)
{
// Type: Linear
// Channel Mode: All in one
// Channel: 0
// Num Freq Bands: 1
// Time Window: 0.02s
// History Size: 30
// Use Peak Values: true
// Num Peaks: 1
_AAManager->InitSpectrumConfig(EAA_SpectrumType::ST_Linear, EAA_ChannelSelectionMode::All_in_one, 0, 1, 0.02, 30, true, 1);
_AAManager->Play();
}
}
// Called when the game starts or when spawned
void AAA_AudioSample::BeginPlay()
{
Super::BeginPlay();
//Construct AudioAnalyzerManager BP and Set
_AAManager = NewObject<UAudioAnalyzerManager>(this, TEXT("AAManager"));
//Bind Events
_AAManager->OnInitPlayerAudioFinished.AddDynamic(this, &AAA_AudioSample::OnPlayerInitEnds);
//Async Init Player audio and Play
FString AudioFileName = FPaths::ProjectContentDir() + "NonAssets/sample1.wav";
_AAManager->AsyncInitPlayerAudio(AudioFileName);
}
// Called every frame
void AAA_AudioSample::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (_AAManager && _AAManager->IsPlaying())
{
TArray<float> Frequencies;
TArray<float> AverageFrequencies;
_AAManager->GetSpectrum(Frequencies, AverageFrequencies, false);
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, FString::Printf(TEXT("%f"), Frequencies[0]));
}
}
...
Using the class in the Editor
To use this class inside the editor we need to create a blueprint for the class.
Launch the Editor using Visual Studio with the Start Menu.
Into C++ Classes folder of the Content Browser we can find our previos Class, rigth click on this object and Create Blueprint class
This Blueprint can be dropped into the Map.
When the project starts the Playback of the song starts too and we can see the frequencies values on the screen.