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.

460 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. #ifdef USE_VST2
  19. extern void vst2_handle_ui_param (int uniqueParamId, float normValue);
  20. #endif // USE_VST2
  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. // Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode
  102. // https://software.intel.com/en-us/node/682949
  103. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
  104. _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
  105. // Every time the engine waits and locks a mutex, it steps this many frames
  106. const int mutexSteps = 64;
  107. // Time in seconds that the engine is rushing ahead of the estimated clock time
  108. double ahead = 0.0;
  109. auto lastTime = std::chrono::high_resolution_clock::now();
  110. while (global->engine.running) {
  111. global->engine.vipMutex.wait();
  112. if (!global->gPaused) {
  113. std::lock_guard<std::mutex> lock(global->engine.mutex);
  114. for (int i = 0; i < mutexSteps; i++) {
  115. engineStep();
  116. }
  117. }
  118. double stepTime = mutexSteps * global->engine.sampleTime;
  119. ahead += stepTime;
  120. auto currTime = std::chrono::high_resolution_clock::now();
  121. const double aheadFactor = 2.0;
  122. ahead -= aheadFactor * std::chrono::duration<double>(currTime - lastTime).count();
  123. lastTime = currTime;
  124. ahead = fmaxf(ahead, 0.0);
  125. // Avoid pegging the CPU at 100% when there are no "blocking" modules like AudioInterface, but still step audio at a reasonable rate
  126. // The number of steps to wait before possibly sleeping
  127. const double aheadMax = 1.0; // seconds
  128. if (ahead > aheadMax) {
  129. std::this_thread::sleep_for(std::chrono::duration<double>(stepTime));
  130. }
  131. }
  132. }
  133. void engineStart() {
  134. global->engine.running = true;
  135. global->engine.thread = std::thread(engineRun);
  136. }
  137. void engineStop() {
  138. global->engine.running = false;
  139. global->engine.thread.join();
  140. }
  141. void engineAddModule(Module *module) {
  142. assert(module);
  143. VIPLock vipLock(global->engine.vipMutex);
  144. std::lock_guard<std::mutex> lock(global->engine.mutex);
  145. // Check that the module is not already added
  146. auto it = std::find(global->gModules.begin(), global->gModules.end(), module);
  147. assert(it == global->gModules.end());
  148. global->gModules.push_back(module);
  149. #ifdef USE_VST2
  150. module->vst2_unique_param_base_id = global->vst2.next_unique_param_base_id;
  151. global->vst2.next_unique_param_base_id += module->params.size() + 1;
  152. #endif // USE_VST2
  153. }
  154. void engineRemoveModule(Module *module) {
  155. assert(module);
  156. VIPLock vipLock(global->engine.vipMutex);
  157. std::lock_guard<std::mutex> lock(global->engine.mutex);
  158. // If a param is being smoothed on this module, stop smoothing it immediately
  159. if (module == global->engine.smoothModule) {
  160. global->engine.smoothModule = NULL;
  161. }
  162. // Check that all wires are disconnected
  163. for (Wire *wire : global->gWires) {
  164. assert(wire->outputModule != module);
  165. assert(wire->inputModule != module);
  166. }
  167. // Check that the module actually exists
  168. auto it = std::find(global->gModules.begin(), global->gModules.end(), module);
  169. assert(it != global->gModules.end());
  170. // Remove it
  171. global->gModules.erase(it);
  172. }
  173. static void updateActive() {
  174. // Set everything to inactive
  175. for (Module *module : global->gModules) {
  176. for (Input &input : module->inputs) {
  177. input.active = false;
  178. }
  179. for (Output &output : module->outputs) {
  180. output.active = false;
  181. }
  182. }
  183. // Set inputs/outputs to active
  184. for (Wire *wire : global->gWires) {
  185. wire->outputModule->outputs[wire->outputId].active = true;
  186. wire->inputModule->inputs[wire->inputId].active = true;
  187. }
  188. }
  189. void engineAddWire(Wire *wire) {
  190. assert(wire);
  191. VIPLock vipLock(global->engine.vipMutex);
  192. std::lock_guard<std::mutex> lock(global->engine.mutex);
  193. // Check wire properties
  194. assert(wire->outputModule);
  195. assert(wire->inputModule);
  196. // Check that the wire is not already added, and that the input is not already used by another cable
  197. for (Wire *wire2 : global->gWires) {
  198. assert(wire2 != wire);
  199. assert(!(wire2->inputModule == wire->inputModule && wire2->inputId == wire->inputId));
  200. }
  201. // Add the wire
  202. global->gWires.push_back(wire);
  203. updateActive();
  204. }
  205. void engineRemoveWire(Wire *wire) {
  206. assert(wire);
  207. VIPLock vipLock(global->engine.vipMutex);
  208. std::lock_guard<std::mutex> lock(global->engine.mutex);
  209. // Check that the wire is already added
  210. auto it = std::find(global->gWires.begin(), global->gWires.end(), wire);
  211. assert(it != global->gWires.end());
  212. // Set input to 0V
  213. wire->inputModule->inputs[wire->inputId].value = 0.0;
  214. // Remove the wire
  215. global->gWires.erase(it);
  216. updateActive();
  217. }
  218. #ifdef USE_VST2
  219. static int loc_vst2_find_unique_param_by_module_and_paramid(Module *module, int paramId) {
  220. return module->vst2_unique_param_base_id + paramId;
  221. }
  222. static bool loc_vst2_find_module_and_paramid_by_unique_paramid(int uniqueParamId, Module**retModule, int *retParamId) {
  223. if(uniqueParamId >= 0)
  224. {
  225. if(uniqueParamId < VST2_MAX_UNIQUE_PARAM_IDS)
  226. {
  227. // (todo) speed this up with a hashtable
  228. for(Module *module : global->gModules) {
  229. if( (uniqueParamId >= module->vst2_unique_param_base_id) &&
  230. (uniqueParamId < (module->vst2_unique_param_base_id + module->params.size()))
  231. )
  232. {
  233. *retParamId = (uniqueParamId - module->vst2_unique_param_base_id);
  234. *retModule = module;
  235. return true;
  236. }
  237. }
  238. }
  239. }
  240. return false;
  241. }
  242. #endif // USE_VST2
  243. #ifdef USE_VST2
  244. void engineSetParam(Module *module, int paramId, float value, bool bVSTAutomate) {
  245. #else
  246. void engineSetParam(Module *module, int paramId, float value) {
  247. #endif
  248. if(module->params[paramId].value == value)
  249. return;
  250. module->params[paramId].value = value;
  251. #ifdef USE_VST2
  252. if(bVSTAutomate && !global->vst2.b_patch_loading)
  253. {
  254. // (note) [bsp] this is usually called from the UI thread (see ParamWidget.cpp)
  255. // (note) [bsp] VST requires all parameters to be in the normalized 0..1 range
  256. // (note) [bsp] VCV Rack parameters however are arbitrary floats
  257. // printf("xxx vcvrack: paramId=%d value=%f (=> %f)\n", paramId, value, normValue);
  258. int uniqueParamId = loc_vst2_find_unique_param_by_module_and_paramid(module, paramId);
  259. if(-1 != uniqueParamId)
  260. {
  261. ModuleWidget *moduleWidget = global_ui->app.gRackWidget->findModuleWidgetByModule(module);
  262. if(NULL != moduleWidget)
  263. {
  264. // Find
  265. ParamWidget *paramWidget = moduleWidget->findParamWidgetByParamId(paramId);
  266. if(NULL != paramWidget)
  267. {
  268. // Normalize parameter
  269. float paramRange = (paramWidget->maxValue - paramWidget->minValue);
  270. if(paramRange > 0.0f)
  271. {
  272. float normValue = (value - paramWidget->minValue) / paramRange;
  273. // printf("xxx paramId=%d normValue=%f\n", paramId, normValue);
  274. // Call host audioMasterAutomate
  275. vst2_handle_ui_param(uniqueParamId, normValue);
  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 normValue) {
  298. // Called from any thread via setParameter()
  299. // (note) protected by caller mutex
  300. VST2QueuedParam qp;
  301. qp.unique_id = uniqueParamId;
  302. qp.norm_value = normValue;
  303. global->vst2.queued_params.push_back(qp);
  304. }
  305. void vst2_handle_queued_params(void) {
  306. // Called in processReplacing()
  307. // (note) protected by caller mutex
  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. // Normalize parameter
  323. float paramRange = (paramWidget->maxValue - paramWidget->minValue);
  324. if(paramRange > 0.0f)
  325. {
  326. // float value = qp.norm_value - 0.5f;
  327. // value *= 2.0f;
  328. float value = (qp.norm_value * paramRange) + paramWidget->minValue;
  329. engineSetParam(module, paramId, value, false/*bVSTAutomate*/);
  330. // Update UI widget
  331. paramWidget->setValue(value);
  332. }
  333. }
  334. }
  335. }
  336. }
  337. global_ui->app.mtx_param.unlock();
  338. global->vst2.queued_params.clear();
  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