5 #include "../juce_IncludeCharacteristics.h"
7 #if JucePlugin_Build_LV2
15 /* Same as juce_lv2_gen.cpp */
18 return String("urn:" JucePlugin_Manufacturer
":" JucePlugin_Name
":" JucePlugin_VersionString
).replace(" ", "_");
21 String
get_juce_ui_uri()
23 return String("urn:" JucePlugin_Manufacturer
":" JucePlugin_Name
":JUCE-Native-UI").replace(" ", "_");
26 String
get_external_ui_uri()
28 return String("urn:" JucePlugin_Manufacturer
":" JucePlugin_Name
":JUCE-External-UI").replace(" ", "_");
31 enum JuceLv2PortType
{
32 JUCE_LV2_PORT_TYPE_NONE
,
33 JUCE_LV2_PORT_TYPE_MIDI
,
34 JUCE_LV2_PORT_TYPE_AUDIO
,
35 JUCE_LV2_PORT_TYPE_CONTROL
44 int get_parameters_padding()
47 #if JucePlugin_WantsMidiInput
50 #if JucePlugin_ProducesMidiOutput
53 padding
+= JucePlugin_MaxNumInputChannels
;
54 padding
+= JucePlugin_MaxNumOutputChannels
;
58 //==============================================================================
59 /** Somewhere in the codebase of your plugin, you need to implement this function
60 and make it create an instance of the filter subclass that you're building.
62 extern AudioProcessor
* JUCE_CALLTYPE
createPluginFilter();
64 static Array
<void*> activePlugins
;
66 /* Create a new JUCE LV2 Plugin */
67 class JuceLV2Wrapper
: private Timer
70 JuceLV2Wrapper(const LV2_Descriptor
* _descriptor
, double _sample_rate
, const LV2_Feature
* const* _features
) :
71 numInChans (JucePlugin_MaxNumInputChannels
),
72 numOutChans (JucePlugin_MaxNumOutputChannels
),
75 firstProcessCallback (true),
76 shouldDeleteEditor (false)
78 printf("JuceLV2Wrapper()\n");
79 filter
= createPluginFilter();
81 filter
->setPlayConfigDetails(numInChans
, numOutChans
, 0, 0);
83 descriptor
= _descriptor
;
84 //features = _features;
86 sample_rate
= _sample_rate
;
90 #if JucePlugin_WantsMidiInput
94 #if JucePlugin_ProducesMidiOutput
99 port_count
+= numInChans
;
100 port_count
+= numOutChans
;
101 port_count
+= filter
->getNumParameters();
103 ports_ctrl
.insertMultiple(0, nullptr, filter
->getNumParameters());
104 ports_ctrl_last
.insertMultiple(0, 0.0f
, filter
->getNumParameters());
106 for (int i
=0; i
< numInChans
; i
++) {
107 ports_ain
[i
] = nullptr;
110 for (int i
=0; i
< numOutChans
; i
++) {
111 ports_aout
[i
] = nullptr;
114 for (int i
=0; i
< filter
->getNumParameters(); i
++) {
115 ports_ctrl_last
.set(i
, filter
->getParameter(i
));
118 midi_uri_id
= 0; // TODO URI-Map Extension
120 activePlugins
.add (this);
125 printf("~JuceLV2Wrapper()\n");
128 ports_ctrl_last
.clear();
129 deleteAndZero(filter
);
132 //==============================================================================
133 // LV2 Descriptor Calls
134 void do_connect_port(uint32_t port
, void* data_location
)
136 if (port
< port_count
) {
140 #if JucePlugin_WantsMidiInput
142 port_min
= data_location
;
148 #if JucePlugin_ProducesMidiOutput
150 port_mout
= data_location
;
156 for (i
=0; i
< numInChans
; i
++) {
158 ports_ain
[i
] = (float*)data_location
;
164 for (i
=0; i
< numOutChans
; i
++) {
166 ports_aout
[i
] = (float*)data_location
;
172 for (i
=0; i
< filter
->getNumParameters(); i
++) {
174 ports_ctrl
.set(i
, (float*)data_location
);
184 if (filter
!= nullptr) {
186 channels
.calloc (numInChans
+ numOutChans
);
188 jassert (sample_rate
> 0);
189 if (sample_rate
<= 0.0)
190 sample_rate
= 44100.0;
192 jassert (buffer_size
> 0);
194 firstProcessCallback
= true;
196 filter
->setNonRealtime (false);
197 filter
->setPlayConfigDetails (numInChans
, numOutChans
, sample_rate
, buffer_size
);
199 deleteTempChannels();
201 filter
->prepareToPlay (sample_rate
, buffer_size
);
203 midiEvents
.ensureSize (2048);
208 void do_run(uint32_t sample_count
)
210 if (firstProcessCallback
)
212 firstProcessCallback
= false;
214 // if this fails, the host hasn't called resume() before processing
215 jassert (isProcessing
);
217 // (tragically, some hosts actually need this, although it's stupid to have
222 filter
->setNonRealtime (false);
225 if (GetThreadPriority (GetCurrentThread()) <= THREAD_PRIORITY_NORMAL
226 && GetThreadPriority (GetCurrentThread()) >= THREAD_PRIORITY_LOWEST
)
227 filter
->setNonRealtime (true);
231 // Change buffer size if needed
232 if (buffer_size
!= sample_count
) {
233 buffer_size
= sample_count
;
234 filter
->setPlayConfigDetails(numInChans
, numOutChans
, sample_rate
, buffer_size
);
235 filter
->prepareToPlay(sample_rate
, buffer_size
);
238 // 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
);
295 for (; i
< numIn
; ++i
)
296 channels
[i
] = ports_ain
[i
];
298 AudioSampleBuffer
chans (channels
, jmax (numIn
, numOut
), sample_count
);
300 filter
->processBlock (chans
, midiEvents
);
304 if (! midiEvents
.isEmpty())
312 if (filter
!= nullptr)
314 filter
->releaseResources();
316 isProcessing
= false;
319 deleteTempChannels();
323 //==============================================================================
327 if (shouldDeleteEditor
)
329 shouldDeleteEditor
= false;
330 //deleteEditor (true);
334 //==============================================================================
336 MidiBuffer midiEvents
;
337 int numInChans
, numOutChans
;
338 bool isProcessing
, hasShutdown
, firstProcessCallback
, shouldDeleteEditor
;
339 HeapBlock
<float*> channels
;
340 Array
<float*> tempChannels
; // see note in processReplacing()
342 AudioProcessor
* filter
;
343 const LV2_Descriptor
* descriptor
;
347 uint16_t midi_uri_id
;
352 float* ports_ain
[JucePlugin_MaxNumInputChannels
];
353 float* ports_aout
[JucePlugin_MaxNumOutputChannels
];
354 Array
<float*> ports_ctrl
;
355 Array
<float> ports_ctrl_last
;
357 //==============================================================================
358 void deleteTempChannels()
360 for (int i
= tempChannels
.size(); --i
>= 0;)
361 delete[] (tempChannels
.getUnchecked(i
));
363 tempChannels
.clear();
365 if (filter
!= nullptr)
366 tempChannels
.insertMultiple (0, 0, filter
->getNumInputChannels() + filter
->getNumOutputChannels());
369 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceLV2Wrapper
);
372 //==============================================================================
373 // LV2 descriptor functions
374 LV2_Handle
juce_lv2_instantiate(const LV2_Descriptor
* descriptor
, double sample_rate
, const char* bundle_path
, const LV2_Feature
* const* features
)
376 JuceLV2Wrapper
* wrapper
= new JuceLV2Wrapper(descriptor
, sample_rate
, features
);
380 void juce_lv2_connect_port(LV2_Handle instance
, uint32_t port
, void* data_location
)
382 JuceLV2Wrapper
* wrapper
= (JuceLV2Wrapper
*)instance
;
383 wrapper
->do_connect_port(port
, data_location
);
386 void juce_lv2_activate(LV2_Handle instance
)
388 JuceLV2Wrapper
* wrapper
= (JuceLV2Wrapper
*)instance
;
389 wrapper
->do_activate();
392 void juce_lv2_run(LV2_Handle instance
, uint32_t sample_count
)
394 JuceLV2Wrapper
* wrapper
= (JuceLV2Wrapper
*)instance
;
395 wrapper
->do_run(sample_count
);
398 void juce_lv2_deactivate(LV2_Handle instance
)
400 JuceLV2Wrapper
* wrapper
= (JuceLV2Wrapper
*)instance
;
401 wrapper
->do_deactivate();
404 void juce_lv2_cleanup(LV2_Handle instance
)
406 JuceLV2Wrapper
* wrapper
= (JuceLV2Wrapper
*)instance
;
407 //free((void*)wrapper->descriptor->URI);
408 //delete wrapper->descriptor;
412 const void* juce_lv2_extension_data(const char* uri
)
414 printf("juce_lv2_extension_data()\n");
418 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
)
421 while (features
[i
++])
424 printf("feature #%i -> %s\n", i
, features
[i
]->URI
);
426 printf("ui_instantiate()");
430 void juce_lv2ui_cleanup(LV2UI_Handle instance
)
432 printf("ui_cleanup()");
435 void juce_lv2ui_port_event(LV2UI_Handle ui
, uint32_t port_index
, uint32_t buffer_size
, uint32_t format
, const void* buffer
)
437 printf("ui_port_event()");
440 //==============================================================================
441 // Create new LV2 objects
442 LV2_Descriptor
* getNewLv2Plugin()
444 LV2_Descriptor
* const Lv2Plugin
= new LV2_Descriptor
;
445 Lv2Plugin
->URI
= strdup((const char*)get_uri().toUTF8());
446 Lv2Plugin
->instantiate
= juce_lv2_instantiate
;
447 Lv2Plugin
->connect_port
= juce_lv2_connect_port
;
448 Lv2Plugin
->activate
= juce_lv2_activate
;
449 Lv2Plugin
->run
= juce_lv2_run
;
450 Lv2Plugin
->deactivate
= juce_lv2_deactivate
;
451 Lv2Plugin
->cleanup
= juce_lv2_cleanup
;
452 Lv2Plugin
->extension_data
= juce_lv2_extension_data
;
456 LV2UI_Descriptor
* getNewLv2UI(bool external
)
458 LV2UI_Descriptor
* Lv2UI
= new LV2UI_Descriptor
;
459 Lv2UI
->URI
= strdup((const char*) (external
? get_external_ui_uri() : get_juce_ui_uri()).toUTF8());
460 Lv2UI
->instantiate
= juce_lv2ui_instantiate
;
461 Lv2UI
->cleanup
= juce_lv2ui_cleanup
;
462 Lv2UI
->port_event
= juce_lv2ui_port_event
;
463 Lv2UI
->extension_data
= juce_lv2_extension_data
;
467 //==============================================================================
468 // Mac startup code..
471 extern "C" __attribute__ ((visibility("default"))) const LV2_Descriptor
* lv2_descriptor(uint32_t index
)
474 return (index
== 0) ? getNewLv2Plugin() : nullptr;
477 extern "C" __attribute__ ((visibility("default"))) const LV2UI_Descriptor
* lv2ui_descriptor(uint32_t index
)
480 // 0 -> External UI; 1 -> JUCE UI
481 return (index
<= 1) ? getNewLv2UI((index
== 0)) : nullptr;
484 //==============================================================================
485 // Linux startup code..
488 extern "C" __attribute__ ((visibility("default"))) const LV2_Descriptor
* lv2_descriptor(uint32_t index
)
490 return (index
== 0) ? getNewLv2Plugin() : nullptr;
493 extern "C" __attribute__ ((visibility("default"))) const LV2UI_Descriptor
* lv2ui_descriptor(uint32_t index
)
495 // 0 -> External UI; 1 -> JUCE UI
496 return (index
<= 1) ? getNewLv2UI((index
== 0)) : nullptr;
499 // don't put initialiseJuce_GUI or shutdownJuce_GUI in these... it will crash!
500 __attribute__((constructor
)) void myPluginInit() {}
501 __attribute__((destructor
)) void myPluginFini() {}
503 //==============================================================================
504 // Win32 startup code..
507 extern "C" __declspec (dllexport
) const LV2_Descriptor
* lv2_descriptor(uint32_t index
)
509 return (index
== 0) ? getNewLv2Plugin() : nullptr;
512 extern "C" __declspec (dllexport
) const LV2UI_Descriptor
* lv2ui_descriptor(uint32_t index
)
514 // 0 -> External UI; 1 -> JUCE UI
515 return (index
<= 1) ? getNewLv2UI((index
== 0)) : nullptr;