MIDI Out
[juce-lv2.git] / juce / source / src / audio / plugin_client / LV2 / juce_LV2_Wrapper.cpp
blob3ee1ba0dbea771a8814abe14ea5f8947c37ebf68
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
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 hasShutdown (false),
53 firstProcessCallback (true),
54 descriptor (descriptor_),
55 sample_rate (sample_rate_),
56 buffer_size (512),
57 midi_uri_id (0),
58 port_count (0)
60 printf("JuceLV2Wrapper()\n");
61 filter = createPluginFilter();
62 filter->setPlayConfigDetails(numInChans, numOutChans, 0, 0);
64 // Port count
65 #if JucePlugin_WantsMidiInput
66 port_count += 1;
67 #endif
68 #if JucePlugin_ProducesMidiOutput
69 port_count += 1;
70 #endif
71 port_count += numInChans;
72 port_count += numOutChans;
73 port_count += filter->getNumParameters();
75 // Set Port data
76 port_min = nullptr;
77 port_mout = nullptr;
78 ports_ctrl.insertMultiple(0, nullptr, filter->getNumParameters());
79 ports_ctrl_last.insertMultiple(0, 0.0f, filter->getNumParameters());
81 for (int i=0; i < numInChans; i++) {
82 ports_ain[i] = nullptr;
85 for (int i=0; i < numOutChans; i++) {
86 ports_aout[i] = nullptr;
89 for (int i=0; i < filter->getNumParameters(); i++) {
90 ports_ctrl_last.set(i, filter->getParameter(i));
93 // Get MIDI URI Id
94 uint16_t j = 0;
95 while(features[j]) {
96 if (strcmp(features[j]->URI, LV2_URI_MAP_URI) == 0) {
97 LV2_URI_Map_Feature* uri_feature = (LV2_URI_Map_Feature*)features[j]->data;
98 midi_uri_id = uri_feature->uri_to_id(uri_feature->callback_data, LV2_EVENT_URI, "http://lv2plug.in/ns/ext/midi#MidiEvent");
99 break;
101 j++;
104 activePlugins.add (this);
107 ~JuceLV2Wrapper()
109 JUCE_AUTORELEASEPOOL
112 hasShutdown = true;
114 delete filter;
115 filter = 0;
117 channels.free();
118 deleteTempChannels();
120 ports_ctrl.clear();
121 ports_ctrl_last.clear();
123 jassert (activePlugins.contains (this));
124 activePlugins.removeValue (this);
127 if (activePlugins.size() == 0)
129 shutdownJuce_GUI();
133 //==============================================================================
134 // LV2 Descriptor Calls
135 void do_connect_port(uint32_t port, void* data_location)
137 if (port < port_count) {
138 int i;
139 uint32_t index = 0;
141 #if JucePlugin_WantsMidiInput
142 if (port == index) {
143 port_min = (LV2_Event_Buffer*)data_location;
144 return;
146 index += 1;
147 #endif
149 #if JucePlugin_ProducesMidiOutput
150 if (port == index) {
151 port_mout = (LV2_Event_Buffer*)data_location;
152 return;
154 index += 1;
155 #endif
157 for (i=0; i < numInChans; i++) {
158 if (port == index) {
159 ports_ain[i] = (float*)data_location;
160 return;
162 index += 1;
165 for (i=0; i < numOutChans; i++) {
166 if (port == index) {
167 ports_aout[i] = (float*)data_location;
168 return;
170 index += 1;
173 for (i=0; i < filter->getNumParameters(); i++) {
174 if (port == index) {
175 ports_ctrl.set(i, (float*)data_location);
176 return;
178 index += 1;
183 void do_activate()
185 if (filter != nullptr) {
186 isProcessing = true;
187 channels.calloc (numInChans + numOutChans);
189 jassert (sample_rate > 0);
190 if (sample_rate <= 0.0)
191 sample_rate = 44100.0;
193 jassert (buffer_size > 0);
195 firstProcessCallback = true;
197 filter->setNonRealtime (false);
198 filter->setPlayConfigDetails (numInChans, numOutChans, sample_rate, buffer_size);
200 deleteTempChannels();
202 filter->prepareToPlay (sample_rate, buffer_size);
204 midiEvents.ensureSize (2048);
205 midiEvents.clear();
209 void do_run(uint32_t sample_count)
211 if (firstProcessCallback)
213 firstProcessCallback = false;
215 // if this fails, the host hasn't called resume() before processing
216 jassert (isProcessing);
218 // (tragically, some hosts actually need this, although it's stupid to have
219 // to do it here..)
220 if (! isProcessing)
221 do_activate();
223 filter->setNonRealtime (false);
225 #if JUCE_WINDOWS
226 if (GetThreadPriority (GetCurrentThread()) <= THREAD_PRIORITY_NORMAL
227 && GetThreadPriority (GetCurrentThread()) >= THREAD_PRIORITY_LOWEST)
228 filter->setNonRealtime (true);
229 #endif
232 // Check if buffer size changed
233 if (buffer_size != sample_count) {
234 buffer_size = sample_count;
235 filter->setPlayConfigDetails(numInChans, numOutChans, sample_rate, buffer_size);
236 filter->prepareToPlay(sample_rate, buffer_size);
239 // Check for updated parameters
240 float cur_value;
241 for (int i = 0; i < ports_ctrl.size(); i++) {
242 if (ports_ctrl[i] != nullptr) {
243 cur_value = *(float*)ports_ctrl[i];
244 if (ports_ctrl_last[i] != cur_value) {
245 filter->setParameter(i, cur_value);
246 ports_ctrl_last.setUnchecked(i, cur_value);
251 jassert (activePlugins.contains (this));
254 const ScopedLock sl (filter->getCallbackLock());
256 const int numIn = numInChans;
257 const int numOut = numOutChans;
259 if (filter->isSuspended())
261 for (int i = 0; i < numOut; ++i)
262 zeromem (ports_aout[i], sizeof (float) * sample_count);
264 else
266 int i;
267 for (i = 0; i < numOut; ++i)
269 float* chan = tempChannels.getUnchecked(i);
271 if (chan == 0)
273 chan = ports_aout[i];
275 // if some output channels are disabled, some hosts supply the same buffer
276 // for multiple channels - this buggers up our method of copying the
277 // inputs over the outputs, so we need to create unique temp buffers in this case..
278 for (int j = i; --j >= 0;)
280 if (ports_aout[j] == chan)
282 chan = new float [buffer_size * 2];
283 tempChannels.set (i, chan);
284 break;
289 if (i < numIn && chan != ports_ain[i])
290 memcpy (chan, ports_ain[i], sizeof (float) * sample_count);
292 channels[i] = chan;
295 // LV2 MIDI Input
296 LV2_Event_Iterator iter;
297 lv2_event_begin(&iter, port_min);
299 lv2_event_buffer_reset(port_min, LV2_EVENT_AUDIO_STAMP, (uint8_t*)(port_min + 1));
301 for (uint32_t i=0; i < iter.buf->event_count; ++i) {
302 uint8_t* data;
303 LV2_Event* ev = lv2_event_get(&iter, &data);
304 midiEvents.addEvent(data, ev->size, ev->frames);
305 lv2_event_increment(&iter);
308 for (; i < numIn; ++i)
309 channels[i] = ports_ain[i];
311 AudioSampleBuffer chans (channels, jmax (numIn, numOut), sample_count);
313 filter->processBlock (chans, midiEvents);
317 if (! midiEvents.isEmpty())
319 #if JucePlugin_ProducesMidiOutput
320 const int numEvents = midiEvents.getNumEvents();
322 LV2_Event_Iterator iter;
323 lv2_event_buffer_reset(port_mout, LV2_EVENT_AUDIO_STAMP, (uint8_t*)(port_mout + 1));
324 lv2_event_begin(&iter, port_mout);
326 const JUCE_NAMESPACE::uint8* midiEventData;
327 int midiEventSize, midiEventPosition;
328 MidiBuffer::Iterator i (midiEvents);
330 while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition))
332 jassert (midiEventPosition >= 0 && midiEventPosition < sample_count);
334 lv2_event_write(&iter, midiEventPosition, 0, midi_uri_id, midiEventSize, midiEventData);
336 #endif
337 midiEvents.clear();
341 void do_deactivate()
343 if (filter != nullptr)
345 filter->releaseResources();
347 isProcessing = false;
348 channels.free();
350 deleteTempChannels();
354 void do_cleanup()
358 // TODO - set/get chunk
360 //==============================================================================
361 // JUCE Stuff, TODO
363 //==============================================================================
364 private:
365 AudioProcessor* filter;
366 JUCE_NAMESPACE::MemoryBlock chunkMemory;
367 JUCE_NAMESPACE::uint32 chunkMemoryTime;
368 MidiBuffer midiEvents;
369 int numInChans, numOutChans;
370 bool isProcessing, hasShutdown, firstProcessCallback;
371 HeapBlock<float*> channels;
372 Array<float*> tempChannels; // see note in do_run()
374 const LV2_Descriptor* descriptor;
376 double sample_rate;
377 int buffer_size;
378 uint16_t midi_uri_id;
379 uint32_t port_count;
381 LV2_Event_Buffer* port_min;
382 LV2_Event_Buffer* port_mout;
383 float* ports_ain[JucePlugin_MaxNumInputChannels];
384 float* ports_aout[JucePlugin_MaxNumOutputChannels];
385 Array<float*> ports_ctrl;
386 Array<float> ports_ctrl_last;
388 //==============================================================================
389 void deleteTempChannels()
391 for (int i = tempChannels.size(); --i >= 0;)
392 delete[] (tempChannels.getUnchecked(i));
394 tempChannels.clear();
396 if (filter != nullptr)
397 tempChannels.insertMultiple (0, 0, filter->getNumInputChannels() + filter->getNumOutputChannels());
400 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceLV2Wrapper);
403 //==============================================================================
404 // LV2 descriptor functions
405 LV2_Handle juce_lv2_instantiate(const LV2_Descriptor* descriptor, double sample_rate, const char* bundle_path, const LV2_Feature* const* features)
407 JuceLV2Wrapper* wrapper = new JuceLV2Wrapper(descriptor, sample_rate, features);
408 return wrapper;
411 void juce_lv2_connect_port(LV2_Handle instance, uint32_t port, void* data_location)
413 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
414 wrapper->do_connect_port(port, data_location);
417 void juce_lv2_activate(LV2_Handle instance)
419 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
420 wrapper->do_activate();
423 void juce_lv2_run(LV2_Handle instance, uint32_t sample_count)
425 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
426 wrapper->do_run(sample_count);
429 void juce_lv2_deactivate(LV2_Handle instance)
431 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
432 wrapper->do_deactivate();
435 void juce_lv2_cleanup(LV2_Handle instance)
437 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
438 wrapper->do_cleanup();
440 //if (wrapper->descriptor)
442 // free((void*)wrapper->descriptor->URI);
443 // delete wrapper->descriptor;
446 delete wrapper;
449 const void* juce_lv2_extension_data(const char* uri)
451 printf("juce_lv2_extension_data()\n");
452 return nullptr;
455 //==============================================================================
456 #if 0
457 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)
459 printf("ui_instantiate()\n");
460 uint16_t i = 0;
461 while (features[i])
463 if (strcmp(features[i]->URI, LV2_INSTANCE_ACCESS_URI) == 0 && features[i]->data) {
464 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)features[i]->data;
465 wrapper->do_ui_instantiate(descriptor->URI, write_function, controller, widget, features);
466 return wrapper;
468 i++;
470 printf("Host does not support instance data - cannot use UI\n");
471 return nullptr;
474 void juce_lv2ui_cleanup(LV2UI_Handle instance)
476 printf("ui_cleanup()\n");
477 if (!instance) return;
478 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
479 wrapper->do_ui_cleanup();
482 void juce_lv2ui_port_event(LV2UI_Handle instance, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
484 printf("ui_port_event()\n");
485 if (!instance) return;
486 if (buffer_size != sizeof(float) || format != 0) return;
487 JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance;
488 float value = *(float*)buffer;
489 wrapper->do_ui_port_event(port_index, value);
491 #endif
493 //==============================================================================
494 // Create new LV2 objects
495 LV2_Descriptor* getNewLv2Plugin()
497 LV2_Descriptor* const Lv2Plugin = new LV2_Descriptor;
498 Lv2Plugin->URI = strdup((const char*)get_uri().toUTF8());
499 Lv2Plugin->instantiate = juce_lv2_instantiate;
500 Lv2Plugin->connect_port = juce_lv2_connect_port;
501 Lv2Plugin->activate = juce_lv2_activate;
502 Lv2Plugin->run = juce_lv2_run;
503 Lv2Plugin->deactivate = juce_lv2_deactivate;
504 Lv2Plugin->cleanup = juce_lv2_cleanup;
505 Lv2Plugin->extension_data = juce_lv2_extension_data;
506 return Lv2Plugin;
509 #if 0
510 LV2UI_Descriptor* getNewLv2UI(bool external)
512 LV2UI_Descriptor* Lv2UI = new LV2UI_Descriptor;
513 Lv2UI->URI = strdup((const char*) (external ? get_external_ui_uri() : get_juce_ui_uri()).toUTF8());
514 Lv2UI->instantiate = juce_lv2ui_instantiate;
515 Lv2UI->cleanup = juce_lv2ui_cleanup;
516 Lv2UI->port_event = juce_lv2ui_port_event;
517 Lv2UI->extension_data = juce_lv2_extension_data;
518 return Lv2UI;
520 #endif
522 //==============================================================================
523 // Mac startup code..
524 #if JUCE_MAC
526 extern "C" __attribute__ ((visibility("default"))) const LV2_Descriptor* lv2_descriptor(uint32_t index)
528 initialiseMac();
529 return (index == 0) ? getNewLv2Plugin() : nullptr;
532 extern "C" __attribute__ ((visibility("default"))) const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
534 initialiseMac();
535 // 0 -> External UI; 1 -> JUCE UI
536 return (index <= 1) ? getNewLv2UI((index == 0)) : nullptr;
539 //==============================================================================
540 // Linux startup code..
541 #elif JUCE_LINUX
543 extern "C" __attribute__ ((visibility("default"))) const LV2_Descriptor* lv2_descriptor(uint32_t index)
545 return (index == 0) ? getNewLv2Plugin() : nullptr;
548 extern "C" __attribute__ ((visibility("default"))) const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
550 // 0 -> External UI; 1 -> JUCE UI
551 return nullptr; //(index <= 1) ? getNewLv2UI((index == 0)) : nullptr;
554 // don't put initialiseJuce_GUI or shutdownJuce_GUI in these... it will crash!
555 __attribute__((constructor)) void myPluginInit() {}
556 __attribute__((destructor)) void myPluginFini() {}
558 //==============================================================================
559 // Win32 startup code..
560 #else
562 extern "C" __declspec (dllexport) const LV2_Descriptor* lv2_descriptor(uint32_t index)
564 return (index == 0) ? getNewLv2Plugin() : nullptr;
567 extern "C" __declspec (dllexport) const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
569 // 0 -> External UI; 1 -> JUCE UI
570 return (index <= 1) ? getNewLv2UI((index == 0)) : nullptr;
573 #endif
575 #endif