You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
7.7KB

  1. //============================================================================================================
  2. //!
  3. //! \file Octave-G1.cpp
  4. //!
  5. //! \brief Octave-G1 quantises the input to 12-ET and provides an octaves-worth of output.
  6. //!
  7. //============================================================================================================
  8. #include "Gratrix.hpp"
  9. namespace rack_plugin_Gratrix {
  10. //============================================================================================================
  11. //! \brief Some settings.
  12. enum Spec
  13. {
  14. LO_BEGIN = -5, // C-1
  15. LO_END = 5, // C+9
  16. LO_SIZE = LO_END - LO_BEGIN + 1,
  17. E = 12, // ET
  18. N = 12, // Number of note outputs
  19. T = 2,
  20. M = 2*T+1 // Number of octave outputs
  21. };
  22. //============================================================================================================
  23. //! \brief The module.
  24. struct GtxModule_Octave_G1 : Module
  25. {
  26. enum ParamIds {
  27. NUM_PARAMS
  28. };
  29. enum InputIds {
  30. VOCT_INPUT = 0,
  31. NUM_INPUTS = VOCT_INPUT + 1
  32. };
  33. enum OutputIds {
  34. NOTE_OUTPUT = 0,
  35. OCT_OUTPUT = NOTE_OUTPUT + N,
  36. NUM_OUTPUTS = OCT_OUTPUT + M
  37. };
  38. enum LightIds {
  39. KEY_LIGHT = 0,
  40. OCT_LIGHT = KEY_LIGHT + E,
  41. NUM_LIGHTS = OCT_LIGHT + LO_SIZE
  42. };
  43. struct Decode
  44. {
  45. /*static constexpr*/ float e = static_cast<float>(E); // Static constexpr gives
  46. /*static constexpr*/ float s = 1.0f / e; // link error on Mac build.
  47. float in = 0; //!< Raw input.
  48. float out = 0; //!< Input quantized.
  49. int note = 0; //!< Integer note (offset midi note).
  50. int key = 0; //!< C, C#, D, D#, etc.
  51. int oct = 0; //!< Octave (C4 = 0).
  52. void step(float input)
  53. {
  54. int safe, fnote;
  55. in = input;
  56. fnote = std::floor(in * e + 0.5f);
  57. out = fnote * s;
  58. note = static_cast<int>(fnote);
  59. safe = note + (E * 1000); // push away from negative numbers
  60. key = safe % E;
  61. oct = (safe / E) - 1000;
  62. }
  63. };
  64. Decode input;
  65. //--------------------------------------------------------------------------------------------------------
  66. //! \brief Constructor.
  67. GtxModule_Octave_G1()
  68. :
  69. Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS)
  70. {}
  71. //--------------------------------------------------------------------------------------------------------
  72. //! \brief Step function.
  73. void step() override
  74. {
  75. // Clear all lights
  76. float leds[NUM_LIGHTS] = {};
  77. // Decode inputs and params
  78. input.step(inputs[VOCT_INPUT].value);
  79. for (std::size_t i=0; i<N; ++i)
  80. {
  81. outputs[i + NOTE_OUTPUT].value = input.out + i * input.s;
  82. }
  83. for (std::size_t i=0; i<M; ++i)
  84. {
  85. outputs[i + OCT_OUTPUT].value = (input.out - T) + i;
  86. }
  87. // Lights
  88. leds[KEY_LIGHT + input.key] = 1.0f;
  89. if (LO_BEGIN <= input.oct && input.oct <= LO_END)
  90. {
  91. leds[OCT_LIGHT + input.oct - LO_BEGIN] = 1.0f;
  92. }
  93. // Write output in one go, seems to prevent flicker
  94. for (std::size_t i=0; i<NUM_LIGHTS; ++i)
  95. {
  96. lights[i].value = leds[i];
  97. }
  98. }
  99. };
  100. static int x(std::size_t i, double radius) { return static_cast<int>(6*15 + 0.5 + radius * dx(i, E)); }
  101. static int y(std::size_t i, double radius) { return static_cast<int>(-20+206 + 0.5 + radius * dy(i, E)); }
  102. //============================================================================================================
  103. //! \brief The widget.
  104. struct GtxWidget_Octave_G1 : ModuleWidget
  105. {
  106. GtxWidget_Octave_G1(GtxModule_Octave_G1 *module) : ModuleWidget(module)
  107. {
  108. GTX__WIDGET();
  109. box.size = Vec(12*15, 380);
  110. // double r1 = 30;
  111. double r2 = 55;
  112. #if GTX__SAVE_SVG
  113. {
  114. PanelGen pg(assetPlugin(plugin, "build/res/Octave-G1.svg"), box.size, "OCTAVE-G1");
  115. pg.circle(Vec(x(0, 0), y(0, 0)), r2+16, "fill:#7092BE;stroke:none");
  116. pg.circle(Vec(x(0, 0), y(0, 0)), r2-16, "fill:#CEE1FD;stroke:none");
  117. /* // Wires
  118. for (std::size_t i=0; i<N; ++i)
  119. {
  120. pg.line(Vec(x(i, r1), y(i, r1)), Vec(x(i, r2), y(i, r2)), "stroke:#440022;stroke-width:1");
  121. if (i) { pg.line(Vec(x(i-1, r1), y(i-1, r1)), Vec(x(i, r1), y(i, r1)), "stroke:#440022;stroke-width:1"); }
  122. }
  123. */
  124. // Ports
  125. pg.circle(Vec(x(0, 0), y(0, 0)), 10, "stroke:#440022;stroke-width:1");
  126. for (std::size_t i=0; i<N; ++i)
  127. {
  128. pg.circle(Vec(x(i, r2), y(i, r2)), 10, "stroke:#440022;stroke-width:1");
  129. }
  130. pg.prt_out(-0.20, 2, "", "-2");
  131. pg.prt_out( 0.15, 2, "", "-1");
  132. pg.prt_out( 0.50, 2, "TRANSPOSE", "0");
  133. pg.prt_out( 0.85, 2, "", "+1");
  134. pg.prt_out( 1.20, 2, "", "+2");
  135. }
  136. #endif
  137. setPanel(SVG::load(assetPlugin(plugin, "res/Octave-G1.svg")));
  138. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  139. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  140. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  141. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  142. addInput(createInputGTX<PortInMed>(Vec(x(0, 0), y(0, 0)), module, GtxModule_Octave_G1::VOCT_INPUT));
  143. for (std::size_t i=0; i<N; ++i)
  144. {
  145. addOutput(createOutputGTX<PortOutMed>(Vec(x(i, r2), y(i, r2)), module, i + GtxModule_Octave_G1::NOTE_OUTPUT));
  146. }
  147. addOutput(createOutputGTX<PortOutMed>(Vec(gx(-0.20), gy(2)), module, 0 + GtxModule_Octave_G1::OCT_OUTPUT));
  148. addOutput(createOutputGTX<PortOutMed>(Vec(gx( 0.15), gy(2)), module, 1 + GtxModule_Octave_G1::OCT_OUTPUT));
  149. addOutput(createOutputGTX<PortOutMed>(Vec(gx( 0.50), gy(2)), module, 2 + GtxModule_Octave_G1::OCT_OUTPUT));
  150. addOutput(createOutputGTX<PortOutMed>(Vec(gx( 0.85), gy(2)), module, 3 + GtxModule_Octave_G1::OCT_OUTPUT));
  151. addOutput(createOutputGTX<PortOutMed>(Vec(gx( 1.20), gy(2)), module, 4 + GtxModule_Octave_G1::OCT_OUTPUT));
  152. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) - 30, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 0)); // C
  153. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) - 25, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 1)); // C#
  154. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) - 20, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 2)); // D
  155. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) - 15, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 3)); // Eb
  156. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) - 10, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 4)); // E
  157. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) , fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 5)); // F
  158. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 5, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 6)); // Fs
  159. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 10, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 7)); // G
  160. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 15, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 8)); // Ab
  161. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 20, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 9)); // A
  162. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 25, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 10)); // Bb
  163. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 30, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 11)); // B
  164. for (std::size_t i=0; i<LO_SIZE; ++i)
  165. {
  166. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + (i - LO_SIZE/2) * 10, fy(0-0.28) + 20), module, GtxModule_Octave_G1::OCT_LIGHT + i));
  167. }
  168. }
  169. };
  170. } // namespace rack_plugin_Gratrix
  171. using namespace rack_plugin_Gratrix;
  172. RACK_PLUGIN_MODEL_INIT(Gratrix, Octave_G1) {
  173. Model *model = Model::create<GtxModule_Octave_G1, GtxWidget_Octave_G1>("Gratrix", "Octave-G1", "Octave-G1", SYNTH_VOICE_TAG); // right tag?
  174. return model;
  175. }