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.

373 lines
9.0KB

  1. #include "ML_modules.hpp"
  2. #include "dsp/digital.hpp"
  3. namespace rack_plugin_ML_modules {
  4. struct Quantum : Module {
  5. enum ParamIds {
  6. SEMI_1_PARAM,
  7. SEMI_2_PARAM,
  8. SEMI_3_PARAM,
  9. SEMI_4_PARAM,
  10. SEMI_5_PARAM,
  11. SEMI_6_PARAM,
  12. SEMI_7_PARAM,
  13. SEMI_8_PARAM,
  14. SEMI_9_PARAM,
  15. SEMI_10_PARAM,
  16. SEMI_11_PARAM,
  17. SEMI_12_PARAM,
  18. NUM_PARAMS
  19. };
  20. enum InputIds {
  21. IN_INPUT,
  22. TRANSPOSE_INPUT,
  23. NOTE_INPUT,
  24. SET_INPUT,
  25. RESET_INPUT,
  26. NUM_INPUTS
  27. };
  28. enum OutputIds {
  29. OUT_OUTPUT,
  30. TRIGGER_OUTPUT,
  31. GATE_OUTPUT,
  32. NUM_OUTPUTS
  33. };
  34. enum LightIds {
  35. SEMI_1_LIGHT,
  36. SEMI_2_LIGHT,
  37. SEMI_3_LIGHT,
  38. SEMI_4_LIGHT,
  39. SEMI_5_LIGHT,
  40. SEMI_6_LIGHT,
  41. SEMI_7_LIGHT,
  42. SEMI_8_LIGHT,
  43. SEMI_9_LIGHT,
  44. SEMI_10_LIGHT,
  45. SEMI_11_LIGHT,
  46. SEMI_12_LIGHT,
  47. NUM_LIGHTS
  48. };
  49. enum Mode {
  50. LAST,
  51. CLOSEST_UP,
  52. CLOSEST_DOWN,
  53. UP,
  54. DOWN
  55. };
  56. Mode mode = LAST;
  57. Quantum() : Module( NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { reset(); };
  58. void step() override;
  59. PulseGenerator pulse;
  60. int last_octave=0, last_semi=0;
  61. bool semiState[12] = {};
  62. SchmittTrigger semiTriggers[12], setTrigger, resetTrigger;
  63. float semiLight[12] = {};
  64. void reset() override {
  65. for (int i = 0; i < 12; i++) {
  66. semiState[i] = false;
  67. semiLight[i] = 0.0;
  68. }
  69. last_octave = 0;
  70. last_semi = 0;
  71. }
  72. void randomize() override {
  73. for (int i = 0; i<12; i++) {
  74. semiState[i] = (randomUniform() > 0.5);
  75. semiLight[i] = semiState[i]?1.0:0.0;
  76. };
  77. last_octave = 0;
  78. last_semi = 0;
  79. }
  80. json_t *toJson() override {
  81. json_t *rootJ = json_object();
  82. json_t *scaleJ = json_array();
  83. for (int i = 0; i < 12; i++) {
  84. json_t *semiJ = json_integer( (int) semiState[i]);
  85. json_array_append_new(scaleJ, semiJ);
  86. }
  87. json_object_set_new(rootJ, "scale", scaleJ);
  88. json_object_set_new(rootJ, "mode", json_integer(mode));
  89. return rootJ;
  90. }
  91. void fromJson(json_t *rootJ) override {
  92. json_t *scaleJ = json_object_get(rootJ, "scale");
  93. for (int i = 0; i < 12; i++) {
  94. json_t *semiJ = json_array_get(scaleJ, i);
  95. semiState[i] = !!json_integer_value(semiJ);
  96. semiLight[i] = semiState[i]?1.0:0.0;
  97. }
  98. json_t *modeJ = json_object_get(rootJ, "mode");
  99. if(modeJ) mode = (Mode) json_integer_value(modeJ);
  100. }
  101. int modulo(int a, int b) {
  102. int r = a % b;
  103. return r < 0 ? r + b : r;
  104. }
  105. };
  106. void Quantum::step() {
  107. for(int i=0; i<12; i++) {
  108. if (semiTriggers[i].process(params[Quantum::SEMI_1_PARAM + i].value)) {
  109. semiState[i] = !semiState[i];
  110. }
  111. lights[i].value = semiState[i]?1.0f:0.0f;
  112. }
  113. float gate = 0.f, trigger=0.f;
  114. float quantized = 0.f;
  115. float v=inputs[IN_INPUT].value;
  116. float t=inputs[TRANSPOSE_INPUT].normalize(0.0);
  117. // int octave = floor(v);
  118. // int octave_t = floor(t);
  119. gate = mode==LAST? 0.0: 10.0;
  120. int semi_full = round( 12.0f*v );
  121. int semi_t = round( 12.0f*t );
  122. int octave = semi_full/12;
  123. int semi =semi_full % 12;
  124. if (semi<0) {
  125. semi+=12;
  126. octave-=1;
  127. }
  128. // transpose to shifted scale:
  129. int tmp_semi = modulo (semi-semi_t, 12) ;
  130. if( inputs[RESET_INPUT].active ) {
  131. if( resetTrigger.process(inputs[RESET_INPUT].value) ) reset();
  132. };
  133. if( inputs[SET_INPUT].active ) {
  134. if( setTrigger.process(inputs[SET_INPUT].value ) ) {
  135. float n=inputs[NOTE_INPUT].normalize(0.0);
  136. int semi_n = round( 12.0*(n - 1.0*round(n)) ) - semi_t;
  137. if(semi_n<0) semi_n+=12;
  138. semiState[semi_n] = !semiState[semi_n];
  139. semiLight[semi_n] = semiState[semi_n]?1.0:0.0;
  140. }
  141. };
  142. if( semiState[tmp_semi] )
  143. {
  144. bool changed = !( (octave==last_octave) && (semi==last_semi));
  145. gate = 10.0f;
  146. quantized = 1.0f*octave + semi/12.0f;
  147. if(changed) pulse.trigger(0.001);
  148. last_octave = octave;
  149. last_semi = semi;
  150. } else {
  151. if(mode==LAST) {
  152. quantized = 1.0f*last_octave + last_semi/12.0f;
  153. } else {
  154. int i_up = 0;
  155. int i_down = 0;
  156. while( !semiState[ modulo(tmp_semi+i_up, 12) ] && i_up < 12 ) i_up++;
  157. while( !semiState[ modulo(tmp_semi-i_down,12) ] && i_down < 12 ) i_down++;
  158. switch(mode) {
  159. case UP: if (i_up < 12) semi += i_up;
  160. else {semi = last_semi; octave = last_octave; gate = 0.0f;}
  161. break;
  162. case DOWN: if (i_down < 12) semi -= i_down;
  163. else {semi = last_semi; octave = last_octave; gate = 0.0f;}
  164. break;
  165. case CLOSEST_UP: if (i_up<12 && i_down<12) semi = (i_up > i_down) ? (semi - i_down) : (semi + i_up);
  166. else {semi = last_semi; octave = last_octave; gate = 0.0f;}
  167. break;
  168. case CLOSEST_DOWN: if (i_up<12 && i_down<12) semi = (i_down > i_up) ? (semi + i_up) : (semi - i_down);
  169. else {semi = last_semi; octave = last_octave; gate = 0.0f;}
  170. break;
  171. case LAST:
  172. default: break;
  173. };
  174. if( semi > 11 ) {
  175. semi -= 12;
  176. octave += 1;
  177. }
  178. if( semi < 0 ) {
  179. semi += 12;
  180. octave -= 1;
  181. }
  182. bool changed = !( (octave==last_octave)&&(semi==last_semi));
  183. quantized = 1.0f*octave + semi/12.0f;
  184. if(changed) pulse.trigger(0.001f);
  185. last_octave = octave;
  186. last_semi = semi;
  187. };
  188. };
  189. float gSampleRate = engineGetSampleRate();
  190. trigger = pulse.process(1.0/gSampleRate) ? 10.0f : 0.0f;
  191. outputs[OUT_OUTPUT].value = quantized;
  192. outputs[GATE_OUTPUT].value = gate - trigger;
  193. outputs[TRIGGER_OUTPUT].value = trigger;
  194. }
  195. struct QuantumModeItem : MenuItem {
  196. Quantum *quantum;
  197. Quantum::Mode mode;
  198. void onAction(EventAction &e) override {
  199. quantum->mode = mode;
  200. };
  201. void step() override {
  202. rightText = (quantum->mode == mode)? "✔" : "";
  203. };
  204. };
  205. struct QuantumWidget : ModuleWidget {
  206. QuantumWidget(Quantum *module);
  207. json_t *toJsonData() ;
  208. void fromJsonData(json_t *root) ;
  209. Menu *createContextMenu() override;
  210. };
  211. Menu *QuantumWidget::createContextMenu() {
  212. Menu *menu = ModuleWidget::createContextMenu();
  213. MenuLabel *spacerLabel = new MenuLabel();
  214. menu->addChild(spacerLabel);
  215. Quantum *quantum = dynamic_cast<Quantum*>(module);
  216. assert(quantum);
  217. MenuLabel *modeLabel = new MenuLabel();
  218. modeLabel->text = "Mode";
  219. menu->addChild(modeLabel);
  220. QuantumModeItem *last_Item = new QuantumModeItem();
  221. last_Item->text = "Last";
  222. last_Item->quantum = quantum;
  223. last_Item->mode = Quantum::LAST;
  224. menu->addChild(last_Item);
  225. QuantumModeItem *up_Item = new QuantumModeItem();
  226. up_Item->text = "Up";
  227. up_Item->quantum = quantum;
  228. up_Item->mode = Quantum::UP;
  229. menu->addChild(up_Item);
  230. QuantumModeItem *down_Item = new QuantumModeItem();
  231. down_Item->text = "Down";
  232. down_Item->quantum = quantum;
  233. down_Item->mode = Quantum::DOWN;
  234. menu->addChild(down_Item);
  235. QuantumModeItem *cl_up_Item = new QuantumModeItem();
  236. cl_up_Item->text = "Closest, up";
  237. cl_up_Item->quantum = quantum;
  238. cl_up_Item->mode = Quantum::CLOSEST_UP;
  239. menu->addChild(cl_up_Item);
  240. QuantumModeItem *cl_dn_Item = new QuantumModeItem();
  241. cl_dn_Item->text = "Closest, Down";
  242. cl_dn_Item->quantum = quantum;
  243. cl_dn_Item->mode = Quantum::CLOSEST_DOWN;
  244. menu->addChild(cl_dn_Item);
  245. return menu;
  246. };
  247. QuantumWidget::QuantumWidget(Quantum *module) : ModuleWidget(module) {
  248. box.size = Vec(15*8, 380);
  249. {
  250. SVGPanel *panel = new SVGPanel();
  251. panel->box.size = box.size;
  252. panel->setBackground(SVG::load(assetPlugin(plugin,"res/Quantum.svg")));
  253. addChild(panel);
  254. }
  255. addChild(Widget::create<MLScrew>(Vec(15, 0)));
  256. addChild(Widget::create<MLScrew>(Vec(box.size.x-30, 0)));
  257. addChild(Widget::create<MLScrew>(Vec(15, 365)));
  258. addChild(Widget::create<MLScrew>(Vec(box.size.x-30, 365)));
  259. addInput( Port::create<MLPort>(Vec(19, 42), Port::INPUT, module, Quantum::IN_INPUT));
  260. addOutput(Port::create<MLPort>(Vec(75, 42), Port::OUTPUT, module, Quantum::OUT_OUTPUT));
  261. addInput( Port::create<MLPort>(Vec(75, 90), Port::INPUT, module, Quantum::TRANSPOSE_INPUT));
  262. addOutput(Port::create<MLPort>(Vec(75, 140), Port::OUTPUT, module, Quantum::GATE_OUTPUT));
  263. addOutput(Port::create<MLPort>(Vec(75, 180), Port::OUTPUT, module, Quantum::TRIGGER_OUTPUT));
  264. addInput(Port::create<MLPort>(Vec(75, 226), Port::INPUT, module, Quantum::NOTE_INPUT));
  265. addInput(Port::create<MLPort>(Vec(75, 266), Port::INPUT, module, Quantum::SET_INPUT));
  266. addInput(Port::create<MLPort>(Vec(75, 312), Port::INPUT, module, Quantum::RESET_INPUT));
  267. static const float offset_x = 24;
  268. static const float offset_y = 333;
  269. for(int i=0; i<12; i++) {
  270. addParam(ParamWidget::create<ML_SmallLEDButton>(Vec(offset_x, -22*i+offset_y), module, Quantum::SEMI_1_PARAM + i, 0.0, 1.0, 0.0));
  271. addChild(ModuleLightWidget::create<MLSmallLight<GreenLight>>(Vec(offset_x+4, -22*i+4+offset_y), module, Quantum::SEMI_1_LIGHT+i));
  272. }
  273. }
  274. } // namespace rack_plugin_ML_modules
  275. using namespace rack_plugin_ML_modules;
  276. RACK_PLUGIN_MODEL_INIT(ML_modules, Quantum) {
  277. Model *modelQuantum = Model::create<Quantum, QuantumWidget>("ML modules", "Quantum", "Quantum", QUANTIZER_TAG);
  278. return modelQuantum;
  279. }