Link Search Menu Expand Document

Writing a processor with Avendish

Avendish describes a media processor through a C++ type: members declare its inputs, outputs and controls, and a processing function performs the work. The optional halp helpers reduce boilerplate. Audio, MIDI, values, CPU images, GPU resources and geometry have different port contracts; choosing the right one lets score supply the corresponding cables and controls.

Start with the upstream introduction and examples. Use the Avendish revision bundled with your score version.

Create an add-on

Use the score Avendish template and follow its README to initialize names and UUIDs. Keep those UUIDs stable after distributing the plug-in: documents use them to identify processes. Set the name, description and other package metadata in addon.json.

Github template creation

The template’s SDK workflow builds the platform packages. Install the generated package and manifest in the Packages directory configured in score, usually Documents/ossia/score/packages/<your-addon>.

Build against a matching SDK

  • OSSIA_SDK is the compiler and dependency SDK used to build score itself, available from ossia/sdk.
  • The score SDK supplies headers for run-time JIT add-ons. For an external CMake build, SCORE_SDK points to its exported usr directory, containing include and lib/cmake/score. Obtain it from the matching application build or the package manager’s SDK entry.

Score SDK

See Release build for dependency SDK setup. On Linux and Windows, put its llvm/bin first on PATH; on macOS, use Xcode. Official Windows builds use llvm-mingw. MSYS2 CLANG64 is the development alternative; MSVC is only needed for exceptional Qt WebEngine builds.

For example, after setting SCORE_SDK and OSSIA_SDK to the correct directories and selecting that compiler:

cmake -S /path/to/your-addon -B addon-build -GNinja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_MODULE_PATH="$SCORE_SDK/lib/cmake/score" \
  -DSCORE_SDK="$SCORE_SDK" \
  -DOSSIA_SDK="$OSSIA_SDK" \
  -DCMAKE_INSTALL_PREFIX=/path/to/Documents/ossia/score/packages/your-addon
cmake --build addon-build --parallel
cmake --install addon-build

Restart score after rebuilding a binary. On Windows, close score before replacing its DLL. Match the score build, architecture and compiler ABI, and keep the generated localaddon.json with the installed files.

For your own score checkout, use the template’s developer-build configuration. ScoreExternalAddon.cmake selects the SDK or developer build mode.

Compile at run time

Desktop builds with the JIT plug-in compile source add-ons at run time on Linux, macOS and Windows (llvm-mingw). Install the matching score SDK through the package manager.

Place a source package with "kind": "addon" in its addon.json in the configured Packages directory. Use an add-on template supported by the run-time compiler, and restart score after source changes.

For a one-file compilation check:

ossia-score --no-restore --compile-node /absolute/path/to/MyProcessor.hpp

--compile-node accepts an Avendish object in a .hpp or .cpp file. Declare its class or struct and a UUID with halp_meta(uuid, "..."), using the UUID generated for your processor.

For a complete source add-on:

ossia-score --no-restore --compile-addon /absolute/path/to/your-addon

These commands compile and register the processor, then exit, reporting compiler errors in the log. They are provided by the JIT plug-in and do not appear in the core --help output. Standalone headers in a library Nodes directory are not discovered automatically.

Ports, scheduling and layouts

The following interfaces map to score’s ports and controls:

Need Interface and score behavior
Variable number of ports halp::dynamic_port<T> represents repeated ports of one type. Read the actual instances through its ports collection; do not treat it as one list-valued cable. See the dynamic-port example.
Time-dependent processing Use the appropriate tick information for frames, musical time or logical time rather than a wall-clock timer. Temporal metadata controls whether the process has timeline content; it is distinct from single_exec (once per execution) and process_exec (start/stop callbacks). See temporality concepts and playback state.
Files and directories File ports and halp::folder_port expose file/folder controls. halp::folder_combobox names a sibling folder port and optional extension filter; score populates the choices at edit/load time and refreshes them when the folder changes. Its value is the selected file name, not the folder itself. See folder combobox.
GPU processing Use the draw or compute interfaces and the shader language supported by the selected backend.
Scene processing A port member carrying ossia::scene_spec scene transports scene data through geometry ports. This is a score-specific extension. See SceneConcepts.hpp for dirty flags and GpuUtils.hpp for transport.
Custom controls layout A nested ui structure arranges controls using layout-based UIs. In addition to boxes, grids, groups and tabs, score supports section (titled padded vertical group), table (rows under shared column titles), and strip_detail (summary cells selecting a detail page). See layout.hpp and the score binding.

In score’s default metadata mapping, the temporal tag sets Process::ProcessFlags::SupportsTemporal; otherwise the object gets SupportsLasting. A dynamic-port interface sets DynamicPorts. If you override Info::flags(), you replace that default mapping and must describe the process’s capabilities yourself. Controls which change port counts are marked as changing ports by the binding. See Metadata.hpp before overriding these flags; they describe editor/process capabilities, not a substitute for implementing timed execution.

Other hosts support different ports and layouts; see the “Supported bindings” notes in the upstream manual.

Qt Creator workflow

Open the add-on’s CMakeLists.txt in Qt Creator, reuse the configured build directory, and set the run executable to the matching score application. Add a CMake install step so building updates the package directory before launch.

For direct editing of a low-level graph node inside a document, see C++ JIT; that process uses a different entry point from the Avendish object command above.