summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.plugins.mk7
-rw-r--r--distrho/extra/String.hpp11
-rw-r--r--distrho/src/CocoaUI/PluginAU_CocoaUI.m18
-rw-r--r--distrho/src/DistrhoPluginAU.cpp1129
-rw-r--r--distrho/src/DistrhoPluginAU.h207
5 files changed, 1111 insertions, 261 deletions
diff --git a/Makefile.plugins.mk b/Makefile.plugins.mk
index 07889472..b104671c 100644
--- a/Makefile.plugins.mk
+++ b/Makefile.plugins.mk
@@ -71,6 +71,7 @@ AU_BUILD_FLAGS = \
-I$(DPF_PATH)/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase \
-I$(DPF_PATH)/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility \
-I$(DPF_PATH)/distrho/src/CoreAudio106/PublicUtility\
+ -I$(DPF_PATH)/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases \
-Wno-deprecated-declarations \
-Wno-four-char-constants \
-Wno-overloaded-virtual \
@@ -348,10 +349,10 @@ $(au_uiplist):
$(au_rsrc):
-@mkdir -p $(shell dirname $@)
@echo "Creating AU rsrc for $(NAME)"
- $(DPF_PATH)/utils/AuRez aufx fxfx 'dpf ' \
+ $(DPF_PATH)/utils/AuRez aufx \?\?\?\? DPFx \
$(REZ_FLAGS) \
- -o $@ -M dpf -P $(NAME) -V 0.0.0 \
- -e _PluginAUEntry -v _PluginAU_CocoaUI
+ -o $@ -M DPF -P $(NAME) -V 0.0.0 \
+ -e _PluginAUEntry -v PluginAU_CocoaUIFactory
$(BUILD_DIR)/PluginAU_CocoaUI.mm.o: $(DPF_PATH)/distrho/src/CocoaUI/PluginAU_CocoaUI.m
-@mkdir -p $(shell dirname $@)
diff --git a/distrho/extra/String.hpp b/distrho/extra/String.hpp
index 650c5bbd..273b2b8d 100644
--- a/distrho/extra/String.hpp
+++ b/distrho/extra/String.hpp
@@ -54,6 +54,17 @@ public:
}
/*
+ * Simple char string, with known length.
+ */
+ explicit String(char* const strBuf, const int len) noexcept
+ : fBuffer(_null()),
+ fBufferLen(0)
+ {
+ fBuffer = strBuf;
+ fBufferLen = len;
+ }
+
+ /*
* Simple char string.
*/
explicit String(char* const strBuf, const bool copyData = true) noexcept
diff --git a/distrho/src/CocoaUI/PluginAU_CocoaUI.m b/distrho/src/CocoaUI/PluginAU_CocoaUI.m
index dec13f50..44fb79fa 100644
--- a/distrho/src/CocoaUI/PluginAU_CocoaUI.m
+++ b/distrho/src/CocoaUI/PluginAU_CocoaUI.m
@@ -3,7 +3,6 @@
#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AUCocoaUIView.h>
#include "DistrhoUIInternal.hpp"
-#include "DistrhoPluginInternal.hpp" // Direct access
#define MAX_PARAMS 100
@@ -14,7 +13,6 @@ class UIAu
public:
UIAu(const char* const uiTitle)
: fUI(this, 0, nullptr, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback),
- fPlugin((PluginExporter *)fUI.getDirectAccess()),
fHostClosed(false)
{
fUI.setWindowTitle(uiTitle);
@@ -24,11 +22,6 @@ public:
{
}
- uint32_t getParameterCountFromDSP()
- {
- return fPlugin->getParameterCount();
- }
-
void auui_showhide(bool show)
{
fUI.setWindowVisible(show);
@@ -55,7 +48,6 @@ protected:
private:
UIExporter fUI;
- PluginExporter *fPlugin;
bool fHostClosed;
// -------------------------------------------------------------------
@@ -130,8 +122,14 @@ END_NAMESPACE_DISTRHO
if (mAU) [self _removeListeners];
mAU = inAU;
fUIAu = new UIAu(DISTRHO_PLUGIN_NAME);
-
- paramCount = fUIAu->getParameterCountFromDSP();
+ void *data = NULL;
+
+ AudioUnitGetProperty (inAU,
+ kAudioUnitProperty_ParameterList,
+ kAudioUnitScope_Global,
+ 0,
+ data,
+ &paramCount);
UInt32 i;
for (i = 0; i < paramCount; ++i) {
diff --git a/distrho/src/DistrhoPluginAU.cpp b/distrho/src/DistrhoPluginAU.cpp
index 9c5a21bd..fc7cc5e0 100644
--- a/distrho/src/DistrhoPluginAU.cpp
+++ b/distrho/src/DistrhoPluginAU.cpp
@@ -14,221 +14,483 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "DistrhoPluginInternal.hpp"
+#include "DistrhoPluginAU.h"
-#include "CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.h"
+START_NAMESPACE_DISTRHO
-// -----------------------------------------------------------------------
+PluginAU::PluginAU (AudioUnit component)
+ : MusicDeviceBase (component, 1, 1),
+ fLastValuesInit(),
+ fPlugin(this, writeMidiCallback),
+ fLastParameterValues(nullptr)
+{
+ inParameterChangedCallback = false;
-START_NAMESPACE_DISTRHO
+ short configs[][2] = {{ DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS }};
+ const int numConfigs = sizeof (configs) / sizeof (short[2]);
-// #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
-static const writeMidiFunc writeMidiCallback = nullptr;
-// #endif
+ fPlugin.setBufferSize(1024, true);
+ fPlugin.setSampleRate(44100.0, true);
-// -----------------------------------------------------------------------
+ if (const uint32_t count = fPlugin.getParameterCount())
+ {
+ fPortControls = new float*[count];
+ fLastControlValues = new float[count];
-struct LastValuesInit {
- LastValuesInit()
+ for (uint32_t i=0; i < count; ++i)
+ {
+ fPortControls[i] = nullptr;
+ fLastControlValues[i] = fPlugin.getParameterValue(i);
+ }
+ }
+ else
{
- if (d_lastBufferSize == 0)
- d_lastBufferSize = kAUDefaultMaxFramesPerSlice;
+ fPortControls = nullptr;
+ fLastControlValues = nullptr;
+ }
- if (d_isZero(d_lastSampleRate))
- d_lastSampleRate = kAUDefaultSampleRate;
- };
-};
+ for (int i = 0; i < numConfigs; ++i)
+ {
+ AUChannelInfo info;
-// -----------------------------------------------------------------------
-// AU Plugin
+ info.inChannels = configs[i][0];
+ info.outChannels = configs[i][1];
-class PluginAU : public AUEffectBase
-{
-public:
- PluginAU(AudioUnit component)
- : AUEffectBase(component),
- fLastValuesInit(),
- fPlugin(this, writeMidiCallback),
- fLastParameterValues(nullptr)
- {
- CreateElements();
+ channelInfo.push_back (info);
+ }
- AUElement* const globals = Globals();
- DISTRHO_SAFE_ASSERT_RETURN(globals != nullptr,);
+ //AddPropertyListener (kAudioUnitProperty_ContextName, auPropertyListenerDispatcher, this);
- if (const uint32_t paramCount = fPlugin.getParameterCount())
- {
- fLastParameterValues = new float[paramCount];
- globals->UseIndexedParameters(paramCount);
+ totalInChannels = DISTRHO_PLUGIN_NUM_INPUTS;
+ totalOutChannels = DISTRHO_PLUGIN_NUM_OUTPUTS;
- for (uint32_t i=0; i < paramCount; ++i)
- {
- fLastParameterValues[i] = fPlugin.getParameterValue(i);
- globals->SetParameter(i, fLastParameterValues[i]);
- }
- }
- }
+ addParameters();
- ~PluginAU() override
+ memset (&auEvent, 0, sizeof(auEvent));
+ auEvent.mArgument.mParameter.mAudioUnit = GetComponentInstance();
+ auEvent.mArgument.mParameter.mScope = kAudioUnitScope_Global;
+ auEvent.mArgument.mParameter.mElement = 0;
+
+ memset (&midiCallback, 0, sizeof(midiCallback));
+
+ CreateElements();
+
+ syncAudioUnitWithProcessor();
+}
+
+PluginAU::~PluginAU() override
+{
+ if (fLastParameterValues)
{
- if (fLastParameterValues)
- {
- delete[] fLastParameterValues;
- fLastParameterValues = nullptr;
- }
+ delete[] fLastParameterValues;
+ fLastParameterValues = nullptr;
}
-
-protected:
- OSStatus GetParameterValueStrings(AudioUnitScope inScope,
- AudioUnitParameterID inParameterID,
- CFArrayRef* outStrings) override
+ if (fLastControlValues)
{
- // TODO scalepoints support via kAudioUnitParameterFlag_ValuesHaveStrings
- return kAudioUnitErr_InvalidProperty;
+ delete[] fLastControlValues;
+ fLastControlValues = nullptr;
}
-
- OSStatus GetParameterInfo(AudioUnitScope inScope,
- AudioUnitParameterID inParameterID,
- AudioUnitParameterInfo& outParameterInfo) override
+ if (fPortControls)
{
- DISTRHO_SAFE_ASSERT_RETURN(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidParameter);
+ delete[] fPortControls;
+ fPortControls = nullptr;
+ }
- outParameterInfo.flags = kAudioUnitParameterFlag_IsReadable | kAudioUnitParameterFlag_IsWritable;
+ // shut fUI;
+}
- // Name
- {
- const String& name = fPlugin.getParameterName(inParameterID);
- CFStringRef cfname = CFStringCreateWithCString(kCFAllocatorDefault, name.buffer(), kCFStringEncodingUTF8);
+ComponentResult
+PluginAU::Initialize() override
+{
+ ComponentResult err;
- AUBase::FillInParameterName(outParameterInfo, cfname, false);
- }
+ if ((err = syncProcessorWithAudioUnit()) != noErr)
+ return err;
+
+ if ((err = MusicDeviceBase::Initialize()) != noErr)
+ return err;
+
+ pulledSucceeded = false;
+
+ prepareToPlay();
+
+ return noErr;
+}
+
+void
+PluginAU::Cleanup() override
+{
+ fPlugin.deactivate();
+ MusicDeviceBase::Cleanup();
+
+ midiEvents.clear();
+ incomingEvents.clear();
+ prepared = false;
+}
+
+ComponentResult
+PluginAU::Reset (AudioUnitScope inScope, AudioUnitElement inElement) override
+{
+ if (! prepared)
+ prepareToPlay();
+
+ return MusicDeviceBase::Reset (inScope, inElement);
+}
+
+void PluginAU::prepareToPlay()
+{
+ fPlugin.setBufferSize (GetMaxFramesPerSlice(), true);
+ fPlugin.setSampleRate (getSampleRate(), true);
+ fPlugin.activate();
+
+ midiEvents.clear();
+ incomingEvents.clear();
+
+ prepared = true;
+}
+
+bool
+PluginAU::BusCountWritable (AudioUnitScope scope) override
+{
+ return false;
+}
+
+OSStatus
+PluginAU::SetBusCount (AudioUnitScope scope, UInt32 count) override
+{
+ OSStatus err = noErr;
+ bool isInput;
+
+ if ((err = scopeToDirection (scope, isInput)) != noErr)
+ return err;
+
+ if (count != 1)
+ {
+ return kAudioUnitErr_PropertyNotWritable;
+ }
- // Hints
+ return noErr;
+}
+
+UInt32
+PluginAU::SupportedNumChannels (const AUChannelInfo** outInfo) override
+{
+ if (outInfo != nullptr)
+ *outInfo = &channelInfo[0];
+
+ return (UInt32) channelInfo.size();
+}
+
+ComponentResult
+PluginAU::GetPropertyInfo (AudioUnitPropertyID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ UInt32& outDataSize,
+ Boolean& outWritable) override
+{
+ if (inScope == kAudioUnitScope_Global)
+ {
+ switch (inID)
{
- const uint32_t hints(fPlugin.getParameterHints(inParameterID));
-
- // other interesting bits:
- // kAudioUnitParameterFlag_OmitFromPresets for outputs?
- // kAudioUnitParameterFlag_MeterReadOnly for outputs?
- // kAudioUnitParameterFlag_CanRamp for log?
- // kAudioUnitParameterFlag_IsHighResolution ??
-
- if ((hints & kParameterIsAutomable) == 0x0)
- outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime;
-
- /* TODO: there doesn't seem to be a hint for this
- if (hints & kParameterIsBoolean)
- {}
- else if (hints & kParameterIsInteger)
- {}
- */
-
- if (hints & kParameterIsLogarithmic)
- outParameterInfo.flags |= kAudioUnitParameterFlag_DisplayLogarithmic;
+ case kAudioUnitProperty_OfflineRender:
+ outWritable = true;
+ outDataSize = sizeof (UInt32);
+ return noErr;
+
+ case kMusicDeviceProperty_InstrumentCount:
+ outDataSize = sizeof (UInt32);
+ outWritable = false;
+ return noErr;
+
+ case kAudioUnitProperty_CocoaUI:
+ outDataSize = sizeof (AudioUnitCocoaViewInfo);
+ outWritable = true;
+ return noErr;
+
+ #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
+ case kAudioUnitProperty_MIDIOutputCallbackInfo:
+ outDataSize = sizeof (CFArrayRef);
+ outWritable = false;
+ return noErr;
+
+ case kAudioUnitProperty_MIDIOutputCallback:
+ outDataSize = sizeof (AUMIDIOutputCallbackStruct);
+ outWritable = true;
+ return noErr;
+ #endif
+
+ case kAudioUnitProperty_BypassEffect:
+ outDataSize = sizeof (UInt32);
+ outWritable = true;
+ return noErr;
+
+ default: break;
}
+ }
+
+ return MusicDeviceBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
+}
- // Ranges
+ComponentResult
+PluginAU::GetProperty (AudioUnitPropertyID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ void* outData) override
+{
+ if (inScope == kAudioUnitScope_Global)
+ {
+ switch (inID)
{
- const ParameterRanges& ranges(fPlugin.getParameterRanges(inParameterID));
+ case kAudioUnitProperty_OfflineRender:
+ *(UInt32*) outData = 0;
+ return noErr;
+
+ case kMusicDeviceProperty_InstrumentCount:
+ *(UInt32*) outData = 1;
+ return noErr;
+
+ case kAudioUnitProperty_BypassEffect:
+ *(UInt32*) outData = isBypassed ? 1 : 0;
+ return noErr;
+
+ case kAudioUnitProperty_CocoaUI:
+ {
+ // Get the main DSP bundle
+ CFBundleRef bundle = CFBundleGetBundleWithIdentifier(
+ CFSTR("com.example.audiounit." DISTRHO_PLUGIN_NAME));
+ if (bundle == NULL) {
+ return fnfErr;
+ }
+
+ CFURLRef auuiURL = CFBundleCopyResourceURL(bundle,
+ CFSTR(DISTRHO_PLUGIN_NAME "-CocoaUI"),
+ CFSTR("bundle"),
+ NULL);
+
+ if (auuiURL == NULL) {
+ return fnfErr;
+ }
+
+ // Use hardcoded UI entrypoint
+ CFStringRef className = CFSTR("PluginAU_CocoaUIFactory");
+
+ AudioUnitCocoaViewInfo info;
+ info.mCocoaAUViewBundleLocation = auuiURL;
+ info.mCocoaAUViewClass[0] = className;
+
+ *((AudioUnitCocoaViewInfo *)outData) = info;
+
+ return noErr;
+ }
+
+ break;
+
+ #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
+ case kAudioUnitProperty_MIDIOutputCallbackInfo:
+ {
+ CFStringRef strs[1];
+ strs[0] = CFSTR ("MIDI Callback");
+
+ CFArrayRef callbackArray = CFArrayCreate (nullptr, (const void**) strs, 1, &kCFTypeArrayCallBacks);
+ *(CFArrayRef*) outData = callbackArray;
+ return noErr;
+ }
+ #endif
- outParameterInfo.defaultValue = ranges.def;
- outParameterInfo.minValue = ranges.min;
- outParameterInfo.maxValue = ranges.max;
+ default:
+ break;
}
+ }
- // Unit
+ return MusicDeviceBase::GetProperty (inID, inScope, inElement, outData);
+}
+
+ComponentResult
+PluginAU::SetProperty (AudioUnitPropertyID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ const void* inData,
+ UInt32 inDataSize) override
+{
+ if (inScope == kAudioUnitScope_Global)
+ {
+ switch (inID)
{
- const String& unit = fPlugin.getParameterUnit(inParameterID);
+ #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
+ case kAudioUnitProperty_MIDIOutputCallback:
+ if (inDataSize < sizeof (AUMIDIOutputCallbackStruct))
+ return kAudioUnitErr_InvalidPropertyValue;
- // TODO: map all AU unit types
+ if (AUMIDIOutputCallbackStruct* callbackStruct = (AUMIDIOutputCallbackStruct*) inData)
+ midiCallback = *callbackStruct;
- if (unit == "dB")
- {
- outParameterInfo.unit = kAudioUnitParameterUnit_LinearGain;
- }
- else
+ return noErr;
+ #endif
+
+ case kAudioUnitProperty_BypassEffect:
{
- outParameterInfo.unit = kAudioUnitParameterUnit_CustomUnit;
- outParameterInfo.unitName = CFStringCreateWithCString(kCFAllocatorDefault, unit.buffer(), kCFStringEncodingUTF8);
+ if (inDataSize < sizeof (UInt32))
+ return kAudioUnitErr_InvalidPropertyValue;
+
+ const bool newBypass = *((UInt32*) inData) != 0;
+ const bool currentlyBypassed = isBypassed;
+
+ if (newBypass != currentlyBypassed)
+ {
+ isBypassed = newBypass;
+
+ if (! currentlyBypassed && IsInitialized())
+ Reset (0, 0);
+ }
+
+ return noErr;
}
+
+ default: break;
}
+ }
- return noErr;
+ return MusicDeviceBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
+}
+
+ComponentResult
+PluginAU::SaveState (CFPropertyListRef* outData) override
+{
+ ComponentResult err = MusicDeviceBase::SaveState (outData);
+
+ if (err != noErr)
+ return err;
+
+ CFMutableDictionaryRef dict = (CFMutableDictionaryRef) *outData;
+
+ for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
+ {
+ CFDataRef ourState = CFDataCreate (kCFAllocatorDefault, (const UInt8*) cit->second.buffer(), (CFIndex) cit->second.length());
+
+ CFStringRef key = CFStringCreateWithCString (kCFAllocatorDefault, cit->first.buffer(), kCFStringEncodingUTF8);
+ CFDictionarySetValue (dict, key, ourState);
+ CFRelease (key);
+ CFRelease (ourState);
}
- OSStatus GetPropertyInfo(AudioUnitPropertyID inID,
- AudioUnitScope inScope,
- AudioUnitElement inElement,
- UInt32& outDataSize,
- Boolean& outWritable) override
+ return noErr;
+}
+
+ComponentResult
+PluginAU::RestoreState (CFPropertyListRef inData) override
+{
{
-#if DISTRHO_PLUGIN_HAS_UI
- if (inID == kAudioUnitProperty_CocoaUI && inScope == kAudioUnitScope_Global)
- {
- d_stdout("GetPropertyInfo asked for CocoaUI");
- outDataSize = sizeof(AudioUnitCocoaViewInfo);
- outWritable = false;
- return noErr;
- }
-#endif
+ // Remove the data entry from the state to prevent the superclass loading the parameters
+ CFMutableDictionaryRef copyWithoutData = CFDictionaryCreateMutableCopy (nullptr, 0, (CFDictionaryRef) inData);
+ CFDictionaryRemoveValue (copyWithoutData, CFSTR (kAUPresetDataKey));
+ ComponentResult err = MusicDeviceBase::RestoreState (copyWithoutData);
+ CFRelease (copyWithoutData);
- return AUEffectBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);
+ if (err != noErr)
+ return err;
}
- OSStatus GetProperty(AudioUnitPropertyID inID,
- AudioUnitScope inScope,
- AudioUnitElement inElement,
- void* outData) override
+ CFDictionaryRef dict = (CFDictionaryRef) inData;
+ CFDataRef data = nullptr;
+
+ for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
-#if DISTRHO_PLUGIN_HAS_UI
- if (inID == kAudioUnitProperty_CocoaUI && inScope == kAudioUnitScope_Global && outData != nullptr)
+ CFStringRef key = CFStringCreateWithCString (kCFAllocatorDefault, cit->first.buffer(), kCFStringEncodingUTF8);
+ bool valuePresent = CFDictionaryGetValueIfPresent (dict, key, (const void**) &data);
+ CFRelease (key);
+
+ if (valuePresent)
{
- d_stdout("GetProperty asked for CocoaUI");
+ if (data != nullptr)
+ {
+ const int numBytes = (int) CFDataGetLength (data);
+ char* rawBytes = (char*) CFDataGetBytePtr (data);
+
+ if (numBytes > 0)
+ fStateMap[cit->first] = String(rawBytes, numBytes);
+ }
+ }
+ }
+ return noErr;
+}
- // Need to do a special dance just to get the path to the UI binary
+bool
+PluginAU::busIgnoresLayout (bool isInput, int busNr) const
+{
+ return true;
+}
- // Get the main DSP bundle
- CFBundleRef bundle = CFBundleGetBundleWithIdentifier(
- CFSTR("com.example.audiounit." DISTRHO_PLUGIN_NAME));
- if (bundle == NULL) {
- d_stdout("XXX bundle=NULL");
- return fnfErr;
- }
+ComponentResult
+PluginAU::GetParameterInfo (AudioUnitScope inScope,
+ AudioUnitParameterID inParameterID,
+ AudioUnitParameterInfo& outParameterInfo) override
+{
+ if (inScope == kAudioUnitScope_Global)
+ {
+ outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
+ outParameterInfo.flags = (UInt32) (kAudioUnitParameterFlag_IsWritable
+ | kAudioUnitParameterFlag_IsReadable
+ | kAudioUnitParameterFlag_HasCFNameString
+ | kAudioUnitParameterFlag_ValuesHaveStrings);
- CFURLRef auuiURL = CFBundleCopyResourceURL(bundle,
- CFSTR(DISTRHO_PLUGIN_NAME "-CocoaUI"),
- CFSTR("bundle"),
- NULL);
+ const String& name = fPlugin.getParameterName(inParameterID);
+ const uint32_t hints(fPlugin.getParameterHints(inParameterID));
+ const ParameterRanges& ranges(fPlugin.getParameterRanges(inParameterID));
- if (auuiURL == NULL) {
- d_stdout("XXX auuiURL=NULL");
- return fnfErr;
- }
+ if (name.isEmpty() || ((hints & kParameterIsAutomable) == 0))
+ outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime;
- // Use hardcoded UI entrypoint
- CFStringRef className = CFSTR("PluginAU_CocoaUIFactory");
+ if ((hints & kParameterIsInteger) == 0)
+ outParameterInfo.flags |= kAudioUnitParameterFlag_CanRamp;
- AudioUnitCocoaViewInfo info;
- info.mCocoaAUViewBundleLocation = auuiURL;
- info.mCocoaAUViewClass[0] = className;
+ if ((hints & kParameterIsInteger) == 0)
+ outParameterInfo.unit = ((hints & kParameterIsBoolean) != 0)
+ ? kAudioUnitParameterUnit_Boolean
+ : kAudioUnitParameterUnit_Indexed;
- *((AudioUnitCocoaViewInfo *)outData) = info;
+ CFStringRef paramName = CFStringCreateWithCString (kCFAllocatorDefault, name.buffer(), kCFStringEncodingUTF8);
+ MusicDeviceBase::FillInParameterName (outParameterInfo, paramName, true);
- return noErr;
- }
-#endif
+ outParameterInfo.minValue = ranges.min;
+ outParameterInfo.maxValue = ranges.max;
+ outParameterInfo.defaultValue = ranges.def;
- return AUEffectBase::GetProperty (inID, inScope, inElement, outData);
+ return noErr;
}
-#if 0
- void SetParameter(AudioUnitParameterID index,
- AudioUnitParameterValue value) override
+ return kAudioUnitErr_InvalidParameter;
+}
+
+ComponentResult
+PluginAU::GetParameter (AudioUnitParameterID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ Float32& outValue) override
+{
+ if (inScope == kAudioUnitScope_Global)
{
- d_stdout("SetParameter %u %f", index, value);
+ const ParameterRanges& ranges(fPlugin.getParameterRanges(inID));
+ const float normValue = fPlugin.getParameterValue(inID);
+
+ outValue = normValue * ranges.max;
+ return noErr;
+ }
- const uint32_t hints(fPlugin.getParameterHints(index));
- const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
+ return MusicDeviceBase::GetParameter (inID, inScope, inElement, outValue);
+}
+
+ComponentResult
+PluginAU::SetParameter (AudioUnitParameterID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ Float32 inValue,
+ UInt32 inBufferOffsetInFrames) override
+{
+ if (inScope == kAudioUnitScope_Global)
+ {
+ const ParameterRanges& ranges(fPlugin.getParameterRanges(inID));
+ const uint32_t hints(fPlugin.getParameterHints(inID));
+ float value = inValue / ranges.max;
if (hints & kParameterIsBoolean)
{
@@ -240,152 +502,524 @@ protected:
value = std::round(value);
}
- fPlugin.setParameterValue(index, value);
- //printf("SET: id=%d val=%f\n", index, value);
+ fPlugin.setParameterValue(inID, value);
+
+ inParameterChangedCallback = true;
+ return noErr;
}
-#endif
- bool SupportsTail() override
+ return MusicDeviceBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames);
+}
+
+bool
+PluginAU::getCurrentPosition (TimePosition& info) override
+{
+ info.bbt.beatsPerBar = 0;
+ info.bbt.beatType = 0;
+ info.bbt.barStartTick = 0;
+ info.frame = 0;
+ info.playing = false;
+ Float64 beat, bpm;
+
+ if (AUBase::CallHostBeatAndTempo (&beat, &bpm) != noErr)
{
- return false;
+ info.bbt.beat = 0;
+ info.bbt.beatsPerMinute = 0;
+ } else {
+ info.bbt.beat = beat;
+ info.bbt.beatsPerMinute = bpm;
}
- OSStatus Version() override
+ UInt32 outDeltaSampleOffsetToNextBeat;
+ double outCurrentMeasureDownBeat;
+ float num;
+ UInt32 den;
+
+ if (AUBase::CallHostMusicalTimeLocation (&outDeltaSampleOffsetToNextBeat, &num, &den, &outCurrentMeasureDownBeat) == noErr)
{
- return fPlugin.getVersion();
+ info.bbt.beatsPerBar = num;
+ info.bbt.beatType = (float) den;
+ info.bbt.barStartTick = outCurrentMeasureDownBeat;
}
- OSStatus ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags,
- const AudioBufferList& inBuffer,
- AudioBufferList& outBuffer,
- UInt32 inFramesToProcess) override
+ double outCurrentSampleInTimeLine, outCycleStartBeat = 0, outCycleEndBeat = 0;
+ Boolean playing = false, looping = false, playchanged;
+
+ if (AUBase::CallHostTransportState (&playing,
+ &playchanged,
+ &outCurrentSampleInTimeLine,
+ &looping,
+ &outCycleStartBeat,
+ &outCycleEndBeat) != noErr)
{
- const float* srcBuffer[DISTRHO_PLUGIN_NUM_INPUTS];
- /* */ float* destBuffer[DISTRHO_PLUGIN_NUM_OUTPUTS];
+ outCurrentSampleInTimeLine = lastTimeStamp.mSampleTime;
+ }
- for (uint32_t i = 0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
- srcBuffer[i] = (const float*)inBuffer.mBuffers[i].mData;
+ info.playing = playing;
+ info.bbt.tick = (int32_t) (outCurrentSampleInTimeLine + 0.5);
- for (uint32_t i = 0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
- destBuffer[i] = (float *)outBuffer.mBuffers[i].mData;
+ return true;
+}
- updateParameterInputs();
+void
+PluginAU::sendAUEvent (const AudioUnitEventType type, const int paramIndex)
+{
+ auEvent.mEventType = type;
+ auEvent.mArgument.mParameter.mParameterID = paramIndex;
+ AUEventListenerNotify (nullptr, nullptr, &auEvent);
+}
- fPlugin.run(srcBuffer, destBuffer, inFramesToProcess);
+void
+PluginAU::setParameterValue (int index, float newValue) override
+{
+ if (inParameterChangedCallback)
+ {
+ inParameterChangedCallback = false;
+ return;
+ }
- updateParameterOutputsAndTriggers();
+ sendAUEvent (kAudioUnitEvent_ParameterValueChange, index);
+}
- ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
+void
+PluginAU::editParameter (int index, bool started) override
+{
+ if (started) {
+ sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index);
+ } else {
+ sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index);
+ }
+}
- return noErr;
+void
+PluginAU::propsChanged (void)
+{
+ PropertyChanged (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0);
+ PropertyChanged (kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0);
+ PropertyChanged (kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, 0);
+ PropertyChanged (kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0);
+
+ refreshCurrentPreset();
+
+ PropertyChanged (kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0);
+}
+
+void
+PluginAU::bypassChanged (int, float)
+{
+ PropertyChanged (kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0);
+}
+
+bool
+PluginAU::StreamFormatWritable (AudioUnitScope scope, AudioUnitElement element) override
+{
+ bool ignore;
+ int busIdx;
+
+ return ((! IsInitialized()) && (elementToBusIdx (scope, element, ignore, busIdx) == noErr));
+}
+
+bool
+PluginAU::ValidFormat (AudioUnitScope scope, AudioUnitElement element, const CAStreamBasicDescription& format) override
+{
+ bool isInput;
+ int busNr;
+
+ // DSP Quattro incorrectly uses global scope for the ValidFormat call
+ if (scope == kAudioUnitScope_Global)
+ return ValidFormat (kAudioUnitScope_Input, element, format)
+ || ValidFormat (kAudioUnitScope_Output, element, format);
+
+ if (elementToBusIdx (scope, element, isInput, busNr) != noErr)
+ return false;
+
+ const int newNumChannels = static_cast<int> (format.NumberChannels());
+ const int oldNumChannels = isInput ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS;
+
+ if (newNumChannels == oldNumChannels)
+ return true;
+
+ return false;
+}
+
+OSStatus
+PluginAU::ChangeStreamFormat (AudioUnitScope scope,
+ AudioUnitElement element,
+ const CAStreamBasicDescription& old,
+ const CAStreamBasicDescription& format) override
+{
+ bool isInput;
+ int busNr;
+ OSStatus err;
+
+ if ((err = elementToBusIdx (scope, element, isInput, busNr)) != noErr)
+ return err;
+
+ const int newNumChannels = static_cast<int> (format.NumberChannels());
+ short config = isInput ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS;
+
+ if (newNumChannels != config)
+ return kAudioUnitErr_FormatNotSupported;
+
+ return MusicDeviceBase::ChangeStreamFormat (scope, element, old, format);
+}
+
+ComponentResult
+PluginAU::Render (AudioUnitRenderActionFlags& ioActionFlags,
+ const AudioTimeStamp& inTimeStamp,
+ const UInt32 nFrames) override
+{
+ lastTimeStamp = inTimeStamp;
+
+ // prepare buffers
+ {
+ pullInputAudio (ioActionFlags, inTimeStamp, nFrames);
+ prepareOutputBuffers (nFrames);
}
- // -------------------------------------------------------------------
+ ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
- ComponentResult Initialize() override
+ const float* srcBuffer[DISTRHO_PLUGIN_NUM_INPUTS];
+ /* */ float* destBuffer[DISTRHO_PLUGIN_NUM_OUTPUTS];
+
+ // set buffer pointers to minimize copying
{
- ComponentResult err;
+ int numChannels = 0;
+ bool interleaved = false;
+ AudioBufferList* buffer = nullptr;
- if ((err = AUEffectBase::Initialize()) != noErr)
- return err;
+ // use output pointers
+ GetAudioBufferList (false, 0, buffer, interleaved, numChannels);
- // make sure things are in sync
- fPlugin.setBufferSize(GetMaxFramesPerSlice(), true);
- fPlugin.setSampleRate(GetSampleRate(), true);
+ for (int ch = 0; ch < numChannels; ++ch)
+ destBuffer[ch] = interleaved ? nullptr : static_cast<float*> (buffer->mBuffers[ch].mData);
+
- fPlugin.activate();
+ // use input pointers
+ const bool badData = ! pulledSucceeded;
- return noErr;
+ if (! badData)
+ GetAudioBufferList (true, 0, buffer, interleaved, numChannels);
+
+ for (int ch = 0; ch < numChannels; ++ch)
+ srcBuffer[ch] = (interleaved || badData) ? nullptr : static_cast<const float*> (buffer->mBuffers[ch].mData);
+
}
- void Cleanup() override
+ #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
+ // swap midi buffers
{
- fPlugin.deactivate();
- AUEffectBase::Cleanup();
+ //const ScopedLock sl (incomingMidiLock);
+ midiEvents.clear();
+ incomingEvents.swap(midiEvents);
}
- // -------------------------------------------------------------------
+ MidiEvent fMidiEvents[midiEvents.size()];
+ for (uint32_t i = 0; i < midiEvents.size(); i++)
+ {
+ fMidiEvents[i] = midiEvents[i];
+ }
- UInt32 SupportedNumChannels(const AUChannelInfo** outInfo) override
+ // process audio/midi
+ fPlugin.run (&srcBuffer[0], &destBuffer[0], nFrames, fMidiEvents, midiEvents.size());
+
+ // process midi output
+ if (! midiEvents.isEmpty() && midiCallback.midiOutputCallback != nullptr)
+ pushMidiOutput (nFrames);
+
+ midiEvents.clear();
+ #else
+ // process audio only
+ fPlugin.run (&srcBuffer[0], &destBuffer[0], nFrames);
+ #endif
+ return noErr;
+}
+
+OSStatus
+PluginAU::HandleMidiEvent (UInt8 nStatus,
+ UInt8 inChannel,
+ UInt8 inData1,
+ UInt8 inData2,
+ UInt32 inStartFrame) override
+{
+ #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
+ const uint8_t data[] = { (uint8_t) (nStatus | inChannel),
+ (uint8_t) inData1,
+ (uint8_t) inData2 };
+
+ //const ScopedLock sl (incomingMidiLock);
+ MidiEvent& midiEvent;
+ midiEvent.frame = inStartFrame;
+ midiEvent.size = 3;
+ midiEvent.dataExt = nullptr;
+ std::memcpy(midiEvent.data, data, midiEvent.size);
+ incomingEvents.push_back (midiEvent);
+ return noErr;
+ #else
+ return kAudioUnitErr_PropertyNotInUse;
+ #endif
+}
+
+OSStatus
+PluginAU::HandleSysEx (const UInt8* inData, UInt32 inLength) override
+{
+ #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
+ //const ScopedLock sl (incomingMidiLock);
+ MidiEvent& midiEvent;
+ midiEvent.size = inLength;
+ midiEvent.dataExt = inData;
+ std::memset(midiEvent.data, 0, MidiEvent::kDataSize);
+ incomingEvents.push_back (midiEvent);
+ return noErr;
+ #else
+ return kAudioUnitErr_PropertyNotInUse;
+ #endif
+}
+
+ComponentResult
+PluginAU::GetPresets (CFArrayRef* outData) override
+{
+ if (outData != nullptr)
{
- static const AUChannelInfo sChannels[1] = {{ DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS }};
+ const int numPrograms = fPlugin.getProgramCount();
- if (outInfo != nullptr)
- *outInfo = sChannels;
+ clearPresetsArray(numPrograms);
- return 1;
+ CFMutableArrayRef presetsArrayRef = CFArrayCreateMutable (nullptr, numPrograms, nullptr);
+
+ for (int i = 0; i < numPrograms; ++i)
+ {
+ String name (fPlugin.getProgramName(i));
+ if (name.isEmpty())
+ name = "Untitled";
+ CFStringRef presetName = CFStringCreateWithCString (kCFAllocatorDefault, name.buffer(), kCFStringEncodingUTF8);
+
+ setPresetName(i, presetName);
+
+ CFArrayAppendValue (presetsArrayRef, &presetsArray.at(i));
+ }
+
+ *outData = (CFArrayRef) presetsArrayRef;
}
- void SetMaxFramesPerSlice(UInt32 nFrames) override
+ return noErr;
+}
+
+OSStatus
+PluginAU::NewFactoryPresetSet (const AUPreset& inNewFactoryPreset) override
+{
+ const int numPrograms = fPlugin.getProgramCount();
+ const SInt32 chosenPresetNumber = (int) inNewFactoryPreset.presetNumber;
+
+ if (chosenPresetNumber >= numPrograms)
+ return kAudioUnitErr_InvalidProperty;
+
+ AUPreset chosenPreset;
+ CFStringRef programName = CFStringCreateWithCString (kCFAllocatorDefault, fPlugin.getProgramName(chosenPresetNumber).buffer(), kCFStringEncodingUTF8);
+
+ chosenPreset.presetNumber = chosenPresetNumber;
+ chosenPreset.presetName = programName;
+
+ fPlugin.loadProgram(chosenPresetNumber);
+
+ for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
{
- fPlugin.setBufferSize(nFrames, true);
- AUEffectBase::SetMaxFramesPerSlice(nFrames);
+ if (fPlugin.isParameterOutput(i))
+ continue;
+
+ fLastControlValues[i] = fPlugin.getParameterValue(i);
+
+ if (fPortControls[i] != nullptr)
+ *fPortControls[i] = fLastControlValues[i];
}
- // -------------------------------------------------------------------
+ SetAFactoryPresetAsCurrent (chosenPreset);
-private:
- LastValuesInit fLastValuesInit;
- PluginExporter fPlugin;
+ return noErr;
+}
- // Temporary data
- float* fLastParameterValues;
+void
+PluginAU::pullInputAudio (AudioUnitRenderActionFlags& flags,
+ const AudioTimeStamp& timestamp,
+ const UInt32 nFrames) noexcept
+{
+ const unsigned int numInputBuses = GetScope (kAudioUnitScope_Input).GetNumberOfElements();
- void updateParameterInputs()
+ for (unsigned int i = 0; i < numInputBuses; ++i)
{
- float value;
-
- for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+ if (AUInputElement* input = GetInput (i))
{
- if (! fPlugin.isParameterInput(i))
- continue;
+ bool succeeded = (input->PullInput (flags, timestamp, i, nFrames) == noErr);
- value = GetParameter(i);
+ pulledSucceeded = succeeded;
+ }
+ }
+}
- if (d_isEqual(fLastParameterValues[i], value))
- continue;
+void
+PluginAU::prepareOutputBuffers (const UInt32 nFrames) noexcept
+{
+ const unsigned int numOutputBuses = GetScope (kAudioUnitScope_Output).GetNumberOfElements();
- fLastParameterValues[i] = value;
- fPlugin.setParameterValue(i, value);
- }
+ for (unsigned int busIdx = 0; busIdx < numOutputBuses; ++busIdx)
+ {
+ AUOutputElement* output = GetOutput (busIdx);
+
+ if (output->WillAllocateBuffer())
+ output->PrepareBuffer (nFrames);
}
+}
+
+void
+PluginAU::pushMidiOutput (UInt32 nFrames) noexcept
+{
+ UInt32 numPackets = 0;
+ size_t dataSize = 0;
- void updateParameterOutputsAndTriggers()
+ for (std::vector<MidiEvent>::iterator i = midiEvents.begin();
+ i != midiEvents.end(); ++i)
{
- float value;
+ dataSize += (size_t) i->size;
+ ++numPackets;
+ }
- for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
- {
- if (fPlugin.isParameterOutput(i))
- {
- value = fLastParameterValues[i] = fPlugin.getParameterValue(i);
- SetParameter(i, value);
- }
- else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger)
- {
- // NOTE: no trigger support in AU, simulate it here
- value = fPlugin.getParameterRanges(i).def;
+ MIDIPacket* p;
+ const size_t packetMembersSize = sizeof (MIDIPacket) - sizeof (p->data);
+ const size_t packetListMembersSize = sizeof (MIDIPacketList) - sizeof (p->data);
- if (d_isEqual(value, fPlugin.getParameterValue(i)))
- continue;
+ MIDIPacketList *packetList;
+ packetList = (MIDIPacketList *)malloc(packetListMembersSize + packetMembersSize * numPackets + dataSize);
+ packetList->numPackets = numPackets;
- fLastParameterValues[i] = value;
- fPlugin.setParameterValue(i, value);
- SetParameter(i, value);
- }
- }
+ p = packetList->packet;
+
+ for (std::vector<MidiEvent>::iterator i = midiEvents.begin();
+ i != midiEvents.end(); ++i)
+ {
+ p->timeStamp = (MIDITimeStamp) i->frame;
+ p->length = (UInt16) i->size;
+ memcpy (p->data, i->data, (size_t) i->size);
+ p = MIDIPacketNext (p);
}
- DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginAU)
-};
+ midiCallback.midiOutputCallback (midiCallback.userData, &lastTimeStamp, 0, packetList);
+}
-END_NAMESPACE_DISTRHO
+void
+PluginAU::GetAudioBufferList (bool isInput,
+ int busIdx,
+ AudioBufferList*& bufferList,
+ bool& interleaved,
+ int& numChannels)
+{
+ AudioUnitScope scope = isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output;
+
+ AUIOElement* ioelement = GetIOElement (scope, static_cast<UInt32> (busIdx));
+ bufferList = &ioelement->GetBufferList();
+
+ interleaved = false;
+ numChannels = static_cast<int> (bufferList->mNumberBuffers);
+}
+
+OSStatus
+PluginAU::scopeToDirection (AudioUnitScope scope, bool& isInput) noexcept
+{
+ OSStatus err;
+
+ isInput = (scope == kAudioUnitScope_Input);
+
+ err = ((scope != kAudioUnitScope_Input) && (scope != kAudioUnitScope_Output)) ? (OSStatus)kAudioUnitErr_InvalidScope : noErr;
+ return err;
+}
-// -----------------------------------------------------------------------
+OSStatus
+PluginAU::elementToBusIdx (AudioUnitScope scope,
+ AudioUnitElement element,
+ bool& isInput,
+ int& busIdx) noexcept
+{
+ OSStatus err;
+
+ busIdx = static_cast<int> (element);
+
+ if ((err = scopeToDirection (scope, isInput)) != noErr) return err;
+ return noErr;
+}
+
+void
+PluginAU::addParameters()
+{
+ const int numParams = fPlugin.getParameterCount();
+ int i;
+
+ Globals()->UseIndexedParameters (numParams);
-COMPONENT_ENTRY(PluginAU)
+ for (i = 0; i < numParams; i++)
+ {
+ fPlugin.setParameterValue(i, fPlugin.getParameterValue(i));
+ }
+}
+
+OSStatus
+PluginAU::syncAudioUnitWithProcessor()
+{
+ OSStatus err = noErr;
+
+ if ((err = MusicDeviceBase::SetBusCount (kAudioUnitScope_Input, 1)) != noErr)
+ return err;
+
+ if ((err = MusicDeviceBase::SetBusCount (kAudioUnitScope_Output, 1)) != noErr)
+ return err;
+
+ return noErr;
+}
+
+OSStatus
+PluginAU::syncProcessorWithAudioUnit()
+{
+ // update total channel count
+ totalInChannels = DISTRHO_PLUGIN_NUM_INPUTS;
+ totalOutChannels = DISTRHO_PLUGIN_NUM_OUTPUTS;
-// -----------------------------------------------------------------------
+ return noErr;
+}
+
+void
+PluginAU::setPresetName(int i, const CFStringRef name)
+{
+ presetsArray.at(i).presetNumber = i;
+ presetsArray.at(i).presetName = name;
+}
+
+void
+PluginAU::clearPresetsArray(int n)
+{
+ for (int i = presetsArray.size(); --i >= 0;)
+ CFRelease (presetsArray[i].presetName);
+
+ presetsArray.clear();
+
+ for (int i = 0; i < n; i++)
+ presetsArray.push_back(emptyPreset);
+}
+
+void
+PluginAU::refreshCurrentPreset()
+{
+ const int currentProgramNumber = 0; // Don't know curr index
+ const String currentProgramName = fPlugin.getProgramName (currentProgramNumber);
+
+ AUPreset currentPreset;
+ CFStringRef presetName = CFStringCreateWithCString (kCFAllocatorDefault, currentProgramName.buffer(), kCFStringEncodingUTF8);
+ currentPreset.presetNumber = currentProgramNumber;
+ currentPreset.presetName = presetName;
+
+ SetAFactoryPresetAsCurrent (currentPreset);
+}
+
+END_NAMESPACE_DISTRHO
+
+COMPONENT_ENTRY (PluginAU)
#include "CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.cpp"
#include "CoreAudio106/AudioUnits/AUPublic/AUBase/AUDispatch.cpp"
@@ -393,7 +1027,8 @@ COMPONENT_ENTRY(PluginAU)
#include "CoreAudio106/AudioUnits/AUPublic/AUBase/AUOutputElement.cpp"
#include "CoreAudio106/AudioUnits/AUPublic/AUBase/AUScopeElement.cpp"
#include "CoreAudio106/AudioUnits/AUPublic/AUBase/ComponentBase.cpp"
-#include "CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.cpp"
+#include "CoreAudio106/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.cpp"
+#include "CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIBase.cpp"
#include "CoreAudio106/AudioUnits/AUPublic/Utility/AUBaseHelper.cpp"
#include "CoreAudio106/AudioUnits/AUPublic/Utility/AUBuffer.cpp"
#include "CoreAudio106/PublicUtility/CAAudioChannelLayout.cpp"
@@ -401,5 +1036,3 @@ COMPONENT_ENTRY(PluginAU)
#include "CoreAudio106/PublicUtility/CAMutex.cpp"
#include "CoreAudio106/PublicUtility/CAStreamBasicDescription.cpp"
#include "CoreAudio106/PublicUtility/CAVectorUnit.cpp"
-
-// -----------------------------------------------------------------------
diff --git a/distrho/src/DistrhoPluginAU.h b/distrho/src/DistrhoPluginAU.h
new file mode 100644
index 00000000..2619a876
--- /dev/null
+++ b/distrho/src/DistrhoPluginAU.h
@@ -0,0 +1,207 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with
+ * or without fee is hereby granted, provided that the above copyright notice and this
+ * permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef DISTRHO_PLUGIN_AU_H_
+#define DISTRHO_PLUGIN_AU_H_
+
+#include "DistrhoPluginInternal.hpp"
+
+//#include <AudioUnit/AUCocoaUIView.h>
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioUnitUtilities.h>
+#include <CoreMIDI/MIDIServices.h>
+#include "CoreAudio106/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.h"
+
+#define fPluginDictKey "fPluginState"
+
+typedef std::map<const String, String> StringMap;
+
+struct LastValuesInit {
+ LastValuesInit()
+ {
+ if (d_lastBufferSize == 0)
+ d_lastBufferSize = kAUDefaultMaxFramesPerSlice;
+
+ if (d_isZero(d_lastSampleRate))
+ d_lastSampleRate = kAUDefaultSampleRate;
+ };
+};
+
+
+START_NAMESPACE_DISTRHO
+
+static const writeMidiFunc writeMidiCallback = nullptr;
+
+// AU Plugin
+
+class PluginAU : public MusicDeviceBase
+{
+public:
+ PluginAU (AudioUnit component);
+ ~PluginAU() override;
+
+ ComponentResult Initialize() override;
+
+ void Cleanup() override;
+
+ ComponentResult Reset (AudioUnitScope inScope, AudioUnitElement inElement) override;
+
+ void prepareToPlay();
+
+ bool BusCountWritable (AudioUnitScope scope) override;
+
+ OSStatus SetBusCount (AudioUnitScope scope, UInt32 count) override;
+
+ UInt32 SupportedNumChannels (const AUChannelInfo** outInfo) override;
+
+ ComponentResult GetPropertyInfo (AudioUnitPropertyID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ UInt32& outDataSize,
+ Boolean& outWritable) override;
+
+ ComponentResult GetProperty (AudioUnitPropertyID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ void* outData) override;
+
+ ComponentResult SetProperty (AudioUnitPropertyID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ const void* inData,
+ UInt32 inDataSize) override;
+
+ ComponentResult SaveState (CFPropertyListRef* outData) override;
+
+ ComponentResult RestoreState (CFPropertyListRef inData) override;
+
+ bool busIgnoresLayout (bool isInput, int busNr) const;
+
+ ComponentResult GetParameterInfo (AudioUnitScope inScope,
+ AudioUnitParameterID inParameterID,
+ AudioUnitParameterInfo& outParameterInfo) override;
+
+ ComponentResult GetParameter (AudioUnitParameterID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ Float32& outValue) override;
+
+ ComponentResult SetParameter (AudioUnitParameterID inID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement,
+ Float32 inValue,
+ UInt32 inBufferOffsetInFrames) override;
+
+ bool CanScheduleParameters() const override { return false; }
+
+ ComponentResult Version() override { return fPlugin.getVersion(); }
+ bool SupportsTail() override { return false; }
+ double getSampleRate() { return GetOutput (0)->GetStreamFormat().mSampleRate; }
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ Float64 GetLatency() override
+ {
+ const double rate = getSampleRate();
+ return rate > 0 ? fPlugin.getLatency() / rate : 0;
+ }
+#endif
+
+ bool getCurrentPosition (TimePosition& info) override;
+
+ void sendAUEvent (const AudioUnitEventType type, const int paramIndex);
+
+ void setParameterValue (int index, float newValue) override;
+
+ void editParameter (int index, bool started) override;
+
+ void propsChanged (void);
+
+ void bypassChanged (int, float);
+
+ bool StreamFormatWritable (AudioUnitScope scope, AudioUnitElement element) override;
+
+ bool ValidFormat (AudioUnitScope scope, AudioUnitElement element, const CAStreamBasicDescription& format) override;
+
+ OSStatus ChangeStreamFormat (AudioUnitScope scope, AudioUnitElement element, const CAStreamBasicDescription& old, const CAStreamBasicDescription& format) override;
+
+ ComponentResult Render (AudioUnitRenderActionFlags& ioActionFlags,
+ const AudioTimeStamp& inTimeStamp,
+ const UInt32 nFrames) override;
+
+ ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID*, UInt32, const MusicDeviceNoteParams&) override { return noErr; }
+ ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32) override { return noErr; }
+
+ OSStatus HandleMidiEvent (UInt8 nStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2, UInt32 inStartFrame) override;
+
+ OSStatus HandleSysEx (const UInt8* inData, UInt32 inLength) override;
+
+ ComponentResult GetPresets (CFArrayRef* outData) override;
+
+ OSStatus NewFactoryPresetSet (const AUPreset& inNewFactoryPreset) override;
+
+ class EditorCompHolder;
+ struct UIAUViewClass;
+ struct UIAUCreationClass;
+
+private:
+ LastValuesInit fLastValuesInit;
+ PluginExporter fPlugin;
+ float* fLastParameterValues;
+ float* fLastControlValues;
+ float** fPortControls;
+
+ std::vector<MidiEvent> midiEvents, incomingEvents;
+ bool prepared, isBypassed;
+ StringMap fStateMap;
+ AudioUnitEvent auEvent;
+ std::vector<struct AUPreset> presetsArray;
+ struct AUPreset emptyPreset;
+ AUMIDIOutputCallbackStruct midiCallback;
+ AudioTimeStamp lastTimeStamp;
+ int totalInChannels, totalOutChannels;
+ bool pulledSucceeded;
+ bool inParameterChangedCallback;
+ std::vector<AUChannelInfo> channelInfo;
+
+ void pullInputAudio (AudioUnitRenderActionFlags& flags, const AudioTimeStamp& timestamp, const UInt32 nFrames) noexcept;
+
+ void prepareOutputBuffers (const UInt32 nFrames) noexcept;
+
+ void pushMidiOutput (UInt32 nFrames) noexcept;
+
+ void GetAudioBufferList (bool isInput, int busIdx, AudioBufferList*& bufferList, bool& interleaved, int& numChannels);
+
+ OSStatus scopeToDirection (AudioUnitScope scope, bool& isInput) noexcept;
+
+ OSStatus elementToBusIdx (AudioUnitScope scope, AudioUnitElement element, bool& isInput, int& busIdx) noexcept;
+
+ void addParameters();
+
+ OSStatus syncAudioUnitWithProcessor();
+
+ OSStatus syncProcessorWithAudioUnit();
+
+ void setPresetName(int i, const CFStringRef name);
+
+ void clearPresetsArray(int n);
+
+ void refreshCurrentPreset();
+
+ DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginAU)
+};
+
+END_NAMESPACE_DISTRHO
+
+#endif