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.

carla-vst.cpp 27KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  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. #ifndef CARLA_PLUGIN_PATCHBAY
  18. # error CARLA_PLUGIN_PATCHBAY undefined
  19. #endif
  20. #ifndef CARLA_PLUGIN_SYNTH
  21. # error CARLA_PLUGIN_SYNTH undefined
  22. #endif
  23. #define CARLA_NATIVE_PLUGIN_VST
  24. #include "carla-base.cpp"
  25. #include "CarlaMathUtils.hpp"
  26. #include "juce_core.h"
  27. #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)
  28. # include "juce_gui_basics.h"
  29. #else
  30. namespace juce {
  31. # include "juce_events/messages/juce_Initialisation.h"
  32. } // namespace juce
  33. #endif
  34. #ifdef VESTIGE_HEADER
  35. # include "vestige/aeffectx.h"
  36. #define effFlagsProgramChunks (1 << 5)
  37. #define effGetParamLabel 6
  38. #define effGetChunk 23
  39. #define effSetChunk 24
  40. #define effGetPlugCategory 35
  41. #define kPlugCategEffect 1
  42. #define kPlugCategSynth 2
  43. #define kVstVersion 2400
  44. struct ERect {
  45. int16_t top, left, bottom, right;
  46. };
  47. #else
  48. # include "vst2/aeffectx.h"
  49. #endif
  50. using juce::ScopedJuceInitialiser_GUI;
  51. using juce::SharedResourcePointer;
  52. static uint32_t d_lastBufferSize = 0;
  53. static double d_lastSampleRate = 0.0;
  54. static const int32_t kVstMidiEventSize = static_cast<int32_t>(sizeof(VstMidiEvent));
  55. // -----------------------------------------------------------------------
  56. class NativePlugin
  57. {
  58. public:
  59. static const uint32_t kMaxMidiEvents = 512;
  60. NativePlugin(const audioMasterCallback audioMaster, AEffect* const effect, const NativePluginDescriptor* desc)
  61. : fAudioMaster(audioMaster),
  62. fEffect(effect),
  63. fHandle(nullptr),
  64. fHost(),
  65. fDescriptor(desc),
  66. fBufferSize(d_lastBufferSize),
  67. fSampleRate(d_lastSampleRate),
  68. fIsActive(false),
  69. fMidiEventCount(0),
  70. fTimeInfo(),
  71. fVstRect(),
  72. fMidiOutEvents(),
  73. fStateChunk(nullptr),
  74. sJuceInitialiser(),
  75. leakDetector_NativePlugin()
  76. {
  77. fHost.handle = this;
  78. fHost.uiName = carla_strdup("CarlaVST");
  79. fHost.uiParentId = 0;
  80. // find resource dir
  81. using juce::File;
  82. File curExe = File::getSpecialLocation(File::currentExecutableFile).getLinkedTarget();
  83. File resDir = curExe.getSiblingFile("carla-resources");
  84. if (! resDir.exists())
  85. resDir = curExe.getSiblingFile("resources");
  86. if (! resDir.exists())
  87. resDir = File("/usr/share/carla/resources/");
  88. fHost.resourceDir = carla_strdup(resDir.getFullPathName().toRawUTF8());
  89. fHost.get_buffer_size = host_get_buffer_size;
  90. fHost.get_sample_rate = host_get_sample_rate;
  91. fHost.is_offline = host_is_offline;
  92. fHost.get_time_info = host_get_time_info;
  93. fHost.write_midi_event = host_write_midi_event;
  94. fHost.ui_parameter_changed = host_ui_parameter_changed;
  95. fHost.ui_custom_data_changed = host_ui_custom_data_changed;
  96. fHost.ui_closed = host_ui_closed;
  97. fHost.ui_open_file = host_ui_open_file;
  98. fHost.ui_save_file = host_ui_save_file;
  99. fHost.dispatcher = host_dispatcher;
  100. fVstRect.top = 0;
  101. fVstRect.left = 0;
  102. fVstRect.bottom = 512;
  103. fVstRect.right = 740;
  104. init();
  105. }
  106. ~NativePlugin()
  107. {
  108. if (fIsActive)
  109. {
  110. // host has not de-activated the plugin yet, nasty!
  111. fIsActive = false;
  112. if (fDescriptor->deactivate != nullptr)
  113. fDescriptor->deactivate(fHandle);
  114. }
  115. if (fDescriptor->cleanup != nullptr && fHandle != nullptr)
  116. fDescriptor->cleanup(fHandle);
  117. fHandle = nullptr;
  118. if (fStateChunk != nullptr)
  119. {
  120. std::free(fStateChunk);
  121. fStateChunk = nullptr;
  122. }
  123. if (fHost.uiName != nullptr)
  124. {
  125. delete[] fHost.uiName;
  126. fHost.uiName = nullptr;
  127. }
  128. if (fHost.resourceDir != nullptr)
  129. {
  130. delete[] fHost.resourceDir;
  131. fHost.resourceDir = nullptr;
  132. }
  133. }
  134. bool init()
  135. {
  136. if (fDescriptor->instantiate == nullptr || fDescriptor->process == nullptr)
  137. {
  138. carla_stderr("Plugin is missing something...");
  139. return false;
  140. }
  141. fHandle = fDescriptor->instantiate(&fHost);
  142. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
  143. carla_zeroStruct<NativeMidiEvent>(fMidiEvents, kMaxMidiEvents);
  144. carla_zeroStruct<NativeTimeInfo>(fTimeInfo);
  145. return true;
  146. }
  147. // -------------------------------------------------------------------
  148. intptr_t vst_dispatcher(const int32_t opcode, const int32_t /*index*/, const intptr_t value, void* const ptr, const float opt)
  149. {
  150. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, 0);
  151. intptr_t ret = 0;
  152. switch (opcode)
  153. {
  154. case effSetSampleRate:
  155. if (carla_compareFloats(fSampleRate, static_cast<double>(opt)))
  156. return 0;
  157. fSampleRate = opt;
  158. if (fDescriptor->dispatcher != nullptr)
  159. fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, (float)fSampleRate);
  160. break;
  161. case effSetBlockSize:
  162. if (fBufferSize == static_cast<uint32_t>(value))
  163. return 0;
  164. fBufferSize = static_cast<uint32_t>(value);
  165. if (fDescriptor->dispatcher != nullptr)
  166. fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, value, nullptr, 0.0f);
  167. break;
  168. case effMainsChanged:
  169. if (value != 0)
  170. {
  171. fMidiEventCount = 0;
  172. carla_zeroStruct<NativeTimeInfo>(fTimeInfo);
  173. // tell host we want MIDI events
  174. fAudioMaster(fEffect, audioMasterWantMidi, 0, 0, nullptr, 0.0f);
  175. CARLA_SAFE_ASSERT_BREAK(! fIsActive);
  176. if (fDescriptor->activate != nullptr)
  177. fDescriptor->activate(fHandle);
  178. fIsActive = true;
  179. }
  180. else
  181. {
  182. CARLA_SAFE_ASSERT_BREAK(fIsActive);
  183. if (fDescriptor->deactivate != nullptr)
  184. fDescriptor->deactivate(fHandle);
  185. fIsActive = false;
  186. }
  187. break;
  188. case effEditGetRect:
  189. *(ERect**)ptr = &fVstRect;
  190. ret = 1;
  191. break;
  192. case effEditOpen:
  193. if (fDescriptor->ui_show != nullptr)
  194. {
  195. char strBuf[0xff+1];
  196. strBuf[0xff] = '\0';
  197. std::snprintf(strBuf, 0xff, P_INTPTR, (intptr_t)ptr);
  198. carla_setenv("CARLA_PLUGIN_EMBED_WINID", strBuf);
  199. fDescriptor->ui_show(fHandle, true);
  200. carla_setenv("CARLA_PLUGIN_EMBED_WINID", "0");
  201. carla_zeroChar(strBuf, 0xff+1);
  202. fAudioMaster(fEffect, audioMasterGetProductString, 0, 0, strBuf, 0);
  203. if (std::strcmp(strBuf, "Tracktion") == 0)
  204. {
  205. carla_stdout("Tracktion detected, delaying UI appearance so it works properly...");
  206. for (int x=10; --x>=0;)
  207. {
  208. fAudioMaster(fEffect, audioMasterIdle, 0, 0, nullptr, 0);
  209. carla_msleep(25);
  210. }
  211. }
  212. ret = 1;
  213. }
  214. break;
  215. case effEditClose:
  216. if (fDescriptor->ui_show != nullptr)
  217. {
  218. fDescriptor->ui_show(fHandle, false);
  219. ret = 1;
  220. }
  221. break;
  222. case effEditIdle:
  223. if (fDescriptor->ui_idle != nullptr)
  224. fDescriptor->ui_idle(fHandle);
  225. break;
  226. case effGetChunk:
  227. if (ptr == nullptr || fDescriptor->get_state == nullptr)
  228. return 0;
  229. if (fStateChunk != nullptr)
  230. std::free(fStateChunk);
  231. fStateChunk = fDescriptor->get_state(fHandle);
  232. if (fStateChunk == nullptr)
  233. return 0;
  234. ret = static_cast<intptr_t>(std::strlen(fStateChunk)+1);
  235. *(void**)ptr = fStateChunk;
  236. break;
  237. case effSetChunk:
  238. if (value <= 0 || fDescriptor->set_state == nullptr)
  239. return 0;
  240. if (value == 1)
  241. return 1;
  242. if (const char* const state = (const char*)ptr)
  243. {
  244. fDescriptor->set_state(fHandle, state);
  245. ret = 1;
  246. }
  247. break;
  248. case effProcessEvents:
  249. if (! fIsActive)
  250. {
  251. // host has not activated the plugin yet, nasty!
  252. vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f);
  253. fIsActive = true;
  254. }
  255. if (const VstEvents* const events = (const VstEvents*)ptr)
  256. {
  257. if (events->numEvents == 0)
  258. break;
  259. for (int i=0, count=events->numEvents; i < count; ++i)
  260. {
  261. const VstMidiEvent* const vstMidiEvent((const VstMidiEvent*)events->events[i]);
  262. if (vstMidiEvent == nullptr)
  263. break;
  264. if (vstMidiEvent->type != kVstMidiType || vstMidiEvent->deltaFrames < 0)
  265. continue;
  266. if (fMidiEventCount >= kMaxMidiEvents)
  267. break;
  268. const uint32_t j(fMidiEventCount++);
  269. fMidiEvents[j].port = 0;
  270. fMidiEvents[j].time = static_cast<uint32_t>(vstMidiEvent->deltaFrames);
  271. fMidiEvents[j].size = 3;
  272. for (uint32_t k=0; k<3; ++k)
  273. fMidiEvents[j].data[k] = static_cast<uint8_t>(vstMidiEvent->midiData[k]);
  274. }
  275. }
  276. break;
  277. case effCanDo:
  278. if (const char* const canDo = (const char*)ptr)
  279. {
  280. if (std::strcmp(canDo, "receiveVstEvents") == 0)
  281. return 1;
  282. if (std::strcmp(canDo, "receiveVstMidiEvent") == 0)
  283. return 1;
  284. if (std::strcmp(canDo, "receiveVstTimeInfo") == 0)
  285. return 1;
  286. if (std::strcmp(canDo, "sendVstEvents") == 0)
  287. return 1;
  288. if (std::strcmp(canDo, "sendVstMidiEvent") == 0)
  289. return 1;
  290. }
  291. break;
  292. }
  293. return ret;
  294. }
  295. float vst_getParameter(const int32_t /*index*/)
  296. {
  297. return 0.0f;
  298. }
  299. void vst_setParameter(const int32_t /*index*/, const float /*value*/)
  300. {
  301. }
  302. void vst_processReplacing(const float** const inputs, float** const outputs, const int32_t sampleFrames)
  303. {
  304. if (sampleFrames <= 0)
  305. return;
  306. if (! fIsActive)
  307. {
  308. // host has not activated the plugin yet, nasty!
  309. vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f);
  310. fIsActive = true;
  311. }
  312. static const int kWantVstTimeFlags(kVstTransportPlaying|kVstPpqPosValid|kVstTempoValid|kVstTimeSigValid);
  313. if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)fAudioMaster(fEffect, audioMasterGetTime, 0, kWantVstTimeFlags, nullptr, 0.0f))
  314. {
  315. fTimeInfo.frame = static_cast<uint64_t>(vstTimeInfo->samplePos);
  316. fTimeInfo.playing = (vstTimeInfo->flags & kVstTransportPlaying);
  317. fTimeInfo.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0);
  318. // ticksPerBeat is not possible with VST
  319. fTimeInfo.bbt.ticksPerBeat = 960.0;
  320. if (vstTimeInfo->flags & kVstTempoValid)
  321. fTimeInfo.bbt.beatsPerMinute = vstTimeInfo->tempo;
  322. else
  323. fTimeInfo.bbt.beatsPerMinute = 120.0;
  324. if (vstTimeInfo->flags & (kVstPpqPosValid|kVstTimeSigValid))
  325. {
  326. const int ppqPerBar = vstTimeInfo->timeSigNumerator * 4 / vstTimeInfo->timeSigDenominator;
  327. const double barBeats = (std::fmod(vstTimeInfo->ppqPos, ppqPerBar) / ppqPerBar) * vstTimeInfo->timeSigDenominator;
  328. const double rest = std::fmod(barBeats, 1.0);
  329. fTimeInfo.bbt.bar = static_cast<int32_t>(vstTimeInfo->ppqPos)/ppqPerBar + 1;
  330. fTimeInfo.bbt.beat = static_cast<int32_t>(barBeats-rest+1.0);
  331. fTimeInfo.bbt.tick = static_cast<int32_t>(rest*fTimeInfo.bbt.ticksPerBeat+0.5);
  332. fTimeInfo.bbt.beatsPerBar = static_cast<float>(vstTimeInfo->timeSigNumerator);
  333. fTimeInfo.bbt.beatType = static_cast<float>(vstTimeInfo->timeSigDenominator);
  334. }
  335. else
  336. {
  337. fTimeInfo.bbt.bar = 1;
  338. fTimeInfo.bbt.beat = 1;
  339. fTimeInfo.bbt.tick = 0;
  340. fTimeInfo.bbt.beatsPerBar = 4.0f;
  341. fTimeInfo.bbt.beatType = 4.0f;
  342. }
  343. fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat*fTimeInfo.bbt.beatsPerBar*(fTimeInfo.bbt.bar-1);
  344. }
  345. fMidiOutEvents.numEvents = 0;
  346. if (fHandle != nullptr)
  347. fDescriptor->process(fHandle, const_cast<float**>(inputs), outputs, static_cast<uint32_t>(sampleFrames), fMidiEvents, fMidiEventCount);
  348. fMidiEventCount = 0;
  349. if (fMidiOutEvents.numEvents > 0)
  350. fAudioMaster(fEffect, audioMasterProcessEvents, 0, 0, &fMidiOutEvents, 0.0f);
  351. }
  352. protected:
  353. // -------------------------------------------------------------------
  354. uint32_t handleGetBufferSize() const
  355. {
  356. return fBufferSize;
  357. }
  358. double handleGetSampleRate() const
  359. {
  360. return fSampleRate;
  361. }
  362. bool handleIsOffline() const
  363. {
  364. return false;
  365. }
  366. const NativeTimeInfo* handleGetTimeInfo() const
  367. {
  368. return &fTimeInfo;
  369. }
  370. bool handleWriteMidiEvent(const NativeMidiEvent* const event)
  371. {
  372. CARLA_SAFE_ASSERT_RETURN(fDescriptor->midiOuts > 0, false);
  373. CARLA_SAFE_ASSERT_RETURN(event != nullptr, false);
  374. CARLA_SAFE_ASSERT_RETURN(event->data[0] != 0, false);
  375. if (fMidiOutEvents.numEvents >= static_cast<int32_t>(kMaxMidiEvents))
  376. return false;
  377. VstMidiEvent& vstMidiEvent(fMidiOutEvents.mdata[fMidiOutEvents.numEvents++]);
  378. vstMidiEvent.type = kVstMidiType;
  379. vstMidiEvent.byteSize = kVstMidiEventSize;
  380. uint8_t i=0;
  381. for (; i<event->size; ++i)
  382. vstMidiEvent.midiData[i] = static_cast<char>(event->data[i]);
  383. for (; i<4; ++i)
  384. vstMidiEvent.midiData[i] = 0;
  385. return false;
  386. }
  387. void handleUiParameterChanged(const uint32_t /*index*/, const float /*value*/) const
  388. {
  389. }
  390. void handleUiCustomDataChanged(const char* const /*key*/, const char* const /*value*/) const
  391. {
  392. }
  393. void handleUiClosed()
  394. {
  395. }
  396. const char* handleUiOpenFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const
  397. {
  398. // TODO
  399. return nullptr;
  400. }
  401. const char* handleUiSaveFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const
  402. {
  403. // TODO
  404. return nullptr;
  405. }
  406. intptr_t handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
  407. {
  408. carla_debug("NativePlugin::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)", opcode, index, value, ptr, opt);
  409. return 0;
  410. // unused for now
  411. (void)opcode; (void)index; (void)value; (void)ptr; (void)opt;
  412. }
  413. private:
  414. // VST stuff
  415. const audioMasterCallback fAudioMaster;
  416. AEffect* const fEffect;
  417. // Native data
  418. NativePluginHandle fHandle;
  419. NativeHostDescriptor fHost;
  420. const NativePluginDescriptor* const fDescriptor;
  421. // VST host data
  422. uint32_t fBufferSize;
  423. double fSampleRate;
  424. // Temporary data
  425. bool fIsActive;
  426. uint32_t fMidiEventCount;
  427. NativeMidiEvent fMidiEvents[kMaxMidiEvents];
  428. NativeTimeInfo fTimeInfo;
  429. ERect fVstRect;
  430. struct FixedVstEvents {
  431. int32_t numEvents;
  432. intptr_t reserved;
  433. VstEvent* data[kMaxMidiEvents];
  434. VstMidiEvent mdata[kMaxMidiEvents];
  435. FixedVstEvents()
  436. : numEvents(0),
  437. reserved(0),
  438. data(),
  439. mdata()
  440. {
  441. for (uint32_t i=0; i<kMaxMidiEvents; ++i)
  442. data[i] = (VstEvent*)&mdata[i];
  443. carla_zeroStruct<VstMidiEvent>(mdata, kMaxMidiEvents);
  444. }
  445. CARLA_DECLARE_NON_COPY_STRUCT(FixedVstEvents);
  446. } fMidiOutEvents;
  447. char* fStateChunk;
  448. SharedResourcePointer<ScopedJuceInitialiser_GUI> sJuceInitialiser;
  449. // -------------------------------------------------------------------
  450. #define handlePtr ((NativePlugin*)handle)
  451. static uint32_t host_get_buffer_size(NativeHostHandle handle)
  452. {
  453. return handlePtr->handleGetBufferSize();
  454. }
  455. static double host_get_sample_rate(NativeHostHandle handle)
  456. {
  457. return handlePtr->handleGetSampleRate();
  458. }
  459. static bool host_is_offline(NativeHostHandle handle)
  460. {
  461. return handlePtr->handleIsOffline();
  462. }
  463. static const NativeTimeInfo* host_get_time_info(NativeHostHandle handle)
  464. {
  465. return handlePtr->handleGetTimeInfo();
  466. }
  467. static bool host_write_midi_event(NativeHostHandle handle, const NativeMidiEvent* event)
  468. {
  469. return handlePtr->handleWriteMidiEvent(event);
  470. }
  471. static void host_ui_parameter_changed(NativeHostHandle handle, uint32_t index, float value)
  472. {
  473. handlePtr->handleUiParameterChanged(index, value);
  474. }
  475. static void host_ui_custom_data_changed(NativeHostHandle handle, const char* key, const char* value)
  476. {
  477. handlePtr->handleUiCustomDataChanged(key, value);
  478. }
  479. static void host_ui_closed(NativeHostHandle handle)
  480. {
  481. handlePtr->handleUiClosed();
  482. }
  483. static const char* host_ui_open_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
  484. {
  485. return handlePtr->handleUiOpenFile(isDir, title, filter);
  486. }
  487. static const char* host_ui_save_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
  488. {
  489. return handlePtr->handleUiSaveFile(isDir, title, filter);
  490. }
  491. static intptr_t host_dispatcher(NativeHostHandle handle, NativeHostDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt)
  492. {
  493. return handlePtr->handleDispatcher(opcode, index, value, ptr, opt);
  494. }
  495. #undef handlePtr
  496. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativePlugin)
  497. };
  498. // -----------------------------------------------------------------------
  499. struct VstObject {
  500. audioMasterCallback audioMaster;
  501. NativePlugin* plugin;
  502. };
  503. #ifdef VESTIGE_HEADER
  504. # define validObject effect != nullptr && effect->ptr3 != nullptr
  505. # define validPlugin effect != nullptr && effect->ptr3 != nullptr && ((VstObject*)effect->ptr3)->plugin != nullptr
  506. # define vstObjectPtr (VstObject*)effect->ptr3
  507. #else
  508. # define validObject effect != nullptr && effect->object != nullptr
  509. # define validPlugin effect != nullptr && effect->object != nullptr && ((VstObject*)effect->object)->plugin != nullptr
  510. # define vstObjectPtr (VstObject*)effect->object
  511. #endif
  512. #define pluginPtr (vstObjectPtr)->plugin
  513. static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
  514. {
  515. // handle base opcodes
  516. switch (opcode)
  517. {
  518. case effOpen:
  519. if (VstObject* const obj = vstObjectPtr)
  520. {
  521. // this must always be valid
  522. CARLA_SAFE_ASSERT_RETURN(obj->audioMaster != nullptr, 0);
  523. // some hosts call effOpen twice
  524. CARLA_SAFE_ASSERT_RETURN(obj->plugin == nullptr, 1);
  525. audioMasterCallback audioMaster = (audioMasterCallback)obj->audioMaster;
  526. d_lastBufferSize = static_cast<uint32_t>(audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f));
  527. d_lastSampleRate = static_cast<double>(audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f));
  528. // some hosts are not ready at this point or return 0 buffersize/samplerate
  529. if (d_lastBufferSize == 0)
  530. d_lastBufferSize = 2048;
  531. if (d_lastSampleRate <= 0.0)
  532. d_lastSampleRate = 44100.0;
  533. const NativePluginDescriptor* pluginDesc = nullptr;
  534. #if CARLA_PLUGIN_PATCHBAY
  535. const char* const pluginLabel = "carlapatchbay";
  536. #else
  537. const char* const pluginLabel = "carlarack";
  538. #endif
  539. PluginListManager& plm(PluginListManager::getInstance());
  540. for (LinkedList<const NativePluginDescriptor*>::Itenerator it = plm.descs.begin(); it.valid(); it.next())
  541. {
  542. const NativePluginDescriptor* const& tmpDesc(it.getValue());
  543. if (std::strcmp(tmpDesc->label, pluginLabel) == 0)
  544. {
  545. pluginDesc = tmpDesc;
  546. break;
  547. }
  548. }
  549. CARLA_SAFE_ASSERT_RETURN(pluginDesc != nullptr, 0);
  550. obj->plugin = new NativePlugin(audioMaster, effect, pluginDesc);
  551. return 1;
  552. }
  553. return 0;
  554. case effClose:
  555. if (VstObject* const obj = vstObjectPtr)
  556. {
  557. if (obj->plugin != nullptr)
  558. {
  559. delete obj->plugin;
  560. obj->plugin = nullptr;
  561. }
  562. #if 0
  563. /* This code invalidates the object created in VSTPluginMain
  564. * Probably not safe against all hosts */
  565. obj->audioMaster = nullptr;
  566. # ifdef VESTIGE_HEADER
  567. effect->ptr3 = nullptr;
  568. # else
  569. vstObjectPtr = nullptr;
  570. # endif
  571. delete obj;
  572. #endif
  573. return 1;
  574. }
  575. //delete effect;
  576. return 0;
  577. case effGetPlugCategory:
  578. #if CARLA_PLUGIN_SYNTH
  579. return kPlugCategSynth;
  580. #else
  581. return kPlugCategEffect;
  582. #endif
  583. case effGetEffectName:
  584. if (char* const cptr = (char*)ptr)
  585. {
  586. #if CARLA_PLUGIN_PATCHBAY
  587. # if CARLA_PLUGIN_SYNTH
  588. std::strncpy(cptr, "Carla-Patchbay", 32);
  589. # else
  590. std::strncpy(cptr, "Carla-PatchbayFX", 32);
  591. # endif
  592. #else
  593. # if CARLA_PLUGIN_SYNTH
  594. std::strncpy(cptr, "Carla-Rack", 32);
  595. # else
  596. std::strncpy(cptr, "Carla-RackFX", 32);
  597. # endif
  598. #endif
  599. return 1;
  600. }
  601. return 0;
  602. case effGetVendorString:
  603. if (char* const cptr = (char*)ptr)
  604. {
  605. std::strncpy(cptr, "falkTX", 32);
  606. return 1;
  607. }
  608. return 0;
  609. case effGetProductString:
  610. if (char* const cptr = (char*)ptr)
  611. {
  612. #if CARLA_PLUGIN_PATCHBAY
  613. # if CARLA_PLUGIN_SYNTH
  614. std::strncpy(cptr, "CarlaPatchbay", 32);
  615. # else
  616. std::strncpy(cptr, "CarlaPatchbayFX", 32);
  617. # endif
  618. #else
  619. # if CARLA_PLUGIN_SYNTH
  620. std::strncpy(cptr, "CarlaRack", 32);
  621. # else
  622. std::strncpy(cptr, "CarlaRackFX", 32);
  623. # endif
  624. #endif
  625. return 1;
  626. }
  627. return 0;
  628. case effGetVendorVersion:
  629. return CARLA_VERSION_HEX;
  630. case effGetVstVersion:
  631. return kVstVersion;
  632. };
  633. // handle advanced opcodes
  634. if (validPlugin)
  635. return pluginPtr->vst_dispatcher(opcode, index, value, ptr, opt);
  636. return 0;
  637. }
  638. static float vst_getParameterCallback(AEffect* effect, int32_t index)
  639. {
  640. if (validPlugin)
  641. return pluginPtr->vst_getParameter(index);
  642. return 0.0f;
  643. }
  644. static void vst_setParameterCallback(AEffect* effect, int32_t index, float value)
  645. {
  646. if (validPlugin)
  647. pluginPtr->vst_setParameter(index, value);
  648. }
  649. static void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
  650. {
  651. if (validPlugin)
  652. pluginPtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames);
  653. }
  654. static void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
  655. {
  656. if (validPlugin)
  657. pluginPtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames);
  658. }
  659. #undef pluginPtr
  660. #undef validObject
  661. #undef validPlugin
  662. #undef vstObjectPtr
  663. // -----------------------------------------------------------------------
  664. CARLA_EXPORT
  665. #if defined(CARLA_OS_WIN) || defined(CARLA_OS_MAC)
  666. const AEffect* VSTPluginMain(audioMasterCallback audioMaster);
  667. #else
  668. const AEffect* VSTPluginMain(audioMasterCallback audioMaster) asm ("main");
  669. #endif
  670. CARLA_EXPORT
  671. const AEffect* VSTPluginMain(audioMasterCallback audioMaster)
  672. {
  673. // old version
  674. if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0)
  675. return nullptr;
  676. AEffect* const effect(new AEffect);
  677. std::memset(effect, 0, sizeof(AEffect));
  678. // vst fields
  679. effect->magic = kEffectMagic;
  680. #ifdef VESTIGE_HEADER
  681. int32_t* const version = (int32_t*)&effect->unknown1;
  682. *version = CARLA_VERSION_HEX;
  683. #else
  684. effect->version = CARLA_VERSION_HEX;
  685. #endif
  686. static const int32_t uniqueId = CCONST('C', 'r', 'l', 'a');
  687. #if CARLA_PLUGIN_SYNTH
  688. # if CARLA_PLUGIN_PATCHBAY
  689. effect->uniqueID = uniqueId+4;
  690. # else
  691. effect->uniqueID = uniqueId+3;
  692. # endif
  693. #else
  694. # if CARLA_PLUGIN_PATCHBAY
  695. effect->uniqueID = uniqueId+2;
  696. # else
  697. effect->uniqueID = uniqueId+1;
  698. # endif
  699. #endif
  700. // plugin fields
  701. effect->numParams = 0;
  702. effect->numPrograms = 0;
  703. effect->numInputs = 2;
  704. effect->numOutputs = 2;
  705. // plugin flags
  706. effect->flags |= effFlagsCanReplacing;
  707. effect->flags |= effFlagsHasEditor;
  708. effect->flags |= effFlagsProgramChunks;
  709. #if CARLA_PLUGIN_SYNTH
  710. effect->flags |= effFlagsIsSynth;
  711. #endif
  712. // static calls
  713. effect->dispatcher = vst_dispatcherCallback;
  714. effect->process = vst_processCallback;
  715. effect->getParameter = vst_getParameterCallback;
  716. effect->setParameter = vst_setParameterCallback;
  717. effect->processReplacing = vst_processReplacingCallback;
  718. // pointers
  719. VstObject* const obj(new VstObject());
  720. obj->audioMaster = audioMaster;
  721. obj->plugin = nullptr;
  722. #ifdef VESTIGE_HEADER
  723. effect->ptr3 = obj;
  724. #else
  725. effect->object = obj;
  726. #endif
  727. return effect;
  728. }
  729. // -----------------------------------------------------------------------