1+ #include " plugin.hpp"
2+
3+ using namespace simd ;
4+
5+ struct ABC : Module {
6+ enum ParamId {
7+ A_PARAM,
8+ B_PARAM,
9+ C_PARAM,
10+ D_PARAM,
11+ E_PARAM,
12+ F_PARAM,
13+ PARAMS_LEN
14+ };
15+ enum InputId {
16+ A_INPUT,
17+ B_INPUT,
18+ C_INPUT,
19+ D_INPUT,
20+ E_INPUT,
21+ F_INPUT,
22+ INPUTS_LEN
23+ };
24+ enum OutputId {
25+ ABC_OUTPUT,
26+ DEF_OUTPUT,
27+ OUTPUTS_LEN
28+ };
29+ enum LightId {
30+ LIGHTS_LEN
31+ };
32+
33+ dsp::TBiquadFilter<float_4> dcBlockFilter[2 ];
34+ bool dcBlockEnabled = true ;
35+
36+ ABC () {
37+ config (PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
38+ configParam (A_PARAM, 0 .f , 1 .f , 1 .f , " Channel A Gain" );
39+ configParam (B_PARAM, 0 .f , 1 .f , 1 .f , " Channel B Gain" );
40+ configParam (C_PARAM, 0 .f , 1 .f , 1 .f , " Channel C Gain" );
41+ configParam (D_PARAM, 0 .f , 1 .f , 1 .f , " Channel D Gain" );
42+ configParam (E_PARAM, 0 .f , 1 .f , 1 .f , " Channel E Gain" );
43+ configParam (F_PARAM, 0 .f , 1 .f , 1 .f , " Channel F Gain" );
44+ configInput (A_INPUT, " Channel A" );
45+ configInput (B_INPUT, " Channel B" );
46+ configInput (C_INPUT, " Channel C" );
47+ configInput (D_INPUT, " Channel D" );
48+ configInput (E_INPUT, " Channel E" );
49+ configInput (F_INPUT, " Channel F" );
50+ configOutput (DEF_OUTPUT, " Sum of D, E, F (and A, B, C if not connected)" );
51+ configOutput (ABC_OUTPUT, " Sum of A, B, C" );
52+ }
53+
54+ void onSampleRateChange () override {
55+ float sampleRate = APP->engine ->getSampleRate ();
56+
57+ // this doesn't work with floats below ~0.0004
58+ const float fc = std::max (0.0004 , (30 . / sampleRate));
59+ dcBlockFilter[0 ].setParameters (dsp::TBiquadFilter<float_4>::HIGHPASS, fc, 0.707 , 1 .0f );
60+ dcBlockFilter[1 ].setParameters (dsp::TBiquadFilter<float_4>::HIGHPASS, fc, 0.707 , 1 .0f );
61+
62+ dcBlockFilter[0 ].reset ();
63+ dcBlockFilter[1 ].reset ();
64+ }
65+
66+ void process (const ProcessArgs &args) override {
67+
68+ float_4 abcInputs = float_4 (inputs[A_INPUT].getVoltage () * params[A_PARAM].getValue (),
69+ inputs[B_INPUT].getVoltage () * params[B_PARAM].getValue (),
70+ inputs[C_INPUT].getVoltage () * params[C_PARAM].getValue (), 0 .f );
71+
72+ float_4 defInputs = float_4 (inputs[D_INPUT].getVoltage () * params[D_PARAM].getValue (),
73+ inputs[E_INPUT].getVoltage () * params[E_PARAM].getValue (),
74+ inputs[F_INPUT].getVoltage () * params[F_PARAM].getValue (), 0 .f );
75+
76+ if (dcBlockEnabled) {
77+ abcInputs = dcBlockFilter[0 ].process (abcInputs);
78+ defInputs = dcBlockFilter[1 ].process (defInputs);
79+ }
80+
81+ float abcSum = abcInputs[0 ] + abcInputs[1 ] + abcInputs[2 ];
82+ float defSum = defInputs[0 ] + defInputs[1 ] + defInputs[2 ];
83+ if (outputs[ABC_OUTPUT].isConnected ()) {
84+ outputs[ABC_OUTPUT].setVoltage (abcSum);
85+ outputs[DEF_OUTPUT].setVoltage (defSum);
86+
87+ } else if (outputs[DEF_OUTPUT].isConnected ()) {
88+ outputs[DEF_OUTPUT].setVoltage (abcSum + defSum);
89+ }
90+ }
91+
92+ json_t *dataToJson () override {
93+ json_t *rootJ = json_object ();
94+ json_object_set_new (rootJ, " dcBlockEnabled" , json_boolean (dcBlockEnabled));
95+ return rootJ;
96+ }
97+
98+ void dataFromJson (json_t *rootJ) override {
99+ json_t *dcBlockEnabledJ = json_object_get (rootJ, " dcBlockEnabled" );
100+ if (dcBlockEnabledJ) {
101+ dcBlockEnabled = json_is_true (dcBlockEnabledJ);
102+ }
103+ }
104+ };
105+
106+ struct ABCWidget : ModuleWidget {
107+ ABCWidget (ABC *module ) {
108+ setModule (module );
109+ setPanel (createPanel (asset::plugin (pluginInstance, " res/panels/ABC.svg" )));
110+
111+ addChild (createWidget<ScrewBlack>(Vec (box.size .x - 2 * RACK_GRID_WIDTH, 0 )));
112+ addChild (createWidget<ScrewBlack>(Vec (box.size .x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
113+
114+ addParam (createParamCentered<Trimpot>(mm2px (Vec (6.791 , 25.42 )), module , ABC::A_PARAM));
115+ addParam (createParamCentered<Trimpot>(mm2px (Vec (6.791 , 44.461 )), module , ABC::B_PARAM));
116+ addParam (createParamCentered<Trimpot>(mm2px (Vec (6.791 , 63.527 )), module , ABC::C_PARAM));
117+ addParam (createParamCentered<Trimpot>(mm2px (Vec (18.203 , 15.861 )), module , ABC::D_PARAM));
118+ addParam (createParamCentered<Trimpot>(mm2px (Vec (18.216 , 34.962 )), module , ABC::E_PARAM));
119+ addParam (createParamCentered<Trimpot>(mm2px (Vec (18.216 , 53.987 )), module , ABC::F_PARAM));
120+
121+ addInput (createInputCentered<PJ301MPort>(mm2px (Vec (18.207 , 73.181 )), module , ABC::D_INPUT));
122+ addInput (createInputCentered<PJ301MPort>(mm2px (Vec (6.809 , 78.25 )), module , ABC::A_INPUT));
123+ addInput (createInputCentered<PJ301MPort>(mm2px (Vec (18.207 , 84.6 )), module , ABC::E_INPUT));
124+ addInput (createInputCentered<PJ301MPort>(mm2px (Vec (6.809 , 89.681 )), module , ABC::B_INPUT));
125+ addInput (createInputCentered<PJ301MPort>(mm2px (Vec (18.207 , 96.02 )), module , ABC::F_INPUT));
126+ addInput (createInputCentered<PJ301MPort>(mm2px (Vec (6.809 , 101.1 )), module , ABC::C_INPUT));
127+
128+ addOutput (createOutputCentered<PJ301MPort>(mm2px (Vec (18.207 , 107.45 )), module , ABC::DEF_OUTPUT));
129+ addOutput (createOutputCentered<PJ301MPort>(mm2px (Vec (6.798 , 112.53 )), module , ABC::ABC_OUTPUT));
130+ }
131+
132+ void appendContextMenu (Menu *menu) override {
133+ ABC *abcModule = dynamic_cast <ABC *>(module );
134+ assert (abcModule);
135+
136+ menu->addChild (new MenuSeparator ());
137+
138+ menu->addChild (createBoolPtrMenuItem (" DC Block" , " " , &abcModule->dcBlockEnabled ));
139+ }
140+ };
141+
142+ Model *modelABC = createModel<ABC, ABCWidget>(" ABC" );
0 commit comments