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.

513 lines
15KB

  1. #include "unless.hpp"
  2. #include "widgets.hpp"
  3. #include "dsp/digital.hpp"
  4. #include <algorithm>
  5. namespace rack_plugin_unless_modules {
  6. #define RELEASED -1
  7. #define UP 0
  8. #define DOWN 1
  9. #define PRESSED 2
  10. struct Markov : Module {
  11. struct Edge {
  12. int note = 0;
  13. int count = 1;
  14. Edge(int n, int c){
  15. note = n;
  16. count = c;
  17. }
  18. };
  19. struct Node {
  20. int note = 0;
  21. int count = 1;
  22. int last = -1;
  23. std::vector<Edge> edges;
  24. Node(int n, int c){
  25. note = n;
  26. count = c;
  27. }
  28. int findEdge(int n){
  29. for(int i = 0; i<(int)edges.size(); i++){
  30. if(edges.at(i).note == n)
  31. return i;
  32. }
  33. return -1;
  34. }
  35. static bool sortByCount(const Edge &a, const Edge &b){
  36. return a.count > b.count;
  37. }
  38. void addEdge(int n){
  39. int i = findEdge(n);
  40. if(i < 0 || i >= (int)edges.size())
  41. edges.push_back(Edge(n, 1));
  42. else
  43. edges.at(i).count++;
  44. std::sort(edges.begin(), edges.end(), sortByCount);
  45. }
  46. // void reverseWeights(){
  47. // }
  48. int getNext(float randomness){
  49. float all = 0;
  50. float mult = randomness * -1.0f;
  51. if(randomness > 0)
  52. mult *= 0.9f;
  53. if(randomness < -0.9f && edges.size() > 0)
  54. return edges.at(0).note;
  55. for(auto& e : edges)
  56. all+= (float)e.count + ((float)e.count * mult);
  57. float r = randomUniform() * all;
  58. float acc = 0;
  59. for(int i = 0; i<(int)edges.size(); i++){
  60. acc += (float)edges.at(i).count + ((float)edges.at(i).count * mult);
  61. if(r <= acc)
  62. return edges.at(i).note;
  63. }
  64. return -1;
  65. }
  66. };
  67. struct MarkovChain{
  68. std::vector<Node> nodes;
  69. bool hasNodes = false;
  70. int current = -1;
  71. void clear(){
  72. nodes.clear();
  73. current = -1;
  74. hasNodes = false;
  75. }
  76. int findNode(int n){
  77. for(int i = 0; i<(int) nodes.size();i++){
  78. if(nodes.at(i).note == n)
  79. return i;
  80. }
  81. return -1;
  82. }
  83. void addNode(int n){
  84. hasNodes = true;
  85. nodes.push_back(Node(n, 1));
  86. }
  87. void setNote(int n){
  88. if(hasNodes){
  89. int closest = 1000;
  90. for(int i = 0; i<(int) nodes.size();i++){
  91. int nt = nodes.at(i).note;
  92. if(nt == n){
  93. closest = nt;
  94. break;
  95. }else if(abs(nt - n) < abs(closest - n)){
  96. closest = nt;
  97. }
  98. }
  99. closest = findNode(closest);
  100. if(closest < (int)nodes.size() && closest >= 0)
  101. current = closest;
  102. // printf("%d\n", closest);
  103. }
  104. }
  105. void forget(){
  106. if(nodes.size() > 0){
  107. int n = nodes.at(current).note;
  108. nodes.erase(nodes.begin() + current);
  109. for (auto& node : nodes){
  110. if(node.edges.size() > 0){
  111. for(int i = (int)node.edges.size() - 1; i>= 0; i--)
  112. if(node.edges.at(i).note == n){
  113. node.count-= node.edges.at(i).count;
  114. node.edges.erase(node.edges.begin() + i);
  115. }
  116. }
  117. }
  118. if(nodes.size() == 0){
  119. hasNodes = false;
  120. current = -1;
  121. }else{
  122. setNote(current);
  123. }
  124. }
  125. }
  126. void addEdge(int n){
  127. int i = findNode(n);
  128. if(i == -1)
  129. addNode(n);
  130. if(current > -1)
  131. nodes.at(current).addEdge(n);
  132. current = i < 0 ? ((int) nodes.size()) - 1 : i;
  133. }
  134. int randomNode(){
  135. return clamp((int)floor(randomUniform() * (float) nodes.size()), 0, ((int) nodes.size()) - 1);
  136. }
  137. int step(float randomness){
  138. // printf("%f\n", randomness);
  139. if(current < 0 && hasNodes){
  140. current = 0;
  141. return current;
  142. }else if(current >= 0 && current < (int) nodes.size()){
  143. // DEAD END
  144. if(nodes.at(current).edges.size() == 0){
  145. if(randomness < -0.5f){
  146. // ORDER
  147. return current;
  148. }else{
  149. // RANDOM
  150. if(randomUniform() * 1.5f < randomness + 0.5f)
  151. return randomNode();
  152. else
  153. return current;
  154. }
  155. }else{
  156. int next = nodes.at(current).getNext(randomness);
  157. if(randomness > 0.5f){
  158. float r = (randomness - 0.5f) * 2.0f;
  159. if(randomUniform() < r){
  160. next = -1;
  161. }
  162. }
  163. current = next < 0 ? (randomness > -0.9f ? randomNode() : current) : findNode(next);
  164. }
  165. }
  166. return current;
  167. }
  168. int getCurrentNote(){
  169. if(current >= 0)
  170. return nodes.at(current).note;
  171. else
  172. return -1;
  173. }
  174. };
  175. enum ParamIds {
  176. LEARN_PARAM,
  177. FORGET_PARAM,
  178. RANDOMNESS_PARAM,
  179. NUM_PARAMS
  180. };
  181. enum InputIds {
  182. LEARN_INPUT,
  183. FORGET_INPUT,
  184. RANDOMNESS_INPUT,
  185. CV_INPUT,
  186. GATE_INPUT,
  187. TRIGGER_INPUT,
  188. NUM_INPUTS
  189. };
  190. enum OutputIds {
  191. CV_OUTPUT,
  192. GATE_OUTPUT,
  193. NUM_OUTPUTS
  194. };
  195. enum LightIds {
  196. LEARN_LIGHT,
  197. // DEADEND_LIGHT,
  198. NUM_LIGHTS
  199. };
  200. bool blackkeys[12] = {false, true, false, true, false, false, true, false, true, false, true, false};
  201. TriggerSwitch learn_trigger;
  202. TriggerSwitch forget_trigger;
  203. TriggerSwitch gate_trigger;
  204. TriggerSwitch trigger_trigger;
  205. bool learning = false;
  206. MarkovChain chain = MarkovChain();
  207. Markov() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  208. // onReset();
  209. }
  210. void onDelete() override{
  211. chain.clear();
  212. }
  213. void onRandomize() override{
  214. }
  215. void onReset() override{
  216. chain.clear();
  217. }
  218. int cvToMidi(float v){
  219. return round(v * 12.0f + 60.0f);
  220. }
  221. float midiToCV(int m){
  222. return ((float) m - 60) / 12.0f;
  223. }
  224. float cvToHertz(float cv){
  225. return 261.626f * powf(2.0f, cv);
  226. }
  227. void bypass(){
  228. outputs[CV_OUTPUT].value = inputs[CV_INPUT].value;
  229. outputs[GATE_OUTPUT].value = inputs[GATE_INPUT].value;
  230. }
  231. void updateTriggers(){
  232. learn_trigger.update(params[LEARN_PARAM].value + inputs[LEARN_INPUT].value);
  233. forget_trigger.update(params[FORGET_PARAM].value + inputs[FORGET_INPUT].value);
  234. trigger_trigger.update(inputs[TRIGGER_INPUT].value);
  235. gate_trigger.update(inputs[GATE_INPUT].value);
  236. }
  237. void step() override {
  238. updateTriggers();
  239. int inputMidi = cvToMidi(inputs[CV_INPUT].value);
  240. if(forget_trigger.state == PRESSED)
  241. chain.forget();
  242. if(learn_trigger.state == PRESSED)
  243. learning = !learning;
  244. if(learning){
  245. if(gate_trigger.state > 0 && chain.getCurrentNote() != inputMidi){
  246. bypass();
  247. if(gate_trigger.state == PRESSED)
  248. outputs[GATE_OUTPUT].value = 0.0f;
  249. chain.addEdge(inputMidi);
  250. }
  251. }
  252. if(trigger_trigger.state == PRESSED){
  253. chain.step(
  254. inputs[RANDOMNESS_INPUT].active
  255. ? (clamp(inputs[RANDOMNESS_INPUT].value, 0.0f, 10.0f) * 0.1f * 2.0f - 1.0f)
  256. : params[RANDOMNESS_PARAM].value
  257. );
  258. outputs[GATE_OUTPUT].value = 0.0f;
  259. }else if(trigger_trigger.state == RELEASED || trigger_trigger.state == UP){
  260. outputs[GATE_OUTPUT].value = 0.0f;
  261. }else{
  262. outputs[GATE_OUTPUT].value = 10.0f;
  263. }
  264. if(gate_trigger.state == PRESSED && !learning)
  265. chain.setNote(cvToMidi(inputs[CV_INPUT].value));
  266. outputs[CV_OUTPUT].value = midiToCV(chain.getCurrentNote());
  267. lights[LEARN_LIGHT].value = learning ? 10.0f : 0.0f;
  268. }
  269. json_t *toJson() override {
  270. json_t *rootJ = json_object();
  271. json_t *nodesJ = json_array();
  272. int i = 0;
  273. for (auto& node : chain.nodes) {
  274. json_t *nodeJ = json_object();
  275. json_t *edges = json_array();
  276. int j = 0;
  277. for(auto& edge : node.edges){
  278. json_t *edgeJ = json_object();
  279. json_object_set_new(edgeJ, "note", json_integer(edge.note));
  280. json_object_set_new(edgeJ, "count", json_integer(edge.count));
  281. json_array_insert_new(edges, j, edgeJ);
  282. j++;
  283. }
  284. json_object_set_new(nodeJ, "edges", edges);
  285. json_object_set_new(nodeJ, "note", json_integer(node.note));
  286. json_object_set_new(nodeJ, "count", json_integer(node.count));
  287. json_array_insert_new(nodesJ, i, nodeJ);
  288. i++;
  289. }
  290. json_object_set_new(rootJ, "nodes", nodesJ);
  291. json_object_set_new(rootJ, "current", json_integer(chain.current));
  292. json_object_set_new(rootJ, "learning", json_boolean(learning));
  293. return rootJ;
  294. }
  295. void fromJson(json_t *rootJ) override {
  296. json_t *nodesJ = json_object_get(rootJ, "nodes");
  297. for (int i = 0; i>=0; i++){
  298. if(json_array_get(nodesJ, i) != NULL){
  299. json_t *node = json_array_get(nodesJ, i);
  300. json_t *edges = json_object_get(node, "edges");
  301. Node n = Node(json_integer_value(json_object_get(node, "note")), json_integer_value(json_object_get(node, "count")));
  302. for (int j = 0; j>=0; j++) {
  303. if(json_array_get(edges, j) != NULL){
  304. std::vector<Edge> es;
  305. json_t *edge = json_array_get(edges, j);
  306. n.edges.push_back(Edge(json_integer_value(json_object_get(edge, "note")), json_integer_value(json_object_get(edge, "count"))));
  307. }else{
  308. break;
  309. }
  310. }
  311. chain.nodes.push_back(n);
  312. }else{
  313. break;
  314. }
  315. }
  316. chain.hasNodes = (int)chain.nodes.size() > 0;
  317. chain.current = json_integer_value(json_object_get(rootJ, "current"));
  318. learning = json_boolean_value(json_object_get(rootJ, "learning"));
  319. }
  320. };
  321. struct MarkovDisplay : Widget {
  322. Markov *module;
  323. NVGcolor black = nvgRGBA(0x22, 0x22, 0x22, 0xee);
  324. NVGcolor white = nvgRGBA(0xf9, 0xfa, 0xea, 0xff);
  325. NVGcolor grey = nvgRGBA(0xee, 0xee, 0xee, 0x88);
  326. float hue = 0.0f;
  327. NVGcolor background = nvgRGB(142,140,136);
  328. std::shared_ptr<Font> font;
  329. MarkovDisplay(int x, int y) {
  330. box.pos = Vec(x, y);
  331. box.size = Vec(96,96);
  332. font = Font::load(assetPlugin(plugin, "res/font/Terminus.ttf"));
  333. }
  334. int cvToMidi(float v){
  335. return round((clamp(v + 5.0f, 0.0f, 10.58f) / 10.58f) * 127.0f);
  336. }
  337. void draw(NVGcontext *vg) override {
  338. // BACKGROUND
  339. nvgBeginPath(vg);
  340. nvgRect(vg, 0, 0, box.size.x, box.size.y);
  341. nvgFillColor(vg, background);
  342. nvgFill(vg);
  343. int w = 8;
  344. if(module->chain.hasNodes){
  345. //NODES
  346. for(auto& node : module->chain.nodes){
  347. int n = node.note;
  348. nvgBeginPath(vg);
  349. nvgRect(vg, (n % 12) * w, (n / 12) * w, w, w);
  350. nvgFillColor(vg, module->blackkeys[n % 12] ? black : white);
  351. nvgFill(vg);
  352. }
  353. int current = module->chain.current;
  354. if(current >= 0 && current < (int) module->chain.nodes.size()){
  355. int n = module->chain.nodes.at(current).note;
  356. int nx = (n % 12) * w + 4;
  357. int ny = (n / 12) * w + 4;
  358. int es = (int) module->chain.nodes.at(current).edges.size();
  359. Vec pos1 = Vec(nx, ny);
  360. for(int j = es - 1; j>=0; j--){
  361. float weight = 1.0f - ((float)j / (float)es);
  362. int next = module->chain.nodes.at(current).edges.at(j).note;
  363. // HIGHLIGHT
  364. nvgBeginPath(vg);
  365. nvgRect(vg, (next % 12) * w, (next / 12) * w, w, w);
  366. nvgFillColor(vg,nvgHSLA(hue + (1.0f - weight) * 0.3f, 0.5f, 0.5f, 50 + weight * 130) );
  367. nvgFill(vg);
  368. // EDGE
  369. // slightly modified version of the wire drawing code from Rack/src/app/WireWidget.cpp
  370. Vec pos2 = Vec((next % 12) * w + 4, (next / 12) * w + 4);
  371. float dist = pos1.minus(pos2).norm();
  372. Vec slump;
  373. slump.y = (1.0 - RACK_PLUGIN_UI_TOOLBAR->wireTensionSlider->value) * 0.4 * (150.0 + 1.0*dist);
  374. Vec pos3 = pos1.plus(pos2).div(2).plus(slump);
  375. nvgLineJoin(vg, NVG_ROUND);
  376. Vec pos4 = pos3.plus(slump.mult(0.08));
  377. nvgBeginPath(vg);
  378. nvgMoveTo(vg, pos1.x, pos1.y);
  379. nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y);
  380. nvgStrokeColor(vg, nvgHSLA(hue + (1.0f - weight) * 0.3f, 0.5f, 0.5f, weight * 255));
  381. nvgStrokeWidth(vg, 2);
  382. nvgStroke(vg);
  383. }
  384. //CURRENT
  385. nvgBeginPath(vg);
  386. nvgRect(vg, (n % 12) * w, (n / 12) * w, w, w);
  387. nvgFillColor(vg, nvgHSL(hue, 0.7f, 0.5f));
  388. nvgFill(vg);
  389. }
  390. }
  391. }
  392. };
  393. // struct MarkovSettingItem : MenuItem {
  394. // uint8_t *setting = NULL;
  395. // uint8_t offValue = 0;
  396. // uint8_t onValue = 1;
  397. // void onAction(EventAction &e) override {
  398. // // Toggle setting
  399. // *setting = (*setting == onValue) ? offValue : onValue;
  400. // }
  401. // void step() override {
  402. // rightText = (*setting == onValue) ? "✔" : "";
  403. // MenuItem::step();
  404. // }
  405. // };
  406. struct MarkovWidget : ModuleWidget {
  407. MarkovWidget(Markov *module) : ModuleWidget(module) {
  408. setPanel(SVG::load(assetPlugin(plugin, "res/panels/Markov.svg")));
  409. // SCREWS
  410. addChild(Widget::create<PeaceScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  411. addChild(Widget::create<PeaceScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  412. //HEAD
  413. int x = (int)(box.size.x * 0.5f);
  414. int y = 210;
  415. int spacex = 0;
  416. int spacey = 27;
  417. addParam(ParamWidget::create<MrChainkov>(Vec(x - 24, y), module, Markov::RANDOMNESS_PARAM, -1.0f, 1.0f, 0.0f));
  418. addInput(Port::create<InputPort>(Vec(x - 12, y - 30), Port::INPUT, module, Markov::RANDOMNESS_INPUT));
  419. // addChild(ModuleLightWidget::create<TinyLight<RedLight>>(Vec(x - 1.5f, y-8), module, Markov::DEADEND_LIGHT));
  420. // LEARN / FORGET
  421. x = 13;
  422. y = 18;
  423. spacex = (int) ((box.size.x - 16.0f) / 3.0f);
  424. spacey = 28;
  425. addChild(ModuleLightWidget::create<LargeLight<RedLight>>(Vec(x + 4.f, y + 4.f), module, Markov::LEARN_LIGHT));
  426. addParam(ParamWidget::create<RecordButton>(Vec(x, y), module, Markov::LEARN_PARAM, 0.0f, 1.0f, 0.0f));
  427. addParam(ParamWidget::create<StopButton>(Vec(x, y + spacey), module, Markov::FORGET_PARAM, 0.0f, 1.0f, 0.0f));
  428. x+=spacex * 2;
  429. addInput(Port::create<InputGatePort>(Vec(x, y), Port::INPUT, module, Markov::LEARN_INPUT));
  430. addInput(Port::create<InputGatePort>(Vec(x, y + spacey), Port::INPUT, module, Markov::FORGET_INPUT));
  431. // PORTS
  432. x = 13;
  433. y = 285;
  434. spacey = 42;
  435. addInput(Port::create<VOctInputPort>(Vec(x, y), Port::INPUT, module, Markov::CV_INPUT));
  436. addOutput(Port::create<VOctOutputPort>(Vec(x, y + spacey), Port::OUTPUT, module, Markov::CV_OUTPUT));
  437. addInput(Port::create<InputGatePort>(Vec(x + spacex + 1, y - 4), Port::INPUT, module, Markov::TRIGGER_INPUT));
  438. addInput(Port::create<InputGatePort>(Vec(x + 2 * spacex, y), Port::INPUT, module, Markov::GATE_INPUT));
  439. addOutput(Port::create<OutputGatePort>(Vec(x + 2 * spacex, y + spacey), Port::OUTPUT, module, Markov::GATE_OUTPUT));
  440. {
  441. MarkovDisplay *display = new MarkovDisplay(12,76);
  442. display->module = module;
  443. addChild(display);
  444. }
  445. }
  446. // void appendContextMenu(Menu *menu) override {
  447. // Markov *markov = dynamic_cast<Markov*>(module);
  448. // assert(markov);
  449. // // menu->addChild(construct<MenuLabel>());
  450. // // menu->addChild(construct<MenuLabel>(&MenuLabel::text, "alpha version !"));
  451. // // menu->addChild(construct<MarkovSettingItem>(&MenuItem::text, "keep loop length", &MarkovSettingItem::setting, &markov->keepLoopLength));
  452. // }
  453. };
  454. } // namespace rack_plugin_unless_modules
  455. using namespace rack_plugin_unless_modules;
  456. RACK_PLUGIN_MODEL_INIT(unless_modules, Markov) {
  457. Model *modelMarkov = Model::create<Markov, MarkovWidget>("unless games", "markov", "Mr.Chainkov : markov chain sequencer", RANDOM_TAG, MIDI_TAG, RECORDING_TAG);
  458. return modelMarkov;
  459. }
  460. /*
  461. BUG
  462. TODO
  463. reverse weights option
  464. OPTIMIZE
  465. calculate all edge counts beforehand
  466. */