2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
5 * Permission to use, copy, modify, and/or distribute this software for any purpose with
6 * or without fee is hereby granted, provided that the above copyright notice and this
7 * permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include "DistrhoPluginInternal.hpp"
19 #if DISTRHO_PLUGIN_HAS_UI
20 # include "DistrhoUIInternal.hpp"
23 #include "CarlaNative.hpp"
26 #undef DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
27 #define DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 0
29 // -----------------------------------------------------------------------
31 START_NAMESPACE_DISTRHO
33 #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
34 static constexpr const writeMidiFunc writeMidiCallback
= nullptr;
36 #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
37 static constexpr const requestParameterValueChangeFunc requestParameterValueChangeCallback
= nullptr;
40 static constexpr const updateStateValueFunc updateStateValueCallback
= nullptr;
42 #if DISTRHO_PLUGIN_HAS_UI
43 // -----------------------------------------------------------------------
46 #if ! DISTRHO_PLUGIN_WANT_STATE
47 static const setStateFunc setStateCallback
= nullptr;
49 #if ! DISTRHO_PLUGIN_IS_SYNTH
50 static const sendNoteFunc sendNoteCallback
= nullptr;
56 UICarla(const NativeHostDescriptor
* const host
, PluginExporter
* const plugin
)
58 fUI(this, 0, plugin
->getSampleRate(),
59 editParameterCallback
, setParameterCallback
, setStateCallback
, sendNoteCallback
,
60 nullptr, // window size
61 nullptr, // TODO file request
62 nullptr, // bundle path
63 plugin
->getInstancePointer())
65 fUI
.setWindowTitle(host
->uiName
);
67 if (host
->uiParentId
!= 0)
68 fUI
.setWindowTransientWinId(host
->uiParentId
);
76 // ---------------------------------------------
78 void carla_show(const bool yesNo
)
80 fUI
.setWindowVisible(yesNo
);
85 return fUI
.plugin_idle();
88 void carla_setParameterValue(const uint32_t index
, const float value
)
90 fUI
.parameterChanged(index
, value
);
93 #if DISTRHO_PLUGIN_WANT_PROGRAMS
94 void carla_setMidiProgram(const uint32_t realProgram
)
96 fUI
.programLoaded(realProgram
);
100 #if DISTRHO_PLUGIN_WANT_STATE
101 void carla_setCustomData(const char* const key
, const char* const value
)
103 fUI
.stateChanged(key
, value
);
107 void carla_setUiTitle(const char* const uiTitle
)
109 fUI
.setWindowTitle(uiTitle
);
112 // ---------------------------------------------
115 void handleEditParameter(const uint32_t, const bool)
120 void handleSetParameterValue(const uint32_t rindex
, const float value
)
122 fHost
->ui_parameter_changed(fHost
->handle
, rindex
, value
);
125 #if DISTRHO_PLUGIN_WANT_STATE
126 void handleSetState(const char* const key
, const char* const value
)
128 fHost
->ui_custom_data_changed(fHost
->handle
, key
, value
);
132 #if DISTRHO_PLUGIN_IS_SYNTH
133 void handleSendNote(const uint8_t, const uint8_t, const uint8_t)
139 // ---------------------------------------------
143 const NativeHostDescriptor
* const fHost
;
148 // ---------------------------------------------
151 #define handlePtr ((UICarla*)ptr)
153 static void editParameterCallback(void* ptr
, uint32_t index
, bool started
)
155 handlePtr
->handleEditParameter(index
, started
);
158 static void setParameterCallback(void* ptr
, uint32_t rindex
, float value
)
160 handlePtr
->handleSetParameterValue(rindex
, value
);
163 #if DISTRHO_PLUGIN_WANT_STATE
164 static void setStateCallback(void* ptr
, const char* key
, const char* value
)
166 handlePtr
->handleSetState(key
, value
);
170 #if DISTRHO_PLUGIN_IS_SYNTH
171 static void sendNoteCallback(void* ptr
, uint8_t channel
, uint8_t note
, uint8_t velocity
)
173 handlePtr
->handleSendNote(channel
, note
, velocity
);
179 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UICarla
)
181 #endif // DISTRHO_PLUGIN_HAS_UI
183 // -----------------------------------------------------------------------
186 class PluginCarla
: public NativePluginClass
189 PluginCarla(const NativeHostDescriptor
* const host
)
190 : NativePluginClass(host
),
191 fPlugin(this, writeMidiCallback
, requestParameterValueChangeCallback
, updateStateValueCallback
),
192 fScalePointsCache(nullptr)
194 #if DISTRHO_PLUGIN_HAS_UI
199 ~PluginCarla() override
201 #if DISTRHO_PLUGIN_HAS_UI
202 if (fUiPtr
!= nullptr)
209 if (fScalePointsCache
!= nullptr)
211 delete[] fScalePointsCache
;
212 fScalePointsCache
= nullptr;
217 // -------------------------------------------------------------------
218 // Plugin parameter calls
220 uint32_t getParameterCount() const override
222 return fPlugin
.getParameterCount();
225 const NativeParameter
* getParameterInfo(const uint32_t index
) const override
227 CARLA_SAFE_ASSERT_RETURN(index
< getParameterCount(), nullptr);
229 static NativeParameter param
;
231 param
.scalePointCount
= 0;
232 param
.scalePoints
= nullptr;
235 int nativeParamHints
= ::NATIVE_PARAMETER_IS_ENABLED
;
236 const uint32_t paramHints
= fPlugin
.getParameterHints(index
);
238 if (paramHints
& kParameterIsAutomatable
)
239 nativeParamHints
|= ::NATIVE_PARAMETER_IS_AUTOMABLE
;
240 if (paramHints
& kParameterIsBoolean
)
241 nativeParamHints
|= ::NATIVE_PARAMETER_IS_BOOLEAN
;
242 if (paramHints
& kParameterIsInteger
)
243 nativeParamHints
|= ::NATIVE_PARAMETER_IS_INTEGER
;
244 if (paramHints
& kParameterIsLogarithmic
)
245 nativeParamHints
|= ::NATIVE_PARAMETER_IS_LOGARITHMIC
;
246 if (paramHints
& kParameterIsOutput
)
247 nativeParamHints
|= ::NATIVE_PARAMETER_IS_OUTPUT
;
249 param
.hints
= static_cast<NativeParameterHints
>(nativeParamHints
);
252 param
.name
= fPlugin
.getParameterName(index
);
253 param
.unit
= fPlugin
.getParameterUnit(index
);
256 const ParameterRanges
& ranges(fPlugin
.getParameterRanges(index
));
258 param
.ranges
.def
= ranges
.def
;
259 param
.ranges
.min
= ranges
.min
;
260 param
.ranges
.max
= ranges
.max
;
264 const ParameterEnumerationValues
& enumValues(fPlugin
.getParameterEnumValues(index
));
266 if (const uint32_t scalePointCount
= enumValues
.count
)
268 NativeParameterScalePoint
* const scalePoints
= new NativeParameterScalePoint
[scalePointCount
];
270 for (uint32_t i
=0; i
<scalePointCount
; ++i
)
272 scalePoints
[i
].label
= enumValues
.values
[i
].label
.buffer();
273 scalePoints
[i
].value
= enumValues
.values
[i
].value
;
276 param
.scalePoints
= scalePoints
;
277 param
.scalePointCount
= scalePointCount
;
279 if (enumValues
.restrictedMode
)
280 param
.hints
= static_cast<NativeParameterHints
>(param
.hints
|::NATIVE_PARAMETER_USES_SCALEPOINTS
);
282 else if (fScalePointsCache
!= nullptr)
284 delete[] fScalePointsCache
;
285 fScalePointsCache
= nullptr;
292 float getParameterValue(const uint32_t index
) const override
294 CARLA_SAFE_ASSERT_RETURN(index
< getParameterCount(), 0.0f
);
296 return fPlugin
.getParameterValue(index
);
299 // -------------------------------------------------------------------
300 // Plugin midi-program calls
302 #if DISTRHO_PLUGIN_WANT_PROGRAMS
303 uint32_t getMidiProgramCount() const override
305 return fPlugin
.getProgramCount();
308 const NativeMidiProgram
* getMidiProgramInfo(const uint32_t index
) const override
310 CARLA_SAFE_ASSERT_RETURN(index
< getMidiProgramCount(), nullptr);
312 static NativeMidiProgram midiProgram
;
314 midiProgram
.bank
= index
/ 128;
315 midiProgram
.program
= index
% 128;
316 midiProgram
.name
= fPlugin
.getProgramName(index
);
322 // -------------------------------------------------------------------
323 // Plugin state calls
325 void setParameterValue(const uint32_t index
, const float value
) override
327 CARLA_SAFE_ASSERT_RETURN(index
< getParameterCount(),);
329 fPlugin
.setParameterValue(index
, value
);
332 #if DISTRHO_PLUGIN_WANT_PROGRAMS
333 void setMidiProgram(const uint8_t, const uint32_t bank
, const uint32_t program
) override
335 const uint32_t realProgram(bank
* 128 + program
);
337 CARLA_SAFE_ASSERT_RETURN(realProgram
< getMidiProgramCount(),);
339 fPlugin
.loadProgram(realProgram
);
343 #if DISTRHO_PLUGIN_WANT_STATE
344 void setCustomData(const char* const key
, const char* const value
) override
346 CARLA_SAFE_ASSERT_RETURN(key
!= nullptr && key
[0] != '\0',);
347 CARLA_SAFE_ASSERT_RETURN(value
!= nullptr,);
349 fPlugin
.setState(key
, value
);
353 // -------------------------------------------------------------------
354 // Plugin process calls
356 void activate() override
361 void deactivate() override
363 fPlugin
.deactivate();
366 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
367 void process(const float* const* const inBuffer
, float** const outBuffer
, const uint32_t frames
,
368 const NativeMidiEvent
* const midiEvents
, const uint32_t midiEventCount
) override
370 MidiEvent realMidiEvents
[midiEventCount
];
372 for (uint32_t i
=0; i
< midiEventCount
; ++i
)
374 const NativeMidiEvent
& midiEvent(midiEvents
[i
]);
375 MidiEvent
& realMidiEvent(realMidiEvents
[i
]);
377 realMidiEvent
.frame
= midiEvent
.time
;
378 realMidiEvent
.size
= midiEvent
.size
;
381 for (; j
<midiEvent
.size
; ++j
)
382 realMidiEvent
.data
[j
] = midiEvent
.data
[j
];
383 for (; j
<midiEvent
.size
; ++j
)
384 realMidiEvent
.data
[j
] = midiEvent
.data
[j
];
386 realMidiEvent
.dataExt
= nullptr;
389 fPlugin
.run(const_cast<const float**>(inBuffer
), outBuffer
, frames
, realMidiEvents
, midiEventCount
);
392 void process(const float* const* const inBuffer
, float** const outBuffer
, const uint32_t frames
,
393 const NativeMidiEvent
* const, const uint32_t) override
395 fPlugin
.run(const_cast<const float**>(inBuffer
), outBuffer
, frames
);
399 // -------------------------------------------------------------------
402 #if DISTRHO_PLUGIN_HAS_UI
403 void uiShow(const bool show
) override
408 CARLA_SAFE_ASSERT_RETURN(fUiPtr
!= nullptr,);
410 fUiPtr
->carla_show(show
);
412 else if (fUiPtr
!= nullptr)
419 void uiIdle() override
421 CARLA_SAFE_ASSERT_RETURN(fUiPtr
!= nullptr,);
423 if (! fUiPtr
->carla_idle())
432 void uiSetParameterValue(const uint32_t index
, const float value
) override
434 CARLA_SAFE_ASSERT_RETURN(fUiPtr
!= nullptr,);
435 CARLA_SAFE_ASSERT_RETURN(index
< getParameterCount(),);
437 fUiPtr
->carla_setParameterValue(index
, value
);
440 # if DISTRHO_PLUGIN_WANT_PROGRAMS
441 void uiSetMidiProgram(const uint8_t, const uint32_t bank
, const uint32_t program
) override
443 CARLA_SAFE_ASSERT_RETURN(fUiPtr
!= nullptr,);
445 const uint32_t realProgram(bank
* 128 + program
);
447 CARLA_SAFE_ASSERT_RETURN(realProgram
< getMidiProgramCount(),);
449 fUiPtr
->carla_setMidiProgram(realProgram
);
453 # if DISTRHO_PLUGIN_WANT_STATE
454 void uiSetCustomData(const char* const key
, const char* const value
) override
456 CARLA_SAFE_ASSERT_RETURN(fUiPtr
!= nullptr,);
457 CARLA_SAFE_ASSERT_RETURN(key
!= nullptr && key
[0] != '\0',);
458 CARLA_SAFE_ASSERT_RETURN(value
!= nullptr,);
460 fUiPtr
->carla_setCustomData(key
, value
);
465 // -------------------------------------------------------------------
466 // Plugin dispatcher calls
468 void bufferSizeChanged(const uint32_t bufferSize
) override
470 fPlugin
.setBufferSize(bufferSize
, true);
473 void sampleRateChanged(const double sampleRate
) override
475 fPlugin
.setSampleRate(sampleRate
, true);
478 #if DISTRHO_PLUGIN_HAS_UI
479 void uiNameChanged(const char* const uiName
) override
481 CARLA_SAFE_ASSERT_RETURN(fUiPtr
!= nullptr,);
483 fUiPtr
->carla_setUiTitle(uiName
);
487 // -------------------------------------------------------------------
490 PluginExporter fPlugin
;
491 mutable NativeParameterScalePoint
* fScalePointsCache
;
493 #if DISTRHO_PLUGIN_HAS_UI
497 void createUiIfNeeded()
499 if (fUiPtr
== nullptr)
500 fUiPtr
= new UICarla(getHostHandle(), &fPlugin
);
504 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
505 static bool writeMidiCallback(void* ptr
, const MidiEvent
& midiEvent
)
507 if (midiEvent
.size
> 4)
510 const NativeMidiEvent event
= {
511 midiEvent
.frame
, 0, midiEvent
.size
, midiEvent
.data
514 return ((PluginCarla
*)ptr
)->fPlugin
.writeMidiEvent(midiEvent
);
518 #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
519 bool requestParameterValueChange(const uint32_t index
, const float value
)
521 // TODO implementation
525 static bool requestParameterValueChangeCallback(void* ptr
, const uint32_t index
, const float value
)
527 return thisPtr
->requestParameterValueChange(index
, value
);
531 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla
)
533 // -------------------------------------------------------------------
536 static NativePluginHandle
_instantiate(const NativeHostDescriptor
* host
)
538 d_nextBufferSize
= host
->get_buffer_size(host
->handle
);
539 d_nextSampleRate
= host
->get_sample_rate(host
->handle
);
540 return new PluginCarla(host
);
543 static void _cleanup(NativePluginHandle handle
)
545 delete (PluginCarla
*)handle
;
549 END_NAMESPACE_DISTRHO
551 // -----------------------------------------------------------------------