Skip to content
This repository has been archived by the owner on May 9, 2024. It is now read-only.

Some details #1

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 55 additions & 50 deletions include/PicoOSC/PicoOSC.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,27 @@ static constexpr auto MAX_MESSAGES = 255;
// The maximum size of an OSC bundle's timestamp is 8 bytes.
static constexpr auto MAX_TIMESTAMP_SIZE = 8;

// The maximum size of an OSC bundle's timestamp is 8 bytes.
// The maximum size of an OSC bundle's timetag is 8 bytes.
static constexpr auto MAX_TIMETAG_SIZE = 8;

// From
// https://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c
template<typename T>
T swap_endian(T u)
auto swap_endian(T uns) -> T
{
static_assert(CHAR_BIT == 8, "CHAR_BIT != 8");

union
{
T u;
T uns;
unsigned char u8[sizeof(T)];
} source, dest;

source.u = u;
source.uns = uns;

for (size_t k = 0; k < sizeof(T); k++)
dest.u8[k] = source.u8[sizeof(T) - k - 1];
for (size_t k = 0; k < sizeof(T); k++) {
dest.u8[k] = source.u8[sizeof(T) - k - 1];
}

return dest.u;
}
Expand All @@ -62,17 +63,21 @@ using namespace std;
class OSCClient
{
public:
OSCClient(const OSCClient&) = default;
OSCClient(OSCClient&&) = delete;
auto operator=(const OSCClient&) -> OSCClient& = default;
auto operator=(OSCClient&&) -> OSCClient& = delete;
// Constructor that takes an address as a string and a port number
OSCClient(const char* address, uint16_t port)
{
// Convert the address string to an ip_addr_t
ipaddr_aton(address, &mAddr);
ipaddr_aton(address, &m_addr);

// Set the port
this->mPort = port;
this->m_port = port;

// Create a new OSC pcb
mPcb = udp_new();
m_pcb = udp_new();

// Bind the pcb to the port
// const auto result = udp_bind(mPcb, &mAddr, port);
Expand All @@ -88,7 +93,7 @@ class OSCClient
~OSCClient()
{
// Close the pcb
udp_remove(mPcb);
udp_remove(m_pcb);
}

// Send packet
Expand All @@ -101,7 +106,7 @@ class OSCClient
std::memcpy(p->payload, buffer, size);

// Attempt to send the packet
const auto error = udp_sendto(mPcb, p, &mAddr, mPort);
const auto error = udp_sendto(m_pcb, p, &m_addr, m_port);

// Free packet buffer
pbuf_free(p);
Expand All @@ -116,9 +121,9 @@ class OSCClient
}

private:
udp_pcb* mPcb;
ip_addr_t mAddr;
uint16_t mPort;
udp_pcb* m_pcb{};
ip_addr_t m_addr{};
uint16_t m_port;
};

// This class represents a valid OSC message that can be sent over the via UDP
Expand All @@ -132,8 +137,8 @@ class OSCMessage
public:
// Constructor
OSCMessage()
: mBuffer {0}
, mBufferSize {0}
: m_buffer {0}
, m_bufferSize {0}
{
clear();
}
Expand All @@ -154,12 +159,12 @@ class OSCMessage
}

// Add the address to the buffer
std::memcpy(mBuffer + mBufferSize, address, std::strlen(address));
mBufferSize += std::strlen(address);
std::memcpy(m_buffer + m_bufferSize, address, std::strlen(address));
m_bufferSize += std::strlen(address);

// Add a null terminator
mBuffer[mBufferSize] = '\0';
mBufferSize += 1;
m_buffer[m_bufferSize] = '\0';
m_bufferSize += 1;

// Pad the buffer to the next 4-byte boundary
padBuffer();
Expand All @@ -168,9 +173,9 @@ class OSCMessage
void padBuffer()
{
// Pad the buffer to the next 4-byte boundary
while (mBufferSize % 4 != 0) {
mBuffer[mBufferSize] = '\0';
mBufferSize += 1;
while (m_bufferSize % 4 != 0) {
m_buffer[m_bufferSize] = '\0';
m_bufferSize += 1;
}
}

Expand All @@ -180,7 +185,7 @@ class OSCMessage
void add(T value)
{
// Check if there is enough space in the buffer
if (mBufferSize + 4 > MAX_MESSAGE_SIZE) {
if (m_bufferSize + 4 > MAX_MESSAGE_SIZE) {
printf("Not enough space in buffer\n");
return;
}
Expand All @@ -191,20 +196,20 @@ class OSCMessage

// Add type tag
// Add comma before type tag
mBuffer[mBufferSize] = ',';
mBufferSize += 1;
m_buffer[m_bufferSize] = ',';
m_bufferSize += 1;

if constexpr (isFloat) {
mBuffer[mBufferSize] = 'f';
m_buffer[m_bufferSize] = 'f';
} else if constexpr (isInt) {
mBuffer[mBufferSize] = 'i';
m_buffer[m_bufferSize] = 'i';
} else if constexpr (isString) {
mBuffer[mBufferSize] = 's';
m_buffer[m_bufferSize] = 's';
} else {
printf("Unsupported type\n");
}

mBufferSize += 1;
m_bufferSize += 1;

// For simple types like floats and integers we can just copy the value to
// the buffer
Expand All @@ -215,30 +220,30 @@ class OSCMessage
padBuffer();

// Copy to the buffer
std::memcpy(mBuffer + mBufferSize, &value, 4);
mBufferSize += 4;
std::memcpy(m_buffer + m_bufferSize, &value, 4);
m_bufferSize += 4;

} else if constexpr (isString) {
// For strings it's a bit more complex

// Add a null terminator
mBuffer[mBufferSize] = '\0';
mBufferSize += 1;
m_buffer[m_bufferSize] = '\0';
m_bufferSize += 1;

// Swap the endianness of all chars
for (int i = 0; i < std::strlen(value); i++) {
mBuffer[mBufferSize + i] = swap_endian<char>(value[i]);
m_buffer[m_bufferSize + i] = swap_endian<char>(value[i]);
}

// Add a null terminator
mBuffer[mBufferSize] = '\0';
mBufferSize += 1;
m_buffer[m_bufferSize] = '\0';
m_bufferSize += 1;

padBuffer();

// Copy the string to the buffer
std::memcpy(mBuffer + mBufferSize, value, std::strlen(value));
mBufferSize += std::strlen(value);
std::memcpy(m_buffer + m_bufferSize, value, std::strlen(value));
m_bufferSize += std::strlen(value);

} else {
printf("Unsupported type\n");
Expand All @@ -249,37 +254,37 @@ class OSCMessage
}

// Get the data
const char* data() const
auto data() const -> const char*
{
return mBuffer;
return m_buffer;
}

// Get the size
std::size_t size() const
auto size() const -> std::size_t
{
return mBufferSize;
return m_bufferSize;
}

// Clear the buffer
void clear()
{
mBufferSize = 0;
std::memset(mBuffer, 0, MAX_MESSAGE_SIZE);
m_bufferSize = 0;
std::memset(m_buffer, 0, MAX_MESSAGE_SIZE);
}

// Send the message over the network using a OSC Client
auto send(OSCClient& client) -> bool
{
const auto error = client.send(mBuffer, mBufferSize);
const auto error = client.send(m_buffer, m_bufferSize);

return error == ERR_OK;
}

// Print the buffer
void print()
{
for (std::size_t i = 0; i < mBufferSize; i++) {
std::cout << mBuffer[i];
for (std::size_t i = 0; i < m_bufferSize; i++) {
std::cout << m_buffer[i];
}
std::cout << std::endl;
}
Expand All @@ -288,10 +293,10 @@ class OSCMessage

private:
// Buffer
std::size_t mBufferSize;
std::size_t m_bufferSize;

// A buffer based on char as the basic type
char mBuffer[MAX_MESSAGE_SIZE];
char m_buffer[MAX_MESSAGE_SIZE];
};

} // namespace picoosc