mirror of
https://github.com/storytold/UE4-OSC.git
synced 2026-10-09 00:09:43 +00:00
add SendOscBundle blueprint function
This commit is contained in:
@@ -135,68 +135,148 @@ FOscDataElemStruct UOscFunctionLibrary::FromString(FName input)
|
||||
}
|
||||
|
||||
|
||||
void UOscFunctionLibrary::SendOsc(FName Address, const TArray<FOscDataElemStruct> & Data, int32 TargetIndex)
|
||||
namespace
|
||||
{
|
||||
if(!Address.IsValid())
|
||||
bool isValidAddress(const FName & Address)
|
||||
{
|
||||
UE_LOG(LogOSC, Error, TEXT("Empty OSC address"));
|
||||
return;
|
||||
if(!Address.IsValid())
|
||||
{
|
||||
UE_LOG(LogOSC, Error, TEXT("Empty OSC address"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Address.GetDisplayNameEntry()->IsWide())
|
||||
{
|
||||
const auto tmp = Address.GetPlainNameString();
|
||||
UE_LOG(LogOSC, Error, TEXT("Invalid OSC address \"%s\": ASCII only"), *tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Address.GetPlainANSIString()[0] != '/')
|
||||
{
|
||||
const auto tmp = Address.GetPlainNameString();
|
||||
UE_LOG(LogOSC, Error, TEXT("Invalid OSC address \"%s\": must start with '/'"), *tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if(Address.GetDisplayNameEntry()->IsWide())
|
||||
void appendMessage(osc::OutboundPacketStream & output, FName Address, const TArray<FOscDataElemStruct> & Data)
|
||||
{
|
||||
const auto tmp = Address.GetPlainNameString();
|
||||
UE_LOG(LogOSC, Error, TEXT("Invalid OSC address \"%s\": ASCII only"), *tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
if(Address.GetPlainANSIString()[0] != '/')
|
||||
{
|
||||
const auto tmp = Address.GetPlainNameString();
|
||||
UE_LOG(LogOSC, Error, TEXT("Invalid OSC address \"%s\": must start with '/'"), *tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
static_assert(sizeof(uint8) == sizeof(char), "Cannot cast uint8 to char");
|
||||
uint8 buffer[1024];
|
||||
|
||||
osc::OutboundPacketStream output((char *)buffer, sizeof(buffer));
|
||||
output << osc::BeginMessage(Address.GetPlainANSIString());
|
||||
for(const auto & elem : Data)
|
||||
{
|
||||
if(elem.IsFloat())
|
||||
{
|
||||
output << (float)elem.AsFloatValue();
|
||||
}
|
||||
else if(elem.IsInt())
|
||||
{
|
||||
output << (int32)elem.AsIntValue();
|
||||
}
|
||||
else if(elem.IsBool())
|
||||
{
|
||||
output << elem.AsBoolValue();
|
||||
}
|
||||
else if(elem.IsString())
|
||||
{
|
||||
output << elem.AsStringValue().GetPlainANSIString();
|
||||
}
|
||||
|
||||
output << osc::BeginMessage(Address.GetPlainANSIString());
|
||||
if(output.State() != osc::SUCCESS)
|
||||
{
|
||||
UE_LOG(LogOSC, Error, TEXT("OSC Send Message Error: %s"), osc::errorString(output.State()));
|
||||
return;
|
||||
}
|
||||
|
||||
for(const auto & elem : Data)
|
||||
{
|
||||
if(elem.IsFloat())
|
||||
{
|
||||
output << (float)elem.AsFloatValue();
|
||||
}
|
||||
else if(elem.IsInt())
|
||||
{
|
||||
output << (int32)elem.AsIntValue();
|
||||
}
|
||||
else if(elem.IsBool())
|
||||
{
|
||||
output << elem.AsBoolValue();
|
||||
}
|
||||
else if(elem.IsString())
|
||||
{
|
||||
output << elem.AsStringValue().GetPlainANSIString();
|
||||
}
|
||||
|
||||
if(output.State() != osc::SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
output << osc::EndMessage;
|
||||
}
|
||||
|
||||
TArray<uint8> GlobalBuffer(TArray<uint8>(), 1024);
|
||||
}
|
||||
|
||||
void UOscFunctionLibrary::SendOsc(FName Address, const TArray<FOscDataElemStruct> & Data, int32 TargetIndex)
|
||||
{
|
||||
if(!isValidAddress(Address))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static_assert(sizeof(uint8) == sizeof(char), "Cannot cast uint8 to char");
|
||||
|
||||
osc::OutboundPacketStream output((char *)GlobalBuffer.GetData(), GlobalBuffer.Max());
|
||||
check(reinterpret_cast<const void *>(GlobalBuffer.GetData()) == reinterpret_cast<const void *>(output.Data()));
|
||||
|
||||
appendMessage(output, Address, Data);
|
||||
|
||||
if(output.State() == osc::OUT_OF_BUFFER_MEMORY_ERROR)
|
||||
{
|
||||
GlobalBuffer.Reserve(GlobalBuffer.Max() * 2); // not enough memory: double the size
|
||||
SendOsc(Address, Data, TargetIndex); // try again
|
||||
return;
|
||||
}
|
||||
|
||||
if(output.State() == osc::SUCCESS)
|
||||
{
|
||||
GetMutableDefault<UOscSettings>()->Send(GlobalBuffer.GetData(), output.Size(), TargetIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogOSC, Error, TEXT("OSC Send Message Error: %s"), osc::errorString(output.State()));
|
||||
}
|
||||
}
|
||||
|
||||
void UOscFunctionLibrary::SendOscBundle(const TArray<FOscMessageStruct> & Messages, int32 TargetIndex)
|
||||
{
|
||||
static_assert(sizeof(uint8) == sizeof(char), "Cannot cast uint8 to char");
|
||||
|
||||
osc::OutboundPacketStream output((char *)GlobalBuffer.GetData(), GlobalBuffer.Max());
|
||||
check(reinterpret_cast<const void *>(GlobalBuffer.GetData()) == reinterpret_cast<const void *>(output.Data()));
|
||||
|
||||
output << osc::BeginBundle();
|
||||
for(const auto & message : Messages)
|
||||
{
|
||||
if(!isValidAddress(message.Address))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
appendMessage(output, message.Address, message.Data);
|
||||
|
||||
if(output.State() == osc::OUT_OF_BUFFER_MEMORY_ERROR)
|
||||
{
|
||||
GlobalBuffer.Reserve(GlobalBuffer.Max() * 2); // not enough memory: double the size
|
||||
SendOscBundle(Messages, TargetIndex); // try again
|
||||
return;
|
||||
}
|
||||
if(output.State() != osc::SUCCESS)
|
||||
{
|
||||
UE_LOG(LogOSC, Error, TEXT("OSC Send Bundle Error: %s"), osc::errorString(output.State()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
output << osc::EndMessage;
|
||||
output << osc::EndBundle;
|
||||
|
||||
if(output.State() != osc::SUCCESS)
|
||||
if(output.State() == osc::OUT_OF_BUFFER_MEMORY_ERROR)
|
||||
{
|
||||
UE_LOG(LogOSC, Error, TEXT("OSC Send Message Error: %s"), osc::errorString(output.State()));
|
||||
GlobalBuffer.Reserve(GlobalBuffer.Max() * 2); // not enough memory: double the size
|
||||
SendOscBundle(Messages, TargetIndex); // try again
|
||||
return;
|
||||
}
|
||||
|
||||
check(reinterpret_cast<const void *>(buffer) == reinterpret_cast<const void *>(output.Data()));
|
||||
GetMutableDefault<UOscSettings>()->Send(buffer, output.Size(), TargetIndex);
|
||||
if(output.State() == osc::SUCCESS)
|
||||
{
|
||||
GetMutableDefault<UOscSettings>()->Send(GlobalBuffer.GetData(), output.Size(), TargetIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogOSC, Error, TEXT("OSC Send Bundle Error: %s"), osc::errorString(output.State()));
|
||||
}
|
||||
}
|
||||
|
||||
int32 UOscFunctionLibrary::AddSendOscTarget(FString IpPort)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "OscDataElemStruct.h"
|
||||
#include "OscMessageStruct.h"
|
||||
#include "OscFunctionLibrary.generated.h"
|
||||
|
||||
|
||||
@@ -88,6 +89,14 @@ public:
|
||||
UFUNCTION(BlueprintCallable, Category=OSC, meta=(AutoCreateRefTerm = "Data"))
|
||||
static void SendOsc(FName Address, const TArray<FOscDataElemStruct> & Data, int32 TargetIndex);
|
||||
|
||||
/**
|
||||
* @brief Send several OSC messages in an OSC bundle.
|
||||
* @param Messages of the bundle.
|
||||
* @param Index index of the destination, -1 for all destinations. (SendTarget list of the plugin settings)
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category=OSC)
|
||||
static void SendOscBundle(const TArray<FOscMessageStruct> & Messages, int32 TargetIndex);
|
||||
|
||||
/**
|
||||
* @brief Add Ip:Port to the available OSC send targets.
|
||||
* @param IpPort "ip:port". e.g. "192.168.0.1:7777"
|
||||
|
||||
@@ -321,7 +321,7 @@ bool OutboundPacketStream::IsBundleInProgress() const
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs )
|
||||
{
|
||||
check( !IsMessageInProgress() )
|
||||
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableBundleSpace();
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -344,6 +344,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator&
|
||||
|
||||
check( IsBundleInProgress() )
|
||||
check( !IsMessageInProgress() )
|
||||
check( state_ == SUCCESS )
|
||||
|
||||
EndElement( messageCursor_ );
|
||||
|
||||
@@ -354,6 +355,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator&
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs )
|
||||
{
|
||||
check( !IsMessageInProgress() )
|
||||
check( state_ == SUCCESS )
|
||||
|
||||
state_ = CheckForAvailableMessageSpace( rhs.addressPattern );
|
||||
|
||||
@@ -387,6 +389,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator&
|
||||
(void) rhs;
|
||||
|
||||
check( IsMessageInProgress() )
|
||||
check( state_ == SUCCESS )
|
||||
|
||||
std::size_t typeTagsCount = end_ - typeTagsCurrent_;
|
||||
|
||||
@@ -436,6 +439,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator&
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(0);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -449,6 +453,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs )
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs )
|
||||
{
|
||||
(void) rhs;
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(0);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -462,6 +467,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs )
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs )
|
||||
{
|
||||
(void) rhs;
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(0);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -474,6 +480,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(4);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -488,6 +495,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(4);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -518,6 +526,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( char rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(4);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -532,6 +541,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( char rhs )
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(4);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -546,6 +556,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs )
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(4);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -560,6 +571,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs )
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(8);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -574,6 +586,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(8);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -588,6 +601,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs )
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(8);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -622,6 +636,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -644,6 +659,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -666,6 +682,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
|
||||
{
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) );
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -690,6 +707,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs )
|
||||
{
|
||||
(void) rhs;
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(0);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
@@ -702,6 +720,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rh
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs )
|
||||
{
|
||||
(void) rhs;
|
||||
check( state_ == SUCCESS )
|
||||
state_ = CheckForAvailableArgumentSpace(0);
|
||||
if(state_ == SUCCESS)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user