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.

2269 lines
69KB

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