BogaudioModules

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

Reftone.cpp (6187B)


      1 
      2 #include "Reftone.hpp"
      3 
      4 void Reftone::processAll(const ProcessArgs& args) {
      5 	// C4 -- the pitch.hpp reference frequency -- in knob values:
      6 	const float referencePitch = 0.0f;
      7 	const float referenceOctave = 4.0f;
      8 
      9 	if (!(
     10 		_pitch == params[PITCH_PARAM].getValue() &&
     11 		_octave == params[OCTAVE_PARAM].getValue() &&
     12 		_fine == params[FINE_PARAM].getValue()
     13 	)) {
     14 		_pitch = params[PITCH_PARAM].getValue();
     15 		_octave = params[OCTAVE_PARAM].getValue();
     16 		_fine = params[FINE_PARAM].getValue();
     17 		_frequency = semitoneToFrequency(referenceSemitone + 12.0f*roundf(_octave - referenceOctave) + roundf(_pitch - referencePitch) + _fine);
     18 		_cv = frequencyToCV(_frequency);
     19 	}
     20 
     21 	if (outputs[CV_OUTPUT].isConnected()) {
     22 		outputs[CV_OUTPUT].setVoltage(_cv);
     23 	}
     24 	else {
     25 		outputs[CV_OUTPUT].setVoltage(0.0);
     26 	}
     27 
     28 	if (outputs[OUT_OUTPUT].isConnected()) {
     29 		_sine.setFrequency(_frequency);
     30 		outputs[OUT_OUTPUT].setVoltage(_sine.next() * 5.0f);
     31 	}
     32 	else {
     33 		outputs[OUT_OUTPUT].setVoltage(0.0);
     34 	}
     35 }
     36 
     37 struct ReftoneDisplay : DisplayWidget {
     38 	const NVGcolor _textColor = nvgRGBA(0x00, 0xff, 0x00, 0xee);
     39 
     40 	Reftone* _module;
     41 	const Vec _size;
     42 	std::string _fontPath;
     43 
     44 	ReftoneDisplay(
     45 		Reftone* module,
     46 		Vec size
     47 	)
     48 	: DisplayWidget(module)
     49 	, _module(module)
     50 	, _size(size)
     51 	, _fontPath(asset::plugin(pluginInstance, "res/fonts/inconsolata-bold.ttf"))
     52 	{
     53 	}
     54 
     55 	void draw(const DrawArgs& args) override;
     56 	void drawLit(const DrawArgs& args) override;
     57 	void drawOnce(const DrawArgs& args, bool screenshot, bool lit) override;
     58 	void drawBackground(const DrawArgs& args);
     59 	void drawText(const DrawArgs& args, const char* s, float x, float y, int size);
     60 	void drawCenteredText(const DrawArgs& args, const char* s, float y, int size);
     61 	float textRenderWidth(const DrawArgs& args, const char* s, int size);
     62 };
     63 
     64 void ReftoneDisplay::draw(const DrawArgs& args) {
     65 	if (!isLit()) {
     66 		drawOnce(args, isScreenshot(), false);
     67 	}
     68 }
     69 
     70 void ReftoneDisplay::drawLit(const DrawArgs& args) {
     71 	if (isLit()) {
     72 		drawOnce(args, false, true);
     73 	}
     74 }
     75 
     76 void ReftoneDisplay::drawOnce(const DrawArgs& args, bool screenshot, bool lit) {
     77 	int mPitch = 9;
     78 	int mOctave = 4;
     79 	float mFine = 0.0f;
     80 	float mFrequency = 440.0f;
     81 	if (!screenshot) {
     82 		mPitch = _module->_pitch;
     83 		mOctave = _module->_octave;
     84 		mFine = _module->_fine;
     85 		mFrequency = _module->_frequency;
     86 	}
     87 
     88 	std::string octave = std::to_string(mOctave);
     89 	std::string fine = format("%s%02d", mFine < 0.0 ? "-" : "+", abs((int)(mFine * 100)));
     90 	std::string frequency = format(mFrequency >= 1000.0 ? "%0.0f" : "%0.1f", mFrequency);
     91 	const char* pitch = NULL;
     92 	const char* sharpFlat = NULL;
     93 	switch (mPitch) {
     94 		case 0: {
     95 			pitch = "C";
     96 			break;
     97 		}
     98 		case 1: {
     99 			pitch = "C";
    100 			sharpFlat = "#";
    101 			break;
    102 		}
    103 		case 2: {
    104 			pitch = "D";
    105 			break;
    106 		}
    107 		case 3: {
    108 			pitch = "E";
    109 			sharpFlat = "b";
    110 			break;
    111 		}
    112 		case 4: {
    113 			pitch = "E";
    114 			break;
    115 		}
    116 		case 5: {
    117 			pitch = "F";
    118 			break;
    119 		}
    120 		case 6: {
    121 			pitch = "F";
    122 			sharpFlat = "#";
    123 			break;
    124 		}
    125 		case 7: {
    126 			pitch = "G";
    127 			break;
    128 		}
    129 		case 8: {
    130 			pitch = "G";
    131 			sharpFlat = "#";
    132 			break;
    133 		}
    134 		case 9: {
    135 			pitch = "A";
    136 			break;
    137 		}
    138 		case 10: {
    139 			pitch = "B";
    140 			sharpFlat = "b";
    141 			break;
    142 		}
    143 		case 11: {
    144 			pitch = "B";
    145 			break;
    146 		}
    147 	}
    148 
    149 	nvgSave(args.vg);
    150 	if (!screenshot && !lit) {
    151 		drawBackground(args);
    152 	}
    153 	else {
    154 		drawBackground(args);
    155 		if (sharpFlat) {
    156 			drawText(args, pitch, 3, 20, 28);
    157 			drawText(args, sharpFlat, 16, 12, 16);
    158 			drawText(args, octave.c_str(), 22, 20, 28);
    159 		}
    160 		else {
    161 			drawCenteredText(args, (pitch + octave).c_str(), 20, 28);
    162 		}
    163 		drawCenteredText(args, fine.c_str(), 32.5, 14);
    164 		drawCenteredText(args, frequency.c_str(), 45, 14);
    165 	}
    166 	nvgRestore(args.vg);
    167 }
    168 
    169 void ReftoneDisplay::drawBackground(const DrawArgs& args) {
    170 	nvgSave(args.vg);
    171 	nvgBeginPath(args.vg);
    172 	nvgRect(args.vg, 0, 0, _size.x, _size.y);
    173 	nvgFillColor(args.vg, nvgRGBA(0x00, 0x00, 0x00, 0xff));
    174 	nvgFill(args.vg);
    175 	nvgStrokeColor(args.vg, nvgRGBA(0x50, 0x50, 0x50, 0xff));
    176 	nvgStroke(args.vg);
    177 	nvgRestore(args.vg);
    178 }
    179 
    180 void ReftoneDisplay::drawText(const DrawArgs& args, const char* s, float x, float y, int size) {
    181 	std::shared_ptr<Font> font = APP->window->loadFont(_fontPath);
    182 	nvgSave(args.vg);
    183 	nvgTranslate(args.vg, x, y);
    184 	nvgFontSize(args.vg, size);
    185 	nvgFontFaceId(args.vg, font->handle);
    186 	nvgFillColor(args.vg, _textColor);
    187 	nvgText(args.vg, 0, 0, s, NULL);
    188 	nvgRestore(args.vg);
    189 }
    190 
    191 void ReftoneDisplay::drawCenteredText(const DrawArgs& args, const char* s, float y, int size) {
    192 	float x = textRenderWidth(args, s, size);
    193 	x = std::max(0.0f, _size.x - x);
    194 	x /= 2.0;
    195 	drawText(args, s, x, y, size);
    196 }
    197 
    198 float ReftoneDisplay::textRenderWidth(const DrawArgs& args, const char* s, int size) {
    199 	// nvgSave(args.vg);
    200 	// nvgFontSize(args.vg, size);
    201 	// float w = nvgTextBounds(args.vg, 0, 0, s, NULL, NULL);
    202 	// nvgRestore(args.vg);
    203 	// return w - size/4.0;
    204 	return strlen(s) * (size / 2.1);
    205 }
    206 
    207 struct ReftoneWidget : BGModuleWidget {
    208 	static constexpr int hp = 3;
    209 
    210 	ReftoneWidget(Reftone* module) {
    211 		setModule(module);
    212 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    213 		setPanel(box.size, "Reftone");
    214 		createScrews();
    215 
    216 		{
    217 			auto inset = Vec(3.5, 18);
    218 			auto size = Vec(38, 48);
    219 			auto display = new ReftoneDisplay(module, size);
    220 			display->box.pos = inset;
    221 			display->box.size = size;
    222 			addChild(display);
    223 		}
    224 
    225 		// generated by svg_widgets.rb
    226 		auto pitchParamPosition = Vec(9.5, 89.5);
    227 		auto octaveParamPosition = Vec(9.5, 143.5);
    228 		auto fineParamPosition = Vec(9.5, 197.5);
    229 
    230 		auto cvOutputPosition = Vec(10.5, 239.0);
    231 		auto outOutputPosition = Vec(10.5, 274.0);
    232 		// end generated by svg_widgets.rb
    233 
    234 		addParam(createParam<Knob26>(pitchParamPosition, module, Reftone::PITCH_PARAM));
    235 		addParam(createParam<Knob26>(octaveParamPosition, module, Reftone::OCTAVE_PARAM));
    236 		addParam(createParam<Knob26>(fineParamPosition, module, Reftone::FINE_PARAM));
    237 
    238 		addOutput(createOutput<Port24>(cvOutputPosition, module, Reftone::CV_OUTPUT));
    239 		addOutput(createOutput<Port24>(outOutputPosition, module, Reftone::OUT_OUTPUT));
    240 	}
    241 };
    242 
    243 Model* modelReftone = bogaudio::createModel<Reftone, ReftoneWidget>("Bogaudio-Reftone", "REFTONE", "Precision pitch CV generator", "Tuner");