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 
getParameterSymbol(const uint32_t index) const378     const String& getParameterSymbol(const uint32_t index) const noexcept
379     {
380         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
381 
382         return fData->parameters[index].symbol;
383     }
384 
getParameterUnit(const uint32_t index) const385     const String& getParameterUnit(const uint32_t index) const noexcept
386     {
387         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
388 
389         return fData->parameters[index].unit;
390     }
391 
getParameterEnumValues(const uint32_t index) const392     const ParameterEnumerationValues& getParameterEnumValues(const uint32_t index) const noexcept
393     {
394         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackEnumValues);
395 
396         return fData->parameters[index].enumValues;
397     }
398 
getParameterRanges(const uint32_t index) const399     const ParameterRanges& getParameterRanges(const uint32_t index) const noexcept
400     {
401         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackRanges);
402 
403         return fData->parameters[index].ranges;
404     }
405 
getParameterMidiCC(const uint32_t index) const406     uint8_t getParameterMidiCC(const uint32_t index) const noexcept
407     {
408         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0);
409 
410         return fData->parameters[index].midiCC;
411     }
412 
getParameterValue(const uint32_t index) const413     float getParameterValue(const uint32_t index) const
414     {
415         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
416         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f);
417 
418         return fPlugin->getParameterValue(index);
419     }
420 
setParameterValue(const uint32_t index,const float value)421     void setParameterValue(const uint32_t index, const float value)
422     {
423         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
424         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount,);
425 
426         fPlugin->setParameterValue(index, value);
427     }
428 
429 #if DISTRHO_PLUGIN_WANT_PROGRAMS
getProgramCount() const430     uint32_t getProgramCount() const noexcept
431     {
432         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
433 
434         return fData->programCount;
435     }
436 
getProgramName(const uint32_t index) const437     const String& getProgramName(const uint32_t index) const noexcept
438     {
439         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount, sFallbackString);
440 
441         return fData->programNames[index];
442     }
443 
loadProgram(const uint32_t index)444     void loadProgram(const uint32_t index)
445     {
446         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
447         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount,);
448 
449         fPlugin->loadProgram(index);
450     }
451 #endif
452 
453 #if DISTRHO_PLUGIN_WANT_STATE
getStateCount() const454     uint32_t getStateCount() const noexcept
455     {
456         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
457 
458         return fData->stateCount;
459     }
460 
getStateKey(const uint32_t index) const461     const String& getStateKey(const uint32_t index) const noexcept
462     {
463         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
464 
465         return fData->stateKeys[index];
466     }
467 
getStateDefaultValue(const uint32_t index) const468     const String& getStateDefaultValue(const uint32_t index) const noexcept
469     {
470         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
471 
472         return fData->stateDefValues[index];
473     }
474 
475 # if DISTRHO_PLUGIN_WANT_FULL_STATE
getState(const char * key) const476     String getState(const char* key) const
477     {
478         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString);
479         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', sFallbackString);
480 
481         return fPlugin->getState(key);
482     }
483 # endif
484 
setState(const char * const key,const char * const value)485     void setState(const char* const key, const char* const value)
486     {
487         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
488         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
489         DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
490 
491         fPlugin->setState(key, value);
492     }
493 
wantStateKey(const char * const key) const494     bool wantStateKey(const char* const key) const noexcept
495     {
496         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false);
497         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false);
498 
499         for (uint32_t i=0; i < fData->stateCount; ++i)
500         {
501             if (fData->stateKeys[i] == key)
502                 return true;
503         }
504 
505         return false;
506     }
507 #endif
508 
509 #if DISTRHO_PLUGIN_WANT_TIMEPOS
setTimePosition(const TimePosition & timePosition)510     void setTimePosition(const TimePosition& timePosition) noexcept
511     {
512         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
513 
514         std::memcpy(&fData->timePosition, &timePosition, sizeof(TimePosition));
515     }
516 #endif
517 
518     // -------------------------------------------------------------------
519 
isActive() const520     bool isActive() const noexcept
521     {
522         return fIsActive;
523     }
524 
activate()525     void activate()
526     {
527         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
528         DISTRHO_SAFE_ASSERT_RETURN(! fIsActive,);
529 
530         fIsActive = true;
531         fPlugin->activate();
532     }
533 
deactivate()534     void deactivate()
535     {
536         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
537         DISTRHO_SAFE_ASSERT_RETURN(fIsActive,);
538 
539         fIsActive = false;
540         fPlugin->deactivate();
541     }
542 
deactivateIfNeeded()543     void deactivateIfNeeded()
544     {
545         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
546 
547         if (fIsActive)
548         {
549             fIsActive = false;
550             fPlugin->deactivate();
551         }
552     }
553 
554 #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)555     void run(const float** const inputs, float** const outputs, const uint32_t frames,
556              const MidiEvent* const midiEvents, const uint32_t midiEventCount)
557     {
558         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
559         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
560 
561         if (! fIsActive)
562         {
563             fIsActive = true;
564             fPlugin->activate();
565         }
566 
567         fData->isProcessing = true;
568         fPlugin->run(inputs, outputs, frames, midiEvents, midiEventCount);
569         fData->isProcessing = false;
570     }
571 #else
run(const float ** const inputs,float ** const outputs,const uint32_t frames)572     void run(const float** const inputs, float** const outputs, const uint32_t frames)
573     {
574         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
575         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
576 
577         if (! fIsActive)
578         {
579             fIsActive = true;
580             fPlugin->activate();
581         }
582 
583         fData->isProcessing = true;
584         fPlugin->run(inputs, outputs, frames);
585         fData->isProcessing = false;
586     }
587 #endif
588 
589     // -------------------------------------------------------------------
590 
getBufferSize() const591     uint32_t getBufferSize() const noexcept
592     {
593         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
594         return fData->bufferSize;
595     }
596 
getSampleRate() const597     double getSampleRate() const noexcept
598     {
599         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0.0);
600         return fData->sampleRate;
601     }
602 
setBufferSize(const uint32_t bufferSize,const bool doCallback=false)603     void setBufferSize(const uint32_t bufferSize, const bool doCallback = false)
604     {
605         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
606         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
607         DISTRHO_SAFE_ASSERT(bufferSize >= 2);
608 
609         if (fData->bufferSize == bufferSize)
610             return;
611 
612         fData->bufferSize = bufferSize;
613 
614         if (doCallback)
615         {
616             if (fIsActive) fPlugin->deactivate();
617             fPlugin->bufferSizeChanged(bufferSize);
618             if (fIsActive) fPlugin->activate();
619         }
620     }
621 
setSampleRate(const double sampleRate,const bool doCallback=false)622     void setSampleRate(const double sampleRate, const bool doCallback = false)
623     {
624         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
625         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
626         DISTRHO_SAFE_ASSERT(sampleRate > 0.0);
627 
628         if (d_isEqual(fData->sampleRate, sampleRate))
629             return;
630 
631         fData->sampleRate = sampleRate;
632 
633         if (doCallback)
634         {
635             if (fIsActive) fPlugin->deactivate();
636             fPlugin->sampleRateChanged(sampleRate);
637             if (fIsActive) fPlugin->activate();
638         }
639     }
640 
641 private:
642     // -------------------------------------------------------------------
643     // Plugin and DistrhoPlugin data
644 
645     Plugin* const fPlugin;
646     Plugin::PrivateData* const fData;
647     bool fIsActive;
648 
649     // -------------------------------------------------------------------
650     // Static fallback data, see DistrhoPlugin.cpp
651 
652     static const String                     sFallbackString;
653     static const AudioPort                  sFallbackAudioPort;
654     static const ParameterRanges            sFallbackRanges;
655     static const ParameterEnumerationValues sFallbackEnumValues;
656 
657     DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter)
658     DISTRHO_PREVENT_HEAP_ALLOCATION
659 };
660 
661 // -----------------------------------------------------------------------
662 
663 END_NAMESPACE_DISTRHO
664 
665 #endif // DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
666