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.

315 lines
8.9KB

  1. ///////////////////////////////////////////////////
  2. //
  3. // Master Clock Module
  4. // VCV Module
  5. //
  6. // Strum 2017
  7. //
  8. ///////////////////////////////////////////////////
  9. #include "mental.hpp"
  10. #include "dsp/digital.hpp"
  11. #include <sstream>
  12. #include <iomanip>
  13. namespace rack_plugin_mental {
  14. struct LFOGenerator {
  15. float phase = 0.0;
  16. float pw = 0.5;
  17. float freq = 1.0;
  18. void setFreq(float freq_to_set)
  19. {
  20. freq = freq_to_set;
  21. }
  22. void step(float dt) {
  23. float deltaPhase = fminf(freq * dt, 0.5);
  24. phase += deltaPhase;
  25. if (phase >= 1.0)
  26. phase -= 1.0;
  27. }
  28. float sqr() {
  29. float sqr = phase < pw ? 1.0 : -1.0;
  30. return sqr;
  31. }
  32. };
  33. struct MentalMasterClock : Module {
  34. enum ParamIds {
  35. TEMPO_PARAM,
  36. TIMESIGTOP_PARAM,
  37. TIMESIGBOTTOM_PARAM,
  38. RESET_BUTTON,
  39. RUN_SWITCH,
  40. NUM_PARAMS
  41. };
  42. enum InputIds {
  43. NUM_INPUTS
  44. };
  45. enum OutputIds {
  46. BEAT_OUT,
  47. EIGHTHS_OUT,
  48. SIXTEENTHS_OUT,
  49. BAR_OUT,
  50. NUM_OUTPUTS
  51. };
  52. enum LightIds {
  53. RESET_LED,
  54. RUN_LED,
  55. NUM_LIGHTS
  56. };
  57. LFOGenerator clock;
  58. SchmittTrigger eighths_trig;
  59. SchmittTrigger quarters_trig;
  60. SchmittTrigger bars_trig;
  61. SchmittTrigger run_button_trig;
  62. bool running = true;
  63. int eighths_count = 0;
  64. int quarters_count = 0;
  65. int bars_count = 0;
  66. int tempo, time_sig_top, time_sig_bottom = 0;
  67. float frequency = 2.0;
  68. int quarters_count_limit = 4;
  69. int eighths_count_limit = 2;
  70. int bars_count_limit = 16;
  71. MentalMasterClock();
  72. void step() override;
  73. json_t *toJson() override
  74. {
  75. json_t *rootJ = json_object();
  76. json_t *button_statesJ = json_array();
  77. json_t *button_stateJ = json_integer((int)running);
  78. json_array_append_new(button_statesJ, button_stateJ);
  79. json_object_set_new(rootJ, "run", button_statesJ);
  80. return rootJ;
  81. }
  82. void fromJson(json_t *rootJ) override
  83. {
  84. json_t *button_statesJ = json_object_get(rootJ, "run");
  85. if (button_statesJ)
  86. {
  87. json_t *button_stateJ = json_array_get(button_statesJ,0);
  88. if (button_stateJ)
  89. running = !!json_integer_value(button_stateJ);
  90. }
  91. }
  92. };
  93. /////////////////////////////////////////////////////////////////////////
  94. MentalMasterClock::MentalMasterClock()
  95. {
  96. params.resize(NUM_PARAMS);
  97. inputs.resize(NUM_INPUTS);
  98. outputs.resize(NUM_OUTPUTS);
  99. lights.resize(NUM_LIGHTS);
  100. }
  101. void MentalMasterClock::step()
  102. {
  103. if (run_button_trig.process(params[RUN_SWITCH].value))
  104. {
  105. running = !running;
  106. }
  107. lights[RUN_LED].value = running ? 1.0 : 0.0;
  108. tempo = std::round(params[TEMPO_PARAM].value);
  109. time_sig_top = std::round(params[TIMESIGTOP_PARAM].value);
  110. time_sig_bottom = std::round(params[TIMESIGBOTTOM_PARAM].value);
  111. time_sig_bottom = std::pow(2,time_sig_bottom+1);
  112. frequency = tempo/60.0;
  113. if (params[RESET_BUTTON].value > 0.0)
  114. {
  115. eighths_count = 0;
  116. quarters_count = 0;
  117. bars_count = 0;
  118. lights[RESET_LED].value = 1.0;
  119. } else lights[RESET_LED].value = 0.0;
  120. if (!running)
  121. {
  122. eighths_count = 0;
  123. quarters_count = 0;
  124. bars_count = 0;
  125. outputs[BAR_OUT].value = 0.0;
  126. outputs[BEAT_OUT].value = 0.0;
  127. outputs[EIGHTHS_OUT].value = 0.0;
  128. outputs[SIXTEENTHS_OUT].value = 0.0;
  129. } else
  130. {
  131. if (time_sig_top == time_sig_bottom)
  132. {
  133. clock.setFreq(frequency*4);
  134. quarters_count_limit = 4;
  135. eighths_count_limit = 2;
  136. bars_count_limit = 16;
  137. } else
  138. {
  139. if (time_sig_bottom == 4)
  140. {
  141. quarters_count_limit = 4;
  142. eighths_count_limit = 2;
  143. bars_count_limit = time_sig_top * 4;
  144. clock.setFreq(frequency*4);
  145. }
  146. if (time_sig_bottom == 8)
  147. {
  148. quarters_count_limit = 4;
  149. eighths_count_limit = 2;
  150. bars_count_limit = time_sig_top * 2;
  151. clock.setFreq(frequency*4);
  152. if ((time_sig_top % 3) == 0)
  153. {
  154. quarters_count_limit = 6;
  155. eighths_count_limit = 2;
  156. bars_count_limit = (time_sig_top/3) * 6;
  157. clock.setFreq(frequency*6);
  158. }
  159. }
  160. }
  161. clock.step(1.0 / engineGetSampleRate());
  162. outputs[SIXTEENTHS_OUT].value = 5.0 * clock.sqr();
  163. if (eighths_trig.process(clock.sqr()) && eighths_count <= eighths_count_limit)
  164. eighths_count++;
  165. if (eighths_count >= eighths_count_limit)
  166. {
  167. eighths_count = 0;
  168. }
  169. if (eighths_count == 0) outputs[EIGHTHS_OUT].value = 5.0;
  170. else outputs[EIGHTHS_OUT].value = 0.0;
  171. if (quarters_trig.process(clock.sqr()) && quarters_count <= quarters_count_limit)
  172. quarters_count++;
  173. if (quarters_count >= quarters_count_limit)
  174. {
  175. quarters_count = 0;
  176. }
  177. if (quarters_count == 0) outputs[BEAT_OUT].value = 5.0;
  178. else outputs[BEAT_OUT].value = 0.0;
  179. if (bars_trig.process(clock.sqr()) && bars_count <= bars_count_limit)
  180. bars_count++;
  181. if (bars_count >= bars_count_limit)
  182. {
  183. bars_count = 0;
  184. }
  185. if (bars_count == 0) outputs[BAR_OUT].value = 5.0;
  186. else outputs[BAR_OUT].value = 0.0;
  187. }
  188. }
  189. ////////////////////////////////////
  190. struct NumberDisplayWidget2 : TransparentWidget {
  191. int *value;
  192. std::shared_ptr<Font> font;
  193. NumberDisplayWidget2() {
  194. font = Font::load(assetPlugin(plugin, "res/Segment7Standard.ttf"));
  195. };
  196. void draw(NVGcontext *vg) override
  197. {
  198. // Background
  199. NVGcolor backgroundColor = nvgRGB(0x00, 0x00, 0x00);
  200. NVGcolor StrokeColor = nvgRGB(0x00, 0x47, 0x7e);
  201. nvgBeginPath(vg);
  202. nvgRoundedRect(vg, -1.0, -1.0, box.size.x+2, box.size.y+2, 4.0);
  203. nvgFillColor(vg, StrokeColor);
  204. nvgFill(vg);
  205. nvgBeginPath(vg);
  206. nvgRoundedRect(vg, 0.0, 0.0, box.size.x, box.size.y, 4.0);
  207. nvgFillColor(vg, backgroundColor);
  208. nvgFill(vg);
  209. // text
  210. nvgFontSize(vg, 18);
  211. nvgFontFaceId(vg, font->handle);
  212. nvgTextLetterSpacing(vg, 2.5);
  213. std::stringstream to_display;
  214. to_display << std::setw(3) << *value;
  215. Vec textPos = Vec(6.0f, 17.0f);
  216. NVGcolor textColor = nvgRGB(0x00, 0x47, 0x7e);
  217. nvgFillColor(vg, textColor);
  218. nvgText(vg, textPos.x, textPos.y, to_display.str().c_str(), NULL);
  219. }
  220. };
  221. //////////////////////////////////
  222. struct MentalMasterClockWidget : ModuleWidget {
  223. MentalMasterClockWidget(MentalMasterClock *module);
  224. };
  225. MentalMasterClockWidget::MentalMasterClockWidget(MentalMasterClock *module) : ModuleWidget(module)
  226. {
  227. setPanel(SVG::load(assetPlugin(plugin, "res/MentalMasterClock.svg")));
  228. addParam(ParamWidget::create<MedKnob>(Vec(2, 20), module, MentalMasterClock::TEMPO_PARAM, 40.0, 250.0, 120.0));
  229. addParam(ParamWidget::create<MedKnob>(Vec(2, 50), module, MentalMasterClock::TIMESIGTOP_PARAM,2.0, 15.0, 4.0));
  230. addParam(ParamWidget::create<MedKnob>(Vec(2, 80), module, MentalMasterClock::TIMESIGBOTTOM_PARAM,0.0, 3.0, 1.0));
  231. addOutput(Port::create<GateOutPort>(Vec(90, 110), Port::OUTPUT, module, MentalMasterClock::BEAT_OUT));
  232. addOutput(Port::create<GateOutPort>(Vec(90, 140), Port::OUTPUT, module, MentalMasterClock::BAR_OUT));
  233. addOutput(Port::create<GateOutPort>(Vec(90, 170), Port::OUTPUT, module, MentalMasterClock::EIGHTHS_OUT));
  234. addOutput(Port::create<GateOutPort>(Vec(90, 200), Port::OUTPUT, module, MentalMasterClock::SIXTEENTHS_OUT));
  235. /* addParam(ParamWidget::create<LEDButton>(Vec(5, 50+group_offset*i), module, MentalMasterClock::STEP_SWITCH + i, 0.0, 1.0, 0.0));
  236. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(10, 55+group_offset*i), &module->button_leds[0][i]));
  237. addParam(ParamWidget::create<LEDButton>(Vec(5, 75+group_offset*i), module, MentalMasterClock::BI_SWITCH + i, 0.0, 1.0, 0.0));
  238. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(10, 80+group_offset*i), &module->button_leds[2][i])); */
  239. //addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(Vec(33, 125), module, MentalClockDivider::LIGHTS));
  240. addParam(ParamWidget::create<LEDButton>(Vec(5, 140), module, MentalMasterClock::RESET_BUTTON, 0.0, 1.0, 0.0));
  241. addChild(ModuleLightWidget::create<MedLight<BlueLED>>(Vec(10, 145), module, MentalMasterClock::RESET_LED));
  242. addParam(ParamWidget::create<LEDButton>(Vec(5, 110), module, MentalMasterClock::RUN_SWITCH, 0.0, 1.0, 0.0));
  243. addChild(ModuleLightWidget::create<MedLight<BlueLED>>(Vec(10, 115), module, MentalMasterClock::RUN_LED));
  244. NumberDisplayWidget2 *display = new NumberDisplayWidget2();
  245. display->box.pos = Vec(35,20);
  246. display->box.size = Vec(50, 20);
  247. display->value = &module->tempo;
  248. addChild(display);
  249. NumberDisplayWidget2 *display2 = new NumberDisplayWidget2();
  250. display2->box.pos = Vec(35,50);
  251. display2->box.size = Vec(50, 20);
  252. display2->value = &module->time_sig_top;
  253. addChild(display2);
  254. NumberDisplayWidget2 *display3 = new NumberDisplayWidget2();
  255. display3->box.pos = Vec(35,80);
  256. display3->box.size = Vec(50, 20);
  257. display3->value = &module->time_sig_bottom;
  258. addChild(display3);
  259. }
  260. } // namespace rack_plugin_mental
  261. using namespace rack_plugin_mental;
  262. RACK_PLUGIN_MODEL_INIT(mental, MentalMasterClock) {
  263. Model *modelMentalMasterClock = Model::create<MentalMasterClock, MentalMasterClockWidget>("mental", "MentalMasterClock", "Master Clock", CLOCK_TAG);
  264. return modelMentalMasterClock;
  265. }