Audio plugin host https://kx.studio/carla
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.

752 lines
22KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #define CARLA_NATIVE_PLUGIN_LV2
  18. #include "carla-native-base.cpp"
  19. #include "CarlaMathUtils.hpp"
  20. #include "juce_core.h"
  21. #ifdef VESTIGE_HEADER
  22. # include "vestige/aeffectx.h"
  23. #define effFlagsProgramChunks (1 << 5)
  24. #define effGetParamLabel 6
  25. #define effGetChunk 23
  26. #define effSetChunk 24
  27. #define effGetPlugCategory 35
  28. #define kPlugCategEffect 1
  29. #define kPlugCategSynth 2
  30. #define kVstVersion 2400
  31. struct ERect {
  32. int16_t top, left, bottom, right;
  33. };
  34. #else
  35. # include "vst/aeffectx.h"
  36. #endif
  37. uint32_t d_lastBufferSize = 0;
  38. double d_lastSampleRate = 0.0;
  39. // -----------------------------------------------------------------------
  40. class NativePlugin
  41. {
  42. public:
  43. static const uint32_t kMaxMidiEvents = 512;
  44. NativePlugin(const audioMasterCallback audioMaster, AEffect* const effect, const NativePluginDescriptor* desc)
  45. : fAudioMaster(audioMaster),
  46. fEffect(effect),
  47. fHandle(nullptr),
  48. fHost(),
  49. fDescriptor(desc),
  50. fBufferSize(d_lastBufferSize),
  51. fSampleRate(d_lastSampleRate),
  52. fMidiEventCount(0),
  53. fTimeInfo(),
  54. fVstRect(),
  55. fStateChunk(nullptr),
  56. leakDetector_NativePlugin()
  57. {
  58. fHost.handle = this;
  59. fHost.uiName = carla_strdup("CarlaVST");
  60. fHost.uiParentId = 0;
  61. // find resource dir
  62. using juce::File;
  63. File curExe = File::getSpecialLocation(File::currentExecutableFile).getLinkedTarget();
  64. File resDir = curExe.getSiblingFile("carla-resources");
  65. if (! resDir.exists())
  66. resDir = curExe.getSiblingFile("resources");
  67. if (! resDir.exists())
  68. resDir = File("/usr/share/carla/resources/");
  69. fHost.resourceDir = carla_strdup(resDir.getFullPathName().toRawUTF8());
  70. fHost.get_buffer_size = host_get_buffer_size;
  71. fHost.get_sample_rate = host_get_sample_rate;
  72. fHost.is_offline = host_is_offline;
  73. fHost.get_time_info = host_get_time_info;
  74. fHost.write_midi_event = host_write_midi_event;
  75. fHost.ui_parameter_changed = host_ui_parameter_changed;
  76. fHost.ui_custom_data_changed = host_ui_custom_data_changed;
  77. fHost.ui_closed = host_ui_closed;
  78. fHost.ui_open_file = host_ui_open_file;
  79. fHost.ui_save_file = host_ui_save_file;
  80. fHost.dispatcher = host_dispatcher;
  81. fVstRect.top = 0;
  82. fVstRect.left = 0;
  83. fVstRect.bottom = 512;
  84. fVstRect.right = 740;
  85. init();
  86. }
  87. ~NativePlugin()
  88. {
  89. if (fDescriptor->cleanup != nullptr && fHandle != nullptr)
  90. fDescriptor->cleanup(fHandle);
  91. fHandle = nullptr;
  92. if (fStateChunk != nullptr)
  93. {
  94. std::free(fStateChunk);
  95. fStateChunk = nullptr;
  96. }
  97. if (fHost.uiName != nullptr)
  98. {
  99. delete[] fHost.uiName;
  100. fHost.uiName = nullptr;
  101. }
  102. if (fHost.resourceDir != nullptr)
  103. {
  104. delete[] fHost.resourceDir;
  105. fHost.resourceDir = nullptr;
  106. }
  107. }
  108. bool init()
  109. {
  110. if (fDescriptor->instantiate == nullptr || fDescriptor->process == nullptr)
  111. {
  112. carla_stderr("Plugin is missing something...");
  113. return false;
  114. }
  115. fHandle = fDescriptor->instantiate(&fHost);
  116. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
  117. carla_zeroStruct<NativeMidiEvent>(fMidiEvents, kMaxMidiEvents);
  118. carla_zeroStruct<NativeTimeInfo>(fTimeInfo);
  119. return true;
  120. }
  121. // -------------------------------------------------------------------
  122. intptr_t vst_dispatcher(const int32_t opcode, const int32_t /*index*/, const intptr_t value, void* const ptr, const float opt)
  123. {
  124. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, 0);
  125. intptr_t ret = 0;
  126. switch (opcode)
  127. {
  128. case effSetSampleRate:
  129. if (carla_compareFloats(fSampleRate, static_cast<double>(opt)))
  130. return 0;
  131. fSampleRate = opt;
  132. if (fDescriptor->dispatcher != nullptr)
  133. fDescriptor->dispatcher(fHandle, PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, (float)fSampleRate);
  134. break;
  135. case effSetBlockSize:
  136. if (fBufferSize == static_cast<uint32_t>(value))
  137. return 0;
  138. fBufferSize = static_cast<uint32_t>(value);
  139. if (fDescriptor->dispatcher != nullptr)
  140. fDescriptor->dispatcher(fHandle, PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, fBufferSize, nullptr, 0.0f);
  141. break;
  142. case effMainsChanged:
  143. if (value != 0)
  144. {
  145. if (fDescriptor->activate != nullptr)
  146. fDescriptor->activate(fHandle);
  147. fMidiEventCount = 0;
  148. carla_zeroStruct<NativeMidiEvent>(fMidiEvents, kMaxMidiEvents);
  149. carla_zeroStruct<NativeTimeInfo>(fTimeInfo);
  150. }
  151. else
  152. {
  153. if (fDescriptor->deactivate != nullptr)
  154. fDescriptor->deactivate(fHandle);
  155. }
  156. break;
  157. case effEditGetRect:
  158. *(ERect**)ptr = &fVstRect;
  159. ret = 1;
  160. break;
  161. case effEditOpen:
  162. if (fDescriptor->ui_show != nullptr)
  163. {
  164. char strBuf[0xff+1];
  165. strBuf[0xff] = '\0';
  166. std::snprintf(strBuf, 0xff, P_INTPTR, (intptr_t)ptr);
  167. carla_setenv("CARLA_PLUGIN_EMBED_WINID", strBuf);
  168. fDescriptor->ui_show(fHandle, true);
  169. carla_setenv("CARLA_PLUGIN_EMBED_WINID", "0");
  170. ret = 1;
  171. }
  172. break;
  173. case effEditClose:
  174. if (fDescriptor->ui_show != nullptr)
  175. {
  176. fDescriptor->ui_show(fHandle, false);
  177. ret = 1;
  178. }
  179. break;
  180. case effEditIdle:
  181. if (fDescriptor->ui_idle != nullptr)
  182. fDescriptor->ui_idle(fHandle);
  183. break;
  184. case effGetChunk:
  185. if (ptr == nullptr || fDescriptor->get_state == nullptr)
  186. return 0;
  187. if (fStateChunk != nullptr)
  188. std::free(fStateChunk);
  189. fStateChunk = fDescriptor->get_state(fHandle);
  190. if (fStateChunk == nullptr)
  191. return 0;
  192. ret = static_cast<intptr_t>(std::strlen(fStateChunk)+1);
  193. *(void**)ptr = fStateChunk;
  194. break;
  195. case effSetChunk:
  196. if (value <= 0 || fDescriptor->set_state == nullptr)
  197. return 0;
  198. if (value == 1)
  199. return 1;
  200. if (const char* const state = (const char*)ptr)
  201. {
  202. fDescriptor->set_state(fHandle, state);
  203. ret = 1;
  204. }
  205. break;
  206. case effProcessEvents:
  207. if (const VstEvents* const events = (const VstEvents*)ptr)
  208. {
  209. if (events->numEvents == 0)
  210. break;
  211. for (int i=0, count=events->numEvents; i < count; ++i)
  212. {
  213. const VstMidiEvent* const vstMidiEvent((const VstMidiEvent*)events->events[i]);
  214. if (vstMidiEvent == nullptr)
  215. break;
  216. if (vstMidiEvent->type != kVstMidiType || vstMidiEvent->deltaFrames < 0)
  217. continue;
  218. if (fMidiEventCount >= kMaxMidiEvents)
  219. break;
  220. fMidiEvents[fMidiEventCount].port = 0;
  221. fMidiEvents[fMidiEventCount].time = static_cast<uint32_t>(vstMidiEvent->deltaFrames);
  222. fMidiEvents[fMidiEventCount].size = 3;
  223. for (uint32_t j=0; j < 3; ++j)
  224. fMidiEvents[fMidiEventCount].data[i] = static_cast<uint8_t>(vstMidiEvent->midiData[i]);
  225. fMidiEventCount += 1;
  226. }
  227. }
  228. break;
  229. case effCanDo:
  230. if (const char* const canDo = (const char*)ptr)
  231. {
  232. if (std::strcmp(canDo, "receiveVstEvents") == 0)
  233. return 1;
  234. if (std::strcmp(canDo, "receiveVstMidiEvent") == 0)
  235. return 1;
  236. if (std::strcmp(canDo, "receiveVstTimeInfo") == 0)
  237. return 1;
  238. }
  239. break;
  240. }
  241. return ret;
  242. }
  243. float vst_getParameter(const int32_t /*index*/)
  244. {
  245. return 0.0f;
  246. }
  247. void vst_setParameter(const int32_t /*index*/, const float /*value*/)
  248. {
  249. }
  250. void vst_processReplacing(const float** const inputs, float** const outputs, const int32_t sampleFrames)
  251. {
  252. if (sampleFrames <= 0)
  253. return;
  254. static const int kWantVstTimeFlags(kVstTransportPlaying|kVstPpqPosValid|kVstTempoValid|kVstBarsValid|kVstTimeSigValid);
  255. if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)fAudioMaster(fEffect, audioMasterGetTime, 0, kWantVstTimeFlags, nullptr, 0.0f))
  256. {
  257. fTimeInfo.frame = static_cast<uint64_t>(vstTimeInfo->samplePos);
  258. fTimeInfo.playing = (vstTimeInfo->flags & kVstTransportPlaying);
  259. fTimeInfo.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0);
  260. // ticksPerBeat is not possible with VST
  261. fTimeInfo.bbt.ticksPerBeat = 960.0;
  262. if (vstTimeInfo->flags & kVstTempoValid)
  263. fTimeInfo.bbt.beatsPerMinute = vstTimeInfo->tempo;
  264. else
  265. fTimeInfo.bbt.beatsPerMinute = 120.0;
  266. if (vstTimeInfo->flags & kVstTimeSigValid)
  267. {
  268. fTimeInfo.bbt.beatsPerBar = static_cast<float>(vstTimeInfo->timeSigNumerator);
  269. fTimeInfo.bbt.beatType = static_cast<float>(vstTimeInfo->timeSigDenominator);
  270. }
  271. else
  272. {
  273. fTimeInfo.bbt.beatsPerBar = 4.0f;
  274. fTimeInfo.bbt.beatType = 4.0f;
  275. }
  276. if (vstTimeInfo->flags & kVstPpqPosValid)
  277. {
  278. const int ppqPerBar = vstTimeInfo->timeSigNumerator * 4 / vstTimeInfo->timeSigDenominator;
  279. const double barBeats = (std::fmod(vstTimeInfo->ppqPos, ppqPerBar) / ppqPerBar) * vstTimeInfo->timeSigDenominator;
  280. const double rest = std::fmod(barBeats, 1.0);
  281. fTimeInfo.bbt.bar = static_cast<int32_t>(vstTimeInfo->ppqPos)/ppqPerBar + 1;
  282. fTimeInfo.bbt.beat = static_cast<int32_t>(barBeats-rest+1.0);
  283. fTimeInfo.bbt.tick = static_cast<int32_t>(rest*fTimeInfo.bbt.ticksPerBeat+0.5);
  284. }
  285. else
  286. {
  287. fTimeInfo.bbt.bar = 1;
  288. fTimeInfo.bbt.beat = 1;
  289. fTimeInfo.bbt.tick = 0;
  290. }
  291. fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat*fTimeInfo.bbt.beatsPerBar*(fTimeInfo.bbt.bar-1);
  292. }
  293. if (fHandle != nullptr)
  294. fDescriptor->process(fHandle, const_cast<float**>(inputs), outputs, static_cast<uint32_t>(sampleFrames), fMidiEvents, fMidiEventCount);
  295. fMidiEventCount = 0;
  296. }
  297. protected:
  298. // -------------------------------------------------------------------
  299. uint32_t handleGetBufferSize() const
  300. {
  301. return fBufferSize;
  302. }
  303. double handleGetSampleRate() const
  304. {
  305. return fSampleRate;
  306. }
  307. bool handleIsOffline() const
  308. {
  309. return false;
  310. }
  311. const NativeTimeInfo* handleGetTimeInfo() const
  312. {
  313. return &fTimeInfo;
  314. }
  315. bool handleWriteMidiEvent(const NativeMidiEvent* const event)
  316. {
  317. CARLA_SAFE_ASSERT_RETURN(fDescriptor->midiOuts > 0, false);
  318. CARLA_SAFE_ASSERT_RETURN(event != nullptr, false);
  319. CARLA_SAFE_ASSERT_RETURN(event->data[0] != 0, false);
  320. // reverse-find first free event, and put it there
  321. for (uint32_t i=(kMaxMidiEvents*2)-1; i > fMidiEventCount; --i)
  322. {
  323. if (fMidiEvents[i].data[0] == 0)
  324. {
  325. std::memcpy(&fMidiEvents[i], event, sizeof(NativeMidiEvent));
  326. return true;
  327. }
  328. }
  329. return false;
  330. }
  331. void handleUiParameterChanged(const uint32_t /*index*/, const float /*value*/) const
  332. {
  333. }
  334. void handleUiCustomDataChanged(const char* const /*key*/, const char* const /*value*/) const
  335. {
  336. }
  337. void handleUiClosed()
  338. {
  339. }
  340. const char* handleUiOpenFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const
  341. {
  342. // TODO
  343. return nullptr;
  344. }
  345. const char* handleUiSaveFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const
  346. {
  347. // TODO
  348. return nullptr;
  349. }
  350. intptr_t handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
  351. {
  352. carla_debug("NativePlugin::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)", opcode, index, value, ptr, opt);
  353. return 0;
  354. // unused for now
  355. (void)opcode; (void)index; (void)value; (void)ptr; (void)opt;
  356. }
  357. private:
  358. // VST stuff
  359. const audioMasterCallback fAudioMaster;
  360. AEffect* const fEffect;
  361. // Native data
  362. NativePluginHandle fHandle;
  363. NativeHostDescriptor fHost;
  364. const NativePluginDescriptor* const fDescriptor;
  365. // VST host data
  366. uint32_t fBufferSize;
  367. double fSampleRate;
  368. // Temporary data
  369. uint32_t fMidiEventCount;
  370. NativeMidiEvent fMidiEvents[kMaxMidiEvents];
  371. NativeTimeInfo fTimeInfo;
  372. ERect fVstRect;
  373. char* fStateChunk;
  374. // -------------------------------------------------------------------
  375. #define handlePtr ((NativePlugin*)handle)
  376. static uint32_t host_get_buffer_size(NativeHostHandle handle)
  377. {
  378. return handlePtr->handleGetBufferSize();
  379. }
  380. static double host_get_sample_rate(NativeHostHandle handle)
  381. {
  382. return handlePtr->handleGetSampleRate();
  383. }
  384. static bool host_is_offline(NativeHostHandle handle)
  385. {
  386. return handlePtr->handleIsOffline();
  387. }
  388. static const NativeTimeInfo* host_get_time_info(NativeHostHandle handle)
  389. {
  390. return handlePtr->handleGetTimeInfo();
  391. }
  392. static bool host_write_midi_event(NativeHostHandle handle, const NativeMidiEvent* event)
  393. {
  394. return handlePtr->handleWriteMidiEvent(event);
  395. }
  396. static void host_ui_parameter_changed(NativeHostHandle handle, uint32_t index, float value)
  397. {
  398. handlePtr->handleUiParameterChanged(index, value);
  399. }
  400. static void host_ui_custom_data_changed(NativeHostHandle handle, const char* key, const char* value)
  401. {
  402. handlePtr->handleUiCustomDataChanged(key, value);
  403. }
  404. static void host_ui_closed(NativeHostHandle handle)
  405. {
  406. handlePtr->handleUiClosed();
  407. }
  408. static const char* host_ui_open_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
  409. {
  410. return handlePtr->handleUiOpenFile(isDir, title, filter);
  411. }
  412. static const char* host_ui_save_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
  413. {
  414. return handlePtr->handleUiSaveFile(isDir, title, filter);
  415. }
  416. static intptr_t host_dispatcher(NativeHostHandle handle, NativeHostDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt)
  417. {
  418. return handlePtr->handleDispatcher(opcode, index, value, ptr, opt);
  419. }
  420. #undef handlePtr
  421. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativePlugin)
  422. };
  423. // -----------------------------------------------------------------------
  424. #ifdef VESTIGE_HEADER
  425. # define handlePtr ((NativePlugin*)effect->ptr2)
  426. # define validEffect effect != nullptr && effect->ptr2 != nullptr
  427. #else
  428. # define handlePtr ((NativePlugin*)effect->resvd2)
  429. # define validEffect effect != nullptr && effect->resvd2 != 0
  430. #endif
  431. static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
  432. {
  433. // handle base opcodes
  434. switch (opcode)
  435. {
  436. case effOpen:
  437. #ifdef VESTIGE_HEADER
  438. if (effect != nullptr && effect->ptr3 != nullptr)
  439. {
  440. audioMasterCallback audioMaster = (audioMasterCallback)effect->ptr3;
  441. #else
  442. if (effect != nullptr && effect->object != nullptr)
  443. {
  444. audioMasterCallback audioMaster = (audioMasterCallback)effect->object;
  445. #endif
  446. d_lastBufferSize = static_cast<uint32_t>(audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f));
  447. d_lastSampleRate = static_cast<double>(audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f));
  448. // some hosts are not ready at this point or return 0 buffersize/samplerate
  449. if (d_lastBufferSize == 0)
  450. d_lastBufferSize = 2048;
  451. if (d_lastSampleRate <= 0.0)
  452. d_lastSampleRate = 44100.0;
  453. const NativePluginDescriptor* pluginDesc = nullptr;
  454. #ifdef CARLA_PLUGIN_PATCHBAY
  455. const char* const pluginLabel = "carlapatchbay";
  456. #else
  457. const char* const pluginLabel = "carlarack";
  458. #endif
  459. PluginListManager& plm(PluginListManager::getInstance());
  460. for (LinkedList<const NativePluginDescriptor*>::Itenerator it = plm.descs.begin(); it.valid(); it.next())
  461. {
  462. const NativePluginDescriptor* const& tmpDesc(it.getValue());
  463. if (std::strcmp(tmpDesc->label, pluginLabel) == 0)
  464. {
  465. pluginDesc = tmpDesc;
  466. break;
  467. }
  468. }
  469. CARLA_SAFE_ASSERT_RETURN(pluginDesc != nullptr, 0);
  470. NativePlugin* const plugin(new NativePlugin(audioMaster, effect, pluginDesc));
  471. #ifdef VESTIGE_HEADER
  472. effect->ptr2 = plugin;
  473. #else
  474. effect->resvd2 = (intptr_t)plugin;
  475. #endif
  476. return 1;
  477. }
  478. return 0;
  479. case effClose:
  480. if (validEffect)
  481. {
  482. #ifdef VESTIGE_HEADER
  483. delete (NativePlugin*)effect->ptr2;
  484. effect->ptr2 = nullptr;
  485. effect->ptr3 = nullptr;
  486. #else
  487. delete (NativePlugin*)effect->resvd2;
  488. effect->resvd2 = 0;
  489. effect->object = nullptr;
  490. #endif
  491. delete effect;
  492. return 1;
  493. }
  494. return 0;
  495. case effGetPlugCategory:
  496. #ifdef CARLA_PLUGIN_SYNTH
  497. return kPlugCategSynth;
  498. #else
  499. return kPlugCategEffect;
  500. #endif
  501. case effGetEffectName:
  502. if (ptr != nullptr)
  503. {
  504. #ifdef CARLA_PLUGIN_PATCHBAY
  505. std::strncpy((char*)ptr, "Carla-Patchbay", 64);
  506. #else
  507. std::strncpy((char*)ptr, "Carla-Rack", 64);
  508. #endif
  509. return 1;
  510. }
  511. return 0;
  512. case effGetVendorString:
  513. if (ptr != nullptr)
  514. {
  515. std::strncpy((char*)ptr, "falkTX", 64);
  516. return 1;
  517. }
  518. return 0;
  519. case effGetProductString:
  520. if (ptr != nullptr)
  521. {
  522. #ifdef CARLA_PLUGIN_PATCHBAY
  523. std::strncpy((char*)ptr, "CarlaPatchbay", 32);
  524. #else
  525. std::strncpy((char*)ptr, "CarlaRack", 32);
  526. #endif
  527. return 1;
  528. }
  529. return 0;
  530. case effGetVendorVersion:
  531. return CARLA_VERSION_HEX;
  532. case effGetVstVersion:
  533. return kVstVersion;
  534. };
  535. // handle advanced opcodes
  536. if (validEffect)
  537. return handlePtr->vst_dispatcher(opcode, index, value, ptr, opt);
  538. return 0;
  539. }
  540. static float vst_getParameterCallback(AEffect* effect, int32_t index)
  541. {
  542. if (validEffect)
  543. return handlePtr->vst_getParameter(index);
  544. return 0.0f;
  545. }
  546. static void vst_setParameterCallback(AEffect* effect, int32_t index, float value)
  547. {
  548. if (validEffect)
  549. handlePtr->vst_setParameter(index, value);
  550. }
  551. static void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
  552. {
  553. if (validEffect)
  554. handlePtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames);
  555. }
  556. static void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
  557. {
  558. if (validEffect)
  559. handlePtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames);
  560. }
  561. #undef handlePtr
  562. // -----------------------------------------------------------------------
  563. CARLA_EXPORT
  564. #ifdef CARLA_OS_WIN
  565. const AEffect* VSTPluginMain(audioMasterCallback audioMaster);
  566. #else
  567. const AEffect* VSTPluginMain(audioMasterCallback audioMaster) asm ("main");
  568. #endif
  569. CARLA_EXPORT
  570. const AEffect* VSTPluginMain(audioMasterCallback audioMaster)
  571. {
  572. // old version
  573. if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0)
  574. return nullptr;
  575. AEffect* const effect(new AEffect);
  576. std::memset(effect, 0, sizeof(AEffect));
  577. // vst fields
  578. effect->magic = kEffectMagic;
  579. effect->uniqueID = CCONST('C', 'r', 'l', 'a');
  580. #ifdef VESTIGE_HEADER
  581. int32_t* const version = (int32_t*)&effect->unknown1;
  582. *version = CARLA_VERSION_HEX;
  583. #else
  584. effect->version = CARLA_VERSION_HEX;
  585. #endif
  586. // plugin fields
  587. effect->numParams = 0;
  588. effect->numPrograms = 0;
  589. effect->numInputs = 2;
  590. effect->numOutputs = 2;
  591. // plugin flags
  592. effect->flags |= effFlagsCanReplacing;
  593. effect->flags |= effFlagsHasEditor;
  594. effect->flags |= effFlagsProgramChunks;
  595. #ifdef CARLA_PLUGIN_SYNTH
  596. effect->flags |= effFlagsIsSynth;
  597. #endif
  598. // static calls
  599. effect->dispatcher = vst_dispatcherCallback;
  600. effect->process = vst_processCallback;
  601. effect->getParameter = vst_getParameterCallback;
  602. effect->setParameter = vst_setParameterCallback;
  603. effect->processReplacing = vst_processReplacingCallback;
  604. // pointers
  605. #ifdef VESTIGE_HEADER
  606. effect->ptr3 = (void*)audioMaster;
  607. #else
  608. effect->object = (void*)audioMaster;
  609. #endif
  610. return effect;
  611. }
  612. // -----------------------------------------------------------------------