# Help Request - New to Development for Rack

Greetings,

I am new to development in rack. I have a background in SuperCollider and Swift, but not too much in C++ or DSP for that matter but I’ve been working through some resources on my own and trying to see if I could Frankenstein some code together to make a module.

I cannot figure out why my module is not working and I would really appreciate it if anyone might have some time to shed a little light on it.

I used some of Andrew’s fundamental code and borrowed some from some other libraries, but my module is only outputting a constant 1V right now and I don’t know why.

Any help would be greatly appreciated! I’m trying my best to learn and I hate asking for this kind of thing. The end goal is making a variable feedback sine oscillator but I’m just making one without right now. I can easily write some code for the feedback portion, just sending it to the phase and limiting it to pi/2.

#include “plugin.hpp”

using simd::float_4;

template <int OVERSAMPLE, int QUALITY, typename T> struct VoltageControlledOscillator {

``````int channels = 0;

T phase = 0.f;
T freq = 0.f;

dsp::MinBlepGenerator<QUALITY, OVERSAMPLE, T> sinMinBlep;

T sinValue = 0.f;

void process(float deltaTime, T) {
T deltaPhase = simd::clamp(freq * deltaTime, 0.f, 0.35f);
phase += deltaPhase;
// Wrap phase
phase -= simd::floor(phase);
sinValue = sin(phase);
sinValue += sinMinBlep.process();
}

T sin(T phase) {
T v;
T halfPhase = (phase < 0.5f);
T x = phase - simd::ifelse(halfPhase, 0.25f, 0.75f);
v = 1.f - 16.f * simd::pow(x, 2);
v *= simd::ifelse(halfPhase, 1.f, -1.f);
return v;
}

T sin() {
return sinValue;
}

T light() {
return simd::sin(2 * T(M_PI) * phase);
}
``````

};

struct Boomerang : Module { enum ParamId { FREQ_PARAM, FEEDBACK_PARAM, FEEDBACK_CV_PARAM, FM_PARAM, PARAMS_LEN }; enum InputId { FM_INPUT, FB_INPUT, VOCT_INPUT, INPUTS_LEN }; enum OutputId { SIN_OUTPUT, OUTPUTS_LEN }; enum LightId { ENUMS(PHASE_LIGHT, 3), LIGHTS_LEN };

``````VoltageControlledOscillator<16, 16, float_4> oscillators[1];
dsp::ClockDivider lightDivider;

Boomerang() {
config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
configParam(FREQ_PARAM, -54.f, 54.f, 0.f, "Frequency", " Hz", dsp::FREQ_SEMITONE, dsp::FREQ_C4);
configParam(FEEDBACK_PARAM, 0.f, 1.f, 0.f, "Feedback", "%", 0.f, 100.f);
configParam(FEEDBACK_CV_PARAM, 0.f, 1.f, 0.f, "Feedback CV depth", "%", 0.f, 100.f);
configParam(FM_PARAM, 0.f, 1.f, 0.f, "Frequency modulation", "%", 0.f, 100.f);
configInput(FM_INPUT, "Frequency modulation");
configInput(FB_INPUT, "Feedback");
configInput(VOCT_INPUT, "1V/oct");
configOutput(SIN_OUTPUT, "Signal");

lightDivider.setDivision(16);
}

void process(const ProcessArgs& args) override {
float freqParam = params[FREQ_PARAM].getValue() / 12.f;
float fmParam = params[FM_PARAM].getValue();

int channels = std::max(inputs[VOCT_INPUT].getChannels(), 1);

for (int c = 0; c < channels; c += 1) {
auto& oscillator = oscillators[c / 1];
oscillator.channels = std::min(channels - c, 1);

//get frequency
float_4 pitch = freqParam + inputs[VOCT_INPUT].getPolyVoltageSimd<float_4>(c);
float_4 freq;
pitch += inputs[FM_INPUT].getPolyVoltageSimd<float_4>(c) * fmParam;
freq = dsp::FREQ_C4 * dsp::approxExp2_taylor5(pitch + 30.f) / std::pow(2.f, 30.f);
freq = clamp(freq, 0.f, args.sampleRate / 2.f);
oscillator.freq = freq;

if (outputs[SIN_OUTPUT].isConnected())
outputs[SIN_OUTPUT].setVoltageSimd(5.f * oscillator.sin(), c);
}

outputs[SIN_OUTPUT].setVoltage(channels);

// Light
if (lightDivider.process()) {
if (channels == 1) {
float lightValue = oscillators[0].light()[0];
lights[PHASE_LIGHT + 0].setSmoothBrightness(-lightValue, args.sampleTime * lightDivider.getDivision());
lights[PHASE_LIGHT + 1].setSmoothBrightness(lightValue, args.sampleTime * lightDivider.getDivision());
lights[PHASE_LIGHT + 2].setBrightness(0.f);
}
else {
lights[PHASE_LIGHT + 0].setBrightness(0.f);
lights[PHASE_LIGHT + 1].setBrightness(0.f);
lights[PHASE_LIGHT + 2].setBrightness(1.f);
}
}
}
``````

};

struct BoomerangWidget : ModuleWidget { BoomerangWidget(Boomerang* module) { setModule(module); setPanel(createPanel(asset::plugin(pluginInstance, “res/Boomerang.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(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));

//defaults not working, check coordinates in illustrator and use mm

}
``````

};

Model* modelBoomerang = createModel<Boomerang, BoomerangWidget>(“Boomerang”);

You are setting the output voltage to 1 via the channels variable.

2 Likes

Got it! Thanks for pointing me in the right direction!

1 Like

Ok once again apologies in advance for my ignorance. I changed this to

outputs[SIN_OUTPUT].setChannel(channels);

and I get an output of 0V. I’m guessing something I’m doing with managing polyphony is wrong and whatever I should have the output set to is either wrong or missing.

for (int c = 0; c < channels; c += 4) { auto& oscillator = oscillators[c / 4]; oscillator.channels = std::min(channels - c, 4);

which I assumed was due to the fact that there are four separate outputs on the fundamental VCO so I would need to change 4 to 1.

My understanding is that my signal output should be here:

``````    if (outputs[SIN_OUTPUT].isConnected())
``````
``````        outputs[SIN_OUTPUT].setVoltageSimd(5.f * oscillator.sin(), c);
``````

Could anyone kindly shed some light on where I’m going wrong here? I’m trying my best to put this together based on the knowledge of other languages I have but I am not sure where I’ve gone wrong. I’ve put the fundamental VCO and mine side by side many times and compared the bracket levels but I can’t seem to find what the inconsistency is.

The loop in the fundamental code is not for separate outputs, it’s for separate channels in one polyphonic output.

1 Like

Andrew has 4 there, not because there are 4 outputs, but because the oscillator can process 4 polyphonic channels at a time.

To do the work for all 16 polyphonic channels that might be engaged, he has an array of 4 oscillators.

setVoltageSimd sets the the channels c, c+1, c+2 and c+3 to the 4 values returned from the oscillator.sin function (multiplied by 5.f).

Gotcha! Thank you! I expect this should help me get everything up and running. I appreciate it very much

I really appreciate you guys! I’ve been referencing your code as well as David’s to make some other things or just try to figure out how everything is put together.

1 Like