BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

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");