Skip to content

Commit

Permalink
Merge pull request #9 from outoftheboxplugins/master
Browse files Browse the repository at this point in the history
Support for Unreal 5
  • Loading branch information
Andrey1994 authored Sep 22, 2023
2 parents 7493b2a + 6c79ff8 commit da8513c
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 79 deletions.
2 changes: 2 additions & 0 deletions BrainFlowPlugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Binaries/
Intermediate/
107 changes: 46 additions & 61 deletions BrainFlowPlugin/Source/BrainFlowPlugin/BrainFlowPlugin.Build.cs
Original file line number Diff line number Diff line change
@@ -1,83 +1,68 @@
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.

using System;
using System.Collections.Generic;
using UnrealBuildTool;
using System.IO;
using System.Linq;

public class BrainFlowPlugin : ModuleRules
{
public BrainFlowPlugin(ReadOnlyTargetRules Target) : base(Target)
{
public BrainFlowPlugin(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });

PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Public"));
PublicDependencyModuleNames.AddRange(new string[] { "Core", "Projects" });

if(Target.Platform == UnrealTargetPlatform.Win32)
{
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Compiled", "Win32_dynamic", "inc"));
PublicLibraryPaths.Add(Path.Combine(ModuleDirectory, "Compiled", "Win32_dynamic", "lib"));
PublicAdditionalLibraries.Add("Brainflow32.lib");
PublicAdditionalLibraries.Add("DataHandler32.lib");
PublicAdditionalLibraries.Add("BoardController32.lib");
PublicAdditionalLibraries.Add("MLModule32.lib");
RuntimeDependencies.Add("$(TargetOutputDir)/BoardController32.dll", Path.Combine(ModuleDirectory, "Compiled", "Win32_dynamic", "lib", "BoardController32.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/DataHandler32.dll", Path.Combine(ModuleDirectory, "Compiled", "Win32_dynamic", "lib", "DataHandler32.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/GanglionLib32.dll", Path.Combine(ModuleDirectory, "Compiled", "Win32_dynamic", "lib", "GanglionLib32.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/gforce32.dll", Path.Combine(ModuleDirectory, "Compiled", "Win32_dynamic", "lib", "gforce32.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/gForceSDKWrapper32.dll", Path.Combine(ModuleDirectory, "Compiled", "Win32_dynamic", "lib", "gForceSDKWrapper32.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/neurosdk-x86.dll", Path.Combine(ModuleDirectory, "Compiled", "Win32_dynamic", "lib", "neurosdk-x86.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/BrainBitLib32.dll", Path.Combine(ModuleDirectory, "Compiled", "Win32_dynamic", "lib", "BrainBitLib32.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/eego-SDK32.dll", Path.Combine(ModuleDirectory, "Compiled", "Win32_dynamic", "lib", "eego-SDK32.dll"));
}
if(Target.Platform == UnrealTargetPlatform.Win64)
{
PublicLibraryPaths.Add(Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib"));
String PrecompiledFolder = Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib");
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "inc"));
PublicAdditionalLibraries.Add("Brainflow.lib");
PublicAdditionalLibraries.Add("DataHandler.lib");
PublicAdditionalLibraries.Add("BoardController.lib");
PublicAdditionalLibraries.Add("MLModule.lib");
RuntimeDependencies.Add("$(TargetOutputDir)/BoardController.dll", Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib", "BoardController.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/DataHandler.dll", Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib", "DataHandler.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/GanglionLib.dll", Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib", "GanglionLib.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/gforce64.dll", Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib", "gforce64.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/gForceSDKWrapper.dll", Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib", "gForceSDKWrapper.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/neurosdk-x64.dll", Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib", "neurosdk-x64.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/Unicorn.dll", Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib", "Unicorn.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/BrainBitLib.dll", Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib", "BrainBitLib.dll"));
RuntimeDependencies.Add("$(TargetOutputDir)/eego-SDK.dll", Path.Combine(ModuleDirectory, "Compiled", "x64_dynamic", "lib", "eego-SDK.dll"));

PublicAdditionalLibraries.Add(Path.Combine(PrecompiledFolder, "Brainflow.lib"));
PublicAdditionalLibraries.Add(Path.Combine(PrecompiledFolder, "DataHandler.lib"));
PublicAdditionalLibraries.Add(Path.Combine(PrecompiledFolder, "BoardController.lib"));
PublicAdditionalLibraries.Add(Path.Combine(PrecompiledFolder, "MLModule.lib"));

PublicDelayLoadDLLs.Add("BoardController.dll");
PublicDelayLoadDLLs.Add("DataHandler.dll");
PublicDelayLoadDLLs.Add("MLModule.dll");

AddRuntimeDependencies(PrecompiledFolder, "*.dll");
}
if(Target.Platform == UnrealTargetPlatform.Mac)
{
String PrecompiledFolder = Path.Combine(ModuleDirectory, "Compiled", "macos", "lib");
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Compiled", "macos", "inc"));
PublicLibraryPaths.Add(Path.Combine(ModuleDirectory, "Compiled", "macos", "lib"));
PublicAdditionalLibraries.Add("libBrainflow.a");
PublicDelayLoadDLLs.Add("libDataHandler.dylib");
PublicDelayLoadDLLs.Add("libBoardController.dylib");
PublicDelayLoadDLLs.Add("libMLModule.dylib");
RuntimeDependencies.Add("$(TargetOutputDir)/libBoardController.dylib", Path.Combine(ModuleDirectory, "Compiled", "macos", "lib", "libBoardController.dylib"));
RuntimeDependencies.Add("$(TargetOutputDir)/libDataHandler.dylib", Path.Combine(ModuleDirectory, "Compiled", "macos", "lib", "libDataHandler.dylib"));
RuntimeDependencies.Add("$(TargetOutputDir)/libGanglionLib.dylib", Path.Combine(ModuleDirectory, "Compiled", "macos", "lib", "libGanglionLib.dylib"));
RuntimeDependencies.Add("$(TargetOutputDir)/libMLModule.dylib", Path.Combine(ModuleDirectory, "Compiled", "macos", "lib", "libMLModule.dylib"));
RuntimeDependencies.Add("$(TargetOutputDir)/libneurosdk-shared.dylib", Path.Combine(ModuleDirectory, "Compiled", "macos", "lib", "libneurosdk-shared.dylib"));
RuntimeDependencies.Add("$(TargetOutputDir)/libBrainBitLib.dylib", Path.Combine(ModuleDirectory, "Compiled", "macos", "lib", "libBrainBitLib.dylib"));

PublicAdditionalLibraries.Add(Path.Combine(PrecompiledFolder, "libBrainflow.a"));

PublicDelayLoadDLLs.Add(Path.Combine(PrecompiledFolder, "libBoardController.dylib"));
PublicDelayLoadDLLs.Add(Path.Combine(PrecompiledFolder, "libDataHandler.dylib"));
PublicDelayLoadDLLs.Add(Path.Combine(PrecompiledFolder, "libMLModule.dylib"));

AddRuntimeDependencies(PrecompiledFolder, "*.dylib");
}
if(Target.Platform == UnrealTargetPlatform.Linux)
{
String PrecompiledFolder = Path.Combine(ModuleDirectory, "Compiled", "linux", "lib");
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Compiled", "linux", "inc"));
PublicLibraryPaths.Add(Path.Combine(ModuleDirectory, "Compiled", "linux", "lib"));
PublicAdditionalLibraries.Add("libBrainflow.a");
PublicDelayLoadDLLs.Add("libDataHandler.so");
PublicDelayLoadDLLs.Add("libBoardController.so");
PublicDelayLoadDLLs.Add("libMLModule.so");
RuntimeDependencies.Add("$(TargetOutputDir)/libBoardController.so", Path.Combine(ModuleDirectory, "Compiled", "linux", "lib", "libBoardController.so"));
RuntimeDependencies.Add("$(TargetOutputDir)/libDataHandler.so", Path.Combine(ModuleDirectory, "Compiled", "linux", "lib", "libDataHandler.so"));
RuntimeDependencies.Add("$(TargetOutputDir)/libGanglionLib.so", Path.Combine(ModuleDirectory, "Compiled", "linux", "lib", "libGanglionLib.so"));
RuntimeDependencies.Add("$(TargetOutputDir)/libMLModule.so", Path.Combine(ModuleDirectory, "Compiled", "linux", "lib", "libMLModule.so"));
RuntimeDependencies.Add("$(TargetOutputDir)/libunicorn.so", Path.Combine(ModuleDirectory, "Compiled", "linux", "lib", "libunicorn.so"));
RuntimeDependencies.Add("$(TargetOutputDir)/libBrainBitLib.so", Path.Combine(ModuleDirectory, "Compiled", "linux", "lib", "libBrainBitLib.so"));
RuntimeDependencies.Add("$(TargetOutputDir)/libeego-SDK.so", Path.Combine(ModuleDirectory, "Compiled", "linux", "lib", "libeego-SDK.so"));

PublicAdditionalLibraries.Add(Path.Combine(PrecompiledFolder, "libBrainflow.a"));

PublicDelayLoadDLLs.Add(Path.Combine(PrecompiledFolder, "libBoardController.so"));
PublicDelayLoadDLLs.Add(Path.Combine(PrecompiledFolder, "libDataHandler.so"));
PublicDelayLoadDLLs.Add(Path.Combine(PrecompiledFolder, "libMLModule.so"));

AddRuntimeDependencies(PrecompiledFolder, "*.so");
}
}

public void AddRuntimeDependencies(string FolderPath, string Extension)
{
List<string> Files = Directory.GetFiles(FolderPath, Extension, SearchOption.AllDirectories).ToList();
foreach (string File in Files)
{
RuntimeDependencies.Add(Path.Combine(FolderPath, File));
Console.WriteLine(Name + "adding runtime dependency:" + File);
}
}
}
125 changes: 114 additions & 11 deletions BrainFlowPlugin/Source/BrainFlowPlugin/Private/BrainFlowPlugin.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,123 @@
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.

#include "BrainFlowPlugin.h"

#define LOCTEXT_NAMESPACE "FBrainFlowPluginModule"
#include <Interfaces/IPluginManager.h>

#define RUN_EXAMPLE 1

#ifdef RUN_EXAMPLE
#include <iostream>
#include <stdlib.h>
#include <string>

#include "board_shim.h"
#include "data_filter.h"
#endif

#ifdef RUN_EXAMPLE
template <typename T>
void UEPrint(const T& In)
{
std::stringstream ss;
ss << In;
std::string dataString = ss.str();

void FBrainFlowPluginModule::StartupModule() {
// This code will execute after your module is loaded into memory; the exact
// timing is specified in the .uplugin file per-module
// Unreal's UE_LOG stops at the first '/n', so we are going to remove them from the string so we can see the full message
std::erase(dataString, '\n');

const FString StringMessage = UTF8_TO_TCHAR(dataString.c_str());

UE_LOG(LogTemp, Warning, TEXT("[Data] %s"), *StringMessage);
}

void FBrainFlowPluginModule::ShutdownModule() {
// This function may be called during shutdown to clean up your module. For
// modules that support dynamic reloading, we call this function before
// unloading the module.
int RunExample()
{
if(IsRunningCommandlet())
{
return 0;
}

BoardShim::enable_dev_board_logger ();

struct BrainFlowInputParams params;
int res = 0;
int board_id = static_cast<int>(BoardIds::SYNTHETIC_BOARD);
// use synthetic board for demo
BoardShim *board = new BoardShim (board_id, params);

board->prepare_session ();
board->start_stream ();

FPlatformProcess::Sleep(5);

board->stop_stream ();
BrainFlowArray<double, 2> data = board->get_board_data ();
board->release_session ();
std::cout << "Original data:" << std::endl << data << std::endl;
UEPrint(data);

// apply filters
int sampling_rate = BoardShim::get_sampling_rate (static_cast<int>(BoardIds::SYNTHETIC_BOARD));
std::vector<int> eeg_channels = BoardShim::get_eeg_channels (board_id);
for (int i = 0; i < eeg_channels.size (); i++)
{
switch (i)
{
// just for test and demo - apply different filters to different eeg channels
// signal filtering methods work in-place
case 0:
DataFilter::perform_lowpass (data.get_address (eeg_channels[i]),
data.get_size (1), BoardShim::get_sampling_rate (board_id), 50.0, 3,
static_cast<int>(FilterTypes::BUTTERWORTH_ZERO_PHASE), 0);
break;
case 1:
DataFilter::perform_highpass (data.get_address (eeg_channels[i]),
data.get_size (1), BoardShim::get_sampling_rate (board_id), 3.0, 5,
static_cast<int>(FilterTypes::CHEBYSHEV_TYPE_1_ZERO_PHASE), 1);
break;
case 2:
DataFilter::perform_bandpass (data.get_address (eeg_channels[i]),
data.get_size (1), BoardShim::get_sampling_rate (board_id), 3.0, 45.0, 3,
static_cast<int>(FilterTypes::BESSEL_ZERO_PHASE), 0);
break;
case 3:
DataFilter::perform_bandstop (data.get_address (eeg_channels[i]),
data.get_size (1), BoardShim::get_sampling_rate (board_id), 48.0, 62.0, 4,
static_cast<int>(FilterTypes::BUTTERWORTH), 0);
break;
default:
DataFilter::remove_environmental_noise (data.get_address (eeg_channels[i]),
data.get_size (1), BoardShim::get_sampling_rate (board_id),
static_cast<int>(NoiseTypes::FIFTY));
break;
}
}
std::cout << "Filtered data:" << std::endl << data << std::endl;
UEPrint(data);

delete board;
return res;
}
#endif

void FBrainFlowPluginModule::StartupModule()
{
const FString DllDirectory = IPluginManager::Get().FindPlugin(TEXT("BrainFlowPlugin"))->GetBaseDir() / TEXT("Source/BrainFlowPlugin/Compiled/x64_dynamic/lib/");

#undef LOCTEXT_NAMESPACE
FPlatformProcess::PushDllDirectory(*DllDirectory);
#if PLATFORM_WINDOWS
FPlatformProcess::GetDllHandle(*FPaths::Combine(DllDirectory, TEXT("BoardController.dll")));
FPlatformProcess::GetDllHandle(*FPaths::Combine(DllDirectory, TEXT("DataHandler.dll")));
FPlatformProcess::GetDllHandle(*FPaths::Combine(DllDirectory, TEXT("MLModule.dll")));
#endif
FPlatformProcess::PopDllDirectory(*DllDirectory);

#ifdef RUN_EXAMPLE
RunExample();
#endif
}

void FBrainFlowPluginModule::ShutdownModule()
{
}

IMPLEMENT_MODULE(FBrainFlowPluginModule, BrainFlowPlugin)
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

#include "board_shim.h"
#include "data_filter.h"
#include "ml_model.h"

class FBrainFlowPluginModule : public IModuleInterface
{
public:

/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ python tools/build.py --clear-build-dir --cmake-install-prefix %FULL_PATH_TO_CLO
# to use debug version you need to add --debug flag
```

##### MacOS ARM64

Compile brainflow using:
```
cd brainflow
python tools/build.py --clear-build-dir --cmake-install-prefix %FULL_PATH_TO_CLONED_FOLDER%/BrainFlowPlugin/Source/BrainFlowPlugin/Compiled/macos --cmake-osx-architectures=arm64
# to use debug version you need to add --debug flag
```

##### Win32

Compile brainflow using:
Expand Down

0 comments on commit da8513c

Please sign in to comment.