helper.py enhancement

Due to my method of development (I keep adding stuff to the panel and moving stuff around using inkscape as opposed to making adjustments to code) I have found it dificult as I keep having to copy and paste code bits from my module into my newly “helper.pyed” module, not to mention having to save copies beforehand (fortunately I have not yet over written anything by accident). I got the idea to include the type of knob / switch in the object properties of the .svg and modified helper.py to support this.

object properties -
ID: circle:SynthTechAlco:401 (in this case I wanted the SynthTechAlco knob to be used)

by adding my choice of knob or switch with a colon on either side to the ID field in object properties my helper now creates the code with knob or switch I want which means I dont have to do any editing of the “module widget” section at the end of the module.

Some copying of the module structure at the start is needed which is usually quite minor and then I just copy over the body of the code.

is this something others would be interested in or are most of you doing all your changes in code rather than the .svg?

1 Like

I have a feeling that a majority use code and a minority use helper.py. But it’s a good Q. Personally, I’ve made a lot of module, and never opened Inkscape.

I’ve made a lot of modules and never used helper.py

but we have both been making modules since before helper.py existed, right? But helper.py does seem to be a solution to an non-existent problem. It’s easy to position jacks and controls in code, there are at ton of example how you do it. Why automate it?

I think helper.py is probably nice to get “first light” - instant module maker. That’s cool, but if you are going to stick with it, why stick with helper.py?

I know it seems like I’ve been around forever but I’ve not quite been here for 3 years yet.The helper script was certainly available when I started.

You’re right though, for someone just starting out it’s a good tool to get them up and running.

I tend to have standard positions for my components and I use a corresponding grid to align the panel graphics in Inkscape.

That makes sense. I don’t do that at all. At the very end I draw the panel from scratch in not Inkscape. Then I hide all the controls and output svg. Then I manually copy the positions from not Inkscape into my code.

I also started before helper.py existed. For me, constantly going back to it and copy pasting code back into a generated skeleton seems like a big time waster.

I think its much quicker to change the existing code to move or add controls.

Maybe that’s one of the problems that helper.py solves?

Yeah. I think for a generator type program to really be efficient and worthwhile it needs to be re-entrant. In other words: It should generate code that only the generator is in charge of, that a person never needs to modify. The other code of the module around that should simply reference it. Strict seperation between generated and edited code. In that way it would be trivial and safe to make quick SVG edits, do another generate cycle and it’s instantly reflected in the module. I don’t know how hard it would be to modify the helper.py code to generate that kind of code structure for a module.

I think many (or most?) people prefer to write code and iterate/test first, and tweak UI later. The controls change a lot during development, and copy some lines to create a badly positioned knob for testing an idea is faster and more streamlined.

Ideally, if we want to make code generation easy to use, the most convenient way is to do it in the same language (using compile-time execution and code insertion), unfortunately C++ is lacking in this direction:

import Rack_Code_Generator

Foo_Widget(Foo_Module* module_handle) {
    
    // c++2077 feature, maybe
    insert_code {
        
        auto path = "res/foo.svg";
        auto info = get_info_from_svg(path);

        code_of_this_block = generate_code(path, info); // this return a string
    }
}

To emulate this in something like helper.py, either we need to do something like this:

struct Foo_Module {
    #include ".generated/foo_module.cpp"
    ...
}

Foo_Widget(Foo_Module* module_handle) {
    #include ".generated/foo_widget.cpp"
}

or the script need to parse the whole cpp file and replace these parts (with backups, probably).

sounds good, i think helper.py would be more useful as an iterative tool if it only touched the ui-related stuff and not the process method.

1 Like

Initially, I was fighting Inkscape more than I was finding it helpful, so I played for a while with making helper.py more useful. In the end, I just started doing all of my panel layout via code, relative to whatever panel size I had decided upon. There are lots of things that can be done to modularize component placement via relative block coordinates, such that an entire block of associated components can be move by changing one line of code. But, I only have one module… but it is a monster :wink:

So, I do not use SVG but rather nanoVG at runtime for panel text and graphics.

By the way, one of the most useful thing I did to help myself do panel design on the fly in code was to write the code below to draw a grid on top of the runtime panel. I usually do a snip of the panel in Rack at 100% zoom and then print that out on a single sheet of paper and use it for my working template for component placements and tweaks, until it gets too messy or outdated and then I do a new grid capture.

Edit: The panelWidth, etc. is based on SVG units. I should clarify that I still use an SVG file but all it does is define the panel dimensions and the background color.

void drawGrid(const DrawArgs &args)
		{
			
				float panelWidth=mm2px(406);
				float panelHeight=mm2px(129);
				int gridWidthDivisions=(int)(panelWidth/10.0);  // 112
				int gridHeightDivisions=(int)(panelHeight/10.0); // 38
				float gridWidth=10.0;
				float gridHeight=10.0;

				
				nvgStrokeColor(args.vg, nvgRGB(0, 0, 0));
				nvgStrokeWidth(args.vg, 1.0);
				
				for (int x=0; x<gridWidthDivisions; ++x)
				{
					if (x%10==0)
					{
						nvgStrokeWidth(args.vg, 2.0);
						nvgStrokeColor(args.vg, nvgRGBA(0, 0, 0xff, 0x80));
					}
					else
					{
						nvgStrokeWidth(args.vg, 1.0);
						nvgStrokeColor(args.vg, nvgRGBA(0xff, 0, 0, 0x80));
					}

					nvgBeginPath(args.vg);
					nvgMoveTo(args.vg, x*gridWidth, 0);
					nvgLineTo(args.vg, x*gridWidth,  gridHeightDivisions*gridHeight);
					nvgStroke(args.vg);
				}
				for (int y=0; y<gridHeightDivisions; ++y)
				{
					if (y%10==0)
					{
						nvgStrokeWidth(args.vg, 2.0);
						nvgStrokeColor(args.vg, nvgRGBA(0, 0, 0xff, 0x80));
					}
					else
					{
						nvgStrokeWidth(args.vg, 1.0);
						nvgStrokeColor(args.vg, nvgRGBA(0xff, 0, 0, 0x80));
					}

					nvgBeginPath(args.vg);
					nvgMoveTo(args.vg, 0, y*gridHeight);
					nvgLineTo(args.vg, gridWidthDivisions*gridWidth, y*gridHeight);
					nvgStroke(args.vg);
				}
		}

By the way, even though I have worked professionally as a 3D animator, I do not consider myself a talented (nor interested) graphic designer. I tend to fake it all via procedural graphics and even procedural animation… and procedural music :wink:

What I meant is that the things that helper.py could speed up are already a very small minority of the things one needs to do making a module. I probably would not be interested enough to try a tool that promises to speed up development by one percent. And I would for sure not give up a proper screen designer to use Inkscape and save that 1%.

The ability to go back and forth between coding and a visual design tool that generates code is sort of the “holy grail”. I’ve used one tool in my life that does this decently - Apple’s XCode. But - that relies on features in Apple’s own languages to make it work, a luxury that few have.

I have worked on tools myself that try to bridge this gap. All have been failures - it’s a difficult problem.

Ultimately, a tool like this would need to allow round-tripping and also provide significant value. Another counter example is Microsoft’s XAML designer. It does round-trip OK, but it doesn’t work well enough to use. Last program I worked on that had native UI everyone used the Apple tool for the Mac UI, but no-one uses the Microsoft tool for the Windows UI - everyone coded that by hand.

Myself, I would much prefer VCV to spend their resources adding things to the SDK to make it easier to make custom widgets, fancy menus, easier tooltips. The 2.0 SDK is a big advance here. It’s now relatively easy to add simple menu items.

I will be interested to see a “top tier” developer here chime in and say they use helper.ph. I’m going to bet that Vult, Bogaudio, VCV, etc… do not use that tool.

1 Like

What is this “paper” whereof you speak? :grin:

I was just thinking the other day about this. It would be possible to embed an interepreted language and ‘wrap’ the C++ API so that you could litereally write a plugin in Javascript or Python. A full wrapping of the API can be made more-or-less automated with Swig https://swig.org/

Of course that would mean interpreting DSP code instead of executing it native, but it would be a cool prototyping tool.

I’ll have you know that I have professionally worked on the paperless office effort, and I have tons of paper to back up that claim… oops, did I get the concept backwards?

“I was just thinking the other day about this. It would be possible to embed an interepreted language and ‘wrap’ the C++ API so that you could litereally write a plugin in Javascript or Python. A full wrapping of the API can be made more-or-less automated with Swig https://swig.org/

Yes! About 18 years ago I worked for a 3D modelling and animation tool company. My claim to fame was that I embedded Python in their SDK as well as exposed their entire API to enable Python (and Javascript) scripting. I used Swig for part of it! It was a pain in the butt, but the results were fantastic, IM~HO. I ended up developing an entire metaverse system based on scriptable viewer apps and UDP message passing worldwide. I even did a realtime hierarchical 3D character/environment collision detection system that could take detection precision down to the pixel level, in realtime.

Like this? VCV - Prototype

Yes, like that. Where is it?

I’ve never used it. Maybe you need to build it yourself? GitHub - VCVRack/VCV-Prototype