Fix crash with clap plugins without MIDI input
[carla.git] / source / backend / plugin / CarlaPluginNative.cpp
blob5537461b99488cf54c0748848aea7b3019573035
1 /*
2 * Carla Native Plugin
3 * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
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.
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.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #include "CarlaPluginInternal.hpp"
19 #include "CarlaEngine.hpp"
21 #include "CarlaBackendUtils.hpp"
22 #include "CarlaMathUtils.hpp"
23 #include "CarlaNative.h"
25 #include "water/misc/Time.h"
26 #include "water/text/StringArray.h"
28 using water::String;
29 using water::StringArray;
31 // -----------------------------------------------------------------------
32 // used in carla-base.cpp
34 std::size_t carla_getNativePluginCount() noexcept;
35 const NativePluginDescriptor* carla_getNativePluginDescriptor(const std::size_t index) noexcept;
37 // -----------------------------------------------------------------------
39 static LinkedList<const NativePluginDescriptor*> gPluginDescriptors;
41 void carla_register_native_plugin(const NativePluginDescriptor* desc)
43 gPluginDescriptors.append(desc);
46 // -----------------------------------------------------------------------
48 static
49 class NativePluginInitializer
51 public:
52 NativePluginInitializer() noexcept
53 : fNeedsInit(true) {}
55 ~NativePluginInitializer() noexcept
57 gPluginDescriptors.clear();
60 void initIfNeeded() noexcept
62 if (! fNeedsInit)
63 return;
65 fNeedsInit = false;
67 try {
68 carla_register_all_native_plugins();
69 } CARLA_SAFE_EXCEPTION("carla_register_all_native_plugins")
72 private:
73 bool fNeedsInit;
75 } sPluginInitializer;
77 // -----------------------------------------------------------------------
79 std::size_t carla_getNativePluginCount() noexcept
81 sPluginInitializer.initIfNeeded();
82 return gPluginDescriptors.count();
85 const NativePluginDescriptor* carla_getNativePluginDescriptor(const std::size_t index) noexcept
87 sPluginInitializer.initIfNeeded();
88 return gPluginDescriptors.getAt(index, nullptr);
91 // -----------------------------------------------------------------------
93 CARLA_BACKEND_START_NAMESPACE
95 // -------------------------------------------------------------------
96 // Fallback data
98 static const CustomData kCustomDataFallback = { nullptr, nullptr, nullptr };
99 static EngineEvent kNullEngineEvent = {
100 kEngineEventTypeNull, 0, 0, {{ kEngineControlEventTypeNull, 0, -1, 0.0f, true }}
103 // -----------------------------------------------------------------------
105 struct NativePluginMidiOutData {
106 uint32_t count;
107 uint32_t* indexes;
108 CarlaEngineEventPort** ports;
110 NativePluginMidiOutData() noexcept
111 : count(0),
112 indexes(nullptr),
113 ports(nullptr) {}
115 ~NativePluginMidiOutData() noexcept
117 CARLA_SAFE_ASSERT_INT(count == 0, count);
118 CARLA_SAFE_ASSERT(indexes == nullptr);
119 CARLA_SAFE_ASSERT(ports == nullptr);
122 bool createNew(const uint32_t newCount)
124 CARLA_SAFE_ASSERT_INT(count == 0, count);
125 CARLA_SAFE_ASSERT_RETURN(indexes == nullptr, false);
126 CARLA_SAFE_ASSERT_RETURN(ports == nullptr, false);
127 CARLA_SAFE_ASSERT_RETURN(newCount > 0, false);
129 indexes = new uint32_t[newCount];
130 ports = new CarlaEngineEventPort*[newCount];
131 count = newCount;
133 carla_zeroStructs(indexes, newCount);
134 carla_zeroStructs(ports, newCount);
136 return true;
139 void clear() noexcept
141 if (ports != nullptr)
143 for (uint32_t i=0; i < count; ++i)
145 if (ports[i] != nullptr)
147 delete ports[i];
148 ports[i] = nullptr;
152 delete[] ports;
153 ports = nullptr;
156 if (indexes != nullptr)
158 delete[] indexes;
159 indexes = nullptr;
162 count = 0;
165 void initBuffers() const noexcept
167 for (uint32_t i=0; i < count; ++i)
169 if (ports[i] != nullptr)
170 ports[i]->initBuffer();
174 CARLA_DECLARE_NON_COPYABLE(NativePluginMidiOutData)
177 struct NativePluginMidiInData : NativePluginMidiOutData {
178 struct MultiPortData {
179 uint32_t cachedEventCount;
180 uint32_t usedIndex;
183 MultiPortData* multiportData;
185 NativePluginMidiInData() noexcept
186 : NativePluginMidiOutData(),
187 multiportData(nullptr) {}
189 ~NativePluginMidiInData() noexcept
191 CARLA_SAFE_ASSERT(multiportData == nullptr);
194 bool createNew(const uint32_t newCount)
196 if (! NativePluginMidiOutData::createNew(newCount))
197 return false;
199 multiportData = new MultiPortData[newCount];
200 carla_zeroStructs(multiportData, newCount);
202 return true;
205 void clear() noexcept
207 if (multiportData != nullptr)
209 delete[] multiportData;
210 multiportData = nullptr;
213 NativePluginMidiOutData::clear();
216 void initBuffers(CarlaEngineEventPort* const port) const noexcept
218 if (count == 1)
220 CARLA_SAFE_ASSERT_RETURN(port != nullptr,);
222 carla_zeroStruct(multiportData[0]);
223 multiportData[0].cachedEventCount = port->getEventCount();
224 return;
227 for (uint32_t i=0; i < count; ++i)
229 carla_zeroStruct(multiportData[i]);
231 if (ports[i] != nullptr)
233 ports[i]->initBuffer();
234 multiportData[i].cachedEventCount = ports[i]->getEventCount();
239 CARLA_DECLARE_NON_COPYABLE(NativePluginMidiInData)
242 // -----------------------------------------------------
244 class CarlaPluginNative : public CarlaPlugin
246 public:
247 CarlaPluginNative(CarlaEngine* const engine, const uint id)
248 : CarlaPlugin(engine, id),
249 fHandle(nullptr),
250 fHandle2(nullptr),
251 fHost(),
252 fDescriptor(nullptr),
253 fIsProcessing(false),
254 fIsOffline(engine->isOffline()),
255 fIsUiAvailable(false),
256 fIsUiVisible(false),
257 fNeedsIdle(false),
258 fInlineDisplayNeedsRedraw(false),
259 fInlineDisplayLastRedrawTime(0),
260 fLastProjectFilename(),
261 fLastProjectFolder(),
262 fAudioAndCvInBuffers(nullptr),
263 fAudioAndCvOutBuffers(nullptr),
264 fMidiEventInCount(0),
265 fMidiEventOutCount(0),
266 fCurBufferSize(engine->getBufferSize()),
267 fCurSampleRate(engine->getSampleRate()),
268 fMidiIn(),
269 fMidiOut(),
270 fTimeInfo()
272 carla_debug("CarlaPluginNative::CarlaPluginNative(%p, %i)", engine, id);
274 carla_fill(fCurMidiProgs, 0, MAX_MIDI_CHANNELS);
275 carla_zeroStructs(fMidiInEvents, kPluginMaxMidiEvents);
276 carla_zeroStructs(fMidiOutEvents, kPluginMaxMidiEvents);
277 carla_zeroStruct(fTimeInfo);
279 fHost.handle = this;
280 fHost.resourceDir = carla_strdup(engine->getOptions().resourceDir);
281 fHost.uiName = nullptr;
282 fHost.uiParentId = engine->getOptions().frontendWinId;
284 fHost.get_buffer_size = carla_host_get_buffer_size;
285 fHost.get_sample_rate = carla_host_get_sample_rate;
286 fHost.is_offline = carla_host_is_offline;
287 fHost.get_time_info = carla_host_get_time_info;
288 fHost.write_midi_event = carla_host_write_midi_event;
289 fHost.ui_parameter_changed = carla_host_ui_parameter_changed;
290 fHost.ui_custom_data_changed = carla_host_ui_custom_data_changed;
291 fHost.ui_closed = carla_host_ui_closed;
292 fHost.ui_open_file = carla_host_ui_open_file;
293 fHost.ui_save_file = carla_host_ui_save_file;
294 fHost.dispatcher = carla_host_dispatcher;
297 ~CarlaPluginNative() override
299 carla_debug("CarlaPluginNative::~CarlaPluginNative()");
301 fInlineDisplayNeedsRedraw = false;
303 // close UI
304 if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
306 if (fIsUiVisible && fDescriptor != nullptr && fDescriptor->ui_show != nullptr && fHandle != nullptr)
307 fDescriptor->ui_show(fHandle, false);
309 #ifndef BUILD_BRIDGE
310 pData->transientTryCounter = 0;
311 #endif
314 pData->singleMutex.lock();
315 pData->masterMutex.lock();
317 if (pData->client != nullptr && pData->client->isActive())
318 pData->client->deactivate(true);
320 CARLA_ASSERT(! fIsProcessing);
322 if (pData->active)
324 deactivate();
325 pData->active = false;
328 if (fDescriptor != nullptr)
330 if (fDescriptor->cleanup != nullptr)
332 if (fHandle != nullptr)
333 fDescriptor->cleanup(fHandle);
334 if (fHandle2 != nullptr)
335 fDescriptor->cleanup(fHandle2);
338 fHandle = nullptr;
339 fHandle2 = nullptr;
340 fDescriptor = nullptr;
343 if (fHost.resourceDir != nullptr)
345 delete[] fHost.resourceDir;
346 fHost.resourceDir = nullptr;
349 if (fHost.uiName != nullptr)
351 std::free(const_cast<char*>(fHost.uiName));
352 fHost.uiName = nullptr;
355 clearBuffers();
358 // -------------------------------------------------------------------
359 // Information (base)
361 PluginType getType() const noexcept override
363 return PLUGIN_INTERNAL;
366 PluginCategory getCategory() const noexcept override
368 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, PLUGIN_CATEGORY_NONE);
370 return static_cast<PluginCategory>(fDescriptor->category);
373 // -------------------------------------------------------------------
374 // Information (count)
376 uint32_t getMidiInCount() const noexcept override
378 return fMidiIn.count;
381 uint32_t getMidiOutCount() const noexcept override
383 return fMidiOut.count;
386 uint32_t getParameterScalePointCount(const uint32_t parameterId) const noexcept override
388 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, 0);
389 CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, 0);
390 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, 0);
391 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0);
393 // FIXME - try
394 if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
395 return param->scalePointCount;
397 carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
398 return 0;
401 // -------------------------------------------------------------------
402 // Information (current data)
404 // nothing
406 // -------------------------------------------------------------------
407 // Information (per-plugin data)
409 uint getOptionsAvailable() const noexcept override
411 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, 0x0);
412 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, 0x0);
414 bool hasMidiProgs = false;
416 if (fDescriptor->get_midi_program_count != nullptr)
418 try {
419 hasMidiProgs = fDescriptor->get_midi_program_count(fHandle) > 0;
420 } catch (...) {}
423 uint options = 0x0;
425 // can't disable fixed buffers if required by the plugin
426 if ((fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) == 0x0)
427 options |= PLUGIN_OPTION_FIXED_BUFFERS;
429 // can't disable forced stereo if enabled in the engine, or using CV
430 if (pData->engine->getOptions().forceStereo || pData->cvIn.count != 0 || pData->cvOut.count != 0)
431 pass();
432 // if inputs or outputs are just 1, then yes we can force stereo
433 else if (pData->audioIn.count == 1 || pData->audioOut.count == 1 || fHandle2 != nullptr)
434 options |= PLUGIN_OPTION_FORCE_STEREO;
436 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES)
437 options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
438 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_CHANNEL_PRESSURE)
439 options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
440 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_NOTE_AFTERTOUCH)
441 options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
442 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_PITCHBEND)
443 options |= PLUGIN_OPTION_SEND_PITCHBEND;
444 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_ALL_SOUND_OFF)
445 options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
447 if (fDescriptor->midiIns > 0)
448 options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
450 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_PROGRAM_CHANGES)
451 options |= PLUGIN_OPTION_SEND_PROGRAM_CHANGES;
452 else if (hasMidiProgs)
453 options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES;
455 return options;
458 float getParameterValue(const uint32_t parameterId) const noexcept override
460 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, 0.0f);
461 CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_value != nullptr, 0.0f);
462 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, 0.0f);
463 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0.0f);
465 // FIXME - try
466 return fDescriptor->get_parameter_value(fHandle, parameterId);
469 float getParameterScalePointValue(const uint32_t parameterId, const uint32_t scalePointId) const noexcept override
471 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, 0.0f);
472 CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, 0.0f);
473 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, 0.0f);
474 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0.0f);
476 // FIXME - try
477 if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
479 CARLA_SAFE_ASSERT_RETURN(scalePointId < param->scalePointCount, 0.0f);
481 const NativeParameterScalePoint* scalePoint(&param->scalePoints[scalePointId]);
482 return scalePoint->value;
485 carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
486 return 0.0f;
489 bool getLabel(char* const strBuf) const noexcept override
491 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
493 if (fDescriptor->label != nullptr)
495 std::strncpy(strBuf, fDescriptor->label, STR_MAX);
496 return true;
499 return CarlaPlugin::getLabel(strBuf);
502 bool getMaker(char* const strBuf) const noexcept override
504 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
506 if (fDescriptor->maker != nullptr)
508 std::strncpy(strBuf, fDescriptor->maker, STR_MAX);
509 return true;
512 return CarlaPlugin::getMaker(strBuf);
515 bool getCopyright(char* const strBuf) const noexcept override
517 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
519 if (fDescriptor->copyright != nullptr)
521 std::strncpy(strBuf, fDescriptor->copyright, STR_MAX);
522 return true;
525 return CarlaPlugin::getCopyright(strBuf);
528 bool getRealName(char* const strBuf) const noexcept override
530 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
532 if (fDescriptor->name != nullptr)
534 std::strncpy(strBuf, fDescriptor->name, STR_MAX);
535 return true;
538 return CarlaPlugin::getRealName(strBuf);
541 bool getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept override
543 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
544 CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, false);
545 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
546 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
548 // FIXME - try
549 if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
551 if (param->name != nullptr)
553 std::strncpy(strBuf, param->name, STR_MAX);
554 return true;
557 carla_safe_assert("param->name != nullptr", __FILE__, __LINE__);
558 return CarlaPlugin::getParameterName(parameterId, strBuf);
561 carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
562 return CarlaPlugin::getParameterName(parameterId, strBuf);
565 bool getParameterUnit(const uint32_t parameterId, char* const strBuf) const noexcept override
567 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
568 CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, false);
569 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
570 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
572 // FIXME - try
573 if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
575 if (param->unit != nullptr)
577 std::strncpy(strBuf, param->unit, STR_MAX);
578 return true;
581 return CarlaPlugin::getParameterUnit(parameterId, strBuf);
584 carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
585 return CarlaPlugin::getParameterUnit(parameterId, strBuf);
588 bool getParameterComment(const uint32_t parameterId, char* const strBuf) const noexcept override
590 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
591 CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, false);
592 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
593 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
595 // FIXME - try
596 if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
598 if (param->comment != nullptr)
600 std::strncpy(strBuf, param->comment, STR_MAX);
601 return true;
604 return CarlaPlugin::getParameterComment(parameterId, strBuf);
607 carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
608 return CarlaPlugin::getParameterComment(parameterId, strBuf);
611 bool getParameterGroupName(const uint32_t parameterId, char* const strBuf) const noexcept override
613 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
614 CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, false);
615 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
616 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
618 // FIXME - try
619 if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
621 if (param->groupName != nullptr)
623 std::strncpy(strBuf, param->groupName, STR_MAX);
624 return true;
627 return CarlaPlugin::getParameterGroupName(parameterId, strBuf);
630 carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
631 return CarlaPlugin::getParameterGroupName(parameterId, strBuf);
634 bool getParameterScalePointLabel(const uint32_t parameterId, const uint32_t scalePointId, char* const strBuf) const noexcept override
636 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
637 CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, false);
638 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
639 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
641 // FIXME - try
642 if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
644 CARLA_SAFE_ASSERT_RETURN(scalePointId < param->scalePointCount, false);
646 const NativeParameterScalePoint* scalePoint(&param->scalePoints[scalePointId]);
648 if (scalePoint->label != nullptr)
650 std::strncpy(strBuf, scalePoint->label, STR_MAX);
651 return true;
654 carla_safe_assert("scalePoint->label != nullptr", __FILE__, __LINE__);
655 return CarlaPlugin::getParameterScalePointLabel(parameterId, scalePointId, strBuf);
658 carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
659 return CarlaPlugin::getParameterScalePointLabel(parameterId, scalePointId, strBuf);
662 // -------------------------------------------------------------------
663 // Set data (state)
665 void prepareForSave(bool) override
667 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
668 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
670 if (pData->midiprog.count > 0 && fDescriptor->category == NATIVE_PLUGIN_CATEGORY_SYNTH)
672 char strBuf[STR_MAX+1];
673 std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i",
674 fCurMidiProgs[0], fCurMidiProgs[1], fCurMidiProgs[2], fCurMidiProgs[3],
675 fCurMidiProgs[4], fCurMidiProgs[5], fCurMidiProgs[6], fCurMidiProgs[7],
676 fCurMidiProgs[8], fCurMidiProgs[9], fCurMidiProgs[10], fCurMidiProgs[11],
677 fCurMidiProgs[12], fCurMidiProgs[13], fCurMidiProgs[14], fCurMidiProgs[15]);
678 strBuf[STR_MAX] = '\0';
680 CarlaPlugin::setCustomData(CUSTOM_DATA_TYPE_STRING, "midiPrograms", strBuf, false);
683 if (fDescriptor == nullptr || fDescriptor->get_state == nullptr || (fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0)
684 return;
686 if (char* data = fDescriptor->get_state(fHandle))
688 CarlaPlugin::setCustomData(CUSTOM_DATA_TYPE_CHUNK, "State", data, false);
689 std::free(data);
693 // -------------------------------------------------------------------
694 // Set data (internal stuff)
696 void setName(const char* const newName) override
698 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
699 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
700 CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0',);
702 CarlaPlugin::setName(newName);
704 if (pData->uiTitle.isEmpty())
705 setWindowTitle(nullptr);
708 void setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept override
710 if (channel >= 0 && channel < MAX_MIDI_CHANNELS && pData->midiprog.count > 0)
711 pData->midiprog.current = fCurMidiProgs[channel];
713 CarlaPlugin::setCtrlChannel(channel, sendOsc, sendCallback);
716 void setWindowTitle(const char* const title) noexcept
718 CarlaString uiName;
720 if (title != nullptr)
722 uiName = title;
724 else
726 uiName = pData->name;
727 uiName += " (GUI)";
730 std::free(const_cast<char*>(fHost.uiName));
731 fHost.uiName = uiName.releaseBufferPointer();
733 if (fDescriptor->dispatcher != nullptr && fIsUiVisible)
735 try {
736 fDescriptor->dispatcher(fHandle,
737 NATIVE_PLUGIN_OPCODE_UI_NAME_CHANGED,
738 0, 0,
739 const_cast<char*>(fHost.uiName),
740 0.0f);
741 } CARLA_SAFE_EXCEPTION("set custom ui title");
746 // -------------------------------------------------------------------
747 // Set data (plugin-specific stuff)
749 void setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept override
751 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
752 CARLA_SAFE_ASSERT_RETURN(fDescriptor->set_parameter_value != nullptr,);
753 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
754 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
756 const float fixedValue(pData->param.getFixedValue(parameterId, value));
758 // FIXME - try
759 fDescriptor->set_parameter_value(fHandle, parameterId, fixedValue);
761 if (fHandle2 != nullptr)
762 fDescriptor->set_parameter_value(fHandle2, parameterId, fixedValue);
764 CarlaPlugin::setParameterValue(parameterId, fixedValue, sendGui, sendOsc, sendCallback);
767 void setParameterValueRT(const uint32_t parameterId, const float value, const uint32_t frameOffset, const bool sendCallbackLater) noexcept override
769 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
770 CARLA_SAFE_ASSERT_RETURN(fDescriptor->set_parameter_value != nullptr,);
771 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
772 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
774 const float fixedValue(pData->param.getFixedValue(parameterId, value));
776 // FIXME - try
777 fDescriptor->set_parameter_value(fHandle, parameterId, fixedValue);
779 if (fHandle2 != nullptr)
780 fDescriptor->set_parameter_value(fHandle2, parameterId, fixedValue);
782 CarlaPlugin::setParameterValueRT(parameterId, fixedValue, frameOffset, sendCallbackLater);
785 void setCustomData(const char* const type, const char* const key, const char* const value, const bool sendGui) override
787 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
788 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
789 CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
790 CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
791 CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
792 carla_debug("CarlaPluginNative::setCustomData(\"%s\", \"%s\", ..., %s)", type, key, bool2str(sendGui));
794 if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0)
795 return CarlaPlugin::setCustomData(type, key, value, sendGui);
797 if (std::strcmp(type, CUSTOM_DATA_TYPE_PATH) == 0)
799 CARLA_SAFE_ASSERT_RETURN(std::strcmp(key, "file") == 0,);
800 CARLA_SAFE_ASSERT_RETURN(value[0] != '\0',);
802 else if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) != 0 && std::strcmp(type, CUSTOM_DATA_TYPE_CHUNK) != 0)
804 return carla_stderr2("CarlaPluginNative::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is invalid",
805 type, key, value, bool2str(sendGui));
808 if (std::strcmp(type, CUSTOM_DATA_TYPE_CHUNK) == 0)
810 if (fDescriptor->set_state != nullptr && (fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) != 0)
812 const ScopedSingleProcessLocker spl(this, true);
814 fDescriptor->set_state(fHandle, value);
816 if (fHandle2 != nullptr)
817 fDescriptor->set_state(fHandle2, value);
820 else if (std::strcmp(key, "midiPrograms") == 0 && fDescriptor->set_midi_program != nullptr)
822 StringArray midiProgramList(StringArray::fromTokens(value, ":", ""));
824 if (midiProgramList.size() == MAX_MIDI_CHANNELS)
826 uint8_t channel = 0;
827 for (String *it=midiProgramList.begin(), *end=midiProgramList.end(); it != end; ++it)
829 const int index(it->getIntValue());
831 if (index >= 0 && index < static_cast<int>(pData->midiprog.count))
833 const uint32_t bank = pData->midiprog.data[index].bank;
834 const uint32_t program = pData->midiprog.data[index].program;
836 fDescriptor->set_midi_program(fHandle, channel, bank, program);
838 if (fHandle2 != nullptr)
839 fDescriptor->set_midi_program(fHandle2, channel, bank, program);
841 fCurMidiProgs[channel] = index;
843 if (pData->ctrlChannel == static_cast<int32_t>(channel))
845 pData->midiprog.current = index;
846 pData->engine->callback(true, true,
847 ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED,
848 pData->id,
849 index,
850 0, 0, 0.0f, nullptr);
854 ++channel;
856 CARLA_SAFE_ASSERT(channel == MAX_MIDI_CHANNELS);
859 else
861 if (fDescriptor->set_custom_data != nullptr)
863 fDescriptor->set_custom_data(fHandle, key, value);
865 if (fHandle2 != nullptr)
866 fDescriptor->set_custom_data(fHandle2, key, value);
869 if (sendGui && fIsUiVisible && fDescriptor->ui_set_custom_data != nullptr)
870 fDescriptor->ui_set_custom_data(fHandle, key, value);
873 CarlaPlugin::setCustomData(type, key, value, sendGui);
876 void setMidiProgram(const int32_t index, const bool sendGui, const bool sendOsc, const bool sendCallback, const bool doingInit) noexcept override
878 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
879 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
880 CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->midiprog.count),);
881 CARLA_SAFE_ASSERT_RETURN(sendGui || sendOsc || sendCallback || doingInit,);
883 // TODO, put into check below
884 if ((pData->hints & PLUGIN_IS_SYNTH) != 0 && (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS))
885 return CarlaPlugin::setMidiProgram(index, sendGui, sendOsc, sendCallback, doingInit);
887 if (index >= 0)
889 const uint8_t channel = uint8_t((pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) ? pData->ctrlChannel : 0);
890 const uint32_t bank = pData->midiprog.data[index].bank;
891 const uint32_t program = pData->midiprog.data[index].program;
893 const ScopedSingleProcessLocker spl(this, (sendGui || sendOsc || sendCallback));
895 try {
896 fDescriptor->set_midi_program(fHandle, channel, bank, program);
897 } catch(...) {}
899 if (fHandle2 != nullptr)
901 try {
902 fDescriptor->set_midi_program(fHandle2, channel, bank, program);
903 } catch(...) {}
906 fCurMidiProgs[channel] = index;
909 CarlaPlugin::setMidiProgram(index, sendGui, sendOsc, sendCallback, doingInit);
912 // FIXME: this is never used
913 void setMidiProgramRT(const uint32_t index, const bool sendCallbackLater) noexcept override
915 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
916 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
917 CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count,);
919 // TODO, put into check below
920 if ((pData->hints & PLUGIN_IS_SYNTH) != 0 && (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS))
921 return CarlaPlugin::setMidiProgramRT(index, sendCallbackLater);
923 const uint8_t channel = uint8_t((pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) ? pData->ctrlChannel : 0);
924 const uint32_t bank = pData->midiprog.data[index].bank;
925 const uint32_t program = pData->midiprog.data[index].program;
927 try {
928 fDescriptor->set_midi_program(fHandle, channel, bank, program);
929 } catch(...) {}
931 if (fHandle2 != nullptr)
933 try {
934 fDescriptor->set_midi_program(fHandle2, channel, bank, program);
935 } catch(...) {}
938 fCurMidiProgs[channel] = static_cast<int32_t>(index);
940 CarlaPlugin::setMidiProgramRT(index, sendCallbackLater);
943 // -------------------------------------------------------------------
944 // Set ui stuff
946 void setCustomUITitle(const char* const title) noexcept override
948 setWindowTitle(title);
949 CarlaPlugin::setCustomUITitle(title);
952 void showCustomUI(const bool yesNo) override
954 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
955 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
957 if (fDescriptor->ui_show == nullptr)
958 return;
960 fIsUiAvailable = true;
962 fDescriptor->ui_show(fHandle, yesNo);
964 // UI might not be available, see NATIVE_HOST_OPCODE_UI_UNAVAILABLE
965 if (yesNo && ! fIsUiAvailable)
966 return;
968 fIsUiVisible = yesNo;
970 if (! yesNo)
972 #ifndef BUILD_BRIDGE
973 pData->transientTryCounter = 0;
974 #endif
975 return;
978 #ifndef BUILD_BRIDGE
979 if ((fDescriptor->hints & NATIVE_PLUGIN_USES_PARENT_ID) == 0 && std::strstr(fDescriptor->label, "file") == nullptr)
980 pData->tryTransient();
981 #endif
983 if (fDescriptor->ui_set_custom_data != nullptr)
985 for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
987 const CustomData& cData(it.getValue(kCustomDataFallback));
988 CARLA_SAFE_ASSERT_CONTINUE(cData.isValid());
990 if (std::strcmp(cData.type, CUSTOM_DATA_TYPE_STRING) == 0 && std::strcmp(cData.key, "midiPrograms") != 0)
991 fDescriptor->ui_set_custom_data(fHandle, cData.key, cData.value);
995 if (fDescriptor->ui_set_midi_program != nullptr && pData->midiprog.current >= 0 && pData->midiprog.count > 0)
997 const int32_t index = pData->midiprog.current;
998 const uint8_t channel = uint8_t((pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) ? pData->ctrlChannel : 0);
999 const uint32_t bank = pData->midiprog.data[index].bank;
1000 const uint32_t program = pData->midiprog.data[index].program;
1002 fDescriptor->ui_set_midi_program(fHandle, channel, bank, program);
1005 if (fDescriptor->ui_set_parameter_value != nullptr)
1007 for (uint32_t i=0; i < pData->param.count; ++i)
1008 fDescriptor->ui_set_parameter_value(fHandle, i, fDescriptor->get_parameter_value(fHandle, i));
1012 void idle() override
1014 if (fNeedsIdle)
1016 fNeedsIdle = false;
1017 fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_IDLE, 0, 0, nullptr, 0.0f);
1020 if (fInlineDisplayNeedsRedraw)
1022 // TESTING
1023 CARLA_SAFE_ASSERT(pData->enabled)
1024 CARLA_SAFE_ASSERT(!pData->engine->isAboutToClose());
1025 CARLA_SAFE_ASSERT(pData->client->isActive());
1027 if (pData->enabled && !pData->engine->isAboutToClose() && pData->client->isActive())
1029 const int64_t timeNow = water::Time::currentTimeMillis();
1031 if (timeNow - fInlineDisplayLastRedrawTime > (1000 / 30))
1033 fInlineDisplayNeedsRedraw = false;
1034 fInlineDisplayLastRedrawTime = timeNow;
1035 pData->engine->callback(true, true,
1036 ENGINE_CALLBACK_INLINE_DISPLAY_REDRAW,
1037 pData->id,
1038 0, 0, 0, 0.0f, nullptr);
1041 else
1043 fInlineDisplayNeedsRedraw = false;
1047 CarlaPlugin::idle();
1050 void uiIdle() override
1052 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
1053 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
1055 if (fIsUiVisible && fDescriptor->ui_idle != nullptr)
1056 fDescriptor->ui_idle(fHandle);
1058 CarlaPlugin::uiIdle();
1061 // -------------------------------------------------------------------
1062 // Plugin state
1064 void reload() override
1066 CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,);
1067 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
1068 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
1069 carla_debug("CarlaPluginNative::reload() - start");
1071 const EngineProcessMode processMode(pData->engine->getProccessMode());
1073 // Safely disable plugin for reload
1074 const ScopedDisabler sd(this);
1076 if (pData->active)
1077 deactivate();
1079 clearBuffers();
1081 uint32_t aIns, aOuts, cvIns, cvOuts, mIns, mOuts, j;
1083 bool forcedStereoIn, forcedStereoOut;
1084 forcedStereoIn = forcedStereoOut = false;
1086 bool needsCtrlIn, needsCtrlOut;
1087 needsCtrlIn = needsCtrlOut = false;
1089 aIns = fDescriptor->audioIns;
1090 aOuts = fDescriptor->audioOuts;
1091 cvIns = fDescriptor->cvIns;
1092 cvOuts = fDescriptor->cvOuts;
1093 mIns = fDescriptor->midiIns;
1094 mOuts = fDescriptor->midiOuts;
1096 if ((pData->options & PLUGIN_OPTION_FORCE_STEREO) != 0 && (aIns == 1 || aOuts == 1) && mIns <= 1 && mOuts <= 1)
1098 if (fHandle2 == nullptr)
1099 fHandle2 = fDescriptor->instantiate(&fHost);
1101 if (fHandle2 != nullptr)
1103 if (aIns == 1)
1105 aIns = 2;
1106 forcedStereoIn = true;
1109 if (aOuts == 1)
1111 aOuts = 2;
1112 forcedStereoOut = true;
1117 if (aIns > 0)
1119 pData->audioIn.createNew(aIns);
1122 if (aOuts > 0)
1124 pData->audioOut.createNew(aOuts);
1125 needsCtrlIn = true;
1128 if (cvIns > 0)
1130 pData->cvIn.createNew(cvIns);
1133 if (cvOuts > 0)
1135 pData->cvOut.createNew(cvOuts);
1138 if (const uint32_t acIns = aIns + cvIns)
1140 fAudioAndCvInBuffers = new float*[acIns];
1141 carla_zeroPointers(fAudioAndCvInBuffers, acIns);
1144 if (const uint32_t acOuts = aOuts + cvOuts)
1146 fAudioAndCvOutBuffers = new float*[acOuts];
1147 carla_zeroPointers(fAudioAndCvOutBuffers, acOuts);
1150 if (mIns > 0)
1152 fMidiIn.createNew(mIns);
1153 needsCtrlIn = (mIns == 1);
1156 if (mOuts > 0)
1158 fMidiOut.createNew(mOuts);
1159 needsCtrlOut = (mOuts == 1);
1162 const uint portNameSize(pData->engine->getMaxPortNameSize());
1163 CarlaString portName;
1165 // Audio Ins
1166 for (j=0; j < aIns; ++j)
1168 portName.clear();
1170 if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1172 portName = pData->name;
1173 portName += ":";
1176 if (fDescriptor->get_buffer_port_name != nullptr)
1178 portName += fDescriptor->get_buffer_port_name(fHandle, forcedStereoIn ? 0 : j, false);
1180 else if (aIns > 1 && ! forcedStereoIn)
1182 portName += "input_";
1183 portName += CarlaString(j+1);
1185 else
1186 portName += "input";
1188 portName.truncate(portNameSize);
1190 pData->audioIn.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, j);
1191 pData->audioIn.ports[j].rindex = j;
1193 if (forcedStereoIn)
1195 portName += "_2";
1196 pData->audioIn.ports[1].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, 1);
1197 pData->audioIn.ports[1].rindex = j;
1198 break;
1202 // Audio Outs
1203 for (j=0; j < aOuts; ++j)
1205 portName.clear();
1207 if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1209 portName = pData->name;
1210 portName += ":";
1213 if (fDescriptor->get_buffer_port_name != nullptr)
1215 portName += fDescriptor->get_buffer_port_name(fHandle, forcedStereoOut ? 0 : j, true);
1217 else if (aOuts > 1 && ! forcedStereoOut)
1219 portName += "output_";
1220 portName += CarlaString(j+1);
1222 else
1223 portName += "output";
1225 portName.truncate(portNameSize);
1227 pData->audioOut.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, j);
1228 pData->audioOut.ports[j].rindex = j;
1230 if (forcedStereoOut)
1232 portName += "_2";
1233 pData->audioOut.ports[1].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, 1);
1234 pData->audioOut.ports[1].rindex = j;
1235 break;
1239 // CV Ins
1240 for (j=0; j < cvIns; ++j)
1242 portName.clear();
1244 if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1246 portName = pData->name;
1247 portName += ":";
1250 if (fDescriptor->get_buffer_port_name != nullptr)
1252 portName += fDescriptor->get_buffer_port_name(fHandle, fDescriptor->audioIns + j, false);
1254 else if (cvIns > 1)
1256 portName += "cv_input_";
1257 portName += CarlaString(j+1);
1259 else
1260 portName += "cv_input";
1262 portName.truncate(portNameSize);
1264 float min = -1.0f, max = 1.0f;
1265 if (fDescriptor->get_buffer_port_range != nullptr)
1267 if (const NativePortRange* const range = fDescriptor->get_buffer_port_range(fHandle,
1268 fDescriptor->audioIns + j,
1269 false))
1271 min = range->minimum;
1272 max = range->maximum;
1276 pData->cvIn.ports[j].port = (CarlaEngineCVPort*)pData->client->addPort(kEnginePortTypeCV, portName, true, j);
1277 pData->cvIn.ports[j].rindex = j;
1278 pData->cvIn.ports[j].port->setRange(min, max);
1281 // CV Outs
1282 for (j=0; j < cvOuts; ++j)
1284 portName.clear();
1286 if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1288 portName = pData->name;
1289 portName += ":";
1292 if (fDescriptor->get_buffer_port_name != nullptr)
1294 portName += fDescriptor->get_buffer_port_name(fHandle, fDescriptor->audioOuts + j, true);
1296 else if (cvOuts > 1)
1298 portName += "cv_output_";
1299 portName += CarlaString(j+1);
1301 else
1302 portName += "cv_output";
1304 portName.truncate(portNameSize);
1306 float min = -1.0f, max = 1.0f;
1307 if (fDescriptor->get_buffer_port_range != nullptr)
1309 if (const NativePortRange* const range = fDescriptor->get_buffer_port_range(fHandle,
1310 fDescriptor->audioOuts + j,
1311 true))
1313 min = range->minimum;
1314 max = range->maximum;
1318 pData->cvOut.ports[j].port = (CarlaEngineCVPort*)pData->client->addPort(kEnginePortTypeCV, portName, false, j);
1319 pData->cvOut.ports[j].rindex = j;
1320 pData->cvOut.ports[j].port->setRange(min, max);
1323 // MIDI Input (only if multiple)
1324 if (mIns > 1)
1326 for (j=0; j < mIns; ++j)
1328 portName.clear();
1330 if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1332 portName = pData->name;
1333 portName += ":";
1336 portName += "midi-in_";
1337 portName += CarlaString(j+1);
1338 portName.truncate(portNameSize);
1340 fMidiIn.ports[j] = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, j);
1341 fMidiIn.indexes[j] = j;
1344 pData->event.portIn = fMidiIn.ports[0];
1347 // MIDI Output (only if multiple)
1348 if (mOuts > 1)
1350 for (j=0; j < mOuts; ++j)
1352 portName.clear();
1354 if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1356 portName = pData->name;
1357 portName += ":";
1360 portName += "midi-out_";
1361 portName += CarlaString(j+1);
1362 portName.truncate(portNameSize);
1364 fMidiOut.ports[j] = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, j);
1365 fMidiOut.indexes[j] = j;
1368 pData->event.portOut = fMidiOut.ports[0];
1371 reloadParameters(&needsCtrlIn, &needsCtrlOut);
1373 if (needsCtrlIn || mIns == 1)
1375 portName.clear();
1377 if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1379 portName = pData->name;
1380 portName += ":";
1383 portName += "events-in";
1384 portName.truncate(portNameSize);
1386 pData->event.portIn = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, 0);
1387 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1388 pData->event.cvSourcePorts = pData->client->createCVSourcePorts();
1389 #endif
1392 if (needsCtrlOut || mOuts == 1)
1394 portName.clear();
1396 if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1398 portName = pData->name;
1399 portName += ":";
1402 portName += "events-out";
1403 portName.truncate(portNameSize);
1405 pData->event.portOut = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, 0);
1408 if (forcedStereoIn || forcedStereoOut)
1409 pData->options |= PLUGIN_OPTION_FORCE_STEREO;
1410 else
1411 pData->options &= ~PLUGIN_OPTION_FORCE_STEREO;
1413 // plugin hints
1414 pData->hints = 0x0;
1416 if (aOuts > 0 && (aIns == aOuts || aIns == 1))
1417 pData->hints |= PLUGIN_CAN_DRYWET;
1419 if (aOuts > 0)
1420 pData->hints |= PLUGIN_CAN_VOLUME;
1422 if (aOuts >= 2 && aOuts % 2 == 0)
1423 pData->hints |= PLUGIN_CAN_BALANCE;
1425 // native plugin hints
1426 if (fDescriptor->hints & NATIVE_PLUGIN_IS_RTSAFE)
1427 pData->hints |= PLUGIN_IS_RTSAFE;
1428 if (fDescriptor->hints & NATIVE_PLUGIN_IS_SYNTH)
1429 pData->hints |= PLUGIN_IS_SYNTH;
1430 if (fDescriptor->hints & NATIVE_PLUGIN_HAS_UI)
1431 pData->hints |= PLUGIN_HAS_CUSTOM_UI;
1432 if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS)
1433 pData->hints |= PLUGIN_NEEDS_FIXED_BUFFERS;
1434 if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD)
1435 pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD;
1436 if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
1437 pData->hints |= PLUGIN_HAS_CUSTOM_UI_USING_FILE_OPEN;
1438 if (fDescriptor->hints & NATIVE_PLUGIN_USES_MULTI_PROGS)
1439 pData->hints |= PLUGIN_USES_MULTI_PROGS;
1440 if (fDescriptor->hints & NATIVE_PLUGIN_HAS_INLINE_DISPLAY)
1441 pData->hints |= PLUGIN_HAS_INLINE_DISPLAY;
1443 // extra plugin hints
1444 pData->extraHints = 0x0;
1446 bufferSizeChanged(pData->engine->getBufferSize());
1447 reloadPrograms(true);
1449 if (pData->active)
1450 activate();
1452 carla_debug("CarlaPluginNative::reload() - end");
1455 void reloadParameters(bool* const needsCtrlIn, bool* const needsCtrlOut)
1457 carla_debug("CarlaPluginNative::reloadParameters() - start");
1459 const float sampleRate = static_cast<float>(pData->engine->getSampleRate());
1460 const uint32_t params = (fDescriptor->get_parameter_count != nullptr && fDescriptor->get_parameter_info != nullptr)
1461 ? fDescriptor->get_parameter_count(fHandle)
1462 : 0;
1464 pData->param.clear();
1466 if (params > 0)
1468 pData->param.createNew(params, true);
1471 for (uint32_t j=0; j < params; ++j)
1473 const NativeParameter* const paramInfo(fDescriptor->get_parameter_info(fHandle, j));
1475 CARLA_SAFE_ASSERT_CONTINUE(paramInfo != nullptr);
1477 pData->param.data[j].type = PARAMETER_UNKNOWN;
1478 pData->param.data[j].index = static_cast<int32_t>(j);
1479 pData->param.data[j].rindex = static_cast<int32_t>(j);
1481 float min, max, def, step, stepSmall, stepLarge;
1483 // min value
1484 min = paramInfo->ranges.min;
1486 // max value
1487 max = paramInfo->ranges.max;
1489 if (min > max)
1490 max = min;
1492 if (carla_isEqual(min, max))
1494 carla_stderr2("WARNING - Broken plugin parameter '%s': max == min", paramInfo->name);
1495 max = min + 0.1f;
1498 // default value
1499 def = paramInfo->ranges.def;
1501 if (def < min)
1502 def = min;
1503 else if (def > max)
1504 def = max;
1506 if (paramInfo->hints & NATIVE_PARAMETER_USES_SAMPLE_RATE)
1508 min *= sampleRate;
1509 max *= sampleRate;
1510 def *= sampleRate;
1511 pData->param.data[j].hints |= PARAMETER_USES_SAMPLERATE;
1514 if (paramInfo->hints & NATIVE_PARAMETER_IS_BOOLEAN)
1516 step = max - min;
1517 stepSmall = step;
1518 stepLarge = step;
1519 pData->param.data[j].hints |= PARAMETER_IS_BOOLEAN;
1521 else if (paramInfo->hints & NATIVE_PARAMETER_IS_INTEGER)
1523 step = 1.0f;
1524 stepSmall = 1.0f;
1525 stepLarge = 10.0f;
1526 pData->param.data[j].hints |= PARAMETER_IS_INTEGER;
1528 else
1530 float range = max - min;
1531 step = range/100.0f;
1532 stepSmall = range/1000.0f;
1533 stepLarge = range/10.0f;
1536 if (paramInfo->hints & NATIVE_PARAMETER_IS_OUTPUT)
1538 pData->param.data[j].type = PARAMETER_OUTPUT;
1539 if (needsCtrlOut != nullptr)
1540 *needsCtrlOut = true;
1542 else
1544 pData->param.data[j].type = PARAMETER_INPUT;
1545 if (needsCtrlIn != nullptr)
1546 *needsCtrlIn = true;
1549 // extra parameter hints
1550 if (paramInfo->hints & NATIVE_PARAMETER_IS_ENABLED)
1552 pData->param.data[j].hints |= PARAMETER_IS_ENABLED;
1554 if (paramInfo->hints & NATIVE_PARAMETER_IS_AUTOMATABLE)
1556 pData->param.data[j].hints |= PARAMETER_IS_AUTOMATABLE;
1557 pData->param.data[j].hints |= PARAMETER_CAN_BE_CV_CONTROLLED;
1561 if (paramInfo->hints & NATIVE_PARAMETER_IS_LOGARITHMIC)
1562 pData->param.data[j].hints |= PARAMETER_IS_LOGARITHMIC;
1564 if (paramInfo->hints & NATIVE_PARAMETER_USES_SCALEPOINTS)
1565 pData->param.data[j].hints |= PARAMETER_USES_SCALEPOINTS;
1567 pData->param.ranges[j].min = min;
1568 pData->param.ranges[j].max = max;
1569 pData->param.ranges[j].def = def;
1570 pData->param.ranges[j].step = step;
1571 pData->param.ranges[j].stepSmall = stepSmall;
1572 pData->param.ranges[j].stepLarge = stepLarge;
1575 carla_debug("CarlaPluginNative::reloadParameters() - end");
1578 void reloadPrograms(const bool doInit) override
1580 carla_debug("CarlaPluginNative::reloadPrograms(%s)", bool2str(doInit));
1581 uint32_t i, oldCount = pData->midiprog.count;
1582 const int32_t current = pData->midiprog.current;
1584 // Delete old programs
1585 pData->midiprog.clear();
1587 // Query new programs
1588 uint32_t count = 0;
1589 if (fDescriptor->get_midi_program_count != nullptr && fDescriptor->get_midi_program_info != nullptr && fDescriptor->set_midi_program != nullptr)
1590 count = fDescriptor->get_midi_program_count(fHandle);
1592 if (count > 0)
1594 pData->midiprog.createNew(count);
1596 // Update data
1597 for (i=0; i < count; ++i)
1599 const NativeMidiProgram* const mpDesc(fDescriptor->get_midi_program_info(fHandle, i));
1600 CARLA_SAFE_ASSERT_CONTINUE(mpDesc != nullptr);
1602 pData->midiprog.data[i].bank = mpDesc->bank;
1603 pData->midiprog.data[i].program = mpDesc->program;
1604 pData->midiprog.data[i].name = carla_strdup(mpDesc->name);
1608 if (doInit)
1610 if (count > 0)
1611 setMidiProgram(0, false, false, false, true);
1613 else
1615 // Check if current program is invalid
1616 bool programChanged = false;
1618 if (count == oldCount+1)
1620 // one midi program added, probably created by user
1621 pData->midiprog.current = static_cast<int32_t>(oldCount);
1622 programChanged = true;
1624 else if (current < 0 && count > 0)
1626 // programs exist now, but not before
1627 pData->midiprog.current = 0;
1628 programChanged = true;
1630 else if (current >= 0 && count == 0)
1632 // programs existed before, but not anymore
1633 pData->midiprog.current = -1;
1634 programChanged = true;
1636 else if (current >= static_cast<int32_t>(count))
1638 // current midi program > count
1639 pData->midiprog.current = 0;
1640 programChanged = true;
1642 else
1644 // no change
1645 pData->midiprog.current = current;
1648 if (programChanged)
1649 setMidiProgram(pData->midiprog.current, true, true, true, false);
1651 pData->engine->callback(true, true,
1652 ENGINE_CALLBACK_RELOAD_PROGRAMS,
1653 pData->id,
1654 0, 0, 0, 0.0f, nullptr);
1658 // -------------------------------------------------------------------
1659 // Plugin processing
1661 void activate() noexcept override
1663 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
1664 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
1666 if (fDescriptor->activate != nullptr)
1668 try {
1669 fDescriptor->activate(fHandle);
1670 } catch(...) {}
1672 if (fHandle2 != nullptr)
1674 try {
1675 fDescriptor->activate(fHandle2);
1676 } catch(...) {}
1681 void deactivate() noexcept override
1683 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
1684 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
1686 if (fDescriptor->deactivate != nullptr)
1688 try {
1689 fDescriptor->deactivate(fHandle);
1690 } catch(...) {}
1692 if (fHandle2 != nullptr)
1694 try {
1695 fDescriptor->deactivate(fHandle2);
1696 } catch(...) {}
1701 EngineEvent& findNextEvent()
1703 if (fMidiIn.count == 1)
1705 NativePluginMidiInData::MultiPortData& multiportData(fMidiIn.multiportData[0]);
1707 if (multiportData.usedIndex == multiportData.cachedEventCount)
1709 const uint32_t eventCount = pData->event.portIn->getEventCount();
1710 CARLA_SAFE_ASSERT_INT2(eventCount == multiportData.cachedEventCount,
1711 eventCount, multiportData.cachedEventCount);
1712 return kNullEngineEvent;
1715 return pData->event.portIn->getEvent(multiportData.usedIndex++);
1718 uint32_t lowestSampleTime = 9999999;
1719 uint32_t portMatching = 0;
1720 bool found = false;
1722 // process events in order for multiple ports
1723 for (uint32_t m=0; m < fMidiIn.count; ++m)
1725 CarlaEngineEventPort* const eventPort(fMidiIn.ports[m]);
1726 NativePluginMidiInData::MultiPortData& multiportData(fMidiIn.multiportData[m]);
1728 if (multiportData.usedIndex == multiportData.cachedEventCount)
1729 continue;
1731 const EngineEvent& event(eventPort->getEventUnchecked(multiportData.usedIndex));
1733 if (event.time < lowestSampleTime)
1735 lowestSampleTime = event.time;
1736 portMatching = m;
1737 found = true;
1741 if (found)
1743 CarlaEngineEventPort* const eventPort(fMidiIn.ports[portMatching]);
1744 NativePluginMidiInData::MultiPortData& multiportData(fMidiIn.multiportData[portMatching]);
1746 return eventPort->getEvent(multiportData.usedIndex++);
1749 return kNullEngineEvent;
1752 void process(const float* const* const audioIn, float** const audioOut,
1753 const float* const* const cvIn, float** const cvOut, const uint32_t frames) override
1755 // --------------------------------------------------------------------------------------------------------
1756 // Check if active
1758 if (! pData->active)
1760 // disable any output sound
1761 for (uint32_t i=0; i < pData->audioOut.count; ++i)
1762 carla_zeroFloats(audioOut[i], frames);
1763 for (uint32_t i=0; i < pData->cvOut.count; ++i)
1764 carla_zeroFloats(cvOut[i], frames);
1765 return;
1768 fMidiEventInCount = fMidiEventOutCount = 0;
1769 carla_zeroStructs(fMidiInEvents, kPluginMaxMidiEvents);
1770 carla_zeroStructs(fMidiOutEvents, kPluginMaxMidiEvents);
1772 // --------------------------------------------------------------------------------------------------------
1773 // Check if needs reset
1775 if (pData->needsReset)
1777 if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
1779 fMidiEventInCount = MAX_MIDI_CHANNELS*2;
1781 for (uint8_t k=0, i=MAX_MIDI_CHANNELS; k < MAX_MIDI_CHANNELS; ++k)
1783 fMidiInEvents[k].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT));
1784 fMidiInEvents[k].data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
1785 fMidiInEvents[k].data[2] = 0;
1786 fMidiInEvents[k].size = 3;
1788 fMidiInEvents[k+i].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT));
1789 fMidiInEvents[k+i].data[1] = MIDI_CONTROL_ALL_SOUND_OFF;
1790 fMidiInEvents[k+i].data[2] = 0;
1791 fMidiInEvents[k+i].size = 3;
1794 else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS)
1796 fMidiEventInCount = MAX_MIDI_NOTE;
1798 for (uint8_t k=0; k < MAX_MIDI_NOTE; ++k)
1800 fMidiInEvents[k].data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT));
1801 fMidiInEvents[k].data[1] = k;
1802 fMidiInEvents[k].data[2] = 0;
1803 fMidiInEvents[k].size = 3;
1807 pData->needsReset = false;
1810 // --------------------------------------------------------------------------------------------------------
1811 // Set TimeInfo
1813 const EngineTimeInfo timeInfo(pData->engine->getTimeInfo());
1815 fTimeInfo.playing = timeInfo.playing;
1816 fTimeInfo.frame = timeInfo.frame;
1817 fTimeInfo.usecs = timeInfo.usecs;
1819 if (timeInfo.bbt.valid)
1821 fTimeInfo.bbt.valid = true;
1823 fTimeInfo.bbt.bar = timeInfo.bbt.bar;
1824 fTimeInfo.bbt.beat = timeInfo.bbt.beat;
1825 fTimeInfo.bbt.tick = timeInfo.bbt.tick;
1826 fTimeInfo.bbt.barStartTick = timeInfo.bbt.barStartTick;
1828 fTimeInfo.bbt.beatsPerBar = timeInfo.bbt.beatsPerBar;
1829 fTimeInfo.bbt.beatType = timeInfo.bbt.beatType;
1831 fTimeInfo.bbt.ticksPerBeat = timeInfo.bbt.ticksPerBeat;
1832 fTimeInfo.bbt.beatsPerMinute = timeInfo.bbt.beatsPerMinute;
1834 else
1836 fTimeInfo.bbt.valid = false;
1839 #if 0
1840 // This test code has proven to be quite useful
1841 // So I am leaving it behind, I might need it again..
1842 if (pData->id == 1)
1844 static int64_t last_frame = timeInfo.frame;
1845 static int64_t last_dev_frame = 0;
1846 static double last_val = timeInfo.bbt.barStartTick + ((timeInfo.bbt.beat-1) * timeInfo.bbt.ticksPerBeat) + timeInfo.bbt.tick;
1847 static double last_dev_val = 0.0;
1849 int64_t cur_frame = timeInfo.frame;
1850 int64_t cur_dev_frame = cur_frame - last_frame;
1852 double cur_val = timeInfo.bbt.barStartTick + ((timeInfo.bbt.beat-1) * timeInfo.bbt.ticksPerBeat) + timeInfo.bbt.tick;
1853 double cur_dev_val = cur_val - last_val;
1855 if (std::abs(last_dev_val - cur_dev_val) >= 0.0001 || last_dev_frame != cur_dev_frame)
1857 carla_stdout("currently %u at %u => %f : DEV1: %li : DEV2: %f",
1858 frames,
1859 timeInfo.frame,
1860 cur_val,
1861 cur_dev_frame,
1862 cur_dev_val);
1865 last_val = cur_val;
1866 last_dev_val = cur_dev_val;
1867 last_frame = cur_frame;
1868 last_dev_frame = cur_dev_frame;
1870 #endif
1872 // --------------------------------------------------------------------------------------------------------
1873 // Event Input and Processing
1875 if (pData->event.portIn != nullptr)
1877 // ----------------------------------------------------------------------------------------------------
1878 // MIDI Input (External)
1880 if (pData->extNotes.mutex.tryLock())
1882 ExternalMidiNote note = { 0, 0, 0 };
1884 for (; fMidiEventInCount < kPluginMaxMidiEvents && ! pData->extNotes.data.isEmpty();)
1886 note = pData->extNotes.data.getFirst(note, true);
1888 CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);
1890 NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
1892 nativeEvent.data[0] = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
1893 nativeEvent.data[1] = note.note;
1894 nativeEvent.data[2] = note.velo;
1895 nativeEvent.size = 3;
1898 pData->extNotes.mutex.unlock();
1900 } // End of MIDI Input (External)
1902 // ----------------------------------------------------------------------------------------------------
1903 // Event Input (System)
1905 #ifndef BUILD_BRIDGE
1906 bool allNotesOffSent = false;
1907 #endif
1908 const bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0;
1910 uint32_t startTime = 0;
1911 uint32_t timeOffset = 0;
1912 uint32_t nextBankId;
1914 if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
1915 nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
1916 else
1917 nextBankId = 0;
1919 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1920 if (cvIn != nullptr && pData->event.cvSourcePorts != nullptr)
1921 pData->event.cvSourcePorts->initPortBuffers(cvIn + pData->cvIn.count, frames, isSampleAccurate, pData->event.portIn);
1922 #endif
1924 for (;;)
1926 EngineEvent& event(findNextEvent());
1928 if (event.type == kEngineEventTypeNull)
1929 break;
1931 uint32_t eventTime = event.time;
1932 CARLA_SAFE_ASSERT_UINT2_CONTINUE(eventTime < frames, eventTime, frames);
1934 if (eventTime < timeOffset)
1936 carla_stderr2("Timing error, eventTime:%u < timeOffset:%u for '%s'",
1937 eventTime, timeOffset, pData->name);
1938 eventTime = timeOffset;
1941 if (isSampleAccurate && eventTime > timeOffset)
1943 if (processSingle(audioIn, audioOut, cvIn, cvOut, eventTime - timeOffset, timeOffset))
1945 startTime = 0;
1946 timeOffset = eventTime;
1948 if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
1949 nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
1950 else
1951 nextBankId = 0;
1953 if (fMidiEventInCount > 0)
1955 carla_zeroStructs(fMidiInEvents, fMidiEventInCount);
1956 fMidiEventInCount = 0;
1959 if (fMidiEventOutCount > 0)
1961 carla_zeroStructs(fMidiOutEvents, fMidiEventOutCount);
1962 fMidiEventOutCount = 0;
1965 else
1966 startTime += timeOffset;
1969 // Control change
1970 switch (event.type)
1972 case kEngineEventTypeNull:
1973 break;
1975 case kEngineEventTypeControl: {
1976 EngineControlEvent& ctrlEvent(event.ctrl);
1978 switch (ctrlEvent.type)
1980 case kEngineControlEventTypeNull:
1981 break;
1983 case kEngineControlEventTypeParameter: {
1984 float value;
1986 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1987 // non-midi
1988 if (event.channel == kEngineEventNonMidiChannel)
1990 const uint32_t k = ctrlEvent.param;
1991 CARLA_SAFE_ASSERT_CONTINUE(k < pData->param.count);
1993 ctrlEvent.handled = true;
1994 value = pData->param.getFinalUnnormalizedValue(k, ctrlEvent.normalizedValue);
1995 setParameterValueRT(k, value, event.time, true);
1996 continue;
1999 // Control backend stuff
2000 if (event.channel == pData->ctrlChannel)
2002 if (MIDI_IS_CONTROL_BREATH_CONTROLLER(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_DRYWET) > 0)
2004 ctrlEvent.handled = true;
2005 value = ctrlEvent.normalizedValue;
2006 setDryWetRT(value, true);
2008 else if (MIDI_IS_CONTROL_CHANNEL_VOLUME(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_VOLUME) > 0)
2010 ctrlEvent.handled = true;
2011 value = ctrlEvent.normalizedValue*127.0f/100.0f;
2012 setVolumeRT(value, true);
2014 else if (MIDI_IS_CONTROL_BALANCE(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_BALANCE) > 0)
2016 float left, right;
2017 value = ctrlEvent.normalizedValue/0.5f - 1.0f;
2019 if (value < 0.0f)
2021 left = -1.0f;
2022 right = (value*2.0f)+1.0f;
2024 else if (value > 0.0f)
2026 left = (value*2.0f)-1.0f;
2027 right = 1.0f;
2029 else
2031 left = -1.0f;
2032 right = 1.0f;
2035 ctrlEvent.handled = true;
2036 setBalanceLeftRT(left, true);
2037 setBalanceRightRT(right, true);
2040 #endif
2041 // Control plugin parameters
2042 for (uint32_t k=0; k < pData->param.count; ++k)
2044 if (pData->param.data[k].midiChannel != event.channel)
2045 continue;
2046 if (pData->param.data[k].mappedControlIndex != ctrlEvent.param)
2047 continue;
2048 if (pData->param.data[k].type != PARAMETER_INPUT)
2049 continue;
2050 if ((pData->param.data[k].hints & PARAMETER_IS_AUTOMATABLE) == 0)
2051 continue;
2053 ctrlEvent.handled = true;
2054 value = pData->param.getFinalUnnormalizedValue(k, ctrlEvent.normalizedValue);
2055 setParameterValueRT(k, value, event.time, true);
2058 if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param < MAX_MIDI_VALUE)
2060 if (fMidiEventInCount >= kPluginMaxMidiEvents)
2061 continue;
2063 NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
2064 carla_zeroStruct(nativeEvent);
2066 nativeEvent.time = isSampleAccurate ? startTime : eventTime;
2067 nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
2068 nativeEvent.data[1] = uint8_t(ctrlEvent.param);
2069 nativeEvent.data[2] = uint8_t(ctrlEvent.normalizedValue*127.0f + 0.5f);
2070 nativeEvent.size = 3;
2073 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2074 if (! ctrlEvent.handled)
2075 checkForMidiLearn(event);
2076 #endif
2077 break;
2078 } // case kEngineControlEventTypeParameter
2080 case kEngineControlEventTypeMidiBank:
2081 if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES)
2083 if (event.channel == pData->ctrlChannel)
2084 nextBankId = ctrlEvent.param;
2086 else if (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES)
2088 if (fMidiEventInCount >= kPluginMaxMidiEvents)
2089 continue;
2091 NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
2092 carla_zeroStruct(nativeEvent);
2094 nativeEvent.time = isSampleAccurate ? startTime : eventTime;
2095 nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
2096 nativeEvent.data[1] = MIDI_CONTROL_BANK_SELECT;
2097 nativeEvent.data[2] = uint8_t(ctrlEvent.param);
2098 nativeEvent.size = 3;
2100 break;
2102 case kEngineControlEventTypeMidiProgram:
2103 if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES)
2105 if (event.channel < MAX_MIDI_CHANNELS)
2107 const uint32_t nextProgramId(ctrlEvent.param);
2109 for (uint32_t k=0; k < pData->midiprog.count; ++k)
2111 if (pData->midiprog.data[k].bank == nextBankId && pData->midiprog.data[k].program == nextProgramId)
2113 fDescriptor->set_midi_program(fHandle, event.channel, nextBankId, nextProgramId);
2115 if (fHandle2 != nullptr)
2116 fDescriptor->set_midi_program(fHandle2, event.channel, nextBankId, nextProgramId);
2118 fCurMidiProgs[event.channel] = static_cast<int32_t>(k);
2120 if (event.channel == pData->ctrlChannel)
2122 pData->postponeMidiProgramChangeRtEvent(true, k);
2125 break;
2130 else if (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES)
2132 if (fMidiEventInCount >= kPluginMaxMidiEvents)
2133 continue;
2135 NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
2136 carla_zeroStruct(nativeEvent);
2138 nativeEvent.time = isSampleAccurate ? startTime : eventTime;
2139 nativeEvent.data[0] = uint8_t(MIDI_STATUS_PROGRAM_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
2140 nativeEvent.data[1] = uint8_t(ctrlEvent.param);
2141 nativeEvent.size = 2;
2143 break;
2145 case kEngineControlEventTypeAllSoundOff:
2146 if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
2148 if (fMidiEventInCount >= kPluginMaxMidiEvents)
2149 continue;
2151 NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
2152 carla_zeroStruct(nativeEvent);
2154 nativeEvent.time = isSampleAccurate ? startTime : eventTime;
2155 nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
2156 nativeEvent.data[1] = MIDI_CONTROL_ALL_SOUND_OFF;
2157 nativeEvent.data[2] = 0;
2158 nativeEvent.size = 3;
2160 break;
2162 case kEngineControlEventTypeAllNotesOff:
2163 if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
2165 #ifndef BUILD_BRIDGE
2166 if (event.channel == pData->ctrlChannel && ! allNotesOffSent)
2168 allNotesOffSent = true;
2169 postponeRtAllNotesOff();
2171 #endif
2173 if (fMidiEventInCount >= kPluginMaxMidiEvents)
2174 continue;
2176 NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
2177 carla_zeroStruct(nativeEvent);
2179 nativeEvent.time = isSampleAccurate ? startTime : eventTime;
2180 nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
2181 nativeEvent.data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
2182 nativeEvent.data[2] = 0;
2183 nativeEvent.size = 3;
2185 break;
2187 break;
2190 case kEngineEventTypeMidi: {
2191 if (fMidiEventInCount >= kPluginMaxMidiEvents)
2192 continue;
2194 const EngineMidiEvent& midiEvent(event.midi);
2196 if (midiEvent.size > 4)
2197 continue;
2198 #ifdef CARLA_PROPER_CPP11_SUPPORT
2199 static_assert(4 <= EngineMidiEvent::kDataSize, "Incorrect data");
2200 #endif
2202 uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
2204 if ((status == MIDI_STATUS_NOTE_OFF || status == MIDI_STATUS_NOTE_ON) && (pData->options & PLUGIN_OPTION_SKIP_SENDING_NOTES))
2205 continue;
2206 if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
2207 continue;
2208 if (status == MIDI_STATUS_CONTROL_CHANGE && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0)
2209 continue;
2210 if (status == MIDI_STATUS_POLYPHONIC_AFTERTOUCH && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0)
2211 continue;
2212 if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
2213 continue;
2215 // Fix bad note-off
2216 if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0)
2217 status = MIDI_STATUS_NOTE_OFF;
2219 NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
2220 carla_zeroStruct(nativeEvent);
2222 nativeEvent.port = midiEvent.port;
2223 nativeEvent.time = isSampleAccurate ? startTime : eventTime;
2224 nativeEvent.size = midiEvent.size;
2226 nativeEvent.data[0] = uint8_t(status | (event.channel & MIDI_CHANNEL_BIT));
2227 nativeEvent.data[1] = midiEvent.size >= 2 ? midiEvent.data[1] : 0;
2228 nativeEvent.data[2] = midiEvent.size >= 3 ? midiEvent.data[2] : 0;
2229 nativeEvent.data[3] = midiEvent.size == 4 ? midiEvent.data[3] : 0;
2231 if (status == MIDI_STATUS_NOTE_ON)
2233 pData->postponeNoteOnRtEvent(true, event.channel, midiEvent.data[1], midiEvent.data[2]);
2235 else if (status == MIDI_STATUS_NOTE_OFF)
2237 pData->postponeNoteOffRtEvent(true, event.channel, midiEvent.data[1]);
2239 } break;
2240 } // switch (event.type)
2243 pData->postRtEvents.trySplice();
2245 if (frames > timeOffset)
2246 processSingle(audioIn, audioOut, cvIn, cvOut, frames - timeOffset, timeOffset);
2248 } // End of Event Input and Processing
2250 // --------------------------------------------------------------------------------------------------------
2251 // Plugin processing (no events)
2253 else
2255 processSingle(audioIn, audioOut, cvIn, cvOut, frames, 0);
2257 } // End of Plugin processing (no events)
2259 #ifndef BUILD_BRIDGE
2260 // --------------------------------------------------------------------------------------------------------
2261 // Control Output
2263 if (pData->event.portOut != nullptr)
2265 float value, curValue;
2267 for (uint32_t k=0; k < pData->param.count; ++k)
2269 if (pData->param.data[k].type != PARAMETER_OUTPUT)
2270 continue;
2272 curValue = fDescriptor->get_parameter_value(fHandle, k);
2273 pData->param.ranges[k].fixValue(curValue);
2275 if (pData->param.data[k].mappedControlIndex > 0)
2277 value = pData->param.ranges[k].getNormalizedValue(curValue);
2278 pData->event.portOut->writeControlEvent(0,
2279 pData->param.data[k].midiChannel,
2280 kEngineControlEventTypeParameter,
2281 static_cast<uint16_t>(pData->param.data[k].mappedControlIndex),
2283 value);
2286 } // End of Control Output
2287 #endif
2290 bool processSingle(const float* const* const audioIn, float** const audioOut,
2291 const float* const* const cvIn, float** const cvOut,
2292 const uint32_t frames, const uint32_t timeOffset)
2294 CARLA_SAFE_ASSERT_RETURN(frames > 0, false);
2296 if (pData->audioIn.count > 0) {
2297 CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false);
2299 if (pData->audioOut.count > 0) {
2300 CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr, false);
2302 if (pData->cvIn.count > 0) {
2303 CARLA_SAFE_ASSERT_RETURN(cvIn != nullptr, false);
2305 if (pData->cvOut.count > 0) {
2306 CARLA_SAFE_ASSERT_RETURN(cvOut != nullptr, false);
2309 // --------------------------------------------------------------------------------------------------------
2310 // Try lock, silence otherwise
2312 if (fIsOffline)
2314 pData->singleMutex.lock();
2316 else if (! pData->singleMutex.tryLock())
2318 for (uint32_t i=0; i < pData->audioOut.count; ++i)
2320 for (uint32_t k=0; k < frames; ++k)
2321 audioOut[i][k+timeOffset] = 0.0f;
2323 for (uint32_t i=0; i < pData->cvOut.count; ++i)
2325 for (uint32_t k=0; k < frames; ++k)
2326 cvOut[i][k+timeOffset] = 0.0f;
2329 return false;
2332 // --------------------------------------------------------------------------------------------------------
2333 // Set audio buffers
2336 for (uint32_t i=0; i < pData->audioIn.count; ++i)
2337 carla_copyFloats(fAudioAndCvInBuffers[i], audioIn[i]+timeOffset, frames);
2338 for (uint32_t i=0; i < pData->cvIn.count; ++i)
2339 carla_copyFloats(fAudioAndCvInBuffers[pData->audioIn.count+i], cvIn[i]+timeOffset, frames);
2341 for (uint32_t i=0; i < pData->audioOut.count; ++i)
2342 carla_zeroFloats(fAudioAndCvOutBuffers[i], frames);
2343 for (uint32_t i=0; i < pData->cvOut.count; ++i)
2344 carla_zeroFloats(fAudioAndCvOutBuffers[pData->audioOut.count+i], frames);
2347 // --------------------------------------------------------------------------------------------------------
2348 // Run plugin
2350 fIsProcessing = true;
2352 if (fHandle2 == nullptr)
2354 fDescriptor->process(fHandle,
2355 fAudioAndCvInBuffers, fAudioAndCvOutBuffers, frames,
2356 fMidiInEvents, fMidiEventInCount);
2358 else
2360 fDescriptor->process(fHandle,
2361 (fAudioAndCvInBuffers != nullptr) ? &fAudioAndCvInBuffers[0] : nullptr,
2362 (fAudioAndCvOutBuffers != nullptr) ? &fAudioAndCvOutBuffers[0] : nullptr,
2363 frames, fMidiInEvents, fMidiEventInCount);
2365 fDescriptor->process(fHandle2,
2366 (fAudioAndCvInBuffers != nullptr) ? &fAudioAndCvInBuffers[1] : nullptr,
2367 (fAudioAndCvOutBuffers != nullptr) ? &fAudioAndCvOutBuffers[1] : nullptr,
2368 frames, fMidiInEvents, fMidiEventInCount);
2371 fIsProcessing = false;
2373 if (fTimeInfo.playing)
2374 fTimeInfo.frame += frames;
2376 uint32_t i=0;
2377 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2378 // --------------------------------------------------------------------------------------------------------
2379 // Post-processing (dry/wet, volume and balance)
2382 const bool doDryWet = (pData->hints & PLUGIN_CAN_DRYWET) != 0 && carla_isNotEqual(pData->postProc.dryWet, 1.0f);
2383 const bool doBalance = (pData->hints & PLUGIN_CAN_BALANCE) != 0 && ! (carla_isEqual(pData->postProc.balanceLeft, -1.0f) && carla_isEqual(pData->postProc.balanceRight, 1.0f));
2385 bool isPair;
2386 float bufValue;
2387 float* const oldBufLeft = pData->postProc.extraBuffer;
2389 for (; i < pData->audioOut.count; ++i)
2391 // Dry/Wet
2392 if (doDryWet)
2394 for (uint32_t k=0; k < frames; ++k)
2396 bufValue = fAudioAndCvInBuffers[(pData->audioIn.count == 1) ? 0 : i][k];
2397 fAudioAndCvOutBuffers[i][k] = (fAudioAndCvOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet));
2401 // Balance
2402 if (doBalance)
2404 isPair = (i % 2 == 0);
2406 if (isPair)
2408 CARLA_ASSERT(i+1 < pData->audioOut.count);
2409 carla_copyFloats(oldBufLeft, fAudioAndCvOutBuffers[i], frames);
2412 float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f;
2413 float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f;
2415 for (uint32_t k=0; k < frames; ++k)
2417 if (isPair)
2419 // left
2420 fAudioAndCvOutBuffers[i][k] = oldBufLeft[k] * (1.0f - balRangeL);
2421 fAudioAndCvOutBuffers[i][k] += fAudioAndCvOutBuffers[i+1][k] * (1.0f - balRangeR);
2423 else
2425 // right
2426 fAudioAndCvOutBuffers[i][k] = fAudioAndCvOutBuffers[i][k] * balRangeR;
2427 fAudioAndCvOutBuffers[i][k] += oldBufLeft[k] * balRangeL;
2432 // Volume (and buffer copy)
2434 for (uint32_t k=0; k < frames; ++k)
2435 audioOut[i][k+timeOffset] = fAudioAndCvOutBuffers[i][k] * pData->postProc.volume;
2439 } // End of Post-processing
2440 #else
2441 for (; i < pData->audioOut.count; ++i)
2443 for (uint32_t k=0; k < frames; ++k)
2444 audioOut[i][k+timeOffset] = fAudioAndCvOutBuffers[i][k];
2446 #endif
2447 // CV stuff too
2448 for (; i < pData->cvOut.count; ++i)
2450 for (uint32_t k=0; k < frames; ++k)
2451 cvOut[i][k+timeOffset] = fAudioAndCvOutBuffers[pData->audioOut.count+i][k];
2454 // --------------------------------------------------------------------------------------------------------
2455 // MIDI Output
2457 if (pData->event.portOut != nullptr)
2459 for (uint32_t k = 0; k < fMidiEventOutCount; ++k)
2461 const uint8_t channel = uint8_t(MIDI_GET_CHANNEL_FROM_DATA(fMidiOutEvents[k].data));
2462 const uint8_t port = fMidiOutEvents[k].port;
2464 if (fMidiOut.count > 1 && port < fMidiOut.count)
2465 fMidiOut.ports[port]->writeMidiEvent(fMidiOutEvents[k].time+timeOffset, channel, fMidiOutEvents[k].size, fMidiOutEvents[k].data);
2466 else
2467 pData->event.portOut->writeMidiEvent(fMidiOutEvents[k].time+timeOffset, channel, fMidiOutEvents[k].size, fMidiOutEvents[k].data);
2471 // --------------------------------------------------------------------------------------------------------
2473 pData->singleMutex.unlock();
2474 return true;
2477 void bufferSizeChanged(const uint32_t newBufferSize) override
2479 CARLA_ASSERT_INT(newBufferSize > 0, newBufferSize);
2480 carla_debug("CarlaPluginNative::bufferSizeChanged(%i)", newBufferSize);
2482 for (uint32_t i=0; i < (pData->audioIn.count+pData->cvIn.count); ++i)
2484 if (fAudioAndCvInBuffers[i] != nullptr)
2485 delete[] fAudioAndCvInBuffers[i];
2486 fAudioAndCvInBuffers[i] = new float[newBufferSize];
2489 for (uint32_t i=0; i < (pData->audioOut.count+pData->cvOut.count); ++i)
2491 if (fAudioAndCvOutBuffers[i] != nullptr)
2492 delete[] fAudioAndCvOutBuffers[i];
2493 fAudioAndCvOutBuffers[i] = new float[newBufferSize];
2496 if (fCurBufferSize != newBufferSize)
2498 fCurBufferSize = newBufferSize;
2500 if (fDescriptor != nullptr && fDescriptor->dispatcher != nullptr)
2502 fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, static_cast<intptr_t>(newBufferSize), nullptr, 0.0f);
2504 if (fHandle2 != nullptr)
2505 fDescriptor->dispatcher(fHandle2, NATIVE_PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, static_cast<intptr_t>(newBufferSize), nullptr, 0.0f);
2509 CarlaPlugin::bufferSizeChanged(newBufferSize);
2512 void sampleRateChanged(const double newSampleRate) override
2514 CARLA_ASSERT_INT(newSampleRate > 0.0, newSampleRate);
2515 carla_debug("CarlaPluginNative::sampleRateChanged(%g)", newSampleRate);
2517 if (carla_isEqual(fCurSampleRate, newSampleRate))
2518 return;
2520 fCurSampleRate = newSampleRate;
2522 if (fDescriptor != nullptr && fDescriptor->dispatcher != nullptr)
2524 fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, float(newSampleRate));
2526 if (fHandle2 != nullptr)
2527 fDescriptor->dispatcher(fHandle2, NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, float(newSampleRate));
2531 void offlineModeChanged(const bool isOffline) override
2533 if (fIsOffline == isOffline)
2534 return;
2536 fIsOffline = isOffline;
2538 if (fDescriptor != nullptr && fDescriptor->dispatcher != nullptr)
2540 fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_OFFLINE_CHANGED, 0, isOffline ? 1 : 0, nullptr, 0.0f);
2542 if (fHandle2 != nullptr)
2543 fDescriptor->dispatcher(fHandle2, NATIVE_PLUGIN_OPCODE_OFFLINE_CHANGED, 0, isOffline ? 1 : 0, nullptr, 0.0f);
2547 // -------------------------------------------------------------------
2548 // Plugin buffers
2550 void initBuffers() const noexcept override
2552 CarlaPlugin::initBuffers();
2554 fMidiIn.initBuffers(pData->event.portIn);
2555 fMidiOut.initBuffers();
2558 void clearBuffers() noexcept override
2560 carla_debug("CarlaPluginNative::clearBuffers() - start");
2562 if (fAudioAndCvInBuffers != nullptr)
2564 for (uint32_t i=0; i < (pData->audioIn.count+pData->cvIn.count); ++i)
2566 if (fAudioAndCvInBuffers[i] != nullptr)
2568 delete[] fAudioAndCvInBuffers[i];
2569 fAudioAndCvInBuffers[i] = nullptr;
2573 delete[] fAudioAndCvInBuffers;
2574 fAudioAndCvInBuffers = nullptr;
2577 if (fAudioAndCvOutBuffers != nullptr)
2579 for (uint32_t i=0; i < (pData->audioOut.count+pData->cvOut.count); ++i)
2581 if (fAudioAndCvOutBuffers[i] != nullptr)
2583 delete[] fAudioAndCvOutBuffers[i];
2584 fAudioAndCvOutBuffers[i] = nullptr;
2588 delete[] fAudioAndCvOutBuffers;
2589 fAudioAndCvOutBuffers = nullptr;
2592 if (fMidiIn.count > 1)
2593 pData->event.portIn = nullptr;
2595 if (fMidiOut.count > 1)
2596 pData->event.portOut = nullptr;
2598 fMidiIn.clear();
2599 fMidiOut.clear();
2601 CarlaPlugin::clearBuffers();
2603 carla_debug("CarlaPluginNative::clearBuffers() - end");
2606 // -------------------------------------------------------------------
2607 // Post-poned UI Stuff
2609 void uiParameterChange(const uint32_t index, const float value) noexcept override
2611 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
2612 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
2613 CARLA_SAFE_ASSERT_RETURN(index < pData->param.count,);
2615 if (! fIsUiVisible)
2616 return;
2618 if (fDescriptor->ui_set_parameter_value != nullptr)
2619 fDescriptor->ui_set_parameter_value(fHandle, index, value);
2622 void uiMidiProgramChange(const uint32_t index) noexcept override
2624 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
2625 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
2626 CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count,);
2628 if (! fIsUiVisible)
2629 return;
2630 if (index >= pData->midiprog.count)
2631 return;
2633 if (fDescriptor->ui_set_midi_program != nullptr)
2634 fDescriptor->ui_set_midi_program(fHandle, 0, pData->midiprog.data[index].bank, pData->midiprog.data[index].program);
2637 void uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept override
2639 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
2640 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
2641 CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2642 CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2643 CARLA_SAFE_ASSERT_RETURN(velo > 0 && velo < MAX_MIDI_VALUE,);
2645 if (! fIsUiVisible)
2646 return;
2648 if (fDescriptor->dispatcher != nullptr)
2650 uint8_t data[3] = {
2651 uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT)),
2652 note,
2653 velo
2655 fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_UI_MIDI_EVENT,
2656 3, 0,
2657 data,
2658 0.0f);
2662 void uiNoteOff(const uint8_t channel, const uint8_t note) noexcept override
2664 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
2665 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
2666 CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2667 CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2669 if (! fIsUiVisible)
2670 return;
2671 if (fDescriptor == nullptr || fHandle == nullptr)
2672 return;
2674 if (fDescriptor->dispatcher != nullptr)
2676 uint8_t data[3] = {
2677 uint8_t(MIDI_STATUS_NOTE_OFF | (channel & MIDI_CHANNEL_BIT)),
2678 note,
2681 fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_UI_MIDI_EVENT,
2682 3, 0,
2683 data,
2684 0.0f);
2688 // -------------------------------------------------------------------
2690 const NativeInlineDisplayImageSurface* renderInlineDisplay(const uint32_t width, const uint32_t height) const
2692 CARLA_SAFE_ASSERT_RETURN(fDescriptor->hints & NATIVE_PLUGIN_HAS_INLINE_DISPLAY, nullptr);
2693 CARLA_SAFE_ASSERT_RETURN(fDescriptor->render_inline_display, nullptr);
2694 CARLA_SAFE_ASSERT_RETURN(width > 0, nullptr);
2695 CARLA_SAFE_ASSERT_RETURN(height > 0, nullptr);
2697 return fDescriptor->render_inline_display(fHandle, width, height);
2700 // -------------------------------------------------------------------
2702 protected:
2703 const NativeTimeInfo* handleGetTimeInfo() const noexcept
2705 CARLA_SAFE_ASSERT_RETURN(fIsProcessing, nullptr);
2707 return &fTimeInfo;
2710 bool handleWriteMidiEvent(const NativeMidiEvent* const event)
2712 CARLA_SAFE_ASSERT_RETURN(pData->enabled, false);
2713 CARLA_SAFE_ASSERT_RETURN(fIsProcessing, false);
2714 CARLA_SAFE_ASSERT_RETURN(fMidiOut.count > 0 || pData->event.portOut != nullptr, false);
2715 CARLA_SAFE_ASSERT_RETURN(event != nullptr, false);
2716 CARLA_SAFE_ASSERT_RETURN(event->data[0] != 0, false);
2718 if (fMidiEventOutCount == kPluginMaxMidiEvents)
2720 carla_stdout("CarlaPluginNative::handleWriteMidiEvent(%p) - buffer full", event);
2721 return false;
2724 std::memcpy(&fMidiOutEvents[fMidiEventOutCount++], event, sizeof(NativeMidiEvent));
2725 return true;
2728 void handleUiParameterChanged(const uint32_t index, const float value)
2730 setParameterValue(index, value, false, true, true);
2733 void handleUiCustomDataChanged(const char* const key, const char* const value)
2735 setCustomData(CUSTOM_DATA_TYPE_STRING, key, value, false);
2738 void handleUiClosed()
2740 pData->engine->callback(true, true, ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0, 0.0f, nullptr);
2741 fIsUiVisible = false;
2744 const char* handleUiOpenFile(const bool isDir, const char* const title, const char* const filter)
2746 return pData->engine->runFileCallback(FILE_CALLBACK_OPEN, isDir, title, filter);
2749 const char* handleUiSaveFile(const bool isDir, const char* const title, const char* const filter)
2751 return pData->engine->runFileCallback(FILE_CALLBACK_SAVE, isDir, title, filter);
2754 intptr_t handleDispatcher(const NativeHostDispatcherOpcode opcode,
2755 const int32_t index, const intptr_t value, void* const ptr, const float opt)
2757 #ifdef DEBUG
2758 if (opcode != NATIVE_HOST_OPCODE_QUEUE_INLINE_DISPLAY && opcode != NATIVE_HOST_OPCODE_REQUEST_IDLE) {
2759 carla_debug("CarlaPluginNative::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)",
2760 opcode, index, value, ptr, static_cast<double>(opt));
2762 #endif
2764 switch (opcode)
2766 case NATIVE_HOST_OPCODE_NULL:
2767 break;
2769 case NATIVE_HOST_OPCODE_UPDATE_PARAMETER:
2770 // TODO
2771 pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, -1, 0, 0, 0.0f, nullptr);
2772 break;
2774 case NATIVE_HOST_OPCODE_UPDATE_MIDI_PROGRAM:
2775 // TODO
2776 pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, -1, 0, 0, 0.0f, nullptr);
2777 break;
2779 case NATIVE_HOST_OPCODE_RELOAD_PARAMETERS:
2780 reloadParameters(nullptr, nullptr);
2781 pData->engine->callback(true, true, ENGINE_CALLBACK_RELOAD_PARAMETERS, pData->id, -1, 0, 0, 0.0f, nullptr);
2782 break;
2784 case NATIVE_HOST_OPCODE_RELOAD_MIDI_PROGRAMS:
2785 reloadPrograms(false);
2786 pData->engine->callback(true, true, ENGINE_CALLBACK_RELOAD_PROGRAMS, pData->id, -1, 0, 0, 0.0f, nullptr);
2787 break;
2789 case NATIVE_HOST_OPCODE_RELOAD_ALL:
2790 reload();
2791 pData->engine->callback(true, true, ENGINE_CALLBACK_RELOAD_ALL, pData->id, -1, 0, 0, 0.0f, nullptr);
2792 break;
2794 case NATIVE_HOST_OPCODE_UI_UNAVAILABLE:
2795 pData->engine->callback(true, true, ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, -1, 0, 0, 0.0f, nullptr);
2796 fIsUiAvailable = false;
2797 break;
2799 case NATIVE_HOST_OPCODE_HOST_IDLE:
2800 pData->engine->callback(true, false, ENGINE_CALLBACK_IDLE, 0, 0, 0, 0, 0.0f, nullptr);
2801 break;
2803 case NATIVE_HOST_OPCODE_INTERNAL_PLUGIN:
2804 return 1;
2806 case NATIVE_HOST_OPCODE_QUEUE_INLINE_DISPLAY:
2807 switch (pData->engine->getProccessMode())
2809 case ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS:
2810 case ENGINE_PROCESS_MODE_PATCHBAY:
2811 fInlineDisplayNeedsRedraw = true;
2812 break;
2813 default:
2814 break;
2816 break;
2818 case NATIVE_HOST_OPCODE_UI_TOUCH_PARAMETER:
2819 CARLA_SAFE_ASSERT_RETURN(index >= 0, 0);
2820 pData->engine->touchPluginParameter(pData->id, static_cast<uint32_t>(index), value != 0);
2821 break;
2823 case NATIVE_HOST_OPCODE_REQUEST_IDLE:
2824 fNeedsIdle = true;
2825 break;
2827 case NATIVE_HOST_OPCODE_GET_FILE_PATH:
2828 CARLA_SAFE_ASSERT_RETURN(ptr != nullptr, 0);
2830 const EngineOptions& opts(pData->engine->getOptions());
2831 const char* const filetype = (const char*)ptr;
2832 const char* ret = nullptr;
2834 if (std::strcmp(filetype, "carla") == 0)
2836 ret = pData->engine->getCurrentProjectFilename();
2838 if (fLastProjectFilename != ret)
2840 fLastProjectFilename = ret;
2842 bool found;
2843 const size_t r = fLastProjectFilename.rfind(CARLA_OS_SEP, &found);
2844 if (found)
2846 fLastProjectFolder = ret;
2847 fLastProjectFolder[r] = '\0';
2849 else
2851 fLastProjectFolder.clear();
2855 ret = fLastProjectFolder.buffer();
2858 else if (std::strcmp(filetype, "audio") == 0)
2859 ret = opts.pathAudio;
2860 else if (std::strcmp(filetype, "midi") == 0)
2861 ret = opts.pathMIDI;
2863 return static_cast<intptr_t>((uintptr_t)ret);
2865 break;
2867 case NATIVE_HOST_OPCODE_UI_RESIZE:
2868 case NATIVE_HOST_OPCODE_PREVIEW_BUFFER_DATA:
2869 // unused here
2870 break;
2873 return 0;
2875 // unused for now
2876 (void)opt;
2879 // -------------------------------------------------------------------
2881 public:
2882 void* getNativeHandle() const noexcept override
2884 return fHandle;
2887 const void* getNativeDescriptor() const noexcept override
2889 return fDescriptor;
2892 // -------------------------------------------------------------------
2894 bool init(const CarlaPluginPtr plugin,
2895 const char* const name, const char* const label, const uint options)
2897 CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);
2899 // ---------------------------------------------------------------
2900 // first checks
2902 if (pData->client != nullptr)
2904 pData->engine->setLastError("Plugin client is already registered");
2905 return false;
2908 if (label == nullptr || label[0] == '\0')
2910 pData->engine->setLastError("null label");
2911 return false;
2914 // ---------------------------------------------------------------
2915 // get descriptor that matches label
2917 sPluginInitializer.initIfNeeded();
2919 for (LinkedList<const NativePluginDescriptor*>::Itenerator it = gPluginDescriptors.begin2(); it.valid(); it.next())
2921 fDescriptor = it.getValue(nullptr);
2922 CARLA_SAFE_ASSERT_BREAK(fDescriptor != nullptr);
2924 carla_debug("Check vs \"%s\"", fDescriptor->label);
2926 if (fDescriptor->label != nullptr && std::strcmp(fDescriptor->label, label) == 0)
2927 break;
2929 fDescriptor = nullptr;
2932 if (fDescriptor == nullptr)
2934 pData->engine->setLastError("Invalid internal plugin");
2935 return false;
2938 // ---------------------------------------------------------------
2939 // set icon
2941 /**/ if (std::strcmp(fDescriptor->label, "audiofile") == 0)
2942 pData->iconName = carla_strdup_safe("file");
2943 else if (std::strcmp(fDescriptor->label, "midifile") == 0)
2944 pData->iconName = carla_strdup_safe("file");
2946 else if (std::strcmp(fDescriptor->label, "3bandeq") == 0)
2947 pData->iconName = carla_strdup_safe("distrho");
2948 else if (std::strcmp(fDescriptor->label, "3bandsplitter") == 0)
2949 pData->iconName = carla_strdup_safe("distrho");
2950 else if (std::strcmp(fDescriptor->label, "kars") == 0)
2951 pData->iconName = carla_strdup_safe("distrho");
2952 else if (std::strcmp(fDescriptor->label, "nekobi") == 0)
2953 pData->iconName = carla_strdup_safe("distrho");
2954 else if (std::strcmp(fDescriptor->label, "pingpongpan") == 0)
2955 pData->iconName = carla_strdup_safe("distrho");
2957 // ---------------------------------------------------------------
2958 // set info
2960 if (name != nullptr && name[0] != '\0')
2961 pData->name = pData->engine->getUniquePluginName(name);
2962 else if (fDescriptor->name != nullptr && fDescriptor->name[0] != '\0')
2963 pData->name = pData->engine->getUniquePluginName(fDescriptor->name);
2964 else
2965 pData->name = pData->engine->getUniquePluginName(label);
2968 CARLA_ASSERT(fHost.uiName == nullptr);
2970 CarlaString uiName;
2972 if (pData->uiTitle.isNotEmpty())
2974 uiName = pData->uiTitle;
2976 else
2978 uiName = pData->name;
2979 uiName += " (GUI)";
2982 fHost.uiName = uiName.releaseBufferPointer();
2985 // ---------------------------------------------------------------
2986 // register client
2988 pData->client = pData->engine->addClient(plugin);
2990 if (pData->client == nullptr || ! pData->client->isOk())
2992 pData->engine->setLastError("Failed to register plugin client");
2993 return false;
2996 // ---------------------------------------------------------------
2997 // initialize plugin
2999 fHandle = fDescriptor->instantiate(&fHost);
3001 if (fHandle == nullptr)
3003 pData->engine->setLastError("Plugin failed to initialize");
3004 return false;
3007 // ---------------------------------------------------------------
3008 // set options
3010 bool hasMidiProgs = false;
3012 if (fDescriptor->get_midi_program_count != nullptr)
3014 try {
3015 hasMidiProgs = fDescriptor->get_midi_program_count(fHandle) > 0;
3016 } catch (...) {}
3019 pData->options = 0x0;
3021 if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS)
3022 pData->options |= PLUGIN_OPTION_FIXED_BUFFERS;
3023 else if (options & PLUGIN_OPTION_FIXED_BUFFERS)
3024 pData->options |= PLUGIN_OPTION_FIXED_BUFFERS;
3026 if (pData->engine->getOptions().forceStereo)
3027 pData->options |= PLUGIN_OPTION_FORCE_STEREO;
3028 else if (options & PLUGIN_OPTION_FORCE_STEREO)
3029 pData->options |= PLUGIN_OPTION_FORCE_STEREO;
3031 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES)
3032 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CONTROL_CHANGES))
3033 pData->options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
3035 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_CHANNEL_PRESSURE)
3036 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CHANNEL_PRESSURE))
3037 pData->options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
3039 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_NOTE_AFTERTOUCH)
3040 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH))
3041 pData->options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
3043 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_PITCHBEND)
3044 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PITCHBEND))
3045 pData->options |= PLUGIN_OPTION_SEND_PITCHBEND;
3047 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_ALL_SOUND_OFF)
3048 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_ALL_SOUND_OFF))
3049 pData->options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
3051 if (fDescriptor->midiIns > 0)
3052 if (isPluginOptionInverseEnabled(options, PLUGIN_OPTION_SKIP_SENDING_NOTES))
3053 pData->options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
3055 if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_PROGRAM_CHANGES)
3057 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PROGRAM_CHANGES))
3058 pData->options |= PLUGIN_OPTION_SEND_PROGRAM_CHANGES;
3060 // makes no sense for a plugin to set program changes supported, but it has no midi programs
3061 CARLA_SAFE_ASSERT(! hasMidiProgs);
3063 else if (hasMidiProgs)
3065 if (isPluginOptionEnabled(options, PLUGIN_OPTION_MAP_PROGRAM_CHANGES))
3066 pData->options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES;
3069 return true;
3073 private:
3074 NativePluginHandle fHandle;
3075 NativePluginHandle fHandle2;
3076 NativeHostDescriptor fHost;
3077 const NativePluginDescriptor* fDescriptor;
3079 bool fIsProcessing;
3080 bool fIsOffline;
3081 bool fIsUiAvailable;
3082 bool fIsUiVisible;
3083 volatile bool fNeedsIdle;
3085 bool fInlineDisplayNeedsRedraw;
3086 int64_t fInlineDisplayLastRedrawTime;
3088 CarlaString fLastProjectFilename;
3089 CarlaString fLastProjectFolder;
3091 float** fAudioAndCvInBuffers;
3092 float** fAudioAndCvOutBuffers;
3093 uint32_t fMidiEventInCount;
3094 uint32_t fMidiEventOutCount;
3095 NativeMidiEvent fMidiInEvents[kPluginMaxMidiEvents];
3096 NativeMidiEvent fMidiOutEvents[kPluginMaxMidiEvents];
3098 int32_t fCurMidiProgs[MAX_MIDI_CHANNELS];
3099 uint32_t fCurBufferSize;
3100 double fCurSampleRate;
3102 NativePluginMidiInData fMidiIn;
3103 NativePluginMidiOutData fMidiOut;
3105 NativeTimeInfo fTimeInfo;
3107 // -------------------------------------------------------------------
3109 #define handlePtr ((CarlaPluginNative*)handle)
3111 static uint32_t carla_host_get_buffer_size(NativeHostHandle handle) noexcept
3113 return handlePtr->fCurBufferSize;
3116 static double carla_host_get_sample_rate(NativeHostHandle handle) noexcept
3118 return handlePtr->fCurSampleRate;
3121 static bool carla_host_is_offline(NativeHostHandle handle) noexcept
3123 return handlePtr->fIsOffline;
3126 static const NativeTimeInfo* carla_host_get_time_info(NativeHostHandle handle) noexcept
3128 return handlePtr->handleGetTimeInfo();
3131 static bool carla_host_write_midi_event(NativeHostHandle handle, const NativeMidiEvent* event)
3133 return handlePtr->handleWriteMidiEvent(event);
3136 static void carla_host_ui_parameter_changed(NativeHostHandle handle, uint32_t index, float value)
3138 handlePtr->handleUiParameterChanged(index, value);
3141 static void carla_host_ui_custom_data_changed(NativeHostHandle handle, const char* key, const char* value)
3143 handlePtr->handleUiCustomDataChanged(key, value);
3146 static void carla_host_ui_closed(NativeHostHandle handle)
3148 handlePtr->handleUiClosed();
3151 static const char* carla_host_ui_open_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
3153 return handlePtr->handleUiOpenFile(isDir, title, filter);
3156 static const char* carla_host_ui_save_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
3158 return handlePtr->handleUiSaveFile(isDir, title, filter);
3161 static intptr_t carla_host_dispatcher(NativeHostHandle handle, NativeHostDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt)
3163 return handlePtr->handleDispatcher(opcode, index, value, ptr, opt);
3166 #undef handlePtr
3168 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginNative)
3171 // -----------------------------------------------------------------------
3173 CarlaPluginPtr CarlaPlugin::newNative(const Initializer& init)
3175 carla_debug("CarlaPlugin::newNative({%p, \"%s\", \"%s\", \"%s\", " P_INT64 "})",
3176 init.engine, init.filename, init.name, init.label, init.uniqueId);
3178 std::shared_ptr<CarlaPluginNative> plugin(new CarlaPluginNative(init.engine, init.id));
3180 if (! plugin->init(plugin, init.name, init.label, init.options))
3181 return nullptr;
3183 return plugin;
3186 // used in CarlaStandalone.cpp
3187 const void* carla_render_inline_display_internal(const CarlaPluginPtr& plugin, uint32_t width, uint32_t height);
3189 const void* carla_render_inline_display_internal(const CarlaPluginPtr& plugin, uint32_t width, uint32_t height)
3191 const std::shared_ptr<CarlaPluginNative>& nativePlugin((const std::shared_ptr<CarlaPluginNative>&)plugin);
3193 return nativePlugin->renderInlineDisplay(width, height);
3196 // -----------------------------------------------------------------------
3198 CARLA_BACKEND_END_NAMESPACE