Mix8.cpp (13512B)
1 2 #include "Mix8.hpp" 3 4 #define POLY_OFFSET "poly_channel_offset" 5 6 void Mix8::onRandomize(const RandomizeEvent& e) { 7 Module::onRandomize(e); 8 for (int i = 0; i < 8; ++i) { 9 getParamQuantity(MUTE1_PARAM + 3*i)->setValue(random::uniform() > 0.5f); 10 } 11 } 12 13 json_t* Mix8::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 Mix8::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 Mix8::sampleRateChange() { 28 float sr = APP->engine->getSampleRate(); 29 for (int i = 0; i < 8; ++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 Mix8::processAll(const ProcessArgs& args) { 39 Mix8ExpanderMessage* toExp = &_dummyExpanderMessage; 40 Mix8ExpanderMessage* 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 inputs[IN5_INPUT].isConnected() || 52 inputs[IN6_INPUT].isConnected() || 53 inputs[IN7_INPUT].isConnected() || 54 inputs[IN8_INPUT].isConnected() 55 )) { 56 if (_wasActive > 0) { 57 --_wasActive; 58 for (int i = 0; i < 8; ++i) { 59 _channels[i]->reset(); 60 toExp->active[i] = false; 61 } 62 _rmsLevel = 0.0f; 63 outputs[L_OUTPUT].setVoltage(0.0f); 64 outputs[R_OUTPUT].setVoltage(0.0f); 65 } 66 return; 67 } 68 _wasActive = 2; 69 70 bool solo = 71 params[MUTE1_PARAM].getValue() > 1.5f || 72 params[MUTE2_PARAM].getValue() > 1.5f || 73 params[MUTE3_PARAM].getValue() > 1.5f || 74 params[MUTE4_PARAM].getValue() > 1.5f || 75 params[MUTE5_PARAM].getValue() > 1.5f || 76 params[MUTE6_PARAM].getValue() > 1.5f || 77 params[MUTE7_PARAM].getValue() > 1.5f || 78 params[MUTE8_PARAM].getValue() > 1.5f; 79 80 { 81 float sample = 0.0f; 82 if (_polyChannelOffset >= 0) { 83 sample = inputs[IN1_INPUT].getPolyVoltage(_polyChannelOffset); 84 } else { 85 sample = inputs[IN1_INPUT].getVoltageSum(); 86 } 87 _channels[0]->next(sample, solo, 0, _linearCV); 88 toExp->preFader[0] = sample; 89 toExp->active[0] = inputs[IN1_INPUT].isConnected(); 90 91 for (int i = 1; i < 8; ++i) { 92 float sample = 0.0f; 93 if (inputs[IN1_INPUT + 3 * i].isConnected()) { 94 sample = inputs[IN1_INPUT + 3 * i].getVoltageSum(); 95 _channels[i]->next(sample, solo, 0, _linearCV); 96 _channelActive[i] = true; 97 } 98 else if (_polyChannelOffset >= 0) { 99 sample = inputs[IN1_INPUT].getPolyVoltage(_polyChannelOffset + i); 100 _channels[i]->next(sample, solo, 0, _linearCV); 101 _channelActive[i] = true; 102 } 103 else if (_channelActive[i]) { 104 _channels[i]->reset(); 105 _channelActive[i] = false; 106 } 107 toExp->preFader[i] = sample; 108 toExp->active[i] = _channelActive[i]; 109 } 110 } 111 112 float levelCV = 1.0f; 113 if (inputs[MIX_CV_INPUT].isConnected()) { 114 levelCV = clamp(inputs[MIX_CV_INPUT].getVoltage() / 10.0f, 0.0f, 1.0f); 115 } 116 float level = Amplifier::minDecibels; 117 if (params[MIX_MUTE_PARAM].getValue() < 0.5f) { 118 level = params[MIX_PARAM].getValue(); 119 if (!_linearCV) { 120 level *= levelCV; 121 } 122 level *= MixerChannel::maxDecibels - MixerChannel::minDecibels; 123 level += MixerChannel::minDecibels; 124 if (params[MIX_DIM_PARAM].getValue() > 0.5f) { 125 level = std::max(Amplifier::minDecibels, level - _dimDb); 126 } 127 } 128 _amplifier.setLevel(_slewLimiter.next(level)); 129 levelCV = _levelCVSL.next(levelCV); 130 131 float outs[8]; 132 for (int i = 0; i < 8; ++i) { 133 toExp->postFader[i] = outs[i] = _channels[i]->out; 134 } 135 136 float mono = 0.0f; 137 float left = 0.0f; 138 float right = 0.0f; 139 if (expanderConnected()) { 140 mono += fromExp->returnA[0] + fromExp->returnB[0]; 141 left += fromExp->returnA[0] + fromExp->returnB[0]; 142 right += fromExp->returnA[1] + fromExp->returnB[1]; 143 std::copy(fromExp->postEQ, fromExp->postEQ + 8, outs); 144 } 145 146 for (int i = 0; i < 8; ++i) { 147 mono += outs[i]; 148 } 149 mono = _amplifier.next(mono); 150 if (_linearCV) { 151 mono *= levelCV; 152 } 153 mono = _saturator.next(mono); 154 _rmsLevel = _rms.next(mono) / 5.0f; 155 156 if (outputs[L_OUTPUT].isConnected() && outputs[R_OUTPUT].isConnected()) { 157 for (int i = 0; i < 8; ++i) { 158 float pan = clamp(params[PAN1_PARAM + 3 * i].getValue(), -1.0f, 1.0f); 159 if (inputs[PAN1_INPUT + 3 * i].isConnected()) { 160 pan *= clamp(inputs[PAN1_INPUT + 3 * i].getVoltage() / 5.0f, -1.0f, 1.0f); 161 } 162 _panners[i].setPan(_panSLs[i].next(pan)); 163 float l, r; 164 _panners[i].next(outs[i], l, r); 165 left += l; 166 right += r; 167 } 168 169 left = _amplifier.next(left); 170 if (_linearCV) { 171 left *= levelCV; 172 } 173 left = _saturator.next(left); 174 outputs[L_OUTPUT].setVoltage(left); 175 176 right = _amplifier.next(right); 177 if (_linearCV) { 178 right *= levelCV; 179 } 180 right = _saturator.next(right); 181 outputs[R_OUTPUT].setVoltage(right); 182 } 183 else { 184 outputs[L_OUTPUT].setVoltage(mono); 185 outputs[R_OUTPUT].setVoltage(mono); 186 } 187 } 188 189 struct Mix8Widget : DimmableMixerWidget { 190 static constexpr int hp = 27; 191 192 Mix8Widget(Mix8* module) { 193 setModule(module); 194 box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); 195 setPanel(box.size, "Mix8"); 196 createScrews(); 197 198 // generated by svg_widgets.rb 199 auto level1ParamPosition = Vec(17.5, 32.0); 200 auto mute1ParamPosition = Vec(17.5, 185.0); 201 auto pan1ParamPosition = Vec(18.5, 223.0); 202 auto level2ParamPosition = Vec(61.5, 32.0); 203 auto mute2ParamPosition = Vec(61.5, 185.0); 204 auto pan2ParamPosition = Vec(62.5, 223.0); 205 auto level3ParamPosition = Vec(105.5, 32.0); 206 auto mute3ParamPosition = Vec(105.5, 185.0); 207 auto pan3ParamPosition = Vec(106.5, 223.0); 208 auto level4ParamPosition = Vec(149.5, 32.0); 209 auto mute4ParamPosition = Vec(149.5, 185.0); 210 auto pan4ParamPosition = Vec(150.5, 223.0); 211 auto level5ParamPosition = Vec(193.5, 32.0); 212 auto mute5ParamPosition = Vec(193.5, 185.0); 213 auto pan5ParamPosition = Vec(194.5, 223.0); 214 auto level6ParamPosition = Vec(237.5, 32.0); 215 auto mute6ParamPosition = Vec(237.5, 185.0); 216 auto pan6ParamPosition = Vec(238.5, 223.0); 217 auto level7ParamPosition = Vec(281.5, 32.0); 218 auto mute7ParamPosition = Vec(281.5, 185.0); 219 auto pan7ParamPosition = Vec(282.5, 223.0); 220 auto level8ParamPosition = Vec(325.5, 32.0); 221 auto mute8ParamPosition = Vec(325.5, 185.0); 222 auto pan8ParamPosition = Vec(326.5, 223.0); 223 auto mixParamPosition = Vec(369.5, 32.0); 224 auto mixMuteParamPosition = Vec(369.5, 185.0); 225 auto mixDimParamPosition = Vec(369.5, 218.0); 226 227 auto cv1InputPosition = Vec(14.5, 255.0); 228 auto pan1InputPosition = Vec(14.5, 290.0); 229 auto in1InputPosition = Vec(14.5, 325.0); 230 auto cv2InputPosition = Vec(58.5, 255.0); 231 auto pan2InputPosition = Vec(58.5, 290.0); 232 auto in2InputPosition = Vec(58.5, 325.0); 233 auto cv3InputPosition = Vec(102.5, 255.0); 234 auto pan3InputPosition = Vec(102.5, 290.0); 235 auto in3InputPosition = Vec(102.5, 325.0); 236 auto cv4InputPosition = Vec(146.5, 255.0); 237 auto pan4InputPosition = Vec(146.5, 290.0); 238 auto in4InputPosition = Vec(146.5, 325.0); 239 auto cv5InputPosition = Vec(190.5, 255.0); 240 auto pan5InputPosition = Vec(190.5, 290.0); 241 auto in5InputPosition = Vec(190.5, 325.0); 242 auto cv6InputPosition = Vec(234.5, 255.0); 243 auto pan6InputPosition = Vec(234.5, 290.0); 244 auto in6InputPosition = Vec(234.5, 325.0); 245 auto cv7InputPosition = Vec(278.5, 255.0); 246 auto pan7InputPosition = Vec(278.5, 290.0); 247 auto in7InputPosition = Vec(278.5, 325.0); 248 auto cv8InputPosition = Vec(322.5, 255.0); 249 auto pan8InputPosition = Vec(322.5, 290.0); 250 auto in8InputPosition = Vec(322.5, 325.0); 251 auto mixCvInputPosition = Vec(366.5, 252.0); 252 253 auto lOutputPosition = Vec(366.5, 290.0); 254 auto rOutputPosition = Vec(366.5, 325.0); 255 // end generated by svg_widgets.rb 256 257 addSlider(level1ParamPosition, module, Mix8::LEVEL1_PARAM, module ? &module->_channels[0]->rms : NULL); 258 addParam(createParam<SoloMuteButton>(mute1ParamPosition, module, Mix8::MUTE1_PARAM)); 259 addParam(createParam<Knob16>(pan1ParamPosition, module, Mix8::PAN1_PARAM)); 260 addSlider(level2ParamPosition, module, Mix8::LEVEL2_PARAM, module ? &module->_channels[1]->rms : NULL); 261 addParam(createParam<SoloMuteButton>(mute2ParamPosition, module, Mix8::MUTE2_PARAM)); 262 addParam(createParam<Knob16>(pan2ParamPosition, module, Mix8::PAN2_PARAM)); 263 addSlider(level3ParamPosition, module, Mix8::LEVEL3_PARAM, module ? &module->_channels[2]->rms : NULL); 264 addParam(createParam<SoloMuteButton>(mute3ParamPosition, module, Mix8::MUTE3_PARAM)); 265 addParam(createParam<Knob16>(pan3ParamPosition, module, Mix8::PAN3_PARAM)); 266 addSlider(level4ParamPosition, module, Mix8::LEVEL4_PARAM, module ? &module->_channels[3]->rms : NULL); 267 addParam(createParam<SoloMuteButton>(mute4ParamPosition, module, Mix8::MUTE4_PARAM)); 268 addParam(createParam<Knob16>(pan4ParamPosition, module, Mix8::PAN4_PARAM)); 269 addSlider(level5ParamPosition, module, Mix8::LEVEL5_PARAM, module ? &module->_channels[4]->rms : NULL); 270 addParam(createParam<SoloMuteButton>(mute5ParamPosition, module, Mix8::MUTE5_PARAM)); 271 addParam(createParam<Knob16>(pan5ParamPosition, module, Mix8::PAN5_PARAM)); 272 addSlider(level6ParamPosition, module, Mix8::LEVEL6_PARAM, module ? &module->_channels[5]->rms : NULL); 273 addParam(createParam<SoloMuteButton>(mute6ParamPosition, module, Mix8::MUTE6_PARAM)); 274 addParam(createParam<Knob16>(pan6ParamPosition, module, Mix8::PAN6_PARAM)); 275 addSlider(level7ParamPosition, module, Mix8::LEVEL7_PARAM, module ? &module->_channels[6]->rms : NULL); 276 addParam(createParam<SoloMuteButton>(mute7ParamPosition, module, Mix8::MUTE7_PARAM)); 277 addParam(createParam<Knob16>(pan7ParamPosition, module, Mix8::PAN7_PARAM)); 278 addSlider(level8ParamPosition, module, Mix8::LEVEL8_PARAM, module ? &module->_channels[7]->rms : NULL); 279 addParam(createParam<SoloMuteButton>(mute8ParamPosition, module, Mix8::MUTE8_PARAM)); 280 addParam(createParam<Knob16>(pan8ParamPosition, module, Mix8::PAN8_PARAM)); 281 addSlider(mixParamPosition, module, Mix8::MIX_PARAM, module ? &module->_rmsLevel : NULL); 282 addParam(createParam<MuteButton>(mixMuteParamPosition, module, Mix8::MIX_MUTE_PARAM)); 283 addParam(createParam<MuteButton>(mixDimParamPosition, module, Mix8::MIX_DIM_PARAM)); 284 285 addInput(createInput<Port24>(cv1InputPosition, module, Mix8::CV1_INPUT)); 286 addInput(createInput<Port24>(pan1InputPosition, module, Mix8::PAN1_INPUT)); 287 addInput(createInput<Port24>(in1InputPosition, module, Mix8::IN1_INPUT)); 288 addInput(createInput<Port24>(cv2InputPosition, module, Mix8::CV2_INPUT)); 289 addInput(createInput<Port24>(pan2InputPosition, module, Mix8::PAN2_INPUT)); 290 addInput(createInput<Port24>(in2InputPosition, module, Mix8::IN2_INPUT)); 291 addInput(createInput<Port24>(cv3InputPosition, module, Mix8::CV3_INPUT)); 292 addInput(createInput<Port24>(pan3InputPosition, module, Mix8::PAN3_INPUT)); 293 addInput(createInput<Port24>(in3InputPosition, module, Mix8::IN3_INPUT)); 294 addInput(createInput<Port24>(cv4InputPosition, module, Mix8::CV4_INPUT)); 295 addInput(createInput<Port24>(pan4InputPosition, module, Mix8::PAN4_INPUT)); 296 addInput(createInput<Port24>(in4InputPosition, module, Mix8::IN4_INPUT)); 297 addInput(createInput<Port24>(cv5InputPosition, module, Mix8::CV5_INPUT)); 298 addInput(createInput<Port24>(pan5InputPosition, module, Mix8::PAN5_INPUT)); 299 addInput(createInput<Port24>(in5InputPosition, module, Mix8::IN5_INPUT)); 300 addInput(createInput<Port24>(cv6InputPosition, module, Mix8::CV6_INPUT)); 301 addInput(createInput<Port24>(pan6InputPosition, module, Mix8::PAN6_INPUT)); 302 addInput(createInput<Port24>(in6InputPosition, module, Mix8::IN6_INPUT)); 303 addInput(createInput<Port24>(cv7InputPosition, module, Mix8::CV7_INPUT)); 304 addInput(createInput<Port24>(pan7InputPosition, module, Mix8::PAN7_INPUT)); 305 addInput(createInput<Port24>(in7InputPosition, module, Mix8::IN7_INPUT)); 306 addInput(createInput<Port24>(cv8InputPosition, module, Mix8::CV8_INPUT)); 307 addInput(createInput<Port24>(pan8InputPosition, module, Mix8::PAN8_INPUT)); 308 addInput(createInput<Port24>(in8InputPosition, module, Mix8::IN8_INPUT)); 309 addInput(createInput<Port24>(mixCvInputPosition, module, Mix8::MIX_CV_INPUT)); 310 311 addOutput(createOutput<Port24>(lOutputPosition, module, Mix8::L_OUTPUT)); 312 addOutput(createOutput<Port24>(rOutputPosition, module, Mix8::R_OUTPUT)); 313 } 314 315 void addSlider(Vec position, Mix8* module, int id, float* rms) { 316 auto slider = createParam<VUSlider151>(position, module, id); 317 if (rms) { 318 dynamic_cast<VUSlider*>(slider)->setVULevel(rms); 319 } 320 addParam(slider); 321 } 322 323 void contextMenu(Menu* menu) override { 324 DimmableMixerWidget::contextMenu(menu); 325 auto m = dynamic_cast<Mix8*>(module); 326 assert(m); 327 OptionsMenuItem* mi = new OptionsMenuItem("Input 1 poly spread"); 328 mi->addItem(OptionMenuItem("None", [m]() { return m->_polyChannelOffset == -1; }, [m]() { m->_polyChannelOffset = -1; })); 329 mi->addItem(OptionMenuItem("Channels 1-8", [m]() { return m->_polyChannelOffset == 0; }, [m]() { m->_polyChannelOffset = 0; })); 330 mi->addItem(OptionMenuItem("Channels 9-16", [m]() { return m->_polyChannelOffset == 8; }, [m]() { m->_polyChannelOffset = 8; })); 331 OptionsMenuItem::addToMenu(mi, menu); 332 } 333 }; 334 335 Model* modelMix8 = bogaudio::createModel<Mix8, Mix8Widget>("Bogaudio-Mix8", "MIX8", "8-channel mixer and panner", "Mixer", "Panning");