[{"data":1,"prerenderedAt":72},["ShallowReactive",2],{"project-plugin-hostd-":3},{"page":4,"others":58},{"slug":5,"src":6,"title":6,"source":7,"toc":8,"html":57},"","README.md","https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fplugin-hostd\u002Fblob\u002Fb4ea6a9\u002FREADME.md",[9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54],{"id":10,"title":11},"install","Install",{"id":13,"title":14},"status","Status",{"id":16,"title":17},"try-it","Try it",{"id":19,"title":20},"protocol","Protocol",{"id":22,"title":23},"running","Running",{"id":25,"title":26},"placement","Placement",{"id":28,"title":29},"grouped-workers-against-one-process-per-plugin","Grouped workers against one process per plugin",{"id":31,"title":32},"verbs-the-daemon-adds","Verbs the daemon adds",{"id":34,"title":35},"verbs-a-worker-answers-by-instance","Verbs a worker answers, by instance",{"id":37,"title":38},"the-workers-own-feedback","The workers' own feedback",{"id":40,"title":41},"probing-a-plugin","Probing a plugin",{"id":43,"title":44},"pins","Pins",{"id":46,"title":47},"the-running-history","The running history",{"id":49,"title":50},"what-a-worker-must-do","What a worker must do",{"id":52,"title":53},"formats","Formats",{"id":55,"title":56},"who-runs-an-lv2-plugin","Who runs an LV2 plugin","\u003Ch1 id=\"plugin-hostd\">plugin-hostd\u003C\u002Fh1>\n\u003Cp>plugin-hostd runs your LV2 and CLAP audio plugins, each in a worker process of its own, and\nputs back any worker that dies. A plugin that crashes takes down its own worker and nothing\nelse. It is for anyone who runs plugins live on Linux, on a mixing console, a stage rig or a\nRaspberry Pi, and cannot let one bad plugin stop the show.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>A crash stays small: only the plugin's worker is lost, and it is respawned with the links the daemon made itself.\u003C\u002Fli>\n\u003Cli>Nothing to change in your controller: it speaks mod-host's socket protocol, same ports, same replies.\u003C\u002Fli>\n\u003Cli>LV2 through omx-clap-host's adapter, with mod-host for the plugins the adapter refuses, and CLAP through omx-clap-host, side by side.\u003C\u002Fli>\n\u003Cli>Audio never passes through the daemon; every worker is a JACK client, as in mod-host.\u003C\u002Fli>\n\u003Cli>A plugin that keeps crashing is singled out and given up on without touching its neighbours.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Three things it adds, each optional and taken or left on its own:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Plugin hosting: the LV2 and CLAP plugins hosted in workers, with a qualification on the device saying which are safe\nto load and how.\u003C\u002Fli>\n\u003Cli>Grouping: a controller's chain stays as it is; when several of its plugins may share one process, by their records,\nthey run in one worker, and the others alone.\u003C\u002Fli>\n\u003Cli>Panels: a plugin's control pages and its MOD GUI drawn from its one description, with omx-panel; a plugin's own GUI\nis kept.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"install\">Install\u003C\u002Fh2>\n\u003Cp>Fedora:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo dnf install https:\u002F\u002Fwww.openmixer.org\u002Frpm\u002Fopenmixer-release.noarch.rpm\nsudo dnf install plugin-hostd omx-clap-host\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Debian bookworm and trixie and Raspberry Pi OS (amd64 and arm64):\u003C\u002Fp>\n\u003Cpre>\u003Ccode>curl -fsSLO https:\u002F\u002Fwww.openmixer.org\u002Fdeb\u002Fopenmixer-release.deb &amp;&amp; sudo apt install .\u002Fopenmixer-release.deb\nsudo apt update &amp;&amp; sudo apt install plugin-hostd omx-clap-host\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The LV2 worker is mod-host, which Debian does not package; without it CLAP plugins still work.\u003C\u002Fp>\n\u003Ch2 id=\"status\">Status\u003C\u002Fh2>\n\u003Cp>What the continuous integration runs on every push:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>The daemon against stand-in workers that die on cue: placement, forwarding, the ledger, replay,\nattribution and the bound on a respawn storm. No JACK and no plugin are needed for this.\u003C\u002Fli>\n\u003Cli>The generated protocol files, README tables and man page checked against \u003Ccode>protocol.h\u003C\u002Fcode>, and\nevery guard broken on purpose to see its test go red.\u003C\u002Fli>\n\u003Cli>The daemon with a real CLAP worker (omx-clap-host) over PipeWire's JACK and over JACK2's \u003Ccode>jackd\u003C\u002Fcode>,\nincluding meters reaching the controller.\u003C\u002Fli>\n\u003Cli>RPMs (Fedora 44) and DEBs (bookworm and trixie) built and installed in a clean environment.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The LV2 worker (mod-host) is not run in CI; those steps stay in the Makefile for a machine that has\nmod-host and an LV2 bundle.\u003C\u002Fp>\n\u003Ch2 id=\"try-it\">Try it\u003C\u002Fh2>\n\u003Cp>Start the daemon, with pin checking off for a first try (it says when both ports accept):\u003C\u002Fp>\n\u003Cpre>\u003Ccode>echo 'require_pins 0' &gt; plugin-hostd.conf\nplugin-hostd -n -p 5555 -c plugin-hostd.conf\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>In another terminal, add an LV2 plugin, set its gain and ask where it runs\n(messages end in a NUL byte, which \u003Ccode>printf\u003C\u002Fcode> adds):\u003C\u002Fp>\n\u003Cpre>\u003Ccode>send() { printf '%s\\0' &quot;$1&quot; | nc -w3 127.0.0.1 5555 | tr '\\0' '\\n'; }\nsend &quot;add http:\u002F\u002Fplugin.org.uk\u002Fswh-plugins\u002Famp 0&quot;      # resp 0\nsend &quot;param_set 0 gain 6&quot;                              # resp 0\nsend &quot;param_get 0 gain&quot;                                # resp 0 6.0000\nsend &quot;worker_list&quot;                                     # resp 1 w1:&lt;pid&gt;:lv2:up:1:qualified:own:0\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The plugin now runs as JACK client \u003Ccode>effect_0\u003C\u002Fcode> in its own process. Link it in your graph as\nyou would a mod-host plugin. \u003Ccode>man plugin-hostd\u003C\u002Fcode> has the options; the full protocol is below.\u003C\u002Fp>\n\u003Cp>Using it from your own host (Zynthian, a Raspberry Pi, any Debian): \u003Ca href=\"\u002Fprojects\u002Fplugin-hostd\u002Fown-host\">docs\u002Fown-host.md\u003C\u002Fa>, nine commands from\nnothing to a plugin running.\u003C\u002Fp>\n\u003Cp>Under Zynthian on a Raspberry Pi 5: \u003Ca href=\"https:\u002F\u002Fopenmixer.org\u002Fdocs\u002Fzynthian\">https:\u002F\u002Fopenmixer.org\u002Fdocs\u002Fzynthian\u003C\u002Fa> says what it changes, how to install and use\nit and where it stands; the measurements are at \u003Ca href=\"https:\u002F\u002Fopenmixer.org\u002Fbenchmarks\">https:\u002F\u002Fopenmixer.org\u002Fbenchmarks\u003C\u002Fa>, and how they were taken, with the\ndesign of pins, chains and grouping, in the technical notes at \u003Ca href=\"https:\u002F\u002Fopenmixer.org\u002Fnotes\">https:\u002F\u002Fopenmixer.org\u002Fnotes\u003C\u002Fa>.\u003C\u002Fp>\n\u003Cp>Building from source: see \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fplugin-hostd\u002Fblob\u002Fb4ea6a9\u002FBUILDING.md\">BUILDING.md\u003C\u002Fa>. More about FreeMixer at \u003Ca href=\"https:\u002F\u002Fwww.openmixer.org\">https:\u002F\u002Fwww.openmixer.org\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"protocol\">Protocol\u003C\u002Fh2>\n\u003Cp>The protocol is the plugin-hostd protocol, a superset of mod-host's text protocol: any mod-host client works unchanged.\nIt is declared once, in \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fplugin-hostd-protocol\">plugin-hostd-protocol\u003C\u002Fa>, the library the daemon answers its controllers with; the wire\nprotocol for a reader of another host, mod-host's verbs on plugin-hostd and the verbs mod-host does not have, is its\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fplugin-hostd-protocol\u002Fblob\u002Fmain\u002Fdoc\u002Fprotocol.md\">doc\u002Fprotocol.md\u003C\u002Fa>.\u003C\u002Fp>\n\u003Cp>What it declares is installed with that library's development package (\u003Ccode>plugin-hostd-protocol-devel\u003C\u002Fcode>,\n\u003Ccode>libplugin-hostd-protocol-dev\u003C\u002Fcode>): the header \u003Ccode>&lt;plugin-hostd\u002Fprotocol.h&gt;\u003C\u002Fcode> with the placement syntax, the error codes, the\nfeedback events, the settings and the verbs (\u003Ccode>pkg-config --cflags plugin-hostd-protocol\u003C\u002Fcode>); the one verb table, its\ngrammar, and the protocol and mod-host's as JSON (\u003Ccode>pkg-config --variable=table\u003C\u002Fcode>, \u003Ccode>grammar\u003C\u002Fcode>, \u003Ccode>protocoljson\u003C\u002Fcode> and\n\u003Ccode>modhostjson\u003C\u002Fcode> of \u003Ccode>plugin-hostd-protocol\u003C\u002Fcode>). The verbs the daemon adds are its package of omx-contract's contract\ndirectory (\u003Ccode>plugin-hostd-protocol-contract\u003C\u002Fcode>). A refusal number omx-clap-host answers too carries omx-clap-core's\n\u003Ccode>reply.host.*\u003C\u002Fcode> code (package \u003Ccode>omx-clap-core-contract\u003C\u002Fcode>), the others plugin-hostd's \u003Ccode>reply.plugin-hostd.*\u003C\u002Fcode>: one name per\nnumber. The tables here and the man page's key list are generated from that header; this tree keeps no copy of it.\u003C\u002Fp>\n\u003Cp>This tree's development package installs what it declares beside the protocol: the schemas \u003Ccode>probe-output.schema.json\u003C\u002Fcode>\nfor the probe's document and \u003Ccode>preset.schema.json\u003C\u002Fcode> for the org.openmixer.preset file (\u003Ccode>protocoldir\u003C\u002Fcode> in the pkg-config\nfile of \u003Ccode>plugin-hostd\u003C\u002Fcode> is that directory), and \u003Ccode>&lt;plugin-hostd\u002Fpin.h&gt;\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"running\">Running\u003C\u002Fh2>\n\u003Cpre>\u003Ccode>plugin-hostd -n -p &lt;port&gt; [-f &lt;port&gt;] [-c plugin-hostd.conf]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>It prints \u003Ccode>plugin-hostd ready!\u003C\u002Fcode> once both ports accept.\u003C\u002Fp>\n\u003Cp>No worker exists until the first \u003Ccode>add\u003C\u002Fcode>. \u003Ccode>quit\u003C\u002Fcode> or SIGTERM stops every worker and the daemon;\nafter a SIGKILL the workers notice the parent gone (\u003Ccode>PR_SET_PDEATHSIG\u003C\u002Fcode>) and exit.\u003C\u002Fp>\n\u003Cp>Both ports listen on 127.0.0.1, so only programs on the same machine reach them. To control the daemon from\nanother machine, start it with \u003Ccode>--bind-address &lt;address&gt;\u003C\u002Fcode> or set \u003Ccode>bind_address\u003C\u002Fcode> in the settings; \u003Ccode>0.0.0.0\u003C\u002Fcode> is every\naddress of the machine. A controller is not authenticated and can load a plugin from any path, so do that only on a\nnetwork whose hosts you trust. A daemon that cannot listen on the address does not start. The workers it starts\nlisten on 127.0.0.1 whatever this says, and only the daemon talks to them.\u003C\u002Fp>\n\u003Cp>The settings live in a file, \u003Ccode>-c\u003C\u002Fcode>, \u003Ccode>$PLUGIN_HOSTD_CONF\u003C\u002Fcode> or\n\u003Ccode>~\u002F.config\u002Fplugin-hostd.conf\u003C\u002Fcode>, one \u003Ccode>key value\u003C\u002Fcode> per line:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>key\u003C\u002Fth>\n\u003Cth>default\u003C\u002Fth>\n\u003Cth>meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>mod_host\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>mod-host\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>worker for lv2 (a name on PATH or a path)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>clap_host\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>omx-clap-host\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>worker for clap\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>lv2_worker\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>auto\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>who runs an LV2 plugin: mod-host (the mod_host program), omx-clap-host (the clap_host program, through its LV2 adapter, a plugin it cannot run refused with a code) or auto (the adapter first, mod-host for what it refuses, each such plugin in a worker of its own unless its add names a placement); lv2_worker_set overrides it for one plugin\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>lv2_path\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>$LV2_PATH\u003C\u002Fcode>, else \u003Ccode>\u002Fusr\u002Flib\u002Flv2:\u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002Flv2:\u002Fusr\u002Flib\u002Faarch64-linux-gnu\u002Flv2:\u002Fusr\u002Flib\u002Farm-linux-gnueabihf\u002Flv2:\u002Fusr\u002Flocal\u002Flib\u002Flv2:\u002Fusr\u002Flocal\u002Flib\u002Fx86_64-linux-gnu\u002Flv2:\u002Fusr\u002Flocal\u002Flib\u002Faarch64-linux-gnu\u002Flv2:\u002Fusr\u002Flocal\u002Flib\u002Farm-linux-gnueabihf\u002Flv2:\u002Fusr\u002Flib64\u002Flv2:\u002Fusr\u002Flocal\u002Flib64\u002Flv2\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>where bundles are searched\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>lv2_extra\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>``\u003C\u002Ftd>\n\u003Ctd>the site's own bundle folders, searched after lv2_path: the one declaration of them, which plugin-qualify and omx-panel read too\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>clap_path\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>~\u002F.clap:\u002Fusr\u002Flib\u002Fclap\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>where .clap files are searched by whoever searches (plugin-qualify, omx-panel); an add names its file, so the daemon loads none by search; $CLAP_PATH is searched before it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>state_root\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>$XDG_RUNTIME_DIR\u003C\u002Fcode>, else \u003Ccode>\u002Ftmp\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the daemon's checkpoints and worker logs\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_mode\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>first-use\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>strict or first-use, while require_pins is 1: first-use records the pin of a plugin on its first add, strict admits only a plugin a controller, a pin_file or pins_dir pinned\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>grouping\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>off\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>off or on: whether plan applies its plan (a run of consecutive members that may share a worker is declared as a chain), or only answers it; the default stays off until the benchmark has published a win\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>bind_address\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>127.0.0.1\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the IPv4 address the command and feedback ports listen on: this machine alone by default; 0.0.0.0 is every address of the machine, and a controller is not authenticated, so widen it only on a network whose hosts are trusted; --bind-address overrides it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>placement\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>spread\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>spread or none (docs\u002Fplacement.md): spread pins each new worker to the audio core with the least load, the sum of the qualification costs of the workers already on it, or their number while one of them has a member of unknown cost, the lowest core of a tie, and keeps the daemon, its threads and the scans it forks on the reserved cores; a worker keeps its core across respawns, and one whose format worker_env gave a cpu list is not placed; none pins nothing; --placement overrides it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>audio_cores\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>``\u003C\u002Ftd>\n\u003Ctd>the cpus the placement spreads the workers over, a cpu list inside the daemon's own affinity (&quot;1-3&quot;); empty is that affinity less its lowest cpu; the reserved cores are the rest of it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_store\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>``\u003C\u002Ftd>\n\u003Ctd>the file first-use pins are kept in; empty is $XDG_STATE_HOME\u002Fplugin-hostd\u002Fpins, else $HOME\u002F.local\u002Fstate\u002Fplugin-hostd\u002Fpins\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_file\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>``\u003C\u002Ftd>\n\u003Ctd>a file of pin lines loaded at start, as plugin-qualify --all --pins writes it; empty is none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pins_dir\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>\u002Fusr\u002Fshare\u002Fplugin-hostd\u002Fpins.d\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the read-only pins of packages: every file in it whose name ends in .pins, read at start in name order, under the store, the pin_file and pin_set, except that a pin of verdict=refused there always holds; empty is none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>descriptor_dir\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>$OMX_DESCRIPTOR_DIR\u003C\u002Fcode>, else ``\u003C\u002Ftd>\n\u003Ctd>the scanned descriptors, one file per plugin binary (&lt;id&gt;@&lt;version&gt;-&lt;hash&gt;.json, the hash the binary's SHA-256), written by the scan of an add and read by descriptor_get; empty is $XDG_STATE_HOME\u002Fomx\u002Fdescriptors, else \u002Fvar\u002Flib\u002Fomx\u002Fdescriptors run as root (a system service), else $HOME\u002F.local\u002Fstate\u002Fomx\u002Fdescriptors; its variable is for tests only\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>qualification_dir\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>$OMX_QUALIFICATION_DIR\u003C\u002Fcode>, else ``\u003C\u002Ftd>\n\u003Ctd>plugin-qualify's qualification records (verdict, cost, version tested), kept apart from the descriptors; empty is $XDG_STATE_HOME\u002Fomx\u002Fqualification, else \u002Fvar\u002Flib\u002Fomx\u002Fqualification run as root (a system service), else $HOME\u002F.local\u002Fstate\u002Fomx\u002Fqualification; its variable is for tests only\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>probe\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>plugin-hostd-probe\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the scanner an add runs, as &lt;probe&gt; describe &lt;target&gt;, in a child of its own once per plugin binary; its stdout is the descriptor\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>history_file\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>``\u003C\u002Ftd>\n\u003Ctd>the running history: what each plugin did on this machine, kept per plugin, binary and host class; empty is $XDG_STATE_HOME\u002Fplugin-hostd\u002Fhistory, else $HOME\u002F.local\u002Fstate\u002Fplugin-hostd\u002Fhistory; local to this machine, mode 0600, written by the daemon alone, and deleted by history_clear\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>host_class\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>``\u003C\u002Ftd>\n\u003Ctd>the host class the history is kept under, as arch\u002Fcores\u002Fclock (x86_64\u002F5-8\u002F2.5-3.5GHz); empty is the class of this machine, as the probe writes it; no white space\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>ready_timeout_ms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>5000 ms\u003C\u002Ftd>\n\u003Ctd>a worker that does not accept in this long is a failed spawn\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>rpc_timeout_ms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>5000 ms\u003C\u002Ftd>\n\u003Ctd>a worker that does not answer in this long is killed\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>backoff_base_ms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>250 ms\u003C\u002Ftd>\n\u003Ctd>respawn backoff, doubling per death in the window\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>backoff_max_ms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>5000 ms\u003C\u002Ftd>\n\u003Ctd>the most a respawn backoff grows to\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>storm_deaths\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>5 deaths\u003C\u002Ftd>\n\u003Ctd>deaths inside the window that end respawning of a placement\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>storm_window_ms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>60000 ms\u003C\u002Ftd>\n\u003Ctd>the window storm_deaths are counted in\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>suspect_window_ms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>500 ms\u003C\u002Ftd>\n\u003Ctd>a worker that dies this soon after a reply drops the verb it answered; 0 turns it off\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>checkpoint_ms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>5000 ms\u003C\u002Ftd>\n\u003Ctd>a quiet interval with a changed ledger writes a checkpoint\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain_form_timeout_ms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>10000 ms\u003C\u002Ftd>\n\u003Ctd>a chain or a plan's segment that has not formed in this long is said with chain_stalled; 0 turns it off\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>idle_ms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>25 ms\u003C\u002Ftd>\n\u003Ctd>the period of the idle tick: reap, respawn, checkpoint\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pool_max\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>8 instances\u003C\u002Ftd>\n\u003Ctd>instances in a pool before a sibling opens\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>history_window_s\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>60 s\u003C\u002Ftd>\n\u003Ctd>the length of one history window: a worker's CPU and memory are read and folded into the history of its plugins once per window, and a window the plugin was up less than half of is not counted; 0 keeps no history\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>history_save_s\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>300 s\u003C\u002Ftd>\n\u003Ctd>the history is written at most once this often when it changed, and at quit\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>history_regroup_s\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>600 s\u003C\u002Ftd>\n\u003Ctd>a plan whose group was split by a death that named no culprit is made again after this many seconds without another death of its members, and the members that share are gathered in a worker again; 0 never makes it again by itself\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>ram_budget_mb\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>0 MiB\u003C\u002Ftd>\n\u003Ctd>the memory this host gives its plugins, which estimate answers beside what they hold; 0 for no budget set\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>group_max\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>8 instances\u003C\u002Ftd>\n\u003Ctd>most members of one segment of a plan; 0 sets no limit\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>group_cost_max\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>60 percent of a core\u003C\u002Ftd>\n\u003Ctd>most the costs of the members of one segment of a plan add to, each a member's coreFractionP95 of its qualification record at group_rate and group_quantum; a member over it alone stays alone; 0 sets no limit\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>group_rate\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>48000 Hz\u003C\u002Ftd>\n\u003Ctd>the sample rate the cost of a member is read at\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>group_quantum\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>128 frames\u003C\u002Ftd>\n\u003Ctd>the quantum the cost of a member is read at\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>require_pins\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>1\u003C\u002Ftd>\n\u003Ctd>1: add admits only a plugin that has a pin (see pin_mode), its files hashed before any worker sees it, and a plugin of a format whose pin holds only in a world of its own gets a worker of its own, its world the plugin's files (a default that resolves to a pool is placed own); 0: no pin is checked\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Where plugins are searched is written once, in \u003Ccode>include\u002Fplugin-hostd\u002Fsearch_paths.h\u003C\u002Fcode>. The LV2 default is Zynthian's own\n\u003Ccode>LV2_PATH\u003C\u002Fcode> order (\u003Ccode>\u002Fusr\u002Flib\u002Flv2\u003C\u002Fcode>, \u003Ccode>\u002Fusr\u002Flib\u002F&lt;multiarch&gt;\u002Flv2\u003C\u002Fcode>, \u003Ccode>\u002Fusr\u002Flocal\u002Flib\u002Flv2\u003C\u002Fcode>, \u003Ccode>\u002Fusr\u002Flocal\u002Flib\u002F&lt;multiarch&gt;\u002Flv2\u003C\u002Fcode>)\nand then the lib64 folders; the CLAP rule is CLAP's own, \u003Ccode>$CLAP_PATH\u003C\u002Fcode>, then \u003Ccode>~\u002F.clap\u003C\u002Fcode>, then \u003Ccode>\u002Fusr\u002Flib\u002Fclap\u003C\u002Fcode>. A site adds\nits own folders in \u003Ccode>lv2_extra\u003C\u002Fcode> (a Zynthian image: \u003Ccode>\u002Fzynthian\u002Fzynthian-plugins\u002Flv2\u003C\u002Fcode> and the like), searched after\n\u003Ccode>lv2_path\u003C\u002Fcode>; plugin-qualify and omx-panel read \u003Ccode>lv2_path\u003C\u002Fcode>, \u003Ccode>lv2_extra\u003C\u002Fcode> and \u003Ccode>clap_path\u003C\u002Fcode> from this file, or run\n\u003Ccode>tools\u002Fsearch-paths.py lv2|clap [--existing] [--env]\u003C\u002Fcode>, and keep no list of their own. The benchmark and the scripts of\n\u003Ccode>tools\u002Fzynthian\u002F\u003C\u002Fcode> use the same script.\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>name\u003C\u002Fth>\n\u003Cth>value\u003C\u002Fth>\n\u003Cth>meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>default_command_port\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>5555 port\u003C\u002Ftd>\n\u003Ctd>the command port without -p; the feedback port is the next one, unless -n is given\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>connect_retry_ms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>5000 ms\u003C\u002Ftd>\n\u003Ctd>how long the idle tick asks again for a connect a respawned worker could not make yet\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>line_max\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>4096 bytes\u003C\u002Ftd>\n\u003Ctd>the protocol socket's buffer: the longest pin_set line the daemon takes\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>line_words_max\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>64 words\u003C\u002Ftd>\n\u003Ctd>the words of one command line the daemon reads, the verb included; a word past them is not read\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain_members_min\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>1 instances\u003C\u002Ftd>\n\u003Ctd>the fewest members of a chain: a chain of one is valid, so one isolated plugin is a chain like any other\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Ch2 id=\"placement\">Placement\u003C\u002Fh2>\n\u003Cp>The placement of an \u003Ccode>add\u003C\u002Fcode> is \u003Ccode>own | pool:&lt;name&gt; | chain:&lt;chain&gt; | default\u003C\u002Fcode>. \u003Ccode>own\u003C\u002Fcode> is a worker for that instance alone; \u003Ccode>pool:&lt;name&gt;\u003C\u002Fcode> is the pool's worker, opened on first use and capped by \u003Ccode>pool_config\u003C\u002Fcode>, and a full pool opens \u003Ccode>&lt;name&gt;#2\u003C\u002Fcode>, \u003Ccode>&lt;name&gt;#3\u003C\u002Fcode>, and so on; \u003Ccode>default\u003C\u002Fcode> is the policy of \u003Ccode>policy_set\u003C\u002Fcode>. A pool name matches \u003Ccode>^[A-Za-z0-9_-]{1,32}$\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>\u003Ccode>&lt;uri&gt;\u003C\u002Fcode> is \u003Ccode>lv2:&lt;uri&gt;\u003C\u002Fcode> or a bare URI for an LV2 plugin, \u003Ccode>clap:&lt;path&gt;#&lt;id&gt;\u003C\u002Fcode>\nfor a CLAP one. The instance number is the controller's and reaches the\nworker unchanged. A worker holds one format. An own LV2 worker sees one\nbundle: \u003Ccode>LV2_PATH\u003C\u002Fcode> is a directory of the daemon's holding a link to the bundle\nwhose \u003Ccode>manifest.ttl\u003C\u002Fcode> names the URI.\u003C\u002Fp>\n\u003Cp>A token after the instance that is not a placement is the fork's optional\njack client name, passed on. An instance that crashed in a pool is placed\n\u003Ccode>own\u003C\u002Fcode> whatever the hint until \u003Ccode>quarantine_clear\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"grouped-workers-against-one-process-per-plugin\">Grouped workers against one process per plugin\u003C\u002Fh2>\n\u003Cp>A chain runs its plugins in one worker; the other way is one process per plugin. One measurement of the two, with\n16 plugins, with the numbers of the page at \u003Ca href=\"https:\u002F\u002Fwww.openmixer.org\u002Fdocs\u002Fgrouped-vs-processes\">https:\u002F\u002Fwww.openmixer.org\u002Fdocs\u002Fgrouped-vs-processes\u003C\u002Fa>:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>\u003C\u002Fth>\n\u003Cth>grouped\u003C\u002Fth>\n\u003Cth>one process per plugin\u003C\u002Fth>\n\u003Cth>\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>resident memory (RSS), 48 kHz\u003C\u002Ftd>\n\u003Ctd>125.4 MB\u003C\u002Ftd>\n\u003Ctd>1764.6 MB\u003C\u002Ftd>\n\u003Ctd>14x smaller grouped\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>proportional memory (PSS), 48 kHz\u003C\u002Ftd>\n\u003Ctd>42.9 MB\u003C\u002Ftd>\n\u003Ctd>118.2 MB\u003C\u002Ftd>\n\u003Ctd>2.8x smaller grouped\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cul>\n\u003Cli>RSS counts a shared library once for every process that maps it, so a design with many processes looks larger than\nit is. PSS divides shared pages between the processes that use them, so it is the honest figure. Do not read the RSS\nratio as the saving in real memory.\u003C\u002Fli>\n\u003Cli>CPU: 1.2 to 1.9x less when grouped, across 3, 8 and 16 plugins at 48 and 96 kHz.\u003C\u002Fli>\n\u003Cli>Context switches: up to about 14x fewer when grouped, 13.9x at 48 kHz and 14.8x at 96 kHz with 16 plugins.\u003C\u002Fli>\n\u003Cli>Xruns over the 12 runs of each mode: 10 grouped against 41 with one process per plugin. Each run is one window of\n10 seconds and the xruns in it are few and unevenly spread, so the 10 against 41 is suggestive and not proof.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>How: a Raspberry Pi 5 with 4 cores, CPU governor on performance during the runs, plugin-hostd 0.12.0 with\nomx-clap-host 0.22.1 as the worker, N omx plugins in series, 256 frames, on a private JACK server.\u003C\u002Fp>\n\u003Cp>Not measured: only 256 frames; only plugin-hostd, with omx plugins; the grouping planner is not part of the result and\nno default has been changed because of the numbers; DSP load and xruns are those of the JACK dummy driver, so no claim\nabout real audio hardware is made.\u003C\u002Fp>\n\u003Ch2 id=\"verbs-the-daemon-adds\">Verbs the daemon adds\u003C\u002Fh2>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>verb\u003C\u002Fth>\n\u003Cth>arguments\u003C\u002Fth>\n\u003Cth>reply\u003C\u002Fth>\n\u003Cth>meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>add\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt; &lt;instance&gt; [own | pool:&lt;name&gt; | chain:&lt;chain&gt; | default] [client_name]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp &lt;instance&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host's add with a placement; a token after the instance that is not a placement is the jack client name\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>worker_list\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>none\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp &lt;n&gt; &lt;worker&gt;:&lt;pid&gt;:&lt;format&gt;:&lt;state&gt;:&lt;core&gt;:&lt;pool&gt;:&lt;place&gt;:&lt;i&gt;,&lt;i&gt;,...\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the workers, one record each\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>instance_info\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;worker&gt; &lt;pid&gt; &lt;state&gt; &lt;crashes&gt; &lt;quarantined&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>where an instance lives and what it has cost\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>supervisor_reset\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>[&lt;worker&gt; | all]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>re-arm the storm bound and the backoff of a given-up placement\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>quarantine_clear\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; | all\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>let a quarantined instance go back where its placement says\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>policy_set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;format | *&gt; own | pool:&lt;name&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the placement of an add that says default\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pool_config\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;name&gt; &lt;max_instances&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the instances a pool holds before a sibling opens\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>worker_env\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;format | *&gt; &lt;cpu-list|-&gt; &lt;nice|-&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the cpu list and the nice value of the workers of a format, at spawn and on the ones running\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt; &lt;path&gt;=&lt;sha256&gt;[,&lt;path&gt;=&lt;sha256&gt;...] &lt;scheme&gt;:&lt;sha256&gt; [verdict=&lt;verdict&gt;] [pool=&lt;pool&gt;]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the pin of one plugin: the SHA-256 of every file the host loads for it, a path relative to the bundle (the directory of a single-file format's file), its layout fingerprint and, when they are known, the verdict of its qualification and whether its worker gets the CLAP thread pool; it replaces an earlier pin of the uri; -516 for a plugin whose pins_dir pin carries verdict=refused, which nothing overrides. The pin store, a pin_file and a pins_dir file hold the same line, with or without the verb\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_clear\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt; | all\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>forget the pin of one plugin, or of every one; a pins_dir pin is read-only and holds again\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_reload\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>none\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>read the pin_file and the pins_dir files again and put the pins in at once, without a restart; the daemon also does this by itself when one of those files changes. Running instances keep running: one the new pins refuse is logged and its id in worker_list is followed by !. The pin_set pins of the controller are kept. -902 under pin_mode off or when the pin_file is gone or has a line outside the grammar, and the earlier pins hold\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_changed\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>[&lt;uri&gt;] [files | layout]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the notice the package sync sends to every daemon it knows after it rewrote the pin file: the same as pin_reload, with or without the pin_changed event's words after it; more words than those are -902\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>lv2_worker_set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt; &lt;mod-host | omx-clap-host | auto | -&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the worker of one LV2 plugin, for its adds from now on: it overrides the lv2_worker setting, - takes the override back; -902 for a word that is none of these. Like policy_set it is the controller's, not in the ledger, gone with the daemon\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_accept\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>pin_mode first-use only: take the plugin's files as they are now as its pin, after a pin_changed event; the layout is learned again by the next add and the verdict is dropped; -508 when the plugin has no pin, -509 when its files cannot be collected, -516 when its pins_dir pin carries verdict=refused, -902 under pin_mode strict\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_layout\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;scheme&gt;:&lt;sha256&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>sent by the daemon to a worker of a format that checks layouts, after it accepted the add of a plugin whose layout pin is still unknown: the layout the worker found after init, which the daemon records in the pin\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_expect\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;scheme&gt;:&lt;sha256&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>sent by the daemon to a worker of a format that checks layouts, just before the instance's add: the layout pin that add checks after init and before activate; any other reply than resp 0 refuses the add with that code, and the add is never forwarded\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;chain&gt; &lt;instance&gt; [&lt;instance&gt; ...]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the instances, in this order, are one chain, run in one worker of place chain:&lt;chain&gt;: each member's state is saved, it is removed from the worker it was in and replayed in the chain's. A chain already declared takes the new order, and a member left out of it goes back to a worker of its own; while its worker is up that worker is kept: a new member joins it (its add, the order, its state, its ledger, its connections) and no other member is restarted, unless the new member's format narrows the worker's world, which forms the chain again. Members of clap and lv2-clap form one chain. A worker that runs chains in one client (clap, lv2-clap) is sent this line, with the members it holds, after the adds of its replay; one that does not (mod-host) never is. A worker that refuses the line would not run the members as one: the chain is forgotten and each member runs in a worker of its own, the line answers -501, and the event chain_refused carries the worker's own code, also when the refusal comes later, on a respawn. Every instance verb still names one member by its own number. A member that crashes the worker is quarantined to a worker of its own and the chain goes on without it; quarantine_clear puts it back. -518 for an instance no add made, -519 for one named twice, -520 for one in another chain, -521 for members no one worker program runs together, -501 for a plugin that may not share a worker while require_pins is on (a CLAP plugin whose first-use pin is not in-process; an LV2 member whose bundle is not found, since a chain's worker sees a world narrowed to the union of its members' bundles), -902 for a chain or an instance that is not a number, or fewer than chain_members_min (1) instances\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain_clear\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;chain&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>forget the chain: each member goes to a worker of its own; -522 for a chain no chain declared\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;chain&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;worker&gt; &lt;instance&gt;,... &lt;instance&gt;,...\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>read a chain back: its worker (- when it has none), its members in the declared order, and the members its worker runs now in their order (- for none); a quarantined member is declared and not running; -522 for a chain no chain declared, -902 for a chain that is not a number\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>plan\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;chain&gt; &lt;instance&gt; [&lt;instance&gt; ...]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;instance&gt;,...;&lt;instance&gt;,...;... &lt;core&gt;,...;&lt;core&gt;,...;...\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the instances, in signal order, are planned (the grouping-planner design note): the daemon decides, from the pin and the cost of each, which runs of consecutive members share a worker. A run of two or more is declared as a chain of place chain:&lt;chain&gt;.&lt;k&gt;, k counting segments from 0; a member that shares with no neighbour is placed own. The reply names the segments in order, the members of one joined by commas and the segments by semicolons, then the cores: the segments again with each member replaced by the audio core of the worker that runs it now, - for one the setting placement did not pin (docs\u002Fplacement.md). A chain planned again keeps the running worker of every segment that did not change, and the daemon plans it again by itself when a member is quarantined and, history_regroup_s after a death that split its group, to gather it. The plan numbers are its own, apart from chain's. While the setting grouping is off the plan is answered and kept for plan_get and nothing moves. A segment that cannot be formed refuses the whole plan with its own code, moves nothing and is told by plan_get as plan-refused:&lt;code&gt;. A segment its worker refuses, which is known only once it has moved, refuses the plan with -501 too, and then every segment ends and each member runs in a worker of its own. -518 for an instance no add made, -519 for one named twice, -520 for one in a chain or in the plan of another chain, -501 for a segment no world can be built for or its worker refuses, -902 for a chain or an instance that is not a number, or fewer than chain_members_min (1) instances\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>plan_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;chain&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;instance&gt;,...;&lt;instance&gt;,...;... &lt;instance&gt;:&lt;reason&gt;,... &lt;core&gt;,...;&lt;core&gt;,...;...\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>read the last plan of a chain back: its segments as plan answered them, then the members that have a reason, instance:reason joined by commas (- for none); the reasons are the words of PLUGIN_HOSTD_GROUPING_REASONS (data\u002Fgrouping.json), then the cores of the members as plan answers them; -532 for a chain no plan planned, -902 for a chain that is not a number\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>plan_clear\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;chain&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>forget the plan: each member goes to a worker of its own; -532 for a chain no plan planned\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>descriptor_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &quot;&lt;path&gt;&quot;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the scanned descriptor of the plugin, answered from descriptor_dir: the file named for its binary as it is now (&lt;id&gt;@&lt;version&gt;-&lt;hash&gt;.json), written by the scan the plugin's add ran. -529 when there is none, -530 while its scan runs, -531 when its last scan wrote nothing, -528 when the directory could not be written\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>panel_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &quot;&lt;path&gt;&quot;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the panel the plugin publishes (org.openmixer.panel-description\u002F1), answered from descriptor_dir: the file panels\u002F&lt;id&gt;@&lt;version&gt;-&lt;hash&gt;.json, named as its descriptor, which the same scan writes once the descriptor is in place, {&quot;plugin&quot;: {&quot;format&quot;, &quot;id&quot;}, &quot;panel&quot;: &lt;the panel object omx-clap-scan --json prints for the plugin, null when it serves none&gt;}; an LV2 plugin's panel is null. The codes are descriptor_get's: -529 when there is none, -530 while its scan runs, -531 when its last scan wrote nothing, -528 when the directory could not be written\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>history_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;history&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>what the daemon kept of the plugin on this host class, for the binary its pin holds now (the running history: the windows it ran alone and in a group, its crashes, restarts and quarantines): one word of comma-joined digest=&lt;sha256&gt;, class=&lt;host class&gt;, crashed=&lt;0|1&gt;, raises_xruns=&lt;0|1&gt; and then every key=value of the record (data\u002Fhistory.json); - when the plugin has no pin or no record, unavailable while the history file is blocked or history_window_s is 0, -902 for a line that is not one word\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>history_clear\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt; | all\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>delete the history of one plugin (every binary and host class of it), or all of it, from memory and from the file at once; -902 while the history is blocked or off, or for a line that is not one word\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>estimate\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;rate&gt; &lt;quantum&gt; &lt;uri&gt; [&lt;uri&gt; ...]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;latency_frames&gt; &lt;cpu_percent&gt; &lt;ram_bytes&gt; &lt;workers&gt; &lt;unknown_count&gt; &lt;member&gt;:&lt;code&gt;,... &lt;ram_used_bytes&gt; &lt;ram_added_bytes&gt; &lt;ram_budget_bytes&gt; &lt;ram_unknown_count&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>what a chain of these plugins, in signal order and named as add names them, would cost at that rate and quantum, read from the qualification records of qualification_dir; no plugin is loaded and nothing moves. latency_frames adds up each member's measured latency of the grid point, else its declared one; cpu_percent adds up each member's median nanoseconds per sample times the rate, percent of one core's cycle (a member's cost per block over the block's duration); ram_bytes adds up the Pss of the worker each member ran alone in, the history's pss_mb_solo of the binary its pin holds on this host class, - unless every member has one, since no qualification record carries a RAM figure; workers is how many workers plan would place the members in (an isolated one alone); unknown_count is how many members have no figure at that rate and quantum, and the latency and the CPU add up only the others. The last word names each of them as its position in the line, from 0, and its code, -533 for no record, -534 for no point of the grid at that rate and quantum, -535 for a uri that names no plugin installed here, joined by commas, - for none. Several records of one plugin (several versions) give the largest figure. -902 for a rate or a quantum that is not a whole number above 0, or no uri\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>A \u003Ccode>&lt;state&gt;\u003C\u002Fcode> is \u003Ccode>up\u003C\u002Fcode> (accepting commands), \u003Ccode>starting\u003C\u002Fcode> (spawned, not yet accepting), \u003Ccode>backoff\u003C\u002Fcode> (dead, waiting to be respawned), \u003Ccode>given-up\u003C\u002Fcode> (the storm bound is spent for its placement).\u003C\u002Fp>\n\u003Cp>A record's place holds a colon (\u003Ccode>pool:p\u003C\u002Fcode>), so a \u003Ccode>worker_list\u003C\u002Fcode> record is read from both ends: six fields on the\nleft, the instance list on the right, the place in between. The fifth is the audio core the setting \u003Ccode>placement\u003C\u002Fcode> pinned\nthe worker to, \u003Ccode>-\u003C\u002Fcode> for none (\u003Ca href=\"\u002Fprojects\u002Fplugin-hostd\u002Fplacement\">docs\u002Fplacement.md\u003C\u002Fa>). The sixth is the worker's thread pool: \u003Ccode>on\u003C\u002Fcode> for a\nworker started with \u003Ccode>--thread-pool=on\u003C\u002Fcode>, which only a CLAP or lv2-clap worker of one plugin whose pin carries \u003Ccode>pool=cores\u003C\u002Fcode>\nis, \u003Ccode>qualified\u003C\u002Fcode> for every other (the worker's default, which grants the pool to no plugin).\u003C\u002Fp>\n\u003Cp>\u003Ccode>panel_get\u003C\u002Fcode> gives a host that draws a plugin's panel itself (Zynthian's engine, a console) the panel the plugin\npublishes, as the scan of its add read it: sections, controls with their widget and visibility rule, roles, displays\nand placement defaults. A renderer takes the panel for the structure, \u003Ccode>param_info\u003C\u002Fcode> for each control's unit and scale,\nand \u003Ccode>remote_page_get\u003C\u002Fcode> for the pages of 8: \u003Ca href=\"\u002Fprojects\u002Fplugin-hostd\u002Fpanel\">docs\u002Fpanel.md\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"verbs-a-worker-answers-by-instance\">Verbs a worker answers, by instance\u003C\u002Fh2>\n\u003Cp>What a host knows of a strip and of a plugin's controls. For a CLAP instance the daemon routes them like mod-host's\ninstance verbs and passes the worker's reply through; the worker answers them from the plugin (\u003Ccode>clap.track-info\u003C\u002Fcode>,\n\u003Ccode>clap.remote-controls\u003C\u002Fcode>, \u003Ccode>clap.params\u003C\u002Fcode>), except \u003Ccode>param_info\u003C\u002Fcode>: omx-clap-host answers it from the param contract (\u003Ccode>org.openmixer.param-contract\u002F1\u003C\u002Fcode>), and\n\u003Ccode>-511\u003C\u002Fcode> for a parameter the worker holds no checked contract for (and \u003Ccode>-103\u003C\u002Fcode> for a symbol that is no parameter). \u003Ccode>-511\u003C\u002Fcode>\nis the stable answer to read as &quot;no contract; fall back to the layout from \u003Ccode>omx-clap-scan\u003C\u002Fcode>&quot;; the daemon passes it through\nand drops nothing. For an LV2 instance on mod-host the daemon answers them itself, never forwarding them, so\nmod-host learns none of them: \u003Ccode>track_info\u003C\u002Fcode> is kept and answered \u003Ccode>resp 0\u003C\u002Fcode>, and the other two come from the bundle's\nTurtle, read when they are asked (the manifest and the files it names with \u003Ccode>rdfs:seeAlso\u003C\u002Fcode>). \u003Ccode>remote_pages\u003C\u002Fcode> and\n\u003Ccode>remote_page_get\u003C\u002Fcode> make a page of each \u003Ccode>pg:group\u003C\u002Fcode>'s control inputs in port order (the group's \u003Ccode>lv2:name\u003C\u002Fcode>, else its\n\u003Ccode>rdfs:label\u003C\u002Fcode>; a further page, &quot;Name 2&quot;, for each 8 past the first), one page named Controls for the control inputs in\nno group, the pages in the order their group first appears; outputs and \u003Ccode>pprops:notOnGUI\u003C\u002Fcode> ports are on no page, a slot\nis the port's symbol, and the section is empty. \u003Ccode>param_info\u003C\u002Fcode> answers a control port from its own statements: its\n\u003Ccode>units:unit\u003C\u002Fcode> (the words of \u003Ccode>data\u002Fformats\u002Flv2.json\u003C\u002Fcode>, empty for a port with none), \u003Ccode>stepped\u003C\u002Fcode> for an integer, toggled or\nenumeration port, \u003Ccode>log\u003C\u002Fcode> for a \u003Ccode>pprops:logarithmic\u003C\u002Fcode> port whose bounds are positive and \u003Ccode>linear\u003C\u002Fcode> otherwise, its\n\u003Ccode>lv2:minimum\u003C\u002Fcode>, \u003Ccode>lv2:maximum\u003C\u002Fcode> and \u003Ccode>lv2:default\u003C\u002Fcode> (a toggled port's are 0, 1 and 0 when it states none), a step of 1 for\na stepped port and 0 for the others, and its symbol. \u003Ccode>-511\u003C\u002Fcode> stays the answer for a port with a unit the table has no\nword for (a unit of the plugin's own) or no range, and \u003Ccode>-103\u003C\u002Fcode> for a symbol that is no control port. A bundle the\ndaemon cannot find or read has no pages, and \u003Ccode>param_info\u003C\u002Fcode> asks mod-host as it did. When a CLAP plugin changes its pages, its\nworker writes \u003Ccode>remote_pages_changed &lt;instance&gt;\u003C\u002Fcode> on its feedback port and the daemon relays it.\u003C\u002Fp>\n\u003Cp>Notes are played the same way, by a controller that is not a jack client (a web console, a test, a MIDI surface on the\nnetwork): \u003Ccode>note_input\u003C\u002Fcode> says whether an instance takes notes, and \u003Ccode>note_on\u003C\u002Fcode>, \u003Ccode>note_off\u003C\u002Fcode> and \u003Ccode>all_notes_off\u003C\u002Fcode> reach its\nworker unchanged once the daemon has checked their words. A worker answers them from the plugin's note input. mod-host\ntakes no notes on its socket, so for an LV2 instance on mod-host the daemon answers all four \u003Ccode>-514\u003C\u002Fcode>, and the plugin is\nplayed through its jack MIDI input with \u003Ccode>connect\u003C\u002Fcode>. omx-clap-host does not answer them yet (FreeMixer\u002Fomx-clap-core#122).\u003C\u002Fp>\n\u003Cp>\u003Ccode>preset_list\u003C\u002Fcode> and \u003Ccode>preset_get\u003C\u002Fcode> list a plugin's presets the way \u003Ccode>remote_pages\u003C\u002Fcode> and \u003Ccode>remote_page_get\u003C\u002Fcode> list its pages; the\nkey \u003Ccode>preset_get\u003C\u002Fcode> gives is the one \u003Ccode>preset_load\u003C\u002Fcode> takes. mod-host cannot list presets, so for an LV2 instance on mod-host\nthe daemon answers both \u003Ccode>-515\u003C\u002Fcode>. omx-clap-host lists them with \u003Ccode>preset_list\u003C\u002Fcode> and \u003Ccode>preset_get\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>A plugin with a window or a surface of its own tells its host when the user takes hold of one of its knobs and lets go,\nmoves values by itself, and suggests a remote page. Its worker writes \u003Ccode>param_gesture\u003C\u002Fcode>, mod-host's \u003Ccode>param_set\u003C\u002Fcode> and\n\u003Ccode>remote_page_suggest\u003C\u002Fcode> on its feedback port, and the daemon relays them as written, in order (events below). If the\nworker dies, or the instance is removed, while a gesture is held, the daemon ends the gesture itself, so no control\nstays held at the controller. omx-clap-host writes these lines from FreeMixer\u002Fomx-clap-core#87 on.\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>verb\u003C\u002Fth>\n\u003Cth>arguments\u003C\u002Fth>\n\u003Cth>reply\u003C\u002Fth>\n\u003Cth>meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>track_info\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;name&gt; &lt;#RRGGBB | -&gt; [bus | return | master]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the strip's name (&quot;&quot; for none), colour and kind, absent for an input channel; a worker whose plugin format has a track-info extension passes them on; any other word is -902\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>remote_pages\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp &lt;count&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the plugin's remote-control pages, from clap.remote-controls; 0 for an instance of a format whose worker has none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>remote_page_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;page&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;page_id&gt; &lt;section&gt; &lt;page_name&gt; &lt;s1&gt; &lt;s2&gt; &lt;s3&gt; &lt;s4&gt; &lt;s5&gt; &lt;s6&gt; &lt;s7&gt; &lt;s8&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>one page, 0 to count - 1: each slot the symbol param_set takes, - for an empty one; -902 for a page that is not one\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>param_info\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;symbol&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;unit&gt; &lt;scale&gt; &lt;min&gt; &lt;max&gt; &lt;default&gt; &lt;step&gt; &lt;stable_symbol&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>what a parameter's value means: its unit, its scale, and the symbol it keeps across hosts and versions; -103 for a symbol that is not a parameter, the plugin's own bypass and :bypass included; -511 for a parameter whose unit and scale the worker holds no checked contract for\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>preset_list\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp &lt;count&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the plugin's presets, the ones its preset discovery or its bundle lists; (-515) for an instance of a worker that cannot list them\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>preset_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;index&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;load_key&gt; &lt;name&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>one preset, 0 to count - 1: the key preset_load takes for it, and its name; -902 for an index that is not one\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>note_input\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0 &lt;port | -&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>whether the instance takes notes: the name of its note input on its worker's jack client, - for a plugin that takes none; (-514) for an instance of a worker that cannot say\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>note_on\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;channel&gt; &lt;key&gt; &lt;velocity&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>play a key: channel 0 to 15, key 0 to 127, velocity 1 to 127, a MIDI note on at the start of the worker's next cycle; (-513) for a plugin that takes no notes, (-514) for an instance of a worker that takes none on its socket, -902 for a word out of its range\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>note_off\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;channel&gt; &lt;key&gt; &lt;velocity&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>release a key, velocity 0 to 127, a MIDI note off; answered as note_on is\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>all_notes_off\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>resp 0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>release every key of every channel, MIDI's all notes off (controller 123) on each; answered as note_on is\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>The ledger keeps the latest \u003Ccode>track_info\u003C\u002Fcode> of an instance and replays it after the add; the others are never replayed. A \u003Ccode>&lt;scale&gt;\u003C\u002Fcode> is \u003Ccode>linear\u003C\u002Fcode> (the value is linear in position), \u003Ccode>log\u003C\u002Fcode> (the value is geometric in position; both bounds are positive), \u003Ccode>stepped\u003C\u002Fcode> (the whole numbers from min to max, step 1). A string word is at most 255 bytes of UTF-8 with no control character.\u003C\u002Fp>\n\u003Cp>What each host profile owes every verb a controller sends: mod-host's commands, the two that Zynthian's mod-ui still\nnames, and the verbs the daemon adds. A verb has a row here before the daemon serves it. The daemon relays a worker's\nverb, an instance verb to the worker that holds the instance and any other to every worker, and passes its answer\nback: a required verb (presets and bundles for the CLAP worker and Zynthian) answers -902\nonly while the worker does. MIDI learn and CV addressing are policy of the surfaces: the host answers them only as the\nmechanism, and they stay optional. The preset verbs and the preset file are \u003Ca href=\"\u002Fprojects\u002Fplugin-hostd\u002Fpresets\">docs\u002Fpresets.md\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>verb\u003C\u002Fth>\n\u003Cth>sent by\u003C\u002Fth>\n\u003Cth>lv2-worker\u003C\u002Fth>\n\u003Cth>clap-worker\u003C\u002Fth>\n\u003Cth>console\u003C\u002Fth>\n\u003Cth>zynthian\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>add\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>remove\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>bypass\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>connect\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>param_set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>state_load\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>state_save\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>state_tmpdir\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>feature_enable\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>bundle_add\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>bundle_remove\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>preset_load\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>preset_save\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>preset_show\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>transport\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>transport_sync\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>cpu_load\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>midi_learn\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>midi_map\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>midi_unmap\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>cv_map\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>cv_unmap\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>monitor_midi_program\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>monitor_output\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>output_data_ready\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>patch_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>patch_set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>cc_map\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>cc_value_set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>cc_unmap\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>hmi_map\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>hmi_unmap\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>show_external_ui\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>set_midi_program_change_pedalboard_bank_channel\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>set_midi_program_change_pedalboard_snapshot_channel\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-ui\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003Ctd>absent\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>disconnect\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>set_bpm\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>set_bpb\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>quit\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>param_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>param_monitor\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>licensee\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>monitor\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>load\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>save\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>help\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>track_info\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>remote_pages\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>remote_page_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>param_info\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mod-host\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>preset_list\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>preset_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>note_input\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>note_on\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>note_off\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>all_notes_off\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003Ctd>optional\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>worker_list\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>instance_info\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>supervisor_reset\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>quarantine_clear\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>policy_set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pool_config\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>worker_env\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_clear\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_accept\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_reload\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_changed\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>lv2_worker_set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain_clear\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>plan\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>plan_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>plan_clear\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>descriptor_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>panel_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>history_get\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>history_clear\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>estimate\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>daemon\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003Ctd>required\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>The profiles: \u003Ccode>lv2-worker\u003C\u002Fcode>, an LV2 plugin's worker: mod-host, or omx-clap-host's LV2 adapter; \u003Ccode>clap-worker\u003C\u002Fcode>, a CLAP plugin's worker, omx-clap-host; \u003Ccode>console\u003C\u002Fcode>, the openmixer console as a controller of the daemon; \u003Ccode>zynthian\u003C\u002Fcode>, Zynthian's mod-ui and its plugind engine as a controller of the daemon. \u003Ccode>required\u003C\u002Fcode> is answered as its grammar says; \u003Ccode>optional\u003C\u002Fcode> is answered, or refused with -902, and never misread; \u003Ccode>absent\u003C\u002Fcode> is refused on purpose, and no client of the profile may need it.\u003C\u002Fp>\n\u003Cp>Error codes the daemon adds to mod-host's:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>code\u003C\u002Fth>\n\u003Cth>name\u003C\u002Fth>\n\u003Cth>meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-501\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_PLACEMENT_INVALID_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>placement invalid: not a placement, or not valid here, as a pool:&lt;name&gt; for a plugin of a format whose pin holds only in a world of the plugin's own, while require_pins is on\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-502\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_NO_BACKEND_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>no worker program for the scheme\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-503\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_WORKER_SPAWN_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the worker is not up: the spawn failed, or it is in backoff; ask again after instance_restored\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-504\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_REPLAY_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the name of a refused replay, never a reply: a replayed add that its pin or the worker refuses is announced by the instance_replay_refused event with the refusal's own code, and written to stderr with this one and the step that refused it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-505\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_GAVE_UP_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the storm bound is spent for that placement\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-506\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_NO_SUCH_WORKER_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>no such worker\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-507\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_VERB_DROPPED_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the worker died on this very command and the daemon dropped it: it is not replayed, and the instance_verb_dropped event names it; or it died on, or did not answer in rpc_timeout_ms, the pin_expect of an add, which is then never forwarded\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-508\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_HOST_PIN_ABSENT_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>pin_mode strict and the plugin has no pin, or its layout pin is in a scheme this version does not know: add is refused and no worker sees it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-509\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_PIN_BINARY_MISMATCH_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a pinned file is missing or its SHA-256 differs, or the plugin's manifest names a file the pin does not hold: add is refused and no worker sees it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-510\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_HOST_PIN_LAYOUT_MISMATCH_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the worker found the parameter layout after init differs from the layout pin: the instance is destroyed before activate\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-511\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_HOST_NO_PARAM_CONTRACT_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the host holds no checked unit and scale for this parameter: fall back to qualification\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-512\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_LV2_ADAPTER_REFUSED_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the lv2-clap worker's LV2 adapter cannot run this plugin (MIDI it does not feed, a required feature it lacks, a layout it does not take): the worker answered the add -102, the lv2_adapter_refused event carries the hosting.* code of that reply, and under lv2_worker auto the plugin is run by the lv2 row instead and this code is never answered; a plugin no bundle of the worker's world holds is no refusal: the worker's -101 is answered\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-513\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_HOST_NO_NOTE_INPUT_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the instance's plugin takes no notes (an effect): its worker answers note_on, note_off and all_notes_off with this code\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-514\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_HOST_NOTES_BY_JACK_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the instance's worker takes no notes on its socket (mod-host): the daemon answers the note verbs and note_input with this code, and the plugin is played through its jack MIDI input with connect\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-515\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_NO_PRESET_LIST_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the instance's worker cannot list the plugin's presets (mod-host): the daemon answers preset_list and preset_get with this code; preset_load still takes a preset the controller knows\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-516\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_PIN_REFUSED_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the plugin's pin carries verdict=refused: its files are the ones that failed qualification, so add is refused and no worker sees it, and a replayed add is refused the same way; files that differ from the pin answer (-509) first. A pins_dir pin of that verdict is never overridden: pin_set and pin_accept of its plugin answer this code\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-517\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_HOST_NOTE_QUEUE_FULL_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the instance's worker has no room for this note_on, note_off or all_notes_off before its next block: the line was not taken and nothing of it is kept; the controller may send it again\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-518\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_CHAIN_UNKNOWN_INSTANCE_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a member of chain is an instance no add made: the chain is not declared\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-519\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_CHAIN_DUPLICATE_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>an instance is named twice in one chain: the chain is not declared\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-520\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_CHAIN_INSTANCE_BUSY_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a member of chain is already in another chain: the chain is not declared; chain_clear of the other chain frees it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-521\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_CHAIN_MIXED_FORMAT_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the members of chain are not all run by one worker program, or are of two rows of one program and a row does not run chains in one client, so no one worker runs them: the chain is not declared\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-522\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_NO_SUCH_CHAIN_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>chain_clear or chain_get of a chain no chain declared\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-523\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_PRESET_NOT_OFFERED_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the worker: preset_load or preset_show of a stable name the plugin does not offer, or of a plugin with no preset system and no state\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-524\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_PRESET_INVALID_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>preset_save with a file path that is not absolute or with no name, or preset_load or preset_show of a file that cannot be read, is no JSON, is of a format version other than org.openmixer.preset\u002F1 and org.openmixer.preset\u002F2, or breaks the format (docs\u002Fpresets.md): the daemon answers it and no worker sees the file\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-525\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_PRESET_NEEDS_STATE_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the worker: a preset file that carries state for a worker that cannot take state yet\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-526\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_PRESET_PLUGIN_CHANGED_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the worker: the preset file's plugin id, version or fingerprint is not the instance's; nothing of it is applied\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-527\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_LOAD_REFUSED_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the worker: the plugin refused the preset or the state its file carries\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-528\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_DIR_NOT_WRITABLE_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>descriptor_dir or qualification_dir cannot be made or written: the daemon does not start, and says which key and which path on stderr with this code; a directory that turns read-only later makes the scan of an add write nothing, and descriptor_get and panel_get of that plugin answer this code\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-529\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_DESCRIPTOR_ABSENT_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>descriptor_get (panel_get) of a plugin that has no descriptor (panel) in descriptor_dir for its binary as it is now, and none being written: no add since it changed, or a binary that cannot be found\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-530\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_DESCRIPTOR_PENDING_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>descriptor_get (panel_get) of a plugin whose scan, started by its add, has not written its descriptor (panel) yet: ask again\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-531\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_DESCRIPTOR_SCAN_FAILED_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>descriptor_get (panel_get) of a plugin whose last scan wrote no descriptor (panel): the scanner refused the plugin, made no dump or no panel, or is not installed; the add it ran for stands, and stderr and the scan's log say why. The next add scans again\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-532\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_NO_SUCH_PLAN_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>plan_get or plan_clear of a chain no plan planned\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-533\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_NO_RECORD_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a member of estimate that no qualification record in qualification_dir names: never a reply, the code of the member in the reply's list\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-534\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_NO_CELL_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a member of estimate whose qualification records hold no point of the grid at that rate and quantum with a cost and a latency: never a reply, the code of the member in the reply's list\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>-535\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>OMX_REPLY_PLUGIN_HOSTD_UNKNOWN_PLUGIN_RESP\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a member of estimate whose uri names no plugin installed here (its format cannot tell the plugin's binary, or the binary is not there): never a reply, the code of the member in the reply's list\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>A worker's own refusal is returned as it said it. An \u003Ccode>add\u003C\u002Fcode> that killed its worker answers mod-host's \u003Ccode>-102\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>\u003Ccode>worker_env\u003C\u002Fcode> offers no real-time priority: a worker's audio thread is set by the jack client library (under a SCHED_FIFO 60\ndriver it ran at 55, unasked), and a FIFO priority given to the whole process puts the plugin's own threads above\nit, where a busy thread starves the graph.\u003C\u002Fp>\n\u003Cp>A daemon without privilege cannot give a worker a nice lower than the worker has (a new worker has the daemon's own). The\nverb still answers \u003Ccode>resp 0\u003C\u002Fcode>, the worker keeps its nice, and the daemon logs \u003Ccode>worker_env: worker &lt;pid&gt; keeps nice &lt;n&gt;, the nice &lt;m&gt; was not applied\u003C\u002Fcode> on stderr.\u003C\u002Fp>\n\u003Cp>Like mod-host, the daemon serves one controller at a time, and \u003Ccode>remove\u003C\u002Fcode> of an instance it does not hold answers\n\u003Ccode>resp 0\u003C\u002Fcode>. With \u003Ccode>-n\u003C\u002Fcode> and no \u003Ccode>-f\u003C\u002Fcode> there is no feedback port (mod-host's own rule), and a controller need not open\none; without \u003Ccode>-n\u003C\u002Fcode>, or with \u003Ccode>-f\u003C\u002Fcode>, the daemon waits for the controller to open both. A command that finds its\nworker gone answers \u003Ccode>PHD_ERR_WORKER_SPAWN\u003C\u002Fcode>: the worker is not up, ask again after \u003Ccode>instance_restored\u003C\u002Fcode>. A command that\nkills its worker answers \u003Ccode>PHD_ERR_VERB_DROPPED\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Events on the feedback port, one NUL-terminated line each:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>event\u003C\u002Fth>\n\u003Cth>fields\u003C\u002Fth>\n\u003Cth>meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>worker_died\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;worker&gt; &lt;pid&gt; &lt;exit:N | signal:N&gt; &lt;instance&gt;,...\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a worker died; the instances it held, or - for none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>instance_verb_dropped\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;the command as sent&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the command a worker died on, dropped from the ledger; or the add it died on, the add as the worker was given it, which names the plugin, or the pin_expect of that add\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>instance_verb_dropped\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; suspect:&lt;ms&gt; &lt;the command as sent&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the last verb a worker answered when it died inside suspect_window_ms, &lt;ms&gt; the age of the reply\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>worker_backoff\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;worker&gt; &lt;ms&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the respawn waits this long\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>worker_respawned\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;worker&gt; &lt;pid&gt; &lt;replayed_count&gt; &lt;ms&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a worker is back and its ledger replayed\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>instance_restored\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;worker&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>an instance is back in a worker\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>instance_replay_refused\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;code&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a replayed add was refused, by its pin or by the worker, &lt;code&gt; the refusal's own: no worker holds the instance until the next replay\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>instance_quarantined\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;worker&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the culprit of a pool or a chain death, placed own until cleared; a chain goes on without it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain_formed\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;chain&gt; &lt;worker&gt; &lt;instance&gt;,...\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a chain's worker is up with these members, in this order, after its declaration, a respawn or a member's quarantine; - for none. &lt;chain&gt; is the number chain declared, or &lt;plan&gt;.&lt;k&gt; for segment k of a plan\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain_refused\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;chain&gt; &lt;code&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a chain's worker would not run the members as one chain, &lt;code&gt; its own answer, and its stderr says why: the chain is forgotten and each member runs in a worker of its own. &lt;chain&gt; as chain_formed names it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>chain_stalled\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;chain&gt; &lt;instance | -&gt; &lt;step&gt; &lt;code&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a chain, or a plan's segment, has not formed within chain_form_timeout_ms of its declaration: the member and the step that held it (spawn, add, pin, state, memory) and the code it answered, 0 for none, - for no one member; said once each time it is declared or gathered again, and the daemon goes on trying\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>plan_reason\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;chain&gt; &lt;instance&gt;:&lt;reason&gt;,...\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a plan of the chain changed: the reasons plan_get answers now, after the segments, - for none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>supervisor_gave_up\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;worker&gt; &lt;deaths&gt; &lt;window_ms&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the storm bound is spent; respawning ends\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_changed\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt; files | layout\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>an add or a replay of a plugin was refused because its files, or the layout the worker found, differ from its pin; the pin is as it was until pin_accept or pin_set\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>lv2_adapter_refused\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;uri&gt; &lt;reason&gt; auto | omx-clap-host\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the LV2 adapter of the lv2-clap worker refused a plugin: &lt;reason&gt; is the hosting.* code after -102 on the worker's reply to that add (- when it named none); the last word is the lv2_worker in force, auto for a plugin the lv2 row runs from now on, omx-clap-host for an add answered (-512)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>remote_pages_changed\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>relayed from a worker: the plugin changed its remote pages; read them again\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>remote_page_suggest\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;page_id&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>relayed from a worker: the plugin suggests the remote page of that id (a page_id of remote_page_get); a surface may follow it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>param_gesture\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;symbol&gt; begin | end\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>relayed from a worker: the user took hold of a control of the plugin's own, or let it go; a controller writes no automation of that parameter in between. The values the plugin moves meanwhile, or at any time by itself, are mod-host's param_set feedback lines, relayed as written. A gesture whose worker died, or whose instance was removed, before its end is ended by the daemon, before the worker_died event\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>xruns\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;count&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>relayed from a worker, and read by the daemon: the JACK xruns the worker has counted since it started, written when the count changes and at most once a second; a worker that never writes it counted none. The daemon takes the first count of a worker as its baseline and, at the close of each history window, adds the window to xrun_windows_solo or xrun_windows_grouped of every member of the worker when the count rose in it; a line that is not the word and one whole number is not a count\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>abi_clobber\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;mask&gt; &lt;registers&gt; &lt;call&gt; &lt;block&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>relayed from a worker (omx-clap-host 0.26.2 or later), and read by the daemon: the plugin returned from a call with a callee-saved register changed, said once per instance. The worker put the registers back, so its own frame is whole; the other members' state in the same process is not covered, so the daemon quarantines the instance (instance_quarantined, and the history keeps it alone from then on) and, when it shares its worker or is in a chain, moves it to a worker of its own with its state saved; one already alone is only marked\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>param_set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;instance&gt; &lt;symbol&gt; &lt;value&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>relayed from a worker: parameter feedback, a value the plugin moved by itself (its automation, an LFO, a preset load, a MIDI map, the user's knob of the plugin's own), as mod-host writes it; a controller updates its control to it. A worker never writes it for a value a controller's param_set gave it, and a worker that writes none changes nothing: the daemon adds no line of its own\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Ch2 id=\"the-workers-own-feedback\">The workers' own feedback\u003C\u002Fh2>\n\u003Cp>What a worker reports on its feedback port (the \u003Ccode>output_set\u003C\u002Fcode> of a monitored output, the \u003Ccode>param_set\u003C\u002Fcode> of a parameter the\nplugin moved, \u003Ccode>data_finish\u003C\u002Fcode>, the log lines) reaches the controller on the daemon's feedback port, among the events\nabove:\u003C\u002Fp>\n\u003Cp>Every worker is started as \u003Ccode>&lt;program&gt; -n -p &lt;command port&gt; -f &lt;feedback port&gt;\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>every line a worker writes on its feedback port goes out on the daemon's feedback port as the worker wrote it: output_set, param_set, data_finish and the rest of mod-host's feedback, and a line the daemon does not know.\u003C\u002Fli>\n\u003Cli>the instance number in a relayed line is already the controller's: add hands it to the worker unchanged, so nothing in a line is rewritten.\u003C\u002Fli>\n\u003Cli>a worker's lines go out in the order it wrote them, and what a worker wrote before it died goes out before its worker_died event; an instance lives in one worker at a time, so its lines keep their order across a respawn; the lines of different workers interleave.\u003C\u002Fli>\n\u003Cli>monitor_output is in the ledger, one line per output, and param_monitor as it was sent; a respawn replays them after the add, so a respawned instance reports the same outputs, each once, starting again from its first value.\u003C\u002Fli>\n\u003Cli>output_data_ready names no instance and goes to every worker; each worker's data_finish is relayed.\u003C\u002Fli>\n\u003Cli>with no feedback port, or no controller on it, a line is dropped, as mod-host drops it; the daemon reads every worker's feedback all the time, so no worker waits on it.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>A synced delay or an arpeggiator comes back at the right tempo after a crash. What the daemon keeps of the commands\nevery worker shares:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>the tempo, the metre and the transport a controller sets (mod-host's set_bpm, set_bpb, transport and transport_sync) are kept, the latest line of each as it was sent, in the order they were last sent.\u003C\u002Fli>\n\u003Cli>a worker is handed them before anything else: a respawned one before its first add, and a worker started later, of a new placement, as well; a worker's refusal of one is written to stderr and is no failure.\u003C\u002Fli>\n\u003Cli>a line whose words are not that command's grammar is passed on and not kept.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"probing-a-plugin\">Probing a plugin\u003C\u002Fh2>\n\u003Cp>\u003Ccode>plugin-hostd-probe run\u003C\u002Fcode> loads a plugin in a child process under limits and writes down what happened, as facts only: no\nverdict. The child is clap-qualify for a CLAP plugin. For an LV2 plugin, named \u003Ccode>lv2:&lt;uri&gt;\u003C\u002Fcode>, the child is plugin-qualify's\n\u003Ccode>lv2_measure\u003C\u002Fcode>, found at run time in \u003Ccode>\u002Fusr\u002Flibexec\u002Fplugin-qualify\u003C\u002Fcode> (plugin-qualify is not a dependency of this package).\nThe runner never loads plugin code itself.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>plugin-hostd-probe run --out probe.json --log probe.stderr.log \u002Fusr\u002Flib64\u002Fclap\u002Fplate.clap org.example.plate\nplugin-hostd-probe run --out probe.json lv2:http:\u002F\u002Fexample.org\u002Fplate\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>A CLAP instrument is timed holding notes down: as many as the voice capacity it declares, or, when it declares none,\nthe count \u003Ccode>--probe-notes N\u003C\u002Fcode> gives; \u003Ccode>--hold N\u003C\u002Fcode> holds that count whatever it declares. Both are passed to clap-qualify.\nEach rate's grid point carries the cost clap-qualify timed at that rate, in nanoseconds per sample, and for an instrument\n\u003Ccode>voices\u003C\u002Fcode>, the notes it held and why that many (\u003Ccode>declared\u003C\u002Fcode> or \u003Ccode>probe\u003C\u002Fcode>). A rate it did not time has no cost. An instrument has\nno input for the impulse, so its latency is measured from a note (\u003Ccode>method: note-onset\u003C\u002Fcode>), with \u003Ccode>heard: false\u003C\u002Fcode> at a rate\nwhere the note did not sound.\u003C\u002Fp>\n\u003Cp>clap-qualify runs under plugin-qualify's interposer, \u003Ccode>rt_interpose.so\u003C\u002Fcode> beside the child. A bare \u003Ccode>--child\u003C\u002Fcode> is found as execvp\nfinds it; name the child by path when PATH is unset or holds a directory of its name. The measured child gets the interposer\nand nothing else: an \u003Ccode>LD_PRELOAD\u003C\u002Fcode> the runner was started with is dropped for the measurement, named in \u003Ccode>run.tools.droppedPreload\u003C\u002Fcode>\nand in the \u003Ccode>rt-safety\u003C\u002Fcode> step, and put back in the runner's environment after the child. The first grid point carries what process() did under it, and an instrument's\nnote sweep carries what process() did while notes played. \u003Ccode>run.tools.interposer\u003C\u002Fcode> names it once the child says it counted\nunder it. With no interposer beside the child, or one that did not load, no count is written: rtSafety says\n\u003Ccode>interposer: false\u003C\u002Fcode>, and the \u003Ccode>rt-safety\u003C\u002Fcode> and \u003Ccode>note-sweep\u003C\u002Fcode> steps are \u003Ccode>probe.not-attempted\u003C\u002Fcode> and say why.\u003C\u002Fp>\n\u003Cp>An LV2 plugin is measured the way plugin-qualify's LV2 hosting pass measures it, in two children under the same\nlimits and the same wall clock. The first child (\u003Ccode>lv2_measure --pin\u003C\u002Fcode>) pins the bundle's files without instantiating the\nplugin. The second measures at the highest of \u003Ccode>--rates\u003C\u002Fcode>, in blocks of \u003Ccode>--quantum\u003C\u002Fcode>, with 30 instantiate and destroy cycles\nand 3 swept rt-safety runs. It runs under plugin-qualify's interposer (\u003Ccode>rt_interpose.so\u003C\u002Fcode> beside the child, found and with any\nother preload dropped as for clap-qualify) and the noise stimulus. The document's binary is the plugin's library, with every pinned file of the bundle listed. The rate's grid\npoint carries what run() did under the interposer and, for a plugin with a MIDI input, its note sweep (what run() did\nwhile notes played), and \u003Ccode>behaviour\u003C\u002Fcode> carries the lifecycles, the threads and the features\nthe plugin requires. A plugin no bundle holds exits 3 with no document. A plugin of which nothing could be pinned exits 2\nwith no document, because the document has no binary to name. Its refusal is a code on stderr: \u003Ccode>&lt;plugin&gt;: &lt;code&gt;: &lt;why&gt;\u003C\u002Fcode>,\n\u003Ccode>probe.unpinnable\u003C\u002Fcode> for a bundle the pin cannot cover. Version 1 runs the quick measurement only: the deep lifecycle pass\nand the soak stay plugin-qualify's until the probe protocol says which plugins get them and for how long.\u003C\u002Fp>\n\u003Cp>The runner kills the whole process tree of the child at its wall clock, and again when the child is done, so a process a\nplugin started in a session of its own does not outlive the run. It applies these limits on every Linux: the wall clock,\nthe CPU time, the memory, the open files, the file size, no core dump, the real-time priority it was granted and the\nwall budget as its real-time CPU time, the memory it may lock, no new privileges, the child dying with the runner, and the\ncpus the child may use (\u003Ccode>--cpus\u003C\u002Fcode>). \u003Ccode>--list-limits\u003C\u002Fcode> prints them as a run on this machine would apply them.\u003C\u002Fp>\n\u003Cp>The measured child runs as the host runs the plugin: SCHED_FIFO at the highest priority the runner may give it (all of it\nwith \u003Ccode>CAP_SYS_NICE\u003C\u002Fcode>, else the \u003Ccode>RLIMIT_RTPRIO\u003C\u002Fcode> hard limit the runner was started with, else none), with its memory locked\nby the runner's lock preload (\u003Ccode>&lt;libexecdir&gt;\u002Fplugin-hostd\u002Fprobe-lock.so\u003C\u002Fcode>, \u003Ccode>\u002Fusr\u002Flibexec\u003C\u002Fcode> in the packages, beside the interposer) when its \u003Ccode>RLIMIT_MEMLOCK\u003C\u002Fcode>\ncovers the memory limit. The runner itself and an LV2 plugin's pin pass stay SCHED_OTHER. \u003Ccode>run.realtime\u003C\u002Fcode> says what the\nkernel reported for the child after the exec (class, priority, the priority requested, who granted it, and why none),\n\u003Ccode>capabilityBound\u003C\u002Fcode> (whether the child, as the kernel reports it, holds no capability in its permitted or effective set, so it cannot raise \u003Ccode>RLIMIT_RTPRIO\u003C\u002Fcode>, \u003Ccode>RLIMIT_RTTIME\u003C\u002Fcode> or \u003Ccode>RLIMIT_MEMLOCK\u003C\u002Fcode> again: the probe drops every capability and the bounding set, which a runner without \u003Ccode>CAP_SETPCAP\u003C\u002Fcode> cannot, and then it says \u003Ccode>false\u003C\u002Fcode>),\n\u003Ccode>offer.realtime\u003C\u002Fcode> is that class, and \u003Ccode>run.memoryLock\u003C\u002Fcode> says whether the lock held. A service that runs the probe passes the\ngrant with \u003Ccode>LimitRTPRIO=\u003C\u002Fcode> and \u003Ccode>LimitMEMLOCK=\u003C\u002Fcode> (\u003Ca href=\"\u002Fprojects\u002Fplugin-hostd\u002Fown-host#measuring-plugins-at-real-time-priority\">docs\u002Fown-host.md\u003C\u002Fa>). A limit the set asks for and this version does not\napply (the number of tasks, namespaces, Landlock, seccomp) is listed in the document under \u003Ccode>limits.unavailable\u003C\u002Fcode> with its\ncode, and \u003Ccode>--require tasks\u003C\u002Fcode> makes the run refuse instead.\u003C\u002Fp>\n\u003Cp>The memory limit (\u003Ccode>--data-bytes\u003C\u002Fcode>) is \u003Ccode>memory.max\u003C\u002Fcode> of a cgroup the measured child runs in, so the kernel counts what the\nplugin really holds and kills its whole tree at the limit; that run ends \u003Ccode>probe.memory-limit\u003C\u002Fcode>, with the limit in the step's\ndetail and the document written as for any other outcome. The cgroup goes under the runner's own cgroup when that hands the\nmemory controller down, else beside it, else, when the runner is alone in a delegated cgroup, under it once the runner has\nstepped into a leaf; it is removed after the run. A machine that gives none of these bounds the child with \u003Ccode>RLIMIT_DATA\u003C\u002Fcode>, and\n\u003Ccode>limits.unavailable\u003C\u002Fcode> says so: \u003Ccode>memory\u003C\u002Fcode> with \u003Ccode>probe.limit.cgroup-absent\u003C\u002Fcode> (no cgroup v2 hierarchy) or\n\u003Ccode>probe.limit.controller-not-delegated\u003C\u002Fcode>. Children other than the measured one always run under \u003Ccode>RLIMIT_DATA\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>A plugin's footprint, when the child took one, is the point's \u003Ccode>memory\u003C\u002Fcode>: how far the resident set grew from before the plugin\nloaded, in KB, after instantiate, after activate, at rest after processing, with notes held, and what a second instance\nadded. A figure the child could not take is absent, and \u003Ccode>unmeasuredReason\u003C\u002Fcode> says why when none could be.\u003C\u002Fp>\n\u003Cp>A crash, a hang and a timeout are outcomes in the document, never a missing document: the steps the child finished before\ndying stay in it. The exit status says whether there is one: 0 a complete run, 1 a document with some step that ended\notherwise, 2 no document, 3 no such plugin. The document is described by \u003Ccode>probe-output.schema.json\u003C\u002Fcode>, generated from the\ncodes in \u003Ccode>protocol.h\u003C\u002Fcode>, and installed with the protocol.\u003C\u002Fp>\n\u003Ch2 id=\"pins\">Pins\u003C\u002Fh2>\n\u003Cp>Why: a plugin is checked before the console trusts it. We measure one build of it for crashes, real-time safety and\nits parameters. The pin makes sure the bytes that load are the bytes that were checked, so an update or a swapped\nfile cannot slip in unchecked. The layout pin also protects the controls: presets, surfaces and the REST rows are\nmapped to the plugin's parameters, and a changed layout would send values to the wrong ones. It also leaves a record\nyou can audit: the exact plugin build that processed the audio.\u003C\u002Fp>\n\u003Cp>With \u003Ccode>require_pins\u003C\u002Fcode> on, the default, \u003Ccode>add\u003C\u002Fcode> admits only a plugin that has a pin: the SHA-256 of\nevery file the host loads for it, and its parameter layout fingerprint. Before any worker is spawned or sees the\n\u003Ccode>add\u003C\u002Fcode>, the daemon hashes each pinned file over one open descriptor: for a CLAP the files beside the \u003Ccode>.clap\u003C\u002Fcode> that\n\u003Ccode>clap:&lt;path&gt;#&lt;id&gt;\u003C\u002Fcode> names, the \u003Ccode>.clap\u003C\u002Fcode> itself among them; for an LV2 the files of the bundle whose \u003Ccode>manifest.ttl\u003C\u002Fcode> names\nthe URI, the manifest among them, and every file the manifest names with \u003Ccode>lv2:binary\u003C\u002Fcode> or \u003Ccode>rdfs:seeAlso\u003C\u002Fcode> for the plugin\nmust be held by the pin. No pin, or a layout pin in a scheme this version does not know, answers \u003Ccode>PHD_ERR_PIN_ABSENT\u003C\u002Fcode>;\na file missing, changed or not held answers \u003Ccode>PHD_ERR_PIN_BINARY_MISMATCH\u003C\u002Fcode>. For a CLAP the daemon then sends the worker\n\u003Ccode>pin_expect &lt;instance&gt; &lt;layout pin&gt;\u003C\u002Fcode> and the \u003Ccode>add\u003C\u002Fcode> unchanged, and the worker answers \u003Ccode>PHD_ERR_PIN_LAYOUT_MISMATCH\u003C\u002Fcode>\nwhen the layout after \u003Ccode>init\u003C\u002Fcode> is not the pinned one; a worker that refuses \u003Ccode>pin_expect\u003C\u002Fcode> gets no \u003Ccode>add\u003C\u002Fcode>, and its refusal\nis the reply, and one that dies on it or does not answer it is dropped with \u003Ccode>PHD_ERR_VERB_DROPPED\u003C\u002Fcode>, the\n\u003Ccode>instance_verb_dropped\u003C\u002Fcode> event naming the \u003Ccode>pin_expect\u003C\u002Fcode>. An LV2 worker gets no pin verb: its layout is its bundle's TTL,\nwhich the hash covers, in a world of that one bundle; so a pinned LV2 plugin gets a worker of its own, a \u003Ccode>default\u003C\u002Fcode> that\nresolves to a pool is placed \u003Ccode>own\u003C\u002Fcode> and an explicit \u003Ccode>pool:&lt;name&gt;\u003C\u002Fcode> answers \u003Ccode>PHD_ERR_PLACEMENT_INVALID\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Where the pin comes from is \u003Ccode>pin_mode\u003C\u002Fcode>. \u003Ccode>strict\u003C\u002Fcode> takes it from \u003Ccode>pin_set\u003C\u002Fcode> or from a \u003Ccode>pin_file\u003C\u002Fcode> loaded at start, and a\nplugin with no pin is refused. \u003Ccode>first-use\u003C\u002Fcode>, the default, records it: the first \u003Ccode>add\u003C\u002Fcode> of a plugin with no pin hashes its\nfiles, keeps the pin in the pin store (\u003Ccode>$XDG_STATE_HOME\u002Fplugin-hostd\u002Fpins\u003C\u002Fcode>) and places the instance \u003Ccode>own\u003C\u002Fcode>; the layout is\nasked of the worker after the add (\u003Ccode>pin_layout\u003C\u002Fcode>) and recorded too. A host that pins by itself sets \u003Ccode>pin_mode strict\u003C\u002Fcode>.\nThe store, a \u003Ccode>pin_file\u003C\u002Fcode> and \u003Ccode>pin_set\u003C\u002Fcode> carry one line format, \u003Ccode>pin_set &lt;uri&gt; &lt;files&gt; &lt;layout&gt; [verdict=&lt;word&gt;]\u003C\u002Fcode> with the\nverb optional in a file. In \u003Ccode>first-use\u003C\u002Fcode> only a pin with \u003Ccode>verdict=in-process\u003C\u002Fcode>, which plugin-qualify writes, lets a plugin\nshare a worker. A pin with \u003Ccode>verdict=refused\u003C\u002Fcode> names files that failed qualification. Their \u003Ccode>add\u003C\u002Fcode> answers \u003Ccode>-516\u003C\u002Fcode>\n(\u003Ccode>PIN_REFUSED\u003C\u002Fcode>), no worker sees it, and a replay is refused with the same code. A pin that changes to \u003Ccode>refused\u003C\u002Fcode> while\nthe instance runs takes effect at its next replay. Files that differ from the pin answer \u003Ccode>-509\u003C\u002Fcode> first, because the\nverdict was given for the pinned files only.\u003C\u002Fp>\n\u003Cp>The pins are read again while the daemon runs, so a plugin upgrade never needs a restart (#255). The daemon stats the\n\u003Ccode>pin_file\u003C\u002Fcode> and the \u003Ccode>pins_dir\u003C\u002Fcode> files at every idle tick and before every \u003Ccode>add\u003C\u002Fcode>, and reads them again when one changed\n(a rewrite in place or a rename over it); \u003Ccode>pin_reload\u003C\u002Fcode>, and the sync's \u003Ccode>pin_changed\u003C\u002Fcode> notice, do the same at once. The\nnew tables are put in whole or not at all: a \u003Ccode>pin_file\u003C\u002Fcode> with a line outside the grammar answers \u003Ccode>-902\u003C\u002Fcode> and the earlier\npins hold. A \u003Ccode>pin_set\u003C\u002Fcode> of a controller is not in any file and is kept. Running instances keep running: one whose files\nthe new pins refuse is logged on stderr, and its id in \u003Ccode>worker_list\u003C\u002Fcode> is followed by \u003Ccode>!\u003C\u002Fcode> until a pin holds it again. A plugin that changed since it was pinned is refused (-509, or -510 from the worker), the\n\u003Ccode>pin_changed &lt;uri&gt; files|layout\u003C\u002Fcode> event names what changed, and \u003Ccode>pin_accept &lt;uri&gt;\u003C\u002Fcode> takes the new pin.\u003C\u002Fp>\n\u003Cp>Pins that ship with packages live in a read-only layer of their own, under the host's. At start the daemon reads\nevery \u003Ccode>*.pins\u003C\u002Fcode> file of \u003Ccode>pins_dir\u003C\u002Fcode> (\u003Ccode>\u002Fusr\u002Fshare\u002Fplugin-hostd\u002Fpins.d\u003C\u002Fcode> by default; empty is none), in byte order of\ntheir names, in the same line format. A package drops its own file there, so its plugins and their pins are replaced\nin one transaction and removed together; plugin-hostd owns the directory and another package may co-own it. The\ndaemon never writes it. A pin from this layer is trusted as it is, in both pin modes. The rules:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>A pins.d pin with \u003Ccode>verdict=refused\u003C\u002Fcode> always holds. The pin store, a \u003Ccode>pin_file\u003C\u002Fcode> and \u003Ccode>pin_set\u003C\u002Fcode> never override it:\n\u003Ccode>pin_set\u003C\u002Fcode> and \u003Ccode>pin_accept\u003C\u002Fcode> of its uri answer \u003Ccode>-516\u003C\u002Fcode> (\u003Ccode>PIN_REFUSED\u003C\u002Fcode>), and a line of the store or of the \u003Ccode>pin_file\u003C\u002Fcode>\nfor it is kept but has no effect, which stderr says at start.\u003C\u002Fli>\n\u003Cli>Any other pins.d pin is under the host's layer. A pin of the same uri in the store, the \u003Ccode>pin_file\u003C\u002Fcode> or from\n\u003Ccode>pin_set\u003C\u002Fcode> holds over it, and \u003Ccode>pin_accept\u003C\u002Fcode> of a plugin whose files differ from its package pin records the new files\nin the store, which then hold. \u003Ccode>pin_clear\u003C\u002Fcode> forgets the host's pin only: the package pin holds again.\u003C\u002Fli>\n\u003Cli>When two pins.d files hold the same uri, a refusal wins; otherwise the file last in name order wins. Two lines of\none file follow the same rule, the later line in place of the later file.\u003C\u002Fli>\n\u003Cli>A line outside the grammar, or longer than a pin line can be, is skipped and named on stderr; the rest of the file\nis read. A file that cannot be read is named on stderr and skipped. A directory that is missing or empty holds no\npins and is no error.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>What cannot be pinned:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>a path holding ',', '=' or whitespace cannot be pinned: they are the separators of pin_set's words, and pin_set refuses it as a token outside its grammar.\u003C\u002Fli>\n\u003Cli>a pin_set line is at most line_max, 4096 bytes, the protocol socket's buffer; a longer one is refused as outside the grammar.\u003C\u002Fli>\n\u003Cli>a manifest that uses @base makes add answer OMX_REPLY_PLUGIN_HOSTD_PIN_BINARY_MISMATCH_RESP (-509): the daemon does not resolve it, so it cannot know the file the host would load. A file the manifest names by a percent-encoded IRI is pinned as written, one word, and opened decoded; a name with a stray % is refused the same way.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Pins are the controller's policy, like \u003Ccode>policy_set\u003C\u002Fcode>: not in the ledger, gone with the daemon, set again by a controller\nthat reconnects. A replayed \u003Ccode>add\u003C\u002Fcode> is checked again, so a file swapped while a worker was down is refused on respawn:\nthe daemon emits \u003Ccode>instance_replay_refused &lt;instance&gt; &lt;code&gt;\u003C\u002Fcode> with the refusal's own code (the pin's, or the worker's\nwhen it refuses the replayed \u003Ccode>pin_expect\u003C\u002Fcode> or \u003Ccode>add\u003C\u002Fcode>), writes \u003Ccode>PHD_ERR_REPLAY\u003C\u002Fcode>, the step and that code to stderr, and\nthe worker does not hold that instance until a later replay passes. The hashing and the layout serialisation are \u003Ccode>include\u002Fplugin-hostd\u002Fpin.h\u003C\u002Fcode>, installed beside the\nprotocol header for the hosts that check a layout.\u003C\u002Fp>\n\u003Ch2 id=\"the-running-history\">The running history\u003C\u002Fh2>\n\u003Cp>The daemon keeps what each plugin did on this machine, per plugin, per binary and per host class: the file named by\n\u003Ccode>history_file\u003C\u002Fcode>, else \u003Ccode>$XDG_STATE_HOME\u002Fplugin-hostd\u002Fhistory\u003C\u002Fcode>, else \u003Ccode>$HOME\u002F.local\u002Fstate\u002Fplugin-hostd\u002Fhistory\u003C\u002Fcode>. It is\nlocal: it holds URIs, digests and counters, no audio, no path, no user, session or preset name, the daemon sends it\nnowhere and no verb writes it from outside; \u003Ccode>history_clear &lt;uri | all&gt;\u003C\u002Fcode> deletes it. Only the daemon writes it, mode\n0600 in a directory of mode 0700, to a temporary file that is renamed over it, at most once per \u003Ccode>history_save_s\u003C\u002Fcode> and\nat quit. \u003Ccode>history_window_s\u003C\u002Fcode> 0 keeps none.\u003C\u002Fp>\n\u003Cp>The first line is \u003Ccode># plugin-hostd history\u002F1\u003C\u002Fcode>, then one line per key, \u003Ccode>history &lt;uri&gt; &lt;binary digest&gt; &lt;host class&gt; key=value ...\u003C\u002Fcode>. The binary digest is the SHA-256 of the first file the plugin's pin holds, so a plugin with no pin has\nno history and a changed plugin starts a record of its own, the old one kept and not read. The host class is\n\u003Ccode>arch\u002Fcores\u002Fclock\u003C\u002Fcode> as the probe writes it (\u003Ccode>x86_64\u002F5-8\u002F2.5-3.5GHz\u003C\u002Fcode>), or the \u003Ccode>host_class\u003C\u002Fcode> setting. The keys are the\nwords of \u003Ccode>PLUGIN_HOSTD_HISTORY_KEYS\u003C\u002Fcode> in \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fplugin-hostd\u002Fblob\u002Fb4ea6a9\u002Fdata\u002Fhistory.json\">data\u002Fhistory.json\u003C\u002Fa>: \u003Ccode>first\u003C\u002Fcode>, \u003Ccode>last\u003C\u002Fcode>, \u003Ccode>windows_solo\u003C\u002Fcode>,\n\u003Ccode>windows_grouped\u003C\u002Fcode>, \u003Ccode>cpu_p95_solo\u003C\u002Fcode>, \u003Ccode>cpu_max_solo\u003C\u002Fcode>, \u003Ccode>pss_mb_solo\u003C\u002Fcode>, \u003Ccode>xrun_windows_solo\u003C\u002Fcode>, \u003Ccode>xrun_windows_grouped\u003C\u002Fcode>,\n\u003Ccode>crashes_solo\u003C\u002Fcode>, \u003Ccode>crashes_grouped\u003C\u002Fcode>, \u003Ccode>restarts_grouped\u003C\u002Fcode>, \u003Ccode>quarantines\u003C\u002Fcode>, \u003Ccode>last_crash\u003C\u002Fcode>, \u003Ccode>last_crash_grouped\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>A window is \u003Ccode>history_window_s\u003C\u002Fcode> seconds of one worker: its utime plus stime from \u003Ccode>\u002Fproc\u002F&lt;pid&gt;\u002Fstat\u003C\u002Fcode> as percent of one\ncore, and the \u003Ccode>Pss\u003C\u002Fcode> of its \u003Ccode>smaps_rollup\u003C\u002Fcode>. A worker of its own gives a window to the plugin it holds; a worker of two\nor more gives one to each member, counted in \u003Ccode>windows_grouped\u003C\u002Fcode> and nowhere else, because a group's CPU cannot be split\namong its members. \u003Ccode>cpu_p95_solo\u003C\u002Fcode> is an estimate that needs no list of windows: each window above it moves it up\nby 0.95 of 2 percent of itself and each one not above moves it down by 0.05 of that. A window in which the members of\nthe worker changed is dropped, and a worker that died is counted if it had been up for half the window. A crash is\ncounted when the daemon names a culprit (\u003Ccode>crashes_solo\u003C\u002Fcode> in a worker of its own, \u003Ccode>crashes_grouped\u003C\u002Fcode> in a group), the\nmembers that went down with it and were not the culprit get \u003Ccode>restarts_grouped\u003C\u002Fcode>, and a quarantine counts in\n\u003Ccode>quarantines\u003C\u002Fcode>. A worker writes \u003Ccode>xruns &lt;count&gt;\u003C\u002Fcode> on its feedback port, the JACK xruns it has counted since it started,\nwhen the count changes. The daemon takes the first count of a process as its baseline, never as xruns of the window it\narrives in, and at the close of a window adds one to \u003Ccode>xrun_windows_solo\u003C\u002Fcode> or \u003Ccode>xrun_windows_grouped\u003C\u002Fcode> of every member of\nthe worker when the count rose in it, however many xruns it rose by. A worker that wrote no count counted none; a\nrestarted worker counts from zero and its first count is a baseline again; a line that is not the word and one whole\nnumber is not a count.\u003C\u002Fp>\n\u003Cp>A line this version cannot read, or with a key it does not know, is kept as it is by every save and is not read. A file\nthat cannot be read, or whose first line is another version, is neither read nor overwritten: stderr says why, and\n\u003Ccode>history_get\u003C\u002Fcode> answers \u003Ccode>unavailable\u003C\u002Fcode> until the file is repaired or removed.\u003C\u002Fp>\n\u003Cp>\u003Ccode>history_get &lt;uri&gt;\u003C\u002Fcode> answers the record of the binary the pin holds now, on this host class, as one word: \u003Ccode>digest=\u003C\u002Fcode>,\n\u003Ccode>class=\u003C\u002Fcode>, \u003Ccode>crashed=1\u003C\u002Fcode> when a crash is within 30 days, \u003Ccode>raises_xruns=1\u003C\u002Fcode> when the share of xrun windows in a group\nexceeds the share alone by 5 points (from 30 windows in a group), and then every key. \u003Ccode>-\u003C\u002Fcode> is no record.\u003C\u002Fp>\n\u003Cp>The planner reads that summary. A plugin the history marks \u003Ccode>crashed\u003C\u002Fcode>, or the daemon has quarantined, is left alone by\nthe next plan with the reason \u003Ccode>history-crashed\u003C\u002Fcode>; one marked \u003Ccode>raises_xruns\u003C\u002Fcode> with \u003Ccode>history-xruns\u003C\u002Fcode>. Both are judged after\nthe pin's rules (a history makes a plan more careful than the pin, never less) and before the cost. A plugin's cost is\nthe larger of its qualification record's and its \u003Ccode>cpu_p95_solo\u003C\u002Fcode> (percent of one core, from the windows it ran alone). A\nplugin with no history is judged by its pin and its cost alone. With the history blocked or \u003Ccode>history_window_s\u003C\u002Fcode> 0 the plan\nis the pins' and the costs', and every member with nothing harder to say says \u003Ccode>history-unavailable\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>A plan is made again by the daemon, never in the middle of a cycle of a worker, when a member of it is quarantined or\nits quarantine is cleared, and \u003Ccode>history_regroup_s\u003C\u002Fcode> seconds after a death that named no culprit and split a group, if no\nmember of the plan has died since: the segments that did not change keep their workers, a group that was split is\ngathered, and the member the history marks goes alone. The new reasons come as a \u003Ccode>plan_reason\u003C\u002Fcode> event and in \u003Ccode>plan_get\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>\u003Ccode>estimate &lt;rate&gt; &lt;quantum&gt; &lt;uri&gt; [&lt;uri&gt; ...]\u003C\u002Fcode> answers what a chain of those plugins would cost before any of them is\nadded: a chain editor asks it before an insert. It loads nothing and moves nothing. The figures come from the\nqualification records of \u003Ccode>qualification_dir\u003C\u002Fcode>, the grid point at that rate and quantum: the latency is the measured\nframes, else the declared ones, added up; the CPU is the cost median in nanoseconds per sample times the rate, added up,\nas percent of one core's cycle. No per-worker overhead is added: none is measured. The RAM is the history's\n\u003Ccode>pss_mb_solo\u003C\u002Fcode> of each member, in bytes, and \u003Ccode>-\u003C\u002Fcode> unless every member has one. The workers are the segments \u003Ccode>plan\u003C\u002Fcode> would make of the members, so an isolated plugin counts a worker of\nits own. A member with no figure at that rate and quantum is counted and named by its position in the line, from 0,\nwith \u003Ccode>-533\u003C\u002Fcode> (no record names it), \u003Ccode>-534\u003C\u002Fcode> (no point of the grid at that rate and quantum with a cost and a latency) or\n\u003Ccode>-535\u003C\u002Fcode> (the uri names no plugin installed here, which \u003Ccode>plan\u003C\u002Fcode> would place nowhere); the latency and the CPU add up only\nthe others, so a client says &quot;not measured&quot; for those members and never reads their figure as 0.\u003C\u002Fp>\n\u003Cp>Four more words answer whether the chain fits in memory. \u003Ccode>ram_used_bytes\u003C\u002Fcode> is what the plugins running now hold, the Pss of\nevery worker, \u003Ccode>-\u003C\u002Fcode> when one cannot be read. \u003Ccode>ram_added_bytes\u003C\u002Fcode> is what the members would add, from the memory of the\nqualification records at that rate and quantum: what instances of one plugin share is counted once in a segment, since a\nsegment is one process, and again in another segment, which loads it again. \u003Ccode>ram_budget_bytes\u003C\u002Fcode> is the host's \u003Ccode>ram_budget_mb\u003C\u002Fcode>,\n\u003Ccode>-\u003C\u002Fcode> when none is set. \u003Ccode>ram_unknown_count\u003C\u002Fcode> is how many members have no figure: they add nothing to the sum and are not 0, and\nwhen no member has one \u003Ccode>ram_added_bytes\u003C\u002Fcode> is \u003Ccode>-\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>estimate 48000 128 clap:\u002Fusr\u002Flib64\u002Fclap\u002Fa.clap#org.example.a clap:\u002Fusr\u002Flib64\u002Fclap\u002Fa.clap#org.example.b\nresp 0 64 9.60 - 1 1 1:-534 0 104857600 2147483648 1\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"what-a-worker-must-do\">What a worker must do\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>answer mod-host's protocol on \u003Ccode>-n -p &lt;port&gt; -f &lt;port&gt;\u003C\u002Fcode>, the feedback port opened by the daemon right after the\ncommand port;\u003C\u002Fli>\n\u003Cli>print a line ending \u003Ccode>ready!\u003C\u002Fcode> on stdout once its socket accepts;\u003C\u002Fli>\n\u003Cli>write, for \u003Ccode>state_save &lt;dir&gt;\u003C\u002Fcode>, files whose names begin \u003Ccode>effect_&lt;instance&gt;\u003C\u002Fcode> and read them back on\n\u003Ccode>state_load &lt;dir&gt;\u003C\u002Fcode>, skipping an instance with no file.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Ccode>mod-host\u003C\u002Fcode> and \u003Ccode>omx-clap-host\u003C\u002Fcode> do.\u003C\u002Fp>\n\u003Ch2 id=\"formats\">Formats\u003C\u002Fh2>\n\u003Cp>The daemon holds its plugin formats in one table, \u003Ccode>src\u002Fformats.c\u003C\u002Fcode>, and nothing else in the daemon, the protocol or the\npins names a format. A row says how a uri reaches the format (\u003Ccode>prefix\u003C\u002Fcode>, \u003Ccode>strip_prefix\u003C\u002Fcode>, \u003Ccode>fallback\u003C\u002Fcode>), which program serves\nit (\u003Ccode>worker\u003C\u002Fcode>), where its plugins are searched and how a worker's world is narrowed to one plugin (\u003Ccode>search\u003C\u002Fcode>, \u003Ccode>world_env\u003C\u002Fcode>,\n\u003Ccode>narrow_world\u003C\u002Fcode>), which files a pin holds (\u003Ccode>pin_collect\u003C\u002Fcode>), whether the worker checks the layout (\u003Ccode>layout_check\u003C\u002Fcode>), whether\na pinned plugin must run in a worker of its own (\u003Ccode>pinned_own_only\u003C\u002Fcode>) and who answers the instance verbs\n(\u003Ccode>native_instance_verbs\u003C\u002Fcode>, else \u003Ccode>param_info\u003C\u002Fcode>). Adding a format is a row and its worker; \u003Ccode>formats_register\u003C\u002Fcode> refuses a row\nwith a capability missing and says which. a test registers a third format in the test and takes it through\n\u003Ccode>add\u003C\u002Fcode>, \u003Ccode>param_set\u003C\u002Fcode>, \u003Ccode>pin_set\u003C\u002Fcode> and \u003Ccode>remove\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"who-runs-an-lv2-plugin\">Who runs an LV2 plugin\u003C\u002Fh2>\n\u003Cp>\u003Ccode>lv2_worker\u003C\u002Fcode> chooses the program that runs LV2 plugins: \u003Ccode>auto\u003C\u002Fcode> (the default: the adapter first, mod-host for a plugin the\nadapter refuses, and for every add while omx-clap-host is not installed), \u003Ccode>omx-clap-host\u003C\u002Fcode> (the \u003Ccode>clap_host\u003C\u002Fcode> program, through\nits LV2 adapter, a plugin it cannot run refused with a code) or \u003Ccode>mod-host\u003C\u002Fcode> (the \u003Ccode>mod_host\u003C\u002Fcode> program). \u003Ccode>lv2_worker_set &lt;uri&gt; &lt;mod-host|omx-clap-host|auto|-&gt;\u003C\u002Fcode> overrides it for one plugin from then on, and \u003Ccode>-\u003C\u002Fcode> takes\nthe override back. The two programs are two rows of the table, \u003Ccode>lv2\u003C\u002Fcode> and \u003Ccode>lv2-clap\u003C\u002Fcode>, so \u003Ccode>policy_set\u003C\u002Fcode>, \u003Ccode>worker_env\u003C\u002Fcode> and\n\u003Ccode>worker_list\u003C\u002Fcode> name them like any format. The adapter row differs from the mod-host row in these ways, each held by a test:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>capability\u003C\u002Fth>\n\u003Cth>\u003Ccode>lv2\u003C\u002Fcode> (mod-host)\u003C\u002Fth>\n\u003Cth>\u003Ccode>lv2-clap\u003C\u002Fcode> (omx-clap-host)\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>worker\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>mod_host\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>clap_host\u003C\u002Fcode>, given the uri with its \u003Ccode>lv2:\u003C\u002Fcode> prefix\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>native_instance_verbs\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>no: the daemon answers \u003Ccode>track_info\u003C\u002Fcode>, \u003Ccode>remote_pages\u003C\u002Fcode>, \u003Ccode>remote_page_get\u003C\u002Fcode> and \u003Ccode>param_info\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>yes: the worker answers them from the plugin, and \u003Ccode>track_info\u003C\u002Fcode> is replayed to it after a respawn\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>layout_check\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>no\u003C\u002Ftd>\n\u003Ctd>no: an LV2 pin holds the layout of the plugin's ports, not of the CLAP parameters the adapter presents, so \u003Ccode>pin_expect\u003C\u002Fcode> would refuse every pin \u003Ccode>plugin-qualify\u003C\u002Fcode> wrote\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>world_scope\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>one bundle, narrowed: \u003Ccode>LV2_PATH\u003C\u002Fcode> holds a link to the plugin's bundle\u003C\u002Ftd>\n\u003Ctd>the same: the adapter opens bundles through the LV2 world\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pin_pool\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>no: a pinned plugin is placed \u003Ccode>own\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the same, for the same reason\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>An adapter handles a subset of LV2. When it refuses a plugin, the worker answers the add \u003Ccode>resp -102 &lt;hosting code&gt;\u003C\u002Fcode>\n(for instance \u003Ccode>hosting.features.midi-in-fed-empty\u003C\u002Fcode>, \u003Ccode>hosting.features.missing\u003C\u002Fcode>, \u003Ccode>hosting.topology.wider-than-strip\u003C\u002Fcode> or\n\u003Ccode>hosting.no-realisation\u003C\u002Fcode>). The add under \u003Ccode>omx-clap-host\u003C\u002Fcode> then answers \u003Ccode>-512\u003C\u002Fcode> (\u003Ccode>LV2_ADAPTER_REFUSED\u003C\u002Fcode>) and the\n\u003Ccode>lv2_adapter_refused\u003C\u002Fcode> event carries that code, read from the reply to that add and never from the worker's log, which a\npool worker shares with other plugins (\u003Ccode>-\u003C\u002Fcode> when the reply named none). Under \u003Ccode>auto\u003C\u002Fcode> the add is made again on the \u003Ccode>lv2\u003C\u002Fcode>\nrow, the plugin stays there, the event is sent once, and the controller never sees \u003Ccode>-512\u003C\u002Fcode>. The daemon remembers the refusal until\nthe adapter has a reason to take the plugin again: \u003Ccode>lv2_worker_set\u003C\u002Fcode> of that uri (to any word, \u003Ccode>-\u003C\u002Fcode> included) forgets it, and\nso does a change of pins (\u003Ccode>pin_set\u003C\u002Fcode>, \u003Ccode>pin_accept\u003C\u002Fcode>, \u003Ccode>pin_clear\u003C\u002Fcode>) for every plugin; the next add under \u003Ccode>auto\u003C\u002Fcode> asks the\nadapter once more.\u003C\u002Fp>\n\u003Cp>A plugin the adapter refused under \u003Ccode>auto\u003C\u002Fcode> runs on the \u003Ccode>lv2\u003C\u002Fcode> row in a worker of its own, whatever the policy says, unless\nits add names a placement. The adapter never ran it, so nothing says it is safe in a shared worker. Some plugins abort\nin instantiate: drumkv1, samplv1 and synthv1 do, through Qt, when no display is set. Such a plugin takes down only\nits own worker. The add answers \u003Ccode>-102\u003C\u002Fcode>, and an \u003Ccode>instance_verb_dropped\u003C\u002Fcode> event names the add with its uri.\u003C\u002Fp>\n\u003Cp>A plugin that no bundle of the worker's world holds is not a refusal: the worker answers \u003Ccode>resp -101\u003C\u002Fcode> with no code. Under\n\u003Ccode>omx-clap-host\u003C\u002Fcode> the add answers that \u003Ccode>-101\u003C\u002Fcode>, with no event. Under \u003Ccode>auto\u003C\u002Fcode> the same add is made on the \u003Ccode>lv2\u003C\u002Fcode> row, so mod-host\nlooks for the plugin; nothing is remembered, and the adapter is asked again on the next add. Under \u003Ccode>auto\u003C\u002Fcode> an\n\u003Ccode>omx-clap-host\u003C\u002Fcode> that is not installed is not an error either: the add goes to the \u003Ccode>lv2\u003C\u002Fcode> row.\u003C\u002Fp>\n",[59,61,64,67,69],{"slug":52,"title":60},"docs\u002Fformats.md",{"slug":62,"title":63},"own-host","the highest SCHED_FIFO priority, which the probe asks for, and a lock as large as the probe's memory limit",{"slug":65,"title":66},"panel","docs\u002Fpanel.md",{"slug":25,"title":68},"docs\u002Fplacement.md",{"slug":70,"title":71},"presets","Presets in the host",1793924849752]