BogaudioModules

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

FourFO.cpp (10309B)


      1 
      2 #include "FourFO.hpp"
      3 
      4 const Phasor::phase_delta_t basePhase3Offset = Phasor::radiansToPhase(1.5f * M_PI);
      5 const Phasor::phase_delta_t basePhase2Offset = Phasor::radiansToPhase(M_PI);
      6 const Phasor::phase_delta_t basePhase1Offset = Phasor::radiansToPhase(0.5f * M_PI);
      7 const Phasor::phase_delta_t basePhase0Offset = Phasor::radiansToPhase(0.0f);
      8 
      9 void FourFO::Engine::reset() {
     10 	resetTrigger.reset();
     11 	sampleStep = phasor._sampleRate;
     12 }
     13 
     14 void FourFO::Engine::sampleRateChange() {
     15 	phasor.setSampleRate(APP->engine->getSampleRate());
     16 	sampleStep = phasor._sampleRate;
     17 }
     18 
     19 void FourFO::reset() {
     20 	for (int c = 0; c < _channels; ++c) {
     21 		_engines[c]->reset();
     22 	}
     23 }
     24 
     25 void FourFO::sampleRateChange() {
     26 	for (int c = 0; c < _channels; ++c) {
     27 		_engines[c]->sampleRateChange();
     28 	}
     29 }
     30 
     31 bool FourFO::active() {
     32 	return (
     33 		outputs[PHASE3_OUTPUT].isConnected() ||
     34 		outputs[PHASE2_OUTPUT].isConnected() ||
     35 		outputs[PHASE1_OUTPUT].isConnected() ||
     36 		outputs[PHASE0_OUTPUT].isConnected()
     37 	);
     38 }
     39 
     40 int FourFO::channels() {
     41 	return inputs[PITCH_INPUT].getChannels();
     42 }
     43 
     44 void FourFO::addChannel(int c) {
     45 	_engines[c] = new Engine();
     46 	_engines[c]->reset();
     47 	_engines[c]->sampleRateChange();
     48 	if (c > 0) {
     49 		_engines[c]->phasor.syncPhase(_engines[0]->phasor);
     50 	}
     51 }
     52 
     53 void FourFO::removeChannel(int c) {
     54 	delete _engines[c];
     55 	_engines[c] = NULL;
     56 }
     57 
     58 void FourFO::modulate() {
     59 	_wave = (Wave)roundf(params[WAVE_PARAM].getValue());
     60 	_slowMode = params[SLOW_PARAM].getValue() > 0.5f;
     61 }
     62 
     63 void FourFO::modulateChannel(int c) {
     64 	Engine& e = *_engines[c];
     65 
     66 	setFrequency(params[FREQUENCY_PARAM], inputs[PITCH_INPUT], e.phasor, c);
     67 
     68 	switch (_wave) {
     69 		case SQUARE_WAVE: {
     70 			float pw = params[SAMPLE_PWM_PARAM].getValue();
     71 			if (inputs[SAMPLE_PWM_INPUT].isConnected()) {
     72 				pw *= clamp(inputs[SAMPLE_PWM_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
     73 			}
     74 			pw *= 1.0f - 2.0f * e.square.minPulseWidth;
     75 			pw *= 0.5f;
     76 			pw += 0.5f;
     77 			e.square.setPulseWidth(pw);
     78 			e.sampleSteps = 1;
     79 			break;
     80 		}
     81 		case STEPPED_WAVE: {
     82 			e.sampleSteps = 1;
     83 			break;
     84 		}
     85 		default: {
     86 			float sample = fabsf(params[SAMPLE_PWM_PARAM].getValue());
     87 			if (inputs[SAMPLE_PWM_INPUT].isConnected()) {
     88 				sample *= clamp(fabsf(inputs[SAMPLE_PWM_INPUT].getPolyVoltage(c)) / 5.0f, 0.0f, 1.0f);
     89 			}
     90 			float maxSampleSteps = (e.phasor._sampleRate / e.phasor._frequency) / 4.0f;
     91 			e.sampleSteps = clamp((int)(sample * maxSampleSteps), 1, (int)maxSampleSteps);
     92 		}
     93 	}
     94 
     95 	float smooth = params[SMOOTH_PARAM].getValue();
     96 	if (inputs[SMOOTH_INPUT].isConnected()) {
     97 		smooth *= clamp(inputs[SMOOTH_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
     98 	}
     99 	float sr = APP->engine->getSampleRate();
    100 	e.phase3Smoother.setParams(sr, e.phasor._frequency, smooth);
    101 	e.phase2Smoother.setParams(sr, e.phasor._frequency, smooth);
    102 	e.phase1Smoother.setParams(sr, e.phasor._frequency, smooth);
    103 	e.phase0Smoother.setParams(sr, e.phasor._frequency, smooth);
    104 
    105 	e.offset = params[OFFSET_PARAM].getValue();
    106 	if (inputs[OFFSET_INPUT].isConnected()) {
    107 		e.offset *= clamp(inputs[OFFSET_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    108 	}
    109 	e.offset *= _offsetScale;
    110 	e.offset *= 5.0f;
    111 	e.scale = params[SCALE_PARAM].getValue();
    112 	if (inputs[SCALE_INPUT].isConnected()) {
    113 		e.scale *= clamp(inputs[SCALE_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
    114 	}
    115 
    116 	e.phase3Offset = phaseOffset(c, params[PHASE3_PARAM], inputs[PHASE3_INPUT], basePhase3Offset);
    117 	e.phase2Offset = phaseOffset(c, params[PHASE2_PARAM], inputs[PHASE2_INPUT], basePhase2Offset);
    118 	e.phase1Offset = phaseOffset(c, params[PHASE1_PARAM], inputs[PHASE1_INPUT], basePhase1Offset);
    119 	e.phase0Offset = phaseOffset(c, params[PHASE0_PARAM], inputs[PHASE0_INPUT], basePhase0Offset);
    120 }
    121 
    122 void FourFO::processChannel(const ProcessArgs& args, int c) {
    123 	Engine& e = *_engines[c];
    124 
    125 	if (e.resetTrigger.next(inputs[RESET_INPUT].getPolyVoltage(c))) {
    126 		e.phasor.resetPhase();
    127 	}
    128 
    129 	e.phasor.advancePhase();
    130 	bool useSample = false;
    131 	if (e.sampleSteps > 1) {
    132 		++e.sampleStep;
    133 		if (e.sampleStep >= e.sampleSteps) {
    134 			e.sampleStep = 0;
    135 		}
    136 		else {
    137 			useSample = true;
    138 		}
    139 	}
    140 	updateOutput(c, useSample, outputs[PHASE3_OUTPUT], e.phase3Offset, e.phase3Sample, e.phase3Active, e.phase3Smoother);
    141 	updateOutput(c, useSample, outputs[PHASE2_OUTPUT], e.phase2Offset, e.phase2Sample, e.phase2Active, e.phase2Smoother);
    142 	updateOutput(c, useSample, outputs[PHASE1_OUTPUT], e.phase1Offset, e.phase1Sample, e.phase1Active, e.phase1Smoother);
    143 	updateOutput(c, useSample, outputs[PHASE0_OUTPUT], e.phase0Offset, e.phase0Sample, e.phase0Active, e.phase0Smoother);
    144 }
    145 
    146 Phasor::phase_delta_t FourFO::phaseOffset(int c, Param& p, Input& i, Phasor::phase_delta_t baseOffset) {
    147 	float o = p.getValue() * Phasor::cyclePhase / 2.0f;
    148 	if (i.isConnected()) {
    149 		o *= clamp(i.getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    150 	}
    151 	return baseOffset - o;
    152 }
    153 
    154 void FourFO::updateOutput(int c, bool useSample, Output& output, Phasor::phase_delta_t& offset, float& sample, bool& active, Smoother& smoother) {
    155 	if (output.isConnected()) {
    156 		output.setChannels(_channels);
    157 		if (!useSample || !active) {
    158 			float v = 0.0f;
    159 			switch (_wave) {
    160 				case NO_WAVE: {
    161 					assert(false);
    162 				}
    163 				case SINE_WAVE: {
    164 					v = _engines[c]->sine.nextFromPhasor(_engines[c]->phasor, offset);
    165 					break;
    166 				}
    167 				case TRIANGLE_WAVE: {
    168 					v = _engines[c]->triangle.nextFromPhasor(_engines[c]->phasor, offset);
    169 					break;
    170 				}
    171 				case RAMP_UP_WAVE: {
    172 					v = _engines[c]->ramp.nextFromPhasor(_engines[c]->phasor, offset);
    173 					break;
    174 				}
    175 				case RAMP_DOWN_WAVE: {
    176 					v = -_engines[c]->ramp.nextFromPhasor(_engines[c]->phasor, offset);
    177 					break;
    178 				}
    179 				case SQUARE_WAVE: {
    180 					v = _engines[c]->square.nextFromPhasor(_engines[c]->phasor, offset);
    181 					break;
    182 				}
    183 				case STEPPED_WAVE: {
    184 					v = _engines[c]->stepped.nextFromPhasor(_engines[c]->phasor, offset);
    185 					break;
    186 				}
    187 			}
    188 			sample = amplitude * _engines[c]->scale * v + _engines[c]->offset;
    189 		}
    190 		output.setVoltage(clamp(smoother.next(sample), -12.0f, 12.0f), c);
    191 		active = true;
    192 	}
    193 	else {
    194 		active = false;
    195 	}
    196 }
    197 
    198 struct FourFOWidget : LFOBaseModuleWidget {
    199 	static constexpr int hp = 10;
    200 
    201 	FourFOWidget(FourFO* module) {
    202 		setModule(module);
    203 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    204 		setPanel(box.size, "FourFO");
    205 		createScrews();
    206 
    207 		// generated by svg_widgets.rb
    208 		auto frequencyParamPosition = Vec(23.0, 42.0);
    209 		auto waveParamPosition = Vec(95.0, 53.0);
    210 		auto slowParamPosition = Vec(49.0, 108.7);
    211 		auto samplePwmParamPosition = Vec(13.0, 149.0);
    212 		auto smoothParamPosition = Vec(48.0, 149.0);
    213 		auto offsetParamPosition = Vec(13.0, 198.0);
    214 		auto scaleParamPosition = Vec(48.0, 198.0);
    215 		auto phase0ParamPosition = Vec(121.0, 193.0);
    216 		auto phase1ParamPosition = Vec(84.0, 193.0);
    217 		auto phase2ParamPosition = Vec(84.0, 251.0);
    218 		auto phase3ParamPosition = Vec(121.0, 251.0);
    219 
    220 		auto samplePwmInputPosition = Vec(11.0, 230.0);
    221 		auto smoothInputPosition = Vec(43.0, 230.0);
    222 		auto offsetInputPosition = Vec(11.0, 274.0);
    223 		auto scaleInputPosition = Vec(43.0, 274.0);
    224 		auto pitchInputPosition = Vec(11.0, 318.0);
    225 		auto resetInputPosition = Vec(43.0, 318.0);
    226 		auto phase0InputPosition = Vec(117.0, 104.0);
    227 		auto phase1InputPosition = Vec(80.0, 104.0);
    228 		auto phase2InputPosition = Vec(80.0, 322.0);
    229 		auto phase3InputPosition = Vec(117.0, 322.0);
    230 
    231 		auto phase0OutputPosition = Vec(117.0, 146.0);
    232 		auto phase1OutputPosition = Vec(80.0, 146.0);
    233 		auto phase2OutputPosition = Vec(80.0, 280.0);
    234 		auto phase3OutputPosition = Vec(117.0, 280.0);
    235 		// end generated by svg_widgets.rb
    236 
    237 		addParam(createParam<Knob38>(frequencyParamPosition, module, FourFO::FREQUENCY_PARAM));
    238 		{
    239 			auto w = createParam<Knob16>(waveParamPosition, module, FourFO::WAVE_PARAM);
    240 			auto k = dynamic_cast<SvgKnob*>(w);
    241 			k->minAngle = 0.0;
    242 			k->maxAngle = M_PI;
    243 			k->speed = 3.0;
    244 			addParam(w);
    245 		}
    246 		addParam(createParam<IndicatorButtonGreen9>(slowParamPosition, module, FourFO::SLOW_PARAM));
    247 		addParam(createParam<Knob16>(samplePwmParamPosition, module, FourFO::SAMPLE_PWM_PARAM));
    248 		addParam(createParam<Knob16>(smoothParamPosition, module, FourFO::SMOOTH_PARAM));
    249 		addParam(createParam<Knob16>(offsetParamPosition, module, FourFO::OFFSET_PARAM));
    250 		addParam(createParam<Knob16>(scaleParamPosition, module, FourFO::SCALE_PARAM));
    251 		addPhaseParam(phase3ParamPosition, module, FourFO::PHASE3_PARAM, Phasor::phaseToRadians(basePhase3Offset));
    252 		addPhaseParam(phase2ParamPosition, module, FourFO::PHASE2_PARAM, Phasor::phaseToRadians(basePhase2Offset));
    253 		addPhaseParam(phase1ParamPosition, module, FourFO::PHASE1_PARAM, Phasor::phaseToRadians(basePhase1Offset));
    254 		addPhaseParam(phase0ParamPosition, module, FourFO::PHASE0_PARAM, Phasor::phaseToRadians(basePhase0Offset));
    255 
    256 		addInput(createInput<Port24>(samplePwmInputPosition, module, FourFO::SAMPLE_PWM_INPUT));
    257 		addInput(createInput<Port24>(smoothInputPosition, module, FourFO::SMOOTH_INPUT));
    258 		addInput(createInput<Port24>(offsetInputPosition, module, FourFO::OFFSET_INPUT));
    259 		addInput(createInput<Port24>(scaleInputPosition, module, FourFO::SCALE_INPUT));
    260 		addInput(createInput<Port24>(pitchInputPosition, module, FourFO::PITCH_INPUT));
    261 		addInput(createInput<Port24>(resetInputPosition, module, FourFO::RESET_INPUT));
    262 		addInput(createInput<Port24>(phase0InputPosition, module, FourFO::PHASE0_INPUT));
    263 		addInput(createInput<Port24>(phase1InputPosition, module, FourFO::PHASE1_INPUT));
    264 		addInput(createInput<Port24>(phase2InputPosition, module, FourFO::PHASE2_INPUT));
    265 		addInput(createInput<Port24>(phase3InputPosition, module, FourFO::PHASE3_INPUT));
    266 
    267 		addOutput(createOutput<Port24>(phase0OutputPosition, module, FourFO::PHASE0_OUTPUT));
    268 		addOutput(createOutput<Port24>(phase1OutputPosition, module, FourFO::PHASE1_OUTPUT));
    269 		addOutput(createOutput<Port24>(phase2OutputPosition, module, FourFO::PHASE2_OUTPUT));
    270 		addOutput(createOutput<Port24>(phase3OutputPosition, module, FourFO::PHASE3_OUTPUT));
    271 	}
    272 
    273 	void addPhaseParam(const Vec& position, Module* module, FourFO::ParamsIds paramId, float rotation) {
    274 		auto w = createParam<Knob16>(position, module, paramId);
    275 		auto k = dynamic_cast<SvgKnob*>(w);
    276 		k->minAngle += 0.5 * M_PI - rotation;
    277 		k->maxAngle += 0.5 * M_PI - rotation;
    278 		addParam(w);
    279 	}
    280 };
    281 
    282 Model* modelFourFO = createModel<FourFO, FourFOWidget>("Bogaudio-FourFO", "4FO", "Quadrature LFO", "LFO", "Random", "Polyphonic");