Cmp.cpp (5003B)
1 2 #include "Cmp.hpp" 3 4 void Cmp::reset() { 5 for (int i = 0; i < maxChannels; ++i) { 6 _thresholdState[i] = LOW; 7 _windowState[i] = LOW; 8 } 9 } 10 11 bool Cmp::active() { 12 return ( 13 outputs[GREATER_OUTPUT].isConnected() || 14 outputs[LESS_OUTPUT].isConnected() || 15 outputs[EQUAL_OUTPUT].isConnected() || 16 outputs[NOT_EQUAL_OUTPUT].isConnected() 17 ); 18 } 19 20 int Cmp::channels() { 21 return inputs[A_INPUT].getChannels(); 22 } 23 24 void Cmp::modulate() { 25 _highValue = 10.0f; 26 _lowValue = 0.0f; 27 if (params[OUTPUT_PARAM].getValue() > 0.5f) { 28 _highValue = 5.0f; 29 _lowValue = -5.0f; 30 } 31 } 32 33 void Cmp::modulateChannel(int c) { 34 float lag = params[LAG_PARAM].getValue(); 35 if (inputs[LAG_INPUT].isConnected()) { 36 lag *= clamp(inputs[LAG_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); 37 } 38 _lagInSamples[c] = lag * lag * APP->engine->getSampleRate(); 39 } 40 41 void Cmp::processChannel(const ProcessArgs& args, int c) { 42 float a = params[A_PARAM].getValue() * 10.0f; 43 if (inputs[A_INPUT].isConnected()) { 44 a = clamp(a + inputs[A_INPUT].getPolyVoltage(c), -12.0f, 12.0f); 45 } 46 47 float b = params[B_PARAM].getValue() * 10.0f; 48 if (inputs[B_INPUT].isConnected()) { 49 b = clamp(b + inputs[B_INPUT].getPolyVoltage(c), -12.0f, 12.0f); 50 } 51 52 float window = params[WINDOW_PARAM].getValue(); 53 if (inputs[WINDOW_INPUT].isConnected()) { 54 window *= clamp(inputs[WINDOW_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); 55 } 56 window *= 10.0f; 57 58 stepChannel( 59 c, 60 a >= b, 61 _thresholdState[c], 62 _thresholdLag[c], 63 outputs[GREATER_OUTPUT], 64 outputs[LESS_OUTPUT] 65 ); 66 stepChannel( 67 c, 68 fabsf(a - b) <= window, 69 _windowState[c], 70 _windowLag[c], 71 outputs[EQUAL_OUTPUT], 72 outputs[NOT_EQUAL_OUTPUT] 73 ); 74 } 75 76 void Cmp::stepChannel( 77 int c, 78 bool high, 79 State& state, 80 int& channelLag, 81 Output& highOutput, 82 Output& lowOutput 83 ) { 84 switch (state) { 85 case LOW: { 86 if (high) { 87 if (_lagInSamples[c] < 1) { 88 state = HIGH; 89 } 90 else { 91 state = LAG_HIGH; 92 channelLag = _lagInSamples[c]; 93 } 94 } 95 break; 96 } 97 case HIGH: { 98 if (!high) { 99 if (_lagInSamples[c] < 1) { 100 state = LOW; 101 } 102 else { 103 state = LAG_LOW; 104 channelLag = _lagInSamples[c]; 105 } 106 } 107 break; 108 } 109 case LAG_LOW: { 110 if (!high) { 111 --channelLag; 112 if (channelLag == 0) { 113 state = LOW; 114 } 115 } 116 else { 117 state = HIGH; 118 } 119 break; 120 } 121 case LAG_HIGH: { 122 if (high) { 123 --channelLag; 124 if (channelLag == 0) { 125 state = HIGH; 126 } 127 } 128 else { 129 state = LOW; 130 } 131 break; 132 } 133 }; 134 135 highOutput.setChannels(_channels); 136 lowOutput.setChannels(_channels); 137 switch (state) { 138 case LOW: 139 case LAG_HIGH: { 140 highOutput.setVoltage(_lowValue, c); 141 lowOutput.setVoltage(_highValue, c); 142 break; 143 } 144 case HIGH: 145 case LAG_LOW: { 146 highOutput.setVoltage(_highValue, c); 147 lowOutput.setVoltage(_lowValue, c); 148 break; 149 } 150 } 151 } 152 153 struct CmpWidget : BGModuleWidget { 154 static constexpr int hp = 6; 155 156 CmpWidget(Cmp* module) { 157 setModule(module); 158 box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); 159 setPanel(box.size, "Cmp"); 160 createScrews(); 161 162 // generated by svg_widgets.rb 163 auto aParamPosition = Vec(8.0, 46.0); 164 auto bParamPosition = Vec(53.0, 46.0); 165 auto windowParamPosition = Vec(8.0, 151.0); 166 auto lagParamPosition = Vec(53.0, 151.0); 167 auto outputParamPosition = Vec(25.5, 251.0); 168 169 auto aInputPosition = Vec(10.5, 87.0); 170 auto bInputPosition = Vec(55.5, 87.0); 171 auto windowInputPosition = Vec(10.5, 192.0); 172 auto lagInputPosition = Vec(55.5, 192.0); 173 174 auto greaterOutputPosition = Vec(16.0, 283.0); 175 auto lessOutputPosition = Vec(50.0, 283.0); 176 auto equalOutputPosition = Vec(16.0, 319.0); 177 auto notEqualOutputPosition = Vec(50.0, 319.0); 178 // end generated by svg_widgets.rb 179 180 addParam(createParam<Knob29>(aParamPosition, module, Cmp::A_PARAM)); 181 addParam(createParam<Knob29>(bParamPosition, module, Cmp::B_PARAM)); 182 addParam(createParam<Knob29>(windowParamPosition, module, Cmp::WINDOW_PARAM)); 183 addParam(createParam<Knob29>(lagParamPosition, module, Cmp::LAG_PARAM)); 184 { 185 auto w = createParam<Knob16>(outputParamPosition, module, Cmp::OUTPUT_PARAM); 186 auto k = dynamic_cast<SvgKnob*>(w); 187 k->minAngle = 3.0f * (M_PI / 8.0f); 188 k->maxAngle = 5.0f * (M_PI / 8.0f); 189 k->speed = 3.0; 190 addParam(w); 191 } 192 193 addInput(createInput<Port24>(aInputPosition, module, Cmp::A_INPUT)); 194 addInput(createInput<Port24>(bInputPosition, module, Cmp::B_INPUT)); 195 addInput(createInput<Port24>(windowInputPosition, module, Cmp::WINDOW_INPUT)); 196 addInput(createInput<Port24>(lagInputPosition, module, Cmp::LAG_INPUT)); 197 198 addOutput(createOutput<Port24>(greaterOutputPosition, module, Cmp::GREATER_OUTPUT)); 199 addOutput(createOutput<Port24>(lessOutputPosition, module, Cmp::LESS_OUTPUT)); 200 addOutput(createOutput<Port24>(equalOutputPosition, module, Cmp::EQUAL_OUTPUT)); 201 addOutput(createOutput<Port24>(notEqualOutputPosition, module, Cmp::NOT_EQUAL_OUTPUT)); 202 } 203 }; 204 205 Model* modelCmp = bogaudio::createModel<Cmp, CmpWidget>("Bogaudio-Cmp", "CMP", "Window comparator", "Logic", "Polyphonic");