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.

214 lines
6.2KB

  1. #include "pwmClock.hpp"
  2. namespace rack_plugin_TheXOR {
  3. #define BPM_MINVALUE (10)
  4. #define BPM_MAXVALUE (300)
  5. #define PWM_MINVALUE (0.05)
  6. #define PWM_MAXVALUE (0.95)
  7. #define SWING_MINVALUE (0.0)
  8. #define SWING_MAXVALUE (0.5)
  9. void PwmClock::on_loaded()
  10. {
  11. bpm = 0;
  12. swing = 0;
  13. _reset();
  14. load();
  15. }
  16. void PwmClock::_reset()
  17. {
  18. for(int k = 0; k < OUT_SOCKETS; k++)
  19. {
  20. sa_timer[k].Reset();
  21. odd_beat[k] = false;
  22. }
  23. }
  24. void PwmClock::load()
  25. {
  26. updateBpm();
  27. }
  28. void PwmClock::updateBpm()
  29. {
  30. bool updated = false;
  31. float new_bpm;
  32. if(inputs[EXT_BPM].active)
  33. new_bpm = rescale(inputs[EXT_BPM].value, LVL_OFF, LVL_ON, BPM_MINVALUE, BPM_MAXVALUE);
  34. else
  35. new_bpm = (roundf(params[BPMDEC].value) + 10 * bpm_integer) / 10.0;
  36. if(bpm != new_bpm)
  37. {
  38. updated = true;
  39. bpm = new_bpm;
  40. duration[0] = 240.0 / bpm; // 1/1
  41. duration[1] = duration[0] + duration[0] / 2.0;
  42. duration[2] = 2.0* duration[0] / 3.0;
  43. for(int k = 1; k < 7; k++)
  44. {
  45. duration[3 * k] = duration[3 * (k - 1)] / 2.0;
  46. duration[3 * k + 1] = duration[3 * (k - 1) + 1] / 2.0;
  47. duration[3 * k + 2] = duration[3 * (k - 1) + 2] / 2.0;
  48. }
  49. }
  50. float new_swing = getSwing();
  51. if(updated || new_swing != swing)
  52. {
  53. swing = new_swing;
  54. for(int k = 0; k < OUT_SOCKETS; k++)
  55. swingAmt[k] = duration[k] + duration[k] * swing;
  56. }
  57. }
  58. void PwmClock::process_keys()
  59. {
  60. if(btnup.process(params[BPM_INC].value))
  61. {
  62. if(bpm_integer < BPM_MAXVALUE)
  63. bpm_integer += 1;
  64. pWidget->SetBpm(bpm_integer);
  65. }
  66. if(btndwn.process(params[BPM_DEC].value))
  67. {
  68. if(bpm_integer > 0)
  69. bpm_integer -= 1;
  70. pWidget->SetBpm(bpm_integer);
  71. }
  72. }
  73. void PwmClock::step()
  74. {
  75. process_keys();
  76. bpm_integer = roundf(params[BPM].value);
  77. updateBpm();
  78. if((params[OFFON].value + inputs[OFFON_IN].value) > 0.5)
  79. {
  80. lights[ACTIVE].value = LVL_ON;
  81. if(resetTrigger.process(inputs[RESET].value))
  82. {
  83. _reset();
  84. } else
  85. {
  86. for(int k = 0; k < OUT_SOCKETS; k++)
  87. {
  88. float gate_len = getDuration(k) * getPwm();
  89. sa_timer[k].Step();
  90. float elps = sa_timer[k].Elapsed();
  91. if(elps >= getDuration(k))
  92. {
  93. elps = sa_timer[k].Reset();
  94. odd_beat[k] = !odd_beat[k];
  95. }
  96. if(elps <= gate_len)
  97. outputs[OUT_1 + k].value = LVL_ON;
  98. else
  99. outputs[OUT_1 + k].value = LVL_OFF;
  100. }
  101. }
  102. } else
  103. {
  104. for(int k = 0; k < OUT_SOCKETS; k++)
  105. {
  106. outputs[OUT_1 + k].value = LVL_OFF;
  107. }
  108. lights[ACTIVE].value = LVL_OFF;
  109. }
  110. }
  111. float PwmClock::getPwm()
  112. {
  113. float offs = inputs[PWM_IN].active ? rescale(inputs[PWM_IN].value, 0.0, 5.0, PWM_MINVALUE, PWM_MAXVALUE) : 0.0;
  114. return clamp(offs + params[PWM].value, PWM_MINVALUE, PWM_MAXVALUE);
  115. }
  116. float PwmClock::getSwing()
  117. {
  118. float offs = inputs[SWING_IN].active ? rescale(inputs[SWING_IN].value, 0.0, 5.0, SWING_MINVALUE, SWING_MAXVALUE) : 0.0;
  119. return clamp(offs + params[SWING].value, SWING_MINVALUE, SWING_MAXVALUE);
  120. }
  121. PwmClockWidget::PwmClockWidget(PwmClock *module) : SequencerWidget(module)
  122. {
  123. module->setWidget(this);
  124. box.size = Vec(15 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
  125. {
  126. SVGPanel *panel = new SVGPanel();
  127. panel->box.size = box.size;
  128. panel->setBackground(SVG::load(assetPlugin(plugin, "res/modules/PwmClock.svg")));
  129. addChild(panel);
  130. }
  131. addChild(Widget::create<ScrewBlack>(Vec(15, 0)));
  132. addChild(Widget::create<ScrewBlack>(Vec(box.size.x - 30, 0)));
  133. addChild(Widget::create<ScrewBlack>(Vec(15, 365)));
  134. addChild(Widget::create<ScrewBlack>(Vec(box.size.x - 30, 365)));
  135. addParam(ParamWidget::create<UPSWITCH>(Vec(mm2px(7.572), yncscape(104.588,4.115)), module, PwmClock::BPM_INC, 0.0, 1.0, 0.0));
  136. addParam(ParamWidget::create<DNSWITCH>(Vec(mm2px(7.572), yncscape(99.788, 4.115)), module, PwmClock::BPM_DEC, 0.0, 1.0, 0.0));
  137. SigDisplayWidget *display = new SigDisplayWidget(4, 1);
  138. display->box.pos = Vec(mm2px(20), RACK_GRID_HEIGHT-mm2px(108));
  139. display->box.size = Vec(30+53, 24);
  140. display->value = &module->bpm;
  141. addChild(display);
  142. ParamWidget *pw = ParamWidget::create<Davies1900hFixWhiteKnobSmall>(Vec(mm2px(50.364), yncscape(100.245, 8)), module, PwmClock::BPMDEC, 0.0, 9.0, 0.0);
  143. ((Davies1900hKnob *)pw)->snap = true;
  144. addParam(pw);
  145. pw = ParamWidget::create<Davies1900hFixWhiteKnob>(Vec(mm2px(62.528), yncscape(99.483, 9.525)), module, PwmClock::BPM, BPM_MINVALUE, BPM_MAXVALUE, 120.0);
  146. ((Davies1900hKnob *)pw)->snap = true;
  147. addParam(pw);
  148. addInput(Port::create<PJ301BPort>(Vec(mm2px(50.326), yncscape(86.857, 8.255)), Port::INPUT, module, PwmClock::EXT_BPM));
  149. addInput(Port::create<PJ301YPort>(Vec(mm2px(63.162), yncscape(86.857, 8.255)), Port::INPUT, module, PwmClock::RESET));
  150. addParam(ParamWidget::create<NKK2>(Vec(mm2px(49.040), yncscape(64.997, 9.488)), module, PwmClock::OFFON, 0.0, 1.0, 0.0));
  151. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(mm2px(59.141), yncscape(67.715, 2.176)), module, PwmClock::ACTIVE));
  152. addInput(Port::create<PJ301BPort>(Vec(mm2px(63.162), yncscape(64.675, 8.255)), Port::INPUT, module, PwmClock::OFFON_IN));
  153. addParam(ParamWidget::create<Davies1900hFixRedKnob>(Vec(mm2px(48.511), yncscape(42.040, 9.525)), module, PwmClock::SWING, SWING_MINVALUE, SWING_MAXVALUE, SWING_MINVALUE));
  154. addInput(Port::create<PJ301BPort>(Vec(mm2px(63.162), yncscape(42.675, 8.255)), Port::INPUT, module, PwmClock::SWING_IN));
  155. addParam(ParamWidget::create<Davies1900hFixBlackKnob>(Vec(mm2px(48.511), yncscape(20.040, 9.525)), module, PwmClock::PWM, PWM_MINVALUE, PWM_MAXVALUE, 0.5));
  156. addInput(Port::create<PJ301BPort>(Vec(mm2px(63.162), yncscape(20.675, 8.255)), Port::INPUT, module, PwmClock::PWM_IN));
  157. float col_x[3] = {7.875, 21.633, 35.392};
  158. float pos_y = yncscape(70.175, 8.255);
  159. int col = 0;
  160. for(int k = 0; k < OUT_SOCKETS; k++)
  161. {
  162. addOutput(Port::create<PJ301OPort>(Vec(mm2px(col_x[col]), pos_y), Port::OUTPUT, module, PwmClock::OUT_1 + k));
  163. if(++col >= 3)
  164. {
  165. col = 0;
  166. pos_y += mm2px(11);
  167. }
  168. }
  169. }
  170. void PwmClockWidget::SetBpm(float bpm_integer)
  171. {
  172. int index = getParamIndex(PwmClock::BPM);
  173. if(index >= 0)
  174. {
  175. // VCV interface update is ahem.... migliorabile....
  176. bool smooth = params[index]->smooth;
  177. params[index]->smooth = false;
  178. params[index]->setValue((double)bpm_integer);
  179. params[index]->smooth = smooth;
  180. }
  181. }
  182. } // namespace rack_plugin_TheXOR
  183. using namespace rack_plugin_TheXOR;
  184. RACK_PLUGIN_MODEL_INIT(TheXOR, PwmClock) {
  185. return Model::create<PwmClock, PwmClockWidget>("TheXOR", "PWMClock", "PWM Clock", CLOCK_TAG);
  186. }