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.

290 lines
7.6KB

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