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.

243 lines
6.1KB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <assert.h>
  4. #include <math.h>
  5. #include <vector>
  6. #include <algorithm>
  7. #include <chrono>
  8. #include <thread>
  9. #include <xmmintrin.h>
  10. #include "engine.hpp"
  11. #include "util.hpp"
  12. namespace rack {
  13. float sampleRate = 0.0;
  14. bool gPaused = false;
  15. static bool running = false;
  16. static std::mutex mutex;
  17. static std::thread thread;
  18. static VIPMutex vipMutex;
  19. static std::vector<Module*> modules;
  20. static std::vector<Wire*> wires;
  21. // Parameter interpolation
  22. static Module *smoothModule = NULL;
  23. static int smoothParamId;
  24. static float smoothValue;
  25. void Light::setSmooth(float v) {
  26. value += (v - value) / sampleRate * 60.0;
  27. }
  28. void Wire::step() {
  29. float value = outputModule->outputs[outputId].value;
  30. inputModule->inputs[inputId].value = value;
  31. }
  32. void engineInit() {
  33. engineSetSampleRate(44100.0);
  34. }
  35. void engineDestroy() {
  36. // Make sure there are no wires or modules in the rack on destruction. This suggests that a module failed to remove itself before the GUI was destroyed.
  37. assert(wires.empty());
  38. assert(modules.empty());
  39. }
  40. static void engineStep() {
  41. // Param interpolation
  42. if (smoothModule) {
  43. float value = smoothModule->params[smoothParamId].value;
  44. const float lambda = 60.0; // decay rate is 1 graphics frame
  45. const float snap = 0.0001;
  46. float delta = smoothValue - value;
  47. if (fabsf(delta) < snap) {
  48. smoothModule->params[smoothParamId].value = smoothValue;
  49. smoothModule = NULL;
  50. }
  51. else {
  52. value += delta * lambda / sampleRate;
  53. smoothModule->params[smoothParamId].value = value;
  54. }
  55. }
  56. // Step modules
  57. for (Module *module : modules) {
  58. module->step();
  59. }
  60. // Step cables by moving their output values to inputs
  61. for (Wire *wire : wires) {
  62. wire->step();
  63. }
  64. }
  65. static void engineRun() {
  66. // Set CPU to denormals-are-zero mode
  67. // http://carlh.net/plugins/denormals.php
  68. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
  69. // Every time the engine waits and locks a mutex, it steps this many frames
  70. const int mutexSteps = 64;
  71. // Time in seconds that the engine is rushing ahead of the estimated clock time
  72. double ahead = 0.0;
  73. auto lastTime = std::chrono::high_resolution_clock::now();
  74. while (running) {
  75. vipMutex.wait();
  76. if (!gPaused) {
  77. std::lock_guard<std::mutex> lock(mutex);
  78. for (int i = 0; i < mutexSteps; i++) {
  79. engineStep();
  80. }
  81. }
  82. double stepTime = mutexSteps / sampleRate;
  83. ahead += stepTime;
  84. auto currTime = std::chrono::high_resolution_clock::now();
  85. const double aheadFactor = 2.0;
  86. ahead -= aheadFactor * std::chrono::duration<double>(currTime - lastTime).count();
  87. lastTime = currTime;
  88. ahead = fmaxf(ahead, 0.0);
  89. // Avoid pegging the CPU at 100% when there are no "blocking" modules like AudioInterface, but still step audio at a reasonable rate
  90. // The number of steps to wait before possibly sleeping
  91. const double aheadMax = 1.0; // seconds
  92. if (ahead > aheadMax) {
  93. std::this_thread::sleep_for(std::chrono::duration<double>(stepTime));
  94. }
  95. }
  96. }
  97. void engineStart() {
  98. running = true;
  99. thread = std::thread(engineRun);
  100. }
  101. void engineStop() {
  102. running = false;
  103. thread.join();
  104. }
  105. void engineAddModule(Module *module) {
  106. assert(module);
  107. VIPLock vipLock(vipMutex);
  108. std::lock_guard<std::mutex> lock(mutex);
  109. // Check that the module is not already added
  110. auto it = std::find(modules.begin(), modules.end(), module);
  111. assert(it == modules.end());
  112. modules.push_back(module);
  113. }
  114. void engineRemoveModule(Module *module) {
  115. assert(module);
  116. VIPLock vipLock(vipMutex);
  117. std::lock_guard<std::mutex> lock(mutex);
  118. // If a param is being smoothed on this module, stop smoothing it immediately
  119. if (module == smoothModule) {
  120. smoothModule = NULL;
  121. }
  122. // Check that all wires are disconnected
  123. for (Wire *wire : wires) {
  124. assert(wire->outputModule != module);
  125. assert(wire->inputModule != module);
  126. }
  127. // Check that the module actually exists
  128. auto it = std::find(modules.begin(), modules.end(), module);
  129. assert(it != modules.end());
  130. // Remove it
  131. modules.erase(it);
  132. }
  133. static void updateActive() {
  134. // Set everything to inactive
  135. for (Module *module : modules) {
  136. for (Input &input : module->inputs) {
  137. input.active = false;
  138. }
  139. for (Output &output : module->outputs) {
  140. output.active = false;
  141. }
  142. }
  143. // Set inputs/outputs to active
  144. for (Wire *wire : wires) {
  145. wire->outputModule->outputs[wire->outputId].active = true;
  146. wire->inputModule->inputs[wire->inputId].active = true;
  147. }
  148. }
  149. void engineAddWire(Wire *wire) {
  150. assert(wire);
  151. VIPLock vipLock(vipMutex);
  152. std::lock_guard<std::mutex> lock(mutex);
  153. // Check wire properties
  154. assert(wire->outputModule);
  155. assert(wire->inputModule);
  156. // Check that the wire is not already added, and that the input is not already used by another cable
  157. for (Wire *wire2 : wires) {
  158. assert(wire2 != wire);
  159. assert(!(wire2->inputModule == wire->inputModule && wire2->inputId == wire->inputId));
  160. }
  161. // Add the wire
  162. wires.push_back(wire);
  163. updateActive();
  164. }
  165. void engineRemoveWire(Wire *wire) {
  166. assert(wire);
  167. VIPLock vipLock(vipMutex);
  168. std::lock_guard<std::mutex> lock(mutex);
  169. // Check that the wire is already added
  170. auto it = std::find(wires.begin(), wires.end(), wire);
  171. assert(it != wires.end());
  172. // Set input to 0V
  173. wire->inputModule->inputs[wire->inputId].value = 0.0;
  174. // Remove the wire
  175. wires.erase(it);
  176. updateActive();
  177. }
  178. void engineSetParam(Module *module, int paramId, float value) {
  179. module->params[paramId].value = value;
  180. }
  181. void engineSetParamSmooth(Module *module, int paramId, float value) {
  182. VIPLock vipLock(vipMutex);
  183. std::lock_guard<std::mutex> lock(mutex);
  184. // Since only one param can be smoothed at a time, if another param is currently being smoothed, skip to its final state
  185. if (smoothModule && !(smoothModule == module && smoothParamId == paramId)) {
  186. smoothModule->params[smoothParamId].value = smoothValue;
  187. }
  188. smoothModule = module;
  189. smoothParamId = paramId;
  190. smoothValue = value;
  191. }
  192. void engineSetSampleRate(float newSampleRate) {
  193. VIPLock vipLock(vipMutex);
  194. std::lock_guard<std::mutex> lock(mutex);
  195. sampleRate = newSampleRate;
  196. // onSampleRateChange
  197. for (Module *module : modules) {
  198. module->onSampleRateChange();
  199. }
  200. }
  201. float engineGetSampleRate() {
  202. return sampleRate;
  203. }
  204. } // namespace rack