thirdparty_libraries_1_featured

in Tutorials, UE4

Using thirdparty libraries in our UE4 mobile/desktop project

Sometimes we need to include thirdparty libraries to add support to a new feature or simply to facilitate the development. With this tutorial we are going to explain some details to configure and be able to use a thirdparty library with a UE4 project. We also include an annex about how to deploy this libraries into an Android shipping.

Part 1: Setting up project paths
Part 2: Using the library
Part 3: Frequency spectrum
Part 4: UE4 spectrum visualizer
Part 5: Beat tracking algorithm
Part 6: UE4 beat visualizer

For this tutorial we are going to integrate the FMOD library (only the low level API) into a windows/android project.

FMOD is a sound effects engine and authoring tool for video games and applications developed by Firelight Technologies, that play and mix sounds of diverse formats on many operating systems.

In the FMOD download section we can choose the zip for our UE4 engine version.

fmod_download

For this example we need only the low level API so we need only a few binaries from this zip.

We can start creating a folder for thirdparty libraries, if we want to share this libraries with other projects we can put this folder outside the project folder and configure the paths relative to that folder. In our example we make the Thirdparty folder inside our project.

thirdparty_folder

The next image show the needed files, where can be found inside the fmod zip and their final path inside our thirdparty folder. (This files can be changed in a future version of the library)

thirdparty_tree

To be able to include the binaries of our library into an Android deploy we need to create a .xml file using APL, This file has the information to configure and copy the needed files during the packing process.

<?xml version="1.0" encoding="utf-8"?>
<!--GearVR plugin additions-->
<root xmlns:android="http://schemas.android.com/apk/res/android">
	<!-- init section is always evaluated once per architecture -->
	<init>
		<log text="FMOD APL init (shipping build)"/>
	</init>

	<!-- optional additions to proguard -->
	<proguardAdditions>
		<insert>
			-keep class org.fmod.** {
			*;
			}
			-dontwarn org.fmod.**
		</insert>
	</proguardAdditions>

	<!-- optional files or directories to copy to Intermediate/Android/APK -->
	<resourceCopies>
		<log text="FMOD APL copying files for $S(Architecture)"/>
		<copyFile src="$S(PluginDir)/Libraries/Android/$S(Architecture)/libfmod.so"
					dst="$S(BuildDir)/libs/$S(Architecture)/libfmod.so" />
		<copyFile src="$S(PluginDir)/Libraries/Android/fmod.jar"
					dst="$S(BuildDir)/libs/fmod.jar" />
	</resourceCopies>

	<!-- optional additions to GameActivity onCreate in GameActivity.java -->
	<gameActivityOnCreateAdditions>
		<insert>
		// Initialize FMOD jar file
		org.fmod.FMOD.init(this);
		</insert>
	</gameActivityOnCreateAdditions>

	<!-- optional additions to GameActivity onDestroy in GameActivity.java -->
	<gameActivityOnDestroyAdditions>
		<insert>
		// Shutdown FMOD jar file
		org.fmod.FMOD.close();
		</insert>
	</gameActivityOnDestroyAdditions>

	<!-- optional libraries to load in GameActivity.java before libUE4.so -->
	<soLoadLibrary>
		<log text="FMOD APL adding loadLibrary references"/>
		<loadLibrary name="fmod" failmsg="libfmod not loaded and required!" />
	</soLoadLibrary>
</root>

Now we can open the {PROJECT_NAME}.Build.cs file of our solution. This file declares a class deriving from the ModuleRules base class, and sets properties controlling how it should be built from its constructor. This file is compiled by UnrealBuildTool and constructed to determine the overall compile environment.

using UnrealBuildTool;

public class Tutorial_spectrum : ModuleRules
{
	public Tutorial_spectrum(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
		PrivateDependencyModuleNames.AddRange(new string[] {  });

		// Uncomment if you are using Slate UI
		// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
		
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add("OnlineSubsystem");

		// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
	}
}

In this file we need to set the paths to our thirdparty library for each platform. To obtain the path of the current build.cs file we can use the GetDirectoryName function of the namespace System.IO.Path

var basePath = Path.GetDirectoryName(RulesCompiler.GetFileNameFromType(GetType()));

To reach the Thirdparty folder of our current project we can use Combine to modify the path go up in the directory tree

string thirdPartyPath = Path.Combine(basePath, "..", "..", "Thirdparty");

Now we can start to add the library paths. the first one is the related to the .h files, this tell to the visual studio solution where to find the include files. We need to use the function PublicIncludePaths for this folder, this is common to all platforms.

PublicIncludePaths.Add(Path.Combine(thirdPartyPath, "FMOD", "Includes"));

To add the binary location of the library (.lib/.dll/.so) we need to add the paths according to the platform. To select the current platform we can check the variable Target.Platform value and fill it with the paths of each platform.

if (Target.Platform == UnrealTargetPlatform.Win64)
{
}
else if (Target.Platform == UnrealTargetPlatform.Android)
{
}
else
{
//Unsupported platform
}

To include the path to the library binary we must use the PublicAdditionalLibraries to indicate the library name
For Win64 platform we need to set the runtime dependency path to the .dll file too RuntimeDependencies, since the .dll must be in the same folder than the .exe file of our game, we need to copy it to the build folder to be able to use the library during the editor development. Finally we can use the PublicDelayLoadDLLs to be able to delay the load of our library, the library will be loaded automatically when it is needed.

PublicAdditionalLibraries.Add(Path.Combine(thirdPartyPath, "FMOD", "Libraries", "Win64","fmod_vc.lib"));
string fmodDllPath = Path.Combine(thirdPartyPath, "FMOD", "Libraries", "Win64", "fmod.dll");
RuntimeDependencies.Add(fmodDllPath);

string binariesDir = Path.Combine(basePath,"..","..", "Binaries", "Win64");
if (!Directory.Exists(binariesDir))
    System.IO.Directory.CreateDirectory(binariesDir);

string fmodDllDest = System.IO.Path.Combine(binariesDir, "fmod.dll");
CopyFile(fmodDllPath, fmodDllDest);
PublicDelayLoadDLLs.AddRange(new string[] { "fmod.dll" });

For Android platform we need to add the previous APL.xml file path with AdditionalPropertiesForReceipt too.

PublicAdditionalLibraries.Add(Path.Combine(thirdPartyPath, "FMOD", "Libraries", "Android", "armeabi-v7a","libfmod.so"));
PublicAdditionalLibraries.Add(Path.Combine(thirdPartyPath, "FMOD", "Libraries", "Android", "arm64-v8a","libfmod.so"));
string RelAPLPath = Utils.MakePathRelativeTo(System.IO.Path.Combine(thirdPartyPath, "FMOD", "FMOD_APL.xml"), Target.RelativeEnginePath);
AdditionalPropertiesForReceipt.Add("AndroidPlugin", RelAPLPath);

Putting all together the final build.cs file looks like this:

using UnrealBuildTool;
using System.IO;

public class Tutorial_spectrum : ModuleRules
{
	public Tutorial_spectrum(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
		PrivateDependencyModuleNames.AddRange(new string[] {  });

		var basePath = Path.GetDirectoryName(RulesCompiler.GetFileNameFromType(GetType()));
        string thirdPartyPath = Path.Combine(basePath, "..", "..", "Thirdparty");

        
        //FMOD
        PublicIncludePaths.Add(Path.Combine(thirdPartyPath, "FMOD", "Includes"));
   
		if (Target.Platform == UnrealTargetPlatform.Win64)
		{
                PublicAdditionalLibraries.Add(Path.Combine(thirdPartyPath, "FMOD", "Libraries", "Win64","fmod_vc.lib"));
                string fmodDllPath = Path.Combine(thirdPartyPath, "FMOD", "Libraries", "Win64", "fmod.dll");
                RuntimeDependencies.Add(fmodDllPath);

                string binariesDir = Path.Combine(basePath,"..","..", "Binaries", "Win64");
                if (!Directory.Exists(binariesDir))
                    System.IO.Directory.CreateDirectory(binariesDir);

                string fmodDllDest = System.IO.Path.Combine(binariesDir, "fmod.dll");
                CopyFile(fmodDllPath, fmodDllDest);
                PublicDelayLoadDLLs.AddRange(new string[] { "fmod.dll" });
		}
        else if (Target.Platform == UnrealTargetPlatform.Android)
		{
                PublicAdditionalLibraries.Add(Path.Combine(thirdPartyPath, "FMOD", "Libraries", "Android", "armeabi-v7a","libfmod.so"));
                PublicAdditionalLibraries.Add(Path.Combine(thirdPartyPath, "FMOD", "Libraries", "Android", "arm64-v8a","libfmod.so"));
                string RelAPLPath = Utils.MakePathRelativeTo(System.IO.Path.Combine(thirdPartyPath, "FMOD", "FMOD_APL.xml"), Target.RelativeEnginePath);
                AdditionalPropertiesForReceipt.Add("AndroidPlugin", RelAPLPath);
		}
		else
		{
                //throw new System.Exception(System.String.Format("Unsupported platform {0}", Target.Platform.ToString()));
        }
    }


    private void CopyFile(string source, string dest)
    {
        System.Console.WriteLine("Copying {0} to {1}", source, dest);
        if (System.IO.File.Exists(dest))
        {
            System.IO.File.SetAttributes(dest, System.IO.File.GetAttributes(dest) & ~System.IO.FileAttributes.ReadOnly);
        }
        try
        {
            System.IO.File.Copy(source, dest, true);
        }
        catch (System.Exception ex)
        {
            System.Console.WriteLine("Failed to copy file: {0}", ex.Message);
        }
    }
}

We need to do a Rebuild of the project to see the changes of this file in the current development session. Now we can make a little class to use this library. We are going to create a SoundManager and play a sound using the fmod library.

Part 2: Using the library

2020/06/22 – Updated to Unreal Engine 4.24

Support this blog!

For the past year I've been dedicating more of my time to the creation of tutorials, mainly about game development. If you think these posts have either helped or inspired you, please consider supporting this blog. Thank you so much for your contribution!

Leave a Reply for Derjyn Cancel Reply

Write a Comment

Comment

  1. The paths in the “{PROJECT_NAME}.Build.cs” part are all screwed up. The base directory you end up pulling from is the {PROJECT_NAME}/Source folder, so binaries and such get pulled and copied from the wrong places.

    Look that over!

    • BasePath is in the {PROJECT_NAME}/Source/{PROJECT_NAME} folder, so we are always going up 2 directories to reach the project folder, as in the thirdparty folder path construction

      {PROJECT_NAME}/Source/{PROJECT_NAME}/../../Thirdparty

      So finally we are in the correct place

      {PROJECT_NAME}/Thirdparty