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.

275 lines
8.0KB

  1. #include "HetrickCV.hpp"
  2. namespace rack_plugin_HetrickCV {
  3. struct DigitalToAnalog : Module
  4. {
  5. enum ParamIds
  6. {
  7. SCALE_PARAM,
  8. OFFSET_PARAM,
  9. MODE_PARAM,
  10. RECTIFY_PARAM,
  11. NUM_PARAMS
  12. };
  13. enum InputIds
  14. {
  15. IN1_INPUT,
  16. IN2_INPUT,
  17. IN3_INPUT,
  18. IN4_INPUT,
  19. IN5_INPUT,
  20. IN6_INPUT,
  21. IN7_INPUT,
  22. IN8_INPUT,
  23. SYNC_INPUT,
  24. NUM_INPUTS
  25. };
  26. enum OutputIds
  27. {
  28. MAIN_OUTPUT,
  29. NUM_OUTPUTS
  30. };
  31. enum LightIds
  32. {
  33. IN1_LIGHT,
  34. IN2_LIGHT,
  35. IN3_LIGHT,
  36. IN4_LIGHT,
  37. IN5_LIGHT,
  38. IN6_LIGHT,
  39. IN7_LIGHT,
  40. IN8_LIGHT,
  41. RECT_NONE_LIGHT,
  42. RECT_HALF_LIGHT,
  43. RECT_FULL_LIGHT,
  44. MODE_UNI8_LIGHT,
  45. MODE_BOFF_LIGHT,
  46. MODE_BSIG_LIGHT,
  47. OUT_POS_LIGHT, OUT_NEG_LIGHT,
  48. NUM_LIGHTS
  49. };
  50. SchmittTrigger clockTrigger;
  51. SchmittTrigger modeTrigger;
  52. SchmittTrigger rectTrigger;
  53. int mode = 0;
  54. int rectMode = 0;
  55. float mainOutput = 0.0f;
  56. bool ins[8] = {};
  57. DigitalToAnalog() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS)
  58. {
  59. }
  60. void step() override;
  61. void processUni8();
  62. void processBiOff();
  63. void processBiSig();
  64. void reset() override
  65. {
  66. mode = 0;
  67. rectMode = 0;
  68. }
  69. void randomize() override
  70. {
  71. mode = round(randomf() * 2.0f);
  72. rectMode = round(randomf() * 2.0f);
  73. }
  74. json_t *toJson() override
  75. {
  76. json_t *rootJ = json_object();
  77. json_object_set_new(rootJ, "mode", json_integer(mode));
  78. json_object_set_new(rootJ, "rectMode", json_integer(rectMode));
  79. return rootJ;
  80. }
  81. void fromJson(json_t *rootJ) override
  82. {
  83. json_t *modeJ = json_object_get(rootJ, "mode");
  84. if (modeJ)
  85. mode = json_integer_value(modeJ);
  86. json_t *rectModeJ = json_object_get(rootJ, "rectMode");
  87. if (rectModeJ)
  88. rectMode = json_integer_value(rectModeJ);
  89. }
  90. // For more advanced Module features, read Rack's engine.hpp header file
  91. // - toJson, fromJson: serialization of internal data
  92. // - onSampleRateChange: event triggered by a change of sample rate
  93. // - reset, randomize: implements special behavior when user clicks these from the context menu
  94. };
  95. void DigitalToAnalog::step()
  96. {
  97. if (modeTrigger.process(params[MODE_PARAM].value)) mode = (mode + 1) % 3;
  98. if (rectTrigger.process(params[RECTIFY_PARAM].value)) rectMode = (rectMode + 1) % 3;
  99. lights[MODE_UNI8_LIGHT].setBrightness(mode == 0 ? 1.0f : 0.0f);
  100. lights[MODE_BOFF_LIGHT].setBrightness(mode == 1 ? 1.0f : 0.0f);
  101. lights[MODE_BSIG_LIGHT].setBrightness(mode == 2 ? 1.0f : 0.0f);
  102. lights[RECT_NONE_LIGHT].setBrightness(rectMode == 0 ? 1.0f : 0.0f);
  103. lights[RECT_HALF_LIGHT].setBrightness(rectMode == 1 ? 1.0f : 0.0f);
  104. lights[RECT_FULL_LIGHT].setBrightness(rectMode == 2 ? 1.0f : 0.0f);
  105. const bool syncModeEnabled = inputs[SYNC_INPUT].active;
  106. const bool readyForProcess = (!syncModeEnabled || (syncModeEnabled && clockTrigger.process(inputs[SYNC_INPUT].value)));
  107. if(readyForProcess)
  108. {
  109. mainOutput = 0.0f;
  110. for(int i = 0; i < 8; i++)
  111. {
  112. ins[i] = inputs[IN1_INPUT + i].value > 1.0f;
  113. lights[IN1_LIGHT + i].value = ins[i] ? 1.0f : 0.0f;
  114. }
  115. if(mode == 0) processUni8();
  116. else if (mode == 1) processBiOff();
  117. else if (mode == 2) processBiSig();
  118. mainOutput *= 5.0f;
  119. if (rectMode == 1) mainOutput = mainOutput > 0.0f ? mainOutput : 0.0f;
  120. else if (rectMode == 2) mainOutput = std::abs(mainOutput);
  121. mainOutput *= params[SCALE_PARAM].value;
  122. mainOutput += params[OFFSET_PARAM].value;
  123. lights[OUT_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0, mainOutput * 0.2f));
  124. lights[OUT_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0, mainOutput * 0.2f));
  125. outputs[MAIN_OUTPUT].value = mainOutput;
  126. }
  127. }
  128. void DigitalToAnalog::processUni8()
  129. {
  130. if(ins[0]) mainOutput += 1.0f;
  131. if(ins[1]) mainOutput += 2.0f;
  132. if(ins[2]) mainOutput += 4.0f;
  133. if(ins[3]) mainOutput += 8.0f;
  134. if(ins[4]) mainOutput += 16.0f;
  135. if(ins[5]) mainOutput += 32.0f;
  136. if(ins[6]) mainOutput += 64.0f;
  137. if(ins[7]) mainOutput += 128.0f;
  138. mainOutput = mainOutput/255.0f;
  139. }
  140. void DigitalToAnalog::processBiOff()
  141. {
  142. if(ins[0]) mainOutput += 1.0f;
  143. if(ins[1]) mainOutput += 2.0f;
  144. if(ins[2]) mainOutput += 4.0f;
  145. if(ins[3]) mainOutput += 8.0f;
  146. if(ins[4]) mainOutput += 16.0f;
  147. if(ins[5]) mainOutput += 32.0f;
  148. if(ins[6]) mainOutput += 64.0f;
  149. if(ins[7]) mainOutput += 128.0f;
  150. mainOutput = mainOutput/255.0f;
  151. mainOutput *= 2.0f;
  152. mainOutput = mainOutput - 1.0f;
  153. }
  154. void DigitalToAnalog::processBiSig()
  155. {
  156. if(ins[0]) mainOutput += 1.0f;
  157. if(ins[1]) mainOutput += 2.0f;
  158. if(ins[2]) mainOutput += 4.0f;
  159. if(ins[3]) mainOutput += 8.0f;
  160. if(ins[4]) mainOutput += 16.0f;
  161. if(ins[5]) mainOutput += 32.0f;
  162. if(ins[6]) mainOutput += 64.0f;
  163. mainOutput = mainOutput/127.0f;
  164. if(ins[7]) mainOutput *= -1.0f;
  165. }
  166. struct DigitalToAnalogWidget : ModuleWidget { DigitalToAnalogWidget(DigitalToAnalog *module); };
  167. DigitalToAnalogWidget::DigitalToAnalogWidget(DigitalToAnalog *module) : ModuleWidget(module)
  168. {
  169. box.size = Vec(12 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
  170. {
  171. auto *panel = new SVGPanel();
  172. panel->box.size = box.size;
  173. panel->setBackground(SVG::load(assetPlugin(plugin, "res/DToA.svg")));
  174. addChild(panel);
  175. }
  176. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  177. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 0)));
  178. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  179. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 365)));
  180. //////PARAMS//////
  181. addParam(ParamWidget::create<CKD6>(Vec(85, 270), module, DigitalToAnalog::MODE_PARAM, 0.0, 1.0, 0.0));
  182. addParam(ParamWidget::create<CKD6>(Vec(135, 270), module, DigitalToAnalog::RECTIFY_PARAM, 0.0, 1.0, 0.0));
  183. //////BLINKENLIGHTS//////
  184. int modeLightX = 82;
  185. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(modeLightX, 306), module, DigitalToAnalog::MODE_UNI8_LIGHT));
  186. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(modeLightX, 319), module, DigitalToAnalog::MODE_BOFF_LIGHT));
  187. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(modeLightX, 332), module, DigitalToAnalog::MODE_BSIG_LIGHT));
  188. int rectLightX = 134;
  189. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(rectLightX, 306), module, DigitalToAnalog::RECT_NONE_LIGHT));
  190. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(rectLightX, 319), module, DigitalToAnalog::RECT_HALF_LIGHT));
  191. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(rectLightX, 332), module, DigitalToAnalog::RECT_FULL_LIGHT));
  192. addOutput(Port::create<PJ301MPort>(Vec(78, 70), Port::OUTPUT, module, DigitalToAnalog::MAIN_OUTPUT));
  193. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(Vec(87, 111), module, DigitalToAnalog::OUT_POS_LIGHT));
  194. //////INPUTS//////
  195. addInput(Port::create<PJ301MPort>(Vec(112, 152), Port::INPUT, module, DigitalToAnalog::SYNC_INPUT));
  196. addParam(ParamWidget::create<Trimpot>(Vec(114, 73), module, DigitalToAnalog::SCALE_PARAM, -1.0, 1.0, 0.2));
  197. addParam(ParamWidget::create<Trimpot>(Vec(150, 73), module, DigitalToAnalog::OFFSET_PARAM, -5.0, 5.0, 0.0));
  198. const int inXPos = 10;
  199. const int inLightX = 50;
  200. for(int i = 0; i < 8; i++)
  201. {
  202. const int yPos = 50 + (40 * i);
  203. const int lightY = 59 + (40 * i);
  204. //////OUTPUTS//////
  205. addInput(Port::create<PJ301MPort>(Vec(inXPos, yPos), Port::INPUT, module, DigitalToAnalog::IN1_INPUT + i));
  206. //////BLINKENLIGHTS//////
  207. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(inLightX, lightY), module, DigitalToAnalog::IN1_LIGHT + i));
  208. }
  209. }
  210. } // namespace rack_plugin_HetrickCV
  211. using namespace rack_plugin_HetrickCV;
  212. RACK_PLUGIN_MODEL_INIT(HetrickCV, DigitalToAnalog) {
  213. Model *modelDigitalToAnalog = Model::create<DigitalToAnalog, DigitalToAnalogWidget>("HetrickCV", "DigitalToAnalog", "Digital to Analog", LOGIC_TAG);
  214. return modelDigitalToAnalog;
  215. }