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";
31 void Lv2PluginBaseClass
<NativeTimeInfo
>::clearTimeData() noexcept
33 fLastPositionData
.clear();
34 carla_zeroStruct(fTimeInfo
);
50 // --------------------------------------------------------------------------------------------------------------------
51 // Carla Internal Plugin API exposed as LV2 plugin
53 class NativePlugin
: public Lv2PluginBaseClass
<NativeTimeInfo
>
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
),
66 #ifdef CARLA_PROPER_CPP11_SUPPORT
67 fProgramDesc({0, 0, nullptr}),
69 kIgnoreParameters(std::strncmp(desc
->label
, "carla", 5) == 0),
75 fNeedsNotifyFileChanged(false),
79 carla_zeroStruct(fHost
);
80 #ifndef CARLA_PROPER_CPP11_SUPPORT
81 carla_zeroStruct(fProgramDesc
);
84 if (! loadedInProperHost())
90 String
resourceDir(water::File(bundlePath
).getChildFile("resources").getFullPathName());
93 fHost
.resourceDir
= carla_strdup(resourceDir
.toRawUTF8());
94 fHost
.uiName
= nullptr;
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
);
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 // ----------------------------------------------------------------------------------------------------------------
134 if (fHost
.resourceDir
== nullptr)
137 if (fDescriptor
->instantiate
== nullptr || fDescriptor
->process
== nullptr)
139 carla_stderr("Plugin is missing something...");
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 &&
163 fPorts
.numParams
= fDescriptor
->get_parameter_count(fHandle
);
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
;
180 // ----------------------------------------------------------------------------------------------------------------
185 CARLA_SAFE_ASSERT_RETURN(! fIsActive
,);
189 if (fDescriptor
->activate
!= nullptr)
190 fDescriptor
->activate(fHandle
);
195 void lv2_deactivate()
197 CARLA_SAFE_ASSERT_RETURN(fIsActive
,);
201 if (fDescriptor
->deactivate
!= nullptr)
202 fDescriptor
->deactivate(fHandle
);
209 carla_stderr("Warning: Host forgot to call deactivate!");
212 if (fDescriptor
->deactivate
!= nullptr)
213 fDescriptor
->deactivate(fHandle
);
216 if (fDescriptor
->cleanup
!= nullptr)
217 fDescriptor
->cleanup(fHandle
);
222 // ----------------------------------------------------------------------------------------------------------------
224 void lv2_run(const uint32_t frames
)
226 if (! lv2_pre_run(frames
))
228 updateParameterOutputs();
232 if (fPorts
.numMidiIns
> 0 || fPorts
.hasUI
)
234 uint32_t numEventPortsIn
;
236 if (fPorts
.numMidiIns
> 0)
238 numEventPortsIn
= fPorts
.numMidiIns
;
240 carla_zeroStructs(fMidiEvents
, kMaxMidiEvents
);
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)
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
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
);
271 // worker is not supported, cancel
272 fWorkerUISignal
= -1;
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
)
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
);
296 CARLA_SAFE_ASSERT_CONTINUE(urid
== fURIs
.carlaFile
);
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),
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;
321 if (event
->body
.type
!= fURIs
.midiEvent
)
324 // anything past this point assumes plugin with MIDI input
325 CARLA_SAFE_ASSERT_CONTINUE(fPorts
.numMidiIns
> 0);
327 if (event
->body
.size
> 4)
329 if (event
->time
.frames
>= frames
)
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
;
341 for (uint32_t size
=event
->body
.size
; j
<size
; ++j
)
342 nativeEvent
.data
[j
] = data
[j
];
344 nativeEvent
.data
[j
] = 0;
346 if (fMidiEventCount
>= kMaxMidiEvents
)
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
);
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
);
421 lv2_atom_forge_vector(&atomForge
, sizeof(int32_t), fURIs
.atomBool
, psize
, pbuffer
);
424 lv2_atom_forge_vector(&atomForge
, sizeof(int32_t), fURIs
.atomInt
, psize
, pbuffer
);
427 lv2_atom_forge_vector(&atomForge
, sizeof(float), fURIs
.atomFloat
, psize
, pbuffer
);
430 carla_stderr2("Preview data buffer has wrong type '%c' (and size %u)", ptype
, psize
);
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
;
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
)
498 if (fDescriptor
->get_midi_program_count
== nullptr)
500 if (fDescriptor
->get_midi_program_info
== nullptr)
502 if (index
>= fDescriptor
->get_midi_program_count(fHandle
))
505 const NativeMidiProgram
* const midiProg(fDescriptor
->get_midi_program_info(fHandle
, index
));
507 if (midiProg
== 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
)
521 if (fDescriptor
->set_midi_program
== nullptr)
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
);
574 // this is not safe to call under windows
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());
610 fUridMap
->map(fUridMap
->handle
, "http://kxstudio.sf.net/ns/carla/file"),
614 LV2_STATE_IS_POD
|LV2_STATE_IS_PORTABLE
);
616 if (freePath
!= nullptr && freePath
->free_path
!= nullptr)
617 freePath
->free_path(freePath
->handle
, path
);
619 // this is not safe to call under windows
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
))
633 fUridMap
->map(fUridMap
->handle
, "http://kxstudio.sf.net/ns/carla/chunk"),
635 std::strlen(state
)+1,
637 LV2_STATE_IS_POD
|LV2_STATE_IS_PORTABLE
);
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
,
648 const LV2_Feature
* const* const features
)
650 saveLastProjectPathIfPossible(features
);
655 if (fDescriptor
->hints
& NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE
)
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
);
691 // this is not safe to call under windows
693 std::free(absolute_filename
);
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
;
705 const void* const data
= retrieve(handle
,
706 fUridMap
->map(fUridMap
->handle
, "http://kxstudio.sf.net/ns/carla/chunk"),
707 &size
, &type
, &flags
);
710 return LV2_STATE_ERR_UNKNOWN
;
712 return LV2_STATE_ERR_UNKNOWN
;
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
)
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
);
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
);
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)
779 else if (std::strcmp(msg
, "hide") == 0)
783 else if (std::strcmp(msg
, "idle") == 0)
787 else if (std::strcmp(msg
, "quit") == 0)
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;
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)
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
))
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
);
880 if (fHost
.uiName
== nullptr)
881 fHost
.uiName
= carla_strdup(fDescriptor
->name
);
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)
891 if (portIndex
< fPorts
.indexOffset
|| ! fUI
.isVisible
)
893 if (fDescriptor
->ui_set_parameter_value
== nullptr)
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
)
906 if (fDescriptor
->ui_set_midi_program
== nullptr)
909 fDescriptor
->ui_set_midi_program(fHandle
, 0, bank
, program
);
912 // ----------------------------------------------------------------------------------------------------------------
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)
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)
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
)
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
;
993 void handleUiParameterChanged(const uint32_t index
, const float value
) const
995 if (kIgnoreParameters
|| fWorkerUISignal
)
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
)
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
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)
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
);
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
1055 const char* handleUiSaveFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const
1061 intptr_t handleDispatcher(const NativeHostDispatcherOpcode opcode
, const int32_t index
, const intptr_t value
, void* const ptr
, const float opt
)
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
));
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
:
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;
1095 case NATIVE_HOST_OPCODE_QUEUE_INLINE_DISPLAY
:
1096 if (fInlineDisplay
!= nullptr && fInlineDisplay
->queue_draw
!= nullptr)
1098 fInlineDisplay
->queue_draw(fInlineDisplay
->handle
);
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());
1109 case NATIVE_HOST_OPCODE_UI_UNAVAILABLE
:
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);
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
));
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
);
1140 void updateParameterOutputs()
1144 for (uint32_t i
=0; i
< fPorts
.numParams
; ++i
)
1146 if (! fPorts
.paramsOut
[i
])
1149 fPorts
.paramsLast
[i
] = value
= fDescriptor
->get_parameter_value(fHandle
, i
);
1151 if (fPorts
.paramsPtr
[i
] != nullptr)
1152 *fPorts
.paramsPtr
[i
] = value
;
1156 // -------------------------------------------------------------------
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
);
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
);
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
;
1285 if (pluginDesc
== nullptr)
1287 carla_stderr("Failed to find carla native plugin with label \"%s\"", pluginLabel
);
1291 NativePlugin
* const plugin(new NativePlugin(pluginDesc
, sampleRate
, bundlePath
, features
));
1293 if (! plugin
->init())
1295 carla_stderr("Failed to init plugin");
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();
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)
1400 if (std::strcmp(uri
, LV2_PROGRAMS__Interface
) == 0)
1402 if (std::strcmp(uri
, LV2_STATE__interface
) == 0)
1404 if (std::strcmp(uri
, LV2_WORKER__interface
) == 0)
1406 if (std::strcmp(uri
, LV2_INLINEDISPLAY__interface
) == 0)
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
;
1435 if (plugin
== nullptr)
1437 carla_stderr("Host doesn't support instance-access, cannot show UI");
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)
1493 if (std::strcmp(uri
, LV2_UI__showInterface
) == 0)
1495 if (std::strcmp(uri
, LV2_PROGRAMS__UIInterface
) == 0)
1504 // -----------------------------------------------------------------------
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
);
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);
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
,
1540 /* deactivate */ lv2_deactivate
,
1541 /* cleanup */ lv2_cleanup
,
1542 /* extension_data */ lv2_extension_data
1545 LV2_Descriptor
* lv2Desc
;
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
);
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;
1575 // -----------------------------------------------------------------------