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.

459 lines
14KB

  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. // Normalize parameter
  266. float paramRange = (paramWidget->maxValue - paramWidget->minValue);
  267. if(paramRange > 0.0f)
  268. {
  269. float normValue = (value - paramWidget->minValue) / paramRange;
  270. // printf("xxx paramId=%d normValue=%f\n", paramId, normValue);
  271. // Call host audioMasterAutomate
  272. vst2_handle_ui_param(uniqueParamId, normValue);
  273. }
  274. }
  275. }
  276. // else
  277. // {
  278. // // Should not be reachable
  279. // // (note) [bsp] this scale+bias hack should work for most parameters, though
  280. // // (note) [bsp] => automation curves will look a bit strange, though
  281. // // (note) [bsp] => this may potentially crash modules which cannot deal with params outside the expected range
  282. // float normValue = value / 2.0f;
  283. // normValue += 0.5f;
  284. // // Call host audioMasterAutomate
  285. // vst2_handle_ui_param(uniqueParamId, normValue);
  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 normValue) {
  295. // Called from any thread via setParameter()
  296. // (note) protected by caller mutex
  297. VST2QueuedParam qp;
  298. qp.unique_id = uniqueParamId;
  299. qp.norm_value = normValue;
  300. global->vst2.queued_params.push_back(qp);
  301. }
  302. void vst2_handle_queued_params(void) {
  303. // Called in processReplacing()
  304. // (note) protected by caller mutex
  305. if(global->vst2.queued_params.size() > 0)
  306. {
  307. global_ui->app.mtx_param.lock();
  308. for(VST2QueuedParam qp : global->vst2.queued_params)
  309. {
  310. Module *module;
  311. int paramId;
  312. if(loc_vst2_find_module_and_paramid_by_unique_paramid(qp.unique_id, &module, &paramId))
  313. {
  314. ModuleWidget *moduleWidget = global_ui->app.gRackWidget->findModuleWidgetByModule(module);
  315. if(NULL != moduleWidget)
  316. {
  317. // Find
  318. ParamWidget *paramWidget = moduleWidget->findParamWidgetByParamId(paramId);
  319. if(NULL != paramWidget)
  320. {
  321. // Normalize parameter
  322. float paramRange = (paramWidget->maxValue - paramWidget->minValue);
  323. if(paramRange > 0.0f)
  324. {
  325. // float value = qp.norm_value - 0.5f;
  326. // value *= 2.0f;
  327. float value = (qp.norm_value * paramRange) + paramWidget->minValue;
  328. engineSetParam(module, paramId, value, false/*bVSTAutomate*/);
  329. // Update UI widget
  330. paramWidget->setValue(value);
  331. }
  332. }
  333. }
  334. }
  335. }
  336. global->vst2.queued_params.clear();
  337. global_ui->app.mtx_param.unlock();
  338. }
  339. }
  340. float vst2_get_param(int uniqueParamId) {
  341. Module *module;
  342. int paramId;
  343. if(loc_vst2_find_module_and_paramid_by_unique_paramid(uniqueParamId, &module, &paramId))
  344. {
  345. if(sUI(paramId) < sUI(module->params.size())) // paranoia
  346. {
  347. return module->params[paramId].value;
  348. }
  349. }
  350. return 0.0f;
  351. }
  352. void vst2_get_param_name (int uniqueParamId, char *s, int sMaxLen) {
  353. Module *module;
  354. int paramId;
  355. if(loc_vst2_find_module_and_paramid_by_unique_paramid(uniqueParamId, &module, &paramId))
  356. {
  357. if(sUI(paramId) < sUI(module->params.size())) // paranoia
  358. {
  359. // (note) VCV params do not have names
  360. ::snprintf(s, sMaxLen, "%4d: <param>", uniqueParamId);
  361. return;
  362. }
  363. }
  364. ::snprintf(s, sMaxLen, "%4d: -", uniqueParamId);
  365. }
  366. namespace rack {
  367. #endif // USE_VST2
  368. void engineSetParamSmooth(Module *module, int paramId, float value) {
  369. VIPLock vipLock(global->engine.vipMutex);
  370. std::lock_guard<std::mutex> lock(global->engine.mutex);
  371. // Since only one param can be smoothed at a time, if another param is currently being smoothed, skip to its final state
  372. if (global->engine.smoothModule && !(global->engine.smoothModule == module && global->engine.smoothParamId == paramId)) {
  373. global->engine.smoothModule->params[global->engine.smoothParamId].value = global->engine.smoothValue;
  374. }
  375. global->engine.smoothModule = module;
  376. global->engine.smoothParamId = paramId;
  377. global->engine.smoothValue = value;
  378. }
  379. void engineSetSampleRate(float newSampleRate) {
  380. VIPLock vipLock(global->engine.vipMutex);
  381. std::lock_guard<std::mutex> lock(global->engine.mutex);
  382. global->engine.sampleRate = newSampleRate;
  383. global->engine.sampleTime = 1.0 / global->engine.sampleRate;
  384. // onSampleRateChange
  385. for (Module *module : global->gModules) {
  386. module->onSampleRateChange();
  387. }
  388. }
  389. float engineGetSampleRate() {
  390. return global->engine.sampleRate;
  391. }
  392. float engineGetSampleTime() {
  393. return global->engine.sampleTime;
  394. }
  395. } // namespace rack
  396. #ifdef USE_VST2
  397. using namespace rack;
  398. void vst2_set_samplerate(sF32 _rate) {
  399. rack::engineSetSampleRate(_rate);
  400. }
  401. void vst2_engine_process(float *const*_in, float **_out, unsigned int _numFrames) {
  402. global->vst2.inputs = _in;
  403. global->vst2.outputs = _out;
  404. for(global->vst2.frame_idx = 0u; global->vst2.frame_idx < _numFrames; global->vst2.frame_idx++)
  405. {
  406. engineStep();
  407. }
  408. }
  409. #endif // USE_VST2