add support for OSC blob

This commit is contained in:
monsieurgustav
2016-12-20 16:37:49 +01:00
parent 8b946cb312
commit a6c68e2d6c
5 changed files with 160 additions and 38 deletions
@@ -8,24 +8,20 @@ struct FOscDataElemStruct
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
int32 Type;
UPROPERTY()
int64 Data;
FOscDataElemStruct() : Type(0), Data(0)
{ }
enum
{
FLOAT = 0,
INT = 1,
BOOL = 2,
FLOAT = 0,
INT = 1,
BOOL = 2,
STRING = 3,
BLOB = 4,
};
//-------------------------------------------------------------------------
public:
FOscDataElemStruct() : Type(0), Data(0)
{
}
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.
template <class T>
T GetValue() const
@@ -150,6 +167,14 @@ struct FOscDataElemStruct
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();
}
@@ -163,6 +188,13 @@ private:
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);
}
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)
{
@@ -84,6 +89,14 @@ void UOscFunctionLibrary::PushString(const TArray<FOscDataElemStruct> & input, F
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)
{
@@ -105,6 +118,11 @@ FName UOscFunctionLibrary::AsString(const FOscDataElemStruct & input)
return input.GetValue<FName>();
}
TArray<uint8> UOscFunctionLibrary::AsBlob(const FOscDataElemStruct & input)
{
return input.GetValue<TArray<uint8>>();
}
FOscDataElemStruct UOscFunctionLibrary::FromBool(bool input)
{
@@ -134,6 +152,13 @@ FOscDataElemStruct UOscFunctionLibrary::FromString(FName input)
return result;
}
FOscDataElemStruct UOscFunctionLibrary::FromBlob(const TArray<uint8> & input)
{
FOscDataElemStruct result;
result.SetBlob(input);
return result;
}
namespace
{
@@ -188,6 +213,11 @@ namespace
{
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)
{
@@ -28,6 +28,10 @@ public:
UFUNCTION(BlueprintPure, Category=OSC)
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.
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
@@ -45,6 +49,10 @@ public:
UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input"))
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
UFUNCTION(BlueprintPure, Category=OSC)
@@ -62,6 +70,10 @@ public:
UFUNCTION(BlueprintPure, Category=OSC)
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
UFUNCTION(BlueprintPure, Category=OSC)
@@ -79,6 +91,10 @@ public:
UFUNCTION(BlueprintPure, Category=OSC)
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.
@@ -131,6 +131,25 @@ static void SendMessage(TCircularQueue<std::tuple<FName, TArray<FOscDataElemStru
{
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);
}
+49 -24
View File
@@ -4,8 +4,7 @@ UE4-OSC
OSC plugin for Unreal Engine 4 to send and receive OSC messages with blueprints!
Tutorial
========
# 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
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
Integration
===========
# Integration
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.
Usage
=====
# Usage
- Receiver:
Set the listening port in the plugin settings.
### Receiver
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
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 to" addresses in the plugin settings.
Set the "Send Targets" addresses in the plugin settings. (Edit/Project Settings/Plugins/OSC)
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.
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.
Optionally, set the OSC_ENGINE_VERSION value (in Source/OSC/Private/Osc.h) to compile for a specific engine version.