diff --git a/extras/audio plugins/demo/build/AudioUnit/JuceDemoAU.xcodeproj/project.pbxproj b/extras/audio plugins/demo/build/AudioUnit/JuceDemoAU.xcodeproj/project.pbxproj index 11d6ac4f63..8caf9fa3f6 100644 --- a/extras/audio plugins/demo/build/AudioUnit/JuceDemoAU.xcodeproj/project.pbxproj +++ b/extras/audio plugins/demo/build/AudioUnit/JuceDemoAU.xcodeproj/project.pbxproj @@ -34,6 +34,8 @@ 844C50290C71B6E300D0082E /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844C50280C71B6E300D0082E /* IOKit.framework */; }; 845FAE5F0A5C0A6A008C94D8 /* juce.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 845FAE5E0A5C0A6A008C94D8 /* juce.xcconfig */; }; 845FAEE10A5C2696008C94D8 /* QuickTime.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 845FAEE00A5C2696008C94D8 /* QuickTime.framework */; }; + 84B4CDD10C7DD23B0083122F /* MusicDeviceBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84B4CDCF0C7DD23B0083122F /* MusicDeviceBase.cpp */; }; + 84B4CDD20C7DD23B0083122F /* MusicDeviceBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 84B4CDD00C7DD23B0083122F /* MusicDeviceBase.h */; }; 84CFAEFB090964560053C22C /* AUCarbonViewDispatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5D19AAB03175F3201CA2136 /* AUCarbonViewDispatch.cpp */; }; 84CFAEFC090964560053C22C /* AUCarbonViewControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5D19AA903175F3201CA2136 /* AUCarbonViewControl.cpp */; }; 84CFAEFD090964560053C22C /* AUCarbonViewBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5D19AA703175F3201CA2136 /* AUCarbonViewBase.cpp */; }; @@ -100,6 +102,8 @@ 844C50280C71B6E300D0082E /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = IOKit.framework; sourceTree = ""; }; 845FAE5E0A5C0A6A008C94D8 /* juce.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = juce.xcconfig; path = ../../../../../build/macosx/juce.xcconfig; sourceTree = SOURCE_ROOT; }; 845FAEE00A5C2696008C94D8 /* QuickTime.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = QuickTime.framework; sourceTree = ""; }; + 84B4CDCF0C7DD23B0083122F /* MusicDeviceBase.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = MusicDeviceBase.cpp; path = /Developer/Examples/CoreAudio/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.cpp; sourceTree = ""; }; + 84B4CDD00C7DD23B0083122F /* MusicDeviceBase.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = MusicDeviceBase.h; path = /Developer/Examples/CoreAudio/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.h; sourceTree = ""; }; 84EB4009090A4A2C008FAC1B /* juce_AudioUnitWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioUnitWrapper.cpp; path = ../../../wrapper/formats/AudioUnit/juce_AudioUnitWrapper.cpp; sourceTree = SOURCE_ROOT; }; 84EB400A090A4A2C008FAC1B /* juce_AudioUnitWrapper.r */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.rez; name = juce_AudioUnitWrapper.r; path = ../../../wrapper/formats/AudioUnit/juce_AudioUnitWrapper.r; sourceTree = SOURCE_ROOT; }; 84EB404D090A5116008FAC1B /* JucePluginCharacteristics.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JucePluginCharacteristics.h; path = ../../src/JucePluginCharacteristics.h; sourceTree = SOURCE_ROOT; }; @@ -319,6 +323,8 @@ 84F054E70906C8DD00AEC8DB /* AUMIDIEffectBase.h */, F5D199FE03175E1E01CA2136 /* AUEffectBase.cpp */, F5D199FF03175E1E01CA2136 /* AUEffectBase.h */, + 84B4CDCF0C7DD23B0083122F /* MusicDeviceBase.cpp */, + 84B4CDD00C7DD23B0083122F /* MusicDeviceBase.h */, ); path = OtherBases; sourceTree = ""; @@ -393,6 +399,7 @@ 84F055040906E9EA00AEC8DB /* DemoJuceFilter.h in Headers */, 84F055260906FBCF00AEC8DB /* AUSilentTimeout.h in Headers */, 84EB404E090A5116008FAC1B /* JucePluginCharacteristics.h in Headers */, + 84B4CDD20C7DD23B0083122F /* MusicDeviceBase.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -503,6 +510,7 @@ 84F055030906E9EA00AEC8DB /* DemoJuceFilter.cpp in Sources */, 84EB400B090A4A2C008FAC1B /* juce_AudioUnitWrapper.cpp in Sources */, 84EB4042090A4F5A008FAC1B /* CAVectorUnit.cpp in Sources */, + 84B4CDD10C7DD23B0083122F /* MusicDeviceBase.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/extras/audio plugins/demo/src/JucePluginCharacteristics.h b/extras/audio plugins/demo/src/JucePluginCharacteristics.h index 65faee8b1f..2bbe0b37fc 100644 --- a/extras/audio plugins/demo/src/JucePluginCharacteristics.h +++ b/extras/audio plugins/demo/src/JucePluginCharacteristics.h @@ -1,270 +1,270 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the - GNU General Public License, as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - JUCE is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -#ifndef __JUCE_PLUGIN_CHARACTERISTICS_H__ -#define __JUCE_PLUGIN_CHARACTERISTICS_H__ - - -//============================================================================== -/* All of the following settings need to be defined for your plugin. - - Go through each of these definitions and check that it's correctly - set-up before trying to do a build. -*/ - -//============================================================================== -/* Generic settings */ - -/** The name of your plugin. (Try to keep this as short as possible) -*/ -#define JucePlugin_Name "Juce Demo Plugin" - -/** A longer decription of your plugin. -*/ -#define JucePlugin_Desc "A Demo Plugin demonstrating Juce" - -/** The name of your company. (Try to keep this as short as possible) -*/ -#define JucePlugin_Manufacturer "Raw Material Software" - -/** A four-character code for your company. - Use single quotes - this isn't a string! -*/ -#define JucePlugin_ManufacturerCode 'RawM' - -/** A unique four-character code for your plugin. - Use single quotes - this isn't a string! - - Note that for AU compatibility, this must contain at least one - upper-case letter. -*/ -#define JucePlugin_PluginCode 'JcDm' - -//============================================================================== -/** The maximum number of channels of audio input that the plugin can handle. - - The actual number of channels supplied may be less than this, depending on the host. - For VSTs, you specify a maximum number of channels, for AUs and RTAS a set - of channel configurations is specified in JucePlugin_PreferredChannelConfigurations - and the host will choose one of these, but you should still set the max number of - channels correctly. - - As soon as a plugin's prepareToPlay() method is called, you can find out the actual - number of channels that will be used with the AudioFilterBase::getNumInputChannels() - method. -*/ -#define JucePlugin_MaxNumInputChannels 2 - -/** The maximum number of channels of audio output that the plugin can handle. - - The actual number of channels supplied may be less than this, depending on the host. - For VSTs, you specify a maximum number of channels, for AUs and RTAS a set - of channel configurations is specified in JucePlugin_PreferredChannelConfigurations - and the host will choose one of these, but you should still set the max number of - channels correctly. - - As soon as a plugin's prepareToPlay() method is called, you can find out the actual - number of channels that will be used with the AudioFilterBase::getNumOutputChannels() - method. -*/ -#define JucePlugin_MaxNumOutputChannels 2 - -/** This allows the plugin to specify the configurations of input/output channels that - they can support. - - AU and RTAS hosts will use this information, although VSTs only have a concept of - a maximum number of channels. - - The list is a set of pairs of values in the form { numInputs, numOutputs }, and each - pair indicates a valid configuration that the plugin can handle. - - So for example, {1, 1}, {2, 2} means that the plugin can be used in just two - configurations: either with 1 input and 1 output, or with 2 inputs and 2 outputs. If - you used this in Pro-Tools, the plugin could be placed on a mono or stereo track. - If the list was just {1, 1}, then Pro-Tools would only allow it to be used as a mono - plugin. - - As soon as a plugin's prepareToPlay() method is called, you can find out the actual - number of channels that the host has connected to the plugin by using the - AudioFilterBase::getNumOutputChannels() and AudioFilterBase::getNumInputChannels() - methods. -*/ -#define JucePlugin_PreferredChannelConfigurations { 1, 1 }, { 2, 2 } - -//============================================================================== -/** Set this value to 1 if your plugin is a synth, or 0 if it isn't. -*/ -#define JucePlugin_IsSynth 1 - -/** Set this to 1 if your plugin needs to receive midi messages, or 0 if - it doesn't. -*/ -#define JucePlugin_WantsMidiInput 1 - -/** Set this to 1 if your plugin wants to output midi messages, or 0 if - it doesn't. -*/ -#define JucePlugin_ProducesMidiOutput 1 - -/** If this is 1, it means that when the plugins input buffers are - silent, it's output will be too. - - Some hosts may use this to avoid calling the plugin when no audio - would be produced. -*/ -#define JucePlugin_SilenceInProducesSilenceOut 0 - -/** If set to 1, this hints that the host should ignore any keys that are pressed - when the plugin has keyboard focus. If 0, then the host should still execute - any shortcut keys that are pressed, even if the plugin does have focus. - - Various hosts/platforms may deal with this differently, or ignore it. -*/ -#define JucePlugin_EditorRequiresKeyboardFocus 1 - - -//============================================================================== -/** A version number -*/ -#define JucePlugin_VersionCode 0x00010100 - -#define JucePlugin_VersionString "1.1" - - -//============================================================================== -/* VST settings */ - -/** For VSTs, if you're compiling against the V2.3 SDK, set this to zero. If - you're using V2.4 or later, make sure it's set to 1. -*/ -#define JUCE_USE_VSTSDK_2_4 1 - -/** Defines a UID for your VST plugin. - The default setting here is probably fine, unless you specifically need - a custom value. It's passed to the setUniqueID() method of the plugin class. -*/ -#define JucePlugin_VSTUniqueID JucePlugin_PluginCode - -/** Defines the type of plugin. For most pursposes, you don't need to change this - setting. -*/ -#if JucePlugin_IsSynth - #define JucePlugin_VSTCategory kPlugCategSynth -#else - #define JucePlugin_VSTCategory kPlugCategEffect -#endif - -//============================================================================== -/* AudioUnit settings */ - -/** Defines the major type of plugin - see AUComponent.h for the available options. - If it's an effect, you should use kAudioUnitType_Effect. For a synth, you'll - need to use kAudioUnitType_MusicEffect or kAudioUnitType_MusicDevice. -*/ -#if JucePlugin_IsSynth - #define JucePlugin_AUMainType kAudioUnitType_MusicEffect -#else - #define JucePlugin_AUMainType kAudioUnitType_Effect -#endif - -/** A 4-character plugin ID code that should be unique. - - You can leave this using the generic value JucePlugin_PluginCode, or - override it if necessary. - - Note that for AU, this must contain at least one upper-case letter. -*/ -#define JucePlugin_AUSubType JucePlugin_PluginCode - -/** A prefix for the names of exported entry-point functions that the component exposes. - - It's very important that your plugin's .exp file contains two entries that correspond to - this name. So for example if you set the prefix to "abc" then your exports - file must contain: - - _abcEntry - _abcViewEntry -*/ -#define JucePlugin_AUExportPrefix JuceDemoAU - -/** This is the same as JucePlugin_AUExportPrefix, but in quotes - (needed for the resource compiler...) -*/ -#define JucePlugin_AUExportPrefixQuoted "JuceDemoAU" - -/** A 4-character manufacturer code - this is your company name. - You can leave this using the generic value JucePlugin_ManufacturerCode, or - override it if necessary. -*/ -#define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode - -/** If you define this value to be the same as the CFBundleIdentifier in your - plugin's plist, it allows the plugin to work out its own path, which is - needed if you want to use File::getSpecialLocation (currentExecutableFile) -*/ -#define JucePlugin_CFBundleIdentifier "com.rawmaterialsoftware.JuceDemo" - -//============================================================================== -/* RTAS settings */ - -/** How to categorise this plugin. - - For a synth you probably want to set this to ePlugInCategory_SWGenerators. - For an effect, you could choose one of: - ePlugInCategory_None, ePlugInCategory_EQ, ePlugInCategory_Dynamics, - ePlugInCategory_PitchShift, ePlugInCategory_Reverb, ePlugInCategory_Delay, - ePlugInCategory_Modulation, ePlugInCategory_Harmonic, ePlugInCategory_NoiseReduction, - ePlugInCategory_Dither, ePlugInCategory_SoundField - - (All values are listed in FicPluginEnums.h) -*/ -#if JucePlugin_IsSynth - #define JucePlugin_RTASCategory ePlugInCategory_SWGenerators -#else - #define JucePlugin_RTASCategory ePlugInCategory_None -#endif - -/** A 4-character manufacturer code - this is your company name. - You can leave this using the generic value JucePlugin_ManufacturerCode, or - override it if necessary. -*/ -#define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode - -/** A 4-character plugin ID code that should be unique. - You can leave this using the generic value JucePlugin_PluginCode, or - override it if necessary. -*/ -#define JucePlugin_RTASProductId JucePlugin_PluginCode - - -//============================================================================== - -#endif +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + JUCE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +#ifndef __JUCE_PLUGIN_CHARACTERISTICS_H__ +#define __JUCE_PLUGIN_CHARACTERISTICS_H__ + + +//============================================================================== +/* All of the following settings need to be defined for your plugin. + + Go through each of these definitions and check that it's correctly + set-up before trying to do a build. +*/ + +//============================================================================== +/* Generic settings */ + +/** The name of your plugin. (Try to keep this as short as possible) +*/ +#define JucePlugin_Name "Juce Demo Plugin" + +/** A longer decription of your plugin. +*/ +#define JucePlugin_Desc "A Demo Plugin demonstrating Juce" + +/** The name of your company. (Try to keep this as short as possible) +*/ +#define JucePlugin_Manufacturer "Raw Material Software" + +/** A four-character code for your company. + Use single quotes - this isn't a string! +*/ +#define JucePlugin_ManufacturerCode 'RawM' + +/** A unique four-character code for your plugin. + Use single quotes - this isn't a string! + + Note that for AU compatibility, this must contain at least one + upper-case letter. +*/ +#define JucePlugin_PluginCode 'JcDm' + +//============================================================================== +/** The maximum number of channels of audio input that the plugin can handle. + + The actual number of channels supplied may be less than this, depending on the host. + For VSTs, you specify a maximum number of channels, for AUs and RTAS a set + of channel configurations is specified in JucePlugin_PreferredChannelConfigurations + and the host will choose one of these, but you should still set the max number of + channels correctly. + + As soon as a plugin's prepareToPlay() method is called, you can find out the actual + number of channels that will be used with the AudioFilterBase::getNumInputChannels() + method. +*/ +#define JucePlugin_MaxNumInputChannels 2 + +/** The maximum number of channels of audio output that the plugin can handle. + + The actual number of channels supplied may be less than this, depending on the host. + For VSTs, you specify a maximum number of channels, for AUs and RTAS a set + of channel configurations is specified in JucePlugin_PreferredChannelConfigurations + and the host will choose one of these, but you should still set the max number of + channels correctly. + + As soon as a plugin's prepareToPlay() method is called, you can find out the actual + number of channels that will be used with the AudioFilterBase::getNumOutputChannels() + method. +*/ +#define JucePlugin_MaxNumOutputChannels 2 + +/** This allows the plugin to specify the configurations of input/output channels that + they can support. + + AU and RTAS hosts will use this information, although VSTs only have a concept of + a maximum number of channels. + + The list is a set of pairs of values in the form { numInputs, numOutputs }, and each + pair indicates a valid configuration that the plugin can handle. + + So for example, {1, 1}, {2, 2} means that the plugin can be used in just two + configurations: either with 1 input and 1 output, or with 2 inputs and 2 outputs. If + you used this in Pro-Tools, the plugin could be placed on a mono or stereo track. + If the list was just {1, 1}, then Pro-Tools would only allow it to be used as a mono + plugin. + + As soon as a plugin's prepareToPlay() method is called, you can find out the actual + number of channels that the host has connected to the plugin by using the + AudioFilterBase::getNumOutputChannels() and AudioFilterBase::getNumInputChannels() + methods. +*/ +#define JucePlugin_PreferredChannelConfigurations { 1, 1 }, { 2, 2 } + +//============================================================================== +/** Set this value to 1 if your plugin is a synth, or 0 if it isn't. +*/ +#define JucePlugin_IsSynth 0 + +/** Set this to 1 if your plugin needs to receive midi messages, or 0 if + it doesn't. +*/ +#define JucePlugin_WantsMidiInput 1 + +/** Set this to 1 if your plugin wants to output midi messages, or 0 if + it doesn't. +*/ +#define JucePlugin_ProducesMidiOutput 1 + +/** If this is 1, it means that when the plugins input buffers are + silent, it's output will be too. + + Some hosts may use this to avoid calling the plugin when no audio + would be produced. +*/ +#define JucePlugin_SilenceInProducesSilenceOut 0 + +/** If set to 1, this hints that the host should ignore any keys that are pressed + when the plugin has keyboard focus. If 0, then the host should still execute + any shortcut keys that are pressed, even if the plugin does have focus. + + Various hosts/platforms may deal with this differently, or ignore it. +*/ +#define JucePlugin_EditorRequiresKeyboardFocus 1 + + +//============================================================================== +/** A version number +*/ +#define JucePlugin_VersionCode 0x00010100 + +#define JucePlugin_VersionString "1.1" + + +//============================================================================== +/* VST settings */ + +/** For VSTs, if you're compiling against the V2.3 SDK, set this to zero. If + you're using V2.4 or later, make sure it's set to 1. +*/ +#define JUCE_USE_VSTSDK_2_4 1 + +/** Defines a UID for your VST plugin. + The default setting here is probably fine, unless you specifically need + a custom value. It's passed to the setUniqueID() method of the plugin class. +*/ +#define JucePlugin_VSTUniqueID JucePlugin_PluginCode + +/** Defines the type of plugin. For most pursposes, you don't need to change this + setting. +*/ +#if JucePlugin_IsSynth + #define JucePlugin_VSTCategory kPlugCategSynth +#else + #define JucePlugin_VSTCategory kPlugCategEffect +#endif + +//============================================================================== +/* AudioUnit settings */ + +/** Defines the major type of plugin - see AUComponent.h for the available options. + If it's an effect, you should use kAudioUnitType_Effect. For a synth, you'll + need to use kAudioUnitType_MusicEffect or kAudioUnitType_MusicDevice. +*/ +#if JucePlugin_IsSynth + #define JucePlugin_AUMainType kAudioUnitType_MusicDevice +#else + #define JucePlugin_AUMainType kAudioUnitType_Effect +#endif + +/** A 4-character plugin ID code that should be unique. + + You can leave this using the generic value JucePlugin_PluginCode, or + override it if necessary. + + Note that for AU, this must contain at least one upper-case letter. +*/ +#define JucePlugin_AUSubType JucePlugin_PluginCode + +/** A prefix for the names of exported entry-point functions that the component exposes. + + It's very important that your plugin's .exp file contains two entries that correspond to + this name. So for example if you set the prefix to "abc" then your exports + file must contain: + + _abcEntry + _abcViewEntry +*/ +#define JucePlugin_AUExportPrefix JuceDemoAU + +/** This is the same as JucePlugin_AUExportPrefix, but in quotes + (needed for the resource compiler...) +*/ +#define JucePlugin_AUExportPrefixQuoted "JuceDemoAU" + +/** A 4-character manufacturer code - this is your company name. + You can leave this using the generic value JucePlugin_ManufacturerCode, or + override it if necessary. +*/ +#define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode + +/** If you define this value to be the same as the CFBundleIdentifier in your + plugin's plist, it allows the plugin to work out its own path, which is + needed if you want to use File::getSpecialLocation (currentExecutableFile) +*/ +#define JucePlugin_CFBundleIdentifier "com.rawmaterialsoftware.JuceDemo" + +//============================================================================== +/* RTAS settings */ + +/** How to categorise this plugin. + + For a synth you probably want to set this to ePlugInCategory_SWGenerators. + For an effect, you could choose one of: + ePlugInCategory_None, ePlugInCategory_EQ, ePlugInCategory_Dynamics, + ePlugInCategory_PitchShift, ePlugInCategory_Reverb, ePlugInCategory_Delay, + ePlugInCategory_Modulation, ePlugInCategory_Harmonic, ePlugInCategory_NoiseReduction, + ePlugInCategory_Dither, ePlugInCategory_SoundField + + (All values are listed in FicPluginEnums.h) +*/ +#if JucePlugin_IsSynth + #define JucePlugin_RTASCategory ePlugInCategory_SWGenerators +#else + #define JucePlugin_RTASCategory ePlugInCategory_None +#endif + +/** A 4-character manufacturer code - this is your company name. + You can leave this using the generic value JucePlugin_ManufacturerCode, or + override it if necessary. +*/ +#define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode + +/** A 4-character plugin ID code that should be unique. + You can leave this using the generic value JucePlugin_PluginCode, or + override it if necessary. +*/ +#define JucePlugin_RTASProductId JucePlugin_PluginCode + + +//============================================================================== + +#endif diff --git a/extras/audio plugins/wrapper/formats/AudioUnit/juce_AudioUnitWrapper.cpp b/extras/audio plugins/wrapper/formats/AudioUnit/juce_AudioUnitWrapper.cpp index 7e5e372050..31c4bc3111 100644 --- a/extras/audio plugins/wrapper/formats/AudioUnit/juce_AudioUnitWrapper.cpp +++ b/extras/audio plugins/wrapper/formats/AudioUnit/juce_AudioUnitWrapper.cpp @@ -1,897 +1,945 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the - GNU General Public License, as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - JUCE is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -#include -#include "AUMIDIEffectBase.h" -#include "AUCarbonViewBase.h" -#include "../../juce_AudioFilterBase.h" -#include "../../juce_IncludeCharacteristics.h" - - -//============================================================================== -#define juceFilterObjectPropertyID 0x1a45ffe9 -static VoidArray activePlugins; - -static const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; -static const int numChannelConfigs = numElementsInArray (channelConfigs); - -BEGIN_JUCE_NAMESPACE -extern void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw(); -END_JUCE_NAMESPACE - - -//============================================================================== -class JuceAU : public AUMIDIEffectBase, - public AudioFilterBase::HostCallbacks -{ -public: - //============================================================================== - JuceAU (AudioUnit component) - : AUMIDIEffectBase (component), - juceFilter (0), - bufferSpace (2, 16), - channels (0), - prepared (false) - { - CreateElements(); - - if (activePlugins.size() == 0) - { - initialiseJuce_GUI(); - -#ifdef JucePlugin_CFBundleIdentifier - juce_setCurrentExecutableFileNameFromBundleId (JucePlugin_CFBundleIdentifier); -#endif - - MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (0); - } - - juceFilter = createPluginFilter(); - juceFilter->setHostCallbacks (this); - - jassert (juceFilter != 0); - Globals()->UseIndexedParameters (juceFilter->getNumParameters()); - - activePlugins.add (this); - - zerostruct (auEvent); - auEvent.mArgument.mParameter.mAudioUnit = GetComponentInstance(); - auEvent.mArgument.mParameter.mScope = kAudioUnitScope_Global; - auEvent.mArgument.mParameter.mElement = 0; - } - - ~JuceAU() - { - delete juceFilter; - juceFilter = 0; - - juce_free (channels); - channels = 0; - - jassert (activePlugins.contains (this)); - activePlugins.removeValue (this); - - if (activePlugins.size() == 0) - shutdownJuce_GUI(); - } - - //============================================================================== - ComponentResult GetPropertyInfo (AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - UInt32& outDataSize, - Boolean& outWritable) - { - if (inScope == kAudioUnitScope_Global) - { - if (inID == juceFilterObjectPropertyID) - { - outWritable = false; - outDataSize = sizeof (void*); - return noErr; - } - } - - return AUMIDIEffectBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); - } - - ComponentResult GetProperty (AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - void* outData) - { - if (inScope == kAudioUnitScope_Global) - { - if (inID == juceFilterObjectPropertyID) - { - *((void**) outData) = (void*) juceFilter; - return noErr; - } - } - - return AUMIDIEffectBase::GetProperty (inID, inScope, inElement, outData); - } - - ComponentResult SaveState (CFPropertyListRef* outData) - { - ComponentResult err = AUMIDIEffectBase::SaveState (outData); - - if (err != noErr) - return err; - - jassert (CFGetTypeID (*outData) == CFDictionaryGetTypeID()); - - CFMutableDictionaryRef dict = (CFMutableDictionaryRef) *outData; - - if (juceFilter != 0) - { - JUCE_NAMESPACE::MemoryBlock state; - juceFilter->getStateInformation (state); - - if (state.getSize() > 0) - { - CFDataRef ourState = CFDataCreate (kCFAllocatorDefault, (const uint8*) state, state.getSize()); - CFDictionarySetValue (dict, CFSTR("jucePluginState"), ourState); - CFRelease (ourState); - } - } - - return noErr; - } - - ComponentResult RestoreState (CFPropertyListRef inData) - { - ComponentResult err = AUMIDIEffectBase::RestoreState (inData); - - if (err != noErr) - return err; - - if (juceFilter != 0) - { - CFDictionaryRef dict = (CFDictionaryRef) inData; - CFDataRef data = 0; - - if (CFDictionaryGetValueIfPresent (dict, CFSTR("jucePluginState"), - (const void**) &data)) - { - if (data != 0) - { - const int numBytes = (int) CFDataGetLength (data); - const uint8* const rawBytes = CFDataGetBytePtr (data); - - if (numBytes > 0) - juceFilter->setStateInformation (rawBytes, numBytes); - } - } - } - - return noErr; - } - - UInt32 SupportedNumChannels (const AUChannelInfo** outInfo) - { - if (juceFilter == 0) - return 0; - - // You need to actually add some configurations to the JucePlugin_PreferredChannelConfigurations - // value in your JucePluginCharacteristics.h file.. - jassert (numChannelConfigs > 0); - - if (outInfo != 0) - { - for (int i = 0; i < numChannelConfigs; ++i) - { - channelInfo[i].inChannels = channelConfigs[i][0]; - channelInfo[i].outChannels = channelConfigs[i][1]; - - outInfo[i] = channelInfo + i; - } - } - - return numChannelConfigs; - } - - //============================================================================== - ComponentResult GetParameterInfo (AudioUnitScope inScope, - AudioUnitParameterID inParameterID, - AudioUnitParameterInfo& outParameterInfo) - { - const int index = (int) inParameterID; - - if (inScope == kAudioUnitScope_Global - && juceFilter != 0 - && index < juceFilter->getNumParameters()) - { - outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable - | kAudioUnitParameterFlag_IsReadable - | kAudioUnitParameterFlag_HasCFNameString; - - const String name (juceFilter->getParameterName (index)); - - CharacterFunctions::copy ((char*) outParameterInfo.name, - (const char*) name.toUTF8(), - sizeof (outParameterInfo.name) - 1); - - // set whether the param is automatable (unnamed parameters aren't allowed to be automated) - if (name.isEmpty() || ! juceFilter->isParameterAutomatable (index)) - outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime; - - outParameterInfo.cfNameString = PlatformUtilities::juceStringToCFString (name); - outParameterInfo.minValue = 0.0f; - outParameterInfo.maxValue = 1.0f; - outParameterInfo.defaultValue = 0.0f; - outParameterInfo.unit = kAudioUnitParameterUnit_Generic; - - return noErr; - } - else - { - return kAudioUnitErr_InvalidParameter; - } - } - - ComponentResult GetParameter (AudioUnitParameterID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - Float32& outValue) - { - if (inScope == kAudioUnitScope_Global && juceFilter != 0) - { - outValue = juceFilter->getParameter ((int) inID); - return noErr; - } - - return AUBase::GetParameter (inID, inScope, inElement, outValue); - } - - ComponentResult SetParameter (AudioUnitParameterID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - Float32 inValue, - UInt32 inBufferOffsetInFrames) - { - if (inScope == kAudioUnitScope_Global && juceFilter != 0) - { - juceFilter->setParameter ((int) inID, inValue); - return noErr; - } - - return AUBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames); - } - - //============================================================================== - ComponentResult Version() { return JucePlugin_VersionCode; } - - bool SupportsTail() { return true; } - Float64 GetTailTime() { return 0; } - - Float64 GetLatency() - { - jassert (GetSampleRate() > 0); - - if (GetSampleRate() <= 0) - return 0.0; - - return juceFilter->getLatencySamples() / GetSampleRate(); - } - - //============================================================================== - int GetNumCustomUIComponents() { return 1; } - - void GetUIComponentDescs (ComponentDescription* inDescArray) - { - inDescArray[0].componentType = kAudioUnitCarbonViewComponentType; - inDescArray[0].componentSubType = JucePlugin_AUSubType; - inDescArray[0].componentManufacturer = JucePlugin_AUManufacturerCode; - inDescArray[0].componentFlags = 0; - inDescArray[0].componentFlagsMask = 0; - } - - //============================================================================== - bool getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info) - { - info.timeSigNumerator = 0; - info.timeSigDenominator = 0; - info.timeInSeconds = 0; - info.editOriginTime = 0; - info.ppqPositionOfLastBarStart = 0; - info.isPlaying = false; - info.isRecording = false; - - switch (lastSMPTETime.mType) - { - case kSMPTETimeType24: - info.frameRate = AudioFilterBase::CurrentPositionInfo::fps24; - break; - - case kSMPTETimeType25: - info.frameRate = AudioFilterBase::CurrentPositionInfo::fps25; - break; - - case kSMPTETimeType30Drop: - info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30drop; - break; - - case kSMPTETimeType30: - info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30; - break; - - case kSMPTETimeType2997: - info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997; - break; - - case kSMPTETimeType2997Drop: - info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997drop; - break; - - //case kSMPTETimeType60: - //case kSMPTETimeType5994: - default: - info.frameRate = AudioFilterBase::CurrentPositionInfo::fpsUnknown; - break; - } - - if (CallHostBeatAndTempo (&info.ppqPosition, &info.bpm) != noErr) - { - info.ppqPosition = 0; - info.bpm = 0; - } - - UInt32 outDeltaSampleOffsetToNextBeat; - double outCurrentMeasureDownBeat; - float num; - UInt32 den; - - if (CallHostMusicalTimeLocation (&outDeltaSampleOffsetToNextBeat, &num, &den, - &outCurrentMeasureDownBeat) == noErr) - { - info.timeSigNumerator = (int) num; - info.timeSigDenominator = den; - info.ppqPositionOfLastBarStart = outCurrentMeasureDownBeat; - } - - double outCurrentSampleInTimeLine, outCycleStartBeat, outCycleEndBeat; - Boolean playing, playchanged, looping; - - if (CallHostTransportState (&playing, - &playchanged, - &outCurrentSampleInTimeLine, - &looping, - &outCycleStartBeat, - &outCycleEndBeat) == noErr) - { - info.isPlaying = playing; - info.timeInSeconds = outCurrentSampleInTimeLine / GetSampleRate(); - } - - return true; - } - - void sendAUEvent (const AudioUnitEventType type, const int index) throw() - { - if (AUEventListenerNotify != 0) - { - auEvent.mEventType = type; - auEvent.mArgument.mParameter.mParameterID = (AudioUnitParameterID) index; - AUEventListenerNotify (0, 0, &auEvent); - } - } - - void informHostOfParameterChange (int index, float newValue) - { - if (juceFilter != 0) - { - juceFilter->setParameter (index, newValue); - sendAUEvent (kAudioUnitEvent_ParameterValueChange, index); - } - } - - void informHostOfParameterGestureBegin (int index) - { - if (juceFilter != 0) - sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index); - } - - void informHostOfParameterGestureEnd (int index) - { - if (juceFilter != 0) - sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index); - } - - void informHostOfStateChange() - { - // xxx is there an AU equivalent? - } - - //============================================================================== - ComponentResult Initialize() - { - AUMIDIEffectBase::Initialize(); - - const int numIns = GetInput(0) != 0 ? GetInput(0)->GetStreamFormat().mChannelsPerFrame : 0; - const int numOuts = GetOutput(0) != 0 ? GetOutput(0)->GetStreamFormat().mChannelsPerFrame : 0; - - bool isValidChannelConfig = false; - - for (int i = 0; i < numChannelConfigs; ++i) - if (numIns == channelConfigs[i][0] && numOuts == channelConfigs[i][1]) - isValidChannelConfig = true; - - if (! isValidChannelConfig) - return kAudioUnitErr_FormatNotSupported; - - prepareToPlay(); - return noErr; - } - - void Cleanup() - { - AUMIDIEffectBase::Cleanup(); - - if (juceFilter != 0) - juceFilter->releaseResources(); - - bufferSpace.setSize (2, 16); - midiEvents.clear(); - prepared = false; - } - - ComponentResult Reset (AudioUnitScope inScope, AudioUnitElement inElement) - { - if (! prepared) - prepareToPlay(); - - return AUMIDIEffectBase::Reset (inScope, inElement); - } - - void prepareToPlay() - { - if (juceFilter != 0) - { - juceFilter->setPlayConfigDetails (GetInput(0)->GetStreamFormat().mChannelsPerFrame, - GetOutput(0)->GetStreamFormat().mChannelsPerFrame, - GetSampleRate(), - GetMaxFramesPerSlice()); - - bufferSpace.setSize (juceFilter->getNumInputChannels() + juceFilter->getNumOutputChannels(), - GetMaxFramesPerSlice() + 32); - - juceFilter->prepareToPlay (GetSampleRate(), - GetMaxFramesPerSlice()); - - midiEvents.clear(); - - juce_free (channels); - channels = (float**) juce_calloc (sizeof (float*) * jmax (juceFilter->getNumInputChannels(), - juceFilter->getNumOutputChannels()) + 4); - - prepared = true; - } - } - - ComponentResult Render (AudioUnitRenderActionFlags &ioActionFlags, - const AudioTimeStamp& inTimeStamp, - UInt32 nFrames) - { - lastSMPTETime = inTimeStamp.mSMPTETime; - - return AUMIDIEffectBase::Render (ioActionFlags, inTimeStamp, nFrames); - } - - - OSStatus ProcessBufferLists (AudioUnitRenderActionFlags& ioActionFlags, - const AudioBufferList& inBuffer, - AudioBufferList& outBuffer, - UInt32 numSamples) - { - if (juceFilter != 0) - { - jassert (prepared); - - int numOutChans = 0; - int nextSpareBufferChan = 0; - bool needToReinterleave = false; - const int numIn = juceFilter->getNumInputChannels(); - const int numOut = juceFilter->getNumOutputChannels(); - - unsigned int i; - for (i = 0; i < outBuffer.mNumberBuffers; ++i) - { - AudioBuffer& buf = outBuffer.mBuffers[i]; - - if (buf.mNumberChannels == 1) - { - channels [numOutChans++] = (float*) buf.mData; - } - else - { - needToReinterleave = true; - - for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numOutChans < numOut; ++subChan) - channels [numOutChans++] = bufferSpace.getSampleData (nextSpareBufferChan++); - } - - if (numOutChans >= numOut) - break; - } - - int numInChans = 0; - - for (i = 0; i < inBuffer.mNumberBuffers; ++i) - { - const AudioBuffer& buf = inBuffer.mBuffers[i]; - - if (buf.mNumberChannels == 1) - { - if (numInChans < numOut) - memcpy (channels [numInChans], (const float*) buf.mData, sizeof (float) * numSamples); - else - channels [numInChans] = (float*) buf.mData; - } - else - { - // need to de-interleave.. - for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numInChans < numIn; ++subChan) - { - float* dest; - - if (numInChans >= numOut) - { - dest = bufferSpace.getSampleData (nextSpareBufferChan++); - channels [numInChans++] = dest; - } - else - { - dest = channels [numInChans++]; - } - - const float* src = ((const float*) buf.mData) + subChan; - - for (int j = numSamples; --j >= 0;) - { - *dest++ = *src; - src += buf.mNumberChannels; - } - } - } - - if (numInChans >= numIn) - break; - } - - { - AudioSampleBuffer buffer (channels, jmax (numIn, numOut), numSamples); - - const ScopedLock sl (juceFilter->getCallbackLock()); - - if (juceFilter->isSuspended()) - { - for (int i = 0; i < numOut; ++i) - zeromem (channels [i], sizeof (float) * numSamples); - } - else - { - juceFilter->processBlock (buffer, midiEvents); - } - } - - if (! midiEvents.isEmpty()) - { -#if JucePlugin_ProducesMidiOutput - const uint8* midiEventData; - int midiEventSize, midiEventPosition; - MidiBuffer::Iterator i (midiEvents); - - while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) - { - jassert (midiEventPosition >= 0 && midiEventPosition < (int) numSamples); - - - - //xxx - } -#else - // if your plugin creates midi messages, you'll need to set - // the JucePlugin_ProducesMidiOutput macro to 1 in your - // JucePluginCharacteristics.h file - //jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn); -#endif - midiEvents.clear(); - } - - if (needToReinterleave) - { - nextSpareBufferChan = 0; - - for (i = 0; i < outBuffer.mNumberBuffers; ++i) - { - AudioBuffer& buf = outBuffer.mBuffers[i]; - - if (buf.mNumberChannels > 1) - { - for (unsigned int subChan = 0; subChan < buf.mNumberChannels; ++subChan) - { - const float* src = bufferSpace.getSampleData (nextSpareBufferChan++); - float* dest = ((float*) buf.mData) + subChan; - - for (int j = numSamples; --j >= 0;) - { - *dest = *src++; - dest += buf.mNumberChannels; - } - } - } - } - } - -#if ! JucePlugin_SilenceInProducesSilenceOut - ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence; -#endif - } - - return noErr; - } - -protected: - OSStatus HandleMidiEvent (UInt8 nStatus, - UInt8 inChannel, - UInt8 inData1, - UInt8 inData2, - long inStartFrame) - { -#if JucePlugin_WantsMidiInput - uint8 data [4]; - data[0] = nStatus | inChannel; - data[1] = inData1; - data[2] = inData2; - - midiEvents.addEvent (data, 3, inStartFrame); -#endif - - return noErr; - } - - //============================================================================== -private: - AudioFilterBase* juceFilter; - AudioSampleBuffer bufferSpace; - float** channels; - MidiBuffer midiEvents; - bool prepared; - SMPTETime lastSMPTETime; - AUChannelInfo channelInfo [numChannelConfigs]; - AudioUnitEvent auEvent; -}; - - -//============================================================================== -class JuceAUComponentHolder : public Component -{ -public: - JuceAUComponentHolder (Component* const editorComp) - { - addAndMakeVisible (editorComp); - setOpaque (true); - setVisible (true); - setBroughtToFrontOnMouseClick (true); - -#if ! JucePlugin_EditorRequiresKeyboardFocus - setWantsKeyboardFocus (false); -#endif - } - - ~JuceAUComponentHolder() - { - } - - void resized() - { - if (getNumChildComponents() > 0) - getChildComponent (0)->setBounds (0, 0, getWidth(), getHeight()); - } - - void paint (Graphics& g) - { - } -}; - -//============================================================================== -class JuceAUView : public AUCarbonViewBase, - public ComponentListener, - public MouseListener, - public Timer -{ - AudioFilterBase* juceFilter; - AudioFilterEditor* editorComp; - Component* windowComp; - bool recursive; - int mx, my; - -public: - JuceAUView (AudioUnitCarbonView auview) - : AUCarbonViewBase (auview), - juceFilter (0), - editorComp (0), - windowComp (0), - recursive (false), - mx (0), - my (0) - { - } - - ~JuceAUView() - { - deleteUI(); - } - - ComponentResult CreateUI (Float32 inXOffset, Float32 inYOffset) - { - if (juceFilter == 0) - { - UInt32 propertySize = sizeof (&juceFilter); - - AudioUnitGetProperty (GetEditAudioUnit(), - juceFilterObjectPropertyID, - kAudioUnitScope_Global, - 0, - &juceFilter, - &propertySize); - } - - if (juceFilter != 0) - { - deleteUI(); - - editorComp = juceFilter->createEditorIfNeeded(); - - const int w = editorComp->getWidth(); - const int h = editorComp->getHeight(); - - editorComp->setOpaque (true); - editorComp->setVisible (true); - - windowComp = new JuceAUComponentHolder (editorComp); - windowComp->setBounds ((int) inXOffset, (int) inYOffset, w, h); - - windowComp->addToDesktop (0, (void*) mCarbonPane); - SizeControl (mCarbonPane, w, h); - - editorComp->addComponentListener (this); - windowComp->addMouseListener (this, true); - - startTimer (20); - } - else - { - jassertfalse // can't get a pointer to our effect - } - - return noErr; - } - - void componentMovedOrResized (Component& component, - bool wasMoved, - bool wasResized) - { - if (! recursive) - { - recursive = true; - - if (editorComp != 0 && wasResized) - { - const int w = jmax (32, editorComp->getWidth()); - const int h = jmax (32, editorComp->getHeight()); - - SizeControl (mCarbonPane, w, h); - - if (windowComp->getWidth() != w - || windowComp->getHeight() != h) - { - windowComp->setSize (w, h); - } - - editorComp->repaint(); - } - - recursive = false; - } - } - - void timerCallback() - { - // for some stupid Apple-related reason, mouse move events just don't seem to get sent - // to the windows in an AU, so we have to bodge it here and simulate them with a - // timer.. - if (editorComp != 0) - { - int x, y; - Desktop::getInstance().getMousePosition (x, y); - - if (x != mx || y != my) - { - mx = x; - my = y; - - if (! ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown()) - { - for (int i = ComponentPeer::getNumPeers(); --i >= 0;) - { - ComponentPeer* const peer = ComponentPeer::getPeer (i); - - const int rx = x - peer->getComponent()->getX(); - const int ry = y - peer->getComponent()->getY(); - - if (peer->contains (rx, ry, false) && peer->getComponent()->isShowing()) - { - peer->handleMouseMove (rx, ry, Time::currentTimeMillis()); - break; - } - } - } - } - } - } - - void mouseMove (const MouseEvent& e) - { - Desktop::getInstance().getMousePosition (mx, my); - startTimer (20); - } - -private: - void deleteUI() - { - PopupMenu::dismissAllActiveMenus(); - - // there's some kind of component currently modal, but the host - // is trying to delete our plugin.. - jassert (Component::getCurrentlyModalComponent() == 0); - - if (editorComp != 0) - juceFilter->editorBeingDeleted (editorComp); - - deleteAndZero (editorComp); - deleteAndZero (windowComp); - } -}; - -//============================================================================== -#define JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) \ -extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj); \ -extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj) \ -{ \ - return ComponentEntryPoint::Dispatch(params, obj); \ -} - -#define JUCE_COMPONENT_ENTRY(Class, Name, Suffix) JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) - -JUCE_COMPONENT_ENTRY (JuceAU, JucePlugin_AUExportPrefix, Entry) -JUCE_COMPONENT_ENTRY (JuceAUView, JucePlugin_AUExportPrefix, ViewEntry) +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + JUCE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +#include +#include "AUMIDIEffectBase.h" +#include "MusicDeviceBase.h" +#include "AUCarbonViewBase.h" +#include "../../juce_AudioFilterBase.h" +#include "../../juce_IncludeCharacteristics.h" + + +//============================================================================== +#define juceFilterObjectPropertyID 0x1a45ffe9 +static VoidArray activePlugins; + +static const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; +static const int numChannelConfigs = numElementsInArray (channelConfigs); + +BEGIN_JUCE_NAMESPACE +extern void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw(); +END_JUCE_NAMESPACE + +#if JucePlugin_IsSynth + #define JuceAUBaseClass MusicDeviceBase +#else + #define JuceAUBaseClass AUMIDIEffectBase +#endif + +//============================================================================== +class JuceAU : public JuceAUBaseClass, + public AudioFilterBase::HostCallbacks +{ +public: + //============================================================================== + JuceAU (AudioUnit component) +#if JucePlugin_IsSynth + : MusicDeviceBase (component, 0, 1), +#else + : AUMIDIEffectBase (component), +#endif + juceFilter (0), + bufferSpace (2, 16), + channels (0), + prepared (false) + { + CreateElements(); + + if (activePlugins.size() == 0) + { + initialiseJuce_GUI(); + +#ifdef JucePlugin_CFBundleIdentifier + juce_setCurrentExecutableFileNameFromBundleId (JucePlugin_CFBundleIdentifier); +#endif + + MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (0); + } + + juceFilter = createPluginFilter(); + juceFilter->setHostCallbacks (this); + + jassert (juceFilter != 0); + Globals()->UseIndexedParameters (juceFilter->getNumParameters()); + + activePlugins.add (this); + + zerostruct (auEvent); + auEvent.mArgument.mParameter.mAudioUnit = GetComponentInstance(); + auEvent.mArgument.mParameter.mScope = kAudioUnitScope_Global; + auEvent.mArgument.mParameter.mElement = 0; + } + + ~JuceAU() + { + delete juceFilter; + juceFilter = 0; + + juce_free (channels); + channels = 0; + + jassert (activePlugins.contains (this)); + activePlugins.removeValue (this); + + if (activePlugins.size() == 0) + shutdownJuce_GUI(); + } + + //============================================================================== + ComponentResult GetPropertyInfo (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32& outDataSize, + Boolean& outWritable) + { + if (inScope == kAudioUnitScope_Global) + { + if (inID == juceFilterObjectPropertyID) + { + outWritable = false; + outDataSize = sizeof (void*); + return noErr; + } + } + + return JuceAUBaseClass::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); + } + + ComponentResult GetProperty (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void* outData) + { + if (inScope == kAudioUnitScope_Global) + { + if (inID == juceFilterObjectPropertyID) + { + *((void**) outData) = (void*) juceFilter; + return noErr; + } + } + + return JuceAUBaseClass::GetProperty (inID, inScope, inElement, outData); + } + + ComponentResult SaveState (CFPropertyListRef* outData) + { + ComponentResult err = JuceAUBaseClass::SaveState (outData); + + if (err != noErr) + return err; + + jassert (CFGetTypeID (*outData) == CFDictionaryGetTypeID()); + + CFMutableDictionaryRef dict = (CFMutableDictionaryRef) *outData; + + if (juceFilter != 0) + { + JUCE_NAMESPACE::MemoryBlock state; + juceFilter->getStateInformation (state); + + if (state.getSize() > 0) + { + CFDataRef ourState = CFDataCreate (kCFAllocatorDefault, (const uint8*) state, state.getSize()); + CFDictionarySetValue (dict, CFSTR("jucePluginState"), ourState); + CFRelease (ourState); + } + } + + return noErr; + } + + ComponentResult RestoreState (CFPropertyListRef inData) + { + ComponentResult err = JuceAUBaseClass::RestoreState (inData); + + if (err != noErr) + return err; + + if (juceFilter != 0) + { + CFDictionaryRef dict = (CFDictionaryRef) inData; + CFDataRef data = 0; + + if (CFDictionaryGetValueIfPresent (dict, CFSTR("jucePluginState"), + (const void**) &data)) + { + if (data != 0) + { + const int numBytes = (int) CFDataGetLength (data); + const uint8* const rawBytes = CFDataGetBytePtr (data); + + if (numBytes > 0) + juceFilter->setStateInformation (rawBytes, numBytes); + } + } + } + + return noErr; + } + + UInt32 SupportedNumChannels (const AUChannelInfo** outInfo) + { + // You need to actually add some configurations to the JucePlugin_PreferredChannelConfigurations + // value in your JucePluginCharacteristics.h file.. + jassert (numChannelConfigs > 0); + + if (outInfo != 0) + { + for (int i = 0; i < numChannelConfigs; ++i) + { +#if JucePlugin_IsSynth + channelInfo[i].inChannels = 0; +#else + channelInfo[i].inChannels = channelConfigs[i][0]; +#endif + channelInfo[i].outChannels = channelConfigs[i][1]; + + outInfo[i] = channelInfo + i; + } + } + + return numChannelConfigs; + } + + //============================================================================== + ComponentResult GetParameterInfo (AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + AudioUnitParameterInfo& outParameterInfo) + { + const int index = (int) inParameterID; + + if (inScope == kAudioUnitScope_Global + && juceFilter != 0 + && index < juceFilter->getNumParameters()) + { + outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable + | kAudioUnitParameterFlag_IsReadable + | kAudioUnitParameterFlag_HasCFNameString; + + const String name (juceFilter->getParameterName (index)); + + CharacterFunctions::copy ((char*) outParameterInfo.name, + (const char*) name.toUTF8(), + sizeof (outParameterInfo.name) - 1); + + // set whether the param is automatable (unnamed parameters aren't allowed to be automated) + if (name.isEmpty() || ! juceFilter->isParameterAutomatable (index)) + outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime; + + outParameterInfo.cfNameString = PlatformUtilities::juceStringToCFString (name); + outParameterInfo.minValue = 0.0f; + outParameterInfo.maxValue = 1.0f; + outParameterInfo.defaultValue = 0.0f; + outParameterInfo.unit = kAudioUnitParameterUnit_Generic; + + return noErr; + } + else + { + return kAudioUnitErr_InvalidParameter; + } + } + + ComponentResult GetParameter (AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + Float32& outValue) + { + if (inScope == kAudioUnitScope_Global && juceFilter != 0) + { + outValue = juceFilter->getParameter ((int) inID); + return noErr; + } + + return AUBase::GetParameter (inID, inScope, inElement, outValue); + } + + ComponentResult SetParameter (AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + Float32 inValue, + UInt32 inBufferOffsetInFrames) + { + if (inScope == kAudioUnitScope_Global && juceFilter != 0) + { + juceFilter->setParameter ((int) inID, inValue); + return noErr; + } + + return AUBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames); + } + + //============================================================================== + ComponentResult Version() { return JucePlugin_VersionCode; } + + bool SupportsTail() { return true; } + Float64 GetTailTime() { return 0; } + + Float64 GetSampleRate() + { + return GetOutput(0)->GetStreamFormat().mSampleRate; + } + + Float64 GetLatency() + { + jassert (GetSampleRate() > 0); + + if (GetSampleRate() <= 0) + return 0.0; + + return juceFilter->getLatencySamples() / GetSampleRate(); + } + + //============================================================================== + int GetNumCustomUIComponents() { return 1; } + + void GetUIComponentDescs (ComponentDescription* inDescArray) + { + inDescArray[0].componentType = kAudioUnitCarbonViewComponentType; + inDescArray[0].componentSubType = JucePlugin_AUSubType; + inDescArray[0].componentManufacturer = JucePlugin_AUManufacturerCode; + inDescArray[0].componentFlags = 0; + inDescArray[0].componentFlagsMask = 0; + } + + //============================================================================== + bool getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info) + { + info.timeSigNumerator = 0; + info.timeSigDenominator = 0; + info.timeInSeconds = 0; + info.editOriginTime = 0; + info.ppqPositionOfLastBarStart = 0; + info.isPlaying = false; + info.isRecording = false; + + switch (lastSMPTETime.mType) + { + case kSMPTETimeType24: + info.frameRate = AudioFilterBase::CurrentPositionInfo::fps24; + break; + + case kSMPTETimeType25: + info.frameRate = AudioFilterBase::CurrentPositionInfo::fps25; + break; + + case kSMPTETimeType30Drop: + info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30drop; + break; + + case kSMPTETimeType30: + info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30; + break; + + case kSMPTETimeType2997: + info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997; + break; + + case kSMPTETimeType2997Drop: + info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997drop; + break; + + //case kSMPTETimeType60: + //case kSMPTETimeType5994: + default: + info.frameRate = AudioFilterBase::CurrentPositionInfo::fpsUnknown; + break; + } + + if (CallHostBeatAndTempo (&info.ppqPosition, &info.bpm) != noErr) + { + info.ppqPosition = 0; + info.bpm = 0; + } + + UInt32 outDeltaSampleOffsetToNextBeat; + double outCurrentMeasureDownBeat; + float num; + UInt32 den; + + if (CallHostMusicalTimeLocation (&outDeltaSampleOffsetToNextBeat, &num, &den, + &outCurrentMeasureDownBeat) == noErr) + { + info.timeSigNumerator = (int) num; + info.timeSigDenominator = den; + info.ppqPositionOfLastBarStart = outCurrentMeasureDownBeat; + } + + double outCurrentSampleInTimeLine, outCycleStartBeat, outCycleEndBeat; + Boolean playing, playchanged, looping; + + if (CallHostTransportState (&playing, + &playchanged, + &outCurrentSampleInTimeLine, + &looping, + &outCycleStartBeat, + &outCycleEndBeat) == noErr) + { + info.isPlaying = playing; + info.timeInSeconds = outCurrentSampleInTimeLine / GetSampleRate(); + } + + return true; + } + + void sendAUEvent (const AudioUnitEventType type, const int index) throw() + { + if (AUEventListenerNotify != 0) + { + auEvent.mEventType = type; + auEvent.mArgument.mParameter.mParameterID = (AudioUnitParameterID) index; + AUEventListenerNotify (0, 0, &auEvent); + } + } + + void informHostOfParameterChange (int index, float newValue) + { + if (juceFilter != 0) + { + juceFilter->setParameter (index, newValue); + sendAUEvent (kAudioUnitEvent_ParameterValueChange, index); + } + } + + void informHostOfParameterGestureBegin (int index) + { + if (juceFilter != 0) + sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index); + } + + void informHostOfParameterGestureEnd (int index) + { + if (juceFilter != 0) + sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index); + } + + void informHostOfStateChange() + { + // xxx is there an AU equivalent? + } + + bool StreamFormatWritable (AudioUnitScope inScope, AudioUnitElement element) + { + return ! IsInitialized(); + } + + ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID&, UInt32, const MusicDeviceNoteParams&) + { + return noErr; + } + + ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32) + { + return noErr; + } + + //============================================================================== + ComponentResult Initialize() + { +#if ! JucePlugin_IsSynth + const int numIns = GetInput(0) != 0 ? GetInput(0)->GetStreamFormat().mChannelsPerFrame : 0; +#endif + const int numOuts = GetOutput(0) != 0 ? GetOutput(0)->GetStreamFormat().mChannelsPerFrame : 0; + + bool isValidChannelConfig = false; + + for (int i = 0; i < numChannelConfigs; ++i) +#if JucePlugin_IsSynth + if (numOuts == channelConfigs[i][1]) +#else + if (numIns == channelConfigs[i][0] && numOuts == channelConfigs[i][1]) +#endif + isValidChannelConfig = true; + + if (! isValidChannelConfig) + return kAudioUnitErr_FormatNotSupported; + + JuceAUBaseClass::Initialize(); + prepareToPlay(); + return noErr; + } + + void Cleanup() + { + JuceAUBaseClass::Cleanup(); + + if (juceFilter != 0) + juceFilter->releaseResources(); + + bufferSpace.setSize (2, 16); + midiEvents.clear(); + prepared = false; + } + + ComponentResult Reset (AudioUnitScope inScope, AudioUnitElement inElement) + { + if (! prepared) + prepareToPlay(); + + return JuceAUBaseClass::Reset (inScope, inElement); + } + + void prepareToPlay() + { + if (juceFilter != 0) + { +#if ! JucePlugin_IsSynth + juceFilter->setPlayConfigDetails (GetInput(0)->GetStreamFormat().mChannelsPerFrame, +#else + juceFilter->setPlayConfigDetails (0, +#endif + GetOutput(0)->GetStreamFormat().mChannelsPerFrame, + GetSampleRate(), + GetMaxFramesPerSlice()); + + bufferSpace.setSize (juceFilter->getNumInputChannels() + juceFilter->getNumOutputChannels(), + GetMaxFramesPerSlice() + 32); + + juceFilter->prepareToPlay (GetSampleRate(), + GetMaxFramesPerSlice()); + + midiEvents.clear(); + + juce_free (channels); + channels = (float**) juce_calloc (sizeof (float*) * jmax (juceFilter->getNumInputChannels(), + juceFilter->getNumOutputChannels()) + 4); + + prepared = true; + } + } + + ComponentResult Render (AudioUnitRenderActionFlags &ioActionFlags, + const AudioTimeStamp& inTimeStamp, + UInt32 nFrames) + { + lastSMPTETime = inTimeStamp.mSMPTETime; + +#if ! JucePlugin_IsSynth + return JuceAUBaseClass::Render (ioActionFlags, inTimeStamp, nFrames); +#else + // synths can't have any inputs.. + AudioBufferList inBuffer; + inBuffer.mNumberBuffers = 0; + + return ProcessBufferLists (ioActionFlags, inBuffer, GetOutput(0)->GetBufferList(), nFrames); +#endif + } + + + OSStatus ProcessBufferLists (AudioUnitRenderActionFlags& ioActionFlags, + const AudioBufferList& inBuffer, + AudioBufferList& outBuffer, + UInt32 numSamples) + { + if (juceFilter != 0) + { + jassert (prepared); + + int numOutChans = 0; + int nextSpareBufferChan = 0; + bool needToReinterleave = false; + const int numIn = juceFilter->getNumInputChannels(); + const int numOut = juceFilter->getNumOutputChannels(); + + unsigned int i; + for (i = 0; i < outBuffer.mNumberBuffers; ++i) + { + AudioBuffer& buf = outBuffer.mBuffers[i]; + + if (buf.mNumberChannels == 1) + { + channels [numOutChans++] = (float*) buf.mData; + } + else + { + needToReinterleave = true; + + for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numOutChans < numOut; ++subChan) + channels [numOutChans++] = bufferSpace.getSampleData (nextSpareBufferChan++); + } + + if (numOutChans >= numOut) + break; + } + + int numInChans = 0; + + for (i = 0; i < inBuffer.mNumberBuffers; ++i) + { + const AudioBuffer& buf = inBuffer.mBuffers[i]; + + if (buf.mNumberChannels == 1) + { + if (numInChans < numOut) + memcpy (channels [numInChans], (const float*) buf.mData, sizeof (float) * numSamples); + else + channels [numInChans] = (float*) buf.mData; + } + else + { + // need to de-interleave.. + for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numInChans < numIn; ++subChan) + { + float* dest; + + if (numInChans >= numOut) + { + dest = bufferSpace.getSampleData (nextSpareBufferChan++); + channels [numInChans++] = dest; + } + else + { + dest = channels [numInChans++]; + } + + const float* src = ((const float*) buf.mData) + subChan; + + for (int j = numSamples; --j >= 0;) + { + *dest++ = *src; + src += buf.mNumberChannels; + } + } + } + + if (numInChans >= numIn) + break; + } + + { + AudioSampleBuffer buffer (channels, jmax (numIn, numOut), numSamples); + + const ScopedLock sl (juceFilter->getCallbackLock()); + + if (juceFilter->isSuspended()) + { + for (int i = 0; i < numOut; ++i) + zeromem (channels [i], sizeof (float) * numSamples); + } + else + { + juceFilter->processBlock (buffer, midiEvents); + } + } + + if (! midiEvents.isEmpty()) + { +#if JucePlugin_ProducesMidiOutput + const uint8* midiEventData; + int midiEventSize, midiEventPosition; + MidiBuffer::Iterator i (midiEvents); + + while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) + { + jassert (midiEventPosition >= 0 && midiEventPosition < (int) numSamples); + + + + //xxx + } +#else + // if your plugin creates midi messages, you'll need to set + // the JucePlugin_ProducesMidiOutput macro to 1 in your + // JucePluginCharacteristics.h file + //jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn); +#endif + midiEvents.clear(); + } + + if (needToReinterleave) + { + nextSpareBufferChan = 0; + + for (i = 0; i < outBuffer.mNumberBuffers; ++i) + { + AudioBuffer& buf = outBuffer.mBuffers[i]; + + if (buf.mNumberChannels > 1) + { + for (unsigned int subChan = 0; subChan < buf.mNumberChannels; ++subChan) + { + const float* src = bufferSpace.getSampleData (nextSpareBufferChan++); + float* dest = ((float*) buf.mData) + subChan; + + for (int j = numSamples; --j >= 0;) + { + *dest = *src++; + dest += buf.mNumberChannels; + } + } + } + } + } + +#if ! JucePlugin_SilenceInProducesSilenceOut + ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence; +#endif + } + + return noErr; + } + +protected: + OSStatus HandleMidiEvent (UInt8 nStatus, + UInt8 inChannel, + UInt8 inData1, + UInt8 inData2, + long inStartFrame) + { +#if JucePlugin_WantsMidiInput + uint8 data [4]; + data[0] = nStatus | inChannel; + data[1] = inData1; + data[2] = inData2; + + midiEvents.addEvent (data, 3, inStartFrame); +#endif + + return noErr; + } + + //============================================================================== +private: + AudioFilterBase* juceFilter; + AudioSampleBuffer bufferSpace; + float** channels; + MidiBuffer midiEvents; + bool prepared; + SMPTETime lastSMPTETime; + AUChannelInfo channelInfo [numChannelConfigs]; + AudioUnitEvent auEvent; +}; + + +//============================================================================== +class JuceAUComponentHolder : public Component +{ +public: + JuceAUComponentHolder (Component* const editorComp) + { + addAndMakeVisible (editorComp); + setOpaque (true); + setVisible (true); + setBroughtToFrontOnMouseClick (true); + +#if ! JucePlugin_EditorRequiresKeyboardFocus + setWantsKeyboardFocus (false); +#endif + } + + ~JuceAUComponentHolder() + { + } + + void resized() + { + if (getNumChildComponents() > 0) + getChildComponent (0)->setBounds (0, 0, getWidth(), getHeight()); + } + + void paint (Graphics& g) + { + } +}; + +//============================================================================== +class JuceAUView : public AUCarbonViewBase, + public ComponentListener, + public MouseListener, + public Timer +{ + AudioFilterBase* juceFilter; + AudioFilterEditor* editorComp; + Component* windowComp; + bool recursive; + int mx, my; + +public: + JuceAUView (AudioUnitCarbonView auview) + : AUCarbonViewBase (auview), + juceFilter (0), + editorComp (0), + windowComp (0), + recursive (false), + mx (0), + my (0) + { + } + + ~JuceAUView() + { + deleteUI(); + } + + ComponentResult CreateUI (Float32 inXOffset, Float32 inYOffset) + { + if (juceFilter == 0) + { + UInt32 propertySize = sizeof (&juceFilter); + + AudioUnitGetProperty (GetEditAudioUnit(), + juceFilterObjectPropertyID, + kAudioUnitScope_Global, + 0, + &juceFilter, + &propertySize); + } + + if (juceFilter != 0) + { + deleteUI(); + + editorComp = juceFilter->createEditorIfNeeded(); + + const int w = editorComp->getWidth(); + const int h = editorComp->getHeight(); + + editorComp->setOpaque (true); + editorComp->setVisible (true); + + windowComp = new JuceAUComponentHolder (editorComp); + windowComp->setBounds ((int) inXOffset, (int) inYOffset, w, h); + + windowComp->addToDesktop (0, (void*) mCarbonPane); + SizeControl (mCarbonPane, w, h); + + editorComp->addComponentListener (this); + windowComp->addMouseListener (this, true); + + startTimer (20); + } + else + { + jassertfalse // can't get a pointer to our effect + } + + return noErr; + } + + void componentMovedOrResized (Component& component, + bool wasMoved, + bool wasResized) + { + if (! recursive) + { + recursive = true; + + if (editorComp != 0 && wasResized) + { + const int w = jmax (32, editorComp->getWidth()); + const int h = jmax (32, editorComp->getHeight()); + + SizeControl (mCarbonPane, w, h); + + if (windowComp->getWidth() != w + || windowComp->getHeight() != h) + { + windowComp->setSize (w, h); + } + + editorComp->repaint(); + } + + recursive = false; + } + } + + void timerCallback() + { + // for some stupid Apple-related reason, mouse move events just don't seem to get sent + // to the windows in an AU, so we have to bodge it here and simulate them with a + // timer.. + if (editorComp != 0) + { + int x, y; + Desktop::getInstance().getMousePosition (x, y); + + if (x != mx || y != my) + { + mx = x; + my = y; + + if (! ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown()) + { + for (int i = ComponentPeer::getNumPeers(); --i >= 0;) + { + ComponentPeer* const peer = ComponentPeer::getPeer (i); + + int rx = x, ry = y; + peer->getComponent()->globalPositionToRelative (rx, ry); + + if (peer->contains (rx, ry, false) && peer->getComponent()->isShowing()) + { + peer->handleMouseMove (rx, ry, Time::currentTimeMillis()); + break; + } + } + } + } + } + } + + void mouseMove (const MouseEvent& e) + { + Desktop::getInstance().getMousePosition (mx, my); + startTimer (20); + } + +private: + void deleteUI() + { + PopupMenu::dismissAllActiveMenus(); + + // there's some kind of component currently modal, but the host + // is trying to delete our plugin.. + jassert (Component::getCurrentlyModalComponent() == 0); + + if (editorComp != 0) + juceFilter->editorBeingDeleted (editorComp); + + deleteAndZero (editorComp); + deleteAndZero (windowComp); + } +}; + +//============================================================================== +#define JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) \ +extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj); \ +extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj) \ +{ \ + return ComponentEntryPoint::Dispatch(params, obj); \ +} + +#define JUCE_COMPONENT_ENTRY(Class, Name, Suffix) JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) + +JUCE_COMPONENT_ENTRY (JuceAU, JucePlugin_AUExportPrefix, Entry) +JUCE_COMPONENT_ENTRY (JuceAUView, JucePlugin_AUExportPrefix, ViewEntry)