Small fixing
[juce-lv2.git] / juce / source / src / audio / plugin_client / LV2 / juce_LV2_Wrapper.cpp
blob7088766d3515d956c1953aebcc0f75f6e377e5b1
1 /*
2 * JUCE LV2 wrapper
3 */
5 #include "../juce_IncludeCharacteristics.h"
7 #if JucePlugin_Build_LV2
9 // LV2 includes..
10 #include "lv2/lv2.h"
11 #include "lv2/event.h"
12 #include "lv2/event_helpers.h"
13 #include "lv2/instance_access.h"
14 #include "lv2/uri_map.h"
15 #include "lv2/ui.h"
16 #include "lv2/lv2_external_ui.h"
18 #include "../juce_PluginHeaders.h"
19 #include "../juce_PluginHostType.h"
21 //==============================================================================
22 // Same as juce_lv2_gen.cpp
23 String get_uri()
25 return String("urn:" JucePlugin_Manufacturer ":" JucePlugin_Name ":" JucePlugin_VersionString).replace(" ", "_");
28 String get_juce_ui_uri()
30 return String("urn:" JucePlugin_Manufacturer ":" JucePlugin_Name ":JUCE-Native-UI").replace(" ", "_");
33 String get_external_ui_uri()
35 return String("urn:" JucePlugin_Manufacturer ":" JucePlugin_Name ":JUCE-External-UI").replace(" ", "_");
38 static Array<void*> activePlugins;
40 extern AudioProcessor* JUCE_CALLTYPE createPluginFilter();
42 //==============================================================================
43 // Create a new JUCE LV2 Plugin
44 class JuceLV2Wrapper : private Timer
46 public:
47 JuceLV2Wrapper(const LV2_Descriptor* descriptor_, double sample_rate_, const LV2_Feature* const* features) :
48 chunkMemoryTime (0),
49 numInChans (JucePlugin_MaxNumInputChannels),
50 numOutChans (JucePlugin_MaxNumOutputChannels),
51 isProcessing (false),
52 firstProcessCallback (true),
53 descriptor (descriptor_),
54 sample_rate (sample_rate_),
55 buffer_size (512),
56 midi_uri_id (0),
57 port_count (0)
59 printf("JuceLV2Wrapper()\n");
60 initialiseJuce_GUI();
62 filter = createPluginFilter();
63 filter->setPlayConfigDetails(numInChans, numOutChans, 0, 0);
65 // Port count
66 #if JucePlugin_WantsMidiInput
67 port_count += 1;
68 #endif
69 #if JucePlugin_ProducesMidiOutput
70 port_count += 1;
71 #endif
72 port_count += numInChans;
73 port_count += numOutChans;
74 port_count += filter->getNumParameters();
76 // Set Port data
77 port_min = nullptr;
78 port_mout = nullptr;
79 ports_ctrl.insertMultiple(0, nullptr, filter->getNumParameters());
80 ports_ctrl_last.insertMultiple(0, 0.0f, filter->getNumParameters());
82 for (int i=0; i < numInChans; i++) {
83 ports_ain[i] = nullptr;
86 for (int i=0; i < numOutChans; i++) {
87 ports_aout[i] = nullptr;
90 for (int i=0; i < filter->getNumParameters(); i++) {
91 ports_ctrl_last.set(i, filter->getParameter(i));
94 // Get MIDI URI Id
95 for (uint16_t j = 0; features[j]; j++)
97 if (strcmp(features[j]->URI, LV2_URI_MAP_URI) == 0)
99 LV2_URI_Map_Feature* uri_feature = (LV2_URI_Map_Feature*)features[j]->data;
100 midi_uri_id = uri_feature->uri_to_id(uri_feature->callback_data, LV2_EVENT_URI, "http://lv2plug.in/ns/ext/midi#MidiEvent");
101 break;
105 activePlugins.add (this);
107 startTimer(1000);
110 ~JuceLV2Wrapper()
112 JUCE_AUTORELEASEPOOL
115 stopTimer();
117 delete filter;
118 filter = 0;
120 channels.free();
121 deleteTempChannels();
123 ports_ctrl.clear();
124 ports_ctrl_last.clear();
126 jassert (activePlugins.contains (this));
127 activePlugins.removeValue (this);
129 if (activePlugins.size() == 0)
131 shutdownJuce_GUI();
136 //==============================================================================
137 // LV2 Descriptor Calls
138 void do_connect_port(uint32_t port, void* data_location)
140 if (port < port_count)
142 int i;
143 uint32_t index = 0;
145 #if JucePlugin_WantsMidiInput
146 if (port == index) {
147 port_min = (LV2_Event_Buffer*)data_location;
148 return;
150 index += 1;
151 #endif
153 #if JucePlugin_ProducesMidiOutput
154 if (port == index) {
155 port_mout = (LV2_Event_Buffer*)data_location;
156 return;
158 index += 1;
159 #endif
161 for (i=0; i < numInChans; i++) {
162 if (port == index) {
163 ports_ain[i] = (float*)data_location;
164 return;
166 index += 1;
169 for (i=0; i < numOutChans; i++) {
170 if (port == index) {
171 ports_aout[i] = (float*)data_location;
172 return;
174 index += 1;
177 for (i=0; i < filter->getNumParameters(); i++) {
178 if (port == index) {
179 ports_ctrl.set(i, (float*)data_location);
180 return;
182 index += 1;
187 void do_activate()
189 if (filter != nullptr)
191 isProcessing = true;
192 channels.calloc (numInChans + numOutChans);
194 jassert (sample_rate > 0);
195 if (sample_rate <= 0.0)
196 sample_rate = 44100.0;
198 jassert (buffer_size > 0);
200 firstProcessCallback = true;
202 filter->setNonRealtime (false);
203 filter->setPlayConfigDetails (numInChans, numOutChans, sample_rate, buffer_size);
205 deleteTempChannels();
207 filter->prepareToPlay (sample_rate, buffer_size);
209 midiEvents.ensureSize (2048);
210 midiEvents.clear();
214 void do_run(uint32_t sample_count)
216 if (firstProcessCallback)
218 firstProcessCallback = false;
220 // if this fails, the host hasn't called resume() before processing
221 jassert (isProcessing);
223 // (tragically, some hosts actually need this, although it's stupid to have
224 // to do it here..)
225 if (! isProcessing)
226 do_activate();
228 filter->setNonRealtime (false);
230 #if JUCE_WINDOWS
231 if (GetThreadPriority (GetCurrentThread()) <= THREAD_PRIORITY_NORMAL
232 && GetThreadPriority (GetCurrentThread()) >= THREAD_PRIORITY_LOWEST)
233 filter->setNonRealtime (true);
234 #endif
237 // Check if buffer size changed
238 if (buffer_size != sample_count)
240 buffer_size = sample_count;
241 filter->setPlayConfigDetails(numInChans, numOutChans, sample_rate, buffer_size);
242 filter->prepareToPlay(sample_rate, buffer_size);
245 // Check for updated parameters
246 float cur_value;
247 for (int i = 0; i < ports_ctrl.size(); i++)
249 if (ports_ctrl[i] != nullptr)
251 cur_value = *(float*)ports_ctrl[i];
252 if (ports_ctrl_last[i] != cur_value) {
253 filter->setParameter(i, cur_value);
254 ports_ctrl_last.setUnchecked(i, cur_value);
259 jassert (activePlugins.contains (this));
262 const ScopedLock sl (filter->getCallbackLock());
264 const int numIn = numInChans;
265 const int numOut = numOutChans;
267 if (filter->isSuspended())
269 for (int i = 0; i < numOut; ++i)
270 zeromem (ports_aout[i], sizeof (float) * sample_count);
272 else
274 int i;
275 for (i = 0; i < numOut; ++i)
277 float* chan = tempChannels.getUnchecked(i);
279 if (chan == 0)
281 chan = ports_aout[i];
283 // if some output channels are disabled, some hosts supply the same buffer
284 // for multiple channels - this buggers up our method of copying the
285 // inputs over the outputs, so we need to create unique temp buffers in this case..
286 for (int j = i; --j >= 0;)
288 if (ports_aout[j] == chan)
290 chan = new float [buffer_size * 2];
291 tempChannels.set (i, chan);
292 break;
297 if (i < numIn && chan != ports_ain[i])
298 memcpy (chan, ports_ain[i], sizeof (float) * sample_count);
300 channels[i] = chan;
303 // LV2 MIDI Input
304 LV2_Event_Iterator iter;
305 lv2_event_begin(&iter, port_min);
307 lv2_event_buffer_reset(port_min, LV2_EVENT_AUDIO_STAMP, (uint8_t*)(port_min + 1));
309 for (uint32_t i=0; i < iter.buf->event_count; ++i) {
310 uint8_t* data;
311 LV2_Event* ev = lv2_event_get(&iter, &data);
312 midiEvents.addEvent(data, ev->size, ev->frames);
313 lv2_event_increment(&iter);
316 for (; i < numIn; ++i)
317 channels[i] = ports_ain[i];
319 AudioSampleBuffer chans (channels, jmax (numIn, numOut), sample_count);
321 filter->processBlock (chans, midiEvents);
325 if (! midiEvents.isEmpty())
327 #if JucePlugin_ProducesMidiOutput
328 const int numEvents = midiEvents.getNumEvents();
330 LV2_Event_Iterator iter;
331 lv2_event_buffer_reset(port_mout, LV2_EVENT_AUDIO_STAMP, (uint8_t*)(port_mout + 1));
332 lv2_event_begin(&iter, port_mout);
334 const JUCE_NAMESPACE::uint8* midiEventData;
335 int midiEventSize, midiEventPosition;
336 MidiBuffer::Iterator i (midiEvents);
338 while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition))
340 jassert (midiEventPosition >= 0 && midiEventPosition < sample_count);
342 lv2_event_write(&iter, midiEventPosition, 0, midi_uri_id, midiEventSize, midiEventData);
344 #endif
345 midiEvents.clear();
349 void do_deactivate()
351 if (filter != nullptr)
353 filter->releaseResources();
355 isProcessing = false;
356 channels.free();
358 deleteTempChannels();
362 void do_cleanup()
364 stopTimer();
366 if (descriptor)
368 free((void*)descriptor->URI);
369 delete descriptor;
373 //==============================================================================
374 // JUCE Stuff
376 // TODO - set/get chunk
378 AudioProcessor* getFilter() { return filter; }
380 void timerCallback()
382 if (chunkMemoryTime > 0 && chunkMemoryTime < JUCE_NAMESPACE::Time::getApproximateMillisecondCounter() - 2000)
384 chunkMemoryTime = 0;
385 chunkMemory.setSize (0);
389 //==============================================================================
390 private:
391 AudioProcessor* filter;
392 JUCE_NAMESPACE::MemoryBlock chunkMemory;
393 JUCE_NAMESPACE::uint32 chunkMemoryTime;
394 MidiBuffer midiEvents;
395 int numInChans, numOutChans;
396 bool isProcessing, firstProcessCallback;
397 HeapBlock<float*> channels;
398 Array<float*> tempChannels; // see note in do_run()
400 const LV2_Descriptor* descriptor;
402 double sample_rate;
403 int buffer_size;
404 uint16_t midi_uri_id;
405 uint32_t port_count;
407 LV2_Event_Buffer* port_min;
408 LV2_Event_Buffer* port_mout;
409 float* ports_ain[JucePlugin_MaxNumInputChannels];
410 float* ports_aout[JucePlugin_MaxNumOutputChannels];
411 Array<float*> ports_ctrl;
412 Array<float> ports_ctrl_last;
414 //==============================================================================
415 void deleteTempChannels()
417 for (int i = tempChannels.size(); --i >= 0;)
418 delete[] (tempChannels.getUnchecked(i));
420 tempChannels.clear();
422 if (filter != nullptr)
423 tempChannels.insertMultiple (0, 0, filter->getNumInputChannels() + filter->getNumOutputChannels());
426 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceLV2Wrapper);
429 //==============================================================================
430 // Create a new JUCE Editor
431 class JuceLv2Editor : public AudioProcessorListener
433 public:
434 JuceLv2Editor (JuceLV2Wrapper* const wrapper_, const LV2UI_Descriptor* ui_descriptor_, LV2UI_Write_Function write_function_, LV2UI_Controller controller_, LV2UI_Widget* widget_, const LV2_Feature* const* features) :
435 wrapper(wrapper_),
436 ui_descriptor(ui_descriptor_),
437 write_function(write_function_),
438 controller(controller_),
439 widget(widget_)
441 initialiseJuce_GUI();
443 filter = wrapper->getFilter();
445 //printf("TEST - Before\n");
446 //editor = filter->createEditorIfNeeded();
447 //printf("TEST - After\n");
449 // Padding for control ports
450 ctrl_pad = 0;
451 #if JucePlugin_WantsMidiInput
452 ctrl_pad += 1;
453 #endif
454 #if JucePlugin_ProducesMidiOutput
455 ctrl_pad += 1;
456 #endif
457 ctrl_pad += JucePlugin_MaxNumInputChannels;
458 ctrl_pad += JucePlugin_MaxNumOutputChannels;
461 ~JuceLv2Editor()
463 deleteAndZero (editor);
464 shutdownJuce_GUI();
467 void do_port_event(uint32_t port_index, float value)
469 filter->setParameter(port_index-ctrl_pad, value);
472 void do_cleanup()
474 if (ui_descriptor)
476 free((void*)ui_descriptor->URI);
477 delete ui_descriptor;
481 void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue)
483 if (controller && write_function)
484 write_function(controller, index+ctrl_pad, sizeof(float), 0, &newValue);
487 void audioProcessorChanged (AudioProcessor*) {}
489 private:
490 JuceLV2Wrapper* wrapper;
491 const LV2UI_Descriptor* ui_descriptor;
492 LV2UI_Write_Function write_function;
493 LV2UI_Controller controller;
494 LV2UI_Widget* widget;
496 AudioProcessor* filter;
497 AudioProcessorEditor* editor;
499 int ctrl_pad;
501 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceLv2Editor);
504 //==============================================================================
505 // LV2 descriptor functions
506 LV2_Handle juce_lv2_instantiate(const LV2_Descriptor* descriptor, double sample_rate, const char* bundle_path, const LV2_Feature* const* features)
508 MessageManagerLock mmLock;
509 JuceLV2Wrapper* wrapper = new JuceLV2Wrapper(descriptor, sample_rate, features);
510 return wrapper;
513 void juce_lv2_connect_port(LV2_Handle instance, uint32_t port, void* data_location)
515 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
516 wrapper->do_connect_port(port, data_location);
519 void juce_lv2_activate(LV2_Handle instance)
521 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
522 wrapper->do_activate();
525 void juce_lv2_run(LV2_Handle instance, uint32_t sample_count)
527 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
528 wrapper->do_run(sample_count);
531 void juce_lv2_deactivate(LV2_Handle instance)
533 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
534 wrapper->do_deactivate();
537 void juce_lv2_cleanup(LV2_Handle instance)
539 MessageManagerLock mmLock;
540 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
541 wrapper->do_cleanup();
542 delete wrapper;
545 const void* juce_lv2_extension_data(const char* uri)
547 printf("TODO :: juce_lv2_extension_data()\n");
548 return nullptr;
551 //==============================================================================
552 LV2UI_Handle juce_lv2ui_instantiate(const LV2UI_Descriptor* descriptor, const char* plugin_uri, const char* bundle_path, LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget* widget, const LV2_Feature* const* features)
554 MessageManagerLock mmLock;
555 for (uint16_t i = 0; features[i]; i++)
557 if (strcmp(features[i]->URI, LV2_INSTANCE_ACCESS_URI) == 0 && features[i]->data)
559 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)features[i]->data;
560 JuceLv2Editor* editor = new JuceLv2Editor(wrapper, descriptor, write_function, controller, widget, features);
561 return editor;
564 printf("Host does not support instance data - cannot use UI\n");
565 return nullptr;
568 void juce_lv2ui_port_event(LV2UI_Handle instance, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
570 MessageManagerLock mmLock;
571 JuceLv2Editor* editor = (JuceLv2Editor*)instance;
573 if (buffer_size == sizeof(float) && format == 0)
575 float value = *(float*)buffer;
576 editor->do_port_event(port_index, value);
580 void juce_lv2ui_cleanup(LV2UI_Handle instance)
582 MessageManagerLock mmLock;
583 JuceLv2Editor* editor = (JuceLv2Editor*)instance;
584 //editor->do_cleanup();
585 delete editor;
588 //==============================================================================
589 // Create new LV2 objects
590 LV2_Descriptor* getNewLv2Plugin()
592 LV2_Descriptor* const Lv2Plugin = new LV2_Descriptor;
593 Lv2Plugin->URI = strdup((const char*)get_uri().toUTF8());
594 Lv2Plugin->instantiate = juce_lv2_instantiate;
595 Lv2Plugin->connect_port = juce_lv2_connect_port;
596 Lv2Plugin->activate = juce_lv2_activate;
597 Lv2Plugin->run = juce_lv2_run;
598 Lv2Plugin->deactivate = juce_lv2_deactivate;
599 Lv2Plugin->cleanup = juce_lv2_cleanup;
600 Lv2Plugin->extension_data = juce_lv2_extension_data;
601 return Lv2Plugin;
604 LV2UI_Descriptor* getNewLv2UI(bool external)
606 LV2UI_Descriptor* Lv2UI = new LV2UI_Descriptor;
607 Lv2UI->URI = strdup((const char*) (external ? get_external_ui_uri() : get_juce_ui_uri()).toUTF8());
608 Lv2UI->instantiate = juce_lv2ui_instantiate;
609 Lv2UI->cleanup = juce_lv2ui_cleanup;
610 Lv2UI->port_event = juce_lv2ui_port_event;
611 Lv2UI->extension_data = juce_lv2_extension_data;
612 return Lv2UI;
615 //==============================================================================
616 // Mac startup code..
617 #if JUCE_MAC
619 extern "C" __attribute__ ((visibility("default"))) const LV2_Descriptor* lv2_descriptor(uint32_t index)
621 initialiseMac();
622 return (index == 0) ? getNewLv2Plugin() : nullptr;
625 extern "C" __attribute__ ((visibility("default"))) const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
627 return (index <= 1) ? getNewLv2UI((index == 0)) : nullptr;
630 //==============================================================================
631 // Linux startup code..
632 #elif JUCE_LINUX
634 extern "C" __attribute__ ((visibility("default"))) const LV2_Descriptor* lv2_descriptor(uint32_t index)
636 return (index == 0) ? getNewLv2Plugin() : nullptr;
639 extern "C" __attribute__ ((visibility("default"))) const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
641 return (index <= 1) ? getNewLv2UI((index == 0)) : nullptr;
644 // don't put initialiseJuce_GUI or shutdownJuce_GUI in these... it will crash!
645 __attribute__((constructor)) void myPluginInit() {}
646 __attribute__((destructor)) void myPluginFini() {}
648 //==============================================================================
649 // Win32 startup code..
650 #else
652 extern "C" __declspec (dllexport) const LV2_Descriptor* lv2_descriptor(uint32_t index)
654 return (index == 0) ? getNewLv2Plugin() : nullptr;
657 extern "C" __declspec (dllexport) const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
659 return (index <= 1) ? getNewLv2UI((index == 0)) : nullptr;
662 #endif
664 #endif