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
doc_blueprint_empty_launch
Now select Game an Blank Template
doc_code_project_template
In Project Settings select C++ project. Set a name project and click on Create Project
doc_code_project_name

Project Setup

Enable the Audio Analyzer plugin and restart the Unreal Editor
doc_blueprint_empty_enable_plugin
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.
doc_blueprint_empty_asset_folder
The audio files can be copy directly to this folder. We don’t need to import this files using the engine.
doc_blueprint_empty_asset_file
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
doc_blueprint_empty_asset_pack

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
doc_code_project_copy
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.
doc_code_project_buildcs
AA_CodeProject.Build.cs
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
doc_code_project_editor
This Blueprint can be dropped into the Map.
doc_code_project_map
When the project starts the Playback of the song starts too and we can see the frequencies values on the screen.
doc_code_project_screen

Download Project (Without plugin files)

doc_downloadbutton.png

Sync Version

doc_downloadbutton.png

ASync Version