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.

engine.cpp 6.9KB

7 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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 > 0.0) ? brightness * brightness : 0.0;
  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. // TODO skip this step when plug lights are disabled
  72. // Step ports
  73. for (Input &input : module->inputs) {
  74. if (input.active) {
  75. float value = input.value / 10.0;
  76. input.plugLights[0].setBrightnessSmooth(value);
  77. input.plugLights[1].setBrightnessSmooth(-value);
  78. }
  79. }
  80. for (Output &output : module->outputs) {
  81. if (output.active) {
  82. float value = output.value / 10.0;
  83. output.plugLights[0].setBrightnessSmooth(value);
  84. output.plugLights[1].setBrightnessSmooth(-value);
  85. }
  86. }
  87. }
  88. // Step cables by moving their output values to inputs
  89. for (Wire *wire : wires) {
  90. wire->step();
  91. }
  92. }
  93. static void engineRun() {
  94. // Set CPU to denormals-are-zero mode
  95. // http://carlh.net/plugins/denormals.php
  96. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
  97. // Every time the engine waits and locks a mutex, it steps this many frames
  98. const int mutexSteps = 64;
  99. // Time in seconds that the engine is rushing ahead of the estimated clock time
  100. double ahead = 0.0;
  101. auto lastTime = std::chrono::high_resolution_clock::now();
  102. while (running) {
  103. vipMutex.wait();
  104. if (!gPaused) {
  105. std::lock_guard<std::mutex> lock(mutex);
  106. for (int i = 0; i < mutexSteps; i++) {
  107. engineStep();
  108. }
  109. }
  110. double stepTime = mutexSteps * sampleTime;
  111. ahead += stepTime;
  112. auto currTime = std::chrono::high_resolution_clock::now();
  113. const double aheadFactor = 2.0;
  114. ahead -= aheadFactor * std::chrono::duration<double>(currTime - lastTime).count();
  115. lastTime = currTime;
  116. ahead = fmaxf(ahead, 0.0);
  117. // Avoid pegging the CPU at 100% when there are no "blocking" modules like AudioInterface, but still step audio at a reasonable rate
  118. // The number of steps to wait before possibly sleeping
  119. const double aheadMax = 1.0; // seconds
  120. if (ahead > aheadMax) {
  121. std::this_thread::sleep_for(std::chrono::duration<double>(stepTime));
  122. }
  123. }
  124. }
  125. void engineStart() {
  126. running = true;
  127. thread = std::thread(engineRun);
  128. }
  129. void engineStop() {
  130. running = false;
  131. thread.join();
  132. }
  133. void engineAddModule(Module *module) {
  134. assert(module);
  135. VIPLock vipLock(vipMutex);
  136. std::lock_guard<std::mutex> lock(mutex);
  137. // Check that the module is not already added
  138. auto it = std::find(modules.begin(), modules.end(), module);
  139. assert(it == modules.end());
  140. modules.push_back(module);
  141. }
  142. void engineRemoveModule(Module *module) {
  143. assert(module);
  144. VIPLock vipLock(vipMutex);
  145. std::lock_guard<std::mutex> lock(mutex);
  146. // If a param is being smoothed on this module, stop smoothing it immediately
  147. if (module == smoothModule) {
  148. smoothModule = NULL;
  149. }
  150. // Check that all wires are disconnected
  151. for (Wire *wire : wires) {
  152. assert(wire->outputModule != module);
  153. assert(wire->inputModule != module);
  154. }
  155. // Check that the module actually exists
  156. auto it = std::find(modules.begin(), modules.end(), module);
  157. assert(it != modules.end());
  158. // Remove it
  159. modules.erase(it);
  160. }
  161. static void updateActive() {
  162. // Set everything to inactive
  163. for (Module *module : modules) {
  164. for (Input &input : module->inputs) {
  165. input.active = false;
  166. }
  167. for (Output &output : module->outputs) {
  168. output.active = false;
  169. }
  170. }
  171. // Set inputs/outputs to active
  172. for (Wire *wire : wires) {
  173. wire->outputModule->outputs[wire->outputId].active = true;
  174. wire->inputModule->inputs[wire->inputId].active = true;
  175. }
  176. }
  177. void engineAddWire(Wire *wire) {
  178. assert(wire);
  179. VIPLock vipLock(vipMutex);
  180. std::lock_guard<std::mutex> lock(mutex);
  181. // Check wire properties
  182. assert(wire->outputModule);
  183. assert(wire->inputModule);
  184. // Check that the wire is not already added, and that the input is not already used by another cable
  185. for (Wire *wire2 : wires) {
  186. assert(wire2 != wire);
  187. assert(!(wire2->inputModule == wire->inputModule && wire2->inputId == wire->inputId));
  188. }
  189. // Add the wire
  190. wires.push_back(wire);
  191. updateActive();
  192. }
  193. void engineRemoveWire(Wire *wire) {
  194. assert(wire);
  195. VIPLock vipLock(vipMutex);
  196. std::lock_guard<std::mutex> lock(mutex);
  197. // Check that the wire is already added
  198. auto it = std::find(wires.begin(), wires.end(), wire);
  199. assert(it != wires.end());
  200. // Set input to 0V
  201. wire->inputModule->inputs[wire->inputId].value = 0.0;
  202. // Remove the wire
  203. wires.erase(it);
  204. updateActive();
  205. }
  206. void engineSetParam(Module *module, int paramId, float value) {
  207. module->params[paramId].value = value;
  208. }
  209. void engineSetParamSmooth(Module *module, int paramId, float value) {
  210. VIPLock vipLock(vipMutex);
  211. std::lock_guard<std::mutex> lock(mutex);
  212. // Since only one param can be smoothed at a time, if another param is currently being smoothed, skip to its final state
  213. if (smoothModule && !(smoothModule == module && smoothParamId == paramId)) {
  214. smoothModule->params[smoothParamId].value = smoothValue;
  215. }
  216. smoothModule = module;
  217. smoothParamId = paramId;
  218. smoothValue = value;
  219. }
  220. void engineSetSampleRate(float newSampleRate) {
  221. VIPLock vipLock(vipMutex);
  222. std::lock_guard<std::mutex> lock(mutex);
  223. sampleRate = newSampleRate;
  224. sampleTime = 1.0 / sampleRate;
  225. // onSampleRateChange
  226. for (Module *module : modules) {
  227. module->onSampleRateChange();
  228. }
  229. }
  230. float engineGetSampleRate() {
  231. return sampleRate;
  232. }
  233. float engineGetSampleTime() {
  234. return sampleTime;
  235. }
  236. } // namespace rack