mirror of
https://github.com/storytold/UE4-OSC.git
synced 2026-10-25 08:19:30 +00:00
add support for OSC blob
This commit is contained in:
@@ -8,24 +8,20 @@ struct FOscDataElemStruct
|
|||||||
{
|
{
|
||||||
GENERATED_USTRUCT_BODY()
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
int32 Type;
|
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
int64 Data;
|
|
||||||
|
|
||||||
FOscDataElemStruct() : Type(0), Data(0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FLOAT = 0,
|
FLOAT = 0,
|
||||||
INT = 1,
|
INT = 1,
|
||||||
BOOL = 2,
|
BOOL = 2,
|
||||||
STRING = 3,
|
STRING = 3,
|
||||||
|
BLOB = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
public:
|
||||||
|
|
||||||
|
FOscDataElemStruct() : Type(0), Data(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void SetFloat(double value)
|
void SetFloat(double value)
|
||||||
{
|
{
|
||||||
@@ -112,6 +108,27 @@ struct FOscDataElemStruct
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void SetBlob(TArray<uint8> value)
|
||||||
|
{
|
||||||
|
Data = 0;
|
||||||
|
Type = BLOB;
|
||||||
|
Blob = MakeShared<TArray<uint8>>(std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
const TArray<uint8> & AsBlobValue() const
|
||||||
|
{
|
||||||
|
check(IsBlob());
|
||||||
|
static const TArray<uint8> empty;
|
||||||
|
return Blob.IsValid() ? *Blob : empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBlob() const
|
||||||
|
{
|
||||||
|
return Type == BLOB;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Cast the value to T.
|
/// Cast the value to T.
|
||||||
template <class T>
|
template <class T>
|
||||||
T GetValue() const
|
T GetValue() const
|
||||||
@@ -150,6 +167,14 @@ struct FOscDataElemStruct
|
|||||||
return Cast<T, isString>::eval(value);
|
return Cast<T, isString>::eval(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(IsBlob())
|
||||||
|
{
|
||||||
|
const bool isBlob = std::is_same<T, TArray<uint8>>::value;
|
||||||
|
if(isBlob)
|
||||||
|
{
|
||||||
|
return Cast<T, isBlob>::eval(AsBlobValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
return T();
|
return T();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +188,13 @@ private:
|
|||||||
return T();
|
return T();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 Type;
|
||||||
|
|
||||||
|
int64 Data;
|
||||||
|
|
||||||
|
TSharedPtr<TArray<uint8>> Blob;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ void UOscFunctionLibrary::PopString(const TArray<FOscDataElemStruct> & input, TA
|
|||||||
PopValueImpl(input, output, Value);
|
PopValueImpl(input, output, Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UOscFunctionLibrary::PopBlob(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, TArray<uint8> & Value)
|
||||||
|
{
|
||||||
|
PopValueImpl(input, output, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void UOscFunctionLibrary::PushBool(const TArray<FOscDataElemStruct> & input, bool Value, TArray<FOscDataElemStruct> & output)
|
void UOscFunctionLibrary::PushBool(const TArray<FOscDataElemStruct> & input, bool Value, TArray<FOscDataElemStruct> & output)
|
||||||
{
|
{
|
||||||
@@ -84,6 +89,14 @@ void UOscFunctionLibrary::PushString(const TArray<FOscDataElemStruct> & input, F
|
|||||||
output.Add(elem);
|
output.Add(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UOscFunctionLibrary::PushBlob(const TArray<FOscDataElemStruct> & input, const TArray<uint8> & Value, TArray<FOscDataElemStruct> & output)
|
||||||
|
{
|
||||||
|
output = input;
|
||||||
|
FOscDataElemStruct elem;
|
||||||
|
elem.SetBlob(Value);
|
||||||
|
output.Add(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool UOscFunctionLibrary::AsBool(const FOscDataElemStruct & input)
|
bool UOscFunctionLibrary::AsBool(const FOscDataElemStruct & input)
|
||||||
{
|
{
|
||||||
@@ -105,6 +118,11 @@ FName UOscFunctionLibrary::AsString(const FOscDataElemStruct & input)
|
|||||||
return input.GetValue<FName>();
|
return input.GetValue<FName>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TArray<uint8> UOscFunctionLibrary::AsBlob(const FOscDataElemStruct & input)
|
||||||
|
{
|
||||||
|
return input.GetValue<TArray<uint8>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FOscDataElemStruct UOscFunctionLibrary::FromBool(bool input)
|
FOscDataElemStruct UOscFunctionLibrary::FromBool(bool input)
|
||||||
{
|
{
|
||||||
@@ -134,6 +152,13 @@ FOscDataElemStruct UOscFunctionLibrary::FromString(FName input)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FOscDataElemStruct UOscFunctionLibrary::FromBlob(const TArray<uint8> & input)
|
||||||
|
{
|
||||||
|
FOscDataElemStruct result;
|
||||||
|
result.SetBlob(input);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -188,6 +213,11 @@ namespace
|
|||||||
{
|
{
|
||||||
output << elem.AsStringValue().GetPlainANSIString();
|
output << elem.AsStringValue().GetPlainANSIString();
|
||||||
}
|
}
|
||||||
|
else if(elem.IsBlob())
|
||||||
|
{
|
||||||
|
const TArray<uint8> & value = elem.AsBlobValue();
|
||||||
|
output << osc::Blob(value.GetData(), value.Num());
|
||||||
|
}
|
||||||
|
|
||||||
if(output.State() != osc::SUCCESS)
|
if(output.State() != osc::SUCCESS)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ public:
|
|||||||
UFUNCTION(BlueprintPure, Category=OSC)
|
UFUNCTION(BlueprintPure, Category=OSC)
|
||||||
static void PopString(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, FName & Value);
|
static void PopString(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, FName & Value);
|
||||||
|
|
||||||
|
/// Get the next value from an OSC message as a blob.
|
||||||
|
UFUNCTION(BlueprintPure, Category=OSC)
|
||||||
|
static void PopBlob(const TArray<FOscDataElemStruct> & input, TArray<FOscDataElemStruct> & output, TArray<uint8> & Value);
|
||||||
|
|
||||||
|
|
||||||
/// Add a boolean value to an OSC message.
|
/// Add a boolean value to an OSC message.
|
||||||
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
|
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
|
||||||
@@ -45,6 +49,10 @@ public:
|
|||||||
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
|
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
|
||||||
static void PushString(const TArray<FOscDataElemStruct> & input, FName Value, TArray<FOscDataElemStruct> & output);
|
static void PushString(const TArray<FOscDataElemStruct> & input, FName Value, TArray<FOscDataElemStruct> & output);
|
||||||
|
|
||||||
|
/// Add a blob to an OSC message.
|
||||||
|
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
|
||||||
|
static void PushBlob(const TArray<FOscDataElemStruct> & input, const TArray<uint8> & Value, TArray<FOscDataElemStruct> & output);
|
||||||
|
|
||||||
|
|
||||||
/// Interpret an OSC argument as a boolean
|
/// Interpret an OSC argument as a boolean
|
||||||
UFUNCTION(BlueprintPure, Category=OSC)
|
UFUNCTION(BlueprintPure, Category=OSC)
|
||||||
@@ -62,6 +70,10 @@ public:
|
|||||||
UFUNCTION(BlueprintPure, Category=OSC)
|
UFUNCTION(BlueprintPure, Category=OSC)
|
||||||
static FName AsString(const FOscDataElemStruct & input);
|
static FName AsString(const FOscDataElemStruct & input);
|
||||||
|
|
||||||
|
/// Interpret an OSC argument as a blob.
|
||||||
|
UFUNCTION(BlueprintPure, Category=OSC)
|
||||||
|
static TArray<uint8> AsBlob(const FOscDataElemStruct & input);
|
||||||
|
|
||||||
|
|
||||||
/// Create an OSC argument from a boolean
|
/// Create an OSC argument from a boolean
|
||||||
UFUNCTION(BlueprintPure, Category=OSC)
|
UFUNCTION(BlueprintPure, Category=OSC)
|
||||||
@@ -79,6 +91,10 @@ public:
|
|||||||
UFUNCTION(BlueprintPure, Category=OSC)
|
UFUNCTION(BlueprintPure, Category=OSC)
|
||||||
static FOscDataElemStruct FromString(FName input);
|
static FOscDataElemStruct FromString(FName input);
|
||||||
|
|
||||||
|
/// Create an OSC argument from a blob.
|
||||||
|
UFUNCTION(BlueprintPure, Category=OSC)
|
||||||
|
static FOscDataElemStruct FromBlob(const TArray<uint8> & input);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send an OSC message.
|
* @brief Send an OSC message.
|
||||||
|
|||||||
@@ -131,6 +131,25 @@ static void SendMessage(TCircularQueue<std::tuple<FName, TArray<FOscDataElemStru
|
|||||||
{
|
{
|
||||||
elem.SetString(FName(it->AsStringUnchecked()));
|
elem.SetString(FName(it->AsStringUnchecked()));
|
||||||
}
|
}
|
||||||
|
else if(it->IsBlob())
|
||||||
|
{
|
||||||
|
const void* buffer;
|
||||||
|
osc::osc_bundle_element_size_t size;
|
||||||
|
osc::Errors error = osc::SUCCESS;
|
||||||
|
it->AsBlobUnchecked(buffer, size, error);
|
||||||
|
|
||||||
|
TArray<uint8> blob;
|
||||||
|
if(size && !error)
|
||||||
|
{
|
||||||
|
blob.SetNumUninitialized(size);
|
||||||
|
FMemory::Memcpy(blob.GetData(), buffer, size);
|
||||||
|
}
|
||||||
|
else if(error)
|
||||||
|
{
|
||||||
|
UE_LOG(LogOSC, Warning, TEXT("OSC Received Message Error: %s"), osc::errorString(error));
|
||||||
|
}
|
||||||
|
elem.SetBlob(std::move(blob));
|
||||||
|
}
|
||||||
data.Add(elem);
|
data.Add(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ UE4-OSC
|
|||||||
OSC plugin for Unreal Engine 4 to send and receive OSC messages with blueprints!
|
OSC plugin for Unreal Engine 4 to send and receive OSC messages with blueprints!
|
||||||
|
|
||||||
|
|
||||||
Tutorial
|
# Tutorial
|
||||||
========
|
|
||||||
|
|
||||||
Dannington made a super tutorial!
|
Dannington made a super tutorial!
|
||||||
|
|
||||||
@@ -14,13 +13,12 @@ Watch it to properly install the plugin and get some brilliant ideas on how to u
|
|||||||
https://www.youtube.com/watch?v=GGGs-n-CKtY
|
https://www.youtube.com/watch?v=GGGs-n-CKtY
|
||||||
|
|
||||||
|
|
||||||
Also, go to the UE4 forum:
|
Also, go to the UE4 forum dedicated thread:
|
||||||
|
|
||||||
https://forums.unrealengine.com/showthread.php?49627-Plugin-OSC-for-UE4
|
https://forums.unrealengine.com/showthread.php?49627-Plugin-OSC-for-UE4
|
||||||
|
|
||||||
|
|
||||||
Integration
|
# Integration
|
||||||
===========
|
|
||||||
|
|
||||||
Install Visual Studio 2015 on Windows (Community edition works) or XCode on MaxOSX.
|
Install Visual Studio 2015 on Windows (Community edition works) or XCode on MaxOSX.
|
||||||
|
|
||||||
@@ -34,41 +32,68 @@ Run the "*.uproject" file: the plugin is compiled automatically.
|
|||||||
Alternatively, right-clic the "*.uproject" to generate Visual Studio or XCode project files.
|
Alternatively, right-clic the "*.uproject" to generate Visual Studio or XCode project files.
|
||||||
|
|
||||||
|
|
||||||
Usage
|
# Usage
|
||||||
=====
|
|
||||||
|
|
||||||
- Receiver:
|
### Receiver
|
||||||
|
|
||||||
Set the listening port in the plugin settings.
|
Set the listening port as "Receive From" in the plugin settings. (Edit/Project Settings/Plugins/OSC)
|
||||||
|
|
||||||
Add a OscReceiverComponent to your Blueprint class and bind the OnOscReceived custom event, or
|
Add a OscReceiverComponent to your Blueprint class and bind the OnOscReceived custom event, or
|
||||||
|
subclass the OscReceiverActor and bind the OnOscReceived custom event.
|
||||||
|
|
||||||
Subclass the OscReceiverActor and bind the OnOscReceived custom event.
|
The OnOscReceived event gives: the OSC address, the OSC parameters and the IP of the sender.
|
||||||
|
|
||||||
Use the PopFloat/Int/Bool/String functions, or standard array functions, to retrieve the OSC message parameters.
|
The OSC parameters is an array of OSC elements. To read the content, either:
|
||||||
|
- chain PopFloat/Int/Bool/String/Blob functions to get the first value, or
|
||||||
|
- use the standard GET function and AsFloat/Int/Bool/String/Blob functions to cast the element to its value. This is slightly more efficient.
|
||||||
|
|
||||||
|
### Sender
|
||||||
|
|
||||||
- Sender:
|
Set the "Send Targets" addresses in the plugin settings. (Edit/Project Settings/Plugins/OSC)
|
||||||
|
|
||||||
Set the "send to" addresses in the plugin settings.
|
|
||||||
|
|
||||||
Use the PushFloat/Int/Bool/String functions, or standard array functions, to build the OSC message parameters.
|
You can also add new targets dynamically, using the "Add Send Osc Target" function.
|
||||||
|
It is especially useful for "ping"-like behavior.
|
||||||
|
|
||||||
Use the SendOsc function to send the OSC message
|
Send a single message with "Send Osc" or a bundle of messages with "Send Osc Bundle".
|
||||||
|
|
||||||
Use the SendOscBundle function to send an OSC bundle (array of messages)
|
The "Send Osc" function takes: the OSC address, the OSC parameters and the "target index" of the destination.
|
||||||
|
|
||||||
|
Build the OSC parameters for a message:
|
||||||
|
- chain PushFloat/Int/Bool/String/Blob functions, or
|
||||||
|
- fill an array of "Osc Data Elem" with the standard array functions and the FromFloat/Int/Bool/String/Blob functions.
|
||||||
|
|
||||||
|
The "target index" refers to an index in the "Send Targets" array in the settings,
|
||||||
|
or to the result of the "Add Send Osc Target" function.
|
||||||
|
|
||||||
|
### Inputs (experimental)
|
||||||
|
|
||||||
- Inputs:
|
|
||||||
|
|
||||||
List the messages that should be UE4 inputs (like a game controller). A new input is created for each message.
|
List the messages that should be UE4 inputs (like a game controller). A new input is created for each message.
|
||||||
|
|
||||||
Bind OSC inputs to UE4 action in the usual "Input" project settings.
|
Bind OSC inputs to UE4 action in the usual "Input" project settings.
|
||||||
|
|
||||||
|
|
||||||
Engine version
|
# General information
|
||||||
=====
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
The plugin uses the standard UE4 logging system.
|
||||||
|
|
||||||
|
Check your logs (Window/Developers Tools/Output Log) before asking for help!
|
||||||
|
|
||||||
|
### String limitation
|
||||||
|
|
||||||
|
Historically, the plugin handles OSC string using "FName". Unfortunately, the length of
|
||||||
|
a "FName" is limited to 1024 characters. So this plugin does not handle long strings correctly.
|
||||||
|
|
||||||
|
If you need long strings, prefer using blobs.
|
||||||
|
|
||||||
|
### Blob
|
||||||
|
|
||||||
|
The OSC protocol supports buffers as "blob".
|
||||||
|
|
||||||
|
This plugin implements them as "Array<uint8>". It plays nicely with the "Extended Standard Library" plugin by "Low Entry".
|
||||||
|
|
||||||
|
|
||||||
|
# Engine version
|
||||||
|
|
||||||
Get the right branch for your engine version: "master" for the latest version, "before4.8" for 4.4, ..., 4.7, etc.
|
Get the right branch for your engine version: "master" for the latest version, "before4.8" for 4.4, ..., 4.7, etc.
|
||||||
|
|
||||||
Optionally, set the OSC_ENGINE_VERSION value (in Source/OSC/Private/Osc.h) to compile for a specific engine version.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user