1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com>
4  *
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.
8  *
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.
15  */
16 
17 #ifndef DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
18 #define DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
19 
20 #include "../DistrhoPlugin.hpp"
21 
22 START_NAMESPACE_DISTRHO
23 
24 // -----------------------------------------------------------------------
25 // Maxmimum values
26 
27 static const uint32_t kMaxMidiEvents = 512;
28 
29 // -----------------------------------------------------------------------
30 // Static data, see DistrhoPlugin.cpp
31 
32 extern uint32_t d_lastBufferSize;
33 extern double   d_lastSampleRate;
34 
35 // -----------------------------------------------------------------------
36 // DSP callbacks
37 
38 typedef bool (*writeMidiFunc) (void* ptr, const MidiEvent& midiEvent);
39 
40 // -----------------------------------------------------------------------
41 // Plugin private data
42 
43 struct Plugin::PrivateData {
44     bool isProcessing;
45 
46 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
47     AudioPort* audioPorts;
48 #endif
49 
50     uint32_t   parameterCount;
51     uint32_t   parameterOffset;
52     Parameter* parameters;
53 
54 #if DISTRHO_PLUGIN_WANT_PROGRAMS
55     uint32_t programCount;
56     String*  programNames;
57 #endif
58 
59 #if DISTRHO_PLUGIN_WANT_STATE
60     uint32_t stateCount;
61     String*  stateKeys;
62     String*  stateDefValues;
63 #endif
64 
65 #if DISTRHO_PLUGIN_WANT_LATENCY
66     uint32_t latency;
67 #endif
68 
69 #if DISTRHO_PLUGIN_WANT_TIMEPOS
70     TimePosition timePosition;
71 #endif
72 
73     // Callbacks
74     void*         callbacksPtr;
75     writeMidiFunc writeMidiCallbackFunc;
76 
77     uint32_t bufferSize;
78     double   sampleRate;
79 
PrivateDataPlugin::PrivateData80     PrivateData() noexcept
81         : isProcessing(false),
82 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
83           audioPorts(nullptr),
84 #endif
85           parameterCount(0),
86           parameterOffset(0),
87           parameters(nullptr),
88 #if DISTRHO_PLUGIN_WANT_PROGRAMS
89           programCount(0),
90           programNames(nullptr),
91 #endif
92 #if DISTRHO_PLUGIN_WANT_STATE
93           stateCount(0),
94           stateKeys(nullptr),
95           stateDefValues(nullptr),
96 #endif
97 #if DISTRHO_PLUGIN_WANT_LATENCY
98           latency(0),
99 #endif
100           callbacksPtr(nullptr),
101           writeMidiCallbackFunc(nullptr),
102           bufferSize(d_lastBufferSize),
103           sampleRate(d_lastSampleRate)
104     {
105         DISTRHO_SAFE_ASSERT(bufferSize != 0);
106         DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate));
107 
108 #if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2)
109         parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
110 # if DISTRHO_PLUGIN_WANT_LATENCY
111         parameterOffset += 1;
112 # endif
113 #endif
114 
115 #ifdef DISTRHO_PLUGIN_TARGET_LV2
116 # if (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE)
117         parameterOffset += 1;
118 #  if DISTRHO_PLUGIN_WANT_STATE
119         parameterOffset += 1;
120 #  endif
121 # endif
122 #endif
123     }
124 
~PrivateDataPlugin::PrivateData125     ~PrivateData() noexcept
126     {
127 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
128         if (audioPorts != nullptr)
129         {
130             delete[] audioPorts;
131             audioPorts = nullptr;
132         }
133 #endif
134 
135         if (parameters != nullptr)
136         {
137             delete[] parameters;
138             parameters = nullptr;
139         }
140 
141 #if DISTRHO_PLUGIN_WANT_PROGRAMS
142         if (programNames != nullptr)
143         {
144             delete[] programNames;
145             programNames = nullptr;
146         }
147 #endif
148 
149 #if DISTRHO_PLUGIN_WANT_STATE
150         if (stateKeys != nullptr)
151         {
152             delete[] stateKeys;
153             stateKeys = nullptr;
154         }
155 
156         if (stateDefValues != nullptr)
157         {
158             delete[] stateDefValues;
159             stateDefValues = nullptr;
160         }
161 #endif
162     }
163 
164 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
writeMidiCallbackPlugin::PrivateData165     bool writeMidiCallback(const MidiEvent& midiEvent)
166     {
167         if (writeMidiCallbackFunc != nullptr)
168             return writeMidiCallbackFunc(callbacksPtr, midiEvent);
169 
170         return false;
171     }
172 #endif
173 };
174 
175 // -----------------------------------------------------------------------
176 // Plugin exporter class
177 
178 class PluginExporter
179 {
180 public:
PluginExporter(void * const callbacksPtr,const writeMidiFunc writeMidiCall)181     PluginExporter(void* const callbacksPtr, const writeMidiFunc writeMidiCall)
182         : fPlugin(createPlugin()),
183           fData((fPlugin != nullptr) ? fPlugin->pData : nullptr),
184           fIsActive(false)
185     {
186         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
187         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
188 
189 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
190         {
191             uint32_t j=0;
192 # if DISTRHO_PLUGIN_NUM_INPUTS > 0
193             for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j)
194                 fPlugin->initAudioPort(true, i, fData->audioPorts[j]);
195 # endif
196 # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
197             for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j)
198                 fPlugin->initAudioPort(false, i, fData->audioPorts[j]);
199 # endif
200         }
201 #endif
202 
203         for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
204             fPlugin->initParameter(i, fData->parameters[i]);
205 
206 #if DISTRHO_PLUGIN_WANT_PROGRAMS
207         for (uint32_t i=0, count=fData->programCount; i < count; ++i)
208             fPlugin->initProgramName(i, fData->programNames[i]);
209 #endif
210 
211 #if DISTRHO_PLUGIN_WANT_STATE
212         for (uint32_t i=0, count=fData->stateCount; i < count; ++i)
213             fPlugin->initState(i, fData->stateKeys[i], fData->stateDefValues[i]);
214 #endif
215 
216         fData->callbacksPtr          = callbacksPtr;
217         fData->writeMidiCallbackFunc = writeMidiCall;
218     }
219 
~PluginExporter()220     ~PluginExporter()
221     {
222         delete fPlugin;
223     }
224 
225     // -------------------------------------------------------------------
226 
getName() const227     const char* getName() const noexcept
228     {
229         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
230 
231         return fPlugin->getName();
232     }
233 
getLabel() const234     const char* getLabel() const noexcept
235     {
236         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
237 
238         return fPlugin->getLabel();
239     }
240 
getDescription() const241     const char* getDescription() const noexcept
242     {
243         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
244 
245         return fPlugin->getDescription();
246     }
247 
getMaker() const248     const char* getMaker() const noexcept
249     {
250         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
251 
252         return fPlugin->getMaker();
253     }
254 
getHomePage() const255     const char* getHomePage() const noexcept
256     {
257         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
258 
259         return fPlugin->getHomePage();
260     }
261 
getLicense() const262     const char* getLicense() const noexcept
263     {
264         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
265 
266         return fPlugin->getLicense();
267     }
268 
getVersion() const269     uint32_t getVersion() const noexcept
270     {
271         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0);
272 
273         return fPlugin->getVersion();
274     }
275 
getUniqueId() const276     long getUniqueId() const noexcept
277     {
278         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0);
279 
280         return fPlugin->getUniqueId();
281     }
282 
getInstancePointer() const283     void* getInstancePointer() const noexcept
284     {
285         return fPlugin;
286     }
287 
288     // -------------------------------------------------------------------
289 
290 #if DISTRHO_PLUGIN_WANT_LATENCY
getLatency() const291     uint32_t getLatency() const noexcept
292     {
293         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
294 
295         return fData->latency;
296     }
297 #endif
298 
299 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
getAudioPort(const bool input,const uint32_t index) const300     const AudioPort& getAudioPort(const bool input, const uint32_t index) const noexcept
301     {
302         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort);
303 
304         if (input)
305         {
306 # if DISTRHO_PLUGIN_NUM_INPUTS > 0
307             DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_INPUTS,  sFallbackAudioPort);
308 # endif
309         }
310         else
311         {
312 # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
313             DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_OUTPUTS, sFallbackAudioPort);
314 # endif
315         }
316 
317         return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)];
318     }
319 #endif
320 
getParameterCount() const321     uint32_t getParameterCount() const noexcept
322     {
323         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
324 
325         return fData->parameterCount;
326     }
327 
getParameterOffset() const328     uint32_t getParameterOffset() const noexcept
329     {
330         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
331 
332         return fData->parameterOffset;
333     }
334 
getParameterHints(const uint32_t index) const335     uint32_t getParameterHints(const uint32_t index) const noexcept
336     {
337         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0x0);
338 
339         return fData->parameters[index].hints;
340     }
341 
getParameterDesignation(const uint32_t index) const342     ParameterDesignation getParameterDesignation(const uint32_t index) const noexcept
343     {
344         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kParameterDesignationNull);
345 
346         return fData->parameters[index].designation;
347     }
348 
isParameterInput(const uint32_t index) const349     bool isParameterInput(const uint32_t index) const noexcept
350     {
351         return (getParameterHints(index) & kParameterIsOutput) == 0x0;
352     }
353 
isParameterOutput(const uint32_t index) const354     bool isParameterOutput(const uint32_t index) const noexcept
355     {
356         return (getParameterHints(index) & kParameterIsOutput) != 0x0;
357     }
358 
isParameterOutputOrTrigger(const uint32_t index) const359     bool isParameterOutputOrTrigger(const uint32_t index) const noexcept
360     {
361         const uint32_t hints = getParameterHints(index);
362 
363         if (hints & kParameterIsOutput)
364             return true;
365         if ((hints & kParameterIsTrigger) == kParameterIsTrigger)
366             return true;
367 
368         return false;
369     }
370 
getParameterName(const uint32_t index) const371     const String& getParameterName(const uint32_t index) const noexcept
372     {
373         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
374 
375         return fData->parameters[index].name;
376     }
377 
getParameterShortName(const uint32_t index) const378     const String& getParameterShortName(const uint32_t index) const noexcept
379     {
380         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
381 
382         return fData->parameters[index].shortName;
383     }
384 
getParameterSymbol(const uint32_t index) const385     const String& getParameterSymbol(const uint32_t index) const noexcept
386     {
387         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
388 
389         return fData->parameters[index].symbol;
390     }
391 
getParameterUnit(const uint32_t index) const392     const String& getParameterUnit(const uint32_t index) const noexcept
393     {
394         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
395 
396         return fData->parameters[index].unit;
397     }
398 
getParameterDescription(const uint32_t index) const399     const String& getParameterDescription(const uint32_t index) const noexcept
400     {
401         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
402 
403         return fData->parameters[index].description;
404     }
405 
getParameterEnumValues(const uint32_t index) const406     const ParameterEnumerationValues& getParameterEnumValues(const uint32_t index) const noexcept
407     {
408         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackEnumValues);
409 
410         return fData->parameters[index].enumValues;
411     }
412 
getParameterRanges(const uint32_t index) const413     const ParameterRanges& getParameterRanges(const uint32_t index) const noexcept
414     {
415         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackRanges);
416 
417         return fData->parameters[index].ranges;
418     }
419 
getParameterMidiCC(const uint32_t index) const420     uint8_t getParameterMidiCC(const uint32_t index) const noexcept
421     {
422         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0);
423 
424         return fData->parameters[index].midiCC;
425     }
426 
getParameterValue(const uint32_t index) const427     float getParameterValue(const uint32_t index) const
428     {
429         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
430         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f);
431 
432         return fPlugin->getParameterValue(index);
433     }
434 
setParameterValue(const uint32_t index,const float value)435     void setParameterValue(const uint32_t index, const float value)
436     {
437         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
438         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount,);
439 
440         fPlugin->setParameterValue(index, value);
441     }
442 
443 #if DISTRHO_PLUGIN_WANT_PROGRAMS
getProgramCount() const444     uint32_t getProgramCount() const noexcept
445     {
446         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
447 
448         return fData->programCount;
449     }
450 
getProgramName(const uint32_t index) const451     const String& getProgramName(const uint32_t index) const noexcept
452     {
453         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount, sFallbackString);
454 
455         return fData->programNames[index];
456     }
457 
loadProgram(const uint32_t index)458     void loadProgram(const uint32_t index)
459     {
460         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
461         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount,);
462 
463         fPlugin->loadProgram(index);
464     }
465 #endif
466 
467 #if DISTRHO_PLUGIN_WANT_STATE
getStateCount() const468     uint32_t getStateCount() const noexcept
469     {
470         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
471 
472         return fData->stateCount;
473     }
474 
getStateKey(const uint32_t index) const475     const String& getStateKey(const uint32_t index) const noexcept
476     {
477         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
478 
479         return fData->stateKeys[index];
480     }
481 
getStateDefaultValue(const uint32_t index) const482     const String& getStateDefaultValue(const uint32_t index) const noexcept
483     {
484         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
485 
486         return fData->stateDefValues[index];
487     }
488 
489 # if DISTRHO_PLUGIN_WANT_STATEFILES
isStateFile(const uint32_t index) const490     bool isStateFile(const uint32_t index) const
491     {
492         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, false);
493 
494         return fPlugin->isStateFile(index);
495     }
496 # endif
497 
498 # if DISTRHO_PLUGIN_WANT_FULL_STATE
getState(const char * key) const499     String getState(const char* key) const
500     {
501         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString);
502         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', sFallbackString);
503 
504         return fPlugin->getState(key);
505     }
506 # endif
507 
setState(const char * const key,const char * const value)508     void setState(const char* const key, const char* const value)
509     {
510         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
511         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
512         DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
513 
514         fPlugin->setState(key, value);
515     }
516 
wantStateKey(const char * const key) const517     bool wantStateKey(const char* const key) const noexcept
518     {
519         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false);
520         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false);
521 
522         for (uint32_t i=0; i < fData->stateCount; ++i)
523         {
524             if (fData->stateKeys[i] == key)
525                 return true;
526         }
527 
528         return false;
529     }
530 #endif
531 
532 #if DISTRHO_PLUGIN_WANT_TIMEPOS
setTimePosition(const TimePosition & timePosition)533     void setTimePosition(const TimePosition& timePosition) noexcept
534     {
535         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
536 
537         std::memcpy(&fData->timePosition, &timePosition, sizeof(TimePosition));
538     }
539 #endif
540 
541     // -------------------------------------------------------------------
542 
isActive() const543     bool isActive() const noexcept
544     {
545         return fIsActive;
546     }
547 
activate()548     void activate()
549     {
550         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
551         DISTRHO_SAFE_ASSERT_RETURN(! fIsActive,);
552 
553         fIsActive = true;
554         fPlugin->activate();
555     }
556 
deactivate()557     void deactivate()
558     {
559         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
560         DISTRHO_SAFE_ASSERT_RETURN(fIsActive,);
561 
562         fIsActive = false;
563         fPlugin->deactivate();
564     }
565 
deactivateIfNeeded()566     void deactivateIfNeeded()
567     {
568         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
569 
570         if (fIsActive)
571         {
572             fIsActive = false;
573             fPlugin->deactivate();
574         }
575     }
576 
577 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
run(const float ** const inputs,float ** const outputs,const uint32_t frames,const MidiEvent * const midiEvents,const uint32_t midiEventCount)578     void run(const float** const inputs, float** const outputs, const uint32_t frames,
579              const MidiEvent* const midiEvents, const uint32_t midiEventCount)
580     {
581         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
582         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
583 
584         if (! fIsActive)
585         {
586             fIsActive = true;
587             fPlugin->activate();
588         }
589 
590         fData->isProcessing = true;
591         fPlugin->run(inputs, outputs, frames, midiEvents, midiEventCount);
592         fData->isProcessing = false;
593     }
594 #else
run(const float ** const inputs,float ** const outputs,const uint32_t frames)595     void run(const float** const inputs, float** const outputs, const uint32_t frames)
596     {
597         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
598         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
599 
600         if (! fIsActive)
601         {
602             fIsActive = true;
603             fPlugin->activate();
604         }
605 
606         fData->isProcessing = true;
607         fPlugin->run(inputs, outputs, frames);
608         fData->isProcessing = false;
609     }
610 #endif
611 
612     // -------------------------------------------------------------------
613 
getBufferSize() const614     uint32_t getBufferSize() const noexcept
615     {
616         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
617         return fData->bufferSize;
618     }
619 
getSampleRate() const620     double getSampleRate() const noexcept
621     {
622         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0.0);
623         return fData->sampleRate;
624     }
625 
setBufferSize(const uint32_t bufferSize,const bool doCallback=false)626     void setBufferSize(const uint32_t bufferSize, const bool doCallback = false)
627     {
628         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
629         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
630         DISTRHO_SAFE_ASSERT(bufferSize >= 2);
631 
632         if (fData->bufferSize == bufferSize)
633             return;
634 
635         fData->bufferSize = bufferSize;
636 
637         if (doCallback)
638         {
639             if (fIsActive) fPlugin->deactivate();
640             fPlugin->bufferSizeChanged(bufferSize);
641             if (fIsActive) fPlugin->activate();
642         }
643     }
644 
setSampleRate(const double sampleRate,const bool doCallback=false)645     void setSampleRate(const double sampleRate, const bool doCallback = false)
646     {
647         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
648         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
649         DISTRHO_SAFE_ASSERT(sampleRate > 0.0);
650 
651         if (d_isEqual(fData->sampleRate, sampleRate))
652             return;
653 
654         fData->sampleRate = sampleRate;
655 
656         if (doCallback)
657         {
658             if (fIsActive) fPlugin->deactivate();
659             fPlugin->sampleRateChanged(sampleRate);
660             if (fIsActive) fPlugin->activate();
661         }
662     }
663 
664 private:
665     // -------------------------------------------------------------------
666     // Plugin and DistrhoPlugin data
667 
668     Plugin* const fPlugin;
669     Plugin::PrivateData* const fData;
670     bool fIsActive;
671 
672     // -------------------------------------------------------------------
673     // Static fallback data, see DistrhoPlugin.cpp
674 
675     static const String                     sFallbackString;
676     static const AudioPort                  sFallbackAudioPort;
677     static const ParameterRanges            sFallbackRanges;
678     static const ParameterEnumerationValues sFallbackEnumValues;
679 
680     DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter)
681     DISTRHO_PREVENT_HEAP_ALLOCATION
682 };
683 
684 // -----------------------------------------------------------------------
685 
686 END_NAMESPACE_DISTRHO
687 
688 #endif // DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
689