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.

247 lines
8.0KB

  1. //***********************************************************************************************
  2. //Impromptu Modular: Modules for VCV Rack by Marc Boulé
  3. //
  4. //Based on code from the Fundamental and AudibleInstruments plugins by Andrew Belt
  5. //and graphics from the Component Library by Wes Milholen
  6. //See ./LICENSE.txt for all licenses
  7. //See ./res/fonts/ for font licenses
  8. //***********************************************************************************************
  9. #include "ImpromptuModular.hpp"
  10. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, BlankPanel);
  11. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, Foundry);
  12. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, FourView);
  13. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, Tact);
  14. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, Tact1);
  15. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, TwelveKey);
  16. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, Clocked);
  17. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, MidiFile);
  18. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, PhraseSeq16);
  19. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, PhraseSeq32);
  20. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, GateSeq64);
  21. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, WriteSeq32);
  22. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, WriteSeq64);
  23. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, BigButtonSeq);
  24. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, BigButtonSeq2);
  25. RACK_PLUGIN_MODEL_DECLARE(ImpromptuModular, SemiModularSynth);
  26. RACK_PLUGIN_INIT(ImpromptuModular) {
  27. RACK_PLUGIN_INIT_ID();
  28. RACK_PLUGIN_INIT_VERSION("0.6.16");
  29. RACK_PLUGIN_INIT_WEBSITE("https://github.com/MarcBoule/ImpromptuModular");
  30. RACK_PLUGIN_INIT_MANUAL("https://github.com/MarcBoule/ImpromptuModular");
  31. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, BlankPanel);
  32. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, Foundry);
  33. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, FourView);
  34. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, Tact);
  35. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, Tact1);
  36. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, TwelveKey);
  37. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, Clocked);
  38. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, MidiFile);
  39. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, PhraseSeq16);
  40. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, PhraseSeq32);
  41. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, GateSeq64);
  42. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, WriteSeq32);
  43. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, WriteSeq64);
  44. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, BigButtonSeq);
  45. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, BigButtonSeq2);
  46. RACK_PLUGIN_MODEL_ADD(ImpromptuModular, SemiModularSynth);
  47. }
  48. void IMBigPushButtonWithRClick::onMouseDown(EventMouseDown &e) {
  49. if (e.button == 1) {// if right button (see events.hpp)
  50. maxValue = 2.0f;
  51. // Simulate MomentarySwitch::onDragStart() since not called for right clicks:
  52. setValue(maxValue);
  53. EventAction eAction;
  54. onAction(eAction);
  55. }
  56. else
  57. maxValue = 1.0f;
  58. //ParamWidget::onMouseDown(e);// don't want the reset() that is called in ParamWidget::onMouseDown(), so implement rest of that function here:
  59. e.consumed = true;
  60. e.target = this;
  61. }
  62. void IMBigPushButtonWithRClick::onMouseUp(EventMouseUp &e) {
  63. if (e.button == 1) {// if right button (see events.hpp)
  64. // Simulate MomentarySwitch::onDragEnd() since not called for right clicks:
  65. setValue(minValue);
  66. }
  67. ParamWidget::onMouseUp(e);
  68. }
  69. LEDBezelBig::LEDBezelBig() {
  70. float ratio = 2.13f;
  71. addFrame(SVG::load(assetGlobal("res/ComponentLibrary/LEDBezel.svg")));
  72. sw->box.size = sw->box.size.mult(ratio);
  73. box.size = sw->box.size;
  74. tw = new TransformWidget();
  75. removeChild(sw);
  76. tw->addChild(sw);
  77. addChild(tw);
  78. tw->box.size = sw->box.size;
  79. tw->scale(Vec(ratio, ratio));
  80. }
  81. void InvisibleKeySmall::onMouseDown(EventMouseDown &e) {
  82. if (e.button == 1) {// if right button (see events.hpp)
  83. maxValue = 2.0f;
  84. // Simulate MomentarySwitch::onDragStart() since not called for right clicks:
  85. setValue(maxValue);
  86. EventAction eAction;
  87. onAction(eAction);
  88. }
  89. else
  90. maxValue = 1.0f;
  91. //ParamWidget::onMouseDown(e);// don't want the reset() that is called in ParamWidget::onMouseDown(), so implement rest of that function here:
  92. e.consumed = true;
  93. e.target = this;
  94. }
  95. void InvisibleKeySmall::onMouseUp(EventMouseUp &e) {
  96. if (e.button == 1) {// if right button (see events.hpp)
  97. // Simulate MomentarySwitch::onDragEnd() since not called for right clicks:
  98. setValue(minValue);
  99. }
  100. ParamWidget::onMouseUp(e);
  101. }
  102. void LEDButtonWithRClick::onMouseDown(EventMouseDown &e) {
  103. if (e.button == 1) {// if right button (see events.hpp)
  104. maxValue = 2.0f;
  105. // Simulate MomentarySwitch::onDragStart() since not called for right clicks:
  106. setValue(maxValue);
  107. EventAction eAction;
  108. onAction(eAction);
  109. }
  110. else
  111. maxValue = 1.0f;
  112. //ParamWidget::onMouseDown(e);// don't want the reset() that is called in ParamWidget::onMouseDown(), so implement rest of that function here:
  113. e.consumed = true;
  114. e.target = this;
  115. }
  116. void LEDButtonWithRClick::onMouseUp(EventMouseUp &e) {
  117. if (e.button == 1) {// if right button (see events.hpp)
  118. // Simulate MomentarySwitch::onDragEnd() since not called for right clicks:
  119. setValue(minValue);
  120. }
  121. ParamWidget::onMouseUp(e);
  122. }
  123. ScrewSilverRandomRot::ScrewSilverRandomRot() {
  124. float angle0_90 = randomUniform()*M_PI/2.0f;
  125. //float angle0_90 = randomUniform() > 0.5f ? M_PI/4.0f : 0.0f;// for testing
  126. tw = new TransformWidget();
  127. addChild(tw);
  128. sw = new SVGWidget();
  129. tw->addChild(sw);
  130. //sw->setSVG(SVG::load(assetPlugin(plugin, "res/Screw0.svg")));
  131. sw->setSVG(SVG::load(assetGlobal("res/ComponentLibrary/ScrewSilver.svg")));
  132. sc = new ScrewCircle(angle0_90);
  133. sc->box.size = sw->box.size;
  134. tw->addChild(sc);
  135. box.size = sw->box.size;
  136. tw->box.size = sw->box.size;
  137. tw->identity();
  138. // Rotate SVG
  139. Vec center = sw->box.getCenter();
  140. tw->translate(center);
  141. tw->rotate(angle0_90);
  142. tw->translate(center.neg());
  143. }
  144. ScrewHole::ScrewHole(Vec posGiven) {
  145. box.size = Vec(16, 7);
  146. box.pos = Vec(posGiven.x, posGiven.y + 4);// nudgeX for realism, 0 = no nudge
  147. }
  148. void ScrewHole::draw(NVGcontext *vg) {
  149. NVGcolor backgroundColor = nvgRGB(0x10, 0x10, 0x10);
  150. NVGcolor borderColor = nvgRGB(0x20, 0x20, 0x20);
  151. nvgBeginPath(vg);
  152. nvgRoundedRect(vg, 0.0, 0.0, box.size.x, box.size.y, 2.5f);
  153. nvgFillColor(vg, backgroundColor);
  154. nvgFill(vg);
  155. nvgStrokeWidth(vg, 1.0);
  156. nvgStrokeColor(vg, borderColor);
  157. nvgStroke(vg);
  158. }
  159. NVGcolor prepareDisplay(NVGcontext *vg, Rect *box, int fontSize) {
  160. NVGcolor backgroundColor = nvgRGB(0x38, 0x38, 0x38);
  161. NVGcolor borderColor = nvgRGB(0x10, 0x10, 0x10);
  162. nvgBeginPath(vg);
  163. nvgRoundedRect(vg, 0.0, 0.0, box->size.x, box->size.y, 5.0);
  164. nvgFillColor(vg, backgroundColor);
  165. nvgFill(vg);
  166. nvgStrokeWidth(vg, 1.0);
  167. nvgStrokeColor(vg, borderColor);
  168. nvgStroke(vg);
  169. nvgFontSize(vg, fontSize);
  170. NVGcolor textColor = nvgRGB(0xaf, 0xd2, 0x2c);
  171. return textColor;
  172. }
  173. void printNote(float cvVal, char* text, bool sharp) {// text must be at least 4 chars long (three displayed chars plus end of string)
  174. static const char noteLettersSharp[12] = {'C', 'C', 'D', 'D', 'E', 'F', 'F', 'G', 'G', 'A', 'A', 'B'};
  175. static const char noteLettersFlat [12] = {'C', 'D', 'D', 'E', 'E', 'F', 'G', 'G', 'A', 'A', 'B', 'B'};
  176. static const char isBlackKey [12] = { 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0 };
  177. float cvValOffset = cvVal + 10.0f;// to properly handle negative note voltages
  178. int indexNote = clamp( (int)((cvValOffset-floor(cvValOffset)) * 12.0f + 0.5f), 0, 11);
  179. // note letter
  180. text[0] = sharp ? noteLettersSharp[indexNote] : noteLettersFlat[indexNote];
  181. // octave number
  182. int octave = (int) roundf(floorf(cvVal)+4.0f);
  183. if (octave < 0 || octave > 9)
  184. text[1] = (octave > 9) ? ':' : '_';
  185. else
  186. text[1] = (char) ( 0x30 + octave);
  187. // sharp/flat
  188. text[2] = ' ';
  189. if (isBlackKey[indexNote] == 1)
  190. text[2] = (sharp ? '\"' : 'b' );
  191. text[3] = 0;
  192. }
  193. int moveIndex(int index, int indexNext, int numSteps) {
  194. if (indexNext < 0)
  195. index = numSteps - 1;
  196. else
  197. {
  198. if (indexNext - index >= 0) { // if moving right or same place
  199. if (indexNext >= numSteps)
  200. index = 0;
  201. else
  202. index = indexNext;
  203. }
  204. else { // moving left
  205. if (indexNext >= numSteps)
  206. index = numSteps - 1;
  207. else
  208. index = indexNext;
  209. }
  210. }
  211. return index;
  212. }