Browse Source

SequentialSwitch1/2: Refactor. Add de-click option. When mixing mono and poly inputs, apply mono signal to all poly channels.

tags/v2.5.0
Andrew Belt 2 years ago
parent
commit
1b52924516
1 changed files with 125 additions and 74 deletions
  1. +125
    -74
      src/SequentialSwitch.cpp

+ 125
- 74
src/SequentialSwitch.cpp View File

@@ -29,6 +29,8 @@ struct SequentialSwitch : Module {
dsp::ClockDivider lightDivider;
dsp::SlewLimiter clickFilters[4];

bool declick = false;

SequentialSwitch() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configSwitch(STEPS_PARAM, 0.0, 2.0, 2.0, "Steps", {"2", "3", "4"});
@@ -56,7 +58,16 @@ struct SequentialSwitch : Module {
lightDivider.setDivision(512);
}

void onReset(const ResetEvent& e) override {
Module::onReset(e);
declick = false;
}

void process(const ProcessArgs& args) override {
using simd::float_4;

int length = 2 + int(params[STEPS_PARAM].getValue());

// Determine current index
if (clockTrigger.process(rescale(inputs[CLOCK_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) {
index++;
@@ -64,50 +75,72 @@ struct SequentialSwitch : Module {
if (resetTrigger.process(rescale(inputs[RESET_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) {
index = 0;
}
int length = 2 + (int) std::round(params[STEPS_PARAM].getValue());
if (index >= length)
index = 0;

// Use first input to get number of channels
int channels = std::max(inputs[IN_INPUTS + 0].getChannels(), 1);
// Get number of polyphony channels
int channels = 1;
for (int i = 0; i < INPUTS; i++) {
channels = std::max(channels, inputs[IN_INPUTS + i].getChannels());
}

if (INPUTS == 1) {
// <1, 4>
// Get input
float* in = inputs[IN_INPUTS + 0].getVoltages();
// 1 -> many

// Set output
for (int i = 0; i < OUTPUTS; i++) {
float gain = clickFilters[i].process(args.sampleTime, index == i);
outputs[OUT_OUTPUTS + i].setChannels(channels);
if (gain != 0.f) {
for (int c = 0; c < channels; c++) {
float out = in[c] * gain;
outputs[OUT_OUTPUTS + i].setVoltage(out, c);

if (declick) {
// Step click filter
float gain = clickFilters[i].process(args.sampleTime, i == index);
if (gain != 0.f) {
for (int c = 0; c < channels; c += 4) {
// Get input
float_4 in = inputs[IN_INPUTS + 0].template getVoltageSimd<float_4>(c);
// Set output
outputs[OUT_OUTPUTS + i].setVoltageSimd(in * gain, c);
}
}
else {
outputs[OUT_OUTPUTS + i].clearVoltages();
}
}
else {
outputs[OUT_OUTPUTS + i].clearVoltages();
// Set output
if (i == index)
outputs[OUT_OUTPUTS + i].writeVoltages(inputs[IN_INPUTS + 0].getVoltages());
else
outputs[OUT_OUTPUTS + i].clearVoltages();
}
}
}
else {
// <4, 1>
// Get input
float out[16] = {};
for (int i = 0; i < INPUTS; i++) {
float gain = clickFilters[i].process(args.sampleTime, index == i);
if (gain != 0.f) {
for (int c = 0; c < channels; c++) {
float in = inputs[IN_INPUTS + i].getVoltage(c);
out[c] += in * gain;
// many -> 1

outputs[OUT_OUTPUTS + 0].setChannels(channels);

if (declick) {
// Get mixed output
float_4 out[4] = {};
for (int i = 0; i < INPUTS; i++) {
float gain = clickFilters[i].process(args.sampleTime, i == index);
if (gain != 0.f) {
for (int c = 0; c < channels; c += 4) {
float_4 in = inputs[IN_INPUTS + i].template getPolyVoltageSimd<float_4>(c);
out[c / 4] += in * gain;
}
}
}
}

// Set output
outputs[OUT_OUTPUTS + 0].setChannels(channels);
outputs[OUT_OUTPUTS + 0].writeVoltages(out);
// Set output
for (int c = 0; c < channels; c += 4) {
outputs[OUT_OUTPUTS + 0].setVoltageSimd(out[c / 4], c);
}
}
else {
// Get and set output
outputs[OUT_OUTPUTS + 0].writeVoltages(inputs[IN_INPUTS + index].getVoltages());
}
}

// Set lights
@@ -125,79 +158,97 @@ struct SequentialSwitch : Module {
// If version <2.0 we should transform STEPS_PARAM
json_t* versionJ = json_object_get(rootJ, "version");
if (versionJ) {
std::string version = json_string_value(versionJ);
if (string::startsWith(version, "0.") || string::startsWith(version, "1.")) {
DEBUG("steps %f", params[STEPS_PARAM].getValue());
string::Version version(json_string_value(versionJ));
if (version < string::Version("2")) {
params[STEPS_PARAM].setValue(2 - params[STEPS_PARAM].getValue());
}
}
}

json_t* dataToJson() override {
json_t* rootJ = json_object();
json_object_set_new(rootJ, "declick", json_boolean(declick));
return rootJ;
}

void dataFromJson(json_t* rootJ) override {
json_t* declickJ = json_object_get(rootJ, "declick");
if (declickJ)
declick = json_boolean_value(declickJ);
// In <2.5.0, SequentialSwitch always de-clicked.
else
declick = true;
}
};


struct SequentialSwitch1Widget : ModuleWidget {
typedef SequentialSwitch<1, 4> TSequentialSwitch;
template <int INPUTS, int OUTPUTS>
struct SequentialSwitchWidget : ModuleWidget {
typedef SequentialSwitch<INPUTS, OUTPUTS> TSequentialSwitch;

SequentialSwitch1Widget(TSequentialSwitch* module) {
SequentialSwitchWidget(TSequentialSwitch* module) {
setModule(module);
setPanel(createPanel(asset::plugin(pluginInstance, "res/SequentialSwitch1.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)));
if (INPUTS == 1 && OUTPUTS == 4) {
setPanel(createPanel(asset::plugin(pluginInstance, "res/SequentialSwitch1.svg")));

addParam(createParamCentered<CKSSThreeHorizontal>(mm2px(Vec(7.555, 20.942)), module, TSequentialSwitch::STEPS_PARAM));
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)));

addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 33.831)), module, TSequentialSwitch::CLOCK_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 50.126)), module, TSequentialSwitch::RESET_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 66.379)), module, TSequentialSwitch::IN_INPUTS + 0));
addParam(createParamCentered<CKSSThreeHorizontal>(mm2px(Vec(7.555, 20.942)), module, TSequentialSwitch::STEPS_PARAM));

addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 82.607)), module, TSequentialSwitch::OUT_OUTPUTS + 0));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 92.767)), module, TSequentialSwitch::OUT_OUTPUTS + 1));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 102.927)), module, TSequentialSwitch::OUT_OUTPUTS + 2));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 113.087)), module, TSequentialSwitch::OUT_OUTPUTS + 3));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 33.831)), module, TSequentialSwitch::CLOCK_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 50.126)), module, TSequentialSwitch::RESET_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 66.379)), module, TSequentialSwitch::IN_INPUTS + 0));

addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 78.863)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 0));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 89.023)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 1));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 99.183)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 2));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 109.343)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 3));
}
};
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 82.607)), module, TSequentialSwitch::OUT_OUTPUTS + 0));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 92.767)), module, TSequentialSwitch::OUT_OUTPUTS + 1));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 102.927)), module, TSequentialSwitch::OUT_OUTPUTS + 2));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 113.087)), module, TSequentialSwitch::OUT_OUTPUTS + 3));

addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 78.863)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 0));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 89.023)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 1));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 99.183)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 2));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 109.343)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 3));
}

Model* modelSequentialSwitch1 = createModel<SequentialSwitch<1, 4>, SequentialSwitch1Widget>("SequentialSwitch1");
if (INPUTS == 4 && OUTPUTS == 1) {
setPanel(createPanel(asset::plugin(pluginInstance, "res/SequentialSwitch2.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)));

struct SequentialSwitch2Widget : ModuleWidget {
typedef SequentialSwitch<4, 1> TSequentialSwitch;
addParam(createParamCentered<CKSSThreeHorizontal>(mm2px(Vec(7.8, 20.942)), module, TSequentialSwitch::STEPS_PARAM));

SequentialSwitch2Widget(TSequentialSwitch* module) {
setModule(module);
setPanel(createPanel(asset::plugin(pluginInstance, "res/SequentialSwitch2.svg")));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 33.831)), module, TSequentialSwitch::CLOCK_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 50.126)), module, TSequentialSwitch::RESET_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 66.379)), module, TSequentialSwitch::IN_INPUTS + 0));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 76.539)), module, TSequentialSwitch::IN_INPUTS + 1));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 86.699)), module, TSequentialSwitch::IN_INPUTS + 2));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 96.859)), module, TSequentialSwitch::IN_INPUTS + 3));

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)));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.8, 113.115)), module, TSequentialSwitch::OUT_OUTPUTS + 0));

addParam(createParamCentered<CKSSThreeHorizontal>(mm2px(Vec(7.8, 20.942)), module, TSequentialSwitch::STEPS_PARAM));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 63.259)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 0));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 72.795)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 1));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 82.955)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 2));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 93.115)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 3));
}
}

addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 33.831)), module, TSequentialSwitch::CLOCK_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 50.126)), module, TSequentialSwitch::RESET_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 66.379)), module, TSequentialSwitch::IN_INPUTS + 0));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 76.539)), module, TSequentialSwitch::IN_INPUTS + 1));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 86.699)), module, TSequentialSwitch::IN_INPUTS + 2));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 96.859)), module, TSequentialSwitch::IN_INPUTS + 3));
void appendContextMenu(Menu* menu) override {
TSequentialSwitch* module = getModule<TSequentialSwitch>();

addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.8, 113.115)), module, TSequentialSwitch::OUT_OUTPUTS + 0));
menu->addChild(new MenuSeparator);

addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 63.259)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 0));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 72.795)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 1));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 82.955)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 2));
addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 93.115)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 3));
menu->addChild(createBoolPtrMenuItem("De-click", "", &module->declick));
}
};


Model* modelSequentialSwitch2 = createModel<SequentialSwitch<4, 1>, SequentialSwitch2Widget>("SequentialSwitch2");
Model* modelSequentialSwitch1 = createModel<SequentialSwitch<1, 4>, SequentialSwitchWidget<1, 4>>("SequentialSwitch1");
Model* modelSequentialSwitch2 = createModel<SequentialSwitch<4, 1>, SequentialSwitchWidget<4, 1>>("SequentialSwitch2");

Loading…
Cancel
Save