Cleanup
[carla.git] / source / plugin / carla-lv2.cpp
blob32e90c402cc95ee89bbb3af956c88d138daa4040
1 /*
2 * Carla Native Plugins
3 * Copyright (C) 2013-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 #define CARLA_NATIVE_PLUGIN_LV2
19 #include "carla-base.cpp"
21 #include "CarlaLv2Utils.hpp"
22 #include "CarlaMathUtils.hpp"
23 #include "CarlaPipeUtils.hpp"
24 #include "CarlaString.hpp"
26 #include "water/files/File.h"
28 static const char* const kPathForCarlaFiles = "carlafiles";
30 template<>
31 void Lv2PluginBaseClass<NativeTimeInfo>::clearTimeData() noexcept
33 fLastPositionData.clear();
34 carla_zeroStruct(fTimeInfo);
37 struct PreviewData {
38 char type;
39 uint32_t size;
40 const void* buffer;
41 bool shouldSend;
43 PreviewData()
44 : type(0),
45 size(0),
46 buffer(nullptr),
47 shouldSend(false) {}
50 // --------------------------------------------------------------------------------------------------------------------
51 // Carla Internal Plugin API exposed as LV2 plugin
53 class NativePlugin : public Lv2PluginBaseClass<NativeTimeInfo>
55 public:
56 static const uint32_t kMaxMidiEvents = 512;
58 NativePlugin(const NativePluginDescriptor* const desc,
59 const double sampleRate,
60 const char* const bundlePath,
61 const LV2_Feature* const* const features)
62 : Lv2PluginBaseClass<NativeTimeInfo>(sampleRate, features),
63 fHandle(nullptr),
64 fHost(),
65 fDescriptor(desc),
66 #ifdef CARLA_PROPER_CPP11_SUPPORT
67 fProgramDesc({0, 0, nullptr}),
68 #endif
69 kIgnoreParameters(std::strncmp(desc->label, "carla", 5) == 0),
70 fAtomForge(),
71 fMidiEventCount(0),
72 fLastProjectPath(),
73 fLoadedFile(),
74 fPreviewData(),
75 fNeedsNotifyFileChanged(false),
76 fPluginNeedsIdle(0),
77 fWorkerUISignal(0)
79 carla_zeroStruct(fHost);
80 #ifndef CARLA_PROPER_CPP11_SUPPORT
81 carla_zeroStruct(fProgramDesc);
82 #endif
84 if (! loadedInProperHost())
85 return;
87 using water::File;
88 using water::String;
90 String resourceDir(water::File(bundlePath).getChildFile("resources").getFullPathName());
92 fHost.handle = this;
93 fHost.resourceDir = carla_strdup(resourceDir.toRawUTF8());
94 fHost.uiName = nullptr;
95 fHost.uiParentId = 0;
97 fHost.get_buffer_size = host_get_buffer_size;
98 fHost.get_sample_rate = host_get_sample_rate;
99 fHost.is_offline = host_is_offline;
100 fHost.get_time_info = host_get_time_info;
101 fHost.write_midi_event = host_write_midi_event;
102 fHost.ui_parameter_changed = host_ui_parameter_changed;
103 fHost.ui_custom_data_changed = host_ui_custom_data_changed;
104 fHost.ui_closed = host_ui_closed;
105 fHost.ui_open_file = host_ui_open_file;
106 fHost.ui_save_file = host_ui_save_file;
107 fHost.dispatcher = host_dispatcher;
109 carla_zeroStruct(fAtomForge);
110 lv2_atom_forge_init(&fAtomForge, fUridMap);
113 ~NativePlugin()
115 CARLA_SAFE_ASSERT(fHandle == nullptr);
117 if (fHost.resourceDir != nullptr)
119 delete[] fHost.resourceDir;
120 fHost.resourceDir = nullptr;
123 if (fHost.uiName != nullptr)
125 delete[] fHost.uiName;
126 fHost.uiName = nullptr;
130 // ----------------------------------------------------------------------------------------------------------------
132 bool init()
134 if (fHost.resourceDir == nullptr)
135 return false;
137 if (fDescriptor->instantiate == nullptr || fDescriptor->process == nullptr)
139 carla_stderr("Plugin is missing something...");
140 return false;
143 carla_zeroStructs(fMidiEvents, kMaxMidiEvents);
145 fHandle = fDescriptor->instantiate(&fHost);
146 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
148 fPorts.hasUI = fDescriptor->hints & NATIVE_PLUGIN_HAS_UI;
149 fPorts.usesTime = fDescriptor->hints & NATIVE_PLUGIN_USES_TIME;
150 fPorts.numAudioIns = fDescriptor->audioIns;
151 fPorts.numAudioOuts = fDescriptor->audioOuts;
152 fPorts.numCVIns = fDescriptor->cvIns;
153 fPorts.numCVOuts = fDescriptor->cvOuts;
154 fPorts.numMidiIns = fDescriptor->midiIns;
155 fPorts.numMidiOuts = fDescriptor->midiOuts;
157 if (fDescriptor->get_parameter_count != nullptr &&
158 fDescriptor->get_parameter_info != nullptr &&
159 fDescriptor->get_parameter_value != nullptr &&
160 fDescriptor->set_parameter_value != nullptr &&
161 ! kIgnoreParameters)
163 fPorts.numParams = fDescriptor->get_parameter_count(fHandle);
166 fPorts.init();
168 if (fPorts.numParams > 0)
170 for (uint32_t i=0; i < fPorts.numParams; ++i)
172 fPorts.paramsLast[i] = fDescriptor->get_parameter_value(fHandle, i);
173 fPorts.paramsOut [i] = fDescriptor->get_parameter_info(fHandle, i)->hints & NATIVE_PARAMETER_IS_OUTPUT;
177 return true;
180 // ----------------------------------------------------------------------------------------------------------------
181 // LV2 functions
183 void lv2_activate()
185 CARLA_SAFE_ASSERT_RETURN(! fIsActive,);
187 resetTimeInfo();
189 if (fDescriptor->activate != nullptr)
190 fDescriptor->activate(fHandle);
192 fIsActive = true;
195 void lv2_deactivate()
197 CARLA_SAFE_ASSERT_RETURN(fIsActive,);
199 fIsActive = false;
201 if (fDescriptor->deactivate != nullptr)
202 fDescriptor->deactivate(fHandle);
205 void lv2_cleanup()
207 if (fIsActive)
209 carla_stderr("Warning: Host forgot to call deactivate!");
210 fIsActive = false;
212 if (fDescriptor->deactivate != nullptr)
213 fDescriptor->deactivate(fHandle);
216 if (fDescriptor->cleanup != nullptr)
217 fDescriptor->cleanup(fHandle);
219 fHandle = nullptr;
222 // ----------------------------------------------------------------------------------------------------------------
224 void lv2_run(const uint32_t frames)
226 if (! lv2_pre_run(frames))
228 updateParameterOutputs();
229 return;
232 if (fPorts.numMidiIns > 0 || fPorts.hasUI)
234 uint32_t numEventPortsIn;
236 if (fPorts.numMidiIns > 0)
238 numEventPortsIn = fPorts.numMidiIns;
239 fMidiEventCount = 0;
240 carla_zeroStructs(fMidiEvents, kMaxMidiEvents);
242 else
244 numEventPortsIn = 1;
247 for (uint32_t i=0; i < numEventPortsIn; ++i)
249 const LV2_Atom_Sequence* const eventPortIn(fPorts.eventsIn[i]);
250 CARLA_SAFE_ASSERT_CONTINUE(eventPortIn != nullptr);
252 LV2_ATOM_SEQUENCE_FOREACH(eventPortIn, event)
254 if (event == nullptr)
255 continue;
257 if (event->body.type == fURIs.carlaUiEvents && fWorkerUISignal != -1)
259 CARLA_SAFE_ASSERT_CONTINUE((fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) == 0);
261 if (fWorker != nullptr)
263 // worker is supported by the host, we can continue
264 fWorkerUISignal = 1;
265 const char* const msg((const char*)(event + 1));
266 const size_t msgSize = std::strlen(msg);
267 fWorker->schedule_work(fWorker->handle, static_cast<uint32_t>(msgSize + 1U), msg);
269 else
271 // worker is not supported, cancel
272 fWorkerUISignal = -1;
274 continue;
277 if (event->body.type == fURIs.atomObject)
279 const LV2_Atom_Object* const obj = (const LV2_Atom_Object*)(&event->body);
281 if (obj->body.otype == fURIs.patchSet)
283 // Get property URI.
284 const LV2_Atom* property = nullptr;
285 lv2_atom_object_get(obj, fURIs.patchProperty, &property, 0);
286 CARLA_SAFE_ASSERT_CONTINUE(property != nullptr);
287 CARLA_SAFE_ASSERT_CONTINUE(property->type == fURIs.atomURID);
289 const LV2_URID urid = ((const LV2_Atom_URID*)property)->body;
291 /* */ if (std::strcmp(fDescriptor->label, "audiofile") == 0) {
292 CARLA_SAFE_ASSERT_CONTINUE(urid == fURIs.carlaFileAudio);
293 } else if (std::strcmp(fDescriptor->label, "midifile") == 0) {
294 CARLA_SAFE_ASSERT_CONTINUE(urid == fURIs.carlaFileMIDI);
295 } else {
296 CARLA_SAFE_ASSERT_CONTINUE(urid == fURIs.carlaFile);
299 // Get value.
300 const LV2_Atom* fileobj = nullptr;
301 lv2_atom_object_get(obj, fURIs.patchValue, &fileobj, 0);
302 CARLA_SAFE_ASSERT_CONTINUE(fileobj != nullptr);
303 CARLA_SAFE_ASSERT_CONTINUE(fileobj->type == fURIs.atomPath);
305 const char* const filepath((const char*)(fileobj + 1));
307 fWorker->schedule_work(fWorker->handle,
308 static_cast<uint32_t>(std::strlen(filepath) + 1U),
309 filepath);
311 else if (obj->body.otype == fURIs.patchGet)
313 if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
314 fNeedsNotifyFileChanged = true;
315 if (fPreviewData.buffer != nullptr)
316 fPreviewData.shouldSend = true;
318 continue;
321 if (event->body.type != fURIs.midiEvent)
322 continue;
324 // anything past this point assumes plugin with MIDI input
325 CARLA_SAFE_ASSERT_CONTINUE(fPorts.numMidiIns > 0);
327 if (event->body.size > 4)
328 continue;
329 if (event->time.frames >= frames)
330 break;
332 const uint8_t* const data((const uint8_t*)(event + 1));
334 NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]);
336 nativeEvent.port = (uint8_t)i;
337 nativeEvent.size = (uint8_t)event->body.size;
338 nativeEvent.time = (uint32_t)event->time.frames;
340 uint32_t j=0;
341 for (uint32_t size=event->body.size; j<size; ++j)
342 nativeEvent.data[j] = data[j];
343 for (; j<4; ++j)
344 nativeEvent.data[j] = 0;
346 if (fMidiEventCount >= kMaxMidiEvents)
347 break;
351 if (fNeedsNotifyFileChanged || fPreviewData.shouldSend)
353 uint8_t atomBuf[4096];
354 LV2_Atom* atom = (LV2_Atom*)atomBuf;
355 LV2_Atom_Sequence* const seq = fPorts.eventsOut[0];
356 Ports::EventsOutData& mData(fPorts.eventsOutData[0]);
358 if (fNeedsNotifyFileChanged)
360 fNeedsNotifyFileChanged = false;
362 LV2_Atom_Forge atomForge = fAtomForge;
363 lv2_atom_forge_set_buffer(&atomForge, atomBuf, sizeof(atomBuf));
365 LV2_Atom_Forge_Frame forgeFrame;
366 lv2_atom_forge_object(&atomForge, &forgeFrame, 0, fURIs.patchSet);
368 lv2_atom_forge_key(&atomForge, fURIs.patchProperty);
370 /* */ if (std::strcmp(fDescriptor->label, "audiofile") == 0) {
371 lv2_atom_forge_urid(&atomForge, fURIs.carlaFileAudio);
372 } else if (std::strcmp(fDescriptor->label, "midifile") == 0) {
373 lv2_atom_forge_urid(&atomForge, fURIs.carlaFileMIDI);
374 } else {
375 lv2_atom_forge_urid(&atomForge, fURIs.carlaFile);
378 lv2_atom_forge_key(&atomForge, fURIs.patchValue);
379 lv2_atom_forge_path(&atomForge,
380 fLoadedFile.buffer(),
381 static_cast<uint32_t>(fLoadedFile.length()+1));
383 lv2_atom_forge_pop(&atomForge, &forgeFrame);
385 if (sizeof(LV2_Atom_Event) + atom->size <= mData.capacity - mData.offset)
387 LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq) + mData.offset);
389 aev->time.frames = 0;
390 aev->body.size = atom->size;
391 aev->body.type = atom->type;
392 std::memcpy(LV2_ATOM_BODY(&aev->body), atom + 1, atom->size);
394 const uint32_t size = lv2_atom_pad_size(static_cast<uint32_t>(sizeof(LV2_Atom_Event) + atom->size));
395 mData.offset += size;
396 seq->atom.size += size;
400 if (fPreviewData.shouldSend)
402 const char ptype = fPreviewData.type;
403 const uint32_t psize = fPreviewData.size;
404 const void* const pbuffer = fPreviewData.buffer;
405 fPreviewData.shouldSend = false;
407 LV2_Atom_Forge atomForge = fAtomForge;
408 lv2_atom_forge_set_buffer(&atomForge, atomBuf, sizeof(atomBuf));
410 LV2_Atom_Forge_Frame forgeFrame;
411 lv2_atom_forge_object(&atomForge, &forgeFrame, 0, fURIs.patchSet);
413 lv2_atom_forge_key(&atomForge, fURIs.patchProperty);
414 lv2_atom_forge_urid(&atomForge, fURIs.carlaPreview);
416 lv2_atom_forge_key(&atomForge, fURIs.patchValue);
418 switch (ptype)
420 case 'b':
421 lv2_atom_forge_vector(&atomForge, sizeof(int32_t), fURIs.atomBool, psize, pbuffer);
422 break;
423 case 'i':
424 lv2_atom_forge_vector(&atomForge, sizeof(int32_t), fURIs.atomInt, psize, pbuffer);
425 break;
426 case 'f':
427 lv2_atom_forge_vector(&atomForge, sizeof(float), fURIs.atomFloat, psize, pbuffer);
428 break;
429 default:
430 carla_stderr2("Preview data buffer has wrong type '%c' (and size %u)", ptype, psize);
431 break;
434 lv2_atom_forge_pop(&atomForge, &forgeFrame);
436 if (sizeof(LV2_Atom_Event) + atom->size <= mData.capacity - mData.offset)
438 LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq) + mData.offset);
440 aev->time.frames = 0;
441 aev->body.size = atom->size;
442 aev->body.type = atom->type;
443 std::memcpy(LV2_ATOM_BODY(&aev->body), atom + 1, atom->size);
445 const uint32_t size = lv2_atom_pad_size(static_cast<uint32_t>(sizeof(LV2_Atom_Event) + atom->size));
446 mData.offset += size;
447 seq->atom.size += size;
453 fDescriptor->process(fHandle, fPorts.audioCVIns, fPorts.audioCVOuts, frames, fMidiEvents, fMidiEventCount);
455 if (fPluginNeedsIdle == 1)
457 fPluginNeedsIdle = 2;
458 const char* const msg = "_idle_";
459 const size_t msgSize = std::strlen(msg);
460 fWorker->schedule_work(fWorker->handle, static_cast<uint32_t>(msgSize + 1U), msg);
463 if (fWorkerUISignal == -1 && fPorts.hasUI)
465 const char* const msg = "quit";
466 const size_t msgSize = 5;
468 LV2_Atom_Sequence* const seq(fPorts.eventsOut[0]);
469 Ports::EventsOutData& mData(fPorts.eventsOutData[0]);
471 if (sizeof(LV2_Atom_Event) + msgSize <= mData.capacity - mData.offset)
473 LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq) + mData.offset);
475 aev->time.frames = 0;
476 aev->body.size = msgSize;
477 aev->body.type = fURIs.carlaUiEvents;
478 std::memcpy(LV2_ATOM_BODY(&aev->body), msg, msgSize);
480 const uint32_t size = lv2_atom_pad_size(static_cast<uint32_t>(sizeof(LV2_Atom_Event) + msgSize));
481 mData.offset += size;
482 seq->atom.size += size;
484 fWorkerUISignal = 0;
488 lv2_post_run(frames);
489 updateParameterOutputs();
492 // ----------------------------------------------------------------------------------------------------------------
494 const LV2_Program_Descriptor* lv2_get_program(const uint32_t index)
496 if (fDescriptor->category == NATIVE_PLUGIN_CATEGORY_SYNTH)
497 return nullptr;
498 if (fDescriptor->get_midi_program_count == nullptr)
499 return nullptr;
500 if (fDescriptor->get_midi_program_info == nullptr)
501 return nullptr;
502 if (index >= fDescriptor->get_midi_program_count(fHandle))
503 return nullptr;
505 const NativeMidiProgram* const midiProg(fDescriptor->get_midi_program_info(fHandle, index));
507 if (midiProg == nullptr)
508 return nullptr;
510 fProgramDesc.bank = midiProg->bank;
511 fProgramDesc.program = midiProg->program;
512 fProgramDesc.name = midiProg->name;
514 return &fProgramDesc;
517 void lv2_select_program(uint32_t bank, uint32_t program)
519 if (fDescriptor->category == NATIVE_PLUGIN_CATEGORY_SYNTH)
520 return;
521 if (fDescriptor->set_midi_program == nullptr)
522 return;
524 fDescriptor->set_midi_program(fHandle, 0, bank, program);
526 for (uint32_t i=0; i < fPorts.numParams; ++i)
528 fPorts.paramsLast[i] = fDescriptor->get_parameter_value(fHandle, i);
530 if (fPorts.paramsPtr[i] != nullptr)
531 *fPorts.paramsPtr[i] = fPorts.paramsLast[i];
535 // ----------------------------------------------------------------------------------------------------------------
537 void cleanupLastProjectPath()
539 fLastProjectPath.clear();
542 void saveLastProjectPathIfPossible(const LV2_Feature* const* const features)
544 if (features == nullptr)
545 return cleanupLastProjectPath();
547 const LV2_State_Free_Path* freePath = nullptr;
548 const LV2_State_Make_Path* makePath = nullptr;
550 for (int i=0; features[i] != nullptr; ++i)
552 /**/ if (freePath == nullptr && std::strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
553 freePath = (const LV2_State_Free_Path*)features[i]->data;
554 else if (makePath == nullptr && std::strcmp(features[i]->URI, LV2_STATE__makePath) == 0)
555 makePath = (const LV2_State_Make_Path*)features[i]->data;
558 if (makePath == nullptr || makePath->path == nullptr)
559 return cleanupLastProjectPath();
561 if (freePath == nullptr)
562 freePath = fFreePath;
564 char* const newpath = makePath->path(makePath->handle, kPathForCarlaFiles);
566 if (newpath == nullptr)
567 return cleanupLastProjectPath();
569 fLastProjectPath = CarlaString(water::File(newpath).getParentDirectory().getFullPathName().toRawUTF8());
571 if (freePath != nullptr && freePath->free_path != nullptr)
572 freePath->free_path(freePath->handle, newpath);
573 #ifndef CARLA_OS_WIN
574 // this is not safe to call under windows
575 else
576 std::free(newpath);
577 #endif
580 LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle,
581 const uint32_t /*flags*/, const LV2_Feature* const* const features)
583 saveLastProjectPathIfPossible(features);
585 if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
587 if (fLoadedFile.isEmpty())
588 return LV2_STATE_SUCCESS;
590 const LV2_State_Free_Path* freePath = nullptr;
591 const LV2_State_Map_Path* mapPath = nullptr;
593 if (features != nullptr)
595 for (int i=0; features[i] != nullptr; ++i)
597 /**/ if (freePath == nullptr && std::strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
598 freePath = (const LV2_State_Free_Path*)features[i]->data;
599 else if (mapPath == nullptr && std::strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
600 mapPath = (const LV2_State_Map_Path*)features[i]->data;
604 if (mapPath == nullptr || mapPath->abstract_path == nullptr)
605 return LV2_STATE_ERR_NO_FEATURE;
607 char* path = mapPath->abstract_path(mapPath->handle, fLoadedFile.buffer());
609 store(handle,
610 fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/file"),
611 path,
612 std::strlen(path)+1,
613 fURIs.atomPath,
614 LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE);
616 if (freePath != nullptr && freePath->free_path != nullptr)
617 freePath->free_path(freePath->handle, path);
618 #ifndef CARLA_OS_WIN
619 // this is not safe to call under windows
620 else
621 std::free(path);
622 #endif
624 return LV2_STATE_SUCCESS;
627 if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->get_state == nullptr)
628 return LV2_STATE_ERR_UNKNOWN;
630 if (char* const state = fDescriptor->get_state(fHandle))
632 store(handle,
633 fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"),
634 state,
635 std::strlen(state)+1,
636 fURIs.atomString,
637 LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE);
638 std::free(state);
639 return LV2_STATE_SUCCESS;
642 return LV2_STATE_ERR_UNKNOWN;
645 LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve,
646 const LV2_State_Handle handle,
647 uint32_t flags,
648 const LV2_Feature* const* const features)
650 saveLastProjectPathIfPossible(features);
652 size_t size = 0;
653 uint32_t type = 0;
655 if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
657 size = type = 0;
658 const void* const data = retrieve(handle,
659 fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/file"),
660 &size, &type, &flags);
661 if (size <= 1 || type == 0)
662 return LV2_STATE_ERR_NO_PROPERTY;
664 CARLA_SAFE_ASSERT_RETURN(type == fURIs.atomPath, LV2_STATE_ERR_UNKNOWN);
666 const LV2_State_Free_Path* freePath = nullptr;
667 const LV2_State_Map_Path* mapPath = nullptr;
669 if (features != nullptr)
671 for (int i=0; features[i] != nullptr; ++i)
673 /**/ if (freePath == nullptr && std::strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
674 freePath = (const LV2_State_Free_Path*)features[i]->data;
675 else if (mapPath == nullptr && std::strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
676 mapPath = (const LV2_State_Map_Path*)features[i]->data;
680 if (mapPath == nullptr || mapPath->absolute_path == nullptr)
681 return LV2_STATE_ERR_NO_FEATURE;
683 const char* const filename = (const char*)data;
685 char* const absolute_filename = mapPath->absolute_path(mapPath->handle, filename);
686 fLoadedFile = absolute_filename;
688 if (freePath != nullptr && freePath->free_path != nullptr)
689 freePath->free_path(freePath->handle, absolute_filename);
690 #ifndef CARLA_OS_WIN
691 // this is not safe to call under windows
692 else
693 std::free(absolute_filename);
694 #endif
696 fNeedsNotifyFileChanged = true;
697 fDescriptor->set_custom_data(fHandle, "file", fLoadedFile);
698 return LV2_STATE_SUCCESS;
701 if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->set_state == nullptr)
702 return LV2_STATE_ERR_UNKNOWN;
704 size = type = 0;
705 const void* const data = retrieve(handle,
706 fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"),
707 &size, &type, &flags);
709 if (size == 0)
710 return LV2_STATE_ERR_UNKNOWN;
711 if (type == 0)
712 return LV2_STATE_ERR_UNKNOWN;
713 if (data == nullptr)
714 return LV2_STATE_ERR_UNKNOWN;
715 if (type != fURIs.atomString)
716 return LV2_STATE_ERR_BAD_TYPE;
718 fDescriptor->set_state(fHandle, (const char*)data);
720 return LV2_STATE_SUCCESS;
723 // ----------------------------------------------------------------------------------------------------------------
725 LV2_Worker_Status lv2_work(LV2_Worker_Respond_Function, LV2_Worker_Respond_Handle, uint32_t, const void* data)
727 const char* const msg = (const char*)data;
729 if (std::strcmp(msg, "_idle_") == 0)
731 if (fDescriptor->hints & NATIVE_PLUGIN_REQUESTS_IDLE)
733 fPluginNeedsIdle = 0;
734 fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_IDLE, 0, 0, nullptr, 0.0f);
735 return LV2_WORKER_SUCCESS;
737 return LV2_WORKER_ERR_UNKNOWN;
740 if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
742 fLoadedFile = msg;
743 fDescriptor->set_custom_data(fHandle, "file", msg);
744 return LV2_WORKER_SUCCESS;
747 /**/ if (std::strncmp(msg, "control ", 8) == 0)
749 if (fDescriptor->ui_set_parameter_value == nullptr)
750 return LV2_WORKER_SUCCESS;
752 if (const char* const msgSplit = std::strstr(msg+8, " "))
754 const char* const msgIndex = msg+8;
755 CARLA_SAFE_ASSERT_RETURN(msgSplit - msgIndex < 8, LV2_WORKER_ERR_UNKNOWN);
756 CARLA_SAFE_ASSERT_RETURN(msgSplit[0] != '\0', LV2_WORKER_ERR_UNKNOWN);
758 char strBufIndex[8];
759 carla_zeroChars(strBufIndex, 8);
760 std::strncpy(strBufIndex, msgIndex, static_cast<size_t>(msgSplit - msgIndex));
762 const int index = std::atoi(msgIndex) - static_cast<int>(fPorts.indexOffset);
763 CARLA_SAFE_ASSERT_RETURN(index >= 0, LV2_WORKER_ERR_UNKNOWN);
765 float value;
768 const CarlaScopedLocale csl;
769 value = static_cast<float>(std::atof(msgSplit+1));
772 fDescriptor->ui_set_parameter_value(fHandle, static_cast<uint32_t>(index), value);
775 else if (std::strcmp(msg, "show") == 0)
777 handleUiShow();
779 else if (std::strcmp(msg, "hide") == 0)
781 handleUiHide();
783 else if (std::strcmp(msg, "idle") == 0)
785 handleUiRun();
787 else if (std::strcmp(msg, "quit") == 0)
789 handleUiClosed();
791 else
793 carla_stdout("lv2_work unknown msg '%s'", msg);
794 return LV2_WORKER_ERR_UNKNOWN;
797 return LV2_WORKER_SUCCESS;
800 LV2_Worker_Status lv2_work_resp(uint32_t /*size*/, const void* /*body*/)
802 return LV2_WORKER_SUCCESS;
805 const LV2_Inline_Display_Image_Surface* lv2_idisp_render(const uint32_t width, const uint32_t height)
807 CARLA_SAFE_ASSERT_RETURN(fDescriptor->hints & NATIVE_PLUGIN_HAS_INLINE_DISPLAY, nullptr);
808 CARLA_SAFE_ASSERT_RETURN(fDescriptor->render_inline_display, nullptr);
809 CARLA_SAFE_ASSERT_RETURN(width > 0, nullptr);
810 CARLA_SAFE_ASSERT_RETURN(height > 0, nullptr);
812 const NativeInlineDisplayImageSurface* nsur = fDescriptor->render_inline_display(fHandle, width, height);
813 CARLA_SAFE_ASSERT_RETURN(nsur != nullptr, nullptr);
815 return (const LV2_Inline_Display_Image_Surface*)(nsur);
818 // ----------------------------------------------------------------------------------------------------------------
820 void lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller,
821 LV2UI_Widget* widget, const LV2_Feature* const* features)
823 fUI.writeFunction = writeFunction;
824 fUI.controller = controller;
826 if (fHost.uiName != nullptr)
828 delete[] fHost.uiName;
829 fHost.uiName = nullptr;
832 // ---------------------------------------------------------------
833 // see if the host supports external-ui
835 for (int i=0; features[i] != nullptr; ++i)
837 if (std::strcmp(features[i]->URI, LV2_EXTERNAL_UI__Host) == 0 ||
838 std::strcmp(features[i]->URI, LV2_EXTERNAL_UI_DEPRECATED_URI) == 0)
840 fUI.host = (const LV2_External_UI_Host*)features[i]->data;
842 if (std::strcmp(features[i]->URI, LV2_UI__touch) == 0)
844 fUI.touch = (const LV2UI_Touch*)features[i]->data;
848 if (fUI.host != nullptr)
850 fHost.uiName = carla_strdup(fUI.host->plugin_human_id);
851 *widget = (LV2_External_UI_Widget_Compat*)this;
852 return;
855 // ---------------------------------------------------------------
856 // no external-ui support, use showInterface
858 for (int i=0; features[i] != nullptr; ++i)
860 if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) != 0)
861 continue;
863 const LV2_Options_Option* const options((const LV2_Options_Option*)features[i]->data);
864 CARLA_SAFE_ASSERT_BREAK(options != nullptr);
866 for (int j=0; options[j].key != 0; ++j)
868 if (options[j].key != fUridMap->map(fUridMap->handle, LV2_UI__windowTitle))
869 continue;
871 const char* const title((const char*)options[j].value);
872 CARLA_SAFE_ASSERT_BREAK(title != nullptr && title[0] != '\0');
874 fHost.uiName = carla_strdup(title);
875 break;
877 break;
880 if (fHost.uiName == nullptr)
881 fHost.uiName = carla_strdup(fDescriptor->name);
883 *widget = nullptr;
884 return;
887 void lv2ui_port_event(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) const
889 if (format != 0 || bufferSize != sizeof(float) || buffer == nullptr)
890 return;
891 if (portIndex < fPorts.indexOffset || ! fUI.isVisible)
892 return;
893 if (fDescriptor->ui_set_parameter_value == nullptr)
894 return;
896 const float value(*(const float*)buffer);
897 fDescriptor->ui_set_parameter_value(fHandle, portIndex-fPorts.indexOffset, value);
900 // ----------------------------------------------------------------------------------------------------------------
902 void lv2ui_select_program(uint32_t bank, uint32_t program) const
904 if (fDescriptor->category == NATIVE_PLUGIN_CATEGORY_SYNTH)
905 return;
906 if (fDescriptor->ui_set_midi_program == nullptr)
907 return;
909 fDescriptor->ui_set_midi_program(fHandle, 0, bank, program);
912 // ----------------------------------------------------------------------------------------------------------------
914 protected:
915 void handleUiRun() const override
917 if (fDescriptor->ui_idle != nullptr)
918 fDescriptor->ui_idle(fHandle);
921 void handleUiShow() override
923 if (fDescriptor->ui_show != nullptr)
924 fDescriptor->ui_show(fHandle, true);
926 fUI.isVisible = true;
929 void handleUiHide() override
931 if (fDescriptor->ui_show != nullptr)
932 fDescriptor->ui_show(fHandle, false);
934 fUI.isVisible = false;
937 // ----------------------------------------------------------------------------------------------------------------
939 void handleParameterValueChanged(const uint32_t index, const float value) override
941 fDescriptor->set_parameter_value(fHandle, index, value);
944 void handleBufferSizeChanged(const uint32_t bufferSize) override
946 if (fDescriptor->dispatcher == nullptr)
947 return;
949 fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, bufferSize, nullptr, 0.0f);
952 void handleSampleRateChanged(const double sampleRate) override
954 if (fDescriptor->dispatcher == nullptr)
955 return;
957 fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, (float)sampleRate);
960 // ----------------------------------------------------------------------------------------------------------------
962 bool handleWriteMidiEvent(const NativeMidiEvent* const event)
964 CARLA_SAFE_ASSERT_RETURN(fPorts.numMidiOuts > 0, false);
965 CARLA_SAFE_ASSERT_RETURN(event != nullptr, false);
966 CARLA_SAFE_ASSERT_RETURN(event->size > 0, false);
968 const uint8_t port(event->port);
969 CARLA_SAFE_ASSERT_RETURN(port < fPorts.numMidiOuts, false);
971 LV2_Atom_Sequence* const seq(fPorts.eventsOut[port]);
972 CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false);
974 Ports::EventsOutData& mData(fPorts.eventsOutData[port]);
976 if (sizeof(LV2_Atom_Event) + event->size > mData.capacity - mData.offset)
977 return false;
979 LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq) + mData.offset);
981 aev->time.frames = event->time;
982 aev->body.size = event->size;
983 aev->body.type = fURIs.midiEvent;
984 std::memcpy(LV2_ATOM_BODY(&aev->body), event->data, event->size);
986 const uint32_t size = lv2_atom_pad_size(static_cast<uint32_t>(sizeof(LV2_Atom_Event) + event->size));
987 mData.offset += size;
988 seq->atom.size += size;
990 return true;
993 void handleUiParameterChanged(const uint32_t index, const float value) const
995 if (kIgnoreParameters || fWorkerUISignal)
996 return;
998 if (fUI.writeFunction != nullptr && fUI.controller != nullptr)
999 fUI.writeFunction(fUI.controller, index+fPorts.indexOffset, sizeof(float), 0, &value);
1002 void handleUiParameterTouch(const uint32_t index, const bool touch) const
1004 if (kIgnoreParameters)
1005 return;
1007 if (fUI.touch != nullptr && fUI.touch->touch != nullptr)
1008 fUI.touch->touch(fUI.touch->handle, index+fPorts.indexOffset, touch);
1011 void handleUiResize(const uint32_t, const uint32_t) const
1013 // nothing here
1016 void handlePreviewBufferData(const char type, const uint32_t size, const void* const buffer) noexcept
1018 fPreviewData.type = type;
1019 fPreviewData.size = size;
1020 fPreviewData.buffer = buffer;
1021 fPreviewData.shouldSend = true;
1024 void handleUiCustomDataChanged(const char* const key, const char* const value) const
1026 carla_stdout("TODO: handleUiCustomDataChanged %s %s", key, value);
1027 //storeCustomData(key, value);
1029 if (fUI.writeFunction == nullptr || fUI.controller == nullptr)
1030 return;
1033 void handleUiClosed()
1035 fUI.isVisible = false;
1037 if (fWorkerUISignal)
1038 fWorkerUISignal = -1;
1040 if (fUI.host != nullptr && fUI.host->ui_closed != nullptr && fUI.controller != nullptr)
1041 fUI.host->ui_closed(fUI.controller);
1043 fUI.host = nullptr;
1044 fUI.touch = nullptr;
1045 fUI.writeFunction = nullptr;
1046 fUI.controller = nullptr;
1049 const char* handleUiOpenFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const
1051 // TODO
1052 return nullptr;
1055 const char* handleUiSaveFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const
1057 // TODO
1058 return nullptr;
1061 intptr_t handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
1063 #ifdef DEBUG
1064 if (opcode != NATIVE_HOST_OPCODE_GET_FILE_PATH)
1066 carla_debug("NativePlugin::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)",
1067 opcode, index, value, ptr, static_cast<double>(opt));
1069 #endif
1071 intptr_t ret = 0;
1073 switch (opcode)
1075 case NATIVE_HOST_OPCODE_NULL:
1076 case NATIVE_HOST_OPCODE_UPDATE_PARAMETER:
1077 case NATIVE_HOST_OPCODE_UPDATE_MIDI_PROGRAM:
1078 case NATIVE_HOST_OPCODE_RELOAD_PARAMETERS:
1079 case NATIVE_HOST_OPCODE_RELOAD_MIDI_PROGRAMS:
1080 case NATIVE_HOST_OPCODE_RELOAD_ALL:
1081 case NATIVE_HOST_OPCODE_HOST_IDLE:
1082 case NATIVE_HOST_OPCODE_INTERNAL_PLUGIN:
1083 // nothing
1084 break;
1086 case NATIVE_HOST_OPCODE_REQUEST_IDLE:
1087 CARLA_SAFE_ASSERT_RETURN(fDescriptor->hints & NATIVE_PLUGIN_REQUESTS_IDLE, 0);
1088 if (fWorker != nullptr && fPluginNeedsIdle == 0)
1090 fPluginNeedsIdle = 1;
1091 return 1;
1093 return 0;
1095 case NATIVE_HOST_OPCODE_QUEUE_INLINE_DISPLAY:
1096 if (fInlineDisplay != nullptr && fInlineDisplay->queue_draw != nullptr)
1098 fInlineDisplay->queue_draw(fInlineDisplay->handle);
1099 return 1;
1101 return 0;
1103 case NATIVE_HOST_OPCODE_GET_FILE_PATH:
1104 CARLA_SAFE_ASSERT_RETURN(ptr != nullptr, 0);
1105 if (std::strcmp((char*)ptr, "carla") == 0 && fLastProjectPath != nullptr)
1106 return static_cast<intptr_t>((uintptr_t)fLastProjectPath.buffer());
1107 break;
1109 case NATIVE_HOST_OPCODE_UI_UNAVAILABLE:
1110 handleUiClosed();
1111 break;
1113 case NATIVE_HOST_OPCODE_UI_TOUCH_PARAMETER:
1114 CARLA_SAFE_ASSERT_RETURN(index >= 0, 0);
1115 handleUiParameterTouch(static_cast<uint32_t>(index), value != 0);
1116 break;
1118 case NATIVE_HOST_OPCODE_UI_RESIZE:
1119 CARLA_SAFE_ASSERT_RETURN(index > 0, 0);
1120 CARLA_SAFE_ASSERT_RETURN(value > 0, 0);
1121 handleUiResize(static_cast<uint32_t>(index), static_cast<uint32_t>(value));
1122 break;
1124 case NATIVE_HOST_OPCODE_PREVIEW_BUFFER_DATA:
1125 CARLA_SAFE_ASSERT_RETURN(index != 0, 0);
1126 CARLA_SAFE_ASSERT_RETURN(index >= 'a', 0);
1127 CARLA_SAFE_ASSERT_RETURN(index <= 'z', 0);
1128 CARLA_SAFE_ASSERT_RETURN(value > 0, 0);
1129 CARLA_SAFE_ASSERT_RETURN(ptr != nullptr, 0);
1130 handlePreviewBufferData(static_cast<char>(index), static_cast<uint32_t>(value), (const void*)ptr);
1131 break;
1134 return ret;
1136 // unused for now
1137 (void)opt;
1140 void updateParameterOutputs()
1142 float value;
1144 for (uint32_t i=0; i < fPorts.numParams; ++i)
1146 if (! fPorts.paramsOut[i])
1147 continue;
1149 fPorts.paramsLast[i] = value = fDescriptor->get_parameter_value(fHandle, i);
1151 if (fPorts.paramsPtr[i] != nullptr)
1152 *fPorts.paramsPtr[i] = value;
1156 // -------------------------------------------------------------------
1158 private:
1159 // Native data
1160 NativePluginHandle fHandle;
1161 NativeHostDescriptor fHost;
1162 const NativePluginDescriptor* const fDescriptor;
1163 LV2_Program_Descriptor fProgramDesc;
1165 // carla as plugin does not implement lv2 parameter API yet, needed for feedback
1166 const bool kIgnoreParameters;
1168 LV2_Atom_Forge fAtomForge;
1169 uint32_t fMidiEventCount;
1170 NativeMidiEvent fMidiEvents[kMaxMidiEvents];
1172 CarlaString fLastProjectPath;
1173 CarlaString fLoadedFile;
1174 PreviewData fPreviewData;
1175 volatile bool fNeedsNotifyFileChanged;
1176 volatile int fPluginNeedsIdle;
1178 int fWorkerUISignal;
1179 // -1 needs close, 0 idle, 1 stuff is writing??
1181 // -------------------------------------------------------------------
1183 #define handlePtr ((NativePlugin*)handle)
1185 static uint32_t host_get_buffer_size(NativeHostHandle handle)
1187 return handlePtr->fBufferSize;
1190 static double host_get_sample_rate(NativeHostHandle handle)
1192 return handlePtr->fSampleRate;
1195 static bool host_is_offline(NativeHostHandle handle)
1197 return handlePtr->fIsOffline;
1200 static const NativeTimeInfo* host_get_time_info(NativeHostHandle handle)
1202 return &(handlePtr->fTimeInfo);
1205 static bool host_write_midi_event(NativeHostHandle handle, const NativeMidiEvent* event)
1207 return handlePtr->handleWriteMidiEvent(event);
1210 static void host_ui_parameter_changed(NativeHostHandle handle, uint32_t index, float value)
1212 handlePtr->handleUiParameterChanged(index, value);
1215 static void host_ui_parameter_touch(NativeHostHandle handle, uint32_t index, bool touch)
1217 handlePtr->handleUiParameterTouch(index, touch);
1220 static void host_ui_custom_data_changed(NativeHostHandle handle, const char* key, const char* value)
1222 handlePtr->handleUiCustomDataChanged(key, value);
1225 static void host_ui_closed(NativeHostHandle handle)
1227 handlePtr->handleUiClosed();
1230 static const char* host_ui_open_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
1232 return handlePtr->handleUiOpenFile(isDir, title, filter);
1235 static const char* host_ui_save_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
1237 return handlePtr->handleUiSaveFile(isDir, title, filter);
1240 static intptr_t host_dispatcher(NativeHostHandle handle, NativeHostDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt)
1242 return handlePtr->handleDispatcher(opcode, index, value, ptr, opt);
1245 #undef handlePtr
1247 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativePlugin)
1250 // -----------------------------------------------------------------------
1251 // LV2 plugin descriptor functions
1253 static LV2_Handle lv2_instantiate(const LV2_Descriptor* lv2Descriptor, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
1255 carla_debug("lv2_instantiate(%p, %g, %s, %p)", lv2Descriptor, sampleRate, bundlePath, features);
1257 const NativePluginDescriptor* pluginDesc = nullptr;
1258 const char* pluginLabel = nullptr;
1260 if (std::strncmp(lv2Descriptor->URI, "http://kxstudio.sf.net/carla/plugins/", 37) == 0)
1261 pluginLabel = lv2Descriptor->URI+37;
1263 if (pluginLabel == nullptr)
1265 carla_stderr("Failed to find carla native plugin with URI \"%s\"", lv2Descriptor->URI);
1266 return nullptr;
1269 carla_debug("lv2_instantiate() - looking up label \"%s\"", pluginLabel);
1271 PluginListManager& plm(PluginListManager::getInstance());
1273 for (LinkedList<const NativePluginDescriptor*>::Itenerator it = plm.descs.begin2(); it.valid(); it.next())
1275 const NativePluginDescriptor* const& tmpDesc(it.getValue(nullptr));
1276 CARLA_SAFE_ASSERT_CONTINUE(tmpDesc != nullptr);
1278 if (std::strcmp(tmpDesc->label, pluginLabel) == 0)
1280 pluginDesc = tmpDesc;
1281 break;
1285 if (pluginDesc == nullptr)
1287 carla_stderr("Failed to find carla native plugin with label \"%s\"", pluginLabel);
1288 return nullptr;
1291 NativePlugin* const plugin(new NativePlugin(pluginDesc, sampleRate, bundlePath, features));
1293 if (! plugin->init())
1295 carla_stderr("Failed to init plugin");
1296 delete plugin;
1297 return nullptr;
1300 return (LV2_Handle)plugin;
1303 #define instancePtr ((NativePlugin*)instance)
1305 static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
1307 instancePtr->lv2_connect_port(port, dataLocation);
1310 static void lv2_activate(LV2_Handle instance)
1312 carla_debug("lv2_activate(%p)", instance);
1313 instancePtr->lv2_activate();
1316 static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
1318 instancePtr->lv2_run(sampleCount);
1321 static void lv2_deactivate(LV2_Handle instance)
1323 carla_debug("lv2_deactivate(%p)", instance);
1324 instancePtr->lv2_deactivate();
1327 static void lv2_cleanup(LV2_Handle instance)
1329 carla_debug("lv2_cleanup(%p)", instance);
1330 instancePtr->lv2_cleanup();
1331 delete instancePtr;
1334 static uint32_t lv2_get_options(LV2_Handle instance, LV2_Options_Option* options)
1336 carla_debug("lv2_get_options(%p, %p)", instance, options);
1337 return instancePtr->lv2_get_options(options);
1340 static uint32_t lv2_set_options(LV2_Handle instance, const LV2_Options_Option* options)
1342 carla_debug("lv2_set_options(%p, %p)", instance, options);
1343 return instancePtr->lv2_set_options(options);
1346 static const LV2_Program_Descriptor* lv2_get_program(LV2_Handle instance, uint32_t index)
1348 carla_debug("lv2_get_program(%p, %i)", instance, index);
1349 return instancePtr->lv2_get_program(index);
1352 static void lv2_select_program(LV2_Handle instance, uint32_t bank, uint32_t program)
1354 carla_debug("lv2_select_program(%p, %i, %i)", instance, bank, program);
1355 return instancePtr->lv2_select_program(bank, program);
1358 static LV2_State_Status lv2_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* features)
1360 carla_debug("lv2_save(%p, %p, %p, %i, %p)", instance, store, handle, flags, features);
1361 return instancePtr->lv2_save(store, handle, flags, features);
1364 static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* features)
1366 carla_debug("lv2_restore(%p, %p, %p, %i, %p)", instance, retrieve, handle, flags, features);
1367 return instancePtr->lv2_restore(retrieve, handle, flags, features);
1370 static LV2_Worker_Status lv2_work(LV2_Handle instance, LV2_Worker_Respond_Function respond, LV2_Worker_Respond_Handle handle, uint32_t size, const void* data)
1372 carla_debug("work(%p, %p, %p, %u, %p)", instance, respond, handle, size, data);
1373 return instancePtr->lv2_work(respond, handle, size, data);
1376 static LV2_Worker_Status lv2_work_resp(LV2_Handle instance, uint32_t size, const void* body)
1378 carla_debug("work_resp(%p, %u, %p)", instance, size, body);
1379 return instancePtr->lv2_work_resp(size, body);
1382 static const LV2_Inline_Display_Image_Surface* lv2_idisp_render(LV2_Handle instance, uint32_t w, uint32_t h)
1384 // carla_debug("lv2_idisp_render(%p, %u, %u)", instance, w, h);
1385 return instancePtr->lv2_idisp_render(w, h);
1388 static const void* lv2_extension_data(const char* uri)
1390 carla_debug("lv2_extension_data(\"%s\")", uri);
1392 static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options };
1393 static const LV2_Programs_Interface programs = { lv2_get_program, lv2_select_program };
1394 static const LV2_State_Interface state = { lv2_save, lv2_restore };
1395 static const LV2_Worker_Interface worker = { lv2_work, lv2_work_resp, nullptr };
1396 static const LV2_Inline_Display_Interface idisp = { lv2_idisp_render };
1398 if (std::strcmp(uri, LV2_OPTIONS__interface) == 0)
1399 return &options;
1400 if (std::strcmp(uri, LV2_PROGRAMS__Interface) == 0)
1401 return &programs;
1402 if (std::strcmp(uri, LV2_STATE__interface) == 0)
1403 return &state;
1404 if (std::strcmp(uri, LV2_WORKER__interface) == 0)
1405 return &worker;
1406 if (std::strcmp(uri, LV2_INLINEDISPLAY__interface) == 0)
1407 return &idisp;
1409 return nullptr;
1412 #undef instancePtr
1414 #ifdef HAVE_PYQT
1415 // -----------------------------------------------------------------------
1416 // LV2 UI descriptor functions
1418 static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char*, const char*,
1419 LV2UI_Write_Function writeFunction, LV2UI_Controller controller,
1420 LV2UI_Widget* widget, const LV2_Feature* const* features)
1422 carla_debug("lv2ui_instantiate(..., %p, %p, %p)", writeFunction, controller, widget, features);
1424 NativePlugin* plugin = nullptr;
1426 for (int i=0; features[i] != nullptr; ++i)
1428 if (std::strcmp(features[i]->URI, LV2_INSTANCE_ACCESS_URI) == 0)
1430 plugin = (NativePlugin*)features[i]->data;
1431 break;
1435 if (plugin == nullptr)
1437 carla_stderr("Host doesn't support instance-access, cannot show UI");
1438 return nullptr;
1441 plugin->lv2ui_instantiate(writeFunction, controller, widget, features);
1443 return (LV2UI_Handle)plugin;
1446 #define uiPtr ((NativePlugin*)ui)
1448 static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer)
1450 carla_debug("lv2ui_port_event(%p, %i, %i, %i, %p)", ui, portIndex, bufferSize, format, buffer);
1451 uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer);
1454 static void lv2ui_cleanup(LV2UI_Handle ui)
1456 carla_debug("lv2ui_cleanup(%p)", ui);
1457 uiPtr->lv2ui_cleanup();
1460 static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t program)
1462 carla_debug("lv2ui_select_program(%p, %i, %i)", ui, bank, program);
1463 uiPtr->lv2ui_select_program(bank, program);
1466 static int lv2ui_idle(LV2UI_Handle ui)
1468 return uiPtr->lv2ui_idle();
1471 static int lv2ui_show(LV2UI_Handle ui)
1473 carla_debug("lv2ui_show(%p)", ui);
1474 return uiPtr->lv2ui_show();
1477 static int lv2ui_hide(LV2UI_Handle ui)
1479 carla_debug("lv2ui_hide(%p)", ui);
1480 return uiPtr->lv2ui_hide();
1483 static const void* lv2ui_extension_data(const char* uri)
1485 carla_stdout("lv2ui_extension_data(\"%s\")", uri);
1487 static const LV2UI_Idle_Interface uiidle = { lv2ui_idle };
1488 static const LV2UI_Show_Interface uishow = { lv2ui_show, lv2ui_hide };
1489 static const LV2_Programs_UI_Interface uiprograms = { lv2ui_select_program };
1491 if (std::strcmp(uri, LV2_UI__idleInterface) == 0)
1492 return &uiidle;
1493 if (std::strcmp(uri, LV2_UI__showInterface) == 0)
1494 return &uishow;
1495 if (std::strcmp(uri, LV2_PROGRAMS__UIInterface) == 0)
1496 return &uiprograms;
1498 return nullptr;
1500 #endif
1502 #undef uiPtr
1504 // -----------------------------------------------------------------------
1505 // Startup code
1507 CARLA_PLUGIN_EXPORT
1508 const LV2_Descriptor* lv2_descriptor(uint32_t index)
1510 carla_debug("lv2_descriptor(%i)", index);
1512 PluginListManager& plm(PluginListManager::getInstance());
1514 if (index >= plm.descs.count())
1516 carla_debug("lv2_descriptor(%i) - out of bounds", index);
1517 return nullptr;
1519 if (index < plm.lv2Descs.count())
1521 carla_debug("lv2_descriptor(%i) - found previously allocated", index);
1522 return plm.lv2Descs.getAt(index, nullptr);
1525 const NativePluginDescriptor* const pluginDesc(plm.descs.getAt(index, nullptr));
1526 CARLA_SAFE_ASSERT_RETURN(pluginDesc != nullptr, nullptr);
1528 CarlaString tmpURI;
1529 tmpURI = "http://kxstudio.sf.net/carla/plugins/";
1530 tmpURI += pluginDesc->label;
1532 carla_debug("lv2_descriptor(%i) - not found, allocating new with uri \"%s\"", index, (const char*)tmpURI);
1534 const LV2_Descriptor lv2DescTmp = {
1535 /* URI */ carla_strdup(tmpURI),
1536 /* instantiate */ lv2_instantiate,
1537 /* connect_port */ lv2_connect_port,
1538 /* activate */ lv2_activate,
1539 /* run */ lv2_run,
1540 /* deactivate */ lv2_deactivate,
1541 /* cleanup */ lv2_cleanup,
1542 /* extension_data */ lv2_extension_data
1545 LV2_Descriptor* lv2Desc;
1547 try {
1548 lv2Desc = new LV2_Descriptor;
1549 } CARLA_SAFE_EXCEPTION_RETURN("new LV2_Descriptor", nullptr);
1551 std::memcpy(lv2Desc, &lv2DescTmp, sizeof(LV2_Descriptor));
1553 plm.lv2Descs.append(lv2Desc);
1554 return lv2Desc;
1557 #ifdef HAVE_PYQT
1558 CARLA_PLUGIN_EXPORT
1559 const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
1561 carla_debug("lv2ui_descriptor(%i)", index);
1563 static const LV2UI_Descriptor lv2UiExtDesc = {
1564 /* URI */ "http://kxstudio.sf.net/carla/ui-ext",
1565 /* instantiate */ lv2ui_instantiate,
1566 /* cleanup */ lv2ui_cleanup,
1567 /* port_event */ lv2ui_port_event,
1568 /* extension_data */ lv2ui_extension_data
1571 return (index == 0) ? &lv2UiExtDesc : nullptr;
1573 #endif
1575 // -----------------------------------------------------------------------