BogaudioModules

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

Sine.cpp (6068B)


      1 
      2 #include "Sine.hpp"
      3 
      4 #define WAVE "wave"
      5 #define FM_MODE "fm_mode"
      6 #define LINEAR_MODE "linear_mode"
      7 
      8 json_t* Sine::saveToJson(json_t* root) {
      9 	root = VCOBase::saveToJson(root);
     10 	json_object_set_new(root, WAVE, json_integer((int)_wave));
     11 	json_object_set_new(root, FM_MODE, json_boolean(_fmLinearMode));
     12 	json_object_set_new(root, LINEAR_MODE, json_boolean(_linearMode));
     13 	return root;
     14 }
     15 
     16 void Sine::loadFromJson(json_t* root) {
     17 	VCOBase::loadFromJson(root);
     18 
     19 	json_t* w = json_object_get(root, WAVE);
     20 	if (w) {
     21 		_wave = (Wave)json_integer_value(w);
     22 		if (!(_wave == TRIANGLE_WAVE || _wave == SAW_WAVE || _wave == RAMP_WAVE || _wave == SQUARE_WAVE || _wave == PULSE_25_WAVE || _wave == PULSE_10_WAVE)) {
     23 			_wave = SINE_WAVE;
     24 		}
     25 	}
     26 
     27 	json_t* fm = json_object_get(root, FM_MODE);
     28 	if (fm) {
     29 		_fmLinearMode = json_is_true(fm);
     30 	}
     31 
     32 	json_t* l = json_object_get(root, LINEAR_MODE);
     33 	if (l) {
     34 		_linearMode = json_is_true(l);
     35 	}
     36 }
     37 
     38 bool Sine::active() {
     39 	return outputs[OUT_OUTPUT].isConnected();
     40 }
     41 
     42 void Sine::modulate() {
     43 	_slowMode = params[SLOW_PARAM].getValue() > 0.5f;
     44 	_fmDepth = params[FM_DEPTH_PARAM].getValue();
     45 }
     46 
     47 void Sine::modulateChannel(int c) {
     48 	VCOBase::modulateChannel(c);
     49 	Engine& e = *_engines[c];
     50 
     51 	_outputScale = 1.0f;
     52 	e.sawActive = false;
     53 	e.squareActive = false;
     54 	switch (_wave) {
     55 		case SAW_WAVE: {
     56 			e.sawActive = true;
     57 			break;
     58 		}
     59 		case RAMP_WAVE: {
     60 			e.sawActive = true;
     61 			_outputScale = -1.0f;
     62 			break;
     63 		}
     64 		case SQUARE_WAVE: {
     65 			e.squareActive = true;
     66 			e.square.setPulseWidth(e.squarePulseWidthSL.next(0.5f), _dcCorrection);
     67 			break;
     68 		}
     69 		case PULSE_25_WAVE: {
     70 			e.squareActive = true;
     71 			e.square.setPulseWidth(e.squarePulseWidthSL.next(0.25f), _dcCorrection);
     72 			break;
     73 		}
     74 		case PULSE_10_WAVE: {
     75 			e.squareActive = true;
     76 			e.square.setPulseWidth(e.squarePulseWidthSL.next(0.1f), _dcCorrection);
     77 			break;
     78 		}
     79 		default: {
     80 		}
     81 	}
     82 	e.triangleActive = _wave == TRIANGLE_WAVE;
     83 	e.sineActive = _wave == SINE_WAVE;
     84 }
     85 
     86 void Sine::processChannel(const ProcessArgs& args, int c) {
     87 	Engine& e = *_engines[c];
     88 
     89 	float phaseOffset = params[PHASE_PARAM].getValue();
     90 	if (inputs[PHASE_INPUT].isConnected()) {
     91 		phaseOffset *= clamp(inputs[PHASE_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
     92 	}
     93 	e.additionalPhaseOffset = -phaseOffset * 0.5f * Phasor::cyclePhase;
     94 
     95 	VCOBase::processChannel(args, c);
     96 
     97 	outputs[OUT_OUTPUT].setChannels(_channels);
     98 	outputs[OUT_OUTPUT].setVoltage(_outputScale * (e.squareOut + e.sawOut + e.triangleOut + e.sineOut), c);
     99 }
    100 
    101 struct SineWidget : VCOBaseModuleWidget {
    102 	static constexpr int hp = 3;
    103 
    104 	SineWidget(Sine* module) {
    105 		setModule(module);
    106 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    107 		setPanel(box.size, "Sine");
    108 		createScrews();
    109 
    110 		// generated by svg_widgets.rb
    111 		auto frequencyParamPosition = Vec(9.5, 27.0);
    112 		auto slowParamPosition = Vec(31.0, 62.0);
    113 		auto fmDepthParamPosition = Vec(14.5, 92.5);
    114 		auto phaseParamPosition = Vec(14.5, 134.5);
    115 
    116 		auto pitchInputPosition = Vec(10.5, 161.0);
    117 		auto fmInputPosition = Vec(10.5, 196.0);
    118 		auto phaseInputPosition = Vec(10.5, 231.0);
    119 		auto syncInputPosition = Vec(10.5, 266.0);
    120 
    121 		auto outOutputPosition = Vec(10.5, 304.0);
    122 		// end generated by svg_widgets.rb
    123 
    124 		addParam(createParam<Knob26>(frequencyParamPosition, module, Sine::FREQUENCY_PARAM));
    125 		addParam(createParam<IndicatorButtonGreen9>(slowParamPosition, module, Sine::SLOW_PARAM));
    126 		addParam(createParam<Knob16>(fmDepthParamPosition, module, Sine::FM_DEPTH_PARAM));
    127 		addParam(createParam<Knob16>(phaseParamPosition, module, Sine::PHASE_PARAM));
    128 
    129 		addInput(createInput<Port24>(pitchInputPosition, module, Sine::PITCH_INPUT));
    130 		addInput(createInput<Port24>(fmInputPosition, module, Sine::FM_INPUT));
    131 		addInput(createInput<Port24>(phaseInputPosition, module, Sine::PHASE_INPUT));
    132 		addInput(createInput<Port24>(syncInputPosition, module, Sine::SYNC_INPUT));
    133 
    134 		addOutput(createOutput<Port24>(outOutputPosition, module, Sine::OUT_OUTPUT));
    135 	}
    136 
    137 	void contextMenu(Menu* menu) override {
    138 		auto m = dynamic_cast<Sine*>(module);
    139 		assert(m);
    140 
    141 		OptionsMenuItem* w = new OptionsMenuItem("Waveform");
    142 		w->addItem(OptionMenuItem("Sine", [m]() { return m->_wave == Sine::SINE_WAVE; }, [m]() { m->_wave = Sine::SINE_WAVE; }));
    143 		w->addItem(OptionMenuItem("Triangle", [m]() { return m->_wave == Sine::TRIANGLE_WAVE; }, [m]() { m->_wave = Sine::TRIANGLE_WAVE; }));
    144 		w->addItem(OptionMenuItem("Saw", [m]() { return m->_wave == Sine::SAW_WAVE; }, [m]() { m->_wave = Sine::SAW_WAVE; }));
    145 		w->addItem(OptionMenuItem("Ramp", [m]() { return m->_wave == Sine::RAMP_WAVE; }, [m]() { m->_wave = Sine::RAMP_WAVE; }));
    146 		w->addItem(OptionMenuItem("Square", [m]() { return m->_wave == Sine::SQUARE_WAVE; }, [m]() { m->_wave = Sine::SQUARE_WAVE; }));
    147 		w->addItem(OptionMenuItem("25% pulse", [m]() { return m->_wave == Sine::PULSE_25_WAVE; }, [m]() { m->_wave = Sine::PULSE_25_WAVE; }));
    148 		w->addItem(OptionMenuItem("10% pulse", [m]() { return m->_wave == Sine::PULSE_10_WAVE; }, [m]() { m->_wave = Sine::PULSE_10_WAVE; }));
    149 		OptionsMenuItem::addToMenu(w, menu);
    150 
    151 		OptionsMenuItem* fm = new OptionsMenuItem("FM mode");
    152 		fm->addItem(OptionMenuItem("Exponential", [m]() { return !m->_fmLinearMode; }, [m]() { m->_fmLinearMode = false; }));
    153 		fm->addItem(OptionMenuItem("Linear", [m]() { return m->_fmLinearMode; }, [m]() { m->_fmLinearMode = true; }));
    154 		OptionsMenuItem::addToMenu(fm, menu);
    155 
    156 		menu->addChild(new BoolOptionMenuItem("Linear frequency mode", [m]() { return &m->_linearMode; }));
    157 
    158 		OptionsMenuItem* p = new OptionsMenuItem("Polyphony channels from");
    159 		p->addItem(OptionMenuItem("V/OCT input", [m]() { return m->_polyInputID == Sine::PITCH_INPUT; }, [m]() { m->_polyInputID = Sine::PITCH_INPUT; }));
    160 		p->addItem(OptionMenuItem("FM input", [m]() { return m->_polyInputID == Sine::FM_INPUT; }, [m]() { m->_polyInputID = Sine::FM_INPUT; }));
    161 		OptionsMenuItem::addToMenu(p, menu);
    162 
    163 		VCOBaseModuleWidget::contextMenu(menu);
    164 	}
    165 };
    166 
    167 Model* modelSine = createModel<Sine, SineWidget>("Bogaudio-Sine", "SINE", "Sine oscillator with phase offset", "Oscillator", "Polyphonic");