Line 1,052: |
Line 1,052: |
| ====Listen (bool)==== | | ====Listen (bool)==== |
| When engaged (by default) it will perform detection and level matching. When disengaged it will keep the current gain, but will not further listen. If engaged again, the gain reduction will be reset. | | When engaged (by default) it will perform detection and level matching. When disengaged it will keep the current gain, but will not further listen. If engaged again, the gain reduction will be reset. |
| + | |
| + | |
| + | |
| + | =LV2 custom control groups (ttl)= |
| + | If not edited further, LV2 parameters will be presented in a manner being sorted by their parameter ID and grouped in groups of four without helpful group names. We can edit a specific file to get some more helpful named and ordered parameter groups. It is highly recommended to study other custom control ttl files before edit your own one. |
| + | |
| + | ==Location== |
| + | We start by searching for the original ttl file in the zynthian filesystem. Typically we'll find them in /usr/lib/lv2/[PLUGIN].lv2 or whereever this plugin lives. We copy the whole [PLUGIN].lv2 directory over to /zynthian/zynthian-data/lv2-custom (check the [https://github.com/zynthian/zynthian-data/tree/oram/lv2-custom other custom ttls] for reference). When we look inside, we'll find several *.so and *.ttl files. The file we are searching for is not the manifest.ttl but the other one. We can delete any other file from that directory. |
| + | |
| + | On any zynthian update database regeneration zynthian will replace the original ttl file with the ones in /zynthian/zynthian-data/lv2-custom. |
| + | |
| + | ==Editing the ttl file== |
| + | ===Namespace prefixes=== |
| + | |
| + | Most of the time we have to add some lines to the header, if not already present: |
| + | |
| + | @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . |
| + | @prefix pg: <http://lv2plug.in/ns/ext/port-groups#> . |
| + | @prefix plug: <COPY URN FROM PLUGIN BLOCK> . |
| + | |
| + | These [https://lv2plug.in/book/ namespace prefixes] act like unique identifiers for specific tasks. The URN to copy we'll find on top of the plugin block, which is the section that holds all the control ports. Just look into another custom ttl and compare the top of a plugin block with the URN set under the prefix "plug:". |
| + | |
| + | ===Control groups=== |
| + | |
| + | Add control groups like that outside the plugin block, for example right at the end of the file. Groups with higher displayPriority values will be displayed on top of your parameter group view. GROUP1 and the symbol "group1" can be named yourself (only letters, numbers or _", name "Group1 Display Name" you can also edited and will show on your UI. |
| + | |
| + | plug:GROUP1 |
| + | a pg:ControlGroup ; |
| + | lv2:name "Group1 Display Name" ; |
| + | lv2:symbol "group1" ; |
| + | lv2:displayPriority 3 . |
| + | |
| + | plug:GROUP2 |
| + | a pg:ControlGroup ; |
| + | lv2:name "Group2 Display Name" ; |
| + | lv2:symbol "group2" ; |
| + | lv2:displayPriority 2 . |
| + | |
| + | ... |
| + | |
| + | ===Parameter assignment=== |
| + | |
| + | Add following lines to every control port representing a parameter (contains "a lv2:ControlPort", so not the audio input and output ports), while display priority goes from higher to lower numbers as well: |
| + | |
| + | pg:group plug:GROUP1 ; |
| + | lv2:displayPriority 1 ; |
| + | |
| + | ===Scale Points=== |
| + | |
| + | This is especially helpful for integer or boolean like enumeration parameters and other parameters which should have stepped controls. Here we have an example for a boolean parameter, which should only be in state "On" or "Off": |
| + | |
| + | lv2:scalePoint [ |
| + | rdf:value 0.0 ; |
| + | rdfs:label "OFF" ; |
| + | rdfs:comment "OFF" ; |
| + | ], [ |
| + | rdf:value 1.0 ; |
| + | rdfs:label "ON" ; |
| + | rdfs:comment "ON" ; |
| + | ]; |
| + | |
| + | It has to be like that because typically (oftentimes, but not necessarily) parameters are represented as floating point values (0.000f to 1.000f), even if they're supposed to be boolean or integer, even if LV2 would support these kind of data. Other parameters could be of "integer logic". Let's assume the parameter "Waveform" would have the states "Saw, Sine, Square, Triange", we may assume that every floating point value from 0.0f to <0.25f represents "Saw" and so on. Then we might try this (while value and label are mandatory, comment is not): |
| + | |
| + | lv2:scalePoint [ |
| + | rdf:value 0.0 ; |
| + | rdfs:label "Saw" ; |
| + | rdfs:comment "Saw" ; |
| + | ], [ |
| + | rdf:value 0.25 ; |
| + | rdfs:label "Sine" ; |
| + | rdfs:comment "Sine" ; |
| + | ], [ |
| + | rdf:value 0.5 ; |
| + | rdfs:label "Square" ; |
| + | rdfs:comment "Square" ; |
| + | ], [ |
| + | rdf:value 0.75 ; |
| + | rdfs:label "Triangle" ; |
| + | rdfs:comment "Triangle" ; |
| + | ]; |
| + | |
| + | ===Disable parameter from being shown on UI=== |
| + | |
| + | Sometimes we have parameters which have no function and must not be displayed. You add the following line to the parameter definition: |
| + | |
| + | lv2:portProperty pp:notOnGUI ; |
| + | |
| + | ===Summary parameter definition=== |
| + | So a single parameter should for example look like this: |
| + | |
| + | [ |
| + | a lv2:InputPort, lv2:ControlPort ; |
| + | lv2:index 8 ; |
| + | lv2:symbol "delaytimesync" ; |
| + | lv2:name "Host Sync" ; |
| + | lv2:default 0.473684 ; |
| + | lv2:minimum 0.0 ; |
| + | lv2:maximum 1.0 ; |
| + | '''pg:group plug:DELAY ;''' |
| + | lv2:displayPriority 2 ; |
| + | lv2:scalePoint [ |
| + | rdf:value 0.0 ; |
| + | rdfs:label "Free" ; |
| + | rdfs:comment "Free" ; |
| + | ], [ |
| + | rdf:value 0.052631 ; |
| + | rdfs:label "1/16" ; |
| + | rdfs:comment "1/16" ; |
| + | ], [ |
| + | rdf:value 0.105263 ; |
| + | rdfs:label "1/8" ; |
| + | rdfs:comment "1/8" ; |
| + | ], [ |
| + | rdf:value 0.157895 ; |
| + | rdfs:label "1/4" ; |
| + | rdfs:comment "1/4" ; |
| + | ], [ |
| + | rdf:value 0.211053 ; |
| + | rdfs:label "1/2" ; |
| + | rdfs:comment "1/2" ; |
| + | ], [ |
| + | rdf:value 0.263158 ; |
| + | rdfs:label "1/1" ; |
| + | rdfs:comment "1/1" ; |
| + | ], [ |
| + | rdf:value 0.315789 ; |
| + | rdfs:label "2/1" ; |
| + | rdfs:comment "2/1" ; |
| + | ], [ |
| + | rdf:value 0.368421 ; |
| + | rdfs:label "1/16." ; |
| + | rdfs:comment "1/16." ; |
| + | ], [ |
| + | rdf:value 0.421052 ; |
| + | rdfs:label "1/8." ; |
| + | rdfs:comment "1/8." ; |
| + | ], [ |
| + | rdf:value 0.473684 ; |
| + | rdfs:label "1/4." ; |
| + | rdfs:comment "1/4." ; |
| + | ], [ |
| + | rdf:value 0.526316 ; |
| + | rdfs:label "1/2." ; |
| + | rdfs:comment "1/2." ; |
| + | ], [ |
| + | rdf:value 0.578947 ; |
| + | rdfs:label "1/1." ; |
| + | rdfs:comment "1/1." ; |
| + | ], [ |
| + | rdf:value 0.631579 ; |
| + | rdfs:label "2/1." ; |
| + | rdfs:comment "2/1." ; |
| + | ], [ |
| + | rdf:value 0.684211 ; |
| + | rdfs:label "1/16T" ; |
| + | rdfs:comment "1/16T" ; |
| + | ], [ |
| + | rdf:value 0.736842 ; |
| + | rdfs:label "1/8T" ; |
| + | rdfs:comment "1/8T" ; |
| + | ], [ |
| + | rdf:value 0.789474 ; |
| + | rdfs:label "1/4T" ; |
| + | rdfs:comment "1/4T" ; |
| + | ], [ |
| + | rdf:value 0.842105 ; |
| + | rdfs:label "1/2T" ; |
| + | rdfs:comment "1/2T" ; |
| + | ], [ |
| + | rdf:value 0.894736 ; |
| + | rdfs:label "1/1T" ; |
| + | rdfs:comment "1/1T" ; |
| + | ], [ |
| + | rdf:value 0.947368 ; |
| + | rdfs:label "2/1T" ; |
| + | rdfs:comment "2/1T" ; |
| + | ], [ |
| + | rdf:value 1.0 ; |
| + | rdfs:label "-" ; |
| + | rdfs:comment "-" ; |
| + | ]; |
| + | ] , |
| + | |
| + | The bold line is the one we started to insert things. You typically should only edit the "name" value, which is the display label and the newly added values. In this case we added the control to the previously added group named "DELAY", added the displayPriority, so that it will be displayed within the group above all parameters with value <2 and below paramters with value >2. Then we added stepped controls for delay times defined by subdivisions of the host tempo, where the values represent 1/19, 2/19, 3/19... |
| + | |
| + | ==Recommended workflow== |
| + | Instead of just copying the ttl over to the respective directory and edit it for your own use you can make things easier for the devs to implement your custom feature and share it with everybody this way: |
| + | |
| + | * Fork the zynthian/zynthian-data repositories vangelis branch |
| + | * Checkout to that branch in your zynthian |
| + | * Develop using your fork |
| + | * Make a pull request |