A tiny OSC macro daemon.
osc-macro listens for incoming OSC UDP messages on port 2223, matches them against a small macro file, and sends any configured response messages back to the sender. It was primarily developed for use with the Behringer WING and its missing macro system, so you can build your own macros for things like CC buttons. It is still intended to stay small and portable, so it can also run on other platforms.
This project is work in progress. The core trigger/response flow is usable, but the feature set is still evolving.
- Define one or more macros in a plain text file.
- Each macro has a trigger message and optional response messages.
- When a trigger matches an incoming OSC message, the matching responses are built and sent.
- Responses can be either direct OSC snippets or response factory invocations.
- Response factories let you generate a response dynamically from named arguments, which is useful when the final OSC address or payload depends on runtime input.
Response factories are registered in linked translation units and can then be referenced from the macro file by name.
The included binary ships an echo factory in its own translation unit. It expects the first argument to be an OSC address string, then copies any remaining arguments into the outgoing message.
Example:
/channel/3/test()
> echo("/hello/world" 1 2 3.14f)
This keeps the macro file compact while still allowing responses that are assembled dynamically in C. To add another factory, define it in a separate translation unit and register it with OSC_REGISTER_MACRO_RESPONSE_FACTORY("name", callback);. This global registration is done using a constructor function, so this is currently only supported by GCC and Clang.
For periodic or protocol-specific background work, the daemon exposes a separate main-loop hook API. Hooks are also registered from linked translation units with a constructor, then loaded into the runtime before the main loop starts.
This is a good fit for the Behringer WING keepalive, because the hook can watch OSC_MAIN_LOOP_EVENT_TICK and send /*s whenever its timer expires without mixing that logic into macro parsing or response factories.
Example:
static bool my_hook(osc_main_loop_event_type event_type, osc_main_loop_context *context)
{
if (event_type != OSC_MAIN_LOOP_EVENT_TICK)
return true;
return true;
}
OSC_REGISTER_MAIN_LOOP_HOOK("my_hook", my_hook);The factory callback is expected to have the following signature:
void my_factory_callback(tosc_message_builder *builder, tosc_message_argument args[], size_t arg_count);- OSC argument wildcards in trigger messages.
- Dynamic response arguments derived from wildcarded input arguments.
The included macros.txt shows the expected format:
/channel/1/test("hello")
> /channel/1/another()
> /channel/1/third(1 2 3.14f "test")
> echo("/hello/world" 1 2 3.14f)
For OpenWrt, build with the default target:
make
./osc-macro macros.txtFor other platforms, or when you want a local build without -lrt, use:
make dev
./osc-macro macros.txtTo lock the daemon to a specific peer, pass an optional IPv4 address. In that mode, the daemon only accepts packets from that source address and sends responses back to it:
./osc-macro macros.txt 192.168.1.50As mentioned above, you can build the package for OpenWRT with the default target. The resulting .ipk or .apk file can then be installed on your OpenWRT device.
-
To build and package for an OpenWRT target, you need to first set up the correct OpenWRT SDK for your OpenWRT version and target platform. You can find precompiled SDKs for many versions and platforms on the OpenWRT downloads page.
-
After downloading and extracting the SDK, navigate to the SDK root directory and copy the
osc-macrorepository into thepackagedirectory. Inside the respository then run./configure-openwrt.sh
to make a build environment for the OpenWRT SDK.
-
From the SDK root directory, run the following commands to update the package feeds and build the package:
./scripts/feeds update -a ./scripts/feeds install -a make defcofig make package/osc-macro/compile V=s
-
The resulting
.ipkor.apkfile will be located in thebin/packages/<architecture>/base/osc-macro_<version>_<architecture>.<ipk|apk>directory. -
You can then transfer this file to your OpenWRT device (e.g. using
scp) and install it using theopkgorapkpackage manager:opkg install /path/to/osc-macro_<version>-<architecture>.ipk
or
apk add --allow-untrusted /path/to/osc-macro_<version>-<architecture>.apk
This project incorporates code from:
- tinyosc - Copyright (C) 2015 mhroth Licensed under the ISC License
- nob.h - Copyright (C) 2024 Alexey Kutepov Licensed under the MIT License
matteolutz.de · GitHub @matteolutz · Email info@matteolutz.de