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.

348 lines
8.8KB

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