[{"data":1,"prerenderedAt":60},["ShallowReactive",2],{"project-omx-panel-panel-layout":3},{"page":4,"others":38},{"slug":5,"src":6,"title":7,"source":8,"toc":9,"html":37},"panel-layout","docs\u002Fpanel-layout.md","Panel layout from a descriptor","https:\u002F\u002Fgithub.com\u002FFreeMixer\u002Fomx-panel\u002Fblob\u002Fedaf4f48de7e57496ead1b949f754b7e111867e3\u002Fdocs\u002Fpanel-layout.md",[10,13,16,19,22,25,28,31,34],{"id":11,"title":12},"the-two-inputs","The two inputs",{"id":14,"title":15},"units","Units",{"id":17,"title":18},"meanings-and-roles","Meanings and roles",{"id":20,"title":21},"the-family","The family",{"id":23,"title":24},"the-widget","The widget",{"id":26,"title":27},"sections-with-no-declared-panel","Sections with no declared panel",{"id":29,"title":30},"pages","Pages",{"id":32,"title":33},"the-easy-face","The Easy face",{"id":35,"title":36},"verbatim","Verbatim","\u003Ch1 id=\"panel-layout-from-a-descriptor\">Panel layout from a descriptor\u003C\u002Fh1>\n\u003Cp>\u003Ccode>tools\u002Fpanel-description.mjs\u003C\u002Fcode> lays out a plugin's panel from its \u003Cstrong>descriptor\u003C\u002Fstrong>: the words omx-contract\nuses to describe one plugin, ours or anyone's (omx-contract \u003Ccode>docs\u002Fdescriptors.md\u003C\u002Fcode>). A plugin from any\norigin (\u003Ccode>authored\u003C\u002Fcode>, \u003Ccode>built\u003C\u002Fcode>, \u003Ccode>scanned\u003C\u002Fcode>) gets a layout; a plugin that declares its panel (omx-plugins'\ndo, in \u003Ccode>&lt;stem&gt;.decl.json\u003C\u002Fcode>) adds it on top, and what its faces serve as \u003Ccode>org.openmixer.panel-description\u002F1\u003C\u002Fcode>\nis this layout.\u003C\u002Fp>\n\u003Ch2 id=\"the-two-inputs\">The two inputs\u003C\u002Fh2>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Input\u003C\u002Fth>\n\u003Cth>Who has it\u003C\u002Fth>\n\u003Cth>What it gives\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>The descriptor\u003C\u002Ftd>\n\u003Ctd>every plugin\u003C\u002Ftd>\n\u003Ctd>each control's \u003Ccode>kind\u003C\u002Fcode>, \u003Ccode>travel\u003C\u002Fcode> (range, \u003Ccode>unit\u003C\u002Fcode>, \u003Ccode>scale\u003C\u002Fcode>, default), choice ids and labels, \u003Ccode>label\u003C\u002Fcode>, \u003Ccode>group\u003C\u002Fcode>, \u003Ccode>meaning\u003C\u002Fcode>, \u003Ccode>hidden\u003C\u002Fcode>, \u003Ccode>readonly\u003C\u002Fcode>; the \u003Ccode>ports\u003C\u002Fcode>; the \u003Ccode>origin\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>The declared panel\u003C\u002Ftd>\n\u003Ctd>a plugin that declares one (omx-plugins: \u003Ccode>&lt;stem&gt;.decl.json\u003C\u002Fcode>, \u003Ccode>panel\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd>the family, the section keys and labels, the order of the controls in each section, the roles, the widgets the panel names, the graphs, the per-placement come-up values\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>This package reads descriptors, never a declaration. omx-plugins renders its declarations as their\n\u003Ccode>authored\u003C\u002Fcode> descriptors (its \u003Ccode>tools\u002Fdescriptor.mjs\u003C\u002Fcode>): one control per parameter, its id the parameter's\nindex, its name the symbol, its label the parameter's name; a toggle is a \u003Ccode>toggle\u003C\u002Fcode>, an integer travel\nwith labelled values a \u003Ccode>choice\u003C\u002Fcode>, every other parameter a \u003Ccode>travel\u003C\u002Fcode> with the declared unit and scale; its\n\u003Ccode>group\u003C\u002Fcode> the label of the panel section that lists it; its \u003Ccode>meaning\u003C\u002Fcode> the one the declared role names\n(below). The declared panel then goes to the layout unchanged.\u003C\u002Fp>\n\u003Ch2 id=\"units\">Units\u003C\u002Fh2>\n\u003Cp>A control's unit is the descriptor's \u003Ccode>travel.unit\u003C\u002Fcode>. A role checks it against the units the\nparam-contract extension serves (\u003Ccode>tools\u002Fvocabulary.mjs\u003C\u002Fcode>, \u003Ccode>servedToken\u003C\u002Fcode>): a unit's token is the LV2 unit a\nface writes for it, plugin-hostd's installed LV2 table read backwards, or the name of a unit in the\nextension's vendor block (\u003Ccode>dBu\u003C\u002Fcode>, \u003Ccode>ratio\u003C\u002Fcode>); it is served when the extension's unit table,\n\u003Ccode>OMX_PARAM_CONTRACT_UNITS\u003C\u002Fcode> (omx-contract's sheet, \u003Ccode>3\u002Fomx-contract\u002Fparam-contract.json\u003C\u002Fcode> in the contract directory, omx-contract-data from 3.6.0), gives the token a value. So a unit that table or that block knows (\u003Ccode>LUFS\u003C\u002Fcode>, \u003Ccode>dBu\u003C\u002Fcode>\namong them) is checked like any other. A unit with no token there, \u003Ccode>unknown\u003C\u002Fcode> included, takes no role and\nis drawn as a plain number. Nothing here types a unit: the reader reads the installed table\n(\u003Ccode>$PLUGIN_HOSTD_TABLES\u003C\u002Fcode> stands in for it) and the installed unit sheet (\u003Ccode>param-contract.json\u003C\u002Fcode> in omx-contract's directory), and refuses by name when either is missing.\u003C\u002Fp>\n\u003Cp>The level roles (\u003Ccode>threshold\u003C\u002Fcode>, \u003Ccode>ceiling\u003C\u002Fcode>) take \u003Ccode>dB\u003C\u002Fcode>, \u003Ccode>dBFS\u003C\u002Fcode>, \u003Ccode>dBu\u003C\u002Fcode> and \u003Ccode>LUFS\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"meanings-and-roles\">Meanings and roles\u003C\u002Fh2>\n\u003Cp>A skin binds by meaning, never by symbol. A family's roles map to the descriptor's meanings\n(\u003Ccode>tools\u002Fvocabulary.mjs\u003C\u002Fcode>, \u003Ccode>meaningOfRole\u003C\u002Fcode>, over omx-contract's closed list of meanings as its installed\nschema declares it); a role whose name is a meaning maps to it, and these are renamed:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Role\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>mix\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>wetDryRatio\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>time\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>delay\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>cutoff\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>cutoffFrequency\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>band_freq\u003C\u002Fcode>, \u003Ccode>band_gain\u003C\u002Fcode>, \u003Ccode>band_q\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>frequency\u003C\u002Fcode>, \u003Ccode>gain\u003C\u002Fcode>, \u003Ccode>q\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>hpf_freq\u003C\u002Fcode>, \u003Ccode>low_cut\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>lowCut\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>lpf_freq\u003C\u002Fcode>, \u003Ccode>high_cut\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>highCut\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>hpf_slope\u003C\u002Fcode>, \u003Ccode>lpf_slope\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>slope\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>key_listen\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>listen\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>A role with no meaning word (\u003Ccode>band_type\u003C\u002Fcode>, \u003Ccode>model\u003C\u002Fcode>, \u003Ccode>algorithm\u003C\u002Fcode>, \u003Ccode>knee_start\u003C\u002Fcode>, ...) is bound only by\na declared panel.\u003C\u002Fp>\n\u003Cp>With no declared panel the roles come from the meanings: in the family the layout takes, each\nmeaning that names exactly one of the family's roles plays it; an indexed role (\u003Ccode>band_*\u003C\u002Fcode>) takes every\ncontrol of its meaning, in order; any other role is played by its first control, and a second is\nleft unpublished, named.\u003C\u002Fp>\n\u003Cp>A \u003Ccode>modulation\u003C\u002Fcode> depth is a plain amount (\u003Ccode>none\u003C\u002Fcode>, \u003Ccode>pc\u003C\u002Fcode>, \u003Ccode>coef\u003C\u002Fcode>) or a sweep in octaves (\u003Ccode>oct\u003C\u002Fcode>), as a phaser's is.\u003C\u002Fp>\n\u003Ch2 id=\"the-family\">The family\u003C\u002Fh2>\n\u003Cp>The family follows from the meanings, never from a guess about the plugin:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Family\u003C\u002Fth>\n\u003Cth>A declared family needs one of\u003C\u002Fth>\n\u003Cth>Inferred, with no declared panel, from all of\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>limiter\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>ceiling\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>ceiling\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>deesser\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>frequency\u003C\u002Fcode>, \u003Ccode>threshold\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>frequency\u003C\u002Fcode>, \u003Ccode>threshold\u003C\u002Fcode>, \u003Ccode>listen\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gate\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>threshold\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>threshold\u003C\u002Fcode>, \u003Ccode>range\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>dynamics\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>threshold\u003C\u002Fcode>, \u003Ccode>ratio\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>threshold\u003C\u002Fcode>, \u003Ccode>ratio\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>eq\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>gain\u003C\u002Fcode>, \u003Ccode>frequency\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>frequency\u003C\u002Fcode>, \u003Ccode>gain\u003C\u002Fcode>, \u003Ccode>q\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>filter\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>cutoffFrequency\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>cutoffFrequency\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>drive\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>drive\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>drive\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>delay\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>delay\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>delay\u003C\u002Fcode>, \u003Ccode>feedback\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>reverb\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>size\u003C\u002Fcode>, \u003Ccode>decay\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>size\u003C\u002Fcode>, or \u003Ccode>decay\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pitch\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>shift\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>shift\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>modulation\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>(any: a rotor's speeds and an LFO's shape have no meaning word yet)\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>rate\u003C\u002Fcode>, \u003Ccode>depth\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>A declaration whose family none of its meanings backs is refused, naming the family and the\nmeanings it would need: a transient designer (attack and sustain amounts, no threshold, no ratio) is\nnot a compressor, so its family is \u003Ccode>none\u003C\u002Fcode>. Inference tries the families in the order of the table and\ntakes the first whose meanings are all there; none fits, \u003Ccode>none\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"the-widget\">The widget\u003C\u002Fh2>\n\u003Cp>The widget is a step of its own, \u003Ccode>widgetOf(control, declared)\u003C\u002Fcode>, before any skin. It picks one of the\nstandard widgets, and a representation (a skin) draws it; the skins are not chosen here.\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Standard widget\u003C\u002Fth>\n\u003Cth>Taken by\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>knob\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a travel\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>fader\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a travel the declared panel draws as a fader\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>switch\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a toggle; a trigger (momentary)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>selector\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a choice\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>meter\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a read-only travel in a level unit (\u003Ccode>dB\u003C\u002Fcode>, \u003Ccode>dBFS\u003C\u002Fcode>, \u003Ccode>dBu\u003C\u002Fcode>, \u003Ccode>LUFS\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>display\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>any other read-only control\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>curve\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a section's graph a host computes (\u003Ccode>eq-curve\u003C\u002Fcode>, \u003Ccode>dynamics-curve\u003C\u002Fcode>, \u003Ccode>transfer-curve\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>xy\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>no descriptor word names a pair of controls yet; nothing takes it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>A meter carries its measurement (\u003Ccode>peak\u003C\u002Fcode>, \u003Ccode>rms\u003C\u002Fcode>, \u003Ccode>vu\u003C\u002Fcode>, \u003Ccode>ppm\u003C\u002Fcode>, \u003Ccode>lufs\u003C\u002Fcode>): \u003Ccode>lufs\u003C\u002Fcode> for a LUFS reading.\nThe descriptor has no word for the others, so any other meter's measurement is \u003Ccode>null\u003C\u002Fcode>, not a guess.\u003C\u002Fp>\n\u003Cp>What a face serves keeps the extension's widget enum: \u003Ccode>knob\u003C\u002Fcode>, \u003Ccode>fader\u003C\u002Fcode> and \u003Ccode>switch\u003C\u002Fcode> as they are, a\n\u003Ccode>selector\u003C\u002Fcode> as \u003Ccode>auto\u003C\u002Fcode> (a CLAP selector needs \u003Ccode>CLAP_PARAM_IS_ENUM\u003C\u002Fcode>, which the faces do not set).\u003C\u002Fp>\n\u003Ch2 id=\"sections-with-no-declared-panel\">Sections with no declared panel\u003C\u002Fh2>\n\u003Cp>Each distinct \u003Ccode>group\u003C\u002Fcode> path is a section, in the order its first control comes; its label is the path\njoined with \u003Ccode>\u002F\u003C\u002Fcode>, its key the path's segments in the key grammar, joined with dots. Controls with no\ngroup go to a section \u003Ccode>controls\u003C\u002Fcode>. A hidden control is left out. The layout also carries the ports: the\naudio inputs and outputs with their channels, whether one is a side-chain, and the note inputs.\u003C\u002Fp>\n\u003Ch2 id=\"pages\">Pages\u003C\u002Fh2>\n\u003Cp>\u003Ccode>omx-panel layout --pages\u003C\u002Fcode> cuts each section's controls, in the section's order, into pages of eight (the\nCLAP remote-controls surface); a section of several pages numbers them (\u003Ccode>Filter 1\u003C\u002Fcode>, \u003Ccode>Filter 2\u003C\u002Fcode>). A\nsurface with another number of encoders asks for it: \u003Ccode>--pages --per-page N\u003C\u002Fcode> (\u003Ccode>perPage\u003C\u002Fcode> in\n\u003Ccode>schema\u002Fpanel.schema.json\u003C\u002Fcode>, default 8). Then a group that fits a page is not split across two (the page\nends early), a group wider than N is cut, and a section of several pages names each page by the controls\nit holds (\u003Ccode>Band: Freq - Q\u003C\u002Fcode>). Every page carries N slots, a short page's last ones \u003Ccode>null\u003C\u002Fcode>. Left out, the\noutput is the plain cut of eight, unchanged.\u003C\u002Fp>\n\u003Ch2 id=\"the-easy-face\">The Easy face\u003C\u002Fh2>\n\u003Cp>\u003Ccode>tools\u002Feasy.mjs\u003C\u002Fcode> picks the handful of controls a plugin opens on; every control is one click away, on the same processor.\n\u003Ccode>easyOf\u003C\u002Fcode> returns their symbols, and the layout carries them as \u003Ccode>easy\u003C\u002Fcode>. The first that answers wins:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Declared\u003C\u002Fstrong>: the declared panel's \u003Ccode>easy\u003C\u002Fcode>, else the descriptor's. At most 8. A list that names no control of the panel, a\ncontrol no face can set, or one control twice is refused by name, never trimmed.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Roles\u003C\u002Fstrong>: the family's row below, each role that is mapped, at most 6. An indexed role with more members than places takes\nthem evenly spaced, both ends included, so a 31-band graphic shows its whole span.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Order\u003C\u002Fstrong>: when the roles gave fewer than 4, the first controls in layout order fill up to 4.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Family\u003C\u002Fth>\n\u003Cth>Roles, in order\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gate\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>threshold\u003C\u002Fcode>, \u003Ccode>range\u003C\u002Fcode>, \u003Ccode>attack\u003C\u002Fcode>, \u003Ccode>release\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>dynamics\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>threshold\u003C\u002Fcode>, \u003Ccode>ratio\u003C\u002Fcode>, \u003Ccode>makeup\u003C\u002Fcode>, \u003Ccode>mix\u003C\u002Fcode>, \u003Ccode>attack\u003C\u002Fcode>, \u003Ccode>release\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>limiter\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>ceiling\u003C\u002Fcode>, \u003Ccode>threshold\u003C\u002Fcode>, \u003Ccode>release\u003C\u002Fcode>, \u003Ccode>output\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>deesser\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>frequency\u003C\u002Fcode>, \u003Ccode>threshold\u003C\u002Fcode>, \u003Ccode>range\u003C\u002Fcode>, \u003Ccode>mix\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>eq\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>band_gain\u003C\u002Fcode>, \u003Ccode>output\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>filter\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>cutoff\u003C\u002Fcode>, \u003Ccode>resonance\u003C\u002Fcode>, \u003Ccode>filter_type\u003C\u002Fcode>, \u003Ccode>mix\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>drive\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>drive\u003C\u002Fcode>, \u003Ccode>tone\u003C\u002Fcode>, \u003Ccode>model\u003C\u002Fcode>, \u003Ccode>mix\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>modulation\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>rate\u003C\u002Fcode>, \u003Ccode>depth\u003C\u002Fcode>, \u003Ccode>feedback\u003C\u002Fcode>, \u003Ccode>mix\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>delay\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>time\u003C\u002Fcode>, \u003Ccode>feedback\u003C\u002Fcode>, \u003Ccode>tone\u003C\u002Fcode>, \u003Ccode>mix\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>reverb\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>size\u003C\u002Fcode>, \u003Ccode>decay\u003C\u002Fcode>, \u003Ccode>damping\u003C\u002Fcode>, \u003Ccode>mix\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pitch\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>shift\u003C\u002Fcode>, \u003Ccode>fine\u003C\u002Fcode>, \u003Ccode>mix\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>A face can set any control that is not a reading, a trigger or a bypass. The list is a view of the panel, so it stays out of\nthe canonical serialisation and the fingerprint.\u003C\u002Fp>\n\u003Cp>\u003Ccode>omx-panel layout --pages --easy-first\u003C\u002Fcode> puts the Easy controls first, on pages named \u003Ccode>Easy\u003C\u002Fcode>, \u003Ccode>Easy 2\u003C\u002Fcode>, with no control on two\npages; a scanned descriptor takes the \u003Ccode>easy\u003C\u002Fcode> of the descriptor the plugin's package installed under the same plugin id, as a scan\nhas nothing to read one from. Without the flag the pages are the page rule's. \u003Ccode>omx-panel modgui --easy-first\u003C\u002Fcode> draws the Easy\ncontrols as a MOD GUI's first section and lists them as \u003Ccode>modgui:port\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"verbatim\">Verbatim\u003C\u002Fh2>\n\u003Cp>For omx-plugins' plugins the descriptor carries what the declaration did, so every generated header,\nevery built face's description, every MOD GUI and its rasters stay byte-identical when omx-plugins lays\nthem out through this package; its own \u003Ccode>--check\u003C\u002Fcode> runs hold that.\u003C\u002Fp>\n\u003Cp>\u003Ccode>test\u002Fpanel-layout.test.mjs\u003C\u002Fcode> (\u003Ccode>make test\u003C\u002Fcode>) holds each rule above by value, with an arm per rule that\nbreaks its input and reads the result change; it lays out omx-contract's example descriptors\n(\u003Ccode>test\u002Ffixtures\u002Fdescriptors\u002F\u003C\u002Fcode>, scanned CLAP and LV2, a built instrument). The rule over omx-plugins' own\nplugins, which loads their declarations, stays in omx-plugins.\u003C\u002Fp>\n",[39,42,45,48,51,54,57],{"slug":40,"title":41},"","omx-panel",{"slug":43,"title":44},"compare","Compare A\u002FB\u002FC\u002FD and undo",{"slug":46,"title":47},"group-inference","Port-group inference for LV2 plugins",{"slug":49,"title":50},"lv2-complement","The LV2 complement: a replacing bundle with the inferred port groups",{"slug":52,"title":53},"modgui","The MOD GUI generator",{"slug":55,"title":56},"skin-package","The skin package",{"slug":58,"title":59},"worked-example","Worked example: a third-party LV2 and CLAP plugin to a generated panel, adapted to Zynthian",1793954996071]