//============================================================================================================ //! //! \file Octave-G1.cpp //! //! \brief Octave-G1 quantises the input to 12-ET and provides an octaves-worth of output. //! //============================================================================================================ #include "Gratrix.hpp" namespace rack_plugin_Gratrix { //============================================================================================================ //! \brief Some settings. enum Spec { LO_BEGIN = -5, // C-1 LO_END = 5, // C+9 LO_SIZE = LO_END - LO_BEGIN + 1, E = 12, // ET N = 12, // Number of note outputs T = 2, M = 2*T+1 // Number of octave outputs }; //============================================================================================================ //! \brief The module. struct GtxModule_Octave_G1 : Module { enum ParamIds { NUM_PARAMS }; enum InputIds { VOCT_INPUT = 0, NUM_INPUTS = VOCT_INPUT + 1 }; enum OutputIds { NOTE_OUTPUT = 0, OCT_OUTPUT = NOTE_OUTPUT + N, NUM_OUTPUTS = OCT_OUTPUT + M }; enum LightIds { KEY_LIGHT = 0, OCT_LIGHT = KEY_LIGHT + E, NUM_LIGHTS = OCT_LIGHT + LO_SIZE }; struct Decode { /*static constexpr*/ float e = static_cast(E); // Static constexpr gives /*static constexpr*/ float s = 1.0f / e; // link error on Mac build. float in = 0; //!< Raw input. float out = 0; //!< Input quantized. int note = 0; //!< Integer note (offset midi note). int key = 0; //!< C, C#, D, D#, etc. int oct = 0; //!< Octave (C4 = 0). void step(float input) { int safe, fnote; in = input; fnote = std::floor(in * e + 0.5f); out = fnote * s; note = static_cast(fnote); safe = note + (E * 1000); // push away from negative numbers key = safe % E; oct = (safe / E) - 1000; } }; Decode input; //-------------------------------------------------------------------------------------------------------- //! \brief Constructor. GtxModule_Octave_G1() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} //-------------------------------------------------------------------------------------------------------- //! \brief Step function. void step() override { // Clear all lights float leds[NUM_LIGHTS] = {}; // Decode inputs and params input.step(inputs[VOCT_INPUT].value); for (std::size_t i=0; i(6*15 + 0.5 + radius * dx(i, E)); } static int y(std::size_t i, double radius) { return static_cast(-20+206 + 0.5 + radius * dy(i, E)); } //============================================================================================================ //! \brief The widget. struct GtxWidget_Octave_G1 : ModuleWidget { GtxWidget_Octave_G1(GtxModule_Octave_G1 *module) : ModuleWidget(module) { GTX__WIDGET(); box.size = Vec(12*15, 380); // double r1 = 30; double r2 = 55; #if GTX__SAVE_SVG { PanelGen pg(assetPlugin(plugin, "build/res/Octave-G1.svg"), box.size, "OCTAVE-G1"); pg.circle(Vec(x(0, 0), y(0, 0)), r2+16, "fill:#7092BE;stroke:none"); pg.circle(Vec(x(0, 0), y(0, 0)), r2-16, "fill:#CEE1FD;stroke:none"); /* // Wires for (std::size_t i=0; i(Vec(15, 0))); addChild(Widget::create(Vec(box.size.x-30, 0))); addChild(Widget::create(Vec(15, 365))); addChild(Widget::create(Vec(box.size.x-30, 365))); addInput(createInputGTX(Vec(x(0, 0), y(0, 0)), module, GtxModule_Octave_G1::VOCT_INPUT)); for (std::size_t i=0; i(Vec(x(i, r2), y(i, r2)), module, i + GtxModule_Octave_G1::NOTE_OUTPUT)); } addOutput(createOutputGTX(Vec(gx(-0.20), gy(2)), module, 0 + GtxModule_Octave_G1::OCT_OUTPUT)); addOutput(createOutputGTX(Vec(gx( 0.15), gy(2)), module, 1 + GtxModule_Octave_G1::OCT_OUTPUT)); addOutput(createOutputGTX(Vec(gx( 0.50), gy(2)), module, 2 + GtxModule_Octave_G1::OCT_OUTPUT)); addOutput(createOutputGTX(Vec(gx( 0.85), gy(2)), module, 3 + GtxModule_Octave_G1::OCT_OUTPUT)); addOutput(createOutputGTX(Vec(gx( 1.20), gy(2)), module, 4 + GtxModule_Octave_G1::OCT_OUTPUT)); addChild(ModuleLightWidget::create>(l_s(gx(0.5) - 30, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 0)); // C addChild(ModuleLightWidget::create>(l_s(gx(0.5) - 25, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 1)); // C# addChild(ModuleLightWidget::create>(l_s(gx(0.5) - 20, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 2)); // D addChild(ModuleLightWidget::create>(l_s(gx(0.5) - 15, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 3)); // Eb addChild(ModuleLightWidget::create>(l_s(gx(0.5) - 10, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 4)); // E addChild(ModuleLightWidget::create>(l_s(gx(0.5) , fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 5)); // F addChild(ModuleLightWidget::create>(l_s(gx(0.5) + 5, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 6)); // Fs addChild(ModuleLightWidget::create>(l_s(gx(0.5) + 10, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 7)); // G addChild(ModuleLightWidget::create>(l_s(gx(0.5) + 15, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 8)); // Ab addChild(ModuleLightWidget::create>(l_s(gx(0.5) + 20, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 9)); // A addChild(ModuleLightWidget::create>(l_s(gx(0.5) + 25, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 10)); // Bb addChild(ModuleLightWidget::create>(l_s(gx(0.5) + 30, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 11)); // B for (std::size_t i=0; i>(l_s(gx(0.5) + (i - LO_SIZE/2) * 10, fy(0-0.28) + 20), module, GtxModule_Octave_G1::OCT_LIGHT + i)); } } }; } // namespace rack_plugin_Gratrix using namespace rack_plugin_Gratrix; RACK_PLUGIN_MODEL_INIT(Gratrix, Octave_G1) { Model *model = Model::create("Gratrix", "Octave-G1", "Octave-G1", SYNTH_VOICE_TAG); // right tag? return model; }