Mix4.cpp (10346B)
1 2 #include "Mix4.hpp" 3 4 #define POLY_OFFSET "poly_channel_offset" 5 6 void Mix4::onRandomize(const RandomizeEvent& e) { 7 Module::onRandomize(e); 8 for (int i = 0; i < 4; ++i) { 9 getParamQuantity(MUTE1_PARAM + 3*i)->setValue(random::uniform() > 0.5f); 10 } 11 } 12 13 json_t* Mix4::saveToJson(json_t* root) { 14 root = DimmableMixerModule::saveToJson(root); 15 json_object_set_new(root, POLY_OFFSET, json_integer(_polyChannelOffset)); 16 return root; 17 } 18 19 void Mix4::loadFromJson(json_t* root) { 20 DimmableMixerModule::loadFromJson(root); 21 json_t* o = json_object_get(root, POLY_OFFSET); 22 if (o) { 23 _polyChannelOffset = json_integer_value(o); 24 } 25 } 26 27 void Mix4::sampleRateChange() { 28 float sr = APP->engine->getSampleRate(); 29 for (int i = 0; i < 4; ++i) { 30 _channels[i]->setSampleRate(sr); 31 _panSLs[i].setParams(sr, MIXER_PAN_SLEW_MS, 2.0f); 32 } 33 _slewLimiter.setParams(sr, MixerChannel::levelSlewTimeMS, MixerChannel::maxDecibels - MixerChannel::minDecibels); 34 _levelCVSL.setParams(sr, MixerChannel::levelSlewTimeMS, 1.0f); 35 _rms.setSampleRate(sr); 36 } 37 38 void Mix4::processAll(const ProcessArgs& args) { 39 Mix4ExpanderMessage* toExp = &_dummyExpanderMessage; 40 Mix4ExpanderMessage* fromExp = &_dummyExpanderMessage; 41 if (expanderConnected()) { 42 toExp = toExpander(); 43 fromExp = fromExpander(); 44 } 45 46 if (!( 47 inputs[IN1_INPUT].isConnected() || 48 inputs[IN2_INPUT].isConnected() || 49 inputs[IN3_INPUT].isConnected() || 50 inputs[IN4_INPUT].isConnected() 51 )) { 52 if (_wasActive > 0) { 53 --_wasActive; 54 for (int i = 0; i < 4; ++i) { 55 _channels[i]->reset(); 56 toExp->active[i] = false; 57 } 58 _rmsLevel = 0.0f; 59 outputs[L_OUTPUT].setVoltage(0.0f); 60 outputs[R_OUTPUT].setVoltage(0.0f); 61 } 62 return; 63 } 64 _wasActive = 2; 65 66 bool solo = 67 params[MUTE1_PARAM].getValue() > 1.5f || 68 params[MUTE2_PARAM].getValue() > 1.5f || 69 params[MUTE3_PARAM].getValue() > 1.5f || 70 params[MUTE4_PARAM].getValue() > 1.5f; 71 72 { 73 float sample = 0.0f; 74 if (_polyChannelOffset >= 0) { 75 sample = inputs[IN1_INPUT].getPolyVoltage(_polyChannelOffset); 76 } else { 77 sample = inputs[IN1_INPUT].getVoltageSum(); 78 } 79 _channels[0]->next(sample, solo, 0, _linearCV); 80 toExp->preFader[0] = sample; 81 toExp->active[0] = inputs[IN1_INPUT].isConnected(); 82 83 for (int i = 1; i < 4; ++i) { 84 float sample = 0.0f; 85 if (inputs[IN1_INPUT + 3 * i].isConnected()) { 86 sample = inputs[IN1_INPUT + 3 * i].getVoltageSum(); 87 _channels[i]->next(sample, solo, 0, _linearCV); 88 _channelActive[i] = true; 89 } 90 else if (_polyChannelOffset >= 0) { 91 sample = inputs[IN1_INPUT].getPolyVoltage(_polyChannelOffset + i); 92 _channels[i]->next(sample, solo, 0, _linearCV); 93 _channelActive[i] = true; 94 } 95 else if (_channelActive[i]) { 96 _channels[i]->reset(); 97 _channelActive[i] = false; 98 } 99 toExp->preFader[i] = sample; 100 toExp->active[i] = _channelActive[i]; 101 } 102 } 103 104 float levelCV = 1.0f; 105 if (inputs[MIX_CV_INPUT].isConnected()) { 106 levelCV = clamp(inputs[MIX_CV_INPUT].getVoltage() / 10.0f, 0.0f, 1.0f); 107 } 108 float level = Amplifier::minDecibels; 109 if (params[MIX_MUTE_PARAM].getValue() < 0.5f) { 110 level = params[MIX_PARAM].getValue(); 111 if (!_linearCV) { 112 level *= levelCV; 113 } 114 level *= MixerChannel::maxDecibels - MixerChannel::minDecibels; 115 level += MixerChannel::minDecibels; 116 if (params[MIX_DIM_PARAM].getValue() > 0.5f) { 117 level = std::max(Amplifier::minDecibels, level - _dimDb); 118 } 119 } 120 _amplifier.setLevel(_slewLimiter.next(level)); 121 levelCV = _levelCVSL.next(levelCV); 122 123 float outs[4]; 124 for (int i = 0; i < 4; ++i) { 125 toExp->postFader[i] = outs[i] = _channels[i]->out; 126 } 127 128 float mono = 0.0f; 129 float left = 0.0f; 130 float right = 0.0f; 131 if (expanderConnected()) { 132 mono += fromExp->returnA[0] + fromExp->returnB[0]; 133 left += fromExp->returnA[0] + fromExp->returnB[0]; 134 right += fromExp->returnA[1] + fromExp->returnB[1]; 135 std::copy(fromExp->postEQ, fromExp->postEQ + 4, outs); 136 } 137 138 for (int i = 0; i < 4; ++i) { 139 mono += outs[i]; 140 } 141 mono = _amplifier.next(mono); 142 if (_linearCV) { 143 mono *= levelCV; 144 } 145 mono = _saturator.next(mono); 146 _rmsLevel = _rms.next(mono) / 5.0f; 147 148 if (outputs[L_OUTPUT].isConnected() && outputs[R_OUTPUT].isConnected()) { 149 for (int i = 0; i < 4; ++i) { 150 float pan = clamp(params[PAN1_PARAM + 3 * i].getValue(), -1.0f, 1.0f); 151 if (inputs[PAN1_INPUT + 3 * i].isConnected()) { 152 pan *= clamp(inputs[PAN1_INPUT + 3 * i].getVoltage() / 5.0f, -1.0f, 1.0f); 153 } 154 _panners[i].setPan(_panSLs[i].next(pan)); 155 float l, r; 156 _panners[i].next(outs[i], l, r); 157 left += l; 158 right += r; 159 } 160 161 left = _amplifier.next(left); 162 if (_linearCV) { 163 left *= levelCV; 164 } 165 left = _saturator.next(left); 166 outputs[L_OUTPUT].setVoltage(left); 167 168 right = _amplifier.next(right); 169 if (_linearCV) { 170 right *= levelCV; 171 } 172 right = _saturator.next(right); 173 outputs[R_OUTPUT].setVoltage(right); 174 } 175 else { 176 outputs[L_OUTPUT].setVoltage(mono); 177 outputs[R_OUTPUT].setVoltage(mono); 178 } 179 } 180 181 struct Mix4Widget : DimmableMixerWidget { 182 static constexpr int hp = 15; 183 184 Mix4Widget(Mix4* module) { 185 setModule(module); 186 box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); 187 setPanel(box.size, "Mix4"); 188 createScrews(); 189 190 // generated by svg_widgets.rb 191 auto level1ParamPosition = Vec(17.5, 32.0); 192 auto mute1ParamPosition = Vec(17.5, 185.0); 193 auto pan1ParamPosition = Vec(18.5, 223.0); 194 auto level2ParamPosition = Vec(60.5, 32.0); 195 auto mute2ParamPosition = Vec(60.5, 185.0); 196 auto pan2ParamPosition = Vec(61.5, 223.0); 197 auto level3ParamPosition = Vec(103.5, 32.0); 198 auto mute3ParamPosition = Vec(103.5, 185.0); 199 auto pan3ParamPosition = Vec(104.5, 223.0); 200 auto level4ParamPosition = Vec(146.5, 32.0); 201 auto mute4ParamPosition = Vec(146.5, 185.0); 202 auto pan4ParamPosition = Vec(147.5, 223.0); 203 auto mixParamPosition = Vec(189.5, 32.0); 204 auto mixMuteParamPosition = Vec(189.5, 185.0); 205 auto mixDimParamPosition = Vec(189.5, 218.0); 206 207 auto cv1InputPosition = Vec(14.5, 255.0); 208 auto pan1InputPosition = Vec(14.5, 290.0); 209 auto in1InputPosition = Vec(14.5, 325.0); 210 auto cv2InputPosition = Vec(57.5, 255.0); 211 auto pan2InputPosition = Vec(57.5, 290.0); 212 auto in2InputPosition = Vec(57.5, 325.0); 213 auto cv3InputPosition = Vec(100.5, 255.0); 214 auto pan3InputPosition = Vec(100.5, 290.0); 215 auto in3InputPosition = Vec(100.5, 325.0); 216 auto cv4InputPosition = Vec(143.5, 255.0); 217 auto pan4InputPosition = Vec(143.5, 290.0); 218 auto in4InputPosition = Vec(143.5, 325.0); 219 auto mixCvInputPosition = Vec(186.5, 252.0); 220 221 auto lOutputPosition = Vec(186.5, 290.0); 222 auto rOutputPosition = Vec(186.5, 325.0); 223 // end generated by svg_widgets.rb 224 225 addSlider(level1ParamPosition, module, Mix4::LEVEL1_PARAM, module ? &module->_channels[0]->rms : NULL); 226 addParam(createParam<Knob16>(pan1ParamPosition, module, Mix4::PAN1_PARAM)); 227 addParam(createParam<SoloMuteButton>(mute1ParamPosition, module, Mix4::MUTE1_PARAM)); 228 addSlider(level2ParamPosition, module, Mix4::LEVEL2_PARAM, module ? &module->_channels[1]->rms : NULL); 229 addParam(createParam<Knob16>(pan2ParamPosition, module, Mix4::PAN2_PARAM)); 230 addParam(createParam<SoloMuteButton>(mute2ParamPosition, module, Mix4::MUTE2_PARAM)); 231 addSlider(level3ParamPosition, module, Mix4::LEVEL3_PARAM, module ? &module->_channels[2]->rms : NULL); 232 addParam(createParam<Knob16>(pan3ParamPosition, module, Mix4::PAN3_PARAM)); 233 addParam(createParam<SoloMuteButton>(mute3ParamPosition, module, Mix4::MUTE3_PARAM)); 234 addSlider(level4ParamPosition, module, Mix4::LEVEL4_PARAM, module ? &module->_channels[3]->rms : NULL); 235 addParam(createParam<Knob16>(pan4ParamPosition, module, Mix4::PAN4_PARAM)); 236 addParam(createParam<SoloMuteButton>(mute4ParamPosition, module, Mix4::MUTE4_PARAM)); 237 addSlider(mixParamPosition, module, Mix4::MIX_PARAM, module ? &module->_rmsLevel : NULL); 238 addParam(createParam<MuteButton>(mixMuteParamPosition, module, Mix4::MIX_MUTE_PARAM)); 239 addParam(createParam<MuteButton>(mixDimParamPosition, module, Mix4::MIX_DIM_PARAM)); 240 241 addInput(createInput<Port24>(cv1InputPosition, module, Mix4::CV1_INPUT)); 242 addInput(createInput<Port24>(pan1InputPosition, module, Mix4::PAN1_INPUT)); 243 addInput(createInput<Port24>(in1InputPosition, module, Mix4::IN1_INPUT)); 244 addInput(createInput<Port24>(cv2InputPosition, module, Mix4::CV2_INPUT)); 245 addInput(createInput<Port24>(pan2InputPosition, module, Mix4::PAN2_INPUT)); 246 addInput(createInput<Port24>(in2InputPosition, module, Mix4::IN2_INPUT)); 247 addInput(createInput<Port24>(cv3InputPosition, module, Mix4::CV3_INPUT)); 248 addInput(createInput<Port24>(pan3InputPosition, module, Mix4::PAN3_INPUT)); 249 addInput(createInput<Port24>(in3InputPosition, module, Mix4::IN3_INPUT)); 250 addInput(createInput<Port24>(cv4InputPosition, module, Mix4::CV4_INPUT)); 251 addInput(createInput<Port24>(pan4InputPosition, module, Mix4::PAN4_INPUT)); 252 addInput(createInput<Port24>(in4InputPosition, module, Mix4::IN4_INPUT)); 253 addInput(createInput<Port24>(mixCvInputPosition, module, Mix4::MIX_CV_INPUT)); 254 255 addOutput(createOutput<Port24>(lOutputPosition, module, Mix4::L_OUTPUT)); 256 addOutput(createOutput<Port24>(rOutputPosition, module, Mix4::R_OUTPUT)); 257 } 258 259 void addSlider(Vec position, Mix4* module, int id, float* rms) { 260 auto slider = createParam<VUSlider151>(position, module, id); 261 if (rms) { 262 dynamic_cast<VUSlider*>(slider)->setVULevel(rms); 263 } 264 addParam(slider); 265 } 266 267 void contextMenu(Menu* menu) override { 268 DimmableMixerWidget::contextMenu(menu); 269 auto m = dynamic_cast<Mix4*>(module); 270 assert(m); 271 OptionsMenuItem* mi = new OptionsMenuItem("Input 1 poly spread"); 272 mi->addItem(OptionMenuItem("None", [m]() { return m->_polyChannelOffset == -1; }, [m]() { m->_polyChannelOffset = -1; })); 273 mi->addItem(OptionMenuItem("Channels 1-4", [m]() { return m->_polyChannelOffset == 0; }, [m]() { m->_polyChannelOffset = 0; })); 274 mi->addItem(OptionMenuItem("Channels 5-8", [m]() { return m->_polyChannelOffset == 4; }, [m]() { m->_polyChannelOffset = 4; })); 275 mi->addItem(OptionMenuItem("Channels 9-12", [m]() { return m->_polyChannelOffset == 8; }, [m]() { m->_polyChannelOffset = 8; })); 276 mi->addItem(OptionMenuItem("Channels 13-16", [m]() { return m->_polyChannelOffset == 12; }, [m]() { m->_polyChannelOffset = 12; })); 277 OptionsMenuItem::addToMenu(mi, menu); 278 } 279 }; 280 281 Model* modelMix4 = bogaudio::createModel<Mix4, Mix4Widget>("Bogaudio-Mix4", "MIX4", "4-channel mixer and panner", "Mixer", "Panning");