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.

260 lines
6.4KB

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