[{"data":1,"prerenderedAt":51},["ShallowReactive",2],{"project-omx-panel-worked-example":3},{"page":4,"others":29},{"slug":5,"src":6,"title":7,"source":8,"toc":9,"html":28},"worked-example","docs\u002Fworked-example.md","Worked example: a third-party LV2 and CLAP plugin to a generated panel, adapted to Zynthian","https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fdocs\u002Fworked-example.md",[10,13,16,19,22,25],{"id":11,"title":12},"where-it-ran","Where it ran",{"id":14,"title":15},"1-the-plugins-as-installed","1. The plugins as installed",{"id":17,"title":18},"2-the-scan-into-a-descriptor","2. The scan into a descriptor",{"id":20,"title":21},"3-the-layout-and-the-mod-gui","3. The layout and the MOD GUI",{"id":23,"title":24},"4-zynthian","4. Zynthian",{"id":26,"title":27},"what-is-verified-and-what-is-not","What is verified, and what is not","\u003Ch1 id=\"worked-example-a-third-party-lv2-and-clap-plugin-to-a-generated-panel-adapted-to-zynthian\">Worked example: a third-party LV2 and CLAP plugin to a generated panel, adapted to Zynthian\u003C\u002Fh1>\n\u003Cp>This takes two plugins nobody here wrote, as a distribution installs them, through the whole panel path: the\nscan into a descriptor, the layout, the MOD GUI and the test that holds it to the descriptor. It then follows\nthe LV2 one to where Zynthian looks for it.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>LV2\u003C\u002Fstrong>: ZamComp, Damien Zammit's mono compressor (\u003Ccode>urn:zamaudio:ZamComp\u003C\u002Fcode>), from Fedora's \u003Ccode>lv2-zam-plugins\u003C\u002Fcode>.\nSection 4 reads, from Zynthian's sources, where it would look for it.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>CLAP\u003C\u002Fstrong>: LSP Limiter Mono (\u003Ccode>in.lsp-plug.limiter_mono\u003C\u002Fcode>), from Fedora's \u003Ccode>lsp-plugins-clap\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Every command below was run as written, from the root of this repository, and its output is shown under it, or\nis the committed file it writes under \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fexamples\u002Fworked-example\u002F\">\u003Ccode>examples\u002Fworked-example\u002F\u003C\u002Fcode>\u003C\u002Fa>. What each\ncommand printed is also committed, one file per command, in\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fexamples\u002Fworked-example\u002Ftranscript\u002F\">\u003Ccode>examples\u002Fworked-example\u002Ftranscript\u002F\u003C\u002Fcode>\u003C\u002Fa>, written by\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fexamples\u002Fworked-example\u002Frepeat.sh\">\u003Ccode>repeat.sh\u003C\u002Fcode>\u003C\u002Fa> (run it after the setup of the next section; a command that\nprints nothing leaves no file). The output shown here is that transcript, line for line. A \u003Ccode>[exit N]\u003C\u002Fcode> line is\nthe command's exit status when it is not 0. The \u003Ccode>rpm -q\u003C\u002Fcode> and \u003Ccode>lv2ls\u003C\u002Fcode> lines and the package versions are those of\nthe container the run was made in. Nothing here was run on a Zynthian or a MOD: the last section says what\ncomes from Zynthian's sources and what is still to be seen on one.\u003C\u002Fp>\n\u003Ch2 id=\"where-it-ran\">Where it ran\u003C\u002Fh2>\n\u003Cp>A Fedora 44 container (the \u003Ccode>openmixer-worker\u003C\u002Fcode> image, whose packages the commands below upgrade), the Fedora\nrepositories and the FreeMixer channel enabled. The image also carries a copr repository, which the\ninstalls leave out so that every plugin comes from Fedora itself. As root:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>dnf -y -q --disablerepo=copr-ycollet-audinux install lv2-zam-plugins lsp-plugins-clap omx-clap-host plugin-hostd plugin-hostd-devel omx-contract-devel\ndnf -y -q --disablerepo=copr-ycollet-audinux upgrade omx-contract omx-contract-devel omx-clap-host omx-clap-core plugin-hostd plugin-hostd-devel\nln -s &quot;$PWD\u002Fbin\u002Fomx-panel.mjs&quot; \u002Fusr\u002Flocal\u002Fbin\u002Fomx-panel\ndnf -y -q --disablerepo=copr-ycollet-audinux install omx-panel\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>and, as the user, \u003Ccode>npm ci --silent\u003C\u002Fcode> in this checkout.\u003C\u002Fp>\n\u003Cp>On a stock Fedora 44, the OpenMixer channel comes first, as this repository's CI adds it\n(\u003Ccode>dnf install https:\u002F\u002Fwww.openmixer.org\u002Frpm\u002Fopenmixer-release.noarch.rpm\u003C\u002Fcode>; not run here, the\nimage carries the channel), and \u003Ccode>python3-lilv\u003C\u002Fcode> and \u003Ccode>sord\u003C\u002Fcode> are installed with the rest (the image carries them:\n\u003Ccode>python3-lilv-0.26.4\u003C\u002Fcode>, \u003Ccode>sord-0.16.22\u003C\u002Fcode>, \u003Ccode>lv2-1.18.10\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Cp>\u003Ccode>omx-panel\u003C\u002Fcode> is this checkout, run as \u003Ccode>omx-panel\u003C\u002Fcode> through the link above (\u003Ccode>\u002Fusr\u002Flocal\u002Fbin\u003C\u002Fcode> comes before\n\u003Ccode>\u002Fusr\u002Fbin\u003C\u002Fcode> on the path). The commands ran at \u003Ccode>3ebf9b7\u003C\u002Fcode>, the commit that adds \u003Ccode>repeat.sh\u003C\u002Fcode>; its omx-panel is\n\u003Ccode>origin\u002Fmain\u003C\u002Fcode> at \u003Ccode>15cc25bb9\u003C\u002Fcode> (pull request 26 merged, so the readout fix of omx-panel#25 is in), and the branch\nadds only the example, this document, a line of the README and the exemption of the example's output files in\n\u003Ccode>tools\u002Fcheck-spdx.mjs\u003C\u002Fcode>. The released omx-panel 0.2.5, installed last, is run as \u003Ccode>\u002Fusr\u002Fbin\u002Fomx-panel\u003C\u002Fcode>\nonce: it stops on ZamComp (\u003Ca href=\"#the-released-025-on-zamcomp\">section 3\u003C\u002Fa>). Every other\ncommand runs as an unprivileged user.\u003C\u002Fp>\n\u003Ch2 id=\"1-the-plugins-as-installed\">1. The plugins as installed\u003C\u002Fh2>\n\u003Cpre>\u003Ccode>$ mkdir -p examples\u002Fworked-example\u002Fzamcomp examples\u002Fworked-example\u002Flsp-limiter-mono\n\n$ rpm -q lv2-zam-plugins lsp-plugins-clap\nlv2-zam-plugins-4.4-7.fc44.x86_64\nlsp-plugins-clap-1.2.29-1.fc44.x86_64\n\n$ rpm -ql lv2-zam-plugins | grep '^\u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002F'\n\u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002FZamComp_dsp.so\n\u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002FZamComp_dsp.ttl\n\u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002FZamComp_ui.so\n\u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002FZamComp_ui.ttl\n\u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002Fmanifest.ttl\n\u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002Fpresets.ttl\n\n$ rpm -qf \u002Fusr\u002Flib64\u002Fclap\u002Flsp-plugins.clap\nlsp-plugins-clap-1.2.29-1.fc44.x86_64\n\n$ lv2ls | grep -x urn:zamaudio:ZamComp\nurn:zamaudio:ZamComp\n\n$ lv2info urn:zamaudio:ZamComp &gt; examples\u002Fworked-example\u002Fzamcomp\u002Flv2info.txt\n\n$ omx-clap-scan \u002Fusr\u002Flib64\u002Fclap\u002Flsp-plugins.clap | sed -n '\u002F^  plugin in.lsp-plug.limiter_mono \u002F,\u002F^    note ports\u002Fp' &gt; examples\u002Fworked-example\u002Flsp-limiter-mono\u002Fomx-clap-scan.txt\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fexamples\u002Fworked-example\u002Fzamcomp\u002Flv2info.txt\">\u003Ccode>zamcomp\u002Flv2info.txt\u003C\u002Fcode>\u003C\u002Fa> is ZamComp as lilv reads it: three\naudio ports, eight input controls (\u003Ccode>att\u003C\u002Fcode>, \u003Ccode>rel\u003C\u002Fcode>, \u003Ccode>kn\u003C\u002Fcode>, \u003Ccode>rat\u003C\u002Fcode>, \u003Ccode>thr\u003C\u002Fcode>, \u003Ccode>mak\u003C\u002Fcode>, \u003Ccode>slew\u003C\u002Fcode>, \u003Ccode>sidech\u003C\u002Fcode>, ports 3 to 10)\nand two output controls, the readouts \u003Ccode>gr\u003C\u002Fcode> (gain reduction) and \u003Ccode>outlevel\u003C\u002Fcode> (ports 11 and 12). lilv lists the\nthree presets in an order that changes from run to run, so a repeat can differ from the committed file in those\nthree lines and nowhere else.\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fexamples\u002Fworked-example\u002Flsp-limiter-mono\u002Fomx-clap-scan.txt\">\u003Ccode>lsp-limiter-mono\u002Fomx-clap-scan.txt\u003C\u002Fcode>\u003C\u002Fa> is the\nlimiter as omx-clap-scan lists it, version 1.0.33, 28 parameters; the scan of the whole \u003Ccode>lsp-plugins.clap\u003C\u002Fcode>\nlists every plugin the file holds, and \u003Ccode>sed\u003C\u002Fcode> keeps this one.\u003C\u002Fp>\n\u003Ch2 id=\"2-the-scan-into-a-descriptor\">2. The scan into a descriptor\u003C\u002Fh2>\n\u003Cp>One step writes a \u003Ccode>scanned\u003C\u002Fcode> descriptor (omx-contract \u003Ccode>docs\u002Fdescriptors.md\u003C\u002Fcode>) for either format:\n\u003Ccode>plugin-hostd-probe describe\u003C\u002Fcode> (plugin-hostd 0.7.0 and later, its \u003Ccode>docs\u002Fformats.md\u003C\u002Fcode>). It runs omx-clap-core's\n\u003Ccode>omx-clap-scan --fields\u003C\u002Fcode>, the dump of every field one CLAP or LV2 plugin states, read as a host reads it (for\nLV2, through lilv), and maps each field to a descriptor word by plugin-hostd's format tables. So the LV2 scan\nto a descriptor exists, and it is the same step as the CLAP one.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ rpm -q omx-clap-host omx-clap-core plugin-hostd omx-contract\nomx-clap-host-0.20.1-1.fc44.x86_64\nomx-clap-core-0.20.1-1.fc44.x86_64\nplugin-hostd-0.10.0-1.fc44.x86_64\nomx-contract-3.1.0-1.fc44.noarch\n\n$ omx-clap-scan --fields lv2:urn:zamaudio:ZamComp &gt; examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.fields.tsv\n\n$ plugin-hostd-probe describe lv2:urn:zamaudio:ZamComp &gt; examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.descriptor.json\n\n$ omx-clap-scan --fields clap:\u002Fusr\u002Flib64\u002Fclap\u002Flsp-plugins.clap#in.lsp-plug.limiter_mono &gt; examples\u002Fworked-example\u002Flsp-limiter-mono\u002Flimiter_mono.fields.tsv\n\n$ plugin-hostd-probe describe clap:\u002Fusr\u002Flib64\u002Fclap\u002Flsp-plugins.clap#in.lsp-plug.limiter_mono &gt; examples\u002Fworked-example\u002Flsp-limiter-mono\u002Flimiter_mono.descriptor.json\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The dumps are the committed \u003Ccode>.fields.tsv\u003C\u002Fcode> files, the descriptors the \u003Ccode>.descriptor.json\u003C\u002Fcode> beside them. What a\nscan cannot know, it writes as \u003Ccode>unknown\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>every control's \u003Ccode>meaning\u003C\u002Fcode> is \u003Ccode>unknown\u003C\u002Fcode> (neither format states what a control means), so the layout infers no\nfamily and no roles: both plugins are family \u003Ccode>none\u003C\u002Fcode>;\u003C\u002Fli>\n\u003Cli>ZamComp's units are its TTL's (\u003Ccode>ms\u003C\u002Fcode>, \u003Ccode>dB\u003C\u002Fcode>), its \u003Ccode>rat\u003C\u002Fcode> and \u003Ccode>slew\u003C\u002Fcode> state none (\u003Ccode>unknown\u003C\u002Fcode>); \u003Ccode>gr\u003C\u002Fcode> and \u003Ccode>outlevel\u003C\u002Fcode>\nare \u003Ccode>readonly\u003C\u002Fcode>, with a range and no default;\u003C\u002Fli>\n\u003Cli>the limiter's controls are keyed by CLAP parameter id, a number; their units are \u003Ccode>unknown\u003C\u002Fcode> and their scales\n\u003Ccode>unknown\u003C\u002Fcode> or \u003Ccode>stepped\u003C\u002Fcode>, as CLAP states neither.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"3-the-layout-and-the-mod-gui\">3. The layout and the MOD GUI\u003C\u002Fh2>\n\u003Ch3 id=\"zamcomp-with-no-panel-file\">ZamComp, with no panel file\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>$ omx-panel layout --descriptor examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.descriptor.json &gt; examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.layout.json\n\n$ omx-panel layout --descriptor examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.descriptor.json --pages | tee examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.pages.json\n[\n  {\n    &quot;section&quot;: 0,\n    &quot;sectionName&quot;: &quot;Controls&quot;,\n    &quot;pageName&quot;: &quot;Controls 1&quot;,\n    &quot;ids&quot;: [\n      &quot;att&quot;,\n      &quot;rel&quot;,\n      &quot;kn&quot;,\n      &quot;rat&quot;,\n      &quot;thr&quot;,\n      &quot;mak&quot;,\n      &quot;slew&quot;,\n      &quot;sidech&quot;\n    ]\n  },\n  {\n    &quot;section&quot;: 0,\n    &quot;sectionName&quot;: &quot;Controls&quot;,\n    &quot;pageName&quot;: &quot;Controls 2&quot;,\n    &quot;ids&quot;: [\n      &quot;gr&quot;,\n      &quot;outlevel&quot;,\n      null,\n      null,\n      null,\n      null,\n      null,\n      null\n    ]\n  }\n]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>ZamComp's TTL states no port groups, so every control is in the one section \u003Ccode>Controls\u003C\u002Fcode>, in port order, cut\ninto pages of eight (the page rule of \u003Ccode>docs\u002Fpanel-layout.md\u003C\u002Fcode>). The two readouts take the second page: the\nlayout pages every control it lists, a readout included.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ omx-panel modgui --descriptor examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.descriptor.json --out examples\u002Fworked-example\u002Fzamcomp\u002Fno-panel\u002FZamComp.lv2\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fno-panel\u002FZamComp.lv2\u002Fmodgui.ttl\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fno-panel\u002FZamComp.lv2\u002Fmodgui\u002Ficon-ZamComp.html\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fno-panel\u002FZamComp.lv2\u002Fmodgui\u002Fstylesheet-ZamComp.css\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fno-panel\u002FZamComp.lv2\u002Fmodgui\u002Fscreenshot-ZamComp.png\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fno-panel\u002FZamComp.lv2\u002Fmodgui\u002Fthumbnail-ZamComp.png\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fno-panel\u002FZamComp.lv2\u002Fmodgui\u002Fknobs\u002Fomx-knob.png\n\n$ tools\u002Fmodgui-test.sh examples\u002Fworked-example\u002Fzamcomp\u002Fno-panel\u002FZamComp.lv2 examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.descriptor.json\nPASS modgui-gen --check ZamComp\nPASS template draws att with its declared travel and default\nPASS template draws rel with its declared travel and default\nPASS template draws kn with its declared travel and default\nPASS template draws rat with its declared travel and default\nPASS template draws thr with its declared travel and default\nPASS template draws mak with its declared travel and default\nPASS template draws slew with its declared travel and default\nPASS template draws sidech with its declared travel and default\nPASS template draws readout gr as a display with its declared range\nPASS template draws readout outlevel as a display with its declared range\nPASS template draws exactly the 10 declared parameters\nPASS sord_validate ZamComp.lv2\u002F*.ttl against the LV2 specs, modgui terms and resource-hint terms (Found 21 errors among 85 files (checked 1947 restrictions); all 21 the label errors of omx-contract#144)\nPASS sord_validate refuses a modgui property outside modgui-terms.ttl\nPASS a moved default makes modgui-gen --check fail\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The eight input controls are knobs (none is a toggle or a choice in the TTL), the two readouts displays\n(\u003Ccode>docs\u002Fmodgui.md\u003C\u002Fcode>); \u003Ccode>modgui.ttl\u003C\u002Fcode> lists the eight as \u003Ccode>modgui:port\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch3 id=\"zamcomp-with-a-panel-file\">ZamComp, with a panel file\u003C\u002Fh3>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fexamples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.panel.json\">\u003Ccode>zamcomp\u002Fzamcomp.panel.json\u003C\u002Fcode>\u003C\u002Fa> is a panel written for\nthis example: the detector controls in one section, the makeup gain in a second as a fader, the two readouts in\na third. Its family is \u003Ccode>none\u003C\u002Fcode>: a declared \u003Ccode>dynamics\u003C\u002Fcode> would be refused, since no control of the scan carries the\nmeaning \u003Ccode>threshold\u003C\u002Fcode> or \u003Ccode>ratio\u003C\u002Fcode> (\u003Ccode>docs\u002Fpanel-layout.md\u003C\u002Fcode>, the family).\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ omx-panel layout --descriptor examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.descriptor.json --panel examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.panel.json --pages | tee examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.panel.pages.json\n[\n  {\n    &quot;section&quot;: 0,\n    &quot;sectionName&quot;: &quot;Detector&quot;,\n    &quot;pageName&quot;: &quot;Detector&quot;,\n    &quot;ids&quot;: [\n      &quot;thr&quot;,\n      &quot;rat&quot;,\n      &quot;kn&quot;,\n      &quot;att&quot;,\n      &quot;rel&quot;,\n      &quot;slew&quot;,\n      &quot;sidech&quot;,\n      null\n    ]\n  },\n  {\n    &quot;section&quot;: 1,\n    &quot;sectionName&quot;: &quot;Output&quot;,\n    &quot;pageName&quot;: &quot;Output&quot;,\n    &quot;ids&quot;: [\n      &quot;mak&quot;,\n      null,\n      null,\n      null,\n      null,\n      null,\n      null,\n      null\n    ]\n  },\n  {\n    &quot;section&quot;: 2,\n    &quot;sectionName&quot;: &quot;Meters&quot;,\n    &quot;pageName&quot;: &quot;Meters&quot;,\n    &quot;ids&quot;: [\n      &quot;gr&quot;,\n      &quot;outlevel&quot;,\n      null,\n      null,\n      null,\n      null,\n      null,\n      null\n    ]\n  }\n]\n\n$ omx-panel modgui --descriptor examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.descriptor.json --panel examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.panel.json --out examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\u002Fmodgui.ttl\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\u002Fmodgui\u002Ficon-ZamComp.html\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\u002Fmodgui\u002Fstylesheet-ZamComp.css\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\u002Fmodgui\u002Fscreenshot-ZamComp.png\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\u002Fmodgui\u002Fthumbnail-ZamComp.png\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\u002Fmodgui\u002Fknobs\u002Fomx-knob.png\nmodgui: wrote examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\u002Fmodgui\u002Fknobs\u002Fomx-fader.png\n\n$ tools\u002Fmodgui-test.sh examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2 examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.descriptor.json examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.panel.json\nPASS modgui-gen --check ZamComp\nPASS template draws thr with its declared travel and default\nPASS template draws rat with its declared travel and default\nPASS template draws kn with its declared travel and default\nPASS template draws att with its declared travel and default\nPASS template draws rel with its declared travel and default\nPASS template draws slew with its declared travel and default\nPASS template draws sidech with its declared travel and default\nPASS template draws mak with its declared travel and default\nPASS template draws readout gr as a display with its declared range\nPASS template draws readout outlevel as a display with its declared range\nPASS template draws exactly the 10 declared parameters\nPASS sord_validate ZamComp.lv2\u002F*.ttl against the LV2 specs, modgui terms and resource-hint terms (Found 21 errors among 85 files (checked 1938 restrictions); all 21 the label errors of omx-contract#144)\nPASS sord_validate refuses a modgui property outside modgui-terms.ttl\nPASS a moved default makes modgui-gen --check fail\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>With the panel, \u003Ccode>modgui.ttl\u003C\u002Fcode> lists the seven controls of the first section, \u003Ccode>Detector\u003C\u002Fcode>, as \u003Ccode>modgui:port\u003C\u002Fcode>, and\nthe makeup fader brings its own film strip.\u003C\u002Fp>\n\u003Ch3 id=\"the-released-0-2-5-on-zamcomp\">The released 0.2.5 on ZamComp\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>$ rpm -q omx-panel\nomx-panel-0.2.5-1.fc44.noarch\n\n$ \u002Fusr\u002Fbin\u002Fomx-panel modgui --descriptor examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.descriptor.json --out \u002Ftmp\u002Fzamcomp-0.2.5.lv2 2&gt;&amp;1 | grep '^Error'\nError: modgui-gen: 'gr' is not a declared control input with a travel\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>That is omx-panel#25: 0.2.5 looks a travel up for a readout. This checkout carries the fix.\u003C\u002Fp>\n\u003Ch3 id=\"lsp-limiter-mono-a-clap-plugin\">LSP Limiter Mono, a CLAP plugin\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>$ omx-panel layout --descriptor examples\u002Fworked-example\u002Flsp-limiter-mono\u002Flimiter_mono.descriptor.json &gt; examples\u002Fworked-example\u002Flsp-limiter-mono\u002Flimiter_mono.layout.json\n\n$ omx-panel layout --descriptor examples\u002Fworked-example\u002Flsp-limiter-mono\u002Flimiter_mono.descriptor.json --pages &gt; examples\u002Fworked-example\u002Flsp-limiter-mono\u002Flimiter_mono.pages.json\n\n$ omx-panel modgui --descriptor examples\u002Fworked-example\u002Flsp-limiter-mono\u002Flimiter_mono.descriptor.json --out \u002Ftmp\u002Flimiter_mono.lv2 2&gt;&amp;1 | grep '^Error'\nError: modgui-gen: 'in.lsp-plug.limiter_mono' states no LV2 URI; a MOD GUI belongs to an LV2 bundle\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The limiter's 28 controls state no group, so they are one section \u003Ccode>Controls\u003C\u002Fcode>, four pages of eight, the last\nholding four (\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fexamples\u002Fworked-example\u002Flsp-limiter-mono\u002Flimiter_mono.pages.json\">\u003Ccode>limiter_mono.pages.json\u003C\u002Fcode>\u003C\u002Fa>,\neach slot a CLAP parameter id). These are the pages a CLAP host shows through \u003Ccode>clap.remote-controls\u003C\u002Fcode>. A MOD GUI\nbelongs to an LV2 bundle, so the generator refuses a CLAP descriptor by name; lsp-plugins also ships an LV2\nbuild, which would be scanned as \u003Ccode>lv2:&lt;uri&gt;\u003C\u002Fcode> and go the way of ZamComp.\u003C\u002Fp>\n\u003Cp>Not every lsp CLAP plugin lays out yet. Filter Mono has two parameters named &quot;Filter mode&quot;, and a CLAP\ncontrol, whose id is a number, is keyed by its name:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ plugin-hostd-probe describe clap:\u002Fusr\u002Flib64\u002Fclap\u002Flsp-plugins.clap#in.lsp-plug.filter_mono &gt; examples\u002Fworked-example\u002Flsp-limiter-mono\u002Ffilter_mono.descriptor.json\n\n$ omx-panel layout --descriptor examples\u002Fworked-example\u002Flsp-limiter-mono\u002Ffilter_mono.descriptor.json --pages\nomx-panel: examples\u002Fworked-example\u002Flsp-limiter-mono\u002Ffilter_mono.descriptor.json: 'Filter mode' is a control twice\n[exit 1]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>That is omx-panel#27. \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fexamples\u002Fworked-example\u002Fsurvey-lsp-mono.sh\">\u003Ccode>survey-lsp-mono.sh\u003C\u002Fcode>\u003C\u002Fa> scans and lays out\nevery mono plugin of the file:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ bash examples\u002Fworked-example\u002Fsurvey-lsp-mono.sh\nrefused in.lsp-plug.filter_mono: omx-panel: &lt;descriptor&gt;: 'Filter mode' is a control twice\nrefused in.lsp-plug.sampler_mono: omx-panel: &lt;descriptor&gt;: 'Sample pitch' is a control twice\nrefused in.lsp-plug.trigger_midi_mono: omx-panel: &lt;descriptor&gt;: 'Sample pitch' is a control twice\nrefused in.lsp-plug.trigger_mono: omx-panel: &lt;descriptor&gt;: 'Sample pitch' is a control twice\n59 laid out, 4 refused\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>With \u003Ccode>--all\u003C\u002Fcode> it also lists the 59 plugins that lay out, one \u003Ccode>ok\u003C\u002Fcode> line each\n(\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fexamples\u002Fworked-example\u002Ftranscript\u002F27a-survey-lsp-mono-all.txt\">\u003Ccode>transcript\u002F27a-survey-lsp-mono-all.txt\u003C\u002Fcode>\u003C\u002Fa>).\nThe four refusals have the cause of Filter Mono's, a name two parameters share.\u003C\u002Fp>\n\u003Ch2 id=\"4-zynthian\">4. Zynthian\u003C\u002Fh2>\n\u003Cp>What follows comes from Zynthian's sources (zynthian-ui \u003Ccode>f46b018\u003C\u002Fcode> and zynthian-sys \u003Ccode>0774a58\u003C\u002Fcode>, both on their\n\u003Ccode>vangelis\u003C\u002Fcode> branch; zynthian-plugins \u003Ccode>648c84a\u003C\u002Fcode>, its \u003Ccode>master\u003C\u002Fcode>), the omx-plugins README, and the lilv\nruns shown. Each file and line cited is at those commits. None of it was seen on a Zynthian.\u003C\u002Fp>\n\u003Ch3 id=\"where-zynthian-looks-for-lv2-bundles-and-their-mod-guis\">Where Zynthian looks for LV2 bundles and their MOD GUIs\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>\u003Ccode>LV2_PATH\u003C\u002Fcode> is \u003Ccode>\u002Fusr\u002Flib\u002Flv2:\u002Fusr\u002Flib\u002Farm-linux-gnueabihf\u002Flv2:\u002Fusr\u002Flocal\u002Flib\u002Flv2:$ZYNTHIAN_PLUGINS_DIR\u002Flv2:\u003C\u002Fcode>\n\u003Ccode>$ZYNTHIAN_DATA_DIR\u002Fpresets\u002Flv2:$ZYNTHIAN_MY_DATA_DIR\u002Fpresets\u002Flv2\u003C\u002Fcode> (zynthian-sys\n\u003Ccode>scripts\u002Fzynthian_envars.sh:107\u003C\u002Fcode>), with \u003Ccode>ZYNTHIAN_PLUGINS_DIR\u003C\u002Fcode> \u003Ccode>\u002Fzynthian\u002Fzynthian-plugins\u003C\u002Fcode> (\u003Ccode>:105\u003C\u002Fcode>).\nzynthian-ui loads it with lilv's \u003Ccode>world.load_all()\u003C\u002Fcode> (\u003Ccode>zyngine\u002Fzynthian_lv2.py:213\u003C\u002Fcode>).\u003C\u002Fli>\n\u003Cli>A bundle a user adds goes to \u003Ccode>\u002Fzynthian\u002Fzynthian-plugins\u002Flv2\u003C\u002Fcode> (\u003Ccode>LV2_DIR\u003C\u002Fcode>, \u003Ccode>zynthian_lv2.py:197\u003C\u002Fcode>): the\nwebconf upload copies it there through \u003Ccode>add_engine\u003C\u002Fcode> (\u003Ccode>zynthian_lv2.py:386\u003C\u002Fcode>), and the omx-plugins README has a\nZynthian without the apt channel copy its \u003Ccode>lv2\u002F\u003C\u002Fcode> bundles there and rescan the LV2 plugins from the admin\nmenu. A plugin the rescan finds for the first time is disabled until enabled (\u003Ccode>zynthian_lv2.py:619\u003C\u002Fcode>).\u003C\u002Fli>\n\u003Cli>The last commit of the zynthian-plugins repository (directories \u003Ccode>dssi\u003C\u002Fcode>, \u003Ccode>ladspa\u003C\u002Fcode>, \u003Ccode>lv2\u003C\u002Fcode>, \u003Ccode>vst\u003C\u002Fcode>) is\n\u003Ccode>648c84a\u003C\u002Fcode>, dated 2016-09-21. The image's setup script installs LV2 plugins with \u003Ccode>apt-get\u003C\u002Fcode>, and the list\nnames \u003Ccode>zam-plugins\u003C\u002Fcode> (zynthian-sys \u003Ccode>scripts\u002Fsetup_plugins_rbpi.sh:42-52\u003C\u002Fcode>, the name on line 52); the recipe\nthat builds zam-plugins from source, \u003Ccode>scripts\u002Frecipes\u002Finstall_zam.sh\u003C\u002Fcode>, is commented out at\n\u003Ccode>setup_plugins_rbpi.sh:94\u003C\u002Fcode>. That the Debian package carries the same ZamComp as Fedora's, and puts it in\n\u003Ccode>\u002Fusr\u002Flib\u002Flv2\u003C\u002Fcode>, is not read from these sources.\u003C\u002Fli>\n\u003Cli>A MOD GUI is drawn by MOD-UI, which Zynthian runs as an engine of its own (zynthian-ui\n\u003Ccode>zyngine\u002Fzynthian_engine_modui.py\u003C\u002Fcode>; zynthian's mod-ui fork, \u003Ccode>scripts\u002Frecipes\u002Finstall_mod-ui.sh\u003C\u002Fcode>, run by\n\u003Ccode>setup_system_raspioslite_64bit_trixie.sh:562\u003C\u002Fcode>). Its service takes an \u003Ccode>LV2_PATH\u003C\u002Fcode>\n(\u003Ccode>etc\u002Fsystemd\u002Fmod-ui.service:11\u003C\u002Fcode>) that \u003Ccode>scripts\u002Fupdate_zynthian_sys.sh:527\u003C\u002Fcode> fills from the value set at \u003Ccode>:188\u003C\u002Fcode>:\nthe same directories as above plus \u003Ccode>\u002Fusr\u002Flib\u002F$arch_libdir\u002Flv2\u003C\u002Fcode> and \u003Ccode>$ZYNTHIAN_PLUGINS_DIR\u002Flv2-presets\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"how-the-bundle-gets-there\">How the bundle gets there\u003C\u002Fh3>\n\u003Cp>A MOD GUI is read only when the bundle's manifest names \u003Ccode>modgui.ttl\u003C\u002Fcode>, and only from the bundle lilv takes the\nplugin from. Both are shown on a copy of the installed bundle:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ rm -rf \u002Ftmp\u002Fstage &amp;&amp; mkdir -p \u002Ftmp\u002Fstage\n\n$ cp -R \u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2 \u002Ftmp\u002Fstage\u002F\n\n$ cp -R examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\u002Fmodgui.ttl examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\u002Fmodgui \u002Ftmp\u002Fstage\u002FZamComp.lv2\u002F\n\n$ LV2_PATH=\u002Ftmp\u002Fstage python3 examples\u002Fworked-example\u002Flilv-modgui.py urn:zamaudio:ZamComp\nplugin  urn:zamaudio:ZamComp\nbundle  file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002F\nmodgui:gui  none\n[exit 1]\n\n$ printf '\\n&lt;urn:zamaudio:ZamComp&gt; rdfs:seeAlso &lt;modgui.ttl&gt; .\\n' &gt;&gt; \u002Ftmp\u002Fstage\u002FZamComp.lv2\u002Fmanifest.ttl\n\n$ LV2_PATH=\u002Ftmp\u002Fstage python3 examples\u002Fworked-example\u002Flilv-modgui.py urn:zamaudio:ZamComp\nplugin  urn:zamaudio:ZamComp\nbundle  file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002F\nmodgui:resourcesDirectory  file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002Fmodgui\nmodgui:iconTemplate  file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002Fmodgui\u002Ficon-ZamComp.html\nmodgui:stylesheet  file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002Fmodgui\u002Fstylesheet-ZamComp.css\nmodgui:screenshot  file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002Fmodgui\u002Fscreenshot-ZamComp.png\nmodgui:thumbnail  file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002Fmodgui\u002Fthumbnail-ZamComp.png\nmodgui:brand  Damien Zammit\nmodgui:label  ZamComp\nmodgui:port  0 thr\nmodgui:port  1 rat\nmodgui:port  2 kn\nmodgui:port  3 att\nmodgui:port  4 rel\nmodgui:port  5 slew\nmodgui:port  6 sidech\n\n$ LV2_PATH=\u002Fusr\u002Flib64\u002Flv2:\u002Ftmp\u002Fstage python3 examples\u002Fworked-example\u002Flilv-modgui.py urn:zamaudio:ZamComp\nlilv_world_compare_versions(): warning: Ignoring duplicate version 6.0 of &lt;urn:zamaudio:ZamComp&gt; from &lt;file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002F&gt;\nlilv_world_compare_versions(): note: Previously loaded from &lt;file:\u002F\u002F\u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002F&gt;\nplugin  urn:zamaudio:ZamComp\nbundle  file:\u002F\u002F\u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002F\nmodgui:gui  none\n[exit 1]\n\n$ LV2_PATH=\u002Ftmp\u002Fstage:\u002Fusr\u002Flib64\u002Flv2 python3 examples\u002Fworked-example\u002Flilv-modgui.py urn:zamaudio:ZamComp | head -3\nlilv_world_compare_versions(): warning: Ignoring duplicate version 6.0 of &lt;urn:zamaudio:ZamComp&gt; from &lt;file:\u002F\u002F\u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002F&gt;\nlilv_world_compare_versions(): note: Previously loaded from &lt;file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002F&gt;\nplugin  urn:zamaudio:ZamComp\nbundle  file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002F\nmodgui:resourcesDirectory  file:\u002F\u002F\u002Ftmp\u002Fstage\u002FZamComp.lv2\u002Fmodgui\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fexamples\u002Fworked-example\u002Flilv-modgui.py\">\u003Ccode>lilv-modgui.py\u003C\u002Fcode>\u003C\u002Fa> asks lilv, the library mod-ui reads LV2 data\nwith, for the plugin's \u003Ccode>modgui:gui\u003C\u002Fcode>. The manifest line is added by hand: \u003Ccode>omx-panel modgui\u003C\u002Fcode> leaves the manifest\nas it is (omx-panel#28). Of two bundles with one plugin URI and one version, lilv keeps the first on\n\u003Ccode>LV2_PATH\u003C\u002Fcode> and ignores the other.\u003C\u002Fp>\n\u003Cp>The test over the whole staged bundle:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ tools\u002Fmodgui-test.sh \u002Ftmp\u002Fstage\u002FZamComp.lv2 examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.descriptor.json examples\u002Fworked-example\u002Fzamcomp\u002Fzamcomp.panel.json\nPASS modgui-gen --check ZamComp\nPASS template draws thr with its declared travel and default\nPASS template draws rat with its declared travel and default\nPASS template draws kn with its declared travel and default\nPASS template draws att with its declared travel and default\nPASS template draws rel with its declared travel and default\nPASS template draws slew with its declared travel and default\nPASS template draws sidech with its declared travel and default\nPASS template draws mak with its declared travel and default\nPASS template draws readout gr as a display with its declared range\nPASS template draws readout outlevel as a display with its declared range\nPASS template draws exactly the 10 declared parameters\nerror: Object not in range &lt;http:\u002F\u002Flv2plug.in\u002Fns\u002Flv2core#ExtensionData&gt;\n\nerror: Use of undefined property\n       urn:zamaudio:ZamComp\nerror: Property &lt;http:\u002F\u002Fmoddevices.com\u002Fns\u002Fmod#brand&gt; has no label\n       urn:zamaudio:ZamComp\nerror: Use of undefined property\n       urn:zamaudio:ZamComp\nerror: Property &lt;http:\u002F\u002Fmoddevices.com\u002Fns\u002Fmod#label&gt; has no label\n       urn:zamaudio:ZamComp\nerror: Object not in range &lt;http:\u002F\u002Flv2plug.in\u002Fns\u002Flv2core#ExtensionData&gt;\nFAIL sord_validate ZamComp.lv2\u002F*.ttl (Found 27 errors among 89 files (checked 2194 restrictions))\nPASS sord_validate refuses a modgui property outside modgui-terms.ttl\nPASS a moved default makes modgui-gen --check fail\nmodgui-test: 1 check(s) failed\n[exit 1]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The six errors besides the 21 of omx-contract#144 are ZamComp's own TTL's, and the installed bundle, untouched,\nhas the same six against the same LV2 specifications:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ for s in core port-props units urid atom worker ui options midi patch time log state buf-size parameters presets resize-port port-groups morph dynmanifest instance-access data-access event uri-map schemas; do set -- &quot;$@&quot; \u002Fusr\u002Flib64\u002Flv2\u002F$s.lv2\u002F*.ttl; done; sord_validate \u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002F*.ttl &quot;$@&quot; 2&gt;&amp;1 | grep -A1 '^error'\nerror: Object not in range &lt;http:\u002F\u002Flv2plug.in\u002Fns\u002Flv2core#ExtensionData&gt;\n\n--\nerror: Use of undefined property\n       urn:zamaudio:ZamComp\n--\nerror: Property &lt;http:\u002F\u002Fmoddevices.com\u002Fns\u002Fmod#brand&gt; has no label\n       urn:zamaudio:ZamComp\n--\nerror: Use of undefined property\n       urn:zamaudio:ZamComp\n--\nerror: Property &lt;http:\u002F\u002Fmoddevices.com\u002Fns\u002Fmod#label&gt; has no label\n       urn:zamaudio:ZamComp\n--\nerror: Object not in range &lt;http:\u002F\u002Flv2plug.in\u002Fns\u002Flv2core#ExtensionData&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>On a Zynthian where the Debian package has put ZamComp in \u003Ccode>\u002Fusr\u002Flib\u002Flv2\u002FZamComp.lv2\u003C\u002Fcode> (not read from the\nsources, see above), that bundle is first on \u003Ccode>LV2_PATH\u003C\u002Fcode>, and a copy of the bundle in\n\u003Ccode>\u002Fzynthian\u002Fzynthian-plugins\u002Flv2\u003C\u002Fcode> would be ignored by lilv as above. \u003Ccode>add_engine\u003C\u002Fcode> refuses a plugin whose engine\nis already registered unless \u003Ccode>force\u003C\u002Fcode> is set (\u003Ccode>zynthian_lv2.py:411-424\u003C\u002Fcode>). The MOD GUI then goes into the bundle\nlilv takes: copy \u003Ccode>modgui.ttl\u003C\u002Fcode> and \u003Ccode>modgui\u002F\u003C\u002Fcode> from\n\u003Ccode>examples\u002Fworked-example\u002Fzamcomp\u002Fwith-panel\u002FZamComp.lv2\u002F\u003C\u002Fcode> into \u003Ccode>\u002Fusr\u002Flib\u002Flv2\u002FZamComp.lv2\u002F\u003C\u002Fcode>, append the same\n\u003Ccode>rdfs:seeAlso\u003C\u002Fcode> line to its \u003Ccode>manifest.ttl\u003C\u002Fcode>, and restart MOD-UI. That step was not run, and a \u003Ccode>zam-plugins\u003C\u002Fcode>\nupgrade would overwrite the manifest. The descriptor should be the scan of the Zynthian's own ZamComp, whose\nDebian version may differ from Fedora's 4.4.\u003C\u002Fp>\n\u003Ch3 id=\"what-the-encoder-pages-show\">What the encoder pages show\u003C\u002Fh3>\n\u003Cp>The pages of eight above are the layout's: what a CLAP host shows through \u003Ccode>clap.remote-controls\u003C\u002Fcode>. Zynthian's\ntouchscreen does not read them. For an LV2 plugin hosted by jalv it builds its own screens of four\n(zynthian-ui \u003Ccode>zyngine\u002Fzynthian_engine.py\u003C\u002Fcode>, \u003Ccode>generate_ctrl_screens\u003C\u002Fcode>, lines 681 to 724):\u003C\u002Fp>\n\u003Cul>\n\u003Cli>the controls are the plugin's input control ports, in port order (\u003Ccode>zynthian_lv2.py:940\u003C\u002Fcode>, \u003Ccode>get_plugin_ports\u003C\u002Fcode>),\nsorted by \u003Ccode>lv2:displayPriority\u003C\u002Fcode>, and grouped by \u003Ccode>pg:group\u003C\u002Fcode>; ungrouped controls are the group \u003Ccode>Params\u003C\u002Fcode>;\u003C\u002Fli>\n\u003Cli>each group is cut into screens of four, numbered from 1 when a group has more than four;\u003C\u002Fli>\n\u003Cli>an audio effect with no bypass port of its own gets a \u003Ccode>bypass\u003C\u002Fcode> control, added last\n(\u003Ccode>zyngine\u002Fzynthian_engine_jalv.py:544\u003C\u002Fcode>);\u003C\u002Fli>\n\u003Cli>output control ports are no controllers: a readout is never on a screen.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>ZamComp states no port group and no display priority:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>$ grep -c -E 'portgroups|pg:group|displayPriority' \u002Fusr\u002Flib64\u002Flv2\u002FZamComp.lv2\u002FZamComp_dsp.ttl\n0\n[exit 1]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>So, by those rules, Zynthian shows ZamComp as \u003Ccode>Params 1\u003C\u002Fcode> (Attack, Release, Knee, Ratio), \u003Ccode>Params 2\u003C\u002Fcode>\n(Threshold, Makeup, Slew, Sidechain) and \u003Ccode>Params 3\u003C\u002Fcode> (bypass), and neither \u003Ccode>gr\u003C\u002Fcode> nor \u003Ccode>outlevel\u003C\u002Fcode>. This is read\nfrom the source, not seen. The layout's sections do not reach Zynthian's screens: an LV2 bundle would carry\nthem as \u003Ccode>pg:group\u003C\u002Fcode> in its TTL, which the MOD GUI generator does not write. The word \u003Ccode>clap\u003C\u002Fcode> appears in no file\nof zynthian-ui at \u003Ccode>f46b018\u003C\u002Fcode> (\u003Ccode>grep -ri clap\u003C\u002Fcode> finds nothing), and in zynthian-sys at \u003Ccode>0774a58\u003C\u002Fcode> only once, in\na name misspelt &quot;Claption&quot; in a plugin description (\u003Ccode>config\u002Fengine_config.json:7932\u003C\u002Fcode>), so those sources name no\nCLAP host or plugin and the limiter's pages are not shown there.\u003C\u002Fp>\n\u003Ch2 id=\"what-is-verified-and-what-is-not\">What is verified, and what is not\u003C\u002Fh2>\n\u003Cp>Verified, by the commands above: both plugins come from Fedora 44's own packages; \u003Ccode>plugin-hostd-probe describe\u003C\u002Fcode> writes a \u003Ccode>scanned\u003C\u002Fcode> descriptor of each; \u003Ccode>omx-panel layout\u003C\u002Fcode> lays out ZamComp with and without a panel\nfile and the limiter, and stops on Filter Mono and three more of the 63 mono lsp plugins (omx-panel#27); \u003Ccode>omx-panel modgui\u003C\u002Fcode> writes ZamComp's MOD GUI with\nand without a panel file, each bundle passing \u003Ccode>tools\u002Fmodgui-test.sh\u003C\u002Fcode>, and refuses the CLAP limiter by name;\nomx-panel 0.2.5 stops on ZamComp's readout (omx-panel#25); lilv reads the MOD GUI from a copy of the bundle\nonce its manifest names \u003Ccode>modgui.ttl\u003C\u002Fcode>, and keeps the first of two bundles of one plugin on \u003Ccode>LV2_PATH\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Not verified:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>anything on a Zynthian or a MOD: the bundle's install there, MOD-UI drawing the template, the screens of\nfour, the rescan;\u003C\u002Fli>\n\u003Cli>the template as mod-ui draws it in a browser: the tests read the template's text and its TTL, not a render;\u003C\u002Fli>\n\u003Cli>the readouts' displays showing a value: the generated MOD GUI draws a frame, and a live reading needs a\n\u003Ccode>modgui:javascript\u003C\u002Fcode>, which is not generated (\u003Ccode>docs\u002Fmodgui.md\u003C\u002Fcode>);\u003C\u002Fli>\n\u003Cli>ZamComp's Debian build (Zynthian's) having the same ports as Fedora's;\u003C\u002Fli>\n\u003Cli>the limiter's pages on a CLAP host with a controller.\u003C\u002Fli>\n\u003C\u002Ful>\n",[30,33,36,39,42,45,48],{"slug":31,"title":32},"","omx-panel",{"slug":34,"title":35},"compare","Compare A\u002FB\u002FC\u002FD and undo",{"slug":37,"title":38},"group-inference","Port-group inference for LV2 plugins",{"slug":40,"title":41},"lv2-complement","The LV2 complement: a replacing bundle with the inferred port groups",{"slug":43,"title":44},"modgui","The MOD GUI generator",{"slug":46,"title":47},"panel-layout","Panel layout from a descriptor",{"slug":49,"title":50},"skin-package","The skin package",1793954996091]