mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-31 03:00:05 +00:00
Added AudioProcessor::updateTrackProperties callback to inform plug-ins about track colour and name changes
This commit is contained in:
parent
6ead92430e
commit
b56e3890c2
13 changed files with 231 additions and 1 deletions
|
|
@ -107,6 +107,8 @@ JuceDemoPluginAudioProcessorEditor::JuceDemoPluginAudioProcessorEditor (JuceDemo
|
|||
setSize (owner.lastUIWidth,
|
||||
owner.lastUIHeight);
|
||||
|
||||
updateTrackProperties();
|
||||
|
||||
// start a timer which will keep our timecode display updated
|
||||
startTimerHz (30);
|
||||
}
|
||||
|
|
@ -118,7 +120,7 @@ JuceDemoPluginAudioProcessorEditor::~JuceDemoPluginAudioProcessorEditor()
|
|||
//==============================================================================
|
||||
void JuceDemoPluginAudioProcessorEditor::paint (Graphics& g)
|
||||
{
|
||||
g.setColour (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
|
||||
g.setColour (backgroundColour);
|
||||
g.fillAll();
|
||||
}
|
||||
|
||||
|
|
@ -151,6 +153,16 @@ void JuceDemoPluginAudioProcessorEditor::hostMIDIControllerIsAvailable (bool con
|
|||
midiKeyboard.setVisible (! controllerIsAvailable);
|
||||
}
|
||||
|
||||
void JuceDemoPluginAudioProcessorEditor::updateTrackProperties ()
|
||||
{
|
||||
auto trackColour = getProcessor().trackProperties.colour;
|
||||
auto& lf = getLookAndFeel();
|
||||
|
||||
backgroundColour = (trackColour == Colour() ? lf.findColour (ResizableWindow::backgroundColourId)
|
||||
: trackColour.withAlpha (1.0f).withBrightness (0.266f));
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// quick-and-dirty function to format a timecode string
|
||||
static String timeToTimecodeString (double seconds)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ public:
|
|||
void resized() override;
|
||||
void timerCallback() override;
|
||||
void hostMIDIControllerIsAvailable (bool) override;
|
||||
void updateTrackProperties();
|
||||
|
||||
private:
|
||||
class ParameterSlider;
|
||||
|
|
@ -52,6 +53,7 @@ private:
|
|||
MidiKeyboardComponent midiKeyboard;
|
||||
Label timecodeDisplayLabel, gainLabel, delayLabel;
|
||||
ScopedPointer<ParameterSlider> gainSlider, delaySlider;
|
||||
Colour backgroundColour;
|
||||
|
||||
//==============================================================================
|
||||
JuceDemoPluginAudioProcessor& getProcessor() const
|
||||
|
|
|
|||
|
|
@ -390,6 +390,14 @@ void JuceDemoPluginAudioProcessor::setStateInformation (const void* data, int si
|
|||
}
|
||||
}
|
||||
|
||||
void JuceDemoPluginAudioProcessor::updateTrackProperties (const TrackProperties& properties)
|
||||
{
|
||||
trackProperties = properties;
|
||||
|
||||
if (auto* editor = dynamic_cast<JuceDemoPluginAudioProcessorEditor*> (getActiveEditor()))
|
||||
editor->updateTrackProperties ();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// This creates new instances of the plugin..
|
||||
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ public:
|
|||
void getStateInformation (MemoryBlock&) override;
|
||||
void setStateInformation (const void* data, int sizeInBytes) override;
|
||||
|
||||
//==============================================================================
|
||||
void updateTrackProperties (const TrackProperties& properties) override;
|
||||
|
||||
//==============================================================================
|
||||
// These properties are public so that our editor component can access them
|
||||
// A bit of a hacky way to do it, but it's only a demo! Obviously in your own
|
||||
|
|
@ -104,6 +107,9 @@ public:
|
|||
AudioParameterFloat* gainParam = nullptr;
|
||||
AudioParameterFloat* delayParam = nullptr;
|
||||
|
||||
// Current track colour and name
|
||||
TrackProperties trackProperties;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
template <typename FloatType>
|
||||
|
|
|
|||
|
|
@ -942,6 +942,13 @@ namespace AAXClasses
|
|||
{
|
||||
if (type == AAX_eNotificationEvent_EnteringOfflineMode) pluginInstance->setNonRealtime (true);
|
||||
if (type == AAX_eNotificationEvent_ExitingOfflineMode) pluginInstance->setNonRealtime (false);
|
||||
if (type == AAX_eNotificationEvent_TrackNameChanged && data != nullptr)
|
||||
{
|
||||
AudioProcessor::TrackProperties props;
|
||||
props.name = static_cast<const AAX_IString*> (data)->Get();
|
||||
|
||||
pluginInstance->updateTrackProperties (props);
|
||||
}
|
||||
|
||||
return AAX_CEffectParameters::NotificationReceived (type, data, size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,6 +147,8 @@ public:
|
|||
channelInfo = AudioUnitHelpers::getAUChannelInfo (*juceFilter);
|
||||
#endif
|
||||
|
||||
AddPropertyListener (kAudioUnitProperty_ContextName, auPropertyListenerDispatcher, this);
|
||||
|
||||
totalInChannels = juceFilter->getTotalNumInputChannels();
|
||||
totalOutChannels = juceFilter->getTotalNumOutputChannels();
|
||||
|
||||
|
|
@ -1956,6 +1958,25 @@ private:
|
|||
return (getHostType().isLogic() ? 8 : 64);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void auPropertyListener (AudioUnitPropertyID propId, AudioUnitScope scope, AudioUnitElement)
|
||||
{
|
||||
if (scope == kAudioUnitScope_Global && propId == kAudioUnitProperty_ContextName
|
||||
&& juceFilter != nullptr && mContextName != nullptr)
|
||||
{
|
||||
AudioProcessor::TrackProperties props;
|
||||
props.name = String::fromCFString (mContextName);
|
||||
|
||||
juceFilter->updateTrackProperties (props);
|
||||
}
|
||||
}
|
||||
|
||||
static void auPropertyListenerDispatcher (void* inRefCon, AudioUnit, AudioUnitPropertyID propId,
|
||||
AudioUnitScope scope, AudioUnitElement element)
|
||||
{
|
||||
static_cast<JuceAU*> (inRefCon)->auPropertyListener (propId, scope, element);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (JuceAU)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -195,6 +195,10 @@ public:
|
|||
virtual bool getRenderingOffline() = 0;
|
||||
virtual void setRenderingOffline (bool offline) = 0;
|
||||
|
||||
//==============================================================================
|
||||
virtual NSString* getContextName() const = 0;
|
||||
virtual void setContextName (NSString*) = 0;
|
||||
|
||||
virtual bool allocateRenderResourcesAndReturnError (NSError **outError)
|
||||
{
|
||||
objc_super s = { getAudioUnit(), [AUAudioUnit class] };
|
||||
|
|
@ -273,6 +277,10 @@ private:
|
|||
addMethod (@selector (allocateRenderResourcesAndReturnError:), allocateRenderResourcesAndReturnError, "B@:^@");
|
||||
addMethod (@selector (deallocateRenderResources), deallocateRenderResources, "v@:");
|
||||
|
||||
//==============================================================================
|
||||
addMethod (@selector (contextName), getContextName, "@@:");
|
||||
addMethod (@selector (setContextName:), setContextName, "v@:@");
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
|
||||
addMethod (@selector (supportedViewConfigurations:), getSupportedViewConfigurations, "@@:@");
|
||||
|
|
@ -351,6 +359,10 @@ private:
|
|||
static BOOL allocateRenderResourcesAndReturnError (id self, SEL, NSError** error) { return _this (self)->allocateRenderResourcesAndReturnError (error) ? YES : NO; }
|
||||
static void deallocateRenderResources (id self, SEL) { _this (self)->deallocateRenderResources(); }
|
||||
|
||||
//==============================================================================
|
||||
static NSString* getContextName (id self, SEL) { return _this (self)->getContextName(); }
|
||||
static void setContextName (id self, SEL, NSString* str) { return _this (self)->setContextName (str); }
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
|
||||
static NSIndexSet* getSupportedViewConfigurations (id self, SEL, NSArray<AUAudioUnitViewConfiguration*>* configs) { return _this (self)->getSupportedViewConfigurations (configs); }
|
||||
|
|
@ -679,6 +691,20 @@ public:
|
|||
bool getRenderingOffline() override { return getAudioProcessor().isNonRealtime(); }
|
||||
void setRenderingOffline (bool offline) override { getAudioProcessor().setNonRealtime (offline); }
|
||||
|
||||
//==============================================================================
|
||||
NSString* getContextName() const override { return juceStringToNS (contextName); }
|
||||
void setContextName (NSString* str) override
|
||||
{
|
||||
if (str != nullptr)
|
||||
{
|
||||
AudioProcessor::TrackProperties props;
|
||||
props.name = nsStringToJuce (str);
|
||||
|
||||
getAudioProcessor().updateTrackProperties (props);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool allocateRenderResourcesAndReturnError (NSError **outError) override
|
||||
{
|
||||
AudioProcessor& processor = getAudioProcessor();
|
||||
|
|
@ -1436,6 +1462,8 @@ private:
|
|||
|
||||
AudioTimeStamp lastTimeStamp;
|
||||
CurrentPositionInfo lastAudioHead;
|
||||
|
||||
String contextName;
|
||||
};
|
||||
|
||||
const double JuceAudioUnitv3::kDefaultSampleRate = 44100.0;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ class JuceVST3Component;
|
|||
//==============================================================================
|
||||
class JuceVST3EditController : public Vst::EditController,
|
||||
public Vst::IMidiMapping,
|
||||
public Vst::ChannelContext::IInfoListener,
|
||||
public AudioProcessorListener
|
||||
{
|
||||
public:
|
||||
|
|
@ -147,6 +148,7 @@ public:
|
|||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IEditController2)
|
||||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IConnectionPoint)
|
||||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IMidiMapping)
|
||||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::ChannelContext::IInfoListener)
|
||||
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, IPluginBase, Vst::IEditController)
|
||||
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, IDependent, Vst::IEditController)
|
||||
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, FUnknown, Vst::IEditController)
|
||||
|
|
@ -429,6 +431,41 @@ public:
|
|||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProgramChangeParameter)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
tresult PLUGIN_API setChannelContextInfos (Vst::IAttributeList* list) override
|
||||
{
|
||||
if (auto* instance = getPluginInstance())
|
||||
{
|
||||
if (list != nullptr)
|
||||
{
|
||||
AudioProcessor::TrackProperties trackProperties;
|
||||
|
||||
{
|
||||
Vst::String128 channelName;
|
||||
if (list->getString (Vst::ChannelContext::kChannelNameKey, channelName, sizeof (channelName)) == kResultTrue)
|
||||
trackProperties.name = toString (channelName);
|
||||
}
|
||||
|
||||
{
|
||||
int64 colour;
|
||||
if (list->getInt (Vst::ChannelContext::kChannelColorKey, colour) == kResultTrue)
|
||||
trackProperties.colour = Colour (Vst::ChannelContext::GetRed ((uint32) colour), Vst::ChannelContext::GetGreen ((uint32) colour),
|
||||
Vst::ChannelContext::GetBlue ((uint32) colour), Vst::ChannelContext::GetAlpha ((uint32) colour));
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (MessageManager::getInstance()->isThisTheMessageThread())
|
||||
instance->updateTrackProperties (trackProperties);
|
||||
else
|
||||
MessageManager::callAsync ([trackProperties, instance] ()
|
||||
{ instance->updateTrackProperties (trackProperties); });
|
||||
}
|
||||
}
|
||||
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
tresult PLUGIN_API setComponentState (IBStream* stream) override
|
||||
{
|
||||
|
|
@ -1120,6 +1157,7 @@ public:
|
|||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IAudioProcessor)
|
||||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IUnitInfo)
|
||||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IConnectionPoint)
|
||||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::ChannelContext::IInfoListener)
|
||||
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, FUnknown, Vst::IComponent)
|
||||
|
||||
if (doUIDsMatch (targetIID, JuceAudioProcessor::iid))
|
||||
|
|
|
|||
|
|
@ -1065,6 +1065,19 @@ public:
|
|||
jassertfalse; // xxx not implemented!
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void updateTrackProperties (const TrackProperties& properties) override
|
||||
{
|
||||
if (properties.name.isNotEmpty())
|
||||
{
|
||||
CFStringRef contextName = properties.name.toCFString();
|
||||
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_ContextName, kAudioUnitScope_Global,
|
||||
0, &contextName, sizeof (CFStringRef));
|
||||
|
||||
CFRelease (contextName);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void getStateInformation (MemoryBlock& destData) override
|
||||
{
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
#include <pluginterfaces/vst/vsttypes.h>
|
||||
#include <pluginterfaces/vst/ivstunits.h>
|
||||
#include <pluginterfaces/vst/ivstmidicontrollers.h>
|
||||
#include <pluginterfaces/vst/ivstchannelcontextinfo.h>
|
||||
#include <public.sdk/source/common/memorystream.h>
|
||||
#include <public.sdk/source/vst/vsteditcontroller.h>
|
||||
#else
|
||||
|
|
@ -102,6 +103,7 @@
|
|||
#include <pluginterfaces/gui/iplugview.h>
|
||||
#include <pluginterfaces/gui/iplugviewcontentscalesupport.h>
|
||||
#include <pluginterfaces/vst/ivstmidicontrollers.h>
|
||||
#include <pluginterfaces/vst/ivstchannelcontextinfo.h>
|
||||
#include <public.sdk/source/common/memorystream.cpp>
|
||||
#include <public.sdk/source/common/pluginview.cpp>
|
||||
#include <public.sdk/source/vst/vsteditcontroller.cpp>
|
||||
|
|
|
|||
|
|
@ -2100,6 +2100,67 @@ struct VST3PluginInstance : public AudioPluginInstance
|
|||
return result;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void updateTrackProperties (const TrackProperties& properties) override
|
||||
{
|
||||
if (trackInfoListener != nullptr)
|
||||
{
|
||||
ComSmartPtr<Vst::IAttributeList> l (new TrackPropertiesAttributeList (properties));
|
||||
trackInfoListener->setChannelContextInfos (l);
|
||||
}
|
||||
}
|
||||
|
||||
struct TrackPropertiesAttributeList : public Vst::IAttributeList
|
||||
{
|
||||
TrackPropertiesAttributeList (const TrackProperties& properties) : props (properties) {}
|
||||
virtual ~TrackPropertiesAttributeList() {}
|
||||
|
||||
JUCE_DECLARE_VST3_COM_REF_METHODS
|
||||
|
||||
tresult PLUGIN_API queryInterface (const TUID iid, void** obj) override
|
||||
{
|
||||
TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IAttributeList)
|
||||
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (iid, FUnknown, Vst::IAttributeList)
|
||||
|
||||
*obj = nullptr;
|
||||
return kNotImplemented;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API setInt (AttrID, int64) override { return kOutOfMemory; }
|
||||
tresult PLUGIN_API setFloat (AttrID, double) override { return kOutOfMemory; }
|
||||
tresult PLUGIN_API setString (AttrID, const Vst::TChar*) override { return kOutOfMemory; }
|
||||
tresult PLUGIN_API setBinary (AttrID, const void*, uint32) override { return kOutOfMemory; }
|
||||
tresult PLUGIN_API getFloat (AttrID, double&) override { return kResultFalse; }
|
||||
tresult PLUGIN_API getBinary (AttrID, const void*&, uint32&) override { return kResultFalse; }
|
||||
|
||||
tresult PLUGIN_API getString (AttrID id, Vst::TChar* string, uint32 size) override
|
||||
{
|
||||
if (! std::strcmp (id, Vst::ChannelContext::kChannelNameKey))
|
||||
{
|
||||
Steinberg::String str (props.name.toRawUTF8());
|
||||
str.copyTo (string, 0, (Steinberg::int32) jmin (size, (Steinberg::uint32) std::numeric_limits<Steinberg::int32>::max()));
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getInt (AttrID id, int64& value) override
|
||||
{
|
||||
if (! std::strcmp (Vst::ChannelContext::kChannelNameLengthKey, id)) value = props.name.length();
|
||||
else if (! std::strcmp (Vst::ChannelContext::kChannelColorKey, id)) value = static_cast<int64> (props.colour.getARGB());
|
||||
else return kResultFalse;
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
Atomic<int> refCount;
|
||||
TrackProperties props;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TrackPropertiesAttributeList)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
String getChannelName (int channelIndex, bool forInput, bool forAudioChannel) const
|
||||
{
|
||||
|
|
@ -2449,6 +2510,7 @@ private:
|
|||
ComSmartPtr<Vst::IUnitData> unitData;
|
||||
ComSmartPtr<Vst::IProgramListData> programListData;
|
||||
ComSmartPtr<Vst::IConnectionPoint> componentConnection, editControllerConnection;
|
||||
ComSmartPtr<Vst::ChannelContext::IInfoListener> trackInfoListener;
|
||||
|
||||
/** The number of IO buses MUST match that of the plugin,
|
||||
even if there aren't enough channels to process,
|
||||
|
|
@ -2533,6 +2595,7 @@ private:
|
|||
editController2.loadFrom (holder->component);
|
||||
componentHandler.loadFrom (holder->component);
|
||||
componentHandler2.loadFrom (holder->component);
|
||||
trackInfoListener.loadFrom (holder->component);
|
||||
|
||||
if (processor == nullptr) processor.loadFrom (editController);
|
||||
if (unitInfo == nullptr) unitInfo.loadFrom (editController);
|
||||
|
|
@ -2541,6 +2604,7 @@ private:
|
|||
if (editController2 == nullptr) editController2.loadFrom (editController);
|
||||
if (componentHandler == nullptr) componentHandler.loadFrom (editController);
|
||||
if (componentHandler2 == nullptr) componentHandler2.loadFrom (editController);
|
||||
if (trackInfoListener == nullptr) trackInfoListener.loadFrom (editController);
|
||||
}
|
||||
|
||||
void setStateForAllMidiBuses (bool newState)
|
||||
|
|
|
|||
|
|
@ -1025,6 +1025,9 @@ void AudioProcessor::setCurrentProgramStateInformation (const void* data, int si
|
|||
setStateInformation (data, sizeInBytes);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AudioProcessor::updateTrackProperties (const AudioProcessor::TrackProperties&) {}
|
||||
|
||||
//==============================================================================
|
||||
// magic number to identify memory blocks that we've stored as XML
|
||||
const uint32 magicXmlNumber = 0x21324356;
|
||||
|
|
|
|||
|
|
@ -1310,6 +1310,32 @@ public:
|
|||
*/
|
||||
WrapperType wrapperType;
|
||||
|
||||
/** A struct containing information about the DAW track inside which your
|
||||
AudioProcessor is loaded. */
|
||||
struct TrackProperties
|
||||
{
|
||||
String name; // The name of the track - this will be empty if the track name is not known
|
||||
Colour colour; // The colour of the track - this will be transparentBlack if the colour is not known
|
||||
|
||||
// other properties may be added in the future
|
||||
};
|
||||
|
||||
/** Informs the AudioProcessor that track properties such as the track's name or
|
||||
colour has been changed.
|
||||
|
||||
If you are hosting this AudioProcessor then use this method to inform the
|
||||
AudioProcessor about which track the AudioProcessor is loaded on. This method
|
||||
may only be called on the message thread.
|
||||
|
||||
If you are implemeting an AudioProcessor then you can override this callback
|
||||
to do something useful with the track properties such as changing the colour
|
||||
of your AudioProcessor's editor. It's entirely up to the host when and how
|
||||
often this callback will be called.
|
||||
|
||||
The default implementation of this callback will do nothing.
|
||||
*/
|
||||
virtual void updateTrackProperties (const TrackProperties& properties);
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
/** Deprecated: use getTotalNumInputChannels instead. */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue