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.

248 lines
6.6KB

  1. #include "Southpole.hpp"
  2. #include "dsp/digital.hpp"
  3. namespace rack_plugin_Southpole {
  4. #define NSNAKEBUSS 16
  5. #define NSNAKEPORTS 10
  6. struct Snake : Module {
  7. enum ParamIds {
  8. PLUS_PARAM,
  9. MINUS_PARAM,
  10. NUM_PARAMS
  11. };
  12. enum InputIds {
  13. IN_INPUT,
  14. NUM_INPUTS = IN_INPUT + NSNAKEPORTS + 1
  15. };
  16. enum OutputIds {
  17. OUT_OUTPUT,
  18. NUM_OUTPUTS = OUT_OUTPUT + NSNAKEPORTS + 1
  19. };
  20. enum LightIds {
  21. LOCK_LIGHT,
  22. NUM_LIGHTS = LOCK_LIGHT + 2*NSNAKEPORTS + 2
  23. };
  24. static int nsnakes;
  25. static float cable[NSNAKEBUSS][NSNAKEPORTS];
  26. static int lockid[NSNAKEBUSS][NSNAKEPORTS];
  27. int buss = 0;
  28. int id;
  29. SchmittTrigger plusTrigger;
  30. SchmittTrigger minusTrigger;
  31. Snake() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  32. // first Snake module instantiation
  33. if (nsnakes == 0) {
  34. //printf("initialize Snake system\n");
  35. for (int b=0; b< NSNAKEBUSS; b++) {
  36. for (int i=0; i< NSNAKEPORTS; i++) {
  37. cable[b][i] = 0.;
  38. lockid[b][i] = 0;
  39. }
  40. }
  41. }
  42. nsnakes++;
  43. buss = 0;
  44. id = nsnakes;
  45. //dump("constructor");
  46. }
  47. ~Snake() {
  48. // clean up
  49. for (int i=0; i < NSNAKEPORTS; i++) {
  50. if ( lockid[buss][i] == id ) {
  51. lockid[buss][i] = 0;
  52. cable[buss][i] = 0;
  53. }
  54. }
  55. nsnakes--;
  56. //dump("destructor");
  57. }
  58. void step() override;
  59. json_t *toJson() override {
  60. json_t *rootJ = json_object();
  61. json_object_set_new(rootJ, "buss", json_integer(buss));
  62. return rootJ;
  63. }
  64. void fromJson(json_t *rootJ) override {
  65. json_t *bussJ = json_object_get(rootJ, "buss");
  66. if (bussJ) { buss = json_integer_value(bussJ); }
  67. //dump("fromJson");
  68. }
  69. void dump( const char * where="" ) {
  70. printf( "%p [%s] (%d) buss %d: id %d, lockid: [ ", this, where, nsnakes, buss, id );
  71. for (int i=0; i< NSNAKEPORTS; i++) {
  72. printf("%d, ", lockid[buss][i]);
  73. }
  74. printf(" ] %f %f\n", params[PLUS_PARAM].value, params[MINUS_PARAM].value);
  75. }
  76. };
  77. int Snake::nsnakes = 0;
  78. float Snake::cable[NSNAKEBUSS][NSNAKEPORTS];
  79. int Snake::lockid[NSNAKEBUSS][NSNAKEPORTS];
  80. void Snake::step() {
  81. // change buss on trigger
  82. if (plusTrigger.process(params[PLUS_PARAM].value)) {
  83. if (buss < NSNAKEBUSS-1) {
  84. // free and clean up current buss
  85. for (int i=0; i < NSNAKEPORTS; i++) {
  86. if ( lockid[buss][i] == id ) {
  87. lockid[buss][i] = 0;
  88. cable[buss][i] = 0;
  89. }
  90. }
  91. buss++;
  92. //dump("plus");
  93. }
  94. }
  95. if (minusTrigger.process(params[MINUS_PARAM].value)) {
  96. if (buss > 0) {
  97. // free and clean up current buss
  98. for (int i=0; i < NSNAKEPORTS; i++) {
  99. if ( lockid[buss][i] == id ) {
  100. lockid[buss][i] = 0;
  101. cable[buss][i] = 0;
  102. }
  103. }
  104. buss--;
  105. //dump("minus");
  106. }
  107. }
  108. for (int i=0; i < NSNAKEPORTS; i++) {
  109. // if active try to lock input
  110. if ( inputs[IN_INPUT+i].active ) {
  111. if ( lockid[buss][i] == 0 ) {
  112. lockid[buss][i] = id;
  113. //dump("lock");
  114. }
  115. if ( lockid[buss][i] == id ) {
  116. cable[buss][i] = inputs[IN_INPUT+i].value;
  117. }
  118. } else if ( lockid[buss][i] == id ) {
  119. lockid[buss][i] = 0;
  120. cable[buss][i] = 0;
  121. //dump("release");
  122. }
  123. // operate lights
  124. if ( lockid[buss][i] == 0 ) {
  125. lights[LOCK_LIGHT+2*i ].setBrightness(0);
  126. lights[LOCK_LIGHT+2*i+1].setBrightness(0);
  127. } else if ( lockid[buss][i] == id ) {
  128. lights[LOCK_LIGHT+2*i ].setBrightness(1.0);
  129. lights[LOCK_LIGHT+2*i+1].setBrightness(0.);
  130. } else {
  131. lights[LOCK_LIGHT+2*i ].setBrightness(0.);
  132. lights[LOCK_LIGHT+2*i+1].setBrightness(1.);
  133. }
  134. // set output
  135. outputs[OUT_OUTPUT+i].value = cable[buss][i];
  136. }
  137. }
  138. struct SnakeDisplay : TransparentWidget {
  139. Snake *module;
  140. std::shared_ptr<Font> font;
  141. SnakeDisplay() {
  142. font = Font::load(assetPlugin(plugin, "res/hdad-segment14-1.002/Segment14.ttf"));
  143. }
  144. void draw(NVGcontext *vg) override {
  145. // Background
  146. NVGcolor backgroundColor = nvgRGB(0x30, 0x10, 0x10);
  147. NVGcolor borderColor = nvgRGB(0xd0, 0xd0, 0xd0);
  148. nvgBeginPath(vg);
  149. nvgRoundedRect(vg, 0.0, 0.0, box.size.x, box.size.y, 5.0);
  150. nvgFillColor(vg, backgroundColor);
  151. nvgFill(vg);
  152. nvgStrokeWidth(vg, 1.5);
  153. nvgStrokeColor(vg, borderColor);
  154. nvgStroke(vg);
  155. nvgFontSize(vg, 20.);
  156. nvgFontFaceId(vg, font->handle);
  157. nvgTextLetterSpacing(vg, 2.);
  158. Vec textPos = Vec(5, 28);
  159. NVGcolor textColor = nvgRGB(0xff, 0x00, 0x00);
  160. nvgFillColor(vg, nvgTransRGBA(textColor, 16));
  161. nvgText(vg, textPos.x, textPos.y, "~~~~", NULL);
  162. nvgFillColor(vg, textColor);
  163. char strbuss[4];
  164. sprintf(strbuss,"%1x",module->buss);
  165. nvgText(vg, textPos.x, textPos.y, strbuss, NULL);
  166. }
  167. };
  168. struct SnakeWidget : ModuleWidget {
  169. SnakeWidget(Snake *module) : ModuleWidget(module) {
  170. box.size = Vec(15*4, 380);
  171. {
  172. SVGPanel *panel = new SVGPanel();
  173. panel->box.size = box.size;
  174. panel->setBackground(SVG::load(assetPlugin(plugin, "res/Snake.svg")));
  175. addChild(panel);
  176. }
  177. {
  178. SnakeDisplay *display = new SnakeDisplay();
  179. display->box.pos = Vec(5., 30.);
  180. display->box.size = Vec(25., 34.);
  181. display->module = module;
  182. addChild(display);
  183. }
  184. addParam(ParamWidget::create<TL1105>(Vec( 40, 30 ), module, Snake::PLUS_PARAM, 0.0, 1.0, 0.0));
  185. addParam(ParamWidget::create<TL1105>(Vec( 40, 50 ), module, Snake::MINUS_PARAM, 0.0, 1.0, 0.0));
  186. float y1 = 85;
  187. float yh = 26;
  188. for (int i=0; i< NSNAKEPORTS; i++)
  189. {
  190. float y = y1+i*yh + floor(i/5)*yh*.4;
  191. addInput(Port::create<sp_Port>( Vec( 5, y), Port::INPUT, module, Snake::IN_INPUT + i));
  192. addOutput(Port::create<sp_Port>(Vec(34, y), Port::OUTPUT, module, Snake::OUT_OUTPUT + i));
  193. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(Vec(26, y), module, Snake::LOCK_LIGHT + 2*i));
  194. }
  195. }
  196. };
  197. } // namespace rack_plugin_Southpole
  198. using namespace rack_plugin_Southpole;
  199. RACK_PLUGIN_MODEL_INIT(Southpole, Snake) {
  200. Model *modelSnake = Model::create<Snake,SnakeWidget>( "Southpole", "Snake", "Snake - multicore", UTILITY_TAG);
  201. return modelSnake;
  202. }