Difference between revisions of "Max gen~"

From MOD Wiki
Jump to navigation Jump to search
 
(47 intermediate revisions by 7 users not shown)
Line 1: Line 1:
This page describes how to get Max gen~ objects working as LV2 plugins, with the purpose of running them on the MOD.<br>
+
Apart from programming LV2-plugins in a "traditional" way, it's also possible to generate LV2-plugins for MOD devices from gen~ objects created in Cycling '74 Max.<br>
Note that the same procedure also allows for building cross-platform VST2 plugins (Linux, Mac and Windows), but without a custom graphical interface.<br>
+
This page will tell you the how and why of programming audio effects for the MOD Duo using this very different approach.
In this page we'll focus on LV2 and MOD.
 
  
'''NOTE: This is a work in progress! (specially this page!)'''
+
== Gen basics ==
<br>
 
Except some information to be missing.
 
  
== How it works ==
+
Gen~ objects are normally used in Max as a way to write low-level code that is run at signal-rate, using (if you want to) the same visual approach Max is known for.<br>
 +
Therefore the insides of a gen~ object can be seen as a pedal schematic, perfect for designing audio effects.<br>
 +
The SHIRO plugins are an example of plugins for MOD devices made using this very method.
  
This works by mixing pre-existing plugin wrapper code with the gen~'s code export feature.<br>
+
If you're not familiar with Gen, and this sounds all like gibberish to you, have a look at the links below.
By exporting the code we can compile them together to create an LV2 plugin binary, then generate the meta-data from it.
 
  
The idea was based on the official [https://github.com/Cycling74/gen-plugin-export gen-plugin-export] project made by Cycling '74.<br>
+
* [https://docs.cycling74.com/max7/vignettes/gen_overview Gen Overview]
We're not using that project for MOD because it uses Juce, which requires quite a few things that unnecessary (not to mention a graphical server).
+
* [https://www.youtube.com/watch?v=iuGi2MDaEOg& Tutorial: Create a Gen-based plugin for MOD devices]
  
Based on that project was made [https://github.com/DISTRHO/DPF-Max-Gen DPF-Max-Gen],
+
== Designing your effect in Gen ==
which uses the much simpler (and limited) [https://github.com/DISTRHO/DPF DPF] instead of Juce.<br>
 
That way we no longer require X11, freetype and quite a few other things that Juce needs in Linux. The final binary code is also a lot smaller.<br>
 
Since the plugin DSP code is all done in Max, the wrapper for exposing it as plugin does not really matter per se.<br>
 
So we use the most lightweight and simple approach possible - in this case being [https://github.com/DISTRHO/DPF DPF].
 
  
== DPF-Max-Gen ==
+
If you want to design a plugin for a MOD device, there are a few things you should know:
  
If you open the [https://github.com/DISTRHO/DPF-Max-Gen DPF-Max-Gen project page], you'll see a few things inside.<br>
+
* To get your gen~ object working on a MOD device, you'll need to design one using only Gen's internal objects, without referring to objects outside the gen~ object.<br>Only the objects inside will make it to the final LV2-plugin.
The most important part is the 'plugins' folder. Inside it there's more folders, each containing a separate plugin
+
* If you want controllable parameters, define the default, minimum and maximum arguments in the "param" object.
(with the exception of 'common', which provides the common/base code for gen~).
+
* While designing your gen~ object, remember that all MOD devices are running at 48 kHz sampling rate.
  
Taking the example of bitcrush, we have:
+
You'll find some example-plugins if you download the MOD Duo-package from the Package Manager in Max, and click on Launch.
* DistrhoPluginInfo.h
 
* DistrhoPluginMaxGen.cpp
 
* Makefile
 
* gen_exported.cpp
 
* gen_exported.h
 
* gen~.bitcrush.maxpat
 
  
'''DistrhoPluginInfo.h''' is a C header file, required by DPF, that describes some plugin meta-data.<br>
+
== Getting your Gen-based plugin to a MOD device ==
This includes name, author, description, LV2 URI and the amount of audio channels.<br>
 
Modify this file as needed. Remember that LV2 URIs are global and unique, and don't have to be real online URLs.
 
  
'''DistrhoPluginMaxGen.cpp''' is a symlink to the real DistrhoPluginMaxGen.cpp file located in the common folder.<br>
+
At this point you should have met the requirements specified above. If so, follow the steps below to get your plugin on a MOD device.<br>
This symlink is here so that we compile a different instance per plugin, but the actual code is the same.<br>
+
In order to run Gen-based plugins on a MOD device they must be converted into LV2 plugins and compiled using a custom MOD cloud build system.<br>
Do not modify this file.
+
All the heavy work has already been done by the MOD Team and Cycling '74.
  
'''Makefile''' contains the build rules for compiling the plugin.<br>
+
* Go to or install the MOD Duo-package in the Package Manager in Max if you haven't, and click on Launch.
The only thing that needs change here is the 'NAME' parameter, which specifies the target LV2 bundle and binary name for the plugin.
+
* Make sure your MOD device is connected, then start the MODwatcher from the popped-up screen.
 +
* If you want your plugin to have a name, copy your gen~ objects contents to a gen~ object with a patcher-name argument.<br> WARNING: naming your original gen~ object will initialize it's contents.
 +
* Finally send a message containing "exportnotifier MODwatcher, exportcode" (without the quotation marks) to the gen~ object.
  
'''gen_exported.cpp/h''' is the output from Max gen~ code export utility.<br>
+
Your plugin will now be transferred to the MOD device, within a few minutes the MODwatcher will tell you if the upload succeeded.<br>
You should get a few more files when export code, but only these 2 matter.
+
If all goes well, your Gen-based plugin should now be inside the MOD device, ready to be played!
  
'''gen~.bitcrush.maxpat''' is the Max patch that was used to generate this plugin, being here only for reference.
+
== Additional features (advanced) ==
  
== Compiling ==
+
Optionally you can edit your plugin to, for example, add units, knob behavior, a description or even a GUI.
  
=== Native ===
+
Your Gen-based plugin will only show knobs for each parameter.
 +
To get switches, selector, etc.. you’ll have to edit the .ttl file and add/change a few lines.
  
Before trying to build the plugins for MOD, it's a good idea to see if they work locally on your own PC first.<br>
+
If you get knobs named like your data Gen~ object in Max, you can just ignore those parameters.

After you git-clone the [https://github.com/DISTRHO/DPF-Max-Gen DPF-Max-Gen project] (recursively, it has submodules), you can just do:
+
These extra parameters are a side effect from how max gen works, if they really bother you, edit the main plugin .ttl file and set those as OutputPort instead of InputPort.
<code>
 
cd DPF-Max-Gen
 
make
 
</code>
 
  
If you're running Mac OS use 'make MACOS=true'.
+
On a Mac you can do this with the nano editor:
  
After it finishes you'll have LV2 and VST2 plugins inside the bin folder.<br>
+
Video tuto here : https://www.youtube.com/watch?v=CaLKImvc11w
See if they work on your favourite host. :)
 
  
=== MOD ===
+
* Open up Terminal
  
Compiling plugins for MOD can be done using [https://github.com/moddevices/mod-plugin-builder mod-plugin-builder].<br>
+
* Enter
See [[How_To_Build_and_Deploy_LV2_Plugin_to_MOD_Duo]] for more details.
+
<source lang="console">
 +
$ ssh root@192.168.51.1
 +
</source>
 +
* Password
 +
<source lang="console">
 +
$ mod
 +
</source>
 +
* Enter
 +
<source lang="console">
 +
$ .lv2/YOURPLUGIN_NAME.lv2/YOURPLUGIN_NAME_dsp.ttl
 +
</source>
  
== Making your own plugins ==
+
i.e. to get a switch for this parameter:
  
Right now we do not have the process of turning the gen~ exported code into a plugin directly. You'll have to do some manual work.<br>
+
a lv2:InputPort ,
 +
        lv2:ControlPort ;
 +
        lv2:index 5 ;
 +
        lv2:symbol “FILTER” ;
 +
        lv2:name “FILTER” ;
 +
        lv2:default 0 ;
 +
        lv2:minimum 0 ;
 +
        lv2:maximum 1 ;
  
A good starting point might be to just fork the DPF-Max-Gen project and use it to start your own.<br>
+
* Add this line :  lv2:portProperty lv2:integer, lv2:toggled  ;
The 'Makefile' file in the root folder contains the list of plugins to build, which reside in the plugins folder.
+
which gives:
  
If you've handled makefiles before it should be pretty straight forward.<br>
+
a lv2:InputPort ,
If not please contact us for ideas and discussion on how to possibly automate the creation of this type of plugin.
+
        lv2:ControlPort ;
 +
        lv2:index 5 ;
 +
        lv2:symbol “FILTER” ;
 +
        lv2:name “FILTER” ;
 +
        lv2:default 0 ;
 +
        lv2:minimum 0 ;
 +
        lv2:maximum 1 ;
 +
        lv2:portProperty lv2:integer, lv2:toggled  ;
 +
 
 +
i.e if you want the host/mod tempo to control a time parameter
 +
* Add this line to the prefix list (at the beginning of the file):
 +
@prefix  time: <http://lv2plug.in/ns/ext/time#> .
 +
 
 +
* and these lines to the time Control Port which will give:
 +
lv2:ControlPort ;
 +
        lv2:index 2 ;
 +
        lv2:symbol "BPM" ;
 +
        lv2:name "BPM" ;
 +
        lv2:default 120 ;
 +
        lv2:minimum 24 ;
 +
        lv2:maximum 280 ;
 +
        units:unit units:bpm ;
 +
        lv2:portProperty  mod:tempoRelatedDynamicScalePoints;
 +
 
 +
i.e if you want a selector
 +
* Add this line to the prefix list (at the beginning of the file):
 +
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
 +
 
 +
And change i.e. this:
 +
 
 +
a lv2:InputPort, lv2:ControlPort ;
 +
        lv2:index 6 ;
 +
        lv2:name "Div_L" ;
 +
        lv2:symbol "Div_L" ;
 +
        lv2:default 1.000000 ;
 +
        lv2:minimum 1.000000 ;
 +
        lv2:maximum 5.000000 ;
 +
 
 +
To this :
 +
 
 +
a lv2:InputPort, lv2:ControlPort ;
 +
        lv2:index 6 ;
 +
        lv2:name "Div" ;
 +
        lv2:symbol "Div" ;
 +
        lv2:default 1.0 ;
 +
        lv2:minimum 1.0 ;
 +
        lv2:maximum 5.0 ;
 +
        lv2:portProperty lv2:integer;
 +
        lv2:portProperty lv2:enumeration ;   
 +
        lv2:scalePoint [rdfs:label "1/4note"; rdf:value 1];
 +
        lv2:scalePoint [rdfs:label "Dotted1/8note"; rdf:value 2];
 +
        lv2:scalePoint [rdfs:label "1/4notetriplets"; rdf:value 3];
 +
        lv2:scalePoint [rdfs:label "1/8note"; rdf:value 4];
 +
        lv2:scalePoint [rdfs:label "1/8notetriplets"; rdf:value 5];
 +
 
 +
* When you’re done, exit nano:
 +
<source lang="console">
 +
Ctrl + x
 +
</source>
 +
* select Y(yes) or N (no) 
 +
 
 +
* Enter
 +
<source lang="console">
 +
systemctl restart mod-ui
 +
</source>
 +
 
 +
* Enter
 +
<source lang="console">
 +
exit
 +
</source>
 +
 
 +
* CAUTION: Delete your cache Browser to be shure to see the changes on your GUI
 +
 
 +
If all goes well, your modified Gen-based plugin should now be inside the MOD device, ready to be played!
 +
 
 +
== Alternatively ==
 +
 
 +
There is another process which is different from the process described above. It doesn't use the MOD Duo-package in Max.
 +
 
 +
 
 +
=== Compiling the plugin ===
 +
 
 +
First, download https://download.moddevices.com/releases/max-gen/max-gen-deploy_v6.tar.gz and extract it. <br>
 +
Send an "exportcode" message to the gen~ object in your main Max-patcher to get the YOURPLUGIN_NAME.cpp and YOURPLUGIN_NAME.h files.<br>
 +
replace YOURPLUGIN_NAME with “gen_exported" for both files
 +
Copy the gen_exported.cpp and gen_exported.h files into the extracted max-gen-deploy folder, and run:
 +
 
 +
<source lang="console">
 +
$ cd /path/to/max-gen-deploy/
 +
$ ./mod-build.sh
 +
</source>
 +
 
 +
You'll be asked for a plugin name, and after providing one the cloud should give you back a tar.gz file within a few minutes.
 +
 
 +
=== Editing the plugin ===
 +
 
 +
To add [http://lv2plug.in/ns/extensions/units/units.html units], [http://lv2plug.in/ns/ext/port-props/port-props.html knob behavior] or a description, you'll have to edit the .ttl file.
 +
If you do so, make sure everything is correct,<br> otherwise the plugin won't work and you might have to [[Access_MOD_using_SSH|SSH into the MOD Duo]] to get the corrupt plugin out.<br>
 +
To prevent this from happening, you can [http://lv2plug.in/pages/validating-lv2-data.html validate the lv2-data].
 +
 
 +
The other option is to include a GUI, you can make one with the [https://github.com/moddevices/mod-sdk MOD SDK].<br>
 +
Have a look [https://github.com/moddevices/mod-lv2-data/tree/master/plugins-fixed here] how a GUI affects the .ttl structure.<br>
 +
 
 +
<source lang="console">
 +
OPTIONAL
 +
$ tar -xzvf Plugin.lv2-dwarf.tar.gz
 +
make edits in Plugin.lv2/Plugin_dsp.ttl or include a GUI
 +
$ rm Plugin.lv2-dwarf.tar.gz
 +
$ tar -cvzf Plugin.lv2-duo.tar.gz Plugin.lv2/
 +
</source>
 +
 
 +
=== Deploying the plugin ===
 +
 
 +
Make sure the MOD device is connected to your computer via USB before proceeding. Then run:
 +
 
 +
<source lang="console">
 +
$ cd /path/to/max-gen-deploy/
 +
$ ./mod-deploy.sh
 +
</source>

Latest revision as of 17:25, 19 March 2023

Apart from programming LV2-plugins in a "traditional" way, it's also possible to generate LV2-plugins for MOD devices from gen~ objects created in Cycling '74 Max.
This page will tell you the how and why of programming audio effects for the MOD Duo using this very different approach.

Gen basics

Gen~ objects are normally used in Max as a way to write low-level code that is run at signal-rate, using (if you want to) the same visual approach Max is known for.
Therefore the insides of a gen~ object can be seen as a pedal schematic, perfect for designing audio effects.
The SHIRO plugins are an example of plugins for MOD devices made using this very method.

If you're not familiar with Gen, and this sounds all like gibberish to you, have a look at the links below.

Designing your effect in Gen

If you want to design a plugin for a MOD device, there are a few things you should know:

  • To get your gen~ object working on a MOD device, you'll need to design one using only Gen's internal objects, without referring to objects outside the gen~ object.
    Only the objects inside will make it to the final LV2-plugin.
  • If you want controllable parameters, define the default, minimum and maximum arguments in the "param" object.
  • While designing your gen~ object, remember that all MOD devices are running at 48 kHz sampling rate.

You'll find some example-plugins if you download the MOD Duo-package from the Package Manager in Max, and click on Launch.

Getting your Gen-based plugin to a MOD device

At this point you should have met the requirements specified above. If so, follow the steps below to get your plugin on a MOD device.
In order to run Gen-based plugins on a MOD device they must be converted into LV2 plugins and compiled using a custom MOD cloud build system.
All the heavy work has already been done by the MOD Team and Cycling '74.

  • Go to or install the MOD Duo-package in the Package Manager in Max if you haven't, and click on Launch.
  • Make sure your MOD device is connected, then start the MODwatcher from the popped-up screen.
  • If you want your plugin to have a name, copy your gen~ objects contents to a gen~ object with a patcher-name argument.
    WARNING: naming your original gen~ object will initialize it's contents.
  • Finally send a message containing "exportnotifier MODwatcher, exportcode" (without the quotation marks) to the gen~ object.

Your plugin will now be transferred to the MOD device, within a few minutes the MODwatcher will tell you if the upload succeeded.
If all goes well, your Gen-based plugin should now be inside the MOD device, ready to be played!

Additional features (advanced)

Optionally you can edit your plugin to, for example, add units, knob behavior, a description or even a GUI.

Your Gen-based plugin will only show knobs for each parameter. To get switches, selector, etc.. you’ll have to edit the .ttl file and add/change a few lines.

If you get knobs named like your data Gen~ object in Max, you can just ignore those parameters.
 These extra parameters are a side effect from how max gen works, if they really bother you, edit the main plugin .ttl file and set those as OutputPort instead of InputPort.

On a Mac you can do this with the nano editor:

Video tuto here : https://www.youtube.com/watch?v=CaLKImvc11w

  • Open up Terminal
  • Enter
$ ssh root@192.168.51.1
  • Password
$ mod
  • Enter
$ .lv2/YOURPLUGIN_NAME.lv2/YOURPLUGIN_NAME_dsp.ttl

i.e. to get a switch for this parameter:

a lv2:InputPort ,

        lv2:ControlPort ;
       lv2:index 5 ;
       lv2:symbol “FILTER” ;
       lv2:name “FILTER” ;
       lv2:default 0 ;
       lv2:minimum 0 ;
       lv2:maximum 1 ;
  • Add this line : lv2:portProperty lv2:integer, lv2:toggled  ;

which gives:

a lv2:InputPort ,

        lv2:ControlPort ;
       lv2:index 5 ;
       lv2:symbol “FILTER” ;
       lv2:name “FILTER” ;
       lv2:default 0 ;
       lv2:minimum 0 ;
       lv2:maximum 1 ;
       lv2:portProperty lv2:integer, lv2:toggled  ;

i.e if you want the host/mod tempo to control a time parameter

  • Add this line to the prefix list (at the beginning of the file):

@prefix  time: <http://lv2plug.in/ns/ext/time#> .

  • and these lines to the time Control Port which will give:

lv2:ControlPort ;

       lv2:index 2 ;
       lv2:symbol "BPM" ;
       lv2:name "BPM" ;
       lv2:default 120 ;
       lv2:minimum 24 ;
       lv2:maximum 280 ;
       units:unit units:bpm ;
       lv2:portProperty  mod:tempoRelatedDynamicScalePoints;

i.e if you want a selector

  • Add this line to the prefix list (at the beginning of the file):

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

And change i.e. this:

a lv2:InputPort, lv2:ControlPort ;
       lv2:index 6 ;
       lv2:name "Div_L" ;
       lv2:symbol "Div_L" ;
       lv2:default 1.000000 ;
       lv2:minimum 1.000000 ;
       lv2:maximum 5.000000 ;

To this :

a lv2:InputPort, lv2:ControlPort ;
       lv2:index 6 ;
       lv2:name "Div" ;
       lv2:symbol "Div" ;
       lv2:default 1.0 ;
       lv2:minimum 1.0 ;
       lv2:maximum 5.0 ;
       lv2:portProperty lv2:integer;
       lv2:portProperty lv2:enumeration ;    
       lv2:scalePoint [rdfs:label "1/4note"; rdf:value 1];
       lv2:scalePoint [rdfs:label "Dotted1/8note"; rdf:value 2];
       lv2:scalePoint [rdfs:label "1/4notetriplets"; rdf:value 3];
       lv2:scalePoint [rdfs:label "1/8note"; rdf:value 4];
       lv2:scalePoint [rdfs:label "1/8notetriplets"; rdf:value 5];
  • When you’re done, exit nano:
Ctrl + x
  • select Y(yes) or N (no)
  • Enter
systemctl restart mod-ui
  • Enter
exit
  • CAUTION: Delete your cache Browser to be shure to see the changes on your GUI

If all goes well, your modified Gen-based plugin should now be inside the MOD device, ready to be played!

Alternatively

There is another process which is different from the process described above. It doesn't use the MOD Duo-package in Max.


Compiling the plugin

First, download https://download.moddevices.com/releases/max-gen/max-gen-deploy_v6.tar.gz and extract it.
Send an "exportcode" message to the gen~ object in your main Max-patcher to get the YOURPLUGIN_NAME.cpp and YOURPLUGIN_NAME.h files.
replace YOURPLUGIN_NAME with “gen_exported" for both files Copy the gen_exported.cpp and gen_exported.h files into the extracted max-gen-deploy folder, and run:

$ cd /path/to/max-gen-deploy/
$ ./mod-build.sh

You'll be asked for a plugin name, and after providing one the cloud should give you back a tar.gz file within a few minutes.

Editing the plugin

To add units, knob behavior or a description, you'll have to edit the .ttl file. If you do so, make sure everything is correct,
otherwise the plugin won't work and you might have to SSH into the MOD Duo to get the corrupt plugin out.
To prevent this from happening, you can validate the lv2-data.

The other option is to include a GUI, you can make one with the MOD SDK.
Have a look here how a GUI affects the .ttl structure.

OPTIONAL
$ tar -xzvf Plugin.lv2-dwarf.tar.gz
make edits in Plugin.lv2/Plugin_dsp.ttl or include a GUI
$ rm Plugin.lv2-dwarf.tar.gz
$ tar -cvzf Plugin.lv2-duo.tar.gz Plugin.lv2/

Deploying the plugin

Make sure the MOD device is connected to your computer via USB before proceeding. Then run:

$ cd /path/to/max-gen-deploy/
$ ./mod-deploy.sh