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.

279 lines
7.0KB

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