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.

2188 lines
67KB

  1. #ifdef USE_VST2
  2. /// vst2_main.cpp
  3. ///
  4. /// (c) 2018 bsp. very loosely based on pongasoft's "hello, world" example plugin.
  5. ///
  6. /// Licensed under the Apache License, Version 2.0 (the "License");
  7. /// you may not use this file except in compliance with the License.
  8. /// You may obtain a copy of the License at
  9. ///
  10. /// http://www.apache.org/licenses/LICENSE-2.0
  11. ///
  12. /// Unless required by applicable law or agreed to in writing, software
  13. /// distributed under the License is distributed on an "AS IS" BASIS,
  14. /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. /// See the License for the specific language governing permissions and
  16. /// limitations under the License.
  17. ///
  18. /// created: 25Jun2018
  19. /// changed: 26Jun2018, 27Jun2018, 29Jun2018, 01Jul2018, 02Jul2018, 06Jul2018, 13Jul2018
  20. /// 26Jul2018, 04Aug2018, 05Aug2018, 06Aug2018, 07Aug2018, 09Aug2018, 11Aug2018
  21. /// 18Aug2018, 19Aug2018, 05Sep2018, 06Sep2018, 10Oct2018
  22. ///
  23. ///
  24. // #define DEBUG_PRINT_EVENTS defined
  25. // #define DEBUG_PRINT_PARAMS defined
  26. #define NUM_INPUTS ( 8) // must match AudioInterface.cpp:AUDIO_INPUTS
  27. #define NUM_OUTPUTS ( 8) // must match AudioInterface.cpp:AUDIO_OUTPUTS
  28. // (note) causes reason to shut down when console is freed (when plugin is deleted)
  29. // #define USE_CONSOLE defined
  30. #undef RACK_HOST
  31. #define Dprintf if(0);else printf
  32. // #define Dprintf if(1);else printf
  33. // #define Dprintf_idle if(0);else printf
  34. #define Dprintf_idle if(1);else printf
  35. #include <aeffect.h>
  36. #include <aeffectx.h>
  37. #include <stdio.h>
  38. #ifdef HAVE_UNIX
  39. #include <unistd.h>
  40. #endif
  41. #include "../dep/yac/yac.h"
  42. #include "../dep/yac/yac_host.cpp"
  43. YAC_Host *yac_host; // not actually used, just to satisfy the linker
  44. #include "global_pre.hpp"
  45. #include "global.hpp"
  46. #include "global_ui.hpp"
  47. #define EDITWIN_X 0
  48. #define EDITWIN_Y 0
  49. #define EDITWIN_W 1200
  50. #define EDITWIN_H 800
  51. #define Dfltequal(a, b) ( (((a)-(b)) < 0.0f) ? (((a)-(b)) > -0.0001f) : (((a)-(b)) < 0.0001f) )
  52. typedef union cmemptr_u {
  53. const sUI *u32;
  54. const sF32 *f32;
  55. const void *any;
  56. } cmemptr_t;
  57. typedef union mem_u {
  58. sUI u32;
  59. sF32 f32;
  60. } mem_t;
  61. extern int vst2_init (int argc, char* argv[], bool _bFX);
  62. extern void vst2_exit (void);
  63. namespace rack {
  64. extern void vst2_editor_redraw (void);
  65. }
  66. extern void vst2_set_samplerate (sF32 _rate);
  67. extern void vst2_engine_process (float *const*_in, float **_out, unsigned int _numFrames);
  68. extern void vst2_process_midi_input_event (sU8 _a, sU8 _b, sU8 _c);
  69. extern void vst2_queue_param (int uniqueParamId, float value, bool bNormalized);
  70. extern void vst2_handle_queued_params (void);
  71. extern float vst2_get_param (int uniqueParamId);
  72. extern void vst2_get_param_name (int uniqueParamId, char *s, int sMaxLen);
  73. extern void vst2_set_shared_plugin_tls_globals (void); // see plugin.cpp
  74. extern "C" { extern int vst2_handle_effeditkeydown (unsigned int _vkey); }
  75. namespace rack {
  76. extern bool b_touchkeyboard_enable;
  77. extern void settingsLoad(std::string filename, bool bWindowSizeOnly);
  78. }
  79. #include "../include/window.hpp"
  80. #include "../dep/include/osdialog.h"
  81. #include "../include/app.hpp"
  82. #include <speex/speex_resampler.h>
  83. // using namespace rack;
  84. // extern void rack::windowRun(void);
  85. #if defined(_WIN32) || defined(_WIN64)
  86. #define HAVE_WINDOWS defined
  87. #define WIN32_LEAN_AND_MEAN defined
  88. #include <windows.h>
  89. #include <xmmintrin.h>
  90. EXTERN_C IMAGE_DOS_HEADER __ImageBase;
  91. // Windows:
  92. #define VST_EXPORT extern "C" __declspec(dllexport)
  93. struct PluginMutex {
  94. CRITICAL_SECTION handle;
  95. PluginMutex(void) {
  96. ::InitializeCriticalSection( &handle );
  97. }
  98. ~PluginMutex() {
  99. ::DeleteCriticalSection( &handle );
  100. }
  101. void lock(void) {
  102. ::EnterCriticalSection(&handle);
  103. }
  104. void unlock(void) {
  105. ::LeaveCriticalSection(&handle);
  106. }
  107. };
  108. #else
  109. // MacOSX, Linux:
  110. #define HAVE_UNIX defined
  111. #define VST_EXPORT extern
  112. #include <pthread.h>
  113. #include <errno.h>
  114. #include <unistd.h>
  115. #include <fcntl.h>
  116. #include <sys/mman.h>
  117. //static pthread_mutex_t loc_pthread_mutex_t_init = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
  118. static pthread_mutex_t loc_pthread_mutex_t_init = PTHREAD_MUTEX_INITIALIZER;
  119. struct PluginMutex {
  120. pthread_mutex_t handle;
  121. PluginMutex(void) {
  122. ::memcpy((void*)&handle, (const void*)&loc_pthread_mutex_t_init, sizeof(pthread_mutex_t));
  123. }
  124. ~PluginMutex() {
  125. }
  126. void lock(void) {
  127. ::pthread_mutex_lock(&handle);
  128. }
  129. void unlock(void) {
  130. ::pthread_mutex_unlock(&handle);
  131. }
  132. };
  133. #endif // _WIN32||_WIN64
  134. // // extern "C" {
  135. // // extern void glfwSetInstance(void *_glfw);
  136. // // }
  137. class PluginString : public YAC_String {
  138. public:
  139. static const sUI QUOT2 =(sUI)(1<<26); // \'\'
  140. static const sUI STRFLQMASK = (QUOT | UTAG1 | QUOT2);
  141. void safeFreeChars (void);
  142. sSI _realloc (sSI _numChars);
  143. sSI lastIndexOf (sChar _c, sUI _start) const;
  144. void getDirName (PluginString *_r) const;
  145. void replace (sChar _c, sChar _o);
  146. };
  147. void PluginString::safeFreeChars(void) {
  148. if(bflags & PluginString::DEL)
  149. {
  150. // if(!(bflags & PluginString::LA))
  151. {
  152. Dyacfreechars(chars);
  153. }
  154. }
  155. }
  156. sSI PluginString::_realloc(sSI _numBytes) {
  157. // Force alloc if a very big string is about to shrink a lot or there is simply not enough space available
  158. if( ((buflen >= 1024) && ( (((sUI)_numBytes)<<3) < buflen )) ||
  159. (NULL == chars) ||
  160. (buflen < ((sUI)_numBytes))
  161. ) // xxx (!chars) hack added 180702
  162. {
  163. if(NULL != chars)
  164. {
  165. sUI l = length;
  166. if(((sUI)_numBytes) < l)
  167. {
  168. l = _numBytes;
  169. }
  170. sU8 *nc = Dyacallocchars(_numBytes + 1);
  171. sUI i = 0;
  172. for(; i<l; i++)
  173. {
  174. nc[i] = chars[i];
  175. }
  176. nc[i] = 0;
  177. safeFreeChars();
  178. buflen = (_numBytes + 1);
  179. bflags = PluginString::DEL | (bflags & PluginString::STRFLQMASK); // keep old stringflags
  180. length = i + 1;
  181. chars = nc;
  182. key = YAC_LOSTKEY;
  183. return YAC_TRUE;
  184. }
  185. else
  186. {
  187. return PluginString::alloc(_numBytes + 1);
  188. }
  189. }
  190. else
  191. {
  192. key = YAC_LOSTKEY; // new 010208
  193. return YAC_TRUE;
  194. }
  195. }
  196. sSI PluginString::lastIndexOf(sChar _c, sUI _start) const {
  197. sSI li = -1;
  198. if(NULL != chars)
  199. {
  200. sUI i = _start;
  201. for(; i<length; i++)
  202. {
  203. if(chars[i] == ((sChar)_c))
  204. {
  205. li = i;
  206. }
  207. }
  208. }
  209. return li;
  210. }
  211. void PluginString::replace(sChar _c, sChar _o) {
  212. if(NULL != chars)
  213. {
  214. for(sUI i = 0; i < length; i++)
  215. {
  216. if(chars[i] == _c)
  217. chars[i] = _o;
  218. }
  219. }
  220. }
  221. void PluginString::getDirName(PluginString *_r) const {
  222. sSI idxSlash = lastIndexOf('/', 0);
  223. sSI idxBackSlash = lastIndexOf('\\', 0);
  224. sSI idxDrive = lastIndexOf(':', 0);
  225. sSI idx = -1;
  226. if(idxSlash > idxBackSlash)
  227. {
  228. idx = idxSlash;
  229. }
  230. else
  231. {
  232. idx = idxBackSlash;
  233. }
  234. if(idxDrive > idx)
  235. {
  236. idx = idxDrive;
  237. }
  238. if(-1 != idx)
  239. {
  240. _r->_realloc(idx + 2);
  241. _r->length = idx + 2;
  242. sSI i;
  243. for(i=0; i<=idx; i++)
  244. {
  245. _r->chars[i] = chars[i];
  246. }
  247. _r->chars[i++] = 0;
  248. _r->key = YAC_LOSTKEY;
  249. }
  250. else
  251. {
  252. _r->empty();
  253. }
  254. }
  255. #define MAX_FLOATARRAYALLOCSIZE (1024*1024*64)
  256. class PluginFloatArray : public YAC_FloatArray {
  257. public:
  258. sSI alloc (sSI _maxelements);
  259. };
  260. sSI PluginFloatArray::alloc(sSI _max_elements) {
  261. if(((sUI)_max_elements)>MAX_FLOATARRAYALLOCSIZE)
  262. {
  263. printf("[---] FloatArray::insane array size (maxelements=%08x)\n", _max_elements);
  264. return 0;
  265. }
  266. if(own_data)
  267. {
  268. if(elements)
  269. {
  270. delete [] elements;
  271. elements = NULL;
  272. }
  273. }
  274. if(_max_elements)
  275. {
  276. elements = new(std::nothrow) sF32[_max_elements];
  277. if(elements)
  278. {
  279. max_elements = _max_elements;
  280. num_elements = 0;
  281. own_data = 1;
  282. return 1;
  283. }
  284. }
  285. num_elements = 0;
  286. max_elements = 0;
  287. return 0;
  288. }
  289. /*
  290. * I find the naming a bit confusing so I decided to use more meaningful names instead.
  291. */
  292. /**
  293. * The VSTHostCallback is a function pointer so that the plugin can communicate with the host (not used in this small example)
  294. */
  295. typedef audioMasterCallback VSTHostCallback;
  296. /**
  297. * The VSTPlugin structure (AEffect) contains information about the plugin (like version, number of inputs, ...) and
  298. * callbacks so that the host can call the plugin to do its work. The primary callback will be `processReplacing` for
  299. * single precision (float) sample processing (or `processDoubleReplacing` for double precision (double)).
  300. */
  301. typedef AEffect VSTPlugin;
  302. // Since the host is expecting a very specific API we need to make sure it has C linkage (not C++)
  303. extern "C" {
  304. /*
  305. * This is the main entry point to the VST plugin.
  306. *
  307. * The host (DAW like Maschine, Ableton Live, Reason, ...) will look for this function with this exact API.
  308. *
  309. * It is the equivalent to `int main(int argc, char *argv[])` for a C executable.
  310. *
  311. * @param vstHostCallback is a callback so that the plugin can communicate with the host (not used in this small example)
  312. * @return a pointer to the AEffect structure
  313. */
  314. VST_EXPORT VSTPlugin *VSTPluginMain (VSTHostCallback vstHostCallback);
  315. // note this looks like this without the type aliases (and is obviously 100% equivalent)
  316. // extern AEffect *VSTPluginMain(audioMasterCallback audioMaster);
  317. }
  318. /*
  319. * Constant for the version of the plugin. For example 1100 for version 1.1.0.0
  320. */
  321. const VstInt32 PLUGIN_VERSION = 1000;
  322. /**
  323. * Encapsulates the plugin as a C++ class. It will keep both the host callback and the structure required by the
  324. * host (VSTPlugin). This class will be stored in the `VSTPlugin.object` field (circular reference) so that it can
  325. * be accessed when the host calls the plugin back (for example in `processDoubleReplacing`).
  326. */
  327. class VSTPluginWrapper {
  328. public:
  329. static const uint32_t MIN_SAMPLE_RATE = 8192u;
  330. static const uint32_t MAX_SAMPLE_RATE = 384000u;
  331. static const uint32_t MIN_BLOCK_SIZE = 64u;
  332. static const uint32_t MAX_BLOCK_SIZE = 16384u;
  333. static const uint32_t MAX_OVERSAMPLE_FACTOR = 16u;
  334. static const uint32_t IDLE_DETECT_NONE = 0u; // always active
  335. static const uint32_t IDLE_DETECT_MIDI = 1u; // become idle when output is silence, reactivate when there's MIDI input activity
  336. static const uint32_t IDLE_DETECT_AUDIO = 2u; // become idle when output is silence, reactivate when there's audio input activity
  337. public:
  338. rack::Global rack_global;
  339. rack::GlobalUI rack_global_ui;
  340. protected:
  341. PluginString dllname;
  342. PluginString cwd;
  343. public:
  344. struct {
  345. float factor; // 1=no SR conversion, 2=oversample x2, 4=oversample x4, 0.5=undersample /2, ..
  346. int quality; // SPEEX_RESAMPLER_QUALITY_xxx
  347. float realtime_factor; // used during realtime rendering
  348. int realtime_quality;
  349. float offline_factor; // used during offline rendering (bounce)
  350. int offline_quality; //
  351. sUI num_in; // hack that limits oversampling to "n" input channels. default = NUM_INPUTS
  352. sUI num_out; // hack that limits oversampling to "n" input channels. default = NUM_OUTPUTS
  353. SpeexResamplerState *srs_in;
  354. SpeexResamplerState *srs_out;
  355. sF32 in_buffers[NUM_INPUTS * MAX_BLOCK_SIZE * MAX_OVERSAMPLE_FACTOR];
  356. sF32 out_buffers[NUM_OUTPUTS * MAX_BLOCK_SIZE];
  357. } oversample;
  358. public:
  359. float sample_rate; // e.g. 44100.0
  360. protected:
  361. uint32_t block_size; // e.g. 64
  362. PluginMutex mtx_audio;
  363. public:
  364. PluginMutex mtx_mididev;
  365. public:
  366. bool b_open;
  367. bool b_processing; // true=generate output, false=suspended
  368. bool b_offline; // true=offline rendering (HQ)
  369. bool b_check_offline; // true=ask host if it's in offline rendering mode
  370. sUI idle_detect_mode;
  371. sUI idle_detect_mode_fx;
  372. sUI idle_detect_mode_instr;
  373. sF32 idle_input_level_threshold;
  374. sF32 idle_output_level_threshold;
  375. sF32 idle_output_sec_threshold;
  376. sUI idle_output_framecount;
  377. bool b_idle;
  378. ERect editor_rect;
  379. sBool b_editor_open;
  380. char *last_program_chunk_str;
  381. static sSI instance_count;
  382. sSI instance_id;
  383. sF32 tmp_input_buffers[NUM_INPUTS * MAX_BLOCK_SIZE];
  384. sUI redraw_ival_ms; // 0=use DAW timer (effEditIdle)
  385. public:
  386. VSTPluginWrapper(VSTHostCallback vstHostCallback,
  387. VstInt32 vendorUniqueID,
  388. VstInt32 vendorVersion,
  389. VstInt32 numParams,
  390. VstInt32 numPrograms,
  391. VstInt32 numInputs,
  392. VstInt32 numOutputs
  393. );
  394. ~VSTPluginWrapper();
  395. VSTPlugin *getVSTPlugin(void) {
  396. return &_vstPlugin;
  397. }
  398. void setGlobals(void) {
  399. rack::global = &rack_global;
  400. rack::global_ui = &rack_global_ui;
  401. }
  402. sSI openEffect(void) {
  403. Dprintf("xxx vstrack_plugin::openEffect\n");
  404. // (todo) use mutex
  405. instance_id = instance_count;
  406. Dprintf("xxx vstrack_plugin::openEffect: instance_id=%d\n", instance_id);
  407. rack_global.vst2.wrapper = this;
  408. #ifdef USE_CONSOLE
  409. AllocConsole();
  410. freopen("CON", "w", stdout);
  411. freopen("CON", "w", stderr);
  412. freopen("CON", "r", stdin); // Note: "r", not "w".
  413. #endif // USE_CONSOLE
  414. setGlobals();
  415. rack_global.init();
  416. rack_global_ui.init();
  417. rack::global->vst2.last_seen_instance_count = instance_count;
  418. char oldCWD[1024];
  419. char dllnameraw[1024];
  420. #ifdef HAVE_WINDOWS
  421. ::GetCurrentDirectory(1024, (LPSTR) oldCWD);
  422. // ::GetModuleFileNameA(NULL, dllnameraw, 1024); // returns executable name (not the dll pathname)
  423. GetModuleFileNameA((HINSTANCE)&__ImageBase, dllnameraw, 1024);
  424. #elif defined(HAVE_UNIX)
  425. getcwd(oldCWD, 1024);
  426. readlink("/proc/self/exe", dllnameraw, 1024);
  427. #endif
  428. dllname.visit(dllnameraw);
  429. dllname.getDirName(&cwd);
  430. rack::global->vst2.program_dir = (const char*)cwd.chars;
  431. Dprintf("xxx vstrack_plugin::openEffect: cd to \"%s\"\n", (const char*)cwd.chars);
  432. #ifdef HAVE_WINDOWS
  433. ::SetCurrentDirectory((const char*)cwd.chars);
  434. #elif defined(HAVE_UNIX)
  435. chdir((const char*)cwd.chars);
  436. #endif
  437. Dprintf("xxx vstrack_plugin::openEffect: cwd change done\n");
  438. // cwd.replace('\\', '/');
  439. int argc = 1;
  440. char *argv[1];
  441. //argv[0] = (char*)cwd.chars;
  442. argv[0] = (char*)dllnameraw;
  443. Dprintf("xxx vstrack_plugin::openEffect: dllname=\"%s\"\n", argv[0]);
  444. (void)vst2_init(argc, argv,
  445. #ifdef VST2_EFFECT
  446. true/*bFX*/
  447. #else
  448. false/*bFX*/
  449. #endif // VST2_EFFECT
  450. );
  451. Dprintf("xxx vstrack_plugin::openEffect: vst2_init() done\n");
  452. vst2_set_shared_plugin_tls_globals();
  453. Dprintf("xxx vstrack_plugin::openEffect: restore cwd=\"%s\"\n", oldCWD);
  454. #ifdef HAVE_WINDOWS
  455. ::SetCurrentDirectory(oldCWD);
  456. #elif defined(HAVE_UNIX)
  457. chdir(oldCWD);
  458. #endif
  459. setSampleRate(sample_rate);
  460. b_open = true;
  461. b_editor_open = false;
  462. Dprintf("xxx vstrack_plugin::openEffect: LEAVE\n");
  463. return 1;
  464. }
  465. void setWindowSize(int _width, int _height) {
  466. if(_width < 640)
  467. _width = 640;
  468. if(_height < 480)
  469. _height = 480;
  470. editor_rect.right = EDITWIN_X + _width;
  471. editor_rect.bottom = EDITWIN_Y + _height;
  472. (void)lglw_window_resize(rack_global_ui.window.lglw, _width, _height);
  473. }
  474. void setRefreshRate(float _hz) {
  475. if(_hz < 15.0f)
  476. redraw_ival_ms = 0u;
  477. else
  478. redraw_ival_ms = sUI(1000.0f / _hz);
  479. if(b_editor_open)
  480. {
  481. lglw_timer_stop(rack_global_ui.window.lglw);
  482. if(0u != redraw_ival_ms)
  483. {
  484. lglw_timer_start(rack_global_ui.window.lglw, redraw_ival_ms);
  485. }
  486. }
  487. }
  488. float getRefreshRate(void) {
  489. if(redraw_ival_ms > 0u)
  490. return (1000.0f / redraw_ival_ms);
  491. else
  492. return 0.0f;
  493. }
  494. void destroyResamplerStates(void) {
  495. if(NULL != oversample.srs_in)
  496. {
  497. speex_resampler_destroy(oversample.srs_in);
  498. oversample.srs_in = NULL;
  499. }
  500. if(NULL != oversample.srs_out)
  501. {
  502. speex_resampler_destroy(oversample.srs_out);
  503. oversample.srs_out = NULL;
  504. }
  505. }
  506. void openEditor(void *_hwnd) {
  507. Dprintf("xxx vstrack_plugin: openEditor() parentHWND=%p\n", _hwnd);
  508. setGlobals();
  509. (void)lglw_window_open(rack_global_ui.window.lglw,
  510. _hwnd,
  511. 0/*x*/, 0/*y*/,
  512. (editor_rect.right - editor_rect.left),
  513. (editor_rect.bottom - editor_rect.top)
  514. );
  515. if(0u != redraw_ival_ms)
  516. {
  517. lglw_timer_start(rack_global_ui.window.lglw, redraw_ival_ms);
  518. }
  519. b_editor_open = true;
  520. rack::global_ui->param_info.placeholder_framecount = (30*30)-10;
  521. rack::global_ui->param_info.last_param_widget = NULL;
  522. }
  523. void closeEditor(void) {
  524. Dprintf("xxx vstrack_plugin: closeEditor() b_editor_open=%d\n", b_editor_open);
  525. if(b_editor_open)
  526. {
  527. setGlobals();
  528. lglw_timer_stop(rack_global_ui.window.lglw);
  529. lglw_window_close(rack_global_ui.window.lglw);
  530. b_editor_open = false;
  531. }
  532. }
  533. void closeEffect(void) {
  534. closeEditor();
  535. // (todo) use mutex
  536. Dprintf("xxx vstrack_plugin::closeEffect: last_program_chunk_str=%p\n", last_program_chunk_str);
  537. if(NULL != last_program_chunk_str)
  538. {
  539. ::free(last_program_chunk_str);
  540. last_program_chunk_str = NULL;
  541. }
  542. Dprintf("xxx vstrack_plugin::closeEffect: b_open=%d\n", b_open);
  543. if(b_open)
  544. {
  545. b_open = false;
  546. setGlobals();
  547. vst2_set_shared_plugin_tls_globals();
  548. rack::global->vst2.last_seen_instance_count = instance_count;
  549. Dprintf("xxx vstrack_plugin: call vst2_exit()\n");
  550. vst2_exit();
  551. Dprintf("xxx vstrack_plugin: vst2_exit() done\n");
  552. destroyResamplerStates();
  553. Dprintf("xxx vstrack_plugin: destroyResamplerStates() done\n");
  554. #ifdef USE_CONSOLE
  555. // FreeConsole();
  556. #endif // USE_CONSOLE
  557. }
  558. }
  559. void lockAudio(void) {
  560. mtx_audio.lock();
  561. }
  562. void unlockAudio(void) {
  563. mtx_audio.unlock();
  564. }
  565. VstInt32 getNumInputs(void) const {
  566. return _vstPlugin.numInputs;
  567. }
  568. VstInt32 getNumOutputs(void) const {
  569. return _vstPlugin.numOutputs;
  570. }
  571. void setOversample(float _factor, int _quality, bool _bLock = true) {
  572. oversample.factor = _factor;
  573. oversample.quality = _quality;
  574. setSampleRate(sample_rate, _bLock);
  575. }
  576. void setOversampleRealtime(float _factor, int _quality) {
  577. if(_factor < 0.0f)
  578. _factor = oversample.realtime_factor; // keep
  579. if(_quality < 0)
  580. _quality = oversample.realtime_quality; // keep
  581. if(_factor < 0.001f)
  582. _factor = 1.0f;
  583. else if(_factor > float(MAX_OVERSAMPLE_FACTOR))
  584. _factor = float(MAX_OVERSAMPLE_FACTOR);
  585. if(_quality < SPEEX_RESAMPLER_QUALITY_MIN/*0*/)
  586. _quality = SPEEX_RESAMPLER_QUALITY_MIN;
  587. else if(_quality > SPEEX_RESAMPLER_QUALITY_MAX/*10*/)
  588. _quality = SPEEX_RESAMPLER_QUALITY_MAX;
  589. oversample.realtime_factor = _factor;
  590. oversample.realtime_quality = _quality;
  591. if(!b_offline)
  592. {
  593. setOversample(oversample.realtime_factor, oversample.realtime_quality);
  594. }
  595. }
  596. void setOversampleOffline(float _factor, int _quality) {
  597. if(_factor < 0.0f)
  598. _factor = oversample.offline_factor; // keep
  599. if(_quality < 0)
  600. _quality = oversample.offline_quality; // keep
  601. if(_factor < 0.001f)
  602. _factor = 1.0f;
  603. else if(_factor > float(MAX_OVERSAMPLE_FACTOR))
  604. _factor = float(MAX_OVERSAMPLE_FACTOR);
  605. if(_quality < SPEEX_RESAMPLER_QUALITY_MIN/*0*/)
  606. _quality = SPEEX_RESAMPLER_QUALITY_MIN;
  607. else if(_quality > SPEEX_RESAMPLER_QUALITY_MAX/*10*/)
  608. _quality = SPEEX_RESAMPLER_QUALITY_MAX;
  609. oversample.offline_factor = _factor;
  610. oversample.offline_quality = _quality;
  611. if(b_offline)
  612. {
  613. setOversample(oversample.offline_factor, oversample.offline_quality);
  614. }
  615. }
  616. void setOversampleChannels(int _numIn, int _numOut) {
  617. if(_numIn < 0)
  618. _numIn = int(oversample.num_in); // keep
  619. if(_numOut < 0)
  620. _numOut = int(oversample.num_out); // keep
  621. if(_numIn < 0)
  622. _numIn = 0;
  623. else if(_numIn > NUM_INPUTS)
  624. _numIn = NUM_INPUTS;
  625. if(_numOut < 1)
  626. _numOut = 1;
  627. else if(_numOut > NUM_OUTPUTS)
  628. _numOut = NUM_OUTPUTS;
  629. lockAudio();
  630. oversample.num_in = sUI(_numIn);
  631. oversample.num_out = sUI(_numOut);
  632. unlockAudio();
  633. }
  634. bool setSampleRate(float _rate, bool _bLock = true) {
  635. bool r = false;
  636. if((_rate >= float(MIN_SAMPLE_RATE)) && (_rate <= float(MAX_SAMPLE_RATE)))
  637. {
  638. if(_bLock)
  639. {
  640. setGlobals();
  641. lockAudio();
  642. }
  643. sample_rate = _rate;
  644. vst2_set_samplerate(sample_rate * oversample.factor); // see engine.cpp
  645. destroyResamplerStates();
  646. // Lazy-alloc resampler state
  647. if(!Dfltequal(oversample.factor, 1.0f))
  648. {
  649. int err;
  650. oversample.srs_in = speex_resampler_init(NUM_INPUTS,
  651. sUI(sample_rate), // in rate
  652. sUI(sample_rate * oversample.factor), // out rate
  653. oversample.quality,
  654. &err
  655. );
  656. oversample.srs_out = speex_resampler_init(NUM_OUTPUTS,
  657. sUI(sample_rate * oversample.factor), // in rate
  658. sUI(sample_rate), // out rate
  659. oversample.quality,
  660. &err
  661. );
  662. Dprintf("xxx vstrack_plugin: initialize speex resampler (rate=%f factor=%f quality=%d)\n", sample_rate, oversample.factor, oversample.quality);
  663. }
  664. if(_bLock)
  665. {
  666. unlockAudio();
  667. }
  668. r = true;
  669. }
  670. return r;
  671. }
  672. bool setBlockSize(uint32_t _blockSize) {
  673. bool r = false;
  674. if((_blockSize >= MIN_BLOCK_SIZE) && (_blockSize <= MAX_BLOCK_SIZE))
  675. {
  676. lockAudio();
  677. block_size = _blockSize;
  678. unlockAudio();
  679. r = true;
  680. }
  681. return r;
  682. }
  683. void setEnableProcessingActive(bool _bEnable) {
  684. lockAudio();
  685. b_processing = _bEnable;
  686. unlockAudio();
  687. }
  688. void checkOffline(void) {
  689. // Called by VSTPluginProcessReplacingFloat32()
  690. if(b_check_offline)
  691. {
  692. if(NULL != _vstHostCallback)
  693. {
  694. int level = (int)_vstHostCallback(&_vstPlugin, audioMasterGetCurrentProcessLevel, 0, 0/*value*/, NULL/*ptr*/, 0.0f/*opt*/);
  695. // (note) Reason sets process level to kVstProcessLevelUser during "bounce in place"
  696. bool bOffline = (kVstProcessLevelOffline == level) || (kVstProcessLevelUser == level);
  697. #if 0
  698. {
  699. static int i = 0;
  700. if(0 == (++i & 127))
  701. {
  702. Dprintf("xxx vstrack_plugin: audioMasterGetCurrentProcessLevel: level=%d\n", level);
  703. }
  704. }
  705. #endif
  706. if(b_offline ^ bOffline)
  707. {
  708. // Offline mode changed, update resampler
  709. b_offline = bOffline;
  710. if(bOffline)
  711. {
  712. Dprintf("xxx vstrack_plugin: enter OFFLINE mode. factor=%f quality=%d\n", oversample.offline_factor, oversample.offline_quality);
  713. setOversample(oversample.offline_factor, oversample.offline_quality, false/*bLock*/);
  714. }
  715. else
  716. {
  717. Dprintf("xxx vstrack_plugin: enter REALTIME mode. factor=%f quality=%d\n", oversample.realtime_factor, oversample.realtime_quality);
  718. setOversample(oversample.realtime_factor, oversample.realtime_quality, false/*bLock*/);
  719. }
  720. Dprintf("xxx vstrack_plugin: mode changed to %d\n", int(bOffline));
  721. }
  722. }
  723. }
  724. }
  725. sUI getBankChunk(uint8_t **_addr) {
  726. return 0;
  727. }
  728. void setIdleDetectMode(uint32_t _mode) {
  729. switch(_mode)
  730. {
  731. default:
  732. case IDLE_DETECT_NONE:
  733. idle_detect_mode = IDLE_DETECT_NONE;
  734. break;
  735. case IDLE_DETECT_MIDI:
  736. idle_detect_mode = IDLE_DETECT_MIDI;
  737. break;
  738. case IDLE_DETECT_AUDIO:
  739. idle_detect_mode = IDLE_DETECT_AUDIO;
  740. break;
  741. }
  742. b_idle = false;
  743. idle_output_framecount = 0u;
  744. }
  745. void setIdleDetectModeFx(uint32_t _mode) {
  746. idle_detect_mode_fx = _mode;
  747. #ifdef VST2_EFFECT
  748. setIdleDetectMode(uint32_t(_mode));
  749. #endif // VST2_EFFECT
  750. }
  751. void setIdleDetectModeInstr(uint32_t _mode) {
  752. idle_detect_mode_instr = _mode;
  753. #ifndef VST2_EFFECT
  754. setIdleDetectMode(uint32_t(_mode));
  755. #endif // VST2_EFFECT
  756. }
  757. sUI getProgramChunk(uint8_t**_addr) {
  758. setGlobals();
  759. vst2_set_shared_plugin_tls_globals();
  760. if(NULL != last_program_chunk_str)
  761. {
  762. ::free(last_program_chunk_str);
  763. }
  764. last_program_chunk_str = rack::global_ui->app.gRackWidget->savePatchToString();
  765. if(NULL != last_program_chunk_str)
  766. {
  767. *_addr = (uint8_t*)last_program_chunk_str;
  768. return (sUI)strlen(last_program_chunk_str) + 1/*ASCIIZ*/;
  769. }
  770. return 0;
  771. }
  772. bool setBankChunk(size_t _size, uint8_t *_addr) {
  773. bool r = false;
  774. return r;
  775. }
  776. bool setProgramChunk(size_t _size, uint8_t *_addr) {
  777. setGlobals();
  778. lockAudio();
  779. vst2_set_shared_plugin_tls_globals();
  780. #if 0
  781. Dprintf("xxx vstrack_plugin:setProgramChunk: size=%u\n", _size);
  782. #endif
  783. lglw_glcontext_push(rack::global_ui->window.lglw);
  784. bool r = rack::global_ui->app.gRackWidget->loadPatchFromString((const char*)_addr);
  785. rack::global_ui->ui.gScene->step(); // w/o this the patch is bypassed
  786. lglw_glcontext_pop(rack::global_ui->window.lglw);
  787. Dprintf("xxx vstrack_plugin:setProgramChunk: r=%d\n", r);
  788. unlockAudio();
  789. return r;
  790. }
  791. #ifdef HAVE_WINDOWS
  792. void sleepMillisecs(uint32_t _num) {
  793. ::Sleep((DWORD)_num);
  794. }
  795. #elif defined(HAVE_UNIX)
  796. void sleepMillisecs(uint32_t _num) {
  797. ::usleep(1000u * _num);
  798. }
  799. #endif
  800. const volatile float *getNextInputChannelChunk(void) {
  801. volatile float *r = NULL;
  802. return r;
  803. }
  804. volatile float *lockNextOutputChannelChunk(void) {
  805. volatile float *r = NULL;
  806. return r;
  807. }
  808. sBool getParameterProperties(sUI _index, struct VstParameterProperties *_ret) {
  809. sBool r = 0;
  810. ::memset((void*)_ret, 0, sizeof(struct VstParameterProperties));
  811. if(_index < VST2_MAX_UNIQUE_PARAM_IDS)
  812. {
  813. _ret->stepFloat = 0.001f;
  814. _ret->smallStepFloat = 0.001f;
  815. _ret->largeStepFloat = 0.01f;
  816. _ret->flags = 0;
  817. _ret->displayIndex = VstInt16(_index);
  818. _ret->category = 0; // 0=no category
  819. _ret->numParametersInCategory = 0;
  820. vst2_get_param_name(_index, _ret->label, kVstMaxLabelLen);
  821. vst2_get_param_name(_index, _ret->shortLabel, kVstMaxShortLabelLen);
  822. r = 1;
  823. }
  824. return r;
  825. }
  826. void handleUIParam(int uniqueParamId, float normValue) {
  827. if(NULL != _vstHostCallback)
  828. (void)_vstHostCallback(&_vstPlugin, audioMasterAutomate, uniqueParamId, 0/*value*/, NULL/*ptr*/, normValue/*opt*/);
  829. }
  830. void getTimingInfo(int *_retPlaying, float *_retBPM, float *_retSongPosPPQ) {
  831. *_retPlaying = 0;
  832. if(NULL != _vstHostCallback)
  833. {
  834. VstIntPtr result = _vstHostCallback(&_vstPlugin, audioMasterGetTime, 0,
  835. (kVstTransportPlaying | kVstTempoValid | kVstPpqPosValid)/*value=requestmask*/,
  836. NULL/*ptr*/, 0.0f/*opt*/
  837. );
  838. if(0 != result)
  839. {
  840. const struct VstTimeInfo *timeInfo = (const struct VstTimeInfo *)result;
  841. *_retPlaying = (0 != (timeInfo->flags & kVstTransportPlaying));
  842. if(0 != (timeInfo->flags & kVstTempoValid))
  843. {
  844. *_retBPM = float(timeInfo->tempo);
  845. }
  846. if(0 != (timeInfo->flags & kVstPpqPosValid))
  847. {
  848. *_retSongPosPPQ = (float)timeInfo->ppqPos;
  849. }
  850. }
  851. }
  852. }
  853. void queueRedraw(void) {
  854. setGlobals();
  855. if(lglw_window_is_visible(rack::global_ui->window.lglw))
  856. {
  857. lglw_redraw(rack::global_ui->window.lglw);
  858. }
  859. }
  860. void redraw(void) {
  861. setGlobals();
  862. if(lglw_window_is_visible(rack::global_ui->window.lglw))
  863. {
  864. vst2_set_shared_plugin_tls_globals();
  865. // Save DAW GL context and bind our own
  866. lglw_glcontext_push(rack::global_ui->window.lglw);
  867. rack::vst2_editor_redraw();
  868. // Restore the DAW's GL context
  869. lglw_glcontext_pop(rack::global_ui->window.lglw);
  870. }
  871. }
  872. private:
  873. // the host callback (a function pointer)
  874. VSTHostCallback _vstHostCallback;
  875. // the actual structure required by the host
  876. VSTPlugin _vstPlugin;
  877. };
  878. sSI VSTPluginWrapper::instance_count = 0;
  879. /*******************************************
  880. * Callbacks: Host -> Plugin
  881. *
  882. * Defined here because they are used in the rest of the code later
  883. */
  884. /**
  885. * This is the callback that will be called to process the samples in the case of single precision. This is where the
  886. * meat of the logic happens!
  887. *
  888. * @param vstPlugin the object returned by VSTPluginMain
  889. * @param inputs an array of array of input samples. You read from it. First dimension is for inputs, second dimension is for samples: inputs[numInputs][sampleFrames]
  890. * @param outputs an array of array of output samples. You write to it. First dimension is for outputs, second dimension is for samples: outputs[numOuputs][sampleFrames]
  891. * @param sampleFrames the number of samples (second dimension in both arrays)
  892. */
  893. void VSTPluginProcessReplacingFloat32(VSTPlugin *vstPlugin,
  894. float **_inputs,
  895. float **_outputs,
  896. VstInt32 sampleFrames
  897. ) {
  898. if(sUI(sampleFrames) > VSTPluginWrapper::MAX_BLOCK_SIZE)
  899. return; // should not be reachable
  900. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  901. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  902. // Dprintf("xxx vstrack_plugin: VSTPluginProcessReplacingFloat32: ENTER\n");
  903. wrapper->lockAudio();
  904. wrapper->setGlobals();
  905. vst2_set_shared_plugin_tls_globals();
  906. if(wrapper->b_check_offline)
  907. {
  908. // Check if offline rendering state changed and update resampler when necessary
  909. wrapper->checkOffline();
  910. }
  911. // // rack::global->engine.vipMutex.lock();
  912. rack::global->engine.mutex.lock();
  913. rack::global->vst2.last_seen_num_frames = sUI(sampleFrames);
  914. vst2_handle_queued_params();
  915. //Dprintf("xxx vstrack_plugin: VSTPluginProcessReplacingFloat32: lockAudio done\n");
  916. //Dprintf("xxx vstrack_plugin: VSTPluginProcessReplacingFloat32: wrapper=%p\n", wrapper);
  917. #ifdef HAVE_WINDOWS
  918. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
  919. #endif // HAVE_WINDOWS
  920. sUI chIdx;
  921. if(wrapper->b_idle)
  922. {
  923. switch(wrapper->idle_detect_mode)
  924. {
  925. default:
  926. case VSTPluginWrapper::IDLE_DETECT_NONE:
  927. // should not be reachable
  928. wrapper->b_idle = false;
  929. wrapper->idle_output_framecount = 0u;
  930. break;
  931. case VSTPluginWrapper::IDLE_DETECT_MIDI:
  932. break;
  933. case VSTPluginWrapper::IDLE_DETECT_AUDIO:
  934. {
  935. wrapper->b_idle = true;
  936. for(chIdx = 0u; chIdx < NUM_INPUTS; chIdx++)
  937. {
  938. if(chIdx < wrapper->oversample.num_in)
  939. {
  940. cmemptr_t s;
  941. s.f32 = _inputs[chIdx];
  942. sF32 sum = 0.0f;
  943. for(sUI i = 0u; i < sUI(sampleFrames); i++)
  944. {
  945. mem_t m;
  946. m.u32 = s.u32[i] & ~0x80000000u; // abs
  947. sum += m.f32;
  948. // sum += (s.f32[i] * s.f32[i]); // RMS
  949. }
  950. sum = (sum / float(sampleFrames));
  951. // sum = sqrtf(sum / float(sampleFrames)); // RMS
  952. if(sum >= wrapper->idle_input_level_threshold)
  953. {
  954. wrapper->b_idle = false;
  955. Dprintf_idle("xxx vstrack_plugin: become active after input (sum=%f, threshold=%f)\n", sum, wrapper->idle_input_level_threshold);
  956. wrapper->idle_output_framecount = 0u;
  957. break;
  958. }
  959. }
  960. }
  961. }
  962. break;
  963. } // switch idle_detect_mode
  964. } // if idle
  965. if(!wrapper->b_idle)
  966. {
  967. if( !Dfltequal(wrapper->oversample.factor, 1.0f) &&
  968. (NULL != wrapper->oversample.srs_in) &&
  969. (NULL != wrapper->oversample.srs_out)
  970. )
  971. {
  972. sF32 *inputs[NUM_INPUTS];
  973. sF32 *outputs[NUM_INPUTS];
  974. sUI hostNumFrames = sampleFrames;
  975. sUI overNumFrames = sUI((sampleFrames * wrapper->oversample.factor) + 0.5f);
  976. // Up-sample inputs
  977. {
  978. sUI inNumFrames = hostNumFrames;
  979. sUI outNumFrames = overNumFrames;
  980. sF32 *d = wrapper->oversample.in_buffers;
  981. for(chIdx = 0u; chIdx < NUM_INPUTS; chIdx++)
  982. {
  983. if(chIdx < wrapper->oversample.num_in)
  984. {
  985. sF32 *s = _inputs[chIdx];
  986. int err = speex_resampler_process_float(wrapper->oversample.srs_in,
  987. chIdx,
  988. s,
  989. &inNumFrames,
  990. d,
  991. &outNumFrames
  992. );
  993. (void)err;
  994. }
  995. else
  996. {
  997. // Skip channel
  998. ::memset(d, 0, sizeof(sF32) * outNumFrames);
  999. }
  1000. inputs[chIdx] = d;
  1001. // Next input channel
  1002. d += outNumFrames;
  1003. }
  1004. }
  1005. // Clear output buffers
  1006. // (note) AudioInterface instances accumulate samples in the output buffer
  1007. {
  1008. sF32 *d = wrapper->oversample.out_buffers;
  1009. ::memset((void*)d, 0, (sizeof(sF32) * wrapper->oversample.num_out * overNumFrames));
  1010. for(chIdx = 0u; chIdx < NUM_OUTPUTS; chIdx++)
  1011. {
  1012. outputs[chIdx] = d;
  1013. d += overNumFrames;
  1014. }
  1015. }
  1016. // Process rack modules
  1017. if(wrapper->b_processing)
  1018. {
  1019. vst2_engine_process(inputs, outputs, overNumFrames);
  1020. }
  1021. // Down-sample outputs
  1022. {
  1023. sF32 *s = wrapper->oversample.out_buffers;
  1024. sUI inNumFrames = overNumFrames;
  1025. sUI outNumFrames = hostNumFrames;
  1026. for(chIdx = 0u; chIdx < NUM_OUTPUTS; chIdx++)
  1027. {
  1028. sF32 *d = _outputs[chIdx];
  1029. if(chIdx < wrapper->oversample.num_out)
  1030. {
  1031. int err = speex_resampler_process_float(wrapper->oversample.srs_out,
  1032. chIdx,
  1033. s,
  1034. &inNumFrames,
  1035. d,
  1036. &outNumFrames
  1037. );
  1038. (void)err;
  1039. // Next output channel
  1040. s += inNumFrames;
  1041. }
  1042. else
  1043. {
  1044. // Skip output
  1045. ::memset((void*)d, 0, sizeof(sF32) * outNumFrames);
  1046. }
  1047. }
  1048. }
  1049. }
  1050. else
  1051. {
  1052. // No oversampling
  1053. // (note) Cubase (tested with 9.5.30) uses the same buffer(s) for both input&output
  1054. // => back up the inputs before clearing the outputs
  1055. sF32 *inputs[NUM_INPUTS];
  1056. sUI k = 0u;
  1057. for(chIdx = 0u; chIdx < NUM_INPUTS; chIdx++)
  1058. {
  1059. inputs[chIdx] = &wrapper->tmp_input_buffers[k];
  1060. ::memcpy((void*)inputs[chIdx], _inputs[chIdx], sizeof(sF32)*sampleFrames);
  1061. k += sampleFrames;
  1062. }
  1063. // Clear output buffers
  1064. // (note) AudioInterface instances accumulate samples in the output buffer
  1065. for(chIdx = 0u; chIdx < NUM_OUTPUTS; chIdx++)
  1066. {
  1067. ::memset((void*)_outputs[chIdx], 0, sizeof(sF32)*sampleFrames);
  1068. }
  1069. if(wrapper->b_processing)
  1070. {
  1071. vst2_engine_process(inputs, _outputs, sampleFrames);
  1072. }
  1073. }
  1074. if(VSTPluginWrapper::IDLE_DETECT_NONE != wrapper->idle_detect_mode)
  1075. {
  1076. bool bSilence = true;
  1077. for(chIdx = 0u; chIdx < NUM_OUTPUTS; chIdx++)
  1078. {
  1079. if(chIdx < wrapper->oversample.num_out)
  1080. {
  1081. cmemptr_t d;
  1082. d.f32 = _outputs[chIdx];
  1083. sF32 sum = 0.0f;
  1084. for(sUI i = 0u; i < sUI(sampleFrames); i++)
  1085. {
  1086. mem_t m;
  1087. m.u32 = d.u32[i] & ~0x80000000u; // abs
  1088. sum += m.f32;
  1089. // sum += d.f32[i] * d.f32[i]; // RMS
  1090. }
  1091. sum = (sum / float(sampleFrames));
  1092. // sum = sqrtf(sum / float(sampleFrames)); // RMS
  1093. {
  1094. static int x = 0;
  1095. if(0 == (++x & 127))
  1096. {
  1097. Dprintf_idle("xxx vstrack_plugin: output avg is %f\n", sum);
  1098. }
  1099. }
  1100. if(sum >= wrapper->idle_output_level_threshold)
  1101. {
  1102. bSilence = false;
  1103. break;
  1104. }
  1105. }
  1106. }
  1107. if(bSilence)
  1108. {
  1109. wrapper->idle_output_framecount += sampleFrames;
  1110. if(wrapper->idle_output_framecount >= sUI(wrapper->idle_output_sec_threshold * wrapper->sample_rate))
  1111. {
  1112. // Frame threshold exceeded, become idle
  1113. wrapper->b_idle = true;
  1114. Dprintf_idle("xxx vstrack_plugin: now idle\n");
  1115. }
  1116. }
  1117. else
  1118. {
  1119. wrapper->idle_output_framecount = 0u;
  1120. }
  1121. }
  1122. } // if !wrapper->b_idle
  1123. else
  1124. {
  1125. // Idle, clear output buffers
  1126. for(chIdx = 0u; chIdx < NUM_OUTPUTS; chIdx++)
  1127. {
  1128. ::memset((void*)_outputs[chIdx], 0, sizeof(sF32)*sampleFrames);
  1129. }
  1130. }
  1131. // // rack::global->engine.vipMutex.unlock();
  1132. rack::global->engine.mutex.unlock();
  1133. wrapper->unlockAudio();
  1134. //Dprintf("xxx vstrack_plugin: VSTPluginProcessReplacingFloat32: LEAVE\n");
  1135. }
  1136. /**
  1137. * This is the plugin called by the host to communicate with the plugin, mainly to request information (like the
  1138. * vendor string, the plugin category...) or communicate state/changes (like open/close, frame rate...)
  1139. *
  1140. * @param vstPlugin the object returned by VSTPluginMain
  1141. * @param opCode defined in aeffect.h/AEffectOpcodes and which continues in aeffectx.h/AEffectXOpcodes for a grand
  1142. * total of 79 of them! Only a few of them are implemented in this small plugin.
  1143. * @param index depend on the opcode
  1144. * @param value depend on the opcode
  1145. * @param ptr depend on the opcode
  1146. * @param opt depend on the opcode
  1147. * @return depend on the opcode (0 is ok when you don't implement an opcode...)
  1148. */
  1149. VstIntPtr VSTPluginDispatcher(VSTPlugin *vstPlugin,
  1150. VstInt32 opCode,
  1151. VstInt32 index,
  1152. VstIntPtr value,
  1153. void *ptr,
  1154. float opt
  1155. ) {
  1156. // Dprintf("vstrack_plugin: called VSTPluginDispatcher(%d)\n", opCode);
  1157. VstIntPtr r = 0;
  1158. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  1159. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  1160. // see aeffect.h/AEffectOpcodes and aeffectx.h/AEffectXOpcodes for details on all of them
  1161. switch(opCode)
  1162. {
  1163. case effGetPlugCategory:
  1164. // request for the category of the plugin: in this case it is an effect since it is modifying the input (as opposed
  1165. // to generating sound)
  1166. #ifdef VST2_EFFECT
  1167. return kPlugCategEffect;
  1168. #else
  1169. return kPlugCategSynth;
  1170. #endif // VST2_EFFECT
  1171. case effOpen:
  1172. // called by the host after it has obtained the effect instance (but _not_ during plugin scans)
  1173. // (note) any heavy-lifting init code should go here
  1174. Dprintf("vstrack_plugin<dispatcher>: effOpen\n");
  1175. r = wrapper->openEffect();
  1176. break;
  1177. case effClose:
  1178. // called by the host when the plugin was called... time to reclaim memory!
  1179. wrapper->closeEffect();
  1180. // (note) hosts usually call effStopProcess before effClose
  1181. delete wrapper;
  1182. break;
  1183. case effSetProgram:
  1184. r = 1;
  1185. break;
  1186. case effGetProgram:
  1187. r = 0;
  1188. break;
  1189. case effGetVendorString:
  1190. // request for the vendor string (usually used in the UI for plugin grouping)
  1191. ::strncpy(static_cast<char *>(ptr), "bsp", kVstMaxVendorStrLen);
  1192. r = 1;
  1193. break;
  1194. case effGetVendorVersion:
  1195. // request for the version
  1196. return PLUGIN_VERSION;
  1197. case effGetEffectName:
  1198. #ifdef VST2_EFFECT
  1199. ::strncpy((char*)ptr, "VeeSeeVST Rack 0.6.1", kVstMaxEffectNameLen);
  1200. #else
  1201. ::strncpy((char*)ptr, "VeeSeeVST Rack 0.6.1 I", kVstMaxEffectNameLen);
  1202. #endif // VST2_EFFECT
  1203. r = 1;
  1204. break;
  1205. case effGetProductString:
  1206. #ifdef VST2_EFFECT
  1207. ::strncpy((char*)ptr, "VeeSeeVST Rack 0.6.1 VST2 Plugin v0.4", kVstMaxProductStrLen);
  1208. #else
  1209. ::strncpy((char*)ptr, "VeeSeeVST Rack 0.6.1 I VST2 Plugin v0.4", kVstMaxProductStrLen);
  1210. #endif // VST2_EFFECT
  1211. r = 1;
  1212. break;
  1213. case effGetNumMidiInputChannels:
  1214. r = 16;
  1215. break;
  1216. case effGetNumMidiOutputChannels:
  1217. r = 0;
  1218. break;
  1219. case effGetInputProperties:
  1220. {
  1221. VstPinProperties *pin = (VstPinProperties*)ptr;
  1222. ::snprintf(pin->label, kVstMaxLabelLen, "Input #%d", index);
  1223. pin->flags = kVstPinIsActive | ((0 == (index & 1)) ? kVstPinIsStereo : 0);
  1224. pin->arrangementType = ((0 == (index & 1)) ? kSpeakerArrStereo : kSpeakerArrMono);
  1225. ::snprintf(pin->shortLabel, kVstMaxShortLabelLen, "in%d", index);
  1226. memset((void*)pin->future, 0, 48);
  1227. r = 1;
  1228. }
  1229. break;
  1230. case effGetOutputProperties:
  1231. {
  1232. VstPinProperties *pin = (VstPinProperties*)ptr;
  1233. ::snprintf(pin->label, kVstMaxLabelLen, "Output #%d", index);
  1234. pin->flags = kVstPinIsActive | ((0 == (index & 1)) ? kVstPinIsStereo : 0);
  1235. pin->arrangementType = ((0 == (index & 1)) ? kSpeakerArrStereo : kSpeakerArrMono);
  1236. ::snprintf(pin->shortLabel, kVstMaxShortLabelLen, "out%d", index);
  1237. memset((void*)pin->future, 0, 48);
  1238. r = 1;
  1239. }
  1240. break;
  1241. case effSetSampleRate:
  1242. r = wrapper->setSampleRate(opt) ? 1 : 0;
  1243. break;
  1244. case effSetBlockSize:
  1245. r = wrapper->setBlockSize(uint32_t(value)) ? 1 : 0;
  1246. break;
  1247. case effCanDo:
  1248. // ptr:
  1249. // "sendVstEvents"
  1250. // "sendVstMidiEvent"
  1251. // "sendVstTimeInfo"
  1252. // "receiveVstEvents"
  1253. // "receiveVstMidiEvent"
  1254. // "receiveVstTimeInfo"
  1255. // "offline"
  1256. // "plugAsChannelInsert"
  1257. // "plugAsSend"
  1258. // "mixDryWet"
  1259. // "noRealTime"
  1260. // "multipass"
  1261. // "metapass"
  1262. // "1in1out"
  1263. // "1in2out"
  1264. // "2in1out"
  1265. // "2in2out"
  1266. // "2in4out"
  1267. // "4in2out"
  1268. // "4in4out"
  1269. // "4in8out"
  1270. // "8in4out"
  1271. // "8in8out"
  1272. // "midiProgramNames"
  1273. // "conformsToWindowRules"
  1274. if(!strcmp((char*)ptr, "receiveVstEvents"))
  1275. r = 1;
  1276. else if(!strcmp((char*)ptr, "receiveVstMidiEvent")) // (note) required by Jeskola Buzz
  1277. r = 1;
  1278. else if(!strcmp((char*)ptr, "noRealTime"))
  1279. r = 1;
  1280. else
  1281. r = 0;
  1282. break;
  1283. case effGetProgramName:
  1284. ::snprintf((char*)ptr, kVstMaxProgNameLen, "default");
  1285. r = 1;
  1286. break;
  1287. case effSetProgramName:
  1288. r = 1;
  1289. break;
  1290. case effGetProgramNameIndexed:
  1291. ::sprintf((char*)ptr, "default");
  1292. r = 1;
  1293. break;
  1294. case effGetParamName:
  1295. // kVstMaxParamStrLen(8), much longer in other plugins
  1296. // printf("xxx vstrack_plugin: effGetParamName: ptr=%p\n", ptr);
  1297. wrapper->setGlobals();
  1298. vst2_get_param_name(index, (char*)ptr, kVstMaxParamStrLen);
  1299. r = 1;
  1300. break;
  1301. case effCanBeAutomated:
  1302. // fix Propellerhead Reason VST parameter support
  1303. r = 1;
  1304. break;
  1305. case effGetParamLabel:
  1306. // e.g. "dB"
  1307. break;
  1308. case effGetParamDisplay:
  1309. // e.g. "-20"
  1310. break;
  1311. #if 0
  1312. case effGetParameterProperties:
  1313. // [index]: parameter index [ptr]: #VstParameterProperties* [return value]: 1 if supported
  1314. wrapper->setGlobals();
  1315. r = wrapper->getParameterProperties(sUI(index), (struct VstParameterProperties*)ptr);
  1316. break;
  1317. #endif
  1318. case effGetChunk:
  1319. // Query bank (index=0) or program (index=1) state
  1320. // value: 0
  1321. // ptr: buffer address
  1322. // r: buffer size
  1323. Dprintf("xxx vstrack_plugin: effGetChunk index=%d ptr=%p\n", index, ptr);
  1324. // // if(0 == index)
  1325. // // {
  1326. // // r = wrapper->getBankChunk((uint8_t**)ptr);
  1327. // // }
  1328. // // else
  1329. // // {
  1330. r = wrapper->getProgramChunk((uint8_t**)ptr);
  1331. // // }
  1332. break;
  1333. case effSetChunk:
  1334. // Restore bank (index=0) or program (index=1) state
  1335. // value: buffer size
  1336. // ptr: buffer address
  1337. // r: 1
  1338. Dprintf("xxx vstrack_plugin: effSetChunk index=%d size=%d ptr=%p\n", index, (int)value, ptr);
  1339. // // if(0 == index)
  1340. // // {
  1341. // // r = wrapper->setBankChunk(size_t(value), (uint8_t*)ptr) ? 1 : 0;
  1342. // // }
  1343. // // else
  1344. // // {
  1345. r = wrapper->setProgramChunk(size_t(value), (uint8_t*)ptr) ? 1 : 0;
  1346. // // }
  1347. break;
  1348. case effShellGetNextPlugin:
  1349. // For shell plugins (e.g. Waves), returns next sub-plugin UID (or 0)
  1350. // (note) plugin uses audioMasterCurrentId while it's being instantiated to query the currently selected sub-plugin
  1351. // if the host returns 0, it will then call effShellGetNextPlugin to enumerate the sub-plugins
  1352. // ptr: effect name string ptr (filled out by the plugin)
  1353. r = 0;
  1354. break;
  1355. case effMainsChanged:
  1356. // value = 0=suspend, 1=resume
  1357. wrapper->setEnableProcessingActive((value > 0) ? true : false);
  1358. r = 1;
  1359. break;
  1360. case effStartProcess:
  1361. wrapper->setEnableProcessingActive(true);
  1362. r = 1;
  1363. break;
  1364. case effStopProcess:
  1365. wrapper->setEnableProcessingActive(false);
  1366. r = 1;
  1367. break;
  1368. case effProcessEvents:
  1369. // ptr: VstEvents*
  1370. {
  1371. VstEvents *events = (VstEvents*)ptr;
  1372. // Dprintf("vstrack_plugin:effProcessEvents: recvd %d events", events->numEvents);
  1373. VstEvent**evAddr = &events->events[0];
  1374. if(events->numEvents > 0)
  1375. {
  1376. wrapper->setGlobals();
  1377. wrapper->mtx_mididev.lock();
  1378. for(uint32_t evIdx = 0u; evIdx < uint32_t(events->numEvents); evIdx++, evAddr++)
  1379. {
  1380. VstEvent *ev = *evAddr;
  1381. if(NULL != ev) // paranoia
  1382. {
  1383. #ifdef DEBUG_PRINT_EVENTS
  1384. Dprintf("vstrack_plugin:effProcessEvents: ev[%u].byteSize = %u\n", evIdx, uint32_t(ev->byteSize)); // sizeof(VstMidiEvent) = 32
  1385. Dprintf("vstrack_plugin:effProcessEvents: ev[%u].deltaFrames = %u\n", evIdx, uint32_t(ev->deltaFrames));
  1386. #endif // DEBUG_PRINT_EVENTS
  1387. switch(ev->type)
  1388. {
  1389. default:
  1390. //case kVstAudioType: // deprecated
  1391. //case kVstVideoType: // deprecated
  1392. //case kVstParameterType: // deprecated
  1393. //case kVstTriggerType: // deprecated
  1394. break;
  1395. case kVstMidiType:
  1396. // (note) ev->data stores the actual payload (up to 16 bytes)
  1397. // (note) e.g. 0x90 0x30 0x7F for a C-4 note-on on channel 1 with velocity 127
  1398. // (note) don't forget to use a mutex (lockAudio(), unlockAudio()) when modifying the audio processor state!
  1399. {
  1400. VstMidiEvent *mev = (VstMidiEvent *)ev;
  1401. #ifdef DEBUG_PRINT_EVENTS
  1402. Dprintf("vstrack_plugin:effProcessEvents<midi>: ev[%u].noteLength = %u\n", evIdx, uint32_t(mev->noteLength)); // #frames
  1403. Dprintf("vstrack_plugin:effProcessEvents<midi>: ev[%u].noteOffset = %u\n", evIdx, uint32_t(mev->noteOffset)); // #frames
  1404. Dprintf("vstrack_plugin:effProcessEvents<midi>: ev[%u].midiData = %02x %02x %02x %02x\n", evIdx, uint8_t(mev->midiData[0]), uint8_t(mev->midiData[1]), uint8_t(mev->midiData[2]), uint8_t(mev->midiData[3]));
  1405. Dprintf("vstrack_plugin:effProcessEvents<midi>: ev[%u].detune = %d\n", evIdx, mev->detune); // -64..63
  1406. Dprintf("vstrack_plugin:effProcessEvents<midi>: ev[%u].noteOffVelocity = %d\n", evIdx, mev->noteOffVelocity); // 0..127
  1407. #endif // DEBUG_PRINT_EVENTS
  1408. if((VSTPluginWrapper::IDLE_DETECT_MIDI == wrapper->idle_detect_mode) && wrapper->b_idle)
  1409. {
  1410. if(0x90u == (mev->midiData[0] & 0xF0u)) // Note on ?
  1411. {
  1412. wrapper->lockAudio();
  1413. wrapper->b_idle = false;
  1414. wrapper->idle_output_framecount = 0u;
  1415. wrapper->unlockAudio();
  1416. Dprintf_idle("xxx vstrack_plugin: become active after MIDI note on\n");
  1417. }
  1418. }
  1419. vst2_process_midi_input_event(mev->midiData[0],
  1420. mev->midiData[1],
  1421. mev->midiData[2]
  1422. );
  1423. }
  1424. break;
  1425. case kVstSysExType:
  1426. {
  1427. #ifdef DEBUG_PRINT_EVENTS
  1428. VstMidiSysexEvent *xev = (VstMidiSysexEvent*)ev;
  1429. Dprintf("vstrack_plugin:effProcessEvents<syx>: ev[%u].dumpBytes = %u\n", evIdx, uint32_t(xev->dumpBytes)); // size
  1430. Dprintf("vstrack_plugin:effProcessEvents<syx>: ev[%u].sysexDump = %p\n", evIdx, xev->sysexDump); // buffer addr
  1431. #endif // DEBUG_PRINT_EVENTS
  1432. // (note) don't forget to use a mutex (lockAudio(), unlockAudio()) when modifying the audio processor state!
  1433. }
  1434. break;
  1435. }
  1436. } // if ev
  1437. } // loop events
  1438. wrapper->mtx_mididev.unlock();
  1439. } // if events
  1440. }
  1441. break;
  1442. case effGetTailSize: // 52
  1443. break;
  1444. #if 1
  1445. //case effIdle:
  1446. case 53:
  1447. // Periodic idle call (from UI thread), e.g. at 20ms intervals (depending on host)
  1448. // (note) deprecated in vst2.4 (but some plugins still rely on this)
  1449. r = 1;
  1450. break;
  1451. #endif
  1452. case effEditIdle:
  1453. if(0 == wrapper->redraw_ival_ms)
  1454. {
  1455. wrapper->queueRedraw();
  1456. }
  1457. break;
  1458. case effEditGetRect:
  1459. // Query editor window geometry
  1460. // ptr: ERect* (on Windows)
  1461. if(NULL != ptr)
  1462. {
  1463. // ...
  1464. printf("xxx vstrack_plugin: effEditGetRect: (%d; %d; %d; %d)\n",
  1465. wrapper->editor_rect.top,
  1466. wrapper->editor_rect.left,
  1467. wrapper->editor_rect.bottom,
  1468. wrapper->editor_rect.right
  1469. );
  1470. *(void**)ptr = (void*) &wrapper->editor_rect;
  1471. r = 1;
  1472. }
  1473. else
  1474. {
  1475. r = 0;
  1476. }
  1477. break;
  1478. #if 0
  1479. case effEditTop:
  1480. // deprecated in vst2.4
  1481. r = 0;
  1482. break;
  1483. #endif
  1484. case effEditOpen:
  1485. // Show editor window
  1486. // ptr: native window handle (hWnd on Windows)
  1487. wrapper->openEditor(ptr);
  1488. r = 1;
  1489. break;
  1490. case effEditClose:
  1491. // Close editor window
  1492. wrapper->closeEditor();
  1493. r = 1;
  1494. break;
  1495. case effEditKeyDown:
  1496. // [index]: ASCII character [value]: virtual key [opt]: modifiers [return value]: 1 if key used @see AEffEditor::onKeyDown
  1497. // (note) only used for touch input
  1498. // Dprintf("xxx effEditKeyDown: ascii=%d (\'%c\') vkey=0x%08x mod=0x%08x\n", index, index, value, opt);
  1499. if(rack::b_touchkeyboard_enable)
  1500. {
  1501. wrapper->setGlobals();
  1502. {
  1503. uint32_t vkey = 0u;
  1504. switch(uint32_t(value))
  1505. {
  1506. // see aeffectx.h
  1507. case VKEY_BACK: vkey = LGLW_VKEY_BACKSPACE; break;
  1508. case VKEY_TAB: vkey = LGLW_VKEY_TAB; break;
  1509. case VKEY_RETURN: vkey = LGLW_VKEY_RETURN; break;
  1510. case VKEY_ESCAPE: vkey = LGLW_VKEY_ESCAPE; break;
  1511. case VKEY_END: vkey = LGLW_VKEY_END; break;
  1512. case VKEY_HOME: vkey = LGLW_VKEY_HOME; break;
  1513. case VKEY_LEFT: vkey = LGLW_VKEY_LEFT; break;
  1514. case VKEY_UP: vkey = LGLW_VKEY_UP; break;
  1515. case VKEY_RIGHT: vkey = LGLW_VKEY_RIGHT; break;
  1516. case VKEY_DOWN: vkey = LGLW_VKEY_DOWN; break;
  1517. case VKEY_PAGEUP: vkey = LGLW_VKEY_PAGEUP; break;
  1518. case VKEY_PAGEDOWN: vkey = LGLW_VKEY_PAGEDOWN; break;
  1519. case VKEY_ENTER: vkey = LGLW_VKEY_RETURN; break;
  1520. case VKEY_INSERT: vkey = LGLW_VKEY_INSERT; break;
  1521. case VKEY_DELETE: vkey = LGLW_VKEY_DELETE; break;
  1522. break;
  1523. default:
  1524. vkey = (char)index;
  1525. // (note) some(most?) DAWs don't send the correct VKEY_xxx values for all special keys
  1526. switch(vkey)
  1527. {
  1528. case 8: vkey = LGLW_VKEY_BACKSPACE; break;
  1529. // case 13: vkey = LGLW_VKEY_RETURN; break;
  1530. // case 9: vkey = LGLW_VKEY_TAB; break;
  1531. // case 27: vkey = LGLW_VKEY_ESCAPE; break;
  1532. default:
  1533. if(vkey >= 128)
  1534. vkey = 0u;
  1535. break;
  1536. }
  1537. break;
  1538. }
  1539. if(vkey > 0u)
  1540. {
  1541. r = vst2_handle_effeditkeydown(vkey);
  1542. }
  1543. }
  1544. }
  1545. break;
  1546. default:
  1547. // ignoring all other opcodes
  1548. Dprintf("vstrack_plugin:dispatcher: unhandled opCode %d [ignored] \n", opCode);
  1549. break;
  1550. }
  1551. return r;
  1552. }
  1553. /**
  1554. * Set parameter setting
  1555. */
  1556. void VSTPluginSetParameter(VSTPlugin *vstPlugin,
  1557. VstInt32 index,
  1558. float parameter
  1559. ) {
  1560. #ifdef DEBUG_PRINT_PARAMS
  1561. Dprintf("vstrack_plugin: called VSTPluginSetParameter(%d, %f)\n", index, parameter);
  1562. #endif // DEBUG_PRINT_PARAMS
  1563. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  1564. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  1565. // // wrapper->lockAudio();
  1566. wrapper->setGlobals();
  1567. rack::global_ui->app.mtx_param.lock();
  1568. vst2_queue_param(index, parameter, true/*bNormalized*/);
  1569. rack::global_ui->app.mtx_param.unlock();
  1570. // // wrapper->unlockAudio();
  1571. }
  1572. void vst2_queue_param_sync(int _uniqueParamId, float _value, bool _bNormalized) {
  1573. // Called when parameter is edited numerically via textfield
  1574. printf("xxx vst2_queue_param_sync ENTER: uniqueParamId=%d value=%f bNormalized=%d\n", _uniqueParamId, _value, _bNormalized);
  1575. // // VSTPluginWrapper *wrapper = rack::global->vst2.wrapper;
  1576. // // wrapper->lockAudio();
  1577. rack::global_ui->app.mtx_param.lock();
  1578. vst2_queue_param(_uniqueParamId, _value, _bNormalized);
  1579. rack::global_ui->app.mtx_param.unlock();
  1580. // // wrapper->unlockAudio();
  1581. printf("xxx vst2_queue_param_sync LEAVE\n");
  1582. }
  1583. /**
  1584. * Query parameter
  1585. */
  1586. float VSTPluginGetParameter(VSTPlugin *vstPlugin,
  1587. VstInt32 index
  1588. ) {
  1589. #ifdef DEBUG_PRINT_PARAMS
  1590. Dprintf("vstrack_plugin: called VSTPluginGetParameter(%d)\n", index);
  1591. #endif // DEBUG_PRINT_PARAMS
  1592. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  1593. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  1594. wrapper->lockAudio(); // don't query a param while the module is deleted
  1595. wrapper->setGlobals();
  1596. float r = vst2_get_param(index);
  1597. wrapper->unlockAudio();
  1598. return r;
  1599. }
  1600. /**
  1601. * Main constructor for our C++ class
  1602. */
  1603. VSTPluginWrapper::VSTPluginWrapper(audioMasterCallback vstHostCallback,
  1604. VstInt32 vendorUniqueID,
  1605. VstInt32 vendorVersion,
  1606. VstInt32 numParams,
  1607. VstInt32 numPrograms,
  1608. VstInt32 numInputs,
  1609. VstInt32 numOutputs
  1610. ) : _vstHostCallback(vstHostCallback)
  1611. {
  1612. instance_count++;
  1613. // Make sure that the memory is properly initialized
  1614. memset(&_vstPlugin, 0, sizeof(_vstPlugin));
  1615. // this field must be set with this constant...
  1616. _vstPlugin.magic = kEffectMagic;
  1617. // storing this object into the VSTPlugin so that it can be retrieved when called back (see callbacks for use)
  1618. _vstPlugin.object = this;
  1619. // specifying that we handle both single and NOT double precision (there are other flags see aeffect.h/VstAEffectFlags)
  1620. _vstPlugin.flags =
  1621. #ifndef VST2_EFFECT
  1622. effFlagsIsSynth |
  1623. #endif
  1624. effFlagsCanReplacing |
  1625. // (effFlagsCanDoubleReplacing & 0) |
  1626. effFlagsProgramChunks |
  1627. effFlagsHasEditor ;
  1628. // initializing the plugin with the various values
  1629. _vstPlugin.uniqueID = vendorUniqueID;
  1630. _vstPlugin.version = vendorVersion;
  1631. _vstPlugin.numParams = numParams;
  1632. _vstPlugin.numPrograms = numPrograms;
  1633. _vstPlugin.numInputs = numInputs;
  1634. _vstPlugin.numOutputs = numOutputs;
  1635. // setting the callbacks to the previously defined functions
  1636. _vstPlugin.dispatcher = &VSTPluginDispatcher;
  1637. _vstPlugin.getParameter = &VSTPluginGetParameter;
  1638. _vstPlugin.setParameter = &VSTPluginSetParameter;
  1639. _vstPlugin.processReplacing = &VSTPluginProcessReplacingFloat32;
  1640. _vstPlugin.processDoubleReplacing = NULL;//&VSTPluginProcessReplacingFloat64;
  1641. // report latency
  1642. _vstPlugin.initialDelay = 0;
  1643. oversample.factor = 1.0f;
  1644. oversample.quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
  1645. oversample.realtime_factor = 1.0f;
  1646. oversample.realtime_quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
  1647. oversample.offline_factor = 1.0f;
  1648. oversample.offline_quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
  1649. oversample.srs_in = NULL;
  1650. oversample.srs_out = NULL;
  1651. oversample.num_in = NUM_INPUTS;
  1652. oversample.num_out = NUM_OUTPUTS;
  1653. sample_rate = 44100.0f;
  1654. block_size = 64u;
  1655. b_processing = true;
  1656. b_offline = false;
  1657. b_check_offline = false;
  1658. idle_detect_mode = IDLE_DETECT_NONE;
  1659. idle_detect_mode_fx = IDLE_DETECT_AUDIO;
  1660. idle_detect_mode_instr = IDLE_DETECT_MIDI;
  1661. b_idle = false;
  1662. idle_input_level_threshold = 0.00018f;//0.00007f;
  1663. idle_output_level_threshold = 0.00018f;//0.00003f;
  1664. idle_output_sec_threshold = 120.0f / 1000.0f; // idle after 120ms of silence
  1665. idle_output_framecount = 0u;
  1666. last_program_chunk_str = NULL;
  1667. b_open = false;
  1668. b_editor_open = false;
  1669. editor_rect.left = EDITWIN_X;
  1670. editor_rect.top = EDITWIN_Y;
  1671. editor_rect.right = EDITWIN_X + EDITWIN_W;
  1672. editor_rect.bottom = EDITWIN_Y + EDITWIN_H;
  1673. redraw_ival_ms = 0;
  1674. }
  1675. /**
  1676. * Destructor called when the plugin is closed (see VSTPluginDispatcher with effClose opCode). In this very simply plugin
  1677. * there is nothing to do but in general the memory that gets allocated MUST be freed here otherwise there might be a
  1678. * memory leak which may end up slowing down and/or crashing the host
  1679. */
  1680. VSTPluginWrapper::~VSTPluginWrapper() {
  1681. closeEffect();
  1682. instance_count--;
  1683. }
  1684. void vst2_lock_midi_device() {
  1685. rack::global->vst2.wrapper->mtx_mididev.lock();
  1686. }
  1687. void vst2_unlock_midi_device() {
  1688. rack::global->vst2.wrapper->mtx_mididev.unlock();
  1689. }
  1690. void vst2_handle_ui_param(int uniqueParamId, float normValue) {
  1691. // Called by engineSetParam()
  1692. // printf("xxx vst2_handle_ui_param: uniqueParamId=%d &global=%p global=%p wrapper=%p\n", uniqueParamId, &rack::global, rack::global, rack::global->vst2.wrapper);
  1693. rack::global->vst2.wrapper->handleUIParam(uniqueParamId, normValue);
  1694. }
  1695. void vst2_get_timing_info(int *_retPlaying, float *_retBPM, float *_retSongPosPPQ) {
  1696. // updates the requested fields when query was successful
  1697. rack::global->vst2.wrapper->getTimingInfo(_retPlaying, _retBPM, _retSongPosPPQ);
  1698. }
  1699. void vst2_set_globals(void *_wrapper) {
  1700. VSTPluginWrapper *wrapper = (VSTPluginWrapper *)_wrapper;
  1701. wrapper->setGlobals();
  1702. vst2_set_shared_plugin_tls_globals();
  1703. }
  1704. void vst2_window_size_set(int _width, int _height) {
  1705. rack::global->vst2.wrapper->setWindowSize(_width, _height);
  1706. }
  1707. void vst2_refresh_rate_set(float _hz) {
  1708. rack::global->vst2.wrapper->setRefreshRate(_hz);
  1709. }
  1710. float vst2_refresh_rate_get(void) {
  1711. return rack::global->vst2.wrapper->getRefreshRate();
  1712. }
  1713. extern "C" void lglw_timer_cbk(lglw_t _lglw) {
  1714. VSTPluginWrapper *wrapper = (VSTPluginWrapper*)lglw_userdata_get(_lglw);
  1715. wrapper->queueRedraw();
  1716. }
  1717. extern "C" void lglw_redraw_cbk(lglw_t _lglw) {
  1718. VSTPluginWrapper *wrapper = (VSTPluginWrapper*)lglw_userdata_get(_lglw);
  1719. wrapper->redraw();
  1720. }
  1721. void vst2_oversample_realtime_set(float _factor, int _quality) {
  1722. rack::global->vst2.wrapper->setOversampleRealtime(_factor, _quality);
  1723. }
  1724. void vst2_oversample_realtime_get(float *_factor, int *_quality) {
  1725. *_factor = rack::global->vst2.wrapper->oversample.realtime_factor;
  1726. *_quality = int(rack::global->vst2.wrapper->oversample.realtime_quality);
  1727. }
  1728. void vst2_oversample_offline_set(float _factor, int _quality) {
  1729. rack::global->vst2.wrapper->setOversampleOffline(_factor, _quality);
  1730. }
  1731. void vst2_oversample_offline_get(float *_factor, int *_quality) {
  1732. *_factor = rack::global->vst2.wrapper->oversample.offline_factor;
  1733. *_quality = int(rack::global->vst2.wrapper->oversample.offline_quality);
  1734. }
  1735. void vst2_oversample_offline_check_set(int _bEnable) {
  1736. rack::global->vst2.wrapper->b_check_offline = (0 != _bEnable);
  1737. }
  1738. int32_t vst2_oversample_offline_check_get(void) {
  1739. return int32_t(rack::global->vst2.wrapper->b_check_offline);
  1740. }
  1741. void vst2_oversample_channels_set(int _numIn, int _numOut) {
  1742. rack::global->vst2.wrapper->setOversampleChannels(_numIn, _numOut);
  1743. }
  1744. void vst2_oversample_channels_get(int *_numIn, int *_numOut) {
  1745. *_numIn = int(rack::global->vst2.wrapper->oversample.num_in);
  1746. *_numOut = int(rack::global->vst2.wrapper->oversample.num_out);
  1747. }
  1748. void vst2_idle_detect_mode_fx_set(int _mode) {
  1749. rack::global->vst2.wrapper->setIdleDetectModeFx(uint32_t(_mode));
  1750. }
  1751. int vst2_idle_detect_mode_fx_get(void) {
  1752. return rack::global->vst2.wrapper->idle_detect_mode_fx;
  1753. }
  1754. void vst2_idle_detect_mode_instr_set(int _mode) {
  1755. rack::global->vst2.wrapper->setIdleDetectModeInstr(uint32_t(_mode));
  1756. }
  1757. int vst2_idle_detect_mode_instr_get(void) {
  1758. return rack::global->vst2.wrapper->idle_detect_mode_instr;
  1759. }
  1760. void vst2_idle_detect_mode_set(int _mode) {
  1761. rack::global->vst2.wrapper->setIdleDetectMode(uint32_t(_mode));
  1762. }
  1763. void vst2_idle_detect_mode_get(int *_mode) {
  1764. *_mode = int(rack::global->vst2.wrapper->idle_detect_mode);
  1765. }
  1766. /**
  1767. * Implementation of the main entry point of the plugin
  1768. */
  1769. VST_EXPORT VSTPlugin *VSTPluginMain(VSTHostCallback vstHostCallback) {
  1770. Dprintf("vstrack_plugin: called VSTPluginMain... \n");
  1771. #if 0
  1772. if(!vstHostCallback(0, audioMasterVersion, 0, 0, 0, 0))
  1773. {
  1774. return 0; // old version
  1775. }
  1776. #endif
  1777. // simply create our plugin C++ class
  1778. VSTPluginWrapper *plugin =
  1779. new VSTPluginWrapper(vstHostCallback,
  1780. // registered with Steinberg (http://service.steinberg.de/databases/plugin.nsf/plugIn?openForm)
  1781. #ifdef VST2_EFFECT
  1782. CCONST('g', 'v', 'g', 'y'),
  1783. #else
  1784. CCONST('v', '5', 'k', 'v'),
  1785. #endif // VST2_EFFECT
  1786. PLUGIN_VERSION, // version
  1787. VST2_MAX_UNIQUE_PARAM_IDS, // num params
  1788. 1, // one program
  1789. NUM_INPUTS,
  1790. NUM_OUTPUTS
  1791. );
  1792. // return the plugin per the contract of the API
  1793. return plugin->getVSTPlugin();
  1794. }
  1795. #endif // USE_VST2