[{"data":1,"prerenderedAt":41},["ShallowReactive",2],{"project-plugin-hostd-formats":3},{"page":4,"others":25},{"slug":5,"src":6,"title":6,"source":7,"toc":8,"html":24},"formats","docs\u002Fformats.md","https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fplugin-hostd\u002Fblob\u002Fb4ea6a9\u002Fdocs\u002Fformats.md",[9,12,15,18,21],{"id":10,"title":11},"the-tables","The tables",{"id":13,"title":14},"the-transforms","The transforms",{"id":16,"title":17},"the-coverage-test","The coverage test",{"id":19,"title":20},"the-field-dump","The field dump",{"id":22,"title":23},"the-descriptor-describe-writes","The descriptor `describe` writes","\u003Ch1 id=\"the-format-tables-how-a-scan-becomes-a-descriptor\">The format tables: how a scan becomes a descriptor\u003C\u002Fh1>\n\u003Cp>plugin-hostd turns what a CLAP or LV2 plugin states about itself into a \u003Ccode>scanned\u003C\u002Fcode> descriptor (omx-contract\n\u003Ccode>docs\u002Fdescriptors.md\u003C\u002Fcode>). Three layers do it, and each is one thing:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Layer\u003C\u002Fth>\n\u003Cth>What\u003C\u002Fth>\n\u003Cth>Where\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>L1 description\u003C\u002Ftd>\n\u003Ctd>one mapping table per format, data: every field a scan reads, mapped to a descriptor word, carried in the extension bag, or dropped by a named decision\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>data\u002Fformats\u002Fclap.json\u003C\u002Fcode> (\u003Ccode>PLUGIN_HOSTD_CLAP_MAP\u003C\u002Fcode>), \u003Ccode>data\u002Fformats\u002Flv2.json\u003C\u002Fcode> (\u003Ccode>PLUGIN_HOSTD_LV2_MAP\u003C\u002Fcode>), item kind \u003Ccode>formatMap\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>L2 transforms\u003C\u002Ftd>\n\u003Ctd>a closed list of named functions, each with its inverse, which a table names and never defines\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>src\u002Ftransforms.h\u003C\u002Fcode> (\u003Ccode>TRANSFORMS(X)\u003C\u002Fcode>), \u003Ccode>src\u002Ftransforms.c\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>L3 runtime\u003C\u002Ftd>\n\u003Ctd>the field dump of one plugin, read as a host reads it\u003C\u002Ftd>\n\u003Ctd>omx-clap-core's \u003Ccode>omx-clap-scan --fields\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>\u003Ccode>plugin-hostd-probe describe\u003C\u002Fcode> joins them: it runs the dump in an isolated child, applies the table and its transforms,\nand writes the descriptor. The same tables, read backwards, are what omx-plugins' generators write a CLAP face and an\nLV2 \u003Ccode>.ttl\u003C\u002Fcode> from: one vocabulary, two directions, and the round trip (author, generate both faces, scan back, compare)\nis the proof.\u003C\u002Fp>\n\u003Ch2 id=\"the-tables\">The tables\u003C\u002Fh2>\n\u003Cp>\u003Ccode>make install-contract\u003C\u002Fcode> installs both tables, with omx-contract-devel's \u003Ccode>install-contract-dir.sh\u003C\u002Fcode>, as the package\n\u003Ccode>plugin-hostd\u003C\u002Fcode> of the contract directory: \u003Ccode>&lt;contractdir&gt;\u002F3\u002Fplugin-hostd\u002Fformats\u002F{clap,lv2}.json\u003C\u002Fcode>, with its\n\u003Ccode>MANIFEST.json\u003C\u002Fcode>, beside the daemon's verbs (\u003Ccode>verbs.json\u003C\u002Fcode>). The noarch package plugin-hostd-contract\n(\u003Ccode>plugin-hostd-contract\u003C\u002Fcode> on Debian too) ships them, and a program that reads them at run time requires it.\nIt requires omx-contract 3.2.0 or later (\u003Ccode>Requires\u003C\u002Fcode>, Debian \u003Ccode>Depends\u003C\u002Fcode>): the tables live in omx-contract's contract\ndirectory and are read against its schema, and 3.2.0 is the first whose source field takes an index\n(\u003Ccode>omx_clap_panel_display.meter_ids[0]\u003C\u002Fcode>), so an older omx-contract never sits beside a table it refuses.\u003C\u002Fp>\n\u003Cp>\u003Ccode>make check-contract-dir\u003C\u002Fcode> installs the package into a staging directory and runs \u003Ccode>omx-contract validate\u003C\u002Fcode> over it\ntogether with the installed contract directory (omx-contract's own tables, omx-clap-core's): red on any table the\ninstalled schema refuses, and red, never a skip, when the \u003Ccode>omx-contract\u003C\u002Fcode> command is absent. The coverage test below\nwalks the schema for the words only, never for the row keys; this gate reads every key as a reader of the installed\ndirectory does.\u003C\u002Fp>\n\u003Cp>A table's \u003Ccode>rows\u003C\u002Fcode> are keyed by the source field, and each row has exactly one class:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Class\u003C\u002Fth>\n\u003Cth>Carries\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>word\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>{ word, transform, values? | factor? }\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the descriptor word it becomes (\u003Ccode>controls[].travel.unit\u003C\u002Fcode>), the transform that converts it (a name of \u003Ccode>TRANSFORMS(X)\u003C\u002Fcode>) and that transform's data: \u003Ccode>values\u003C\u002Fcode> for \u003Ccode>lookup\u003C\u002Fcode>, \u003Ccode>factor\u003C\u002Fcode> for \u003Ccode>scale-by\u003C\u002Fcode>. Never code\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>extension\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>true\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>carried verbatim into the descriptor's \u003Ccode>extensions.&lt;format&gt;.&lt;field&gt;\u003C\u002Fcode> (a record of a control's or a port's scope under \u003Ccode>&lt;scope&gt;\u002F&lt;field&gt;\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>dropped\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>{ ruling }\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>left out, by the decision it names: a spec path and section, or the TERM's own \u003Ccode>out-of-scope\u003C\u002Fcode> mark\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Each row names what it covers, one of two: \u003Ccode>term\u003C\u002Fcode>, a TERM of omx-contract's format files (\u003Ccode>LV2_UNITS_TERMS#unit\u003C\u002Fcode>), or\n\u003Ccode>from\u003C\u002Fcode>, the header or specification link of a field no TERM file lists (the CLAP struct fields and \u003Ccode>clap_entry\u003C\u002Fcode>,\n\u003Ccode>rdf:type\u003C\u002Fcode>, \u003Ccode>rdfs:comment\u003C\u002Fcode>, \u003Ccode>rdfs:seeAlso\u003C\u002Fcode>, \u003Ccode>doap:name\u003C\u002Fcode>, \u003Ccode>doap:license\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Ch3 id=\"field-names\">Field names\u003C\u002Fh3>\n\u003Cp>The key of a row is the field as the dump names it:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>a CLAP TERM: its \u003Ccode>id\u003C\u002Fcode> (\u003Ccode>CLAP_PARAM_IS_STEPPED\u003C\u002Fcode>, \u003Ccode>CLAP_EXT_LATENCY\u003C\u002Fcode>, \u003Ccode>CLAP_PLUGIN_FEATURE_DELAY\u003C\u002Fcode>);\u003C\u002Fli>\n\u003Cli>a CLAP struct field: \u003Ccode>&lt;struct&gt;.&lt;member&gt;\u003C\u002Fcode> as the headers spell them (\u003Ccode>clap_param_info.min_value\u003C\u002Fcode>), or\n\u003Ccode>&lt;struct&gt;.&lt;function&gt;\u003C\u002Fcode> for what a call returns (\u003Ccode>clap_plugin.get_extension\u003C\u002Fcode>, \u003Ccode>clap_plugin_params.value_to_text\u003C\u002Fcode>);\u003C\u002Fli>\n\u003Cli>an LV2 TERM: \u003Ccode>&lt;prefix&gt;:&lt;term&gt;\u003C\u002Fcode>, the term's own name under the prefix of its specification (\u003Ccode>units:db\u003C\u002Fcode>,\n\u003Ccode>lv2:toggled\u003C\u002Fcode>, \u003Ccode>pg:group\u003C\u002Fcode>, \u003Ccode>units:units.lv2\u003C\u002Fcode> for the specification itself);\u003C\u002Fli>\n\u003Cli>any other LV2 predicate: its usual CURIE (\u003Ccode>rdf:type\u003C\u002Fcode>, \u003Ccode>rdfs:comment\u003C\u002Fcode>, \u003Ccode>doap:name\u003C\u002Fcode>).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The LV2 prefixes: \u003Ccode>lv2\u003C\u002Fcode> lv2core, \u003Ccode>atom\u003C\u002Fcode>, \u003Ccode>bufsz\u003C\u002Fcode> buf-size, \u003Ccode>da\u003C\u002Fcode> data-access, \u003Ccode>dman\u003C\u002Fcode> dynmanifest, \u003Ccode>ev\u003C\u002Fcode> event,\n\u003Ccode>ia\u003C\u002Fcode> instance-access, \u003Ccode>log\u003C\u002Fcode>, \u003Ccode>midi\u003C\u002Fcode>, \u003Ccode>morph\u003C\u002Fcode>, \u003Ccode>opts\u003C\u002Fcode> options, \u003Ccode>param\u003C\u002Fcode> parameters, \u003Ccode>patch\u003C\u002Fcode>, \u003Ccode>pg\u003C\u002Fcode> port-groups,\n\u003Ccode>pprops\u003C\u002Fcode> port-props, \u003Ccode>pset\u003C\u002Fcode> presets, \u003Ccode>rsz\u003C\u002Fcode> resize-port, \u003Ccode>state\u003C\u002Fcode>, \u003Ccode>time\u003C\u002Fcode>, \u003Ccode>ui\u003C\u002Fcode>, \u003Ccode>units\u003C\u002Fcode>, \u003Ccode>urimap\u003C\u002Fcode> uri-map, \u003Ccode>urid\u003C\u002Fcode>,\n\u003Ccode>work\u003C\u002Fcode> worker; and \u003Ccode>rdf\u003C\u002Fcode>, \u003Ccode>rdfs\u003C\u002Fcode>, \u003Ccode>doap\u003C\u002Fcode>, \u003Ccode>foaf\u003C\u002Fcode> for the W3C and DOAP vocabularies.\u003C\u002Fp>\n\u003Ch3 id=\"field-rows-and-value-rows\">Field rows and value rows\u003C\u002Fh3>\n\u003Cp>Some TERMs are fields (\u003Ccode>lv2:minimum\u003C\u002Fcode>, \u003Ccode>units:unit\u003C\u002Fcode>); others are values a field takes (\u003Ccode>units:db\u003C\u002Fcode> is a value of\n\u003Ccode>units:unit\u003C\u002Fcode>, \u003Ccode>lv2:toggled\u003C\u002Fcode> of \u003Ccode>lv2:portProperty\u003C\u002Fcode>, \u003Ccode>CLAP_PARAM_IS_STEPPED\u003C\u002Fcode> of \u003Ccode>clap_param_info.flags\u003C\u002Fcode>). Every TERM has\nits row either way. A record of the dump is resolved in this order:\u003C\u002Fp>\n\u003Col>\n\u003Cli>when its value is the key of a row (a value row): a \u003Ccode>word\u003C\u002Fcode> row converts it, a \u003Ccode>dropped\u003C\u002Fcode> row drops it, an \u003Ccode>extension\u003C\u002Fcode>\nrow says the value has no word of its own and defers to the field's row;\u003C\u002Fli>\n\u003Cli>otherwise the field's row: a \u003Ccode>word\u003C\u002Fcode> row converts the value (a \u003Ccode>lookup\u003C\u002Fcode> that has no entry for it carries the value\nin the bag instead), an \u003Ccode>extension\u003C\u002Fcode> row carries it in the bag, a \u003Ccode>dropped\u003C\u002Fcode> row drops it;\u003C\u002Fli>\n\u003Cli>a field with no row at all is refused: \u003Ccode>describe\u003C\u002Fcode> names it and writes no descriptor.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>A value row's \u003Ccode>lookup\u003C\u002Fcode> holds its own pair (\u003Ccode>units:db\u003C\u002Fcode> -&gt; \u003Ccode>dB\u003C\u002Fcode>): the unit rows are the same correspondence as\nomx-plugins' \u003Ccode>LV2_UNITS\u003C\u002Fcode> (\u003Ccode>tools\u002Fgen.mjs\u003C\u002Fcode>), and where the TERM file names the unit's word the row maps to that word,\nwhich the coverage test holds.\u003C\u002Fp>\n\u003Ch3 id=\"what-a-table-drops\">What a table drops\u003C\u002Fh3>\n\u003Cp>A row is \u003Ccode>dropped\u003C\u002Fcode> only by a decision it names. The TERMs omx-contract marks \u003Ccode>out-of-scope\u003C\u002Fcode> are dropped by that mark,\nwhich the row quotes. A field this section rules out is dropped by \u003Ccode>docs\u002Fformats.md#what-a-table-drops\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>a runtime handle that is no fact of the plugin (\u003Ccode>clap_param_info.cookie\u003C\u002Fcode>, a pointer the host passes back);\u003C\u002Fli>\n\u003Cli>every field of the panel description (\u003Ccode>omx_clap_plugin_panel_description.*\u003C\u002Fcode> and the \u003Ccode>omx_clap_panel_*\u003C\u002Fcode> structures of\nomx-clap-core's \u003Ccode>omx_clap_ext.h\u003C\u002Fcode>): the panel travels whole, as the scan's \u003Ccode>panel\u003C\u002Fcode> object, by \u003Ccode>panel_get\u003C\u002Fcode>\n(\u003Ca href=\"\u002Fprojects\u002Fplugin-hostd\u002Fpanel\">panel.md\u003C\u002Fa>), and the descriptor carries none of it. A panel field's row is a drop and nothing else;\n\u003Ccode>describe\u003C\u002Fcode> refuses a table that makes one a word or the bag.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>A TERM omx-contract marks \u003Ccode>used\u003C\u002Fcode> is never dropped: its row is a word or the bag.\u003C\u002Fp>\n\u003Ch3 id=\"outbound-read-rows\">Outbound-read rows\u003C\u002Fh3>\n\u003Cp>A generator reads a value row of a table to write a face: the TERM is a value (not a \u003Ccode>property\u003C\u002Fcode>) and omx-contract\nlists omx-plugins among its users (\u003Ccode>by\u003C\u002Fcode>). Such a row's transform is \u003Ccode>identity\u003C\u002Fcode> or \u003Ccode>lookup\u003C\u002Fcode>, the two a generator applies\nby reading the table alone; what is structure (scale points, groups, module paths) stays in the generator's code.\u003C\u002Fp>\n\u003Ch2 id=\"the-transforms\">The transforms\u003C\u002Fh2>\n\u003Cp>\u003Ccode>src\u002Ftransforms.h\u003C\u002Fcode> declares the closed list as one X-macro, \u003Ccode>TRANSFORMS(X)\u003C\u002Fcode>: the name a table writes, the inbound\nfunction (format to descriptor) and its inverse (descriptor to format), all prefixed \u003Ccode>transforms_\u003C\u002Fcode>. A value crosses as\ntext: a JSON literal on the descriptor side (\u003Ccode>-60\u003C\u002Fcode>, \u003Ccode>&quot;dB&quot;\u003C\u002Fcode>, \u003Ccode>true\u003C\u002Fcode>, \u003Ccode>[&quot;Filter&quot;,&quot;Envelope&quot;]\u003C\u002Fcode>), the dump's text on the\nformat side.\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Name\u003C\u002Fth>\n\u003Cth>Inbound\u003C\u002Fth>\n\u003Cth>Inverse\u003C\u002Fth>\n\u003Cth>Data\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>identity\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the value as it is, a number as a number\u003C\u002Ftd>\n\u003Ctd>the same\u003C\u002Ftd>\n\u003Ctd>none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>lookup\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the value's entry in \u003Ccode>values\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the key whose entry it is\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>values\u003C\u002Fcode>, one to one: a table whose values repeat is refused\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>scale-by\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the number times \u003Ccode>factor\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the number divided by \u003Ccode>factor\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>factor\u003C\u002Fcode>, not zero\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>flag\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>present -&gt; \u003Ccode>true\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>true\u003C\u002Fcode> -&gt; the row's key, \u003Ccode>false\u003C\u002Fcode> -&gt; nothing\u003C\u002Ftd>\n\u003Ctd>none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>scale-points\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>&lt;number&gt; &lt;label&gt;\u003C\u002Fcode> -&gt; one point of the control's \u003Ccode>values\u003C\u002Fcode> and \u003Ccode>labels\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the point back as \u003Ccode>&lt;number&gt; &lt;label&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>group-path\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a CLAP module path \u003Ccode>a\u002Fb\u003C\u002Fcode> -&gt; the group \u003Ccode>[&quot;a&quot;,&quot;b&quot;]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the group joined by \u003Ccode>\u002F\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>port-group\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>an LV2 group's label -&gt; the group \u003Ccode>[&quot;label&quot;]\u003C\u002Fcode>; a \u003Ccode>pg:subGroupOf\u003C\u002Fcode> label -&gt; a level put before the group read so far\u003C\u002Ftd>\n\u003Ctd>the path's last level, the group a port names\u003C\u002Ftd>\n\u003Ctd>none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>A new transform is added when a row needs it, never before; \u003Ccode>make test-transforms\u003C\u002Fcode> runs every function and its inverse\nover its vectors (in, out, back in, equal).\u003C\u002Fp>\n\u003Ch2 id=\"the-coverage-test\">The coverage test\u003C\u002Fh2>\n\u003Cp>\u003Ccode>make test-format-coverage\u003C\u002Fcode> runs \u003Ccode>tests\u002Fformat_coverage.py\u003C\u002Fcode> once per format. The field list is every term of the\ninstalled TERM files (\u003Ccode>&lt;contractdir&gt;\u002F3\u002Fomx-contract\u002Fformats\u002F&lt;format&gt;\u002F**\u003C\u002Fcode>) plus every row with a \u003Ccode>from\u003C\u002Fcode>; each field has\nexactly one row. It prints, per field, \u003Ccode>mapped &lt;word&gt; &lt;transform&gt;\u003C\u002Fcode>, \u003Ccode>extension &lt;format&gt;\u003C\u002Fcode> or \u003Ccode>dropped &lt;decision&gt;\u003C\u002Fcode>, then the\ncount per class. It is red for:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>a field with no row, and a row that covers no field (its \u003Ccode>term\u003C\u002Fcode> is no installed term);\u003C\u002Fli>\n\u003Cli>a \u003Ccode>word\u003C\u002Fcode> the descriptor schema lacks (walked in the installed \u003Ccode>omx-contract.schema.json\u003C\u002Fcode>), or a \u003Ccode>lookup\u003C\u002Fcode> entry that\nis no value the word takes;\u003C\u002Fli>\n\u003Cli>a \u003Ccode>transform\u003C\u002Fcode> that is not in \u003Ccode>TRANSFORMS(X)\u003C\u002Fcode>, or a \u003Ccode>lookup\u003C\u002Fcode> that is not one to one;\u003C\u002Fli>\n\u003Cli>a \u003Ccode>used\u003C\u002Fcode> TERM that is \u003Ccode>dropped\u003C\u002Fcode>, and a \u003Ccode>dropped\u003C\u002Fcode> row that names no decision;\u003C\u002Fli>\n\u003Cli>an outbound-read row whose transform is neither \u003Ccode>identity\u003C\u002Fcode> nor \u003Ccode>lookup\u003C\u002Fcode>;\u003C\u002Fli>\n\u003Cli>a unit row that does not map to the word its TERM names.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Ccode>tests\u002Fformat_coverage.py --self-test\u003C\u002Fcode> breaks a copy of each table three ways (one row removed, one \u003Ccode>word\u003C\u002Fcode> misspelt,\none transform renamed) and each arm must go red naming the field.\u003C\u002Fp>\n\u003Ch2 id=\"the-field-dump\">The field dump\u003C\u002Fh2>\n\u003Cp>\u003Ccode>omx-clap-scan --fields clap:&lt;path&gt;#&lt;id&gt; | lv2:&lt;uri&gt;\u003C\u002Fcode> writes one record per line, TAB-separated:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>&lt;scope&gt;\t&lt;field&gt;\t&lt;value&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cul>\n\u003Cli>\u003Ccode>scope\u003C\u002Fcode>: \u003Ccode>plugin\u003C\u002Fcode>; \u003Ccode>param:&lt;index&gt;\u003C\u002Fcode> (CLAP, in \u003Ccode>clap_plugin_params.get_info\u003C\u002Fcode> order); \u003Ccode>audio_in:&lt;index&gt;\u003C\u002Fcode>,\n\u003Ccode>audio_out:&lt;index&gt;\u003C\u002Fcode>, \u003Ccode>note_in:&lt;index&gt;\u003C\u002Fcode>, \u003Ccode>note_out:&lt;index&gt;\u003C\u002Fcode> (CLAP ports); \u003Ccode>port:&lt;index&gt;\u003C\u002Fcode> (an LV2 port, by\n\u003Ccode>lv2:index\u003C\u002Fcode>). A scope is a source field's first segment, so a bag key \u003Ccode>&lt;scope&gt;\u002F&lt;field&gt;\u003C\u002Fcode> is one too. A CLAP plugin\nthat serves a panel description adds \u003Ccode>panel\u003C\u002Fcode>, \u003Ccode>section:&lt;index&gt;\u003C\u002Fcode>, \u003Ccode>control:&lt;index&gt;\u003C\u002Fcode>, \u003Ccode>role:&lt;index&gt;\u003C\u002Fcode>,\n\u003Ccode>display:&lt;index&gt;\u003C\u002Fcode> and \u003Ccode>placement_default:&lt;index&gt;\u003C\u002Fcode> (omx-clap-scan 0.20.0); these scopes are no entry of the\ndescriptor, and each of their fields is dropped (above).\u003C\u002Fli>\n\u003Cli>\u003Ccode>field\u003C\u002Fcode>: a row key, as named above.\u003C\u002Fli>\n\u003Cli>\u003Ccode>value\u003C\u002Fcode>: the field's value as text. A number in \u003Ccode>%.17g\u003C\u002Fcode>; a CLAP constant (a flag bit, a port type, a note dialect,\nan extension id, a feature the headers define) by its macro name, one record per flag set or per item; an LV2 URI as\na CURIE under the prefixes above, a URI no prefix covers in full; a scale point or a CLAP value text as\n\u003Ccode>&lt;number&gt; &lt;label&gt;\u003C\u002Fcode>. A TAB or a newline in a text becomes a space.\u003C\u002Fli>\n\u003Cli>the provenance: a CLAP dump writes \u003Ccode>plugin\tclap_entry\t&lt;file name of the .clap&gt;\u003C\u002Fcode>, an LV2 dump\n\u003Ccode>plugin\trdfs:seeAlso\t&lt;bundle directory&gt;\u002F&lt;data file&gt;\u003C\u002Fcode>, the \u003Ccode>.ttl\u003C\u002Fcode> that describes the plugin.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The first line is \u003Ccode># omx-clap-scan --fields 1\u003C\u002Fcode>, the format's version; a dump with another version is refused.\u003C\u002Fp>\n\u003Ch2 id=\"the-descriptor-describe-writes\">The descriptor \u003Ccode>describe\u003C\u002Fcode> writes\u003C\u002Fh2>\n\u003Cp>\u003Ccode>plugin-hostd-probe describe [--table &lt;file&gt;] [--fields-from &lt;dump.tsv&gt;] clap:&lt;path&gt;#&lt;id&gt; | lv2:&lt;uri&gt;\u003C\u002Fcode> writes the\n\u003Ccode>scanned\u003C\u002Fcode> descriptor on stdout, exit 0; 2 when nothing is written (usage, a table it cannot read, a refused dump), 3 when\nthe dump cannot be made. Without \u003Ccode>--fields-from\u003C\u002Fcode> it runs \u003Ccode>omx-clap-scan --fields\u003C\u002Fcode> under the probe runner's limits, in a\nchild of its own (\u003Ccode>run\u003C\u002Fcode>'s isolation); with it, it reads a recorded dump, which is what its own tests do.\u003C\u002Fp>\n\u003Cp>What the tables leave to \u003Ccode>describe\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>each scope is one entry: a CLAP \u003Ccode>param:\u003C\u002Fcode> scope a control, a CLAP port scope a port, an LV2 \u003Ccode>port:\u003C\u002Fcode> scope a control\nwhen a row makes it one (\u003Ccode>lv2:ControlPort\u003C\u002Fcode>) and a port when a row gives it a port kind; \u003Ccode>id\u003C\u002Fcode> and \u003Ccode>name\u003C\u002Fcode> follow the\nentry;\u003C\u002Fli>\n\u003Cli>an LV2 control's kind is \u003Ccode>travel\u003C\u002Fcode> (its \u003Ccode>lv2:ControlPort\u003C\u002Fcode> row) unless another record of the port gives a more\nspecific one (\u003Ccode>toggle\u003C\u002Fcode>, \u003Ccode>choice\u003C\u002Fcode>, \u003Ccode>trigger\u003C\u002Fcode>), whatever order the dump lists the port's records in;\u003C\u002Fli>\n\u003Cli>an LV2 travel that states both \u003Ccode>lv2:integer\u003C\u002Fcode> (stepped) and \u003Ccode>pprops:logarithmic\u003C\u002Fcode> (log) is \u003Ccode>log\u003C\u002Fcode>, whatever order the\ndump lists them in;\u003C\u002Fli>\n\u003Cli>an LV2 output control is \u003Ccode>readonly\u003C\u002Fcode>; an LV2 port that reports latency (\u003Ccode>lv2:latency\u003C\u002Fcode>) is no control;\u003C\u002Fli>\n\u003Cli>consecutive LV2 audio ports of one direction, role and group are one port, its \u003Ccode>channels\u003C\u002Fcode> their count, its layout\n\u003Ccode>mono\u003C\u002Fcode> or \u003Ccode>stereo\u003C\u002Fcode> by that count;\u003C\u002Fli>\n\u003Cli>a CLAP port that is not main is \u003Ccode>aux\u003C\u002Fcode>; a control's \u003Ccode>unit\u003C\u002Fcode> is \u003Ccode>unknown\u003C\u002Fcode> when no row sets it, its \u003Ccode>scale\u003C\u002Fcode> \u003Ccode>unknown\u003C\u002Fcode>\non CLAP and \u003Ccode>linear\u003C\u002Fcode> on LV2 (where a scale not stated is linear); its \u003Ccode>meaning\u003C\u002Fcode> is \u003Ccode>unknown\u003C\u002Fcode> when no row sets it; a\ncontrol with points is a \u003Ccode>choice\u003C\u002Fcode>, its \u003Ccode>ids\u003C\u002Fcode> taken from its labels and its default the id of the default's point, a\n\u003Ccode>toggle\u003C\u002Fcode> defaults to its default being non-zero;\u003C\u002Fli>\n\u003Cli>an LV2 port's group path is its \u003Ccode>pg:group\u003C\u002Fcode> label with one \u003Ccode>pg:subGroupOf\u003C\u002Fcode> record per group above it, nearest first\n(the scanner follows the chain, \u003Ccode>lv2:name\u003C\u002Fcode> else \u003Ccode>rdfs:label\u003C\u002Fcode> of each group); the path is read outermost first, and a\n\u003Ccode>pg:subGroupOf\u003C\u002Fcode> with no \u003Ccode>pg:group\u003C\u002Fcode> before it is refused;\u003C\u002Fli>\n\u003Cli>the bag holds a field's one value as it is, two or more as a list;\u003C\u002Fli>\n\u003Cli>a plugin no feature of which maps is an \u003Ccode>audio-effect\u003C\u002Fcode>; an LV2 plugin's \u003Ccode>id\u003C\u002Fcode> and \u003Ccode>uri\u003C\u002Fcode> are the URI asked for;\u003C\u002Fli>\n\u003Cli>the links a scanned descriptor needs (\u003Ccode>source.from\u003C\u002Fcode>): a CLAP descriptor's own, \u003Ccode>&lt;file&gt;#clap_entry\u003C\u002Fcode>; each LV2\ncontrol's, \u003Ccode>&lt;data file&gt;#&lt;symbol&gt;\u003C\u002Fcode>, from the row of \u003Ccode>clap_entry\u003C\u002Fcode> and of \u003Ccode>rdfs:seeAlso\u003C\u002Fcode>; a character a link cannot hold\nbecomes \u003Ccode>_\u003C\u002Fcode>; \u003Ccode>instrument\u003C\u002Fcode> is written when the features hold it, \u003Ccode>polyphonic\u003C\u002Fcode> when it states more than one voice; \u003Ccode>latency\u003C\u002Fcode>\nis always written, \u003Ccode>reports\u003C\u002Fcode> false when no row sets it.\u003C\u002Fli>\n\u003Cli>a word of a table that \u003Ccode>describe\u003C\u002Fcode> does not write is refused with the table: a new word is code here first.\u003C\u002Fli>\n\u003C\u002Ful>\n",[26,29,32,35,38],{"slug":27,"title":28},"","README.md",{"slug":30,"title":31},"own-host","the highest SCHED_FIFO priority, which the probe asks for, and a lock as large as the probe's memory limit",{"slug":33,"title":34},"panel","docs\u002Fpanel.md",{"slug":36,"title":37},"placement","docs\u002Fplacement.md",{"slug":39,"title":40},"presets","Presets in the host",1793954996687]