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.

379 lines
9.9KB

  1. #include "engine/Engine.hpp"
  2. #include "settings.hpp"
  3. #include <algorithm>
  4. #include <chrono>
  5. #include <thread>
  6. #include <condition_variable>
  7. #include <mutex>
  8. #include <xmmintrin.h>
  9. #include <pmmintrin.h>
  10. namespace rack {
  11. /** Threads which obtain a VIPLock will cause wait() to block for other less important threads.
  12. This does not provide the VIPs with an exclusive lock. That should be left up to another mutex shared between the less important thread.
  13. */
  14. struct VIPMutex {
  15. int count = 0;
  16. std::condition_variable cv;
  17. std::mutex countMutex;
  18. /** Blocks until there are no remaining VIPLocks */
  19. void wait() {
  20. std::unique_lock<std::mutex> lock(countMutex);
  21. while (count > 0)
  22. cv.wait(lock);
  23. }
  24. };
  25. struct VIPLock {
  26. VIPMutex &m;
  27. VIPLock(VIPMutex &m) : m(m) {
  28. std::unique_lock<std::mutex> lock(m.countMutex);
  29. m.count++;
  30. }
  31. ~VIPLock() {
  32. std::unique_lock<std::mutex> lock(m.countMutex);
  33. m.count--;
  34. lock.unlock();
  35. m.cv.notify_all();
  36. }
  37. };
  38. struct Engine::Internal {
  39. bool running = false;
  40. float sampleRate;
  41. float sampleTime;
  42. float sampleRateRequested;
  43. Module *resetModule = NULL;
  44. Module *randomizeModule = NULL;
  45. int nextModuleId = 1;
  46. int nextCableId = 1;
  47. // Parameter smoothing
  48. Module *smoothModule = NULL;
  49. int smoothParamId;
  50. float smoothValue;
  51. std::mutex mutex;
  52. std::thread thread;
  53. VIPMutex vipMutex;
  54. };
  55. Engine::Engine() {
  56. internal = new Internal;
  57. float sampleRate = 44100.f;
  58. internal->sampleRate = sampleRate;
  59. internal->sampleTime = 1 / sampleRate;
  60. internal->sampleRateRequested = sampleRate;
  61. }
  62. Engine::~Engine() {
  63. // Make sure there are no cables or modules in the rack on destruction. This suggests that a module failed to remove itself before the RackWidget was destroyed.
  64. assert(cables.empty());
  65. assert(modules.empty());
  66. delete internal;
  67. }
  68. static void Engine_step(Engine *engine) {
  69. // Sample rate
  70. if (engine->internal->sampleRateRequested != engine->internal->sampleRate) {
  71. engine->internal->sampleRate = engine->internal->sampleRateRequested;
  72. engine->internal->sampleTime = 1 / engine->internal->sampleRate;
  73. for (Module *module : engine->modules) {
  74. module->onSampleRateChange();
  75. }
  76. }
  77. // Events
  78. if (engine->internal->resetModule) {
  79. engine->internal->resetModule->reset();
  80. engine->internal->resetModule = NULL;
  81. }
  82. if (engine->internal->randomizeModule) {
  83. engine->internal->randomizeModule->randomize();
  84. engine->internal->randomizeModule = NULL;
  85. }
  86. // Param smoothing
  87. {
  88. Module *smoothModule = engine->internal->smoothModule;
  89. int smoothParamId = engine->internal->smoothParamId;
  90. float smoothValue = engine->internal->smoothValue;
  91. if (smoothModule) {
  92. Param *param = &smoothModule->params[smoothParamId];
  93. float value = param->value;
  94. // decay rate is 1 graphics frame
  95. const float lambda = 60.f;
  96. float delta = smoothValue - value;
  97. float newValue = value + delta * lambda * engine->internal->sampleTime;
  98. if (value == newValue) {
  99. // Snap to actual smooth value if the value doesn't change enough (due to the granularity of floats)
  100. param->value = smoothValue;
  101. engine->internal->smoothModule = NULL;
  102. }
  103. else {
  104. param->value = newValue;
  105. }
  106. }
  107. }
  108. // Iterate modules
  109. for (Module *module : engine->modules) {
  110. if (module->bypass) {
  111. // Bypass module
  112. for (Output &output : module->outputs) {
  113. output.numChannels = 1;
  114. output.setVoltage(0.f);
  115. }
  116. module->cpuTime = 0.f;
  117. }
  118. else {
  119. // Step module
  120. if (settings::powerMeter) {
  121. auto startTime = std::chrono::high_resolution_clock::now();
  122. module->step();
  123. auto stopTime = std::chrono::high_resolution_clock::now();
  124. float cpuTime = std::chrono::duration<float>(stopTime - startTime).count();
  125. // Smooth cpu time
  126. float powerLambda = engine->internal->sampleTime / 2.f;
  127. module->cpuTime += (cpuTime - module->cpuTime) * powerLambda;
  128. }
  129. else {
  130. module->step();
  131. }
  132. }
  133. // Iterate ports and step plug lights
  134. for (Input &input : module->inputs) {
  135. if (input.active) {
  136. float value = input.value / 5.f;
  137. input.plugLights[0].setBrightnessSmooth(value);
  138. input.plugLights[1].setBrightnessSmooth(-value);
  139. }
  140. }
  141. for (Output &output : module->outputs) {
  142. if (output.active) {
  143. float value = output.value / 5.f;
  144. output.plugLights[0].setBrightnessSmooth(value);
  145. output.plugLights[1].setBrightnessSmooth(-value);
  146. }
  147. }
  148. }
  149. // Step cables
  150. for (Cable *cable : engine->cables) {
  151. cable->step();
  152. }
  153. }
  154. static void Engine_run(Engine *engine) {
  155. // Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode
  156. // https://software.intel.com/en-us/node/682949
  157. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
  158. _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
  159. // Every time the engine waits and locks a mutex, it steps this many frames
  160. const int mutexSteps = 64;
  161. // Time in seconds that the engine is rushing ahead of the estimated clock time
  162. double ahead = 0.0;
  163. auto lastTime = std::chrono::high_resolution_clock::now();
  164. while (engine->internal->running) {
  165. engine->internal->vipMutex.wait();
  166. if (!engine->paused) {
  167. std::lock_guard<std::mutex> lock(engine->internal->mutex);
  168. for (int i = 0; i < mutexSteps; i++) {
  169. Engine_step(engine);
  170. }
  171. }
  172. double stepTime = mutexSteps * engine->internal->sampleTime;
  173. ahead += stepTime;
  174. auto currTime = std::chrono::high_resolution_clock::now();
  175. const double aheadFactor = 2.0;
  176. ahead -= aheadFactor * std::chrono::duration<double>(currTime - lastTime).count();
  177. lastTime = currTime;
  178. ahead = std::fmax(ahead, 0.0);
  179. // Avoid pegging the CPU at 100% when there are no "blocking" modules like AudioInterface, but still step audio at a reasonable rate
  180. // The number of steps to wait before possibly sleeping
  181. const double aheadMax = 1.0; // seconds
  182. if (ahead > aheadMax) {
  183. std::this_thread::sleep_for(std::chrono::duration<double>(stepTime));
  184. }
  185. }
  186. }
  187. void Engine::start() {
  188. internal->running = true;
  189. internal->thread = std::thread(Engine_run, this);
  190. }
  191. void Engine::stop() {
  192. internal->running = false;
  193. internal->thread.join();
  194. }
  195. void Engine::addModule(Module *module) {
  196. assert(module);
  197. VIPLock vipLock(internal->vipMutex);
  198. std::lock_guard<std::mutex> lock(internal->mutex);
  199. // Check that the module is not already added
  200. auto it = std::find(modules.begin(), modules.end(), module);
  201. assert(it == modules.end());
  202. // Set ID
  203. if (module->id == 0) {
  204. // Automatically assign ID
  205. module->id = internal->nextModuleId++;
  206. }
  207. else {
  208. // Manual ID
  209. assert(module->id < internal->nextModuleId);
  210. // Check that the ID is not already taken
  211. for (Module *m : modules) {
  212. assert(module->id != m->id);
  213. }
  214. }
  215. // Add module
  216. modules.push_back(module);
  217. }
  218. void Engine::removeModule(Module *module) {
  219. assert(module);
  220. VIPLock vipLock(internal->vipMutex);
  221. std::lock_guard<std::mutex> lock(internal->mutex);
  222. // If a param is being smoothed on this module, stop smoothing it immediately
  223. if (module == internal->smoothModule) {
  224. internal->smoothModule = NULL;
  225. }
  226. // Check that all cables are disconnected
  227. for (Cable *cable : cables) {
  228. assert(cable->outputModule != module);
  229. assert(cable->inputModule != module);
  230. }
  231. // Check that the module actually exists
  232. auto it = std::find(modules.begin(), modules.end(), module);
  233. assert(it != modules.end());
  234. // Remove the module
  235. modules.erase(it);
  236. // Remove id
  237. module->id = 0;
  238. }
  239. void Engine::resetModule(Module *module) {
  240. internal->resetModule = module;
  241. }
  242. void Engine::randomizeModule(Module *module) {
  243. internal->randomizeModule = module;
  244. }
  245. static void Engine_updateActive(Engine *engine) {
  246. // Set everything to inactive
  247. for (Module *module : engine->modules) {
  248. for (Input &input : module->inputs) {
  249. input.active = false;
  250. }
  251. for (Output &output : module->outputs) {
  252. output.active = false;
  253. }
  254. }
  255. // Set inputs/outputs to active
  256. for (Cable *cable : engine->cables) {
  257. cable->outputModule->outputs[cable->outputId].active = true;
  258. cable->inputModule->inputs[cable->inputId].active = true;
  259. }
  260. }
  261. void Engine::addCable(Cable *cable) {
  262. assert(cable);
  263. VIPLock vipLock(internal->vipMutex);
  264. std::lock_guard<std::mutex> lock(internal->mutex);
  265. // Check cable properties
  266. assert(cable->outputModule);
  267. assert(cable->inputModule);
  268. // Check that the cable is not already added, and that the input is not already used by another cable
  269. for (Cable *cable2 : cables) {
  270. assert(cable2 != cable);
  271. assert(!(cable2->inputModule == cable->inputModule && cable2->inputId == cable->inputId));
  272. }
  273. // Set ID
  274. if (cable->id == 0) {
  275. // Automatically assign ID
  276. cable->id = internal->nextCableId++;
  277. }
  278. else {
  279. // Manual ID
  280. assert(cable->id < internal->nextCableId);
  281. // Check that the ID is not already taken
  282. for (Cable *w : cables) {
  283. assert(cable->id != w->id);
  284. }
  285. }
  286. // Add the cable
  287. cables.push_back(cable);
  288. Engine_updateActive(this);
  289. }
  290. void Engine::removeCable(Cable *cable) {
  291. assert(cable);
  292. VIPLock vipLock(internal->vipMutex);
  293. std::lock_guard<std::mutex> lock(internal->mutex);
  294. // Check that the cable is already added
  295. auto it = std::find(cables.begin(), cables.end(), cable);
  296. assert(it != cables.end());
  297. // Set input to 0V
  298. cable->inputModule->inputs[cable->inputId].value = 0.f;
  299. // Remove the cable
  300. cables.erase(it);
  301. Engine_updateActive(this);
  302. // Remove ID
  303. cable->id = 0;
  304. }
  305. void Engine::setParam(Module *module, int paramId, float value) {
  306. // TODO Make thread safe
  307. module->params[paramId].value = value;
  308. }
  309. void Engine::setParamSmooth(Module *module, int paramId, float value) {
  310. // If another param is being smoothed, jump value
  311. if (internal->smoothModule && !(internal->smoothModule == module && internal->smoothParamId == paramId)) {
  312. internal->smoothModule->params[internal->smoothParamId].value = internal->smoothValue;
  313. }
  314. internal->smoothParamId = paramId;
  315. internal->smoothValue = value;
  316. internal->smoothModule = module;
  317. }
  318. int Engine::getNextModuleId() {
  319. return internal->nextModuleId++;
  320. }
  321. void Engine::setSampleRate(float newSampleRate) {
  322. internal->sampleRateRequested = newSampleRate;
  323. }
  324. float Engine::getSampleRate() {
  325. return internal->sampleRate;
  326. }
  327. float Engine::getSampleTime() {
  328. return internal->sampleTime;
  329. }
  330. } // namespace rack