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.

325 lines
10.0KB

  1. #include "Bidoo.hpp"
  2. #include "BidooComponents.hpp"
  3. #include "dsp/digital.hpp"
  4. #include <sstream>
  5. #include <iomanip>
  6. #include "engine.hpp"
  7. using namespace std;
  8. namespace rack_plugin_Bidoo {
  9. struct MOIRE : Module {
  10. enum ParamIds {
  11. CURRENTSCENE_PARAM,
  12. TARGETSCENE_PARAM,
  13. MORPH_PARAM,
  14. ADONF_PARAM,
  15. NADA_PARAM,
  16. SAVE_PARAM,
  17. VOLTAGE_PARAM,
  18. TYPE_PARAMS,
  19. CONTROLS_PARAMS = TYPE_PARAMS + 16,
  20. NUM_PARAMS = CONTROLS_PARAMS + 16
  21. };
  22. enum InputIds {
  23. TARGETSCENE_INPUT,
  24. CURRENTSCENE_INPUT,
  25. MORPH_INPUT,
  26. NUM_INPUTS
  27. };
  28. enum OutputIds {
  29. CV_OUTPUTS,
  30. NUM_OUTPUTS = CV_OUTPUTS + 16
  31. };
  32. enum LightIds {
  33. TYPE_LIGHTS,
  34. NUM_LIGHTS = TYPE_LIGHTS + 16
  35. };
  36. float scenes[16][16] = {{0.0f}};
  37. int currentScene = 0;
  38. int targetScene = 0;
  39. float currentValues[16] = {0.0f};
  40. int controlsTypes[16] = {0};
  41. bool controlFocused[16] = {false};
  42. SchmittTrigger typeTriggers[16];
  43. MOIRE() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { }
  44. void step() override;
  45. void randomizeTargetScene() {
  46. for (int i = 0; i < 16; i++) {
  47. scenes[targetScene][i]=randomUniform()*10;
  48. }
  49. }
  50. json_t *toJson() override {
  51. json_t *rootJ = json_object();
  52. // scenes
  53. json_t *scenesJ = json_array();
  54. json_t *typesJ = json_array();
  55. for (int i = 0; i < 16; i++) {
  56. json_t *sceneJ = json_array();
  57. for (int j = 0; j < 16; j++) {
  58. json_t *controlJ = json_real(scenes[i][j]);
  59. json_array_append_new(sceneJ, controlJ);
  60. }
  61. json_array_append_new(scenesJ, sceneJ);
  62. json_t *typeJ = json_integer(controlsTypes[i]);
  63. json_array_append_new(typesJ, typeJ);
  64. }
  65. json_object_set_new(rootJ, "scenes", scenesJ);
  66. json_object_set_new(rootJ, "types", typesJ);
  67. return rootJ;
  68. }
  69. void fromJson(json_t *rootJ) override {
  70. // scenes
  71. json_t *scenesJ = json_object_get(rootJ, "scenes");
  72. if (scenesJ) {
  73. for (int i = 0; i < 16; i++) {
  74. json_t *sceneJ = json_array_get(scenesJ, i);
  75. if (sceneJ) {
  76. for (int j = 0; j < 16; j++) {
  77. json_t *controlJ = json_array_get(sceneJ, j);
  78. if (controlJ) {
  79. scenes[i][j] = json_number_value(controlJ);
  80. }
  81. }
  82. }
  83. }
  84. }
  85. //controlTypes
  86. json_t *typesJ = json_object_get(rootJ, "types");
  87. if (typesJ) {
  88. for (int i = 0; i < 16; i++) {
  89. json_t *typeJ = json_array_get(typesJ, i);
  90. if (typeJ) {
  91. controlsTypes[i] = json_integer_value(typeJ);
  92. }
  93. }
  94. }
  95. }
  96. };
  97. void MOIRE::step() {
  98. targetScene = clamp(floor(inputs[TARGETSCENE_INPUT].value * 1.6f) + params[TARGETSCENE_PARAM].value , 0.0f, 15.0f);
  99. currentScene = clamp(floor(inputs[CURRENTSCENE_INPUT].value * 1.6f) + params[CURRENTSCENE_PARAM].value , 0.0f, 15.0f);
  100. for (int i = 0; i < 16; i++) {
  101. if (typeTriggers[i].process(params[TYPE_PARAMS + i].value)) {
  102. controlsTypes[i] = controlsTypes[i] == 0 ? 1 : 0;
  103. }
  104. lights[TYPE_LIGHTS + i].value = controlsTypes[i];
  105. }
  106. float coeff = clamp(inputs[MORPH_INPUT].value + params[MORPH_PARAM].value, 0.0f, 10.0f);
  107. for (int i = 0 ; i < 16; i++) {
  108. if (!controlFocused[i]) {
  109. if (controlsTypes[i] == 0) {
  110. currentValues[i] = rescale(coeff,0.0f,10.0f,scenes[currentScene][i],scenes[targetScene][i]);
  111. } else {
  112. if (coeff >= 9.98f) {
  113. currentValues[i] = scenes[targetScene][i];
  114. }
  115. else {
  116. currentValues[i] = scenes[currentScene][i];
  117. }
  118. }
  119. }
  120. else {
  121. currentValues[i] = params[CONTROLS_PARAMS + i].value;
  122. }
  123. outputs[CV_OUTPUTS + i].value = currentValues[i] - 5.0f * params[VOLTAGE_PARAM].value;
  124. }
  125. }
  126. struct MOIREWidget : ModuleWidget {
  127. ParamWidget *controls[16];
  128. ParamWidget *morphButton;
  129. MOIREWidget(MOIRE *module);
  130. void step() override;
  131. Menu *createContextMenu() override;
  132. };
  133. struct MOIRECKD6 : BlueCKD6 {
  134. void onMouseDown(EventMouseDown &e) override {
  135. MOIREWidget *parent = dynamic_cast<MOIREWidget*>(this->parent);
  136. MOIRE *module = dynamic_cast<MOIRE*>(this->module);
  137. if (parent && module) {
  138. if (this->paramId == MOIRE::ADONF_PARAM) {
  139. parent->morphButton->setValue(10.0f);
  140. for (int i = 0; i<16; i++){
  141. parent->controls[i]->setValue(module->scenes[module->targetScene][i]);
  142. module->controlFocused[i] = false;
  143. }
  144. } else if (this->paramId == MOIRE::NADA_PARAM) {
  145. parent->morphButton->setValue(0.0f);
  146. for (int i = 0; i<16; i++){
  147. parent->controls[i]->setValue(module->scenes[module->currentScene][i]);
  148. module->controlFocused[i] = false;
  149. }
  150. }
  151. else if (this->paramId == MOIRE::SAVE_PARAM) {
  152. for (int i = 0 ; i < 16; i++) {
  153. module->scenes[module->targetScene][i] = parent->controls[i]->value;
  154. }
  155. }
  156. }
  157. BlueCKD6::onMouseDown(e);
  158. }
  159. };
  160. struct MOIREDisplay : TransparentWidget {
  161. shared_ptr<Font> font;
  162. int *value;
  163. MOIREDisplay() {
  164. font = Font::load(assetPlugin(plugin, "res/DejaVuSansMono.ttf"));
  165. }
  166. void drawMessage(NVGcontext *vg, Vec pos) {
  167. nvgFontSize(vg, 18);
  168. nvgFontFaceId(vg, font->handle);
  169. nvgTextLetterSpacing(vg, -2);
  170. nvgFillColor(vg, YELLOW_BIDOO);
  171. std::stringstream ss;
  172. ss << std::setw(2) << std::setfill('0') << *value + 1;
  173. std::string s = ss.str();
  174. nvgText(vg, pos.x + 2, pos.y + 2, s.c_str(), NULL);
  175. }
  176. void draw(NVGcontext *vg) override {
  177. drawMessage(vg, Vec(0, 20));
  178. }
  179. };
  180. struct MOIREColoredKnob : BidooColoredKnob {
  181. void setValueNoEngine(float value) {
  182. float newValue = clamp(value, fminf(minValue, maxValue), fmaxf(minValue, maxValue));
  183. if (this->value != newValue) {
  184. this->value = newValue;
  185. this->dirty=true;
  186. }
  187. };
  188. void onDragStart(EventDragStart &e) override {
  189. RoundKnob::onDragStart(e);
  190. MOIRE *module = dynamic_cast<MOIRE*>(this->module);
  191. module->controlFocused[this->paramId - MOIRE::MOIRE::CONTROLS_PARAMS] = true;
  192. }
  193. };
  194. struct MOIREMorphKnob : BidooMorphKnob {
  195. void onMouseDown(EventMouseDown &e) override {
  196. MOIRE *module = dynamic_cast<MOIRE*>(this->module);
  197. for (int i = 0 ; i < 16; i++) {
  198. module->controlFocused[i] = false;
  199. }
  200. BidooMorphKnob::onMouseDown(e);
  201. }
  202. };
  203. MOIREWidget::MOIREWidget(MOIRE *module) : ModuleWidget(module) {
  204. setPanel(SVG::load(assetPlugin(plugin, "res/MOIRE.svg")));
  205. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  206. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  207. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  208. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  209. static const float portX0[10] = {20,34,48,62,76,90,120,150,180,210};
  210. static const float portY0[12] = {20,50,80,110,140,170,200,230,260,290,320,350};
  211. addParam(ParamWidget::create<MOIRECKD6>(Vec(portX0[5], portY0[0]+18), module, MOIRE::SAVE_PARAM, 0.0f, 1.0f, 0.0f));
  212. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(portX0[0], portY0[1]+16), module, MOIRE::TARGETSCENE_PARAM, 0.0f, 15.1f, 0.0f));
  213. MOIREDisplay *displayTarget = new MOIREDisplay();
  214. displayTarget->box.pos = Vec(50,portY0[2]-21);
  215. displayTarget->box.size = Vec(20, 20);
  216. displayTarget->value = &module->targetScene;
  217. addChild(displayTarget);
  218. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(portX0[0], portY0[6]-5), module, MOIRE::CURRENTSCENE_PARAM, 0.0f, 15.1f, 0.0f));
  219. MOIREDisplay *displayCurrent = new MOIREDisplay();
  220. displayCurrent->box.pos = Vec(50,portY0[5]+19);
  221. displayCurrent->box.size = Vec(20, 20);
  222. displayCurrent->value = &module->currentScene;
  223. addChild(displayCurrent);
  224. addParam(ParamWidget::create<MOIRECKD6>(Vec(portX0[0]-5, portY0[3]-3), module, MOIRE::ADONF_PARAM, 0.0f, 1.0f, 0.0f));
  225. addParam(ParamWidget::create<MOIRECKD6>(Vec(portX0[0]-5, portY0[4]+5), module, MOIRE::NADA_PARAM, 0.0f, 1.0f, 0.0f));
  226. addInput(Port::create<TinyPJ301MPort>(Vec(portX0[0]+2, portY0[0]+21), Port::INPUT, module, MOIRE::TARGETSCENE_INPUT));
  227. addInput(Port::create<TinyPJ301MPort>(Vec(portX0[0]+2, portY0[7]-6), Port::INPUT, module, MOIRE::CURRENTSCENE_INPUT));
  228. addInput(Port::create<TinyPJ301MPort>(Vec(portX0[0]+33.2, portY0[7]-6), Port::INPUT, module, MOIRE::MORPH_INPUT));
  229. morphButton = ParamWidget::create<MOIREMorphKnob>(Vec(portX0[0]+26, portY0[3]+14), module, MOIRE::MORPH_PARAM, 0.0f, 10.0f, 0.0f);
  230. addParam(morphButton);
  231. addParam(ParamWidget::create<CKSS>(Vec(40, 279), module, MOIRE::VOLTAGE_PARAM, 0.0f, 1.0f, 0.0f));
  232. for (int i = 0; i < 16; i++) {
  233. controls[i] = ParamWidget::create<MOIREColoredKnob>(Vec(portX0[i%4+5]+1, portY0[int(i/4) + 2] + 2), module, MOIRE::CONTROLS_PARAMS + i, 0.0f, 10.0f, 0.0f);
  234. addParam(controls[i]);
  235. addParam(ParamWidget::create<MiniLEDButton>(Vec(portX0[i%4+5]+24, portY0[int(i/4) + 2]+24), module, MOIRE::TYPE_PARAMS + i, 0.0f, 1.0f, 0.0f));
  236. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(portX0[i%4+5]+24, portY0[int(i/4) + 2]+25), module, MOIRE::TYPE_LIGHTS + i));
  237. addOutput(Port::create<PJ301MPort>(Vec(portX0[i%4+5]+2, portY0[int(i/4) + 7]), Port::OUTPUT, module, MOIRE::CV_OUTPUTS + i));
  238. }
  239. }
  240. void MOIREWidget::step() {
  241. MOIRE *module = dynamic_cast<MOIRE*>(this->module);
  242. for (int i = 0; i < 16; i++) {
  243. if (!module->controlFocused[i]){
  244. MOIREColoredKnob* knob = dynamic_cast<MOIREColoredKnob*>(controls[i]);
  245. engineSetParam(module, controls[i]->paramId, module->currentValues[i]);
  246. knob->setValueNoEngine(module->currentValues[i]);
  247. }
  248. }
  249. ModuleWidget::step();
  250. }
  251. struct MOIRERandTargetSceneItem : MenuItem {
  252. MOIRE *moireModule;
  253. void onAction(EventAction &e) override {
  254. moireModule->randomizeTargetScene();
  255. }
  256. };
  257. Menu *MOIREWidget::createContextMenu() {
  258. Menu *menu = ModuleWidget::createContextMenu();
  259. MenuLabel *spacerLabel = new MenuLabel();
  260. menu->addChild(spacerLabel);
  261. MOIREWidget *dtroyWidget = dynamic_cast<MOIREWidget*>(this);
  262. assert(dtroyWidget);
  263. MOIRE *moireModule = dynamic_cast<MOIRE*>(module);
  264. assert(moireModule);
  265. MOIRERandTargetSceneItem *randomizeTargetSceneItem = new MOIRERandTargetSceneItem();
  266. randomizeTargetSceneItem->text = "Randomize target scene";
  267. randomizeTargetSceneItem->moireModule = moireModule;
  268. menu->addChild(randomizeTargetSceneItem);
  269. return menu;
  270. }
  271. } // namespace rack_plugin_Bidoo
  272. using namespace rack_plugin_Bidoo;
  273. RACK_PLUGIN_MODEL_INIT(Bidoo, MOIRE) {
  274. Model *modelMOIRE = Model::create<MOIRE, MOIREWidget>("Bidoo", "MOiRE", "MOiRE controller", CONTROLLER_TAG);
  275. return modelMOIRE;
  276. }