Rack development - setting things up

Hi, I have decided to tip my toe on the plugin development pool and I’m trying to set up my build environment. So far I have managed to build the Fundamental modules and load them into VCV Rack and use them. So far so good!

I’m following the official rack development guide and and this guide from the Medium: https://medium.com/@tonetechnician/how-to-setup-your-windows-vs-code-environment-for-vcv-rack-plugin-development-and-debugging-6e76c5a5f115

I’m using VS Code as my IDE, and I’m trying to set up tasks so that when I build the module, they will be automatically copied into plugin folder. In the guide from the Medium, the author creates two tasks, one for the build/copy, and one for the cleanup. Both works just fine, only problem is that only the ‘.vcvplugin’ plugin file is copied into plugin folder - the actual dll is missing.

I investigated the makefile, that was created by the helper.py, and noticed these two files on tope of the file:

# If RACK_DIR is not defined when calling the Makefile, default to two directories above
RACK_DIR ?= ../..

To make life a bit harder, my plugin folder is located on a non standard location, so I need to somehow specify the location where the files should be copied.

Few questions: what are the directories mentioned in the makefile? And what kind of build tasks you use in VS Code to aid your plugin development?

More questions will be posted when I manage to set-up everything and start the actual development!

-k

It’s fine to just copy the .vcvplugin file that results from running make dist or make install. The plugin.dll is inside it and gets unpacked when Rack runs. These commands will work properly out-of-the-box for your custom user folder when you set the appropriate environment variables.

See Command-Line Usage in the rack manual. The last paragraph is:

You may also set the RACK_SYSTEM_DIR or RACK_USER_DIR environment variables to override these locations.

I used to build from VSCode, but I don’t anymore (only debug). Now I just build from a MINGW64 console (in Windows Terminal). I also have MINGW terminal inside VSCode and sometimes build from there.

I don’t use the SDK. I build/run from a clone of the Rack source, in this setup there’s no need for doing a make install or creating or copying the .vcvplugin to your retail Rack install – it is built in-place and ready to run.

Thank you!

VCV Rack’s plugin.mk supports RACK_USER_DIR, so if the environment variable is set, make install will build, package, and install your plugin in your specified location. RACK_DIR should point to the extracted Rack SDK folder.

Be wary of third-party instructions, as they may be incorrect, misleading, or out of date. If VCV’s instructions aren’t working for you, contact VCV Support so we can assist you or fix our documentation.

1 Like

Everything is building and VCV Rack is loading my module but there is no UI :smiley:

I’m trying to use Affinity Designer as my SVG editor. UI looks like this in AD:

When I execute the helper.py, output says:

Found 0 params, 0 inputs, 0 outputs, 0 lights, and 0 custom widgets in "components" layer.

I found this one related to using AD as a UI designer for VCV Rack panels https://github.com/modlfo/FixAffinitySVG but that page is pretty old and I thought that doesn’t matter anymore

When I load my plugin in VCV Rack, it looks like this:

Here is the SVG file:

test

Generated CPP file looks like this:

struct TestWidget : ModuleWidget {
	TestWidget(Test* module) {
		setModule(module);
		setPanel(createPanel(asset::plugin(pluginInstance, "res/Test.svg")));

		addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
		addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
		addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
		addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
	}
};

Any thoughts that what could be wrong?

-k

I suspect helper.py is not compatible with Afinity. But I’ve never used either, so my suspicion may be wrong.

I’m also using Affinity Designer for creating my panels, I don’t have to change anything in the exported SVG files.

What size did you specify for your document in Designer? All my panel designs have a height of 380px and a width of 15px per HP (i.e. per “screw hole”). So a panel of 3 wide would be 45px. If I try to use your svg file directly in my plugin, it also doesn’t show a UI, but if I open the svg file in designer and change the document size to 45x380px in File → Document Setup and export it again, it does show the UI as a 3HP wide panel

Do you use helper.py?

@not-things I probably made a rookie mistake and used millimeters as unit. I’ll try with pixels!

@Squinky Yes, helper.py for generating the cpp

Here’s your svg file in plain text:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:serif="http://www.serif.com/" width="100%" height="100%" viewBox="0 0 25 127" version="1.1" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
    <g id="background" transform="matrix(1.69333,0,0,1.10133,-8.66667,-8.48778)">
        <g id="panel">
            <rect id="background1" serif:id="background" x="5.118" y="7.707" width="14.764" height="114.84" style="fill:rgb(64,64,64);"/>
        </g>
    </g>
    <g id="components">
    </g>
</svg>

There is only one <rect> inside, and nothing else - no red circle, no green circle, no blue circle.

Here’s my standard advice on problems with svg and VCV: use Inkscape :+1:

Oh boy, looks like I need to chek my export settings…or start installing Inkscape😂

@not-things I changed the document units to pixels but that didn’t help. Well it helped a bit but now I’m getting errors from the helper.py when it tries to parse the file. Any chance if you could open the AD file on your AD and see if you can see what is going on? Remove the ‘.txt’ extension!

test.afdesign.txt (14.9 KB)

I’m using following settings when exporting:

When I run helper.py against the exported SVG, I’m getting following errors:

$ helper.py createmodule Test res/test.svg src/test.cpp
Module Test already exists in plugin.json. Edit this file to modify the module manifest.
src/test.cpp already exists. Overwrite? (y/n) [n]: y
Traceback (most recent call last):
  File "/d/msys64/home/kila/Rack-SDK/helper.py", line 610, in <module>
    parse_args(sys.argv)
  File "/d/msys64/home/kila/Rack-SDK/helper.py", line 601, in parse_args
    create_module(*args)
  File "/d/msys64/home/kila/Rack-SDK/helper.py", line 251, in create_module
    components = panel_to_components(tree)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/d/msys64/home/kila/Rack-SDK/helper.py", line 379, in panel_to_components
    color = color_match.group(1)
            ^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'group'

Here is the SVG:

test

@Ahornberg Reason for the ‘empty’ file was that items on the “components” layer were marked as hidden. Now that they are visible, they are included int the SVG.

-k

A small adaption is needed in the script: the helper.py accepts both “#00f” and “#0000ff” as color values for a fill attribute, but for a style attribute with a fill inside it, it only checks for “#0000ff” (or similarly formatted color).

If you update re.search(r'fill:\S*(#[0-9a-fA-F]{6})', style) on line 378 in helper.py to re.search(r'fill:\S*(#(?:[0-9a-fA-F]{3}){1,2})', style), it will accept both the 3 and 6 character color values. And make sure you check the “Use hex colours” option in the SVG export dialog in Affinity Designer.

1 Like

IMO Helper.py is unsustainable. When it works, it’s only usable as an initial bootstrap and shouldn’t be used once your module is running. Depending on your SVG tool, it’s easy to get an SVG that helper.py is broken for. IIRC it doesn’t understand transforms, which are very commonly added by svg editors whenever you move something. The whole Rack tutorial leads you into traps that you cannot sustain as you iterate.

Better to start from an already clean, building, and loading module (e.g. use my GenericBlank template repo).

1 Like

If our software fails to parse your SVG file, send a bug report to VCV Support and our team will help you get started.

I already sent an email to the support address after replying here with a suggested change for the helper.py script so that it also accept the Affinity Designer SVG export :slight_smile:

When I’m a little more familiar with everything, I intend to do all the code manually and skip the “helper.py” altogether if possible. But at the moment there are just too many moving parts, and I’m just trying to create some kind of prototype and learn all the functions needed to create the interface, and what are the “correct” sizes of the elements, and “helper.py” is great for that.

Some progress. After changing the HEX colors on the file, the module appears and contains all the controls, but the placement is incorrect:

module

Here is the SVG:

test

And here is the generatd code:

struct TestWidget : ModuleWidget {
	TestWidget(Test* module) {
		setModule(module);
		setPanel(createPanel(asset::plugin(pluginInstance, "res/Test.svg")));

		addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
		addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
		addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
		addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));

		addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(16.933, 16.568)), module, Test::MODIFY_PARAM));

		addInput(createInputCentered<PJ301MPort>(mm2px(Vec(16.933, 4.838)), module, Test::INCV_INPUT));

		addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(16.933, 28.299)), module, Test::OUTCV_OUTPUT));
	}
};

In the SVG file, if you update the width="100%" and height="100%" on the root element to width="75" and height="380" (the same values as used in the viewBox), the helper.py script should be able to determine the positions correctly.

The helper.py script expects the width and height in either pixels or mm, and unfortunately, it is not possible to instruct Affinity Designer to export in px and also keep the viewBox (which is also needed by helper.py). This is only needed while using the script to generate the code. Once you’re comfortable changing the code directly yourself, you won’t have to update the SVG anymore.

1 Like

Thank you!!!

There is a proverb in the Finnish language - Ei ole lahjahevosen suuhun katsomista - which freely translates to “Don’t look into the mouth of a gift horse”, i.e., if you get something for free, don’t whine. Or something like that.

I installed Inkscape… and then I removed it. Using it after Affinity Designer is a bit too harsh a punishment IMO.

I probably need to write a small script or console application that processes the SVG file so that I don’t have to remember to do it manually after each edit.

Thank you again, now it looks a bit better :smiley:

panel

2 Likes