o
odin.langpkg.dev
packages / library / odin-osc

odin-osc

0c13753library

Open Sound Control in pure Odin lang, ported from vosc

MIT · updated 7 months ago

odin-osc

A pure Odin implementation of the OSC(Open Sound Control) 1.0 protocol.

Ported from funatsufumiya/vosc (based on Okabintaro/nosc)

Usage

Sender

see sender example.

// NOTE: partial code, not full code

msg := osc.OscMessage{address = "/hello", args = {int(1), f32(2.3), "world"}}

buf := make([dynamic]u8)
defer delete(buf)

osc.add_message(&buf, msg)

bytes_written, send_err := net.send_udp(udp_socket, buf[:], endpoint)

Receiver (using filter)

filter messages

show all messages even if wrapped in OSC Bundle.

see filter messages example.

// NOTE: partial code, not full code

buf : [2048]u8
buf = {}

for {
    bytes_read, remote_endpoint, recv_err := net.recv_udp(udp_socket, buf[:])
    if recv_err != net.UDP_Recv_Error.None || bytes_read == 0 {
        continue
    }

    fmt.printfln("bytes_read: {}", bytes_read)

    packet, err := osc.read_packet(buf[:bytes_read])
    defer osc.delete_osc_packet(packet)
    
    if err != nil {
        fmt.eprintfln("failed to parse OSC packet: {}", err)
        continue
    }

    osc.filter_messages(&packet, proc(msg: ^osc.OscMessage) {
        fmt.printfln("{}", msg.address)
        fmt.printfln("{}", msg.args)
    })
}

filter addresses

see filter addresses example.

// NOTE: partial code, not full code

buf : [2048]u8
buf = {}

for {
    bytes_read, remote_endpoint, recv_err := net.recv_udp(udp_socket, buf[:])
    if recv_err != net.UDP_Recv_Error.None || bytes_read == 0 {
        continue
    }

    // fmt.printfln("bytes_read: {}", bytes_read)

    packet, err := osc.read_packet(buf[:bytes_read])
    defer osc.delete_osc_packet(packet)

    if err != nil {
        fmt.eprintfln("failed to parse OSC packet: {}", err)
        continue
    }

    osc.filter_address(&packet, "/hello", proc(msg: ^osc.OscMessage) {
        fmt.printfln("{}", msg.address)
        fmt.printfln("{}", msg.args)
    })
    osc.filter_address(&packet, "/test", proc(msg: ^osc.OscMessage) {
        fmt.printfln("{}", msg.address)
        fmt.printfln("{}", msg.args)
    })
}

Receiver (plain)

This example shows how to access OSC Bundle directly (such as time, etc)

see receiver plain example.

// NOTE: partial code, not full code

buf : [2048]u8
buf = {}

for {
    bytes_read, remote_endpoint, recv_err := net.recv_udp(udp_socket, buf[:])
    if recv_err != net.UDP_Recv_Error.None || bytes_read == 0 {
        continue
    }

    fmt.printfln("bytes_read: {}", bytes_read)

    packet, err := osc.read_packet(buf[:bytes_read])
    defer osc.delete_osc_packet(packet)

    if err != nil {
        fmt.eprintfln("failed to parse OSC packet: {}", err)
        continue
    }

    #partial switch _ in packet {
    case osc.OscBundle:
        bundle := packet.(osc.OscBundle)
        fmt.printfln("bundle time: {}", bundle.time)

        // result for example:
        // bundle time: 2025-12-08 05:01:53.132265599 +0000 UTC
    }

    fmt.printfln("{}", packet)

    // results for example:

    // bytes_read: 64
    // OscBundle{time = 2025-12-08 05:11:47.131840699 +0000 UTC, contents = [OscMessage{address = "/_samplerate", args = [60]}, OscMessage{address = "/chan1", args = [0.6064136]}]}
    // bytes_read: 32
    // OscMessage{address = "/hello", args = [1, 2, "hello"]}
}

Tests

$ odin test tests

License

see LICENSE.