How Do I Troubleshoot a Module Not Successfully Appearing?

I’m not a real programmer, but was able to describe a module idea to ChatGPT. I know chatbots hallucinate, but on the other hand, ChatGPT and other AIs are built now to make code. The robot created:

Makefile plugin.cpp plugin.hpp plugin.json SergeCurveBender.cpp and a matching SVG in a folder /res

It showed me how to use Terminal with the Rack SDK downloads to compile the plugin.dylib. I used the Silicon version of SDK to match the version of Rack I have.

The chatbot and I have checked and double-checked what’s written in the various files. I used BBEdit, not TextEdit, to save the robot’s code into files with the proper extensions, because I heard TextEdit sometimes screws things up.

The only ambiguity I encountered was the robot first created a plugin.json, then mentioned it should be manifest.json for Rack 2. But when I tried compiling that in Terminal, I got the message “can’t find plugin.json,” if I’m remembering correctly, so I changed the filename back to plugin.json.

Thank you for your wisdom! I got so excited once the robot told me it could help me build my VCV Rack dreams, but I’ve been crushed with disappointment ever since.

Makefile:

PLUGIN_NAME := SergeCurveBender
RACK_DIR ?= /Users/anneevans/Documents/Rack-SDK
PLUGIN_SLUG := SergeCurveBender
PLUGIN_VERSION := 1.0.0
include $(RACK_DIR)/plugin.mk```

plugin.hpp (which for some reason is ignoring the code-box)

#pragma once

#include "rack.hpp"

using namespace rack;

extern Plugin* pluginInstance;

extern Model* modelSergeCurveBender;```

plugin.cpp:

#include "plugin.hpp"

Plugin* pluginInstance;

void init(Plugin* p) {
    pluginInstance = p;
    p->addModel(modelSergeCurveBender);
}```

plugin.json:

{
  "slug": "SergeCurveBender",
  "name": "Serge Curve Bender",
  "version": "1.0.0",
  "author": "Anne Evans",
  "license": "Proprietary"
}

The brains of the module:

// SergeCurveBender.cpp
#include "plugin.hpp"

struct SergeCurveBender : Module {
    enum ParamIds {
        BEND_PARAM,
        CURVE_PARAM,
        DRIVE_PARAM,
        NUM_PARAMS
    };
    enum InputIds {
        IN_INPUT,
        BEND_INPUT,
        CURVE_INPUT,
        DRIVE_INPUT,
        NUM_INPUTS
    };
    enum OutputIds {
        OUT_OUTPUT,
        NUM_OUTPUTS
    };
    enum LightIds {
        NUM_LIGHTS
    };

    SergeCurveBender() {
        config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
        configParam(BEND_PARAM, 0.f, 1.f, 0.f, "Bend Amount");
        configParam(CURVE_PARAM, 0.f, 1.f, 0.f, "Curvature Amount");
        configParam(DRIVE_PARAM, 0.f, 2.f, 1.f, "Drive Amount");
    }

    void process(const ProcessArgs& args) override {
        float in = inputs[IN_INPUT].getVoltage();

        float bend = params[BEND_PARAM].getValue();
        if (inputs[BEND_INPUT].isConnected())
            bend += inputs[BEND_INPUT].getVoltage() / 10.f;
        bend = clamp(bend, 0.f, 1.f);

        float curve = params[CURVE_PARAM].getValue();
        if (inputs[CURVE_INPUT].isConnected())
            curve += inputs[CURVE_INPUT].getVoltage() / 10.f;
        curve = clamp(curve, 0.f, 1.f);

        float drive = params[DRIVE_PARAM].getValue();
        if (inputs[DRIVE_INPUT].isConnected())
            drive += inputs[DRIVE_INPUT].getVoltage() / 10.f;
        drive = clamp(drive, 0.f, 2.f);

        in *= drive;

        float out;
        if (bend <= 0.001f) {
            out = in;
        } else if (bend >= 0.999f) {
            out = std::abs(in);
        } else {
            float signIn = (in >= 0.f) ? 1.f : -1.f;
            float absIn = std::abs(in);
            float alpha = 0.1f + 0.9f * curve;
            float softened = absIn / (1.f + alpha * absIn);
            out = (1.f - bend) * in + bend * signIn * softened;
        }

        out = clamp(out, -5.f, 5.f);
        outputs[OUT_OUTPUT].setVoltage(out);
    }
};

struct SergeCurveBenderWidget : ModuleWidget {
    SergeCurveBenderWidget(SergeCurveBender* module) {
        setModule(module);
        setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/SergeCurveBender.svg")));

        addInput(createInputCentered<PJ301MPort>(mm2px(Vec(10, 30)), module, SergeCurveBender::IN_INPUT));
        addInput(createInputCentered<PJ301MPort>(mm2px(Vec(10, 50)), module, SergeCurveBender::BEND_INPUT));
        addInput(createInputCentered<PJ301MPort>(mm2px(Vec(10, 70)), module, SergeCurveBender::CURVE_INPUT));
        addInput(createInputCentered<PJ301MPort>(mm2px(Vec(10, 90)), module, SergeCurveBender::DRIVE_INPUT));

        addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(25, 50)), module, SergeCurveBender::BEND_PARAM));
        addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(25, 70)), module, SergeCurveBender::CURVE_PARAM));
        addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(25, 90)), module, SergeCurveBender::DRIVE_PARAM));

        addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(10, 110)), module, SergeCurveBender::OUT_OUTPUT));
    }
};

Model* modelSergeCurveBender = createModel<SergeCurveBender, SergeCurveBenderWidget>("SergeCurveBender");

SVG:

<svg xmlns="http://www.w3.org/2000/svg" width="6" height="128" viewBox="0 0 6 128">
  <rect width="100%" height="100%" fill="#e6f0fa"/>
  <g stroke="none" fill="#fdfdf6">
    <rect x="0.5" y="10" width="5" height="22" rx="1"/>
    <rect x="0.5" y="38" width="5" height="22" rx="1"/>
    <rect x="0.5" y="66" width="5" height="22" rx="1"/>
    <rect x="0.5" y="94" width="5" height="22" rx="1"/>
  </g>

  <!-- Labels -->
  <text x="3" y="8" text-anchor="middle" font-size="2" fill="#333">IN</text>
  <text x="3" y="36" text-anchor="middle" font-size="2" fill="#333">BEND</text>
  <text x="3" y="64" text-anchor="middle" font-size="2" fill="#333">CURVE</text>
  <text x="3" y="92" text-anchor="middle" font-size="2" fill="#333">DRIVE</text>
  <text x="3" y="124" text-anchor="middle" font-size="2" fill="#333">OUT</text>

  <!-- Ports and knobs markers -->
  <circle cx="1.5" cy="15" r="1" fill="#d44"/>
  <circle cx="4.5" cy="15" r="1" fill="#d44"/>
  <circle cx="1.5" cy="43" r="1" fill="#d44"/>
  <circle cx="4.5" cy="43" r="1" fill="#d44"/>
  <circle cx="1.5" cy="71" r="1" fill="#d44"/>
  <circle cx="4.5" cy="71" r="1" fill="#d44"/>
  <circle cx="1.5" cy="99" r="1" fill="#d44"/>
  <circle cx="4.5" cy="99" r="1" fill="#d44"/>
  <circle cx="3" cy="120" r="1" fill="#d44"/>
</svg>```

Your problem is trying to use AI as a beginner. Getting good results depends on knowing when the AI has got things wrong, so if you’re a beginner, you’re already lost.

One thing immediately wrong at a cursory glance is that your SVG contains text, which Rack’s SVG dependency doesn’t support.

Better to start with the Rack manual for setting up a build environment, then use an existing template so you have something that actually builds and runs from the beginning (e.g. use the repo template at Paul-Dempsey/GenericBlank: Template for a VCV Rack Blank module.

Sooner or later, you’re going to just have to learn how to build, write code, and debug on your own without the crutch.

1 Like

You should see some more information in the VCV Rack log file, but a first thing that I noticed: version “1.0.0” will not be loaded by VCV Rack 2, since it assumes that this means that it’s a plugin for VCV Rack 1. You need to start with “2.”

2 Likes

Thank you. I think your expectations might be a bit high for a liberal arts major who mainly builds in Max, which is not code, obviously. The coders I know have been coding for decades.

Thank you, that’s very helpful.

Depends on what you do in Max. The paradigm is a bit different, but if you’re doing anything more than glueing things together, you’re programming. Don’t sell yourself short. I was an Art major.

You’ll have more success if you’re learning from something/someone who knows what they’re doing, which AIs do not.

Starting off with something that actually works is helpful, which is why I created GenericBlank. This actually puts in a better position for success than the Rack tutorial IMO.

But also, it’s considered poor form to post AI-generated code and ask others to figure out the problems with it. Too much of that will be discouraged by the forum moderators.

4 Likes

For what it’s worth, I’m a musician who went to music school etc, and a few years ago I knew next to nothing about code, but now I know some c++. Even without decades of experience I’ve been able to contribute to Surge for example. It does require some patience, but is not impossible!

As a beginner who tries (a lot) to understand (very little) what’s going on under the hood, I’d like to share my opinion. I think using AI to try to code is the best way to never learn how to do it. Especially since its suggestions sometimes reveal errors. On the other hand, it’s undeniable that AI is a valuable learning aid: it helps clarify certain points that seem unclear and helps unblock certain situations. For example, the VCV manual says to run “helper.py createplugin MyPlugin”… which I do several times without success. I then ask the AI, which advises me to run “python3 helper.py createplugin MyPlugin” instead, explaining why… and it works.

In tutorials or manuals, the most common pitfall that a novice (like me) will stumble upon is the “unspoken”—that is, concepts that specialists don’t explain because they consider them basic and taken for granted. For a non-specialist, being able to consult a single source that also provides an immediate answer is invaluable.

In the future, please let us know at VCV Support if you encounter an issue with our documentation or software. We aren’t able to know that you’ve hit an obstacle unless you tell us.

As a complete beginner, when I encounter a problem, my first instinct is to doubt myself. I tell myself that if the problem came from VCV Rack, it would probably have already been reported. These are the reasons why I hesitate to bother VCV support, which, I think, probably has other fish to fry.