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.

181 lines
4.3KB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <assert.h>
  4. #include <math.h>
  5. #include <list>
  6. #include <thread>
  7. #include <mutex>
  8. #include <condition_variable>
  9. #include "rack.hpp"
  10. static std::thread thread;
  11. static std::mutex mutex;
  12. static std::condition_variable cv;
  13. static long frame;
  14. static long frameLimit;
  15. static bool running;
  16. static std::set<Module*> modules;
  17. // Merely used for keeping track of which module inputs point to which module outputs, to prevent pointer mistakes and make the rack API rigorous
  18. static std::set<Wire*> wires;
  19. static Module *smoothModule = NULL;
  20. static int smoothParamId;
  21. static float smoothValue;
  22. void rackInit() {
  23. }
  24. void rackDestroy() {
  25. // Make sure there are no wires or modules in the rack on destruction. This suggests that a module failed to remove itself when the GUI was destroyed.
  26. assert(wires.empty());
  27. assert(modules.empty());
  28. }
  29. void rackStep() {
  30. // Param interpolation
  31. if (smoothModule) {
  32. float value = smoothModule->params[smoothParamId];
  33. const float minSpeed = 0.01 * 60.0 / SAMPLE_RATE; // Roughly 0.01 every graphics frame
  34. const float lpCoeff = 60.0 / SAMPLE_RATE / 1.0; // decay rate is 1 graphics frame
  35. float delta = smoothValue - value;
  36. float speed = fmaxf(fabsf(delta) * lpCoeff, minSpeed);
  37. if (delta < 0) {
  38. value -= speed;
  39. if (value < smoothValue) value = smoothValue;
  40. }
  41. else if (delta > 0) {
  42. value += speed;
  43. if (value > smoothValue) value = smoothValue;
  44. }
  45. smoothModule->params[smoothParamId] = value;
  46. if (value == smoothValue) {
  47. smoothModule = NULL;
  48. }
  49. }
  50. // Step all modules
  51. for (Module *module : modules) {
  52. module->step();
  53. }
  54. }
  55. void rackRun() {
  56. while (1) {
  57. std::unique_lock<std::mutex> lock(mutex);
  58. if (!running)
  59. break;
  60. if (frame >= frameLimit) {
  61. // Delay for at most 1ms if there are no needed frames
  62. cv.wait_for(lock, std::chrono::milliseconds(1));
  63. }
  64. frame++;
  65. lock.unlock();
  66. // Speed up
  67. // for (int i = 0; i < 16; i++)
  68. rackStep();
  69. }
  70. }
  71. void rackStart() {
  72. frame = 0;
  73. frameLimit = 0;
  74. running = true;
  75. thread = std::thread(rackRun);
  76. }
  77. void rackStop() {
  78. {
  79. std::unique_lock<std::mutex> lock(mutex);
  80. running = false;
  81. }
  82. cv.notify_all();
  83. thread.join();
  84. }
  85. void rackAddModule(Module *module) {
  86. assert(module);
  87. // Check that the module is not already added
  88. assert(modules.find(module) == modules.end());
  89. modules.insert(module);
  90. }
  91. void rackRemoveModule(Module *module) {
  92. assert(module);
  93. // Remove parameter interpolation which point to this module
  94. if (module == smoothModule) {
  95. smoothModule = NULL;
  96. }
  97. // FIXME use a mutex here
  98. // Check that all wires are disconnected
  99. for (Wire *wire : wires) {
  100. assert(wire->outputModule != module);
  101. assert(wire->inputModule != module);
  102. }
  103. auto it = modules.find(module);
  104. if (it != modules.end()) {
  105. modules.erase(it);
  106. }
  107. }
  108. void rackConnectWire(Wire *wire) {
  109. assert(wire);
  110. // It would probably be good to reset the wire voltage
  111. wire->value = 0.0;
  112. // Check that the wire is not already added
  113. assert(wires.find(wire) == wires.end());
  114. assert(wire->outputModule);
  115. assert(wire->inputModule);
  116. // Check that the inputs/outputs are not already used by another cable
  117. for (Wire *wire2 : wires) {
  118. assert(wire2 != wire);
  119. assert(!(wire2->outputModule == wire->outputModule && wire2->outputId == wire->outputId));
  120. assert(!(wire2->inputModule == wire->inputModule && wire2->inputId == wire->inputId));
  121. }
  122. // Connect the wire to inputModule
  123. wires.insert(wire);
  124. wire->inputModule->inputs[wire->inputId] = &wire->value;
  125. wire->outputModule->outputs[wire->outputId] = &wire->value;
  126. }
  127. void rackDisconnectWire(Wire *wire) {
  128. assert(wire);
  129. // Disconnect wire from inputModule
  130. wire->inputModule->inputs[wire->inputId] = NULL;
  131. wire->outputModule->outputs[wire->outputId] = NULL;
  132. auto it = wires.find(wire);
  133. assert(it != wires.end());
  134. wires.erase(it);
  135. }
  136. long rackGetFrame() {
  137. return frame;
  138. }
  139. void rackRequestFrame(long f) {
  140. std::unique_lock<std::mutex> lock(mutex);
  141. if (f > frameLimit) {
  142. frameLimit = f;
  143. lock.unlock();
  144. cv.notify_all();
  145. }
  146. }
  147. void rackSetParamSmooth(Module *module, int paramId, float value) {
  148. // Check existing parameter interpolation
  149. if (smoothModule) {
  150. if (!(smoothModule == module && smoothParamId == paramId)) {
  151. // Jump param value to smooth value
  152. smoothModule->params[smoothParamId] = smoothValue;
  153. }
  154. }
  155. smoothModule = module;
  156. smoothParamId = paramId;
  157. smoothValue = value;
  158. }