diff --git a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm index 1d30630167..ad41389193 100644 --- a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -288,6 +288,7 @@ public: numInputBusses (0), numOutputBusses (0), audioUnit (0), + parameterListenerRef (0), midiConcatenator (2048) { using namespace AudioUnitFormatHelpers; @@ -323,6 +324,12 @@ public: jassert (AudioUnitFormatHelpers::insideCallback == 0); + if (parameterListenerRef != 0) + { + AUListenerDispose (parameterListenerRef); + parameterListenerRef = 0; + } + if (audioUnit != 0) { if (prepared) @@ -580,19 +587,26 @@ public: bool isOutputChannelStereoPair (int index) const { return isPositiveAndBelow (index, getNumOutputChannels()); } //============================================================================== - int getNumParameters() { return parameterIds.size(); } + int getNumParameters() { return parameters.size(); } float getParameter (int index) { const ScopedLock sl (lock); - Float32 value = 0.0f; + AudioUnitParameterValue value = 0; + + if (audioUnit != 0) + { + if (const ParamInfo* p = parameters[index]) + { + AudioUnitGetParameter (audioUnit, + p->paramID, + kAudioUnitScope_Global, 0, + &value); - if (audioUnit != 0 && isPositiveAndBelow (index, parameterIds.size())) - AudioUnitGetParameter (audioUnit, - (UInt32) parameterIds.getUnchecked (index), - kAudioUnitScope_Global, 0, - &value); + value = (value - p->minValue) / (p->maxValue - p->minValue); + } + } return value; } @@ -601,25 +615,28 @@ public: { const ScopedLock sl (lock); - if (audioUnit != 0 && isPositiveAndBelow (index, parameterIds.size())) + if (audioUnit != 0) { - AudioUnitSetParameter (audioUnit, - (UInt32) parameterIds.getUnchecked (index), - kAudioUnitScope_Global, 0, - newValue, 0); + if (const ParamInfo* p = parameters[index]) + { + AudioUnitSetParameter (audioUnit, p->paramID, kAudioUnitScope_Global, 0, + p->minValue + (p->maxValue - p->minValue) * newValue, 0); - sendParameterChangeEvent (index); + sendParameterChangeEvent (index); + } } } void sendParameterChangeEvent (int index) { - jassert (audioUnit != 0 && isPositiveAndBelow (index, parameterIds.size())); + jassert (audioUnit != 0); + + const ParamInfo& p = *parameters.getUnchecked (index); AudioUnitEvent ev; ev.mEventType = kAudioUnitEvent_ParameterValueChange; ev.mArgument.mParameter.mAudioUnit = audioUnit; - ev.mArgument.mParameter.mParameterID = (UInt32) parameterIds.getUnchecked (index); + ev.mArgument.mParameter.mParameterID = p.paramID; ev.mArgument.mParameter.mScope = kAudioUnitScope_Global; ev.mArgument.mParameter.mElement = 0; @@ -628,51 +645,26 @@ public: void sendAllParametersChangedEvents() { - for (int i = 0; i < parameterIds.size(); ++i) + for (int i = 0; i < parameters.size(); ++i) sendParameterChangeEvent (i); } const String getParameterName (int index) { - AudioUnitParameterInfo info; - UInt32 sz = sizeof (info); - String name; - - if (AudioUnitGetProperty (audioUnit, - kAudioUnitProperty_ParameterInfo, - kAudioUnitScope_Global, - parameterIds [index], &info, &sz) == noErr) - { - if ((info.flags & kAudioUnitParameterFlag_HasCFNameString) != 0) - { - name = String::fromCFString (info.cfNameString); - - if ((info.flags & kAudioUnitParameterFlag_CFNameRelease) != 0) - CFRelease (info.cfNameString); - } - else - { - name = String (info.name, sizeof (info.name)); - } - } + if (const ParamInfo* p = parameters[index]) + return p->name; - return name; + return String::empty; } const String getParameterText (int index) { return String (getParameter (index)); } bool isParameterAutomatable (int index) const { - AudioUnitParameterInfo info; - UInt32 sz = sizeof (info); - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterInfo, - kAudioUnitScope_Global, parameterIds [index], &info, &sz) == noErr) - { - return (info.flags & kAudioUnitParameterFlag_NonRealTime) == 0; - } + if (const ParamInfo* p = parameters[index]) + return p->automatable; - return true; + return false; } //============================================================================== @@ -816,7 +808,7 @@ public: void refreshParameterList() { - parameterIds.clear(); + parameters.clear(); if (audioUnit != 0) { @@ -826,10 +818,44 @@ public: if (paramListSize > 0) { - parameterIds.insertMultiple (0, 0, paramListSize / sizeof (int)); + const size_t numParams = paramListSize / sizeof (int); + + HeapBlock ids; + ids.calloc (numParams); AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, - 0, parameterIds.getRawDataPointer(), ¶mListSize); + 0, ids, ¶mListSize); + + for (int i = 0; i < numParams; ++i) + { + AudioUnitParameterInfo info; + UInt32 sz = sizeof (info); + + if (AudioUnitGetProperty (audioUnit, + kAudioUnitProperty_ParameterInfo, + kAudioUnitScope_Global, + ids[i], &info, &sz) == noErr) + { + ParamInfo* const param = new ParamInfo(); + parameters.add (param); + param->paramID = ids[i]; + param->minValue = info.minValue; + param->maxValue = info.maxValue; + param->automatable = (info.flags & kAudioUnitParameterFlag_NonRealTime) == 0; + + if ((info.flags & kAudioUnitParameterFlag_HasCFNameString) != 0) + { + param->name = String::fromCFString (info.cfNameString); + + if ((info.flags & kAudioUnitParameterFlag_CFNameRelease) != 0) + CFRelease (info.cfNameString); + } + else + { + param->name = String (info.name, sizeof (info.name)); + } + } + } } } } @@ -860,7 +886,17 @@ private: int numInputBusChannels, numOutputBusChannels, numInputBusses, numOutputBusses; AudioUnit audioUnit; - Array parameterIds; + AUParameterListenerRef parameterListenerRef; + + struct ParamInfo + { + UInt32 paramID; + String name; + AudioUnitParameterValue minValue, maxValue; + bool automatable; + }; + + OwnedArray parameters; MidiDataConcatenator midiConcatenator; CriticalSection midiInLock; @@ -906,9 +942,43 @@ private: AudioUnitSetProperty (audioUnit, kAudioUnitProperty_HostCallbacks, kAudioUnitScope_Global, 0, &info, sizeof (info)); } + + AUListenerCreate (parameterListenerCallback, this, nullptr, nullptr, 0, ¶meterListenerRef); + + for (int i = 0; i < parameters.size(); ++i) + { + const ParamInfo& p = *parameters.getUnchecked(i); + + AudioUnitParameter paramToAdd; + paramToAdd.mAudioUnit = audioUnit; + paramToAdd.mParameterID = p.paramID; + paramToAdd.mScope = kAudioUnitScope_Global; + paramToAdd.mElement = 0; + + AUListenerAddParameter (parameterListenerRef, nullptr, ¶mToAdd); + } + } + } + + void parameterChanged (const AudioUnitParameter* param, AudioUnitParameterValue newValue) + { + for (int i = 0; i < parameters.size(); ++i) + { + const ParamInfo& p = *parameters.getUnchecked(i); + + if (p.paramID == param->mParameterID) + { + sendParamChangeMessageToListeners (i, (newValue - p.minValue) / (p.maxValue - p.minValue)); + break; + } } } + static void parameterListenerCallback (void* userData, void*, const AudioUnitParameter* param, AudioUnitParameterValue newValue) + { + ((AudioUnitPluginInstance*) userData)->parameterChanged (param, newValue); + } + //============================================================================== OSStatus renderGetInput (AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, diff --git a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp index c8154d5893..99d59ee56d 100644 --- a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp +++ b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp @@ -256,7 +256,7 @@ public: y += dh; } - const int maxBoxHeight = 100;//(getHeight() - y - dh * 2) / numBoxes; + const int maxBoxHeight = 100; if (outputChanList != nullptr) {