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.

480 lines
15KB

  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 "global_pre.hpp"
  12. #include "app.hpp"
  13. #include "engine.hpp"
  14. #include "plugin.hpp"
  15. #include "window.hpp"
  16. #include "global.hpp"
  17. #include "global_ui.hpp"
  18. #ifdef __GNUC__
  19. #include <fenv.h>
  20. #endif
  21. namespace rack {
  22. float Light::getBrightness() {
  23. // LEDs are diodes, so don't allow reverse current.
  24. // For some reason, instead of the RMS, the sqrt of RMS looks better
  25. return powf(fmaxf(0.f, value), 0.25f);
  26. }
  27. void Light::setBrightnessSmooth(float brightness, float frames) {
  28. float v = (brightness > 0.f) ? brightness * brightness : 0.f;
  29. if (v < value) {
  30. // Fade out light with lambda = framerate
  31. value += (v - value) * global->engine.sampleTime * frames * 60.f;
  32. }
  33. else {
  34. // Immediately illuminate light
  35. value = v;
  36. }
  37. }
  38. void Wire::step() {
  39. float value = outputModule->outputs[outputId].value;
  40. inputModule->inputs[inputId].value = value;
  41. }
  42. void engineInit() {
  43. engineSetSampleRate(44100.0);
  44. }
  45. void engineDestroy() {
  46. // 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.
  47. assert(global->gWires.empty());
  48. assert(global->gModules.empty());
  49. }
  50. static void engineStep() {
  51. // Param interpolation
  52. if (global->engine.smoothModule) {
  53. float value = global->engine.smoothModule->params[global->engine.smoothParamId].value;
  54. const float lambda = 60.0; // decay rate is 1 graphics frame
  55. float delta = global->engine.smoothValue - value;
  56. float newValue = value + delta * lambda * global->engine.sampleTime;
  57. if (value == newValue) {
  58. // Snap to actual smooth value if the value doesn't change enough (due to the granularity of floats)
  59. global->engine.smoothModule->params[global->engine.smoothParamId].value = global->engine.smoothValue;
  60. global->engine.smoothModule = NULL;
  61. }
  62. else {
  63. global->engine.smoothModule->params[global->engine.smoothParamId].value = newValue;
  64. }
  65. }
  66. // Step modules
  67. for (Module *module : global->gModules) {
  68. std::chrono::high_resolution_clock::time_point startTime;
  69. if (global->gPowerMeter) {
  70. startTime = std::chrono::high_resolution_clock::now();
  71. module->step();
  72. auto stopTime = std::chrono::high_resolution_clock::now();
  73. float cpuTime = std::chrono::duration<float>(stopTime - startTime).count() * global->engine.sampleRate;
  74. module->cpuTime += (cpuTime - module->cpuTime) * global->engine.sampleTime / 0.5f;
  75. }
  76. else {
  77. module->step();
  78. }
  79. // Step ports
  80. for (Input &input : module->inputs) {
  81. if (input.active) {
  82. float value = input.value / 5.f;
  83. input.plugLights[0].setBrightnessSmooth(value);
  84. input.plugLights[1].setBrightnessSmooth(-value);
  85. }
  86. }
  87. for (Output &output : module->outputs) {
  88. if (output.active) {
  89. float value = output.value / 5.f;
  90. output.plugLights[0].setBrightnessSmooth(value);
  91. output.plugLights[1].setBrightnessSmooth(-value);
  92. }
  93. }
  94. }
  95. // Step cables by moving their output values to inputs
  96. for (Wire *wire : global->gWires) {
  97. wire->step();
  98. }
  99. }
  100. static void engineRun() {
  101. #ifdef _MSC_VER
  102. // Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode
  103. // https://software.intel.com/en-us/node/682949
  104. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
  105. _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
  106. #endif // _MSC_VER
  107. #if defined(__GNUC__) && (defined(ARCH_X64) || defined(ARCH_X86))
  108. ::fesetround(FE_TOWARDZERO);
  109. #endif // __GNUC__
  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 (global->engine.running) {
  116. global->engine.vipMutex.wait();
  117. if (!global->gPaused) {
  118. std::lock_guard<std::mutex> lock(global->engine.mutex);
  119. for (int i = 0; i < mutexSteps; i++) {
  120. engineStep();
  121. }
  122. }
  123. double stepTime = mutexSteps * global->engine.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. global->engine.running = true;
  140. global->engine.thread = std::thread(engineRun);
  141. }
  142. void engineStop() {
  143. global->engine.running = false;
  144. global->engine.thread.join();
  145. }
  146. void engineAddModule(Module *module) {
  147. assert(module);
  148. VIPLock vipLock(global->engine.vipMutex);
  149. std::lock_guard<std::mutex> lock(global->engine.mutex);
  150. // Check that the module is not already added
  151. auto it = std::find(global->gModules.begin(), global->gModules.end(), module);
  152. assert(it == global->gModules.end());
  153. global->gModules.push_back(module);
  154. #ifdef USE_VST2
  155. module->vst2_unique_param_base_id = global->vst2.next_unique_param_base_id;
  156. global->vst2.next_unique_param_base_id += module->params.size() + 1;
  157. #endif // USE_VST2
  158. }
  159. void engineRemoveModule(Module *module) {
  160. assert(module);
  161. VIPLock vipLock(global->engine.vipMutex);
  162. std::lock_guard<std::mutex> lock(global->engine.mutex);
  163. // If a param is being smoothed on this module, stop smoothing it immediately
  164. if (module == global->engine.smoothModule) {
  165. global->engine.smoothModule = NULL;
  166. }
  167. // Check that all wires are disconnected
  168. for (Wire *wire : global->gWires) {
  169. assert(wire->outputModule != module);
  170. assert(wire->inputModule != module);
  171. }
  172. // Check that the module actually exists
  173. auto it = std::find(global->gModules.begin(), global->gModules.end(), module);
  174. assert(it != global->gModules.end());
  175. // Remove it
  176. global->gModules.erase(it);
  177. }
  178. static void updateActive() {
  179. // Set everything to inactive
  180. for (Module *module : global->gModules) {
  181. for (Input &input : module->inputs) {
  182. input.active = false;
  183. }
  184. for (Output &output : module->outputs) {
  185. output.active = false;
  186. }
  187. }
  188. // Set inputs/outputs to active
  189. for (Wire *wire : global->gWires) {
  190. wire->outputModule->outputs[wire->outputId].active = true;
  191. wire->inputModule->inputs[wire->inputId].active = true;
  192. }
  193. }
  194. void engineAddWire(Wire *wire) {
  195. assert(wire);
  196. VIPLock vipLock(global->engine.vipMutex);
  197. std::lock_guard<std::mutex> lock(global->engine.mutex);
  198. // Check wire properties
  199. assert(wire->outputModule);
  200. assert(wire->inputModule);
  201. // Check that the wire is not already added, and that the input is not already used by another cable
  202. for (Wire *wire2 : global->gWires) {
  203. assert(wire2 != wire);
  204. assert(!(wire2->inputModule == wire->inputModule && wire2->inputId == wire->inputId));
  205. }
  206. // Add the wire
  207. global->gWires.push_back(wire);
  208. updateActive();
  209. }
  210. void engineRemoveWire(Wire *wire) {
  211. assert(wire);
  212. VIPLock vipLock(global->engine.vipMutex);
  213. std::lock_guard<std::mutex> lock(global->engine.mutex);
  214. // Check that the wire is already added
  215. auto it = std::find(global->gWires.begin(), global->gWires.end(), wire);
  216. assert(it != global->gWires.end());
  217. // Set input to 0V
  218. wire->inputModule->inputs[wire->inputId].value = 0.0;
  219. // Remove the wire
  220. global->gWires.erase(it);
  221. updateActive();
  222. }
  223. #ifdef USE_VST2
  224. static int loc_vst2_find_unique_param_by_module_and_paramid(Module *module, int paramId) {
  225. return module->vst2_unique_param_base_id + paramId;
  226. }
  227. static bool loc_vst2_find_module_and_paramid_by_unique_paramid(int uniqueParamId, Module**retModule, int *retParamId) {
  228. if(uniqueParamId >= 0)
  229. {
  230. if(uniqueParamId < VST2_MAX_UNIQUE_PARAM_IDS)
  231. {
  232. // (todo) speed this up with a hashtable
  233. for(Module *module : global->gModules) {
  234. if( (uniqueParamId >= module->vst2_unique_param_base_id) &&
  235. (uniqueParamId < int(module->vst2_unique_param_base_id + module->params.size()))
  236. )
  237. {
  238. *retParamId = (uniqueParamId - module->vst2_unique_param_base_id);
  239. *retModule = module;
  240. return true;
  241. }
  242. }
  243. }
  244. }
  245. return false;
  246. }
  247. #endif // USE_VST2
  248. #ifdef USE_VST2
  249. void engineSetParam(Module *module, int paramId, float value, bool bVSTAutomate) {
  250. #else
  251. void engineSetParam(Module *module, int paramId, float value) {
  252. #endif
  253. if(module->params[paramId].value == value)
  254. return;
  255. module->params[paramId].value = value;
  256. #ifdef USE_VST2
  257. if(bVSTAutomate && !global->vst2.b_patch_loading)
  258. {
  259. // (note) [bsp] this is usually called from the UI thread (see ParamWidget.cpp)
  260. // (note) [bsp] VST requires all parameters to be in the normalized 0..1 range
  261. // (note) [bsp] VCV Rack parameters however are arbitrary floats
  262. // printf("xxx vcvrack: paramId=%d value=%f (=> %f)\n", paramId, value, normValue);
  263. int uniqueParamId = loc_vst2_find_unique_param_by_module_and_paramid(module, paramId);
  264. if(-1 != uniqueParamId)
  265. {
  266. ModuleWidget *moduleWidget = global_ui->app.gRackWidget->findModuleWidgetByModule(module);
  267. if(NULL != moduleWidget)
  268. {
  269. // Find
  270. ParamWidget *paramWidget = moduleWidget->findParamWidgetByParamId(paramId);
  271. if(NULL != paramWidget)
  272. {
  273. if(isfinite(paramWidget->minValue) && isfinite(paramWidget->maxValue))
  274. {
  275. // Normalize parameter
  276. float paramRange = (paramWidget->maxValue - paramWidget->minValue);
  277. if(paramRange > 0.0f)
  278. {
  279. float normValue = (value - paramWidget->minValue) / paramRange;
  280. // printf("xxx paramId=%d normValue=%f\n", paramId, normValue);
  281. // Call host audioMasterAutomate
  282. vst2_handle_ui_param(uniqueParamId, normValue);
  283. }
  284. }
  285. }
  286. }
  287. }
  288. }
  289. #endif // USE_VST2
  290. }
  291. #ifdef USE_VST2
  292. }
  293. using namespace rack;
  294. void vst2_queue_param(int uniqueParamId, float value, bool bNormalized) {
  295. // Called from any thread via setParameter()
  296. // (note) protected by caller mutex
  297. VST2QueuedParam qp;
  298. qp.unique_id = uniqueParamId;
  299. qp.value = value;
  300. qp.b_normalized = bNormalized;
  301. global->vst2.queued_params.push_back(qp);
  302. }
  303. void vst2_handle_queued_params(void) {
  304. // Called in processReplacing()
  305. // (note) protected by caller mutex
  306. if(global->vst2.queued_params.size() > 0)
  307. {
  308. global_ui->app.mtx_param.lock();
  309. for(VST2QueuedParam qp : global->vst2.queued_params)
  310. {
  311. Module *module;
  312. int paramId;
  313. if(loc_vst2_find_module_and_paramid_by_unique_paramid(qp.unique_id, &module, &paramId))
  314. {
  315. ModuleWidget *moduleWidget = global_ui->app.gRackWidget->findModuleWidgetByModule(module);
  316. if(NULL != moduleWidget)
  317. {
  318. // Find
  319. ParamWidget *paramWidget = moduleWidget->findParamWidgetByParamId(paramId);
  320. if(NULL != paramWidget)
  321. {
  322. if(isfinite(paramWidget->minValue) && isfinite(paramWidget->maxValue))
  323. {
  324. if(qp.b_normalized)
  325. {
  326. // De-Normalize parameter
  327. global_ui->param_info.b_lock = true;
  328. float paramRange = (paramWidget->maxValue - paramWidget->minValue);
  329. if(paramRange > 0.0f)
  330. {
  331. float value = (qp.value * paramRange) + paramWidget->minValue;
  332. engineSetParam(module, paramId, value, false/*bVSTAutomate*/);
  333. // Update UI widget
  334. paramWidget->setValue(value);
  335. }
  336. global_ui->param_info.b_lock = false;
  337. }
  338. else
  339. {
  340. float value = qp.value;
  341. if(value < paramWidget->minValue)
  342. value = paramWidget->minValue;
  343. else if(value > paramWidget->maxValue)
  344. value = paramWidget->maxValue;
  345. engineSetParam(module, paramId, value, false/*bVSTAutomate*/);
  346. // Update UI widget
  347. paramWidget->setValue(qp.value);
  348. }
  349. }
  350. }
  351. }
  352. }
  353. }
  354. global->vst2.queued_params.clear();
  355. global_ui->app.mtx_param.unlock();
  356. }
  357. }
  358. float vst2_get_param(int uniqueParamId) {
  359. Module *module;
  360. int paramId;
  361. if(loc_vst2_find_module_and_paramid_by_unique_paramid(uniqueParamId, &module, &paramId))
  362. {
  363. if(sUI(paramId) < sUI(module->params.size())) // paranoia
  364. {
  365. return module->params[paramId].value;
  366. }
  367. }
  368. return 0.0f;
  369. }
  370. void vst2_get_param_name (int uniqueParamId, char *s, int sMaxLen) {
  371. Module *module;
  372. int paramId;
  373. if(loc_vst2_find_module_and_paramid_by_unique_paramid(uniqueParamId, &module, &paramId))
  374. {
  375. if(sUI(paramId) < sUI(module->params.size())) // paranoia
  376. {
  377. // (note) VCV params do not have names
  378. ::snprintf(s, sMaxLen, "%4d: <param>", uniqueParamId);
  379. return;
  380. }
  381. }
  382. ::snprintf(s, sMaxLen, "%4d: -", uniqueParamId);
  383. }
  384. namespace rack {
  385. #endif // USE_VST2
  386. void engineSetParamSmooth(Module *module, int paramId, float value) {
  387. VIPLock vipLock(global->engine.vipMutex);
  388. std::lock_guard<std::mutex> lock(global->engine.mutex);
  389. // Since only one param can be smoothed at a time, if another param is currently being smoothed, skip to its final state
  390. if (global->engine.smoothModule && !(global->engine.smoothModule == module && global->engine.smoothParamId == paramId)) {
  391. global->engine.smoothModule->params[global->engine.smoothParamId].value = global->engine.smoothValue;
  392. }
  393. global->engine.smoothModule = module;
  394. global->engine.smoothParamId = paramId;
  395. global->engine.smoothValue = value;
  396. }
  397. void engineSetSampleRate(float newSampleRate) {
  398. VIPLock vipLock(global->engine.vipMutex);
  399. std::lock_guard<std::mutex> lock(global->engine.mutex);
  400. global->engine.sampleRate = newSampleRate;
  401. global->engine.sampleTime = 1.0 / global->engine.sampleRate;
  402. // onSampleRateChange
  403. for (Module *module : global->gModules) {
  404. module->onSampleRateChange();
  405. }
  406. }
  407. float engineGetSampleRate() {
  408. return global->engine.sampleRate;
  409. }
  410. float engineGetSampleTime() {
  411. return global->engine.sampleTime;
  412. }
  413. } // namespace rack
  414. #ifdef USE_VST2
  415. using namespace rack;
  416. void vst2_set_samplerate(sF32 _rate) {
  417. rack::engineSetSampleRate(_rate);
  418. }
  419. void vst2_engine_process(float *const*_in, float **_out, unsigned int _numFrames) {
  420. global->vst2.inputs = _in;
  421. global->vst2.outputs = _out;
  422. for(global->vst2.frame_idx = 0u; global->vst2.frame_idx < _numFrames; global->vst2.frame_idx++)
  423. {
  424. engineStep();
  425. }
  426. }
  427. #endif // USE_VST2