Snap knob to select input channels

Good evening people. I’ve been disturbing you a lot lately. I think it’s normal when you start doing things for which people have years of school and you have studied five minutes on wikipedia and five minutes on youtube (actually I read a lot, but never like those who study computer science at school).

I get to the point: I have knobs that I can’t get to work in any way. I’ve made dozens of attempts, maybe hundreds. Two things happen, either I write the correct syntax but useless for the purpose (so the compiler doesn’t find errors but the knob still doesn’t work), or when I’m using something that maybe could work, the compiler gives me “warning: unused variable”, or other less frequent errors. I don’t know what to write anymore, I could type rude words for him.

The project is this: a polyphonic input sends the signal to 5 monophonic outputs, which are mixed into a polyphonic main output, I would like each of the 5 knobs to be able to select one of the sixteen input channels (maximum polyphony), to obtain the 5 chosen channels separated (mono), or mixed in the main output.

(I’m not sure if at present the main output is taking the signal from the mono outputs, maybe it takes it directly from the input, but eventually I will address the problem later)

When I began developing my plugin, I had to ask lots of questions. I also had to look at a lot of open source modules’ code to learn how a plugin and modules are put together. I suggest picking an existing open source module that is in the same genre as yours and study their Github source code. All of the pieces will be there.

2 Likes

That’s what I’m doing. I have already developed a vco, a vca, an lfo and an adsr studying other codes, but in this case I just can’t find something useful (or I can’t use what I find correctly).

If I have asked here, it is because I have truly come to despair. :slight_smile:

Is your code available on github? If others can view all the source code that is the best way to get help. The second-best option would be to paste the code that isn’t working into a post in this thread. There aren’t really any 3rd best options, people need to see the code in order to help!

Good luck, I know programming can be very frustrating and confusing when you’re starting out. It can also be very frustrating when you have 10+ years of experience! The computers are unforgiving and quite rude usually.

1 Like

Here is the code (I deleted all my wrong attempts)

#include "plugin.hpp"


struct Deviat5 : Module {
	enum ParamId {
		SEL1_PARAM,
		SEL2_PARAM,
		SEL3_PARAM,
		SEL4_PARAM,
		SEL5_PARAM,
		PARAMS_LEN
	};
	enum InputId {
		IN_INPUT,
		INPUTS_LEN
	};
	enum OutputId {
		OUT1_OUTPUT,
		OUT2_OUTPUT,
		OUT3_OUTPUT,
		OUT4_OUTPUT,
		OUT5_OUTPUT,
		MAIN_OUTPUT,
		OUTPUTS_LEN
	};
	enum LightId {
		LIGHTS_LEN
	};
    
    //edit channels = 5
	int channels = 16;
    //edit lastChannels 0
	int lastChannels = 0;

	Deviat5() {
		config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
        configParam(SEL1_PARAM, 0.f, 15.f, 0.f, "Channel Selector 1");
		configParam(SEL2_PARAM, 0.f, 15.f, 0.f, "Channel Selector 2");
		configParam(SEL3_PARAM, 0.f, 15.f, 0.f, "Channel Selector 3");
		configParam(SEL4_PARAM, 0.f, 15.f, 0.f, "Channel Selector 4");
		configParam(SEL5_PARAM, 0.f, 15.f, 0.f, "Channel Selector 5");
		configInput(IN_INPUT, "Polyphonic");
        configOutput(OUT1_OUTPUT, "Output 1");
		configOutput(OUT2_OUTPUT, "Output 2");
		configOutput(OUT3_OUTPUT, "Output 3");
		configOutput(OUT4_OUTPUT, "Output 4");
		configOutput(OUT5_OUTPUT, "Output 5");
		configOutput(MAIN_OUTPUT, "Main");
	}

	void process(const ProcessArgs& args) override {
        lastChannels = inputs[IN_INPUT].getChannels();
		for (int c = 0; c < 5; c++) {
			float v = inputs[IN_INPUT].getVoltage(c);
			outputs[OUT1_OUTPUT + c].setVoltage(v);
            outputs[MAIN_OUTPUT].setVoltage(v, c);
		}
        
        int automaticChannels = 5;
        
        automaticChannels = lastChannels;
        outputs[MAIN_OUTPUT].channels = (channels >= 0) ? channels : automaticChannels;
	}

};


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

		addChild(createWidget<DR4Screw>(Vec(RACK_GRID_WIDTH, 0)));
		addChild(createWidget<DR4Screw>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
		addChild(createWidget<DR4Screw>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
		addChild(createWidget<DR4Screw>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
        
        addParam(createParamCentered<DR4KnobSnap>(mm2px(Vec(9.884, 32.999)), module, Deviat5::SEL1_PARAM));
		addParam(createParamCentered<DR4KnobSnap>(mm2px(Vec(9.884, 47.405)), module, Deviat5::SEL2_PARAM));
		addParam(createParamCentered<DR4KnobSnap>(mm2px(Vec(9.884, 61.81)), module, Deviat5::SEL3_PARAM));
		addParam(createParamCentered<DR4KnobSnap>(mm2px(Vec(9.884, 76.216)), module, Deviat5::SEL4_PARAM));
		addParam(createParamCentered<DR4KnobSnap>(mm2px(Vec(9.884, 90.621)), module, Deviat5::SEL5_PARAM));

		addInput(createInputCentered<DR4Port>(mm2px(Vec(8.909, 113.653)), module, Deviat5::IN_INPUT));

		addOutput(createOutputCentered<DR4Port>(mm2px(Vec(26.652, 32.999)), module, Deviat5::OUT1_OUTPUT));
		addOutput(createOutputCentered<DR4Port>(mm2px(Vec(26.652, 47.405)), module, Deviat5::OUT2_OUTPUT));
		addOutput(createOutputCentered<DR4Port>(mm2px(Vec(26.652, 61.81)), module, Deviat5::OUT3_OUTPUT));
		addOutput(createOutputCentered<DR4Port>(mm2px(Vec(26.652, 76.216)), module, Deviat5::OUT4_OUTPUT));
		addOutput(createOutputCentered<DR4Port>(mm2px(Vec(26.652, 90.621)), module, Deviat5::OUT5_OUTPUT));
		addOutput(createOutputCentered<DR4Port>(mm2px(Vec(26.652, 113.653)), module, Deviat5::MAIN_OUTPUT));
	}
};


Model* modelDeviat5 = createModel<Deviat5, Deviat5Widget>("Deviat5");

I suggest rather than:

outputs[MAIN_OUTPUT].channels=n;

use:

outputs[MAIN_OUTPUT].setChannels(n);

I would use the SPLIT module with 4 instances of “Volt Meter” to check exactly what you are inputting into your module and a similar set to check exactly what you are getting out of your module. SPLIT will display the number of channels. This assumes you get as far as your module executing without crashing.

Also, I do not see where you have called createParamCentered() and addParam() for each parameter.

I didn’t post that part because I thought it wasn’t important (if it is, I’ll add it)

The module is developed and running. The five mono outputs emit a mono signal, the polyphonic output emits a polyphonic signal up to a maximum of 5 channels (but I cannot tell if it takes the signal from the other outputs or from the input)

The biggest problem I have now is getting the channel select knobs to work.

poli

I’ve already tried using .setChannels (they’ve already suggested it) but the compiler returns errors to me. Instead .channels interprets it without problems.

Personally, I would use something like Submarine SS-221 and run a unique integer voltage into each of 8 inputs on the MERGE. Otherwise it is very hard to determine which channels are making it to which outputs.

On a quick look–the channel selector knobs will be returning a float (like 1.0 or 3.0) between 0 and 15, but to access the array of input channels you need an int (like 1 or 3) between 0 and 15.

I think you left out the part of the code where you read the channel selector knobs (which sounds like the part that’s breaking)–can you post a recent attempt?

Yeah, that is most probably the case, unless they just did not show that code.

1 Like

(I did not use the Volt Meter because having the audio available I used the ears)

poli2

So in that example would be you be expecting all five outputs to be 10V, since that’s on poly channel 1 and the CH SEL knobs are in minimum position?

Generally, how exactly are the channel select knobs misbehaving? And is that the only problem, or is there something else going on?

I wish the input was able to receive 16 channels, and this happens. The knobs (snap) should select a channel from 1 to 16 (example, I like channels 4,8,9,12,15) now that I have chosen them, I would like to be able to output them all together from the Main output, or separately from the 5 mono outputs

Right–I think I understand what you want to do. What I don’t understand is what’s not working :slight_smile:

Are you saying that the knobs don’t select the channels when you turn them? I don’t see anything in the snippet above that reads the SEL*_PARAMs; have you written a version that’s not behaving as expected, or are you trying to figure out how to get started with that functionality?

gc3 is right. You are probably not reading the knob params via something like:

params[SEL1_PARAM].getValue()
and then doing something with the value.
2 Likes

Exact. I have made many attempts but random, because I am not clear how to express to the code what I want.

1 Like

Maybe that’s the part I’m really missing. I tried .setValue, .getValue, → getValue (because the compiler recommended it to me), I also took inspiration from the Step knob of SEQ-3, and the Lenght knob of Manifold (CountModula), I tried many things, but even when the compiler did not mark errors, the code did not work.

Ah. Got it. I’m not at my dev machine right now, but let me write out one way of doing it generally, and see if that helps?

First, what you need to do is get the value from the params (as @k-chaffin wrote) into local variables. However, bear in mind that you want to use these to read one of the incoming voltages, and to do that you need an int, not a float. So cast it to an int. Lots of ways to do this, here’s a simple way that should work unless I’ve typo’d (again, not testing this, which is especially risky for C++ at least if you’re me :slight_smile: )

int sel1_c = (int)params[SEL1_PARAM].getValue();
...
int sel5_c = (int)params[SEL5_PARAM].getValue();

Now you’ve got five integers (like the 4, 8, 9, 12, 15 in your post above). Let’s just call them int sel1_c through int sel5_c for now. One simple way to do the next step would be to save the five voltages of interest with five lines that look like this:

float sel1_v = inputs[IN_INPUT].getVoltage(sel1_c);
...
float sel5_v = inputs[IN_INPUT].getVoltage(sel5_c);

So that should store the five voltages you’re interested in, selected from the five channels you’re interested in, as local variables.

From there, you put them on the individual mono outputs, with five lines like:

outputs[OUT1_OUTPUT].setVoltage(sel1_v);
...
outputs[OUT5_OUTPUT].setVoltage(sel5_v);

and in the first five channels of the poly output with five more lines like:

outputs[MAIN_OUTPUT].setVoltage(sel1_v, 0);
...
outputs[MAIN_OUTPUT].setVoltage(sel5_v, 4);

You could do this all with arrays and loops, and you could also pack this down into one or two lines per channel by nesting calls, but we’re not going for efficiency or style when starting out. I’d get it working with simple repeated lines first and then refactor it (happy to help with that too when the time comes).

Hopefully I haven’t made a mistake writing that up–post back if it helps, or doesn’t?

2 Likes