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.

633 lines
18KB

  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. ///
  21. ///
  22. ///
  23. // #define DEBUG_PRINT_EVENTS defined
  24. // #define DEBUG_PRINT_PARAMS defined
  25. #define NUM_INPUTS ( 2) // must match AudioInterface.cpp:AUDIO_INPUTS
  26. #define NUM_OUTPUTS ( 2) // must match AudioInterface.cpp:AUDIO_OUTPUTS
  27. // (note) causes reason to shut down when console is freed (when plugin is deleted)
  28. //#define USE_CONSOLE defined
  29. #undef RACK_HOST
  30. #include <aeffect.h>
  31. #include <aeffectx.h>
  32. #include <stdio.h>
  33. #include "../dep/yac/yac.h"
  34. #include "../dep/yac/yac_host.cpp"
  35. YAC_Host *yac_host; // not actually used, just to satisfy the linker
  36. #include "global_pre.hpp"
  37. #include "global.hpp"
  38. #include "global_ui.hpp"
  39. extern int vst2_init (int argc, char* argv[]);
  40. extern void vst2_exit (void);
  41. extern void vst2_editor_create (void);
  42. extern void vst2_editor_loop (void);
  43. extern void vst2_editor_destroy (void);
  44. extern void vst2_set_samplerate (sF32 _rate);
  45. extern void vst2_engine_process (float *const*_in, float **_out, unsigned int _numFrames);
  46. extern void vst2_process_midi_input_event (sU8 _a, sU8 _b, sU8 _c);
  47. extern void vst2_queue_param (int uniqueParamId, float normValue);
  48. extern void vst2_handle_queued_params (void);
  49. extern float vst2_get_param (int uniqueParamId);
  50. extern void vst2_get_param_name (int uniqueParamId, char *s, int sMaxLen);
  51. extern void vst2_set_shared_plugin_tls_globals (void);
  52. #include "../include/window.hpp"
  53. #include "../dep/include/osdialog.h"
  54. #include "../include/app.hpp"
  55. // using namespace rack;
  56. // extern void rack::windowRun(void);
  57. #if defined(_WIN32) || defined(_WIN64)
  58. #define HAVE_WINDOWS defined
  59. #define WIN32_LEAN_AND_MEAN defined
  60. #include <windows.h>
  61. #include <xmmintrin.h>
  62. EXTERN_C IMAGE_DOS_HEADER __ImageBase;
  63. extern "C" extern HWND g_glfw_vst2_parent_hwnd; // read by modified version of GLFW (see glfw/src/win32_window.c)
  64. extern "C" extern HWND __hack__glfwGetHWND (GLFWwindow *window);
  65. // Windows:
  66. #define VST_EXPORT extern "C" __declspec(dllexport)
  67. struct PluginMutex {
  68. CRITICAL_SECTION handle;
  69. PluginMutex(void) {
  70. ::InitializeCriticalSection( &handle );
  71. }
  72. ~PluginMutex() {
  73. ::DeleteCriticalSection( &handle );
  74. }
  75. void lock(void) {
  76. ::EnterCriticalSection(&handle);
  77. }
  78. void unlock(void) {
  79. ::LeaveCriticalSection(&handle);
  80. }
  81. };
  82. #else
  83. // MacOSX, Linux:
  84. #define HAVE_UNIX defined
  85. #define VST_EXPORT extern
  86. #include <pthread.h>
  87. #include <errno.h>
  88. #include <unistd.h>
  89. #include <fcntl.h>
  90. #include <sys/mman.h>
  91. //static pthread_mutex_t loc_pthread_mutex_t_init = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
  92. static pthread_mutex_t loc_pthread_mutex_t_init = PTHREAD_MUTEX_INITIALIZER;
  93. struct PluginMutex {
  94. pthread_mutex_t handle;
  95. PluginMutex(void) {
  96. ::memcpy((void*)&handle, (const void*)&loc_pthread_mutex_t_init, sizeof(pthread_mutex_t));
  97. }
  98. ~PluginMutex() {
  99. }
  100. void lock(void) {
  101. ::pthread_mutex_lock(&handle);
  102. }
  103. void unlock(void) {
  104. ::pthread_mutex_unlock(&handle);
  105. }
  106. };
  107. #endif // _WIN32||_WIN64
  108. // // extern "C" {
  109. // // extern void glfwSetInstance(void *_glfw);
  110. // // }
  111. class PluginString : public YAC_String {
  112. public:
  113. static const sUI QUOT2 =(sUI)(1<<26); // \'\'
  114. static const sUI STRFLQMASK = (QUOT | UTAG1 | QUOT2);
  115. void safeFreeChars (void);
  116. sSI _realloc (sSI _numChars);
  117. sSI lastIndexOf (sChar _c, sUI _start) const;
  118. void getDirName (PluginString *_r) const;
  119. void replace (sChar _c, sChar _o);
  120. };
  121. void PluginString::safeFreeChars(void) {
  122. if(bflags & PluginString::DEL)
  123. {
  124. // if(!(bflags & PluginString::LA))
  125. {
  126. Dyacfreechars(chars);
  127. }
  128. }
  129. }
  130. sSI PluginString::_realloc(sSI _numBytes) {
  131. // Force alloc if a very big string is about to shrink a lot or there is simply not enough space available
  132. if( ((buflen >= 1024) && ( (((sUI)_numBytes)<<3) < buflen )) ||
  133. (NULL == chars) ||
  134. (buflen < ((sUI)_numBytes))
  135. ) // xxx (!chars) hack added 180702
  136. {
  137. if(NULL != chars)
  138. {
  139. sUI l = length;
  140. if(((sUI)_numBytes) < l)
  141. {
  142. l = _numBytes;
  143. }
  144. sU8 *nc = Dyacallocchars(_numBytes + 1);
  145. sUI i = 0;
  146. for(; i<l; i++)
  147. {
  148. nc[i] = chars[i];
  149. }
  150. nc[i] = 0;
  151. safeFreeChars();
  152. buflen = (_numBytes + 1);
  153. bflags = PluginString::DEL | (bflags & PluginString::STRFLQMASK); // keep old stringflags
  154. length = i + 1;
  155. chars = nc;
  156. key = YAC_LOSTKEY;
  157. return YAC_TRUE;
  158. }
  159. else
  160. {
  161. return PluginString::alloc(_numBytes + 1);
  162. }
  163. }
  164. else
  165. {
  166. key = YAC_LOSTKEY; // new 010208
  167. return YAC_TRUE;
  168. }
  169. }
  170. sSI PluginString::lastIndexOf(sChar _c, sUI _start) const {
  171. sSI li = -1;
  172. if(NULL != chars)
  173. {
  174. sUI i = _start;
  175. for(; i<length; i++)
  176. {
  177. if(chars[i] == ((sChar)_c))
  178. {
  179. li = i;
  180. }
  181. }
  182. }
  183. return li;
  184. }
  185. void PluginString::replace(sChar _c, sChar _o) {
  186. if(NULL != chars)
  187. {
  188. for(sUI i = 0; i < length; i++)
  189. {
  190. if(chars[i] == _c)
  191. chars[i] = _o;
  192. }
  193. }
  194. }
  195. void PluginString::getDirName(PluginString *_r) const {
  196. sSI idxSlash = lastIndexOf('/', 0);
  197. sSI idxBackSlash = lastIndexOf('\\', 0);
  198. sSI idxDrive = lastIndexOf(':', 0);
  199. sSI idx = -1;
  200. if(idxSlash > idxBackSlash)
  201. {
  202. idx = idxSlash;
  203. }
  204. else
  205. {
  206. idx = idxBackSlash;
  207. }
  208. if(idxDrive > idx)
  209. {
  210. idx = idxDrive;
  211. }
  212. if(-1 != idx)
  213. {
  214. _r->_realloc(idx + 2);
  215. _r->length = idx + 2;
  216. sSI i;
  217. for(i=0; i<=idx; i++)
  218. {
  219. _r->chars[i] = chars[i];
  220. }
  221. _r->chars[i++] = 0;
  222. _r->key = YAC_LOSTKEY;
  223. }
  224. else
  225. {
  226. _r->empty();
  227. }
  228. }
  229. #define MAX_FLOATARRAYALLOCSIZE (1024*1024*64)
  230. class PluginFloatArray : public YAC_FloatArray {
  231. public:
  232. sSI alloc (sSI _maxelements);
  233. };
  234. sSI PluginFloatArray::alloc(sSI _max_elements) {
  235. if(((sUI)_max_elements)>MAX_FLOATARRAYALLOCSIZE)
  236. {
  237. printf("[---] FloatArray::insane array size (maxelements=%08x)\n", _max_elements);
  238. return 0;
  239. }
  240. if(own_data)
  241. {
  242. if(elements)
  243. {
  244. delete [] elements;
  245. elements = NULL;
  246. }
  247. }
  248. if(_max_elements)
  249. {
  250. elements = new(std::nothrow) sF32[_max_elements];
  251. if(elements)
  252. {
  253. max_elements = _max_elements;
  254. num_elements = 0;
  255. own_data = 1;
  256. return 1;
  257. }
  258. }
  259. num_elements = 0;
  260. max_elements = 0;
  261. return 0;
  262. }
  263. /*
  264. * I find the naming a bit confusing so I decided to use more meaningful names instead.
  265. */
  266. /**
  267. * The VSTHostCallback is a function pointer so that the plugin can communicate with the host (not used in this small example)
  268. */
  269. typedef audioMasterCallback VSTHostCallback;
  270. /**
  271. * The VSTPlugin structure (AEffect) contains information about the plugin (like version, number of inputs, ...) and
  272. * callbacks so that the host can call the plugin to do its work. The primary callback will be `processReplacing` for
  273. * single precision (float) sample processing (or `processDoubleReplacing` for double precision (double)).
  274. */
  275. typedef AEffect VSTPlugin;
  276. void vst2_lock_midi_device() {
  277. }
  278. void vst2_unlock_midi_device() {
  279. }
  280. void vst2_handle_queued_set_program_chunk(void) {
  281. }
  282. void vst2_handle_ui_param(int uniqueParamId, float normValue) {
  283. }
  284. void vst2_get_timing_info(int *_retPlaying, float *_retBPM, float *_retSongPosPPQ) {
  285. }
  286. void vst2_maximize_reparented_window(void) {
  287. }
  288. // Since the host is expecting a very specific API we need to make sure it has C linkage (not C++)
  289. extern "C" {
  290. /*
  291. * This is the main entry point to the VST plugin.
  292. *
  293. * The host (DAW like Maschine, Ableton Live, Reason, ...) will look for this function with this exact API.
  294. *
  295. * It is the equivalent to `int main(int argc, char *argv[])` for a C executable.
  296. *
  297. * @param vstHostCallback is a callback so that the plugin can communicate with the host (not used in this small example)
  298. * @return a pointer to the AEffect structure
  299. */
  300. VST_EXPORT VSTPlugin *VSTPluginMain(VSTHostCallback vstHostCallback);
  301. // note this looks like this without the type aliases (and is obviously 100% equivalent)
  302. // extern AEffect *VSTPluginMain(audioMasterCallback audioMaster);
  303. }
  304. /*
  305. * Constant for the version of the plugin. For example 1100 for version 1.1.0.0
  306. */
  307. const VstInt32 PLUGIN_VERSION = 1000;
  308. /**
  309. * Encapsulates the plugin as a C++ class. It will keep both the host callback and the structure required by the
  310. * host (VSTPlugin). This class will be stored in the `VSTPlugin.object` field (circular reference) so that it can
  311. * be accessed when the host calls the plugin back (for example in `processDoubleReplacing`).
  312. */
  313. class VSTPluginWrapper
  314. {
  315. public:
  316. VSTPluginWrapper(VSTHostCallback vstHostCallback,
  317. VstInt32 vendorUniqueID,
  318. VstInt32 vendorVersion,
  319. VstInt32 numParams,
  320. VstInt32 numPrograms,
  321. VstInt32 numInputs,
  322. VstInt32 numOutputs);
  323. ~VSTPluginWrapper();
  324. inline VSTPlugin *getVSTPlugin()
  325. {
  326. return &_vstPlugin;
  327. }
  328. inline VstInt32 getNumInputs() const
  329. {
  330. return _vstPlugin.numInputs;
  331. }
  332. inline VstInt32 getNumOutputs() const
  333. {
  334. return _vstPlugin.numOutputs;
  335. }
  336. private:
  337. // the host callback (a function pointer)
  338. VSTHostCallback _vstHostCallback;
  339. // the actual structure required by the host
  340. VSTPlugin _vstPlugin;
  341. };
  342. /*******************************************
  343. * Callbacks: Host -> Plugin
  344. *
  345. * Defined here because they are used in the rest of the code later
  346. */
  347. /**
  348. * This is the callback that will be called to process the samples in the case of single precision. This is where the
  349. * meat of the logic happens!
  350. *
  351. * @param vstPlugin the object returned by VSTPluginMain
  352. * @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]
  353. * @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]
  354. * @param sampleFrames the number of samples (second dimension in both arrays)
  355. */
  356. void VSTPluginProcessSamplesFloat32(VSTPlugin *vstPlugin, float **inputs, float **outputs, VstInt32 sampleFrames)
  357. {
  358. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  359. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  360. // code speaks for itself: for each input (2 when stereo input), iterating over every sample and writing the
  361. // result in the outputs array after multiplying by 0.5 (which result in a 3dB attenuation of the sound)
  362. for(int i = 0; i < wrapper->getNumInputs(); i++)
  363. {
  364. auto inputSamples = inputs[i];
  365. auto outputSamples = outputs[i];
  366. for(int j = 0; j < sampleFrames; j++)
  367. {
  368. outputSamples[j] = inputSamples[j] * 0.5f;
  369. }
  370. }
  371. }
  372. /**
  373. * This is the callback that will be called to process the samples in the case of double precision. This is where the
  374. * meat of the logic happens!
  375. *
  376. * @param vstPlugin the object returned by VSTPluginMain
  377. * @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]
  378. * @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]
  379. * @param sampleFrames the number of samples (second dimension in both arrays)
  380. */
  381. void VSTPluginProcessSamplesFloat64(VSTPlugin *vstPlugin, double **inputs, double **outputs, VstInt32 sampleFrames)
  382. {
  383. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  384. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  385. // code speaks for itself: for each input (2 when stereo input), iterating over every sample and writing the
  386. // result in the outputs array after multiplying by 0.5 (which result in a 3dB attenuation of the sound)
  387. for(int i = 0; i < wrapper->getNumInputs(); i++)
  388. {
  389. auto inputSamples = inputs[i];
  390. auto outputSamples = outputs[i];
  391. for(int j = 0; j < sampleFrames; j++)
  392. {
  393. outputSamples[j] = inputSamples[j] * 0.5;
  394. }
  395. }
  396. }
  397. /**
  398. * This is the plugin called by the host to communicate with the plugin, mainly to request information (like the
  399. * vendor string, the plugin category...) or communicate state/changes (like open/close, frame rate...)
  400. *
  401. * @param vstPlugin the object returned by VSTPluginMain
  402. * @param opCode defined in aeffect.h/AEffectOpcodes and which continues in aeffectx.h/AEffectXOpcodes for a grand
  403. * total of 79 of them! Only a few of them are implemented in this small plugin.
  404. * @param index depend on the opcode
  405. * @param value depend on the opcode
  406. * @param ptr depend on the opcode
  407. * @param opt depend on the opcode
  408. * @return depend on the opcode (0 is ok when you don't implement an opcode...)
  409. */
  410. VstIntPtr VSTPluginDispatcher(VSTPlugin *vstPlugin, VstInt32 opCode, VstInt32 index, VstIntPtr value, void *ptr, float opt)
  411. {
  412. printf("called VSTPluginDispatcher(%d)\n", opCode);
  413. VstIntPtr v = 0;
  414. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  415. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  416. // see aeffect.h/AEffectOpcodes and aeffectx.h/AEffectXOpcodes for details on all of them
  417. switch(opCode)
  418. {
  419. // request for the category of the plugin: in this case it is an effect since it is modifying the input (as opposed
  420. // to generating sound)
  421. case effGetPlugCategory:
  422. return kPlugCategEffect;
  423. // called by the host when the plugin was called... time to reclaim memory!
  424. case effClose:
  425. delete wrapper;
  426. break;
  427. // request for the vendor string (usually used in the UI for plugin grouping)
  428. case effGetVendorString:
  429. strncpy(static_cast<char *>(ptr), "testsoft", kVstMaxVendorStrLen);
  430. v = 1;
  431. break;
  432. // request for the version
  433. case effGetVendorVersion:
  434. return PLUGIN_VERSION;
  435. // ignoring all other opcodes
  436. default:
  437. printf("Unknown opCode %d [ignored] \n", opCode);
  438. break;
  439. }
  440. return v;
  441. }
  442. /**
  443. * Used for parameter setting (not used by this plugin)
  444. */
  445. void VSTPluginSetParameter(VSTPlugin *vstPlugin, VstInt32 index, float parameter)
  446. {
  447. printf("called VSTPluginSetParameter(%d, %f)\n", index, parameter);
  448. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  449. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  450. }
  451. /**
  452. * Used for parameter (not used by this plugin)
  453. */
  454. float VSTPluginGetParameter(VSTPlugin *vstPlugin, VstInt32 index)
  455. {
  456. printf("called VSTPluginGetParameter(%d)\n", index);
  457. // we can get a hold to our C++ class since we stored it in the `object` field (see constructor)
  458. VSTPluginWrapper *wrapper = static_cast<VSTPluginWrapper *>(vstPlugin->object);
  459. return 0;
  460. }
  461. /**
  462. * Main constructor for our C++ class
  463. */
  464. VSTPluginWrapper::VSTPluginWrapper(audioMasterCallback vstHostCallback,
  465. VstInt32 vendorUniqueID,
  466. VstInt32 vendorVersion,
  467. VstInt32 numParams,
  468. VstInt32 numPrograms,
  469. VstInt32 numInputs,
  470. VstInt32 numOutputs) :
  471. _vstHostCallback(vstHostCallback)
  472. {
  473. // Make sure that the memory is properly initialized
  474. memset(&_vstPlugin, 0, sizeof(_vstPlugin));
  475. // this field must be set with this constant...
  476. _vstPlugin.magic = kEffectMagic;
  477. // storing this object into the VSTPlugin so that it can be retrieved when called back (see callbacks for use)
  478. _vstPlugin.object = this;
  479. // specifying that we handle both single and double precision (there are other flags see aeffect.h/VstAEffectFlags)
  480. _vstPlugin.flags = effFlagsCanReplacing | effFlagsCanDoubleReplacing;
  481. // initializing the plugin with the various values
  482. _vstPlugin.uniqueID = vendorUniqueID;
  483. _vstPlugin.version = vendorVersion;
  484. _vstPlugin.numParams = numParams;
  485. _vstPlugin.numPrograms = numPrograms;
  486. _vstPlugin.numInputs = numInputs;
  487. _vstPlugin.numOutputs = numOutputs;
  488. // setting the callbacks to the previously defined functions
  489. _vstPlugin.dispatcher = VSTPluginDispatcher;
  490. _vstPlugin.getParameter = VSTPluginGetParameter;
  491. _vstPlugin.setParameter = VSTPluginSetParameter;
  492. _vstPlugin.processReplacing = VSTPluginProcessSamplesFloat32;
  493. _vstPlugin.processDoubleReplacing = VSTPluginProcessSamplesFloat64;
  494. }
  495. /**
  496. * Destructor called when the plugin is closed (see VSTPluginDispatcher with effClose opCode). In this very simply plugin
  497. * there is nothing to do but in general the memory that gets allocated MUST be freed here otherwise there might be a
  498. * memory leak which may end up slowing down and/or crashing the host
  499. */
  500. VSTPluginWrapper::~VSTPluginWrapper()
  501. {
  502. }
  503. /**
  504. * Implementation of the main entry point of the plugin
  505. */
  506. VST_EXPORT VSTPlugin *VSTPluginMain(VSTHostCallback vstHostCallback)
  507. {
  508. printf("called VSTPluginMain... \n");
  509. // simply create our plugin C++ class
  510. VSTPluginWrapper *plugin =
  511. new VSTPluginWrapper(vstHostCallback,
  512. CCONST('u', 's', 'b', 'n'), // registered with Steinberg (http://service.steinberg.de/databases/plugin.nsf/plugIn?openForm)
  513. PLUGIN_VERSION, // version
  514. 0, // no params
  515. 0, // no programs
  516. 2, // 2 inputs
  517. 2); // 2 outputs
  518. // return the plugin per the contract of the API
  519. return plugin->getVSTPlugin();
  520. }