CactusOSC 0.6.4

dotnet add package CactusOSC --version 0.6.4
                    
NuGet\Install-Package CactusOSC -Version 0.6.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CactusOSC" Version="0.6.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CactusOSC" Version="0.6.4" />
                    
Directory.Packages.props
<PackageReference Include="CactusOSC" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CactusOSC --version 0.6.4
                    
#r "nuget: CactusOSC, 0.6.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CactusOSC@0.6.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CactusOSC&version=0.6.4
                    
Install as a Cake Addin
#tool nuget:?package=CactusOSC&version=0.6.4
                    
Install as a Cake Tool

CactusOSC

a simple, powerful, easy to use c# Open Sound Control sending and receiving library, built entirely in c#, from the ground up, for .NET and c#. its not the fastest in the world, nor does it make the least allocations, but it sure is nice to use!

it comes fully featured with:

  • array support
  • nesting support
  • bundle support
  • Strong .NET object model
  • a complete set of osc object classes
  • a built in osc send and receive udp server
  • a built in osc send and receive tcp server
  • multithreading
  • Automatic type-tag generation
  • automatic sizing
  • guaranteed send and receive ordering
  • polling model
  • Messages are immutable after creation
  • Bundle hierarchy is never flattened
  • full OSC 1.1 bundle hierarchy preservation
  • OSC 1.1 compliance
  • zero dependencies besides the standard library

just create and start an OSCServer object and you are good to go! messages will automatically be processed and queued, and building messages is easy, just assemble them out of the provided classes. or, if you aren't using UDP or TCP, or just want to get your hands dirty, use the RawOSCConverter class to manually convert your object trees into sendable data and back!

there is no real documentation, but it should be understandable with just the types file and some trial and error. in leu of documentation, have a complete example program:

using CactusOSC;
namespace demo
{
    public class OSCMaster
    {
        const string OSCServerAddress = "127.0.0.1";
        const string receiveAddress = "127.0.0.1";
        const UInt16 sendPort = 8000;
        const UInt16 receivePort = 9000;
        public OSCMaster()
        {

        }
        public OSCPackage finalBundle;
        public void testTCP()
        {
            
            
            RawOSCConverter testConverter = new RawOSCConverter();
            OSCMessage demoMessage = new OSCMessage("/demo");

            OSCInt testInt = new OSCInt(43110);
            OSCString testString = new OSCString("test");
            OSCFloat testFloat = new OSCFloat(3.14f);
            OSCBlob testBlob = new OSCBlob(testConverter.EncodeOSCPackage(demoMessage));
            OSCLong testLong = new OSCLong(43110L);
            OSCTimeTag testTimeTag = new OSCTimeTag(new OSCTimeTagValue(0, 1));
            OSCDouble testDouble = new OSCDouble(3.14d);
            OSCNonstandardString testNonstandardString = new OSCNonstandardString("test");
            OSCChar testChar = new OSCChar('c');
            OSCColor testColor = new OSCColor(255, 0, 0, 255);
            OSCMIDI testMidi = new OSCMIDI(0, 0x9c, 0x0, 0x7f);
            OSCBool testBool = new OSCBool(true);
            OSCNil testNil = new OSCNil();
            OSCInfinitum testInf = new OSCInfinitum();

            OSCValue[] templateOSCArray = new OSCValue[14] { testInt, testString, testFloat, testBlob, testLong, testTimeTag, testDouble, testNonstandardString, testChar, testColor, testMidi, testBool, testNil, testInf };


            OSCArray testArray = new OSCArray(templateOSCArray);

            OSCValue[] messageArguments = new OSCValue[15] { testArray, testInt, testString, testFloat, testBlob, testLong, testTimeTag, testDouble, testNonstandardString, testChar, testColor, testMidi, testBool, testNil, testInf };

            OSCMessage testMessage = new OSCMessage("/test", messageArguments);

            OSCBundleElement testElement = new OSCBundleElement(testMessage);

            OSCBundleElement[] bundlePayloads = new OSCBundleElement[2] { testElement, testElement };

            OSCBundle packageToSend = new OSCBundle(bundlePayloads);
            this.finalBundle = packageToSend;
            Task.Run(externalServer);
            OSCTCPServer testServer1= new OSCTCPServer();
            testServer1.InitiateConnection(IPAddress.Loopback, 6000, true, 50000, false, 640000, true, true, true, 50000, OSCQueueDropMode.DropNewest, OSCQueueDropMode.Wait);
            
            while (true)
            {
                testServer1.WaitForOSCPackageReception();
                
                OSCPackage received;

                if (testServer1.TryReceiveOSCPackage(out received))
                {
                    Console.WriteLine(received.ToString());
                }
                else
                {
                    Console.WriteLine("none received!");
                }

                
            }

        }

        public async Task externalServer()
        {
            OSCTCPServer testServer0= new OSCTCPServer();
            testServer0.AcceptConnection(6000, false, IPAddress.Any, true, 30000, false, 64000, true, true, true, 50000, OSCQueueDropMode.DropNewest, OSCQueueDropMode.Wait);
            while (true)
            {
                testServer0.SendOSCPackage(this.finalBundle);
                testServer0.WaitForSendCompletion();
                await Task.Delay(1000);
            }
        }
        public void testUDP()
        {
            OSCUDPServer testServer = new OSCUDPServer();
            testServer.StartOSCServer(receivePort, IPAddress.Any, receivePort, IPAddress.Parse(OSCServerAddress), true, true, 50000, OSCQueueDropMode.DropOldest, OSCQueueDropMode.Wait);
            RawOSCConverter testConverter = new RawOSCConverter();
            OSCMessage demoMessage = new OSCMessage("/demo");

            OSCInt testInt = new OSCInt(43110);
            OSCString testString = new OSCString("test");
            OSCFloat testFloat = new OSCFloat(3.14f);
            OSCBlob testBlob = new OSCBlob(testConverter.EncodeOSCPackage(demoMessage));
            OSCLong testLong = new OSCLong(43110L);
            OSCTimeTag testTimeTag = new OSCTimeTag(new OSCTimeTagValue(0, 1));
            OSCDouble testDouble = new OSCDouble(3.14d);
            OSCNonstandardString testNonstandardString = new OSCNonstandardString("test");
            OSCChar testChar = new OSCChar('c');
            OSCColor testColor = new OSCColor(255, 0, 0, 255);
            OSCMIDI testMidi = new OSCMIDI(0, 0x9c, 0x0, 0x7f);
            OSCBool testBool = new OSCBool(true);
            OSCNil testNil = new OSCNil();
            OSCInfinitum testInf = new OSCInfinitum();

            OSCValue[] templateOSCArray = new OSCValue[14] { testInt, testString, testFloat, testBlob, testLong, testTimeTag, testDouble, testNonstandardString, testChar, testColor, testMidi, testBool, testNil, testInf };


            OSCArray testArray = new OSCArray(templateOSCArray);

            OSCValue[] messageArguments = new OSCValue[15] { testArray, testInt, testString, testFloat, testBlob, testLong, testTimeTag, testDouble, testNonstandardString, testChar, testColor, testMidi, testBool, testNil, testInf };

            OSCMessage testMessage = new OSCMessage("/test", messageArguments);

            OSCBundleElement testElement = new OSCBundleElement(testMessage);

            OSCBundleElement[] bundlePayloads = new OSCBundleElement[2] { testElement, testElement };

            OSCBundle packageToSend = new OSCBundle(bundlePayloads);

            while (true)
            {

                long startTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
                testServer.SendOSCPackage(packageToSend);
                testServer.WaitForSendCompletion();
                testServer.WaitForOSCPackageReception();
                long endTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
                long elapsed = endTime - startTime;
                Console.WriteLine(elapsed.ToString());
                OSCPackage received;

                if (testServer.TryReceiveOSCPackage(out received))
                {
                    Console.WriteLine(received.ToString());
                }
                else
                {
                    Console.WriteLine("none received!");
                }

                Thread.Sleep(100);
            }
        }
    }
}

end of example program;

i will say that Incoming messages are buffered internally in an ordered queue. Applications should poll frequently enough to prevent unbounded backlog growth. also Timetags are preserved but not scheduled.

enjoy!

copyright 2026 RedCactus5

CactusOSC is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

CactusOSC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with CactusOSC. If not, see https://www.gnu.org/licenses/.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.6.4 106 8/20/2026
0.6.3 109 8/20/2026 0.6.3 is deprecated because it is no longer maintained.
0.6.2 127 8/20/2026 0.6.2 is deprecated because it is no longer maintained.
0.6.1 114 8/20/2026 0.6.1 is deprecated because it is no longer maintained.
0.6.0 112 8/20/2026 0.6.0 is deprecated.
0.4.0 129 8/9/2026 0.4.0 is deprecated because it is no longer maintained.
0.3.10 123 8/9/2026 0.3.10 is deprecated because it is no longer maintained.
0.3.9 118 8/9/2026 0.3.9 is deprecated because it is no longer maintained.
0.3.8 122 8/9/2026 0.3.8 is deprecated because it is no longer maintained.
0.3.7 120 8/9/2026 0.3.7 is deprecated because it is no longer maintained.
0.3.6 160 8/1/2026 0.3.6 is deprecated because it is no longer maintained.
0.3.5 120 8/1/2026 0.3.5 is deprecated because it is no longer maintained.
0.3.4 130 8/1/2026 0.3.4 is deprecated because it is no longer maintained.
0.3.3 122 8/1/2026 0.3.3 is deprecated because it is no longer maintained.
0.3.2 131 8/1/2026 0.3.2 is deprecated because it is no longer maintained.
0.3.1 126 7/31/2026 0.3.1 is deprecated because it is no longer maintained.
0.3.0 128 7/31/2026 0.3.0 is deprecated because it is no longer maintained.
0.2.7 133 7/17/2026 0.2.7 is deprecated because it is no longer maintained.
0.2.6 128 7/17/2026 0.2.6 is deprecated because it is no longer maintained.
0.2.5 128 7/17/2026 0.2.5 is deprecated because it is no longer maintained.
Loading failed