5 #include "../juce_IncludeCharacteristics.h"
7 #if JucePlugin_Build_LV2
11 #include "lv2/event.h"
12 #include "lv2/event_helpers.h"
13 #include "lv2/instance_access.h"
14 #include "lv2/uri_map.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
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
47 JuceLV2Wrapper(const LV2_Descriptor
* descriptor_
, double sample_rate_
, const LV2_Feature
* const* features
) :
49 numInChans (JucePlugin_MaxNumInputChannels
),
50 numOutChans (JucePlugin_MaxNumOutputChannels
),
53 firstProcessCallback (true),
54 descriptor (descriptor_
),
55 sample_rate (sample_rate_
),
60 printf("JuceLV2Wrapper()\n");
61 filter
= createPluginFilter();
62 filter
->setPlayConfigDetails(numInChans
, numOutChans
, 0, 0);
65 #if JucePlugin_WantsMidiInput
68 #if JucePlugin_ProducesMidiOutput
71 port_count
+= numInChans
;
72 port_count
+= numOutChans
;
73 port_count
+= filter
->getNumParameters();
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
));
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");
104 activePlugins
.add (this);
118 deleteTempChannels();
121 ports_ctrl_last
.clear();
123 jassert (activePlugins
.contains (this));
124 activePlugins
.removeValue (this);
127 if (activePlugins
.size() == 0)
133 //==============================================================================
134 // LV2 Descriptor Calls
135 void do_connect_port(uint32_t port
, void* data_location
)
137 if (port
< port_count
) {
141 #if JucePlugin_WantsMidiInput
143 port_min
= (LV2_Event_Buffer
*)data_location
;
149 #if JucePlugin_ProducesMidiOutput
151 port_mout
= (LV2_Event_Buffer
*)data_location
;
157 for (i
=0; i
< numInChans
; i
++) {
159 ports_ain
[i
] = (float*)data_location
;
165 for (i
=0; i
< numOutChans
; i
++) {
167 ports_aout
[i
] = (float*)data_location
;
173 for (i
=0; i
< filter
->getNumParameters(); i
++) {
175 ports_ctrl
.set(i
, (float*)data_location
);
185 if (filter
!= nullptr) {
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);
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
223 filter
->setNonRealtime (false);
226 if (GetThreadPriority (GetCurrentThread()) <= THREAD_PRIORITY_NORMAL
227 && GetThreadPriority (GetCurrentThread()) >= THREAD_PRIORITY_LOWEST
)
228 filter
->setNonRealtime (true);
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
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
);
267 for (i
= 0; i
< numOut
; ++i
)
269 float* chan
= tempChannels
.getUnchecked(i
);
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
);
289 if (i
< numIn
&& chan
!= ports_ain
[i
])
290 memcpy (chan
, ports_ain
[i
], sizeof (float) * sample_count
);
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
) {
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
);
343 if (filter
!= nullptr)
345 filter
->releaseResources();
347 isProcessing
= false;
350 deleteTempChannels();
358 // TODO - set/get chunk
360 //==============================================================================
363 //==============================================================================
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
;
378 uint16_t midi_uri_id
;
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
);
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;
449 const void* juce_lv2_extension_data(const char* uri
)
451 printf("juce_lv2_extension_data()\n");
455 //==============================================================================
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");
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
);
470 printf("Host does not support instance data - cannot use UI\n");
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
);
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
;
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
;
522 //==============================================================================
523 // Mac startup code..
526 extern "C" __attribute__ ((visibility("default"))) const LV2_Descriptor
* lv2_descriptor(uint32_t index
)
529 return (index
== 0) ? getNewLv2Plugin() : nullptr;
532 extern "C" __attribute__ ((visibility("default"))) const LV2UI_Descriptor
* lv2ui_descriptor(uint32_t index
)
535 // 0 -> External UI; 1 -> JUCE UI
536 return (index
<= 1) ? getNewLv2UI((index
== 0)) : nullptr;
539 //==============================================================================
540 // Linux startup code..
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..
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;