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.

479 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. namespace rack {
  19. float Light::getBrightness() {
  20. // LEDs are diodes, so don't allow reverse current.
  21. // For some reason, instead of the RMS, the sqrt of RMS looks better
  22. return powf(fmaxf(0.f, value), 0.25f);
  23. }
  24. void Light::setBrightnessSmooth(float brightness, float frames) {
  25. float v = (brightness > 0.f) ? brightness * brightness : 0.f;
  26. if (v < value) {
  27. // Fade out light with lambda = framerate
  28. value += (v - value) * global->engine.sampleTime * frames * 60.f;
  29. }
  30. else {
  31. // Immediately illuminate light
  32. value = v;
  33. }
  34. }
  35. void Wire::step() {
  36. float value = outputModule->outputs[outputId].value;
  37. inputModule->inputs[inputId].value = value;
  38. }
  39. void engineInit() {
  40. engineSetSampleRate(44100.0);
  41. }
  42. void engineDestroy() {
  43. // 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.
  44. assert(global->gWires.empty());
  45. assert(global->gModules.empty());
  46. }
  47. static void engineStep() {
  48. // Param interpolation
  49. if (global->engine.smoothModule) {
  50. float value = global->engine.smoothModule->params[global->engine.smoothParamId].value;
  51. const float lambda = 60.0; // decay rate is 1 graphics frame
  52. float delta = global->engine.smoothValue - value;
  53. float newValue = value + delta * lambda * global->engine.sampleTime;
  54. if (value == newValue) {
  55. // Snap to actual smooth value if the value doesn't change enough (due to the granularity of floats)
  56. global->engine.smoothModule->params[global->engine.smoothParamId].value = global->engine.smoothValue;
  57. global->engine.smoothModule = NULL;
  58. }
  59. else {
  60. global->engine.smoothModule->params[global->engine.smoothParamId].value = newValue;
  61. }
  62. }
  63. // Step modules
  64. for (Module *module : global->gModules) {
  65. std::chrono::high_resolution_clock::time_point startTime;
  66. if (global->gPowerMeter) {
  67. startTime = std::chrono::high_resolution_clock::now();
  68. module->step();
  69. auto stopTime = std::chrono::high_resolution_clock::now();
  70. float cpuTime = std::chrono::duration<float>(stopTime - startTime).count() * global->engine.sampleRate;
  71. module->cpuTime += (cpuTime - module->cpuTime) * global->engine.sampleTime / 0.5f;
  72. }
  73. else {
  74. module->step();
  75. }
  76. // Step ports
  77. for (Input &input : module->inputs) {
  78. if (input.active) {
  79. float value = input.value / 5.f;
  80. input.plugLights[0].setBrightnessSmooth(value);
  81. input.plugLights[1].setBrightnessSmooth(-value);
  82. }
  83. }
  84. for (Output &output : module->outputs) {
  85. if (output.active) {
  86. float value = output.value / 5.f;
  87. output.plugLights[0].setBrightnessSmooth(value);
  88. output.plugLights[1].setBrightnessSmooth(-value);
  89. }
  90. }
  91. }
  92. // Step cables by moving their output values to inputs
  93. for (Wire *wire : global->gWires) {
  94. wire->step();
  95. }
  96. }
  97. static void engineRun() {
  98. // Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode
  99. // https://software.intel.com/en-us/node/682949
  100. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
  101. _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
  102. // Every time the engine waits and locks a mutex, it steps this many frames
  103. const int mutexSteps = 64;
  104. // Time in seconds that the engine is rushing ahead of the estimated clock time
  105. double ahead = 0.0;
  106. auto lastTime = std::chrono::high_resolution_clock::now();
  107. while (global->engine.running) {
  108. global->engine.vipMutex.wait();
  109. if (!global->gPaused) {
  110. std::lock_guard<std::mutex> lock(global->engine.mutex);
  111. for (int i = 0; i < mutexSteps; i++) {
  112. engineStep();
  113. }
  114. }
  115. double stepTime = mutexSteps * global->engine.sampleTime;
  116. ahead += stepTime;
  117. auto currTime = std::chrono::high_resolution_clock::now();
  118. const double aheadFactor = 2.0;
  119. ahead -= aheadFactor * std::chrono::duration<double>(currTime - lastTime).count();
  120. lastTime = currTime;
  121. ahead = fmaxf(ahead, 0.0);
  122. // Avoid pegging the CPU at 100% when there are no "blocking" modules like AudioInterface, but still step audio at a reasonable rate
  123. // The number of steps to wait before possibly sleeping
  124. const double aheadMax = 1.0; // seconds
  125. if (ahead > aheadMax) {
  126. std::this_thread::sleep_for(std::chrono::duration<double>(stepTime));
  127. }
  128. }
  129. }
  130. void engineStart() {
  131. global->engine.running = true;
  132. global->engine.thread = std::thread(engineRun);
  133. }
  134. void engineStop() {
  135. global->engine.running = false;
  136. global->engine.thread.join();
  137. }
  138. void engineAddModule(Module *module) {
  139. assert(module);
  140. VIPLock vipLock(global->engine.vipMutex);
  141. std::lock_guard<std::mutex> lock(global->engine.mutex);
  142. // Check that the module is not already added
  143. auto it = std::find(global->gModules.begin(), global->gModules.end(), module);
  144. assert(it == global->gModules.end());
  145. global->gModules.push_back(module);
  146. #ifdef USE_VST2
  147. module->vst2_unique_param_base_id = global->vst2.next_unique_param_base_id;
  148. global->vst2.next_unique_param_base_id += module->params.size() + 1;
  149. #endif // USE_VST2
  150. }
  151. void engineRemoveModule(Module *module) {
  152. assert(module);
  153. VIPLock vipLock(global->engine.vipMutex);
  154. std::lock_guard<std::mutex> lock(global->engine.mutex);
  155. // If a param is being smoothed on this module, stop smoothing it immediately
  156. if (module == global->engine.smoothModule) {
  157. global->engine.smoothModule = NULL;
  158. }
  159. // Check that all wires are disconnected
  160. for (Wire *wire : global->gWires) {
  161. assert(wire->outputModule != module);
  162. assert(wire->inputModule != module);
  163. }
  164. // Check that the module actually exists
  165. auto it = std::find(global->gModules.begin(), global->gModules.end(), module);
  166. assert(it != global->gModules.end());
  167. // Remove it
  168. global->gModules.erase(it);
  169. }
  170. static void updateActive() {
  171. // Set everything to inactive
  172. for (Module *module : global->gModules) {
  173. for (Input &input : module->inputs) {
  174. input.active = false;
  175. }
  176. for (Output &output : module->outputs) {
  177. output.active = false;
  178. }
  179. }
  180. // Set inputs/outputs to active
  181. for (Wire *wire : global->gWires) {
  182. wire->outputModule->outputs[wire->outputId].active = true;
  183. wire->inputModule->inputs[wire->inputId].active = true;
  184. }
  185. }
  186. void engineAddWire(Wire *wire) {
  187. assert(wire);
  188. VIPLock vipLock(global->engine.vipMutex);
  189. std::lock_guard<std::mutex> lock(global->engine.mutex);
  190. // Check wire properties
  191. assert(wire->outputModule);
  192. assert(wire->inputModule);
  193. // Check that the wire is not already added, and that the input is not already used by another cable
  194. for (Wire *wire2 : global->gWires) {
  195. assert(wire2 != wire);
  196. assert(!(wire2->inputModule == wire->inputModule && wire2->inputId == wire->inputId));
  197. }
  198. // Add the wire
  199. global->gWires.push_back(wire);
  200. updateActive();
  201. }
  202. void engineRemoveWire(Wire *wire) {
  203. assert(wire);
  204. VIPLock vipLock(global->engine.vipMutex);
  205. std::lock_guard<std::mutex> lock(global->engine.mutex);
  206. // Check that the wire is already added
  207. auto it = std::find(global->gWires.begin(), global->gWires.end(), wire);
  208. assert(it != global->gWires.end());
  209. // Set input to 0V
  210. wire->inputModule->inputs[wire->inputId].value = 0.0;
  211. // Remove the wire
  212. global->gWires.erase(it);
  213. updateActive();
  214. }
  215. #ifdef USE_VST2
  216. static int loc_vst2_find_unique_param_by_module_and_paramid(Module *module, int paramId) {
  217. return module->vst2_unique_param_base_id + paramId;
  218. }
  219. static bool loc_vst2_find_module_and_paramid_by_unique_paramid(int uniqueParamId, Module**retModule, int *retParamId) {
  220. if(uniqueParamId >= 0)
  221. {
  222. if(uniqueParamId < VST2_MAX_UNIQUE_PARAM_IDS)
  223. {
  224. // (todo) speed this up with a hashtable
  225. for(Module *module : global->gModules) {
  226. if( (uniqueParamId >= module->vst2_unique_param_base_id) &&
  227. (uniqueParamId < (module->vst2_unique_param_base_id + module->params.size()))
  228. )
  229. {
  230. *retParamId = (uniqueParamId - module->vst2_unique_param_base_id);
  231. *retModule = module;
  232. return true;
  233. }
  234. }
  235. }
  236. }
  237. return false;
  238. }
  239. #endif // USE_VST2
  240. #ifdef USE_VST2
  241. void engineSetParam(Module *module, int paramId, float value, bool bVSTAutomate) {
  242. #else
  243. void engineSetParam(Module *module, int paramId, float value) {
  244. #endif
  245. if(module->params[paramId].value == value)
  246. return;
  247. module->params[paramId].value = value;
  248. #ifdef USE_VST2
  249. if(bVSTAutomate && !global->vst2.b_patch_loading)
  250. {
  251. // (note) [bsp] this is usually called from the UI thread (see ParamWidget.cpp)
  252. // (note) [bsp] VST requires all parameters to be in the normalized 0..1 range
  253. // (note) [bsp] VCV Rack parameters however are arbitrary floats
  254. // printf("xxx vcvrack: paramId=%d value=%f (=> %f)\n", paramId, value, normValue);
  255. int uniqueParamId = loc_vst2_find_unique_param_by_module_and_paramid(module, paramId);
  256. if(-1 != uniqueParamId)
  257. {
  258. ModuleWidget *moduleWidget = global_ui->app.gRackWidget->findModuleWidgetByModule(module);
  259. if(NULL != moduleWidget)
  260. {
  261. // Find
  262. ParamWidget *paramWidget = moduleWidget->findParamWidgetByParamId(paramId);
  263. if(NULL != paramWidget)
  264. {
  265. if(isfinite(paramWidget->minValue) && isfinite(paramWidget->maxValue))
  266. {
  267. // Normalize parameter
  268. float paramRange = (paramWidget->maxValue - paramWidget->minValue);
  269. if(paramRange > 0.0f)
  270. {
  271. float normValue = (value - paramWidget->minValue) / paramRange;
  272. // printf("xxx paramId=%d normValue=%f\n", paramId, normValue);
  273. // Call host audioMasterAutomate
  274. vst2_handle_ui_param(uniqueParamId, normValue);
  275. }
  276. }
  277. }
  278. }
  279. // else
  280. // {
  281. // // Should not be reachable
  282. // // (note) [bsp] this scale+bias hack should work for most parameters, though
  283. // // (note) [bsp] => automation curves will look a bit strange, though
  284. // // (note) [bsp] => this may potentially crash modules which cannot deal with params outside the expected range
  285. // float normValue = value / 2.0f;
  286. // normValue += 0.5f;
  287. // // Call host audioMasterAutomate
  288. // vst2_handle_ui_param(uniqueParamId, normValue);
  289. // }
  290. }
  291. }
  292. #endif // USE_VST2
  293. }
  294. #ifdef USE_VST2
  295. }
  296. using namespace rack;
  297. void vst2_queue_param(int uniqueParamId, float value, bool bNormalized) {
  298. // Called from any thread via setParameter()
  299. // (note) protected by caller mutex
  300. VST2QueuedParam qp;
  301. qp.unique_id = uniqueParamId;
  302. qp.value = value;
  303. qp.b_normalized = bNormalized;
  304. global->vst2.queued_params.push_back(qp);
  305. }
  306. void vst2_handle_queued_params(void) {
  307. // Called in processReplacing()
  308. // (note) protected by caller mutex
  309. if(global->vst2.queued_params.size() > 0)
  310. {
  311. global_ui->app.mtx_param.lock();
  312. for(VST2QueuedParam qp : global->vst2.queued_params)
  313. {
  314. Module *module;
  315. int paramId;
  316. if(loc_vst2_find_module_and_paramid_by_unique_paramid(qp.unique_id, &module, &paramId))
  317. {
  318. ModuleWidget *moduleWidget = global_ui->app.gRackWidget->findModuleWidgetByModule(module);
  319. if(NULL != moduleWidget)
  320. {
  321. // Find
  322. ParamWidget *paramWidget = moduleWidget->findParamWidgetByParamId(paramId);
  323. if(NULL != paramWidget)
  324. {
  325. if(isfinite(paramWidget->minValue) && isfinite(paramWidget->maxValue))
  326. {
  327. if(qp.b_normalized)
  328. {
  329. // De-Normalize parameter
  330. global_ui->param_info.b_lock = true;
  331. float paramRange = (paramWidget->maxValue - paramWidget->minValue);
  332. if(paramRange > 0.0f)
  333. {
  334. // float value = qp.norm_value - 0.5f;
  335. // value *= 2.0f;
  336. float value = (qp.value * paramRange) + paramWidget->minValue;
  337. engineSetParam(module, paramId, value, false/*bVSTAutomate*/);
  338. // Update UI widget
  339. paramWidget->setValue(value);
  340. }
  341. global_ui->param_info.b_lock = false;
  342. }
  343. else
  344. {
  345. engineSetParam(module, paramId, qp.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