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.

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