BuildSoft.OscCore
1.2.1.1
dotnet add package BuildSoft.OscCore --version 1.2.1.1
NuGet\Install-Package BuildSoft.OscCore -Version 1.2.1.1
<PackageReference Include="BuildSoft.OscCore" Version="1.2.1.1" />
paket add BuildSoft.OscCore --version 1.2.1.1
#r "nuget: BuildSoft.OscCore, 1.2.1.1"
// Install BuildSoft.OscCore as a Cake Addin #addin nuget:?package=BuildSoft.OscCore&version=1.2.1.1 // Install BuildSoft.OscCore as a Cake Tool #tool nuget:?package=BuildSoft.OscCore&version=1.2.1.1
OscCore
A performance-oriented OSC (Open Sound Control) library for .NET.
Versions and Platforms
Releases are checked for compatibility with the latest release of these versions.
- .NET Standard 2.1
Installation
Download & import the .nupkg from the Releases page.
I can also download from NuGet Package Manager. See nuget.org for the NuGet package latest version.
Usage
Receiving messages
Using Code
Adding address handlers
There are several different kinds of method that can be registered with a server via script.
Single method
You can register a single callback, to be executed on the server's background thread immediately when a message is received, by calling oscServer.TryAddMethod
.
If you have no need to queue a method to be called on the main thread, you probably want this one.
var Server = OscServer.GetOrCreate(7000);
// add a single callback that reads message values at `/layers/1/opacity`
Server.TryAddMethod("/layers/1/opacity", ReadValues);
void ReadValues(OscMessageValues values)
{
// call ReadElement methods here to extract values
}
Method pair
You can register a pair of methods to an address by calling oscServer.TryAddMethodPair
.
These pairs consist of two methods, with the main thread one being optional.
- Runs on background thread, immediate execution, just like single methods
- Runs on main thread, queued on the next frame
This is useful for invoking events on the main thread, or any other use case that needs a main thread api. Read the message values in the first method.
var server = OscServer.GetOrCreate(7000);
float messageValue = 0.0f;
void ReadValues(OscMessageValues values)
{
messageValue = values.ReadFloatElement(0);
}
void MainThreadMethod()
{
// do something with MessageValue on the main thread
}
public CallbackPairExample()
{
// add a pair of methods for the OSC address "/layers/2/color/red"
server.TryAddMethodPair("/layers/2/color/red", ReadValues, MainThreadMethod);
}
Reading Message Values
Reading values from incoming messages is done on a per-element basis, using methods named like Read<Type>Element(int elementIndex)
.
Your value-reading methods will probably look something like this.
// these methods would be registered as background thread callbacks for an address
int ReadSingleIntMessage(OscMessageValues values)
{
return values.ReadIntElement(0);
}
int ReadTripleFloatMessage(OscMessageValues values)
{
float x = values.ReadFloatElement(0);
float y = values.ReadFloatElement(1);
float z = values.ReadFloatElement(2);
}
Most data types offer an Unchecked
version of the method that is slightly faster, and still safe to use if you know for sure what data type an element is.
double ReadUncheckedDoubleMessage(OscMessageValues values)
{
return values.ReadFloat64ElementUnchecked(0);
}
Monitor Callbacks
If you just want to inspect message, you can add a monitor callback to be able to inspect every incoming message.
A monitor callback is an Action<BlobString, OscMessageValues>
, where the blob string is the address.
Sending Messages
Using Code
OscWriter handles serialization of individual message elements.
OscClient wraps a writer and sends whole messages.
Sending of complex messages with multiple elements hasn't been abstracted yet - take a look at the methods in OscClient
to see how to send any message you need.
OscClient Client = new OscClient("127.0.0.1", 7000);
// single a single float element message
Client.Send("/layers/1/opacity", 0.5f);
// send a blob
byte[] Blob = new byte[256];
Client.Send("/blobs", Blob, Blob.Length);
// send a string
Client.Send("/layers/3/name", "Textural");
Additional safety checks
Define OSCCORE_SAFETY_CHECKS
in your project to have reads of message elements be bounds-checked. It amounts to making sure the element you asked for isn't beyond the number of elements in the message.
Protocol Support Details
All OSC 1.0 types, required and non-standard are supported.
The notable parts missing from the spec for the initial release are:
Matching incoming Address Patterns
"A received OSC Message must be disptched to every OSC method in the current OSC Address Space whose OSC Address matches the OSC Message's OSC Address Pattern"
Currently, an exact address match is required for incoming messages. If our address space has two methods:
/layer/1/opacity
/layer/2/opacity
and we get a message at
/layer/?/opacity
, we should invoke both messages.Right now, we would not invoke either message. We would only invoke messages received at exactly one of the two addresses. This is the first thing that i think will be implemented after initial release - some of the other packages also lack this feature, and you can get far without it.
Syncing to a source of absolute time
"An OSC server must have access to a representation of the correct current absolute time".
I've implemented this, as a class that syncs to an external NTP server, but without solving clock sync i'm not ready to add it.
Respecting bundle timestamps
"If the time represented by the OSC Time Tag is before or equal to the current time, the OSC Server should invoke the methods immediately... Otherwise the OSC Time Tag represents a time in the future, and the OSC server must store the OSC Bundle until the specified time and then invoke the appropriate OSC Methods."
This is simple enough to implement, but without a mechanism for clock synchronization, it could easily lead to errors. If the sending application worked from a different time source than OscCore, events would happen at the wrong time.
Performance Details
Strings and Addresses
Every OSC message starts with an "address", specified as an ascii string.
It's perfectly reasonable to represent this address in C# as a standard string
, which is how other libraries work.
However, because strings in C# are immutable & UTF16, every time we receive a message from the network, this now requires us to allocate a new string
, and in the process expand the received ascii string's bytes (where each character is a single byte) to UTF16 (each char
is two bytes).
OscCore eliminates both
- string allocation
- the need to convert ascii bytes to UTF16
This works through leveraging the BlobHandles package.
Incoming message's addresses are matched directly against their unmanaged ascii bytes.
This has two benefits
- no memory is allocated when a message is received
- takes less CPU time to parse a message
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Runtime.CompilerServices.Unsafe (>= 6.0.0)
-
.NETStandard 2.1
- System.Runtime.CompilerServices.Unsafe (>= 6.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on BuildSoft.OscCore:
Package | Downloads |
---|---|
VRCOscLib
A OSC library for VRChat |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated | |
---|---|---|---|
1.2.1.1 | 1,104 | 12/24/2022 | |
1.2.1 | 1,181 | 12/19/2022 | |
1.2.0 | 325 | 12/19/2022 | |
1.1.3 | 299 | 12/17/2022 | |
1.1.2 | 527 | 12/9/2022 | |
1.1.1 | 1,484 | 11/8/2022 | |
1.1.0 | 788 | 9/20/2022 | |
1.0.5 | 3,657 | 2/23/2022 | |
1.0.4 | 467 | 2/23/2022 | |
1.0.3 | 955 | 2/22/2022 | |
1.0.2 | 979 | 2/21/2022 | |
1.0.1 | 456 | 2/20/2022 | |
1.0.0 | 454 | 2/20/2022 |