diff --git a/build/linux/platform_specific_code/juce_linux_Files.cpp b/build/linux/platform_specific_code/juce_linux_Files.cpp index f02e298738..4816c44229 100644 --- a/build/linux/platform_specific_code/juce_linux_Files.cpp +++ b/build/linux/platform_specific_code/juce_linux_Files.cpp @@ -352,7 +352,7 @@ struct FindFileStruct // returns 0 on failure void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile, - bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, + bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw() { DIR* d = opendir (directory.toUTF8()); diff --git a/build/linux/platform_specific_code/juce_linux_WebBrowserComponent.cpp b/build/linux/platform_specific_code/juce_linux_WebBrowserComponent.cpp index 0fa0590c9e..d5c7acf9ca 100644 --- a/build/linux/platform_specific_code/juce_linux_WebBrowserComponent.cpp +++ b/build/linux/platform_specific_code/juce_linux_WebBrowserComponent.cpp @@ -53,7 +53,7 @@ WebBrowserComponent::~WebBrowserComponent() } //============================================================================== -void WebBrowserComponent::goToURL (const String& url, +void WebBrowserComponent::goToURL (const String& url, const StringArray* headers, const MemoryBlock* postData) { diff --git a/build/macosx/platform_specific_code/juce_mac_Files.cpp b/build/macosx/platform_specific_code/juce_mac_Files.cpp index 812418c7d4..45b9c997b9 100644 --- a/build/macosx/platform_specific_code/juce_mac_Files.cpp +++ b/build/macosx/platform_specific_code/juce_mac_Files.cpp @@ -633,7 +633,7 @@ struct FindFileStruct // returns 0 on failure void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile, - bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, + bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw() { DIR* const d = opendir (directory.toUTF8()); diff --git a/build/macosx/platform_specific_code/juce_mac_HTTPStream.h b/build/macosx/platform_specific_code/juce_mac_HTTPStream.h index 1630e93f99..220300edd6 100644 --- a/build/macosx/platform_specific_code/juce_mac_HTTPStream.h +++ b/build/macosx/platform_specific_code/juce_mac_HTTPStream.h @@ -142,7 +142,7 @@ public: StringArray lines; lines.addLines (responseHeader); - // NB - using charToString() here instead of just T(" "), because that was + // NB - using charToString() here instead of just T(" "), because that was // causing a mysterious gcc internal compiler error... const int statusCode = responseHeader.fromFirstOccurrenceOf (String::charToString (T(' ')), false, false) .substring (0, 3) @@ -399,4 +399,3 @@ int juce_seekInInternetFile (void* handle, int newPosition) return 0; } - diff --git a/build/win32/platform_specific_code/juce_win32_ASIO.cpp b/build/win32/platform_specific_code/juce_win32_ASIO.cpp index e0ca308694..b2ff61e75a 100644 --- a/build/win32/platform_specific_code/juce_win32_ASIO.cpp +++ b/build/win32/platform_specific_code/juce_win32_ASIO.cpp @@ -1844,7 +1844,7 @@ public: } } - jassert (freeSlot >= 0); // unfortunately you can only have a finite number + jassert (freeSlot >= 0); // unfortunately you can only have a finite number // of ASIO devices open at the same time.. if (freeSlot >= 0) diff --git a/build/win32/platform_specific_code/juce_win32_WebBrowserComponent.cpp b/build/win32/platform_specific_code/juce_win32_WebBrowserComponent.cpp index 84b9863829..b8aabe0871 100644 --- a/build/win32/platform_specific_code/juce_win32_WebBrowserComponent.cpp +++ b/build/win32/platform_specific_code/juce_win32_WebBrowserComponent.cpp @@ -316,7 +316,7 @@ void WebBrowserComponent::checkWindowAssociation() { if (browser != 0 && ! blankPageShown) { - // when the component becomes invisible, some stuff like flash + // when the component becomes invisible, some stuff like flash // carries on playing audio, so we need to force it onto a blank // page to avoid this.. diff --git a/extras/audio plugin host/src/host/FilterGraph.h b/extras/audio plugin host/src/host/FilterGraph.h index 39cff0d9e0..c71c1a7b1b 100644 --- a/extras/audio plugin host/src/host/FilterGraph.h +++ b/extras/audio plugin host/src/host/FilterGraph.h @@ -1,282 +1,282 @@ -/* - ============================================================================== - - 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_FILTERGRAPH_JUCEHEADER__ -#define __JUCE_FILTERGRAPH_JUCEHEADER__ - -class FilterInGraph; -class FilterGraph; - -const char* const filenameSuffix = ".filtergraph"; -const char* const filenameWildcard = "*.filtergraph"; - -//============================================================================== -/** - Represents a connection between two pins in a FilterGraph. -*/ -class FilterConnection -{ -public: - //============================================================================== - FilterConnection (FilterGraph& owner); - FilterConnection (const FilterConnection& other); - ~FilterConnection(); - - //============================================================================== - uint32 sourceFilterID; - int sourceChannel; - uint32 destFilterID; - int destChannel; - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - FilterGraph& owner; - - const FilterConnection& operator= (const FilterConnection&); -}; - - -//============================================================================== -/** - Represents one of the filters in a FilterGraph. -*/ -/*class FilterInGraph : public ReferenceCountedObject -{ -public: - //============================================================================== - FilterInGraph (FilterGraph& owner, AudioPluginInstance* const plugin); - ~FilterInGraph(); - - //============================================================================== - AudioPluginInstance* const filter; - uint32 uid; - - //============================================================================== - void showUI (bool useGenericUI); - - double getX() const throw() { return x; } - double getY() const throw() { return y; } - void setPosition (double x, double y) throw(); - - XmlElement* createXml() const; - - static FilterInGraph* createForDescription (FilterGraph& owner, - const PluginDescription& desc, - String& errorMessage); - - static FilterInGraph* createFromXml (FilterGraph& owner, const XmlElement& xml); - - //============================================================================== - typedef ReferenceCountedObjectPtr Ptr; - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - friend class FilterGraphPlayer; - FilterGraph& owner; - double x, y; - - friend class PluginWindow; - Component* activeUI; - Component* activeGenericUI; - int lastX, lastY; - - MidiBuffer outputMidi; - AudioSampleBuffer processedAudio; - MidiBuffer processedMidi; - - void prepareBuffers (int blockSize); - void renderBlock (int numSamples, - const ReferenceCountedArray & filters, - const OwnedArray & connections); - - FilterInGraph (const FilterInGraph&); - const FilterInGraph& operator= (const FilterInGraph&); -}; -*/ - -//============================================================================== -/** - A collection of filters and some connections between them. -*/ -class FilterGraph : public FileBasedDocument -{ -public: - //============================================================================== - FilterGraph(); - ~FilterGraph(); - - //============================================================================== - AudioProcessorGraph& getGraph() throw() { return graph; } - - int getNumFilters() const throw(); - const AudioProcessorGraph::Node::Ptr getNode (const int index) const throw(); - const AudioProcessorGraph::Node::Ptr getNodeForId (const uint32 uid) const throw(); - - void addFilter (const PluginDescription* desc, double x, double y); - - void removeFilter (const uint32 filterUID); - void disconnectFilter (const uint32 filterUID); - - void removeIllegalConnections(); - - void setNodePosition (const int nodeId, double x, double y); - void getNodePosition (const int nodeId, double& x, double& y) const; - - //============================================================================== - int getNumConnections() const throw(); - const AudioProcessorGraph::Connection* getConnection (const int index) const throw(); - - const AudioProcessorGraph::Connection* getConnectionBetween (uint32 sourceFilterUID, int sourceFilterChannel, - uint32 destFilterUID, int destFilterChannel) const throw(); - - bool canConnect (uint32 sourceFilterUID, int sourceFilterChannel, - uint32 destFilterUID, int destFilterChannel) const throw(); - - bool addConnection (uint32 sourceFilterUID, int sourceFilterChannel, - uint32 destFilterUID, int destFilterChannel); - - void removeConnection (const int index); - - void removeConnection (uint32 sourceFilterUID, int sourceFilterChannel, - uint32 destFilterUID, int destFilterChannel); - - void clear(); - - - //============================================================================== - - XmlElement* createXml() const; - void restoreFromXml (const XmlElement& xml); - - //============================================================================== - const String getDocumentTitle(); - const String loadDocument (const File& file); - const String saveDocument (const File& file); - const File getLastDocumentOpened(); - void setLastDocumentOpened (const File& file); - - /** The special channel index used to refer to a filter's midi channel. - */ - static const int midiChannelNumber; - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - //friend class FilterGraphPlayer; - //ReferenceCountedArray filters; - //OwnedArray connections; - - AudioProcessorGraph graph; - AudioProcessorPlayer player; - - uint32 lastUID; - uint32 getNextUID() throw(); - - void createNodeFromXml (const XmlElement& xml); - - FilterGraph (const FilterGraph&); - const FilterGraph& operator= (const FilterGraph&); -}; - - -//============================================================================== -/** - -*/ -/*class FilterGraphPlayer : public AudioIODeviceCallback, - public MidiInputCallback, - public ChangeListener - -{ -public: - //============================================================================== - FilterGraphPlayer (FilterGraph& graph); - ~FilterGraphPlayer(); - - //============================================================================== - void setAudioDeviceManager (AudioDeviceManager* dm); - AudioDeviceManager* getAudioDeviceManager() const throw() { return deviceManager; } - - //============================================================================== - void audioDeviceIOCallback (const float** inputChannelData, - int totalNumInputChannels, - float** outputChannelData, - int totalNumOutputChannels, - int numSamples); - void audioDeviceAboutToStart (double sampleRate, int numSamplesPerBlock); - void audioDeviceStopped(); - - void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message); - - void changeListenerCallback (void*); - - //============================================================================== - static int compareElements (FilterInGraph* const first, FilterInGraph* const second) throw(); - - const float** inputChannelData; - int totalNumInputChannels; - float** outputChannelData; - int totalNumOutputChannels; - MidiBuffer incomingMidi; - - MidiKeyboardState keyState; - MidiMessageCollector messageCollector; - - //============================================================================== - class PlayerAwareFilter - { - public: - virtual void setPlayer (FilterGraphPlayer* newPlayer) = 0; - }; - -private: - FilterGraph& graph; - CriticalSection processLock; - double sampleRate; - int blockSize; - AudioDeviceManager* deviceManager; - - ReferenceCountedArray filters; - OwnedArray connections; - - void update(); - - FilterGraphPlayer (const FilterGraphPlayer&); - const FilterGraphPlayer& operator= (const FilterGraphPlayer&); -}; -*/ - -#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_FILTERGRAPH_JUCEHEADER__ +#define __JUCE_FILTERGRAPH_JUCEHEADER__ + +class FilterInGraph; +class FilterGraph; + +const char* const filenameSuffix = ".filtergraph"; +const char* const filenameWildcard = "*.filtergraph"; + +//============================================================================== +/** + Represents a connection between two pins in a FilterGraph. +*/ +class FilterConnection +{ +public: + //============================================================================== + FilterConnection (FilterGraph& owner); + FilterConnection (const FilterConnection& other); + ~FilterConnection(); + + //============================================================================== + uint32 sourceFilterID; + int sourceChannel; + uint32 destFilterID; + int destChannel; + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + FilterGraph& owner; + + const FilterConnection& operator= (const FilterConnection&); +}; + + +//============================================================================== +/** + Represents one of the filters in a FilterGraph. +*/ +/*class FilterInGraph : public ReferenceCountedObject +{ +public: + //============================================================================== + FilterInGraph (FilterGraph& owner, AudioPluginInstance* const plugin); + ~FilterInGraph(); + + //============================================================================== + AudioPluginInstance* const filter; + uint32 uid; + + //============================================================================== + void showUI (bool useGenericUI); + + double getX() const throw() { return x; } + double getY() const throw() { return y; } + void setPosition (double x, double y) throw(); + + XmlElement* createXml() const; + + static FilterInGraph* createForDescription (FilterGraph& owner, + const PluginDescription& desc, + String& errorMessage); + + static FilterInGraph* createFromXml (FilterGraph& owner, const XmlElement& xml); + + //============================================================================== + typedef ReferenceCountedObjectPtr Ptr; + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + friend class FilterGraphPlayer; + FilterGraph& owner; + double x, y; + + friend class PluginWindow; + Component* activeUI; + Component* activeGenericUI; + int lastX, lastY; + + MidiBuffer outputMidi; + AudioSampleBuffer processedAudio; + MidiBuffer processedMidi; + + void prepareBuffers (int blockSize); + void renderBlock (int numSamples, + const ReferenceCountedArray & filters, + const OwnedArray & connections); + + FilterInGraph (const FilterInGraph&); + const FilterInGraph& operator= (const FilterInGraph&); +}; +*/ + +//============================================================================== +/** + A collection of filters and some connections between them. +*/ +class FilterGraph : public FileBasedDocument +{ +public: + //============================================================================== + FilterGraph(); + ~FilterGraph(); + + //============================================================================== + AudioProcessorGraph& getGraph() throw() { return graph; } + + int getNumFilters() const throw(); + const AudioProcessorGraph::Node::Ptr getNode (const int index) const throw(); + const AudioProcessorGraph::Node::Ptr getNodeForId (const uint32 uid) const throw(); + + void addFilter (const PluginDescription* desc, double x, double y); + + void removeFilter (const uint32 filterUID); + void disconnectFilter (const uint32 filterUID); + + void removeIllegalConnections(); + + void setNodePosition (const int nodeId, double x, double y); + void getNodePosition (const int nodeId, double& x, double& y) const; + + //============================================================================== + int getNumConnections() const throw(); + const AudioProcessorGraph::Connection* getConnection (const int index) const throw(); + + const AudioProcessorGraph::Connection* getConnectionBetween (uint32 sourceFilterUID, int sourceFilterChannel, + uint32 destFilterUID, int destFilterChannel) const throw(); + + bool canConnect (uint32 sourceFilterUID, int sourceFilterChannel, + uint32 destFilterUID, int destFilterChannel) const throw(); + + bool addConnection (uint32 sourceFilterUID, int sourceFilterChannel, + uint32 destFilterUID, int destFilterChannel); + + void removeConnection (const int index); + + void removeConnection (uint32 sourceFilterUID, int sourceFilterChannel, + uint32 destFilterUID, int destFilterChannel); + + void clear(); + + + //============================================================================== + + XmlElement* createXml() const; + void restoreFromXml (const XmlElement& xml); + + //============================================================================== + const String getDocumentTitle(); + const String loadDocument (const File& file); + const String saveDocument (const File& file); + const File getLastDocumentOpened(); + void setLastDocumentOpened (const File& file); + + /** The special channel index used to refer to a filter's midi channel. + */ + static const int midiChannelNumber; + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + //friend class FilterGraphPlayer; + //ReferenceCountedArray filters; + //OwnedArray connections; + + AudioProcessorGraph graph; + AudioProcessorPlayer player; + + uint32 lastUID; + uint32 getNextUID() throw(); + + void createNodeFromXml (const XmlElement& xml); + + FilterGraph (const FilterGraph&); + const FilterGraph& operator= (const FilterGraph&); +}; + + +//============================================================================== +/** + +*/ +/*class FilterGraphPlayer : public AudioIODeviceCallback, + public MidiInputCallback, + public ChangeListener + +{ +public: + //============================================================================== + FilterGraphPlayer (FilterGraph& graph); + ~FilterGraphPlayer(); + + //============================================================================== + void setAudioDeviceManager (AudioDeviceManager* dm); + AudioDeviceManager* getAudioDeviceManager() const throw() { return deviceManager; } + + //============================================================================== + void audioDeviceIOCallback (const float** inputChannelData, + int totalNumInputChannels, + float** outputChannelData, + int totalNumOutputChannels, + int numSamples); + void audioDeviceAboutToStart (double sampleRate, int numSamplesPerBlock); + void audioDeviceStopped(); + + void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message); + + void changeListenerCallback (void*); + + //============================================================================== + static int compareElements (FilterInGraph* const first, FilterInGraph* const second) throw(); + + const float** inputChannelData; + int totalNumInputChannels; + float** outputChannelData; + int totalNumOutputChannels; + MidiBuffer incomingMidi; + + MidiKeyboardState keyState; + MidiMessageCollector messageCollector; + + //============================================================================== + class PlayerAwareFilter + { + public: + virtual void setPlayer (FilterGraphPlayer* newPlayer) = 0; + }; + +private: + FilterGraph& graph; + CriticalSection processLock; + double sampleRate; + int blockSize; + AudioDeviceManager* deviceManager; + + ReferenceCountedArray filters; + OwnedArray connections; + + void update(); + + FilterGraphPlayer (const FilterGraphPlayer&); + const FilterGraphPlayer& operator= (const FilterGraphPlayer&); +}; +*/ + +#endif diff --git a/extras/audio plugin host/src/juce_AppConfig.h b/extras/audio plugin host/src/juce_AppConfig.h index 9a885f3b51..08968f08e1 100644 --- a/extras/audio plugin host/src/juce_AppConfig.h +++ b/extras/audio plugin host/src/juce_AppConfig.h @@ -30,7 +30,7 @@ */ /* - This file contains settings that you might want to explicitly apply to + This file contains settings that you might want to explicitly apply to the your build. Most of these are turned on or off by default, but you can override diff --git a/extras/audio plugin host/src/juce_LibrarySource.cpp b/extras/audio plugin host/src/juce_LibrarySource.cpp index ab4357598c..6310476300 100644 --- a/extras/audio plugin host/src/juce_LibrarySource.cpp +++ b/extras/audio plugin host/src/juce_LibrarySource.cpp @@ -1,10 +1,10 @@ -/* +/* This file includes the entire juce source tree via the amalgamated file. You could add the amalgamated file directly to your project, but doing it - like this allows you to put your app's config settings in the - juce_AppConfig.h file and have them applied to both the juce headers and + like this allows you to put your app's config settings in the + juce_AppConfig.h file and have them applied to both the juce headers and the source code. */ diff --git a/extras/audio plugins/wrapper/formats/AudioUnit/juce_AudioUnitWrapper.cpp b/extras/audio plugins/wrapper/formats/AudioUnit/juce_AudioUnitWrapper.cpp index d0d1173f42..6c215d4c8a 100644 --- a/extras/audio plugins/wrapper/formats/AudioUnit/juce_AudioUnitWrapper.cpp +++ b/extras/audio plugins/wrapper/formats/AudioUnit/juce_AudioUnitWrapper.cpp @@ -1,1049 +1,1049 @@ -/* - ============================================================================== - - 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_IncludeCharacteristics.h" -#include "../../../../../juce_amalgamated.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 - -//============================================================================== -/** Somewhere in the codebase of your plugin, you need to implement this function - and make it create an instance of the filter subclass that you're building. -*/ -extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); -class JuceAUView; - -//============================================================================== -class JuceAU : public JuceAUBaseClass, - public AudioProcessorListener, - public AudioPlayHead -{ -public: - //============================================================================== - JuceAU (AudioUnit component) -#if JucePlugin_IsSynth - : MusicDeviceBase (component, 0, 1), -#else - : AUMIDIEffectBase (component), -#endif - currentView (0), - 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->setPlayHead (this); - juceFilter->addListener (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*) * 2; - return noErr; - } - else if (inID == kAudioUnitProperty_OfflineRender) - { - outWritable = true; - outDataSize = sizeof (UInt32); - 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)[0] = (void*) juceFilter; - ((void**) outData)[1] = (void*) this; - return noErr; - } - else if (inID == kAudioUnitProperty_OfflineRender) - { - *(UInt32*) outData = (juceFilter != 0 && juceFilter->isNonRealtime()) ? 1 : 0; - return noErr; - } - } - - return JuceAUBaseClass::GetProperty (inID, inScope, inElement, outData); - } - - ComponentResult SetProperty (AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - const void* inData, - UInt32 inDataSize) - { - if (inScope == kAudioUnitScope_Global && inID == kAudioUnitProperty_OfflineRender) - { - if (juceFilter != 0) - juceFilter->setNonRealtime ((*(UInt32*) inData) != 0); - - return noErr; - } - - return JuceAUBaseClass::SetProperty (inID, inScope, inElement, inData, inDataSize); - } - - 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) - { - MemoryBlock state; - juceFilter->getCurrentProgramStateInformation (state); - - if (state.getSize() > 0) - { - CFDataRef ourState = CFDataCreate (kCFAllocatorDefault, (const UInt8*) state.getData(), 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 JUCE_NAMESPACE::uint8* const rawBytes = CFDataGetBytePtr (data); - - if (numBytes > 0) - juceFilter->setCurrentProgramStateInformation (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) - { - *outInfo = channelInfo; - - 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]; - } - } - - 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)); - - // set whether the param is automatable (unnamed parameters aren't allowed to be automated) - if (name.isEmpty() || ! juceFilter->isParameterAutomatable (index)) - outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime; - - AUBase::FillInParameterName (outParameterInfo, - PlatformUtilities::juceStringToCFString (name), - false); - - 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 getCurrentPosition (AudioPlayHead::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 = AudioPlayHead::fps24; - break; - - case kSMPTETimeType25: - info.frameRate = AudioPlayHead::fps25; - break; - - case kSMPTETimeType30Drop: - info.frameRate = AudioPlayHead::fps30drop; - break; - - case kSMPTETimeType30: - info.frameRate = AudioPlayHead::fps30; - break; - - case kSMPTETimeType2997: - info.frameRate = AudioPlayHead::fps2997; - break; - - case kSMPTETimeType2997Drop: - info.frameRate = AudioPlayHead::fps2997drop; - break; - - //case kSMPTETimeType60: - //case kSMPTETimeType5994: - default: - info.frameRate = AudioPlayHead::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); - } - } - - // (can only be called immediately after sendAUEvent) - void sendOldFashionedGestureEvent (const AudioUnitCarbonViewEventID gestureType); - - void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) - { - sendAUEvent (kAudioUnitEvent_ParameterValueChange, index); - } - - void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) - { - sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index); - sendOldFashionedGestureEvent (kAudioUnitCarbonViewEvent_MouseDownInControl); - } - - void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) - { - sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index); - sendOldFashionedGestureEvent (kAudioUnitCarbonViewEvent_MouseUpInControl); - } - - void audioProcessorChanged (AudioProcessor*) - { - // xxx is there an AU equivalent? - } - - bool StreamFormatWritable (AudioUnitScope inScope, AudioUnitElement element) - { - return ! IsInitialized(); - } - - // (these two slightly different versions are because the definition changed between 10.4 and 10.5) - ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID&, UInt32, const MusicDeviceNoteParams&) { return noErr; } - 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 < numOutChans) - memcpy (channels [numInChans], (const float*) buf.mData, sizeof (float) * numSamples); - else - channels [numInChans] = (float*) buf.mData; - - ++numInChans; - } - else - { - // need to de-interleave.. - for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numInChans < numIn; ++subChan) - { - float* dest; - - if (numInChans < numOutChans) - { - dest = channels [numInChans++]; - } - else - { - dest = bufferSpace.getSampleData (nextSpareBufferChan++); - channels [numInChans++] = dest; - } - - 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 JUCE_NAMESPACE::uint8* midiEventData; - int midiEventSize, midiEventPosition; - MidiBuffer::Iterator i (midiEvents); - - while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) - { - jassert (((unsigned int) midiEventPosition) < (unsigned 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 - JUCE_NAMESPACE::uint8 data [4]; - data[0] = nStatus | inChannel; - data[1] = inData1; - data[2] = inData2; - - midiEvents.addEvent (data, 3, inStartFrame); -#endif - - return noErr; - } - - //============================================================================== - ComponentResult GetPresets (CFArrayRef* outData) const - { - if (outData != 0) - { - const int numPrograms = juceFilter->getNumPrograms(); - presetsArray.ensureSize (sizeof (AUPreset) * numPrograms, true); - AUPreset* const presets = (AUPreset*) presetsArray.getData(); - - CFMutableArrayRef presetsArray = CFArrayCreateMutable (0, numPrograms, 0); - - for (int i = 0; i < numPrograms; ++i) - { - presets[i].presetNumber = i; - presets[i].presetName = PlatformUtilities::juceStringToCFString (juceFilter->getProgramName (i)); - - CFArrayAppendValue (presetsArray, presets + i); - } - - *outData = (CFArrayRef) presetsArray; - } - - return noErr; - } - - OSStatus NewFactoryPresetSet (const AUPreset& inNewFactoryPreset) - { - const int numPrograms = juceFilter->getNumPrograms(); - const SInt32 chosenPresetNumber = (int) inNewFactoryPreset.presetNumber; - - if (chosenPresetNumber >= numPrograms) - return kAudioUnitErr_InvalidProperty; - - AUPreset chosenPreset; - chosenPreset.presetNumber = chosenPresetNumber; - chosenPreset.presetName = PlatformUtilities::juceStringToCFString (juceFilter->getProgramName (chosenPresetNumber)); - - juceFilter->setCurrentProgram (chosenPresetNumber); - SetAFactoryPresetAsCurrent (chosenPreset); - - return noErr; - } - - //============================================================================== -public: - JuceAUView* currentView; - -private: - AudioProcessor* juceFilter; - AudioSampleBuffer bufferSpace; - float** channels; - MidiBuffer midiEvents; - bool prepared; - SMPTETime lastSMPTETime; - AUChannelInfo channelInfo [numChannelConfigs]; - AudioUnitEvent auEvent; - mutable MemoryBlock presetsArray; -}; - - -//============================================================================== -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 -{ - AudioProcessor* juceFilter; - AudioProcessorEditor* editorComp; - Component* windowComp; - bool recursive; - int mx, my; - JuceAU* owner; - -public: - JuceAUView (AudioUnitCarbonView auview) - : AUCarbonViewBase (auview), - juceFilter (0), - editorComp (0), - windowComp (0), - recursive (false), - mx (0), - my (0), - owner (0) - { - } - - ~JuceAUView() - { - if (owner->currentView == this) - owner->currentView = 0; - - deleteUI(); - } - - ComponentResult CreateUI (Float32 inXOffset, Float32 inYOffset) - { - if (juceFilter == 0) - { - void* pointers[2]; - UInt32 propertySize = sizeof (pointers); - - AudioUnitGetProperty (GetEditAudioUnit(), - juceFilterObjectPropertyID, - kAudioUnitScope_Global, - 0, - pointers, - &propertySize); - - juceFilter = (AudioProcessor*) pointers[0]; - - owner = (JuceAU*) pointers[1]; - owner->currentView = this; - } - - 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); - } - - AudioUnitCarbonViewEventListener getEventListener() const throw() { return mEventListener; } - void* getEventListenerUserData() const throw() { return mEventListenerUserData; } - -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); - } -}; - -void JuceAU::sendOldFashionedGestureEvent (const AudioUnitCarbonViewEventID gestureType) -{ - if (currentView != 0 && currentView->getEventListener() != 0) - { - (*currentView->getEventListener()) (currentView->getEventListenerUserData(), currentView->GetComponentInstance(), - &(auEvent.mArgument.mParameter), gestureType, 0); - } -} - - -//============================================================================== -#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_IncludeCharacteristics.h" +#include "../../../../../juce_amalgamated.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 + +//============================================================================== +/** Somewhere in the codebase of your plugin, you need to implement this function + and make it create an instance of the filter subclass that you're building. +*/ +extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); +class JuceAUView; + +//============================================================================== +class JuceAU : public JuceAUBaseClass, + public AudioProcessorListener, + public AudioPlayHead +{ +public: + //============================================================================== + JuceAU (AudioUnit component) +#if JucePlugin_IsSynth + : MusicDeviceBase (component, 0, 1), +#else + : AUMIDIEffectBase (component), +#endif + currentView (0), + 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->setPlayHead (this); + juceFilter->addListener (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*) * 2; + return noErr; + } + else if (inID == kAudioUnitProperty_OfflineRender) + { + outWritable = true; + outDataSize = sizeof (UInt32); + 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)[0] = (void*) juceFilter; + ((void**) outData)[1] = (void*) this; + return noErr; + } + else if (inID == kAudioUnitProperty_OfflineRender) + { + *(UInt32*) outData = (juceFilter != 0 && juceFilter->isNonRealtime()) ? 1 : 0; + return noErr; + } + } + + return JuceAUBaseClass::GetProperty (inID, inScope, inElement, outData); + } + + ComponentResult SetProperty (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void* inData, + UInt32 inDataSize) + { + if (inScope == kAudioUnitScope_Global && inID == kAudioUnitProperty_OfflineRender) + { + if (juceFilter != 0) + juceFilter->setNonRealtime ((*(UInt32*) inData) != 0); + + return noErr; + } + + return JuceAUBaseClass::SetProperty (inID, inScope, inElement, inData, inDataSize); + } + + 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) + { + MemoryBlock state; + juceFilter->getCurrentProgramStateInformation (state); + + if (state.getSize() > 0) + { + CFDataRef ourState = CFDataCreate (kCFAllocatorDefault, (const UInt8*) state.getData(), 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 JUCE_NAMESPACE::uint8* const rawBytes = CFDataGetBytePtr (data); + + if (numBytes > 0) + juceFilter->setCurrentProgramStateInformation (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) + { + *outInfo = channelInfo; + + 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]; + } + } + + 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)); + + // set whether the param is automatable (unnamed parameters aren't allowed to be automated) + if (name.isEmpty() || ! juceFilter->isParameterAutomatable (index)) + outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime; + + AUBase::FillInParameterName (outParameterInfo, + PlatformUtilities::juceStringToCFString (name), + false); + + 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 getCurrentPosition (AudioPlayHead::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 = AudioPlayHead::fps24; + break; + + case kSMPTETimeType25: + info.frameRate = AudioPlayHead::fps25; + break; + + case kSMPTETimeType30Drop: + info.frameRate = AudioPlayHead::fps30drop; + break; + + case kSMPTETimeType30: + info.frameRate = AudioPlayHead::fps30; + break; + + case kSMPTETimeType2997: + info.frameRate = AudioPlayHead::fps2997; + break; + + case kSMPTETimeType2997Drop: + info.frameRate = AudioPlayHead::fps2997drop; + break; + + //case kSMPTETimeType60: + //case kSMPTETimeType5994: + default: + info.frameRate = AudioPlayHead::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); + } + } + + // (can only be called immediately after sendAUEvent) + void sendOldFashionedGestureEvent (const AudioUnitCarbonViewEventID gestureType); + + void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) + { + sendAUEvent (kAudioUnitEvent_ParameterValueChange, index); + } + + void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) + { + sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index); + sendOldFashionedGestureEvent (kAudioUnitCarbonViewEvent_MouseDownInControl); + } + + void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) + { + sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index); + sendOldFashionedGestureEvent (kAudioUnitCarbonViewEvent_MouseUpInControl); + } + + void audioProcessorChanged (AudioProcessor*) + { + // xxx is there an AU equivalent? + } + + bool StreamFormatWritable (AudioUnitScope inScope, AudioUnitElement element) + { + return ! IsInitialized(); + } + + // (these two slightly different versions are because the definition changed between 10.4 and 10.5) + ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID&, UInt32, const MusicDeviceNoteParams&) { return noErr; } + 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 < numOutChans) + memcpy (channels [numInChans], (const float*) buf.mData, sizeof (float) * numSamples); + else + channels [numInChans] = (float*) buf.mData; + + ++numInChans; + } + else + { + // need to de-interleave.. + for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numInChans < numIn; ++subChan) + { + float* dest; + + if (numInChans < numOutChans) + { + dest = channels [numInChans++]; + } + else + { + dest = bufferSpace.getSampleData (nextSpareBufferChan++); + channels [numInChans++] = dest; + } + + 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 JUCE_NAMESPACE::uint8* midiEventData; + int midiEventSize, midiEventPosition; + MidiBuffer::Iterator i (midiEvents); + + while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) + { + jassert (((unsigned int) midiEventPosition) < (unsigned 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 + JUCE_NAMESPACE::uint8 data [4]; + data[0] = nStatus | inChannel; + data[1] = inData1; + data[2] = inData2; + + midiEvents.addEvent (data, 3, inStartFrame); +#endif + + return noErr; + } + + //============================================================================== + ComponentResult GetPresets (CFArrayRef* outData) const + { + if (outData != 0) + { + const int numPrograms = juceFilter->getNumPrograms(); + presetsArray.ensureSize (sizeof (AUPreset) * numPrograms, true); + AUPreset* const presets = (AUPreset*) presetsArray.getData(); + + CFMutableArrayRef presetsArray = CFArrayCreateMutable (0, numPrograms, 0); + + for (int i = 0; i < numPrograms; ++i) + { + presets[i].presetNumber = i; + presets[i].presetName = PlatformUtilities::juceStringToCFString (juceFilter->getProgramName (i)); + + CFArrayAppendValue (presetsArray, presets + i); + } + + *outData = (CFArrayRef) presetsArray; + } + + return noErr; + } + + OSStatus NewFactoryPresetSet (const AUPreset& inNewFactoryPreset) + { + const int numPrograms = juceFilter->getNumPrograms(); + const SInt32 chosenPresetNumber = (int) inNewFactoryPreset.presetNumber; + + if (chosenPresetNumber >= numPrograms) + return kAudioUnitErr_InvalidProperty; + + AUPreset chosenPreset; + chosenPreset.presetNumber = chosenPresetNumber; + chosenPreset.presetName = PlatformUtilities::juceStringToCFString (juceFilter->getProgramName (chosenPresetNumber)); + + juceFilter->setCurrentProgram (chosenPresetNumber); + SetAFactoryPresetAsCurrent (chosenPreset); + + return noErr; + } + + //============================================================================== +public: + JuceAUView* currentView; + +private: + AudioProcessor* juceFilter; + AudioSampleBuffer bufferSpace; + float** channels; + MidiBuffer midiEvents; + bool prepared; + SMPTETime lastSMPTETime; + AUChannelInfo channelInfo [numChannelConfigs]; + AudioUnitEvent auEvent; + mutable MemoryBlock presetsArray; +}; + + +//============================================================================== +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 +{ + AudioProcessor* juceFilter; + AudioProcessorEditor* editorComp; + Component* windowComp; + bool recursive; + int mx, my; + JuceAU* owner; + +public: + JuceAUView (AudioUnitCarbonView auview) + : AUCarbonViewBase (auview), + juceFilter (0), + editorComp (0), + windowComp (0), + recursive (false), + mx (0), + my (0), + owner (0) + { + } + + ~JuceAUView() + { + if (owner->currentView == this) + owner->currentView = 0; + + deleteUI(); + } + + ComponentResult CreateUI (Float32 inXOffset, Float32 inYOffset) + { + if (juceFilter == 0) + { + void* pointers[2]; + UInt32 propertySize = sizeof (pointers); + + AudioUnitGetProperty (GetEditAudioUnit(), + juceFilterObjectPropertyID, + kAudioUnitScope_Global, + 0, + pointers, + &propertySize); + + juceFilter = (AudioProcessor*) pointers[0]; + + owner = (JuceAU*) pointers[1]; + owner->currentView = this; + } + + 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); + } + + AudioUnitCarbonViewEventListener getEventListener() const throw() { return mEventListener; } + void* getEventListenerUserData() const throw() { return mEventListenerUserData; } + +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); + } +}; + +void JuceAU::sendOldFashionedGestureEvent (const AudioUnitCarbonViewEventID gestureType) +{ + if (currentView != 0 && currentView->getEventListener() != 0) + { + (*currentView->getEventListener()) (currentView->getEventListenerUserData(), currentView->GetComponentInstance(), + &(auEvent.mArgument.mParameter), gestureType, 0); + } +} + + +//============================================================================== +#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) diff --git a/extras/juce demo/src/BinaryData.cpp b/extras/juce demo/src/BinaryData.cpp index bcf27d0548..311073f2bb 100644 --- a/extras/juce demo/src/BinaryData.cpp +++ b/extras/juce demo/src/BinaryData.cpp @@ -7969,4 +7969,3 @@ static const unsigned char temp17[] = {47,42,13,10,32,32,61,61,61,61,61,61,61,61 111,109,109,97,110,100,77,97,110,97,103,101,114,41,13,10,123,13,10,32,32,32,32,114,101,116,117,114,110,32,110,101,119,32,87,105,100,103,101,116, 115,68,101,109,111,32,40,99,111,109,109,97,110,100,77,97,110,97,103,101,114,41,59,13,10,125,13,10,0,0}; const char* BinaryData::widgetsdemo_cpp = (const char*) temp17; - diff --git a/extras/juce demo/src/binarydata/QuickTimeDemo.cpp b/extras/juce demo/src/binarydata/QuickTimeDemo.cpp index f157c06663..3ad78aefce 100644 --- a/extras/juce demo/src/binarydata/QuickTimeDemo.cpp +++ b/extras/juce demo/src/binarydata/QuickTimeDemo.cpp @@ -1,129 +1,129 @@ -/* - ============================================================================== - - 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 "../jucedemo_headers.h" - -#if JUCE_QUICKTIME && ! JUCE_LINUX - -//============================================================================== -// so that we can easily have two QT windows each with a file browser, wrap this up as a class.. -class QuickTimeWindowWithFileBrowser : public Component, - public FilenameComponentListener -{ -public: - QuickTimeWindowWithFileBrowser() - { - addAndMakeVisible (qtComp = new QuickTimeMovieComponent()); - - // and a file-chooser.. - addAndMakeVisible (fileChooser = new FilenameComponent (T("movie"), - File::nonexistent, - true, false, false, - T("*.*"), - String::empty, - T("(choose a video file to play)"))); - fileChooser->addListener (this); - fileChooser->setBrowseButtonText (T("browse")); - } - - ~QuickTimeWindowWithFileBrowser() - { - deleteAllChildren(); - } - - void resized() - { - qtComp->setBounds (0, 0, getWidth(), getHeight() - 30); - fileChooser->setBounds (0, getHeight() - 24, getWidth(), 24); - } - - void filenameComponentChanged (FilenameComponent*) - { - // this is called when the user changes the filename in the file chooser box - if (qtComp->loadMovie (fileChooser->getCurrentFile(), true)) - { - // loaded the file ok, so let's start it playing.. - - qtComp->play(); - } - else - { - AlertWindow::showMessageBox (AlertWindow::WarningIcon, - T("Couldn't load the file!"), - T("Sorry, QuickTime didn't manage to load that file!")); - } - } - -private: - QuickTimeMovieComponent* qtComp; - FilenameComponent* fileChooser; -}; - - -//============================================================================== -class QuickTimeDemo : public Component -{ -public: - //============================================================================== - QuickTimeDemo() - { - setName (T("QuickTime")); - - // add a movie component.. - addAndMakeVisible (qtComp1 = new QuickTimeWindowWithFileBrowser()); - addAndMakeVisible (qtComp2 = new QuickTimeWindowWithFileBrowser()); - } - - ~QuickTimeDemo() - { - deleteAllChildren(); - } - - void resized() - { - qtComp1->setBoundsRelative (0.05f, 0.05f, 0.425f, 0.9f); - qtComp2->setBoundsRelative (0.525f, 0.05f, 0.425f, 0.9f); - } - -private: - //============================================================================== - QuickTimeWindowWithFileBrowser* qtComp1; - QuickTimeWindowWithFileBrowser* qtComp2; -}; - - -//============================================================================== -Component* createQuickTimeDemo() -{ - return new QuickTimeDemo(); -} - -#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. + + ============================================================================== +*/ + +#include "../jucedemo_headers.h" + +#if JUCE_QUICKTIME && ! JUCE_LINUX + +//============================================================================== +// so that we can easily have two QT windows each with a file browser, wrap this up as a class.. +class QuickTimeWindowWithFileBrowser : public Component, + public FilenameComponentListener +{ +public: + QuickTimeWindowWithFileBrowser() + { + addAndMakeVisible (qtComp = new QuickTimeMovieComponent()); + + // and a file-chooser.. + addAndMakeVisible (fileChooser = new FilenameComponent (T("movie"), + File::nonexistent, + true, false, false, + T("*.*"), + String::empty, + T("(choose a video file to play)"))); + fileChooser->addListener (this); + fileChooser->setBrowseButtonText (T("browse")); + } + + ~QuickTimeWindowWithFileBrowser() + { + deleteAllChildren(); + } + + void resized() + { + qtComp->setBounds (0, 0, getWidth(), getHeight() - 30); + fileChooser->setBounds (0, getHeight() - 24, getWidth(), 24); + } + + void filenameComponentChanged (FilenameComponent*) + { + // this is called when the user changes the filename in the file chooser box + if (qtComp->loadMovie (fileChooser->getCurrentFile(), true)) + { + // loaded the file ok, so let's start it playing.. + + qtComp->play(); + } + else + { + AlertWindow::showMessageBox (AlertWindow::WarningIcon, + T("Couldn't load the file!"), + T("Sorry, QuickTime didn't manage to load that file!")); + } + } + +private: + QuickTimeMovieComponent* qtComp; + FilenameComponent* fileChooser; +}; + + +//============================================================================== +class QuickTimeDemo : public Component +{ +public: + //============================================================================== + QuickTimeDemo() + { + setName (T("QuickTime")); + + // add a movie component.. + addAndMakeVisible (qtComp1 = new QuickTimeWindowWithFileBrowser()); + addAndMakeVisible (qtComp2 = new QuickTimeWindowWithFileBrowser()); + } + + ~QuickTimeDemo() + { + deleteAllChildren(); + } + + void resized() + { + qtComp1->setBoundsRelative (0.05f, 0.05f, 0.425f, 0.9f); + qtComp2->setBoundsRelative (0.525f, 0.05f, 0.425f, 0.9f); + } + +private: + //============================================================================== + QuickTimeWindowWithFileBrowser* qtComp1; + QuickTimeWindowWithFileBrowser* qtComp2; +}; + + +//============================================================================== +Component* createQuickTimeDemo() +{ + return new QuickTimeDemo(); +} + +#endif diff --git a/extras/juce demo/src/demos/QuickTimeDemo.cpp b/extras/juce demo/src/demos/QuickTimeDemo.cpp index f157c06663..3ad78aefce 100644 --- a/extras/juce demo/src/demos/QuickTimeDemo.cpp +++ b/extras/juce demo/src/demos/QuickTimeDemo.cpp @@ -1,129 +1,129 @@ -/* - ============================================================================== - - 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 "../jucedemo_headers.h" - -#if JUCE_QUICKTIME && ! JUCE_LINUX - -//============================================================================== -// so that we can easily have two QT windows each with a file browser, wrap this up as a class.. -class QuickTimeWindowWithFileBrowser : public Component, - public FilenameComponentListener -{ -public: - QuickTimeWindowWithFileBrowser() - { - addAndMakeVisible (qtComp = new QuickTimeMovieComponent()); - - // and a file-chooser.. - addAndMakeVisible (fileChooser = new FilenameComponent (T("movie"), - File::nonexistent, - true, false, false, - T("*.*"), - String::empty, - T("(choose a video file to play)"))); - fileChooser->addListener (this); - fileChooser->setBrowseButtonText (T("browse")); - } - - ~QuickTimeWindowWithFileBrowser() - { - deleteAllChildren(); - } - - void resized() - { - qtComp->setBounds (0, 0, getWidth(), getHeight() - 30); - fileChooser->setBounds (0, getHeight() - 24, getWidth(), 24); - } - - void filenameComponentChanged (FilenameComponent*) - { - // this is called when the user changes the filename in the file chooser box - if (qtComp->loadMovie (fileChooser->getCurrentFile(), true)) - { - // loaded the file ok, so let's start it playing.. - - qtComp->play(); - } - else - { - AlertWindow::showMessageBox (AlertWindow::WarningIcon, - T("Couldn't load the file!"), - T("Sorry, QuickTime didn't manage to load that file!")); - } - } - -private: - QuickTimeMovieComponent* qtComp; - FilenameComponent* fileChooser; -}; - - -//============================================================================== -class QuickTimeDemo : public Component -{ -public: - //============================================================================== - QuickTimeDemo() - { - setName (T("QuickTime")); - - // add a movie component.. - addAndMakeVisible (qtComp1 = new QuickTimeWindowWithFileBrowser()); - addAndMakeVisible (qtComp2 = new QuickTimeWindowWithFileBrowser()); - } - - ~QuickTimeDemo() - { - deleteAllChildren(); - } - - void resized() - { - qtComp1->setBoundsRelative (0.05f, 0.05f, 0.425f, 0.9f); - qtComp2->setBoundsRelative (0.525f, 0.05f, 0.425f, 0.9f); - } - -private: - //============================================================================== - QuickTimeWindowWithFileBrowser* qtComp1; - QuickTimeWindowWithFileBrowser* qtComp2; -}; - - -//============================================================================== -Component* createQuickTimeDemo() -{ - return new QuickTimeDemo(); -} - -#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. + + ============================================================================== +*/ + +#include "../jucedemo_headers.h" + +#if JUCE_QUICKTIME && ! JUCE_LINUX + +//============================================================================== +// so that we can easily have two QT windows each with a file browser, wrap this up as a class.. +class QuickTimeWindowWithFileBrowser : public Component, + public FilenameComponentListener +{ +public: + QuickTimeWindowWithFileBrowser() + { + addAndMakeVisible (qtComp = new QuickTimeMovieComponent()); + + // and a file-chooser.. + addAndMakeVisible (fileChooser = new FilenameComponent (T("movie"), + File::nonexistent, + true, false, false, + T("*.*"), + String::empty, + T("(choose a video file to play)"))); + fileChooser->addListener (this); + fileChooser->setBrowseButtonText (T("browse")); + } + + ~QuickTimeWindowWithFileBrowser() + { + deleteAllChildren(); + } + + void resized() + { + qtComp->setBounds (0, 0, getWidth(), getHeight() - 30); + fileChooser->setBounds (0, getHeight() - 24, getWidth(), 24); + } + + void filenameComponentChanged (FilenameComponent*) + { + // this is called when the user changes the filename in the file chooser box + if (qtComp->loadMovie (fileChooser->getCurrentFile(), true)) + { + // loaded the file ok, so let's start it playing.. + + qtComp->play(); + } + else + { + AlertWindow::showMessageBox (AlertWindow::WarningIcon, + T("Couldn't load the file!"), + T("Sorry, QuickTime didn't manage to load that file!")); + } + } + +private: + QuickTimeMovieComponent* qtComp; + FilenameComponent* fileChooser; +}; + + +//============================================================================== +class QuickTimeDemo : public Component +{ +public: + //============================================================================== + QuickTimeDemo() + { + setName (T("QuickTime")); + + // add a movie component.. + addAndMakeVisible (qtComp1 = new QuickTimeWindowWithFileBrowser()); + addAndMakeVisible (qtComp2 = new QuickTimeWindowWithFileBrowser()); + } + + ~QuickTimeDemo() + { + deleteAllChildren(); + } + + void resized() + { + qtComp1->setBoundsRelative (0.05f, 0.05f, 0.425f, 0.9f); + qtComp2->setBoundsRelative (0.525f, 0.05f, 0.425f, 0.9f); + } + +private: + //============================================================================== + QuickTimeWindowWithFileBrowser* qtComp1; + QuickTimeWindowWithFileBrowser* qtComp2; +}; + + +//============================================================================== +Component* createQuickTimeDemo() +{ + return new QuickTimeDemo(); +} + +#endif diff --git a/extras/juce demo/src/juce_AppConfig.h b/extras/juce demo/src/juce_AppConfig.h index bda0dbc8df..00ed78cd97 100644 --- a/extras/juce demo/src/juce_AppConfig.h +++ b/extras/juce demo/src/juce_AppConfig.h @@ -30,7 +30,7 @@ */ /* - This file contains settings that you might want to explicitly apply to + This file contains settings that you might want to explicitly apply to the your build. Most of these are turned on or off by default, but you can override diff --git a/extras/juce demo/src/juce_LibrarySource.cpp b/extras/juce demo/src/juce_LibrarySource.cpp index ab4357598c..6310476300 100644 --- a/extras/juce demo/src/juce_LibrarySource.cpp +++ b/extras/juce demo/src/juce_LibrarySource.cpp @@ -1,10 +1,10 @@ -/* +/* This file includes the entire juce source tree via the amalgamated file. You could add the amalgamated file directly to your project, but doing it - like this allows you to put your app's config settings in the - juce_AppConfig.h file and have them applied to both the juce headers and + like this allows you to put your app's config settings in the + juce_AppConfig.h file and have them applied to both the juce headers and the source code. */ diff --git a/extras/the jucer/src/BinaryData.cpp b/extras/the jucer/src/BinaryData.cpp index c08fddd03e..1279f531a8 100644 --- a/extras/the jucer/src/BinaryData.cpp +++ b/extras/the jucer/src/BinaryData.cpp @@ -911,4 +911,3 @@ static const unsigned char temp4[] = {137,80,78,71,13,10,26,10,0,0,0,13,73,72,68 0,98,28,9,155,95,0,2,104,68,236,11,1,8,160,17,225,73,128,0,3,0,120,52,172,151,198,78,252,63,0,0,0,0,73,69,78,68,174,66, 96,130,0,0}; const char* BinaryData::prefs_misc_png = (const char*) temp4; - diff --git a/extras/the jucer/src/juce_AppConfig.h b/extras/the jucer/src/juce_AppConfig.h index bda0dbc8df..00ed78cd97 100644 --- a/extras/the jucer/src/juce_AppConfig.h +++ b/extras/the jucer/src/juce_AppConfig.h @@ -30,7 +30,7 @@ */ /* - This file contains settings that you might want to explicitly apply to + This file contains settings that you might want to explicitly apply to the your build. Most of these are turned on or off by default, but you can override diff --git a/extras/the jucer/src/juce_LibrarySource.cpp b/extras/the jucer/src/juce_LibrarySource.cpp index ab4357598c..6310476300 100644 --- a/extras/the jucer/src/juce_LibrarySource.cpp +++ b/extras/the jucer/src/juce_LibrarySource.cpp @@ -1,10 +1,10 @@ -/* +/* This file includes the entire juce source tree via the amalgamated file. You could add the amalgamated file directly to your project, but doing it - like this allows you to put your app's config settings in the - juce_AppConfig.h file and have them applied to both the juce headers and + like this allows you to put your app's config settings in the + juce_AppConfig.h file and have them applied to both the juce headers and the source code. */ diff --git a/extras/the jucer/src/utility/jucer_UtilityFunctions.cpp b/extras/the jucer/src/utility/jucer_UtilityFunctions.cpp index 01ce031dfb..1170eedfff 100644 --- a/extras/the jucer/src/utility/jucer_UtilityFunctions.cpp +++ b/extras/the jucer/src/utility/jucer_UtilityFunctions.cpp @@ -362,7 +362,7 @@ void positionToCode (const RelativePositionedRectangle& position, positionToCode (ComponentTypeHandler::getComponentPosition (relCompW), layout, wrx, wry, wrw, wrh); String hrx, hry, hrw, hrh; - Component* const relCompH = (layout != 0 && position.rect.getHeightMode() != PositionedRectangle::absoluteSize) + Component* const relCompH = (layout != 0 && position.rect.getHeightMode() != PositionedRectangle::absoluteSize) ? layout->findComponentWithId (position.relativeToH) : 0; if (relCompH != 0) positionToCode (ComponentTypeHandler::getComponentPosition (relCompH), layout, hrx, hry, hrw, hrh); diff --git a/src/juce_amalgamated_template.cpp b/src/juce_amalgamated_template.cpp index c5fdf60b14..6283939b86 100644 --- a/src/juce_amalgamated_template.cpp +++ b/src/juce_amalgamated_template.cpp @@ -32,7 +32,7 @@ /* This monolithic file contains the entire Juce source tree! - To build an app which uses Juce, all you need to do is to add this + To build an app which uses Juce, all you need to do is to add this file to your project, and include juce.h in your own cpp files. */ @@ -343,7 +343,7 @@ #endif //============================================================================== -// some files include lots of library code, so leave them to the end to avoid cluttering +// some files include lots of library code, so leave them to the end to avoid cluttering // up the build for the clean files. #include "juce_core/io/streams/juce_GZIPCompressorOutputStream.cpp" #include "juce_core/io/streams/juce_GZIPDecompressorInputStream.cpp" diff --git a/src/juce_amalgamated_template.h b/src/juce_amalgamated_template.h index 69b0e155e6..1111dd565c 100644 --- a/src/juce_amalgamated_template.h +++ b/src/juce_amalgamated_template.h @@ -29,11 +29,10 @@ ============================================================================== */ - /* ============================================================================== - This header contains the entire Juce source tree, and can be #included in + This header contains the entire Juce source tree, and can be #included in all your source files. As well as including this in your files, you should also add juce_inline.cpp @@ -43,11 +42,11 @@ ============================================================================== */ -#ifndef __ALL_JUCE_HEADERS_H__ -#define __ALL_JUCE_HEADERS_H__ +#ifndef __JUCE_AMALGAMATED_TEMPLATE_JUCEHEADER__ +#define __JUCE_AMALGAMATED_TEMPLATE_JUCEHEADER__ #define DONT_AUTOLINK_TO_JUCE_LIBRARY 1 #include "../juce.h" -#endif +#endif // __JUCE_AMALGAMATED_TEMPLATE_JUCEHEADER__ diff --git a/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp b/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp index b3d884e59f..9e9af852d0 100644 --- a/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp +++ b/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp @@ -97,7 +97,7 @@ public: return; #elif JUCE_MAC EnterMoviesOnThread (0); -#endif +#endif if (EnterMovies() != noErr) return; diff --git a/src/juce_appframework/audio/audio_sources/juce_AudioSourcePlayer.cpp b/src/juce_appframework/audio/audio_sources/juce_AudioSourcePlayer.cpp index 2d36a6922a..b6025d6495 100644 --- a/src/juce_appframework/audio/audio_sources/juce_AudioSourcePlayer.cpp +++ b/src/juce_appframework/audio/audio_sources/juce_AudioSourcePlayer.cpp @@ -43,7 +43,7 @@ AudioSourcePlayer::AudioSourcePlayer() sampleRate (0), bufferSize (0), tempBuffer (2, 8), - lastGain (1.0f), + lastGain (1.0f), gain (1.0f) { } diff --git a/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp b/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp index b608bebe0c..fd0e1be538 100644 --- a/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp +++ b/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp @@ -458,7 +458,7 @@ void AudioDeviceManager::updateXml() for (int i = 0; i < midiInsFromXml.size(); ++i) { - if (! availableMidiDevices.contains (midiInsFromXml[i], true)) + if (! availableMidiDevices.contains (midiInsFromXml[i], true)) { XmlElement* const m = new XmlElement (T("MIDIINPUT")); m->setAttribute (T("name"), midiInsFromXml[i]); diff --git a/src/juce_appframework/audio/devices/juce_AudioIODevice.h b/src/juce_appframework/audio/devices/juce_AudioIODevice.h index b70b9ee4c0..00a5fc05f6 100644 --- a/src/juce_appframework/audio/devices/juce_AudioIODevice.h +++ b/src/juce_appframework/audio/devices/juce_AudioIODevice.h @@ -68,21 +68,21 @@ public: @param inputChannelData a set of arrays containing the audio data for each incoming channel - this data is valid until the function - returns. There will be one channel of data for each input + returns. There will be one channel of data for each input channel that was enabled when the audio device was opened (see AudioIODevice::open()) - @param numInputChannels the number of pointers to channel data in the + @param numInputChannels the number of pointers to channel data in the inputChannelData array. @param outputChannelData a set of arrays which need to be filled with the data that should be sent to each outgoing channel of the device. There will be one channel of data for each output channel - that was enabled when the audio device was opened (see + that was enabled when the audio device was opened (see AudioIODevice::open()) The initial contents of the array is undefined, so the callback function must fill all the channels with zeros if its output is silence. Failing to do this could cause quite an unpleasant noise! - @param numOutputChannels the number of pointers to channel data in the + @param numOutputChannels the number of pointers to channel data in the outputChannelData array. @param numSamples the number of samples in each channel of the input and output arrays. The number of samples will depend on the diff --git a/src/juce_appframework/audio/processors/juce_AudioProcessorGraph.cpp b/src/juce_appframework/audio/processors/juce_AudioProcessorGraph.cpp index e29b878939..3dbb44fd43 100644 --- a/src/juce_appframework/audio/processors/juce_AudioProcessorGraph.cpp +++ b/src/juce_appframework/audio/processors/juce_AudioProcessorGraph.cpp @@ -1,1358 +1,1358 @@ -/* - ============================================================================== - - 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 "../../../juce_core/basics/juce_StandardHeader.h" - -BEGIN_JUCE_NAMESPACE - -#include "juce_AudioProcessorGraph.h" -#include "../../events/juce_MessageManager.h" - - -const int AudioProcessorGraph::midiChannelIndex = 0x1000; - -//============================================================================== -AudioProcessorGraph::Node::Node (const uint32 id_, - AudioProcessor* const processor_) throw() - : id (id_), - processor (processor_), - isPrepared (false) -{ - jassert (processor_ != 0); -} - -AudioProcessorGraph::Node::~Node() -{ - delete processor; -} - -void AudioProcessorGraph::Node::prepare (const double sampleRate, const int blockSize, - AudioProcessorGraph* const graph) -{ - if (! isPrepared) - { - isPrepared = true; - - AudioProcessorGraph::AudioGraphIOProcessor* const ioProc - = dynamic_cast (processor); - - if (ioProc != 0) - ioProc->setParentGraph (graph); - - processor->setPlayConfigDetails (processor->getNumInputChannels(), - processor->getNumOutputChannels(), - sampleRate, blockSize); - - processor->prepareToPlay (sampleRate, blockSize); - } -} - -void AudioProcessorGraph::Node::unprepare() -{ - if (isPrepared) - { - isPrepared = false; - processor->releaseResources(); - } -} - -//============================================================================== -AudioProcessorGraph::AudioProcessorGraph() - : lastNodeId (0), - renderingBuffers (1, 1), - currentAudioOutputBuffer (1, 1) -{ -} - -AudioProcessorGraph::~AudioProcessorGraph() -{ - clearRenderingSequence(); - clear(); -} - -const String AudioProcessorGraph::getName() const -{ - return "Audio Graph"; -} - -//============================================================================== -void AudioProcessorGraph::clear() -{ - nodes.clear(); - connections.clear(); - triggerAsyncUpdate(); -} - -AudioProcessorGraph::Node* AudioProcessorGraph::getNodeForId (const uint32 nodeId) const throw() -{ - for (int i = nodes.size(); --i >= 0;) - if (nodes.getUnchecked(i)->id == nodeId) - return nodes.getUnchecked(i); - - return 0; -} - -AudioProcessorGraph::Node* AudioProcessorGraph::addNode (AudioProcessor* const newProcessor, - uint32 nodeId) -{ - if (newProcessor == 0) - { - jassertfalse - return 0; - } - - if (nodeId == 0) - { - nodeId = ++lastNodeId; - } - else - { - // you can't add a node with an id that already exists in the graph.. - jassert (getNodeForId (nodeId) == 0); - removeNode (nodeId); - } - - lastNodeId = nodeId; - - Node* const n = new Node (nodeId, newProcessor); - nodes.add (n); - triggerAsyncUpdate(); - - AudioProcessorGraph::AudioGraphIOProcessor* const ioProc - = dynamic_cast (n->processor); - - if (ioProc != 0) - ioProc->setParentGraph (this); - - return n; -} - -bool AudioProcessorGraph::removeNode (const uint32 nodeId) -{ - disconnectNode (nodeId); - - for (int i = nodes.size(); --i >= 0;) - { - if (nodes.getUnchecked(i)->id == nodeId) - { - AudioProcessorGraph::AudioGraphIOProcessor* const ioProc - = dynamic_cast (nodes.getUnchecked(i)->processor); - - if (ioProc != 0) - ioProc->setParentGraph (0); - - nodes.remove (i); - triggerAsyncUpdate(); - - return true; - } - } - - return false; -} - -//============================================================================== -const AudioProcessorGraph::Connection* AudioProcessorGraph::getConnectionBetween (const uint32 sourceNodeId, - const int sourceChannelIndex, - const uint32 destNodeId, - const int destChannelIndex) const throw() -{ - for (int i = connections.size(); --i >= 0;) - { - const Connection* const c = connections.getUnchecked(i); - - if (c->sourceNodeId == sourceNodeId - && c->destNodeId == destNodeId - && c->sourceChannelIndex == sourceChannelIndex - && c->destChannelIndex == destChannelIndex) - { - return c; - } - } - - return 0; -} - -bool AudioProcessorGraph::isConnected (const uint32 possibleSourceNodeId, - const uint32 possibleDestNodeId) const throw() -{ - for (int i = connections.size(); --i >= 0;) - { - const Connection* const c = connections.getUnchecked(i); - - if (c->sourceNodeId == possibleSourceNodeId - && c->destNodeId == possibleDestNodeId) - { - return true; - } - } - - return false; -} - -bool AudioProcessorGraph::canConnect (const uint32 sourceNodeId, - const int sourceChannelIndex, - const uint32 destNodeId, - const int destChannelIndex) const throw() -{ - if (sourceChannelIndex < 0 - || destChannelIndex < 0 - || sourceNodeId == destNodeId - || (destChannelIndex == midiChannelIndex) != (sourceChannelIndex == midiChannelIndex)) - return false; - - const Node* const source = getNodeForId (sourceNodeId); - - if (source == 0 - || (sourceChannelIndex != midiChannelIndex && sourceChannelIndex >= source->processor->getNumOutputChannels()) - || (sourceChannelIndex == midiChannelIndex && ! source->processor->producesMidi())) - return false; - - const Node* const dest = getNodeForId (destNodeId); - - if (dest == 0 - || (destChannelIndex != midiChannelIndex && destChannelIndex >= dest->processor->getNumInputChannels()) - || (destChannelIndex == midiChannelIndex && ! dest->processor->acceptsMidi())) - return false; - - return getConnectionBetween (sourceNodeId, sourceChannelIndex, - destNodeId, destChannelIndex) == 0; -} - -bool AudioProcessorGraph::addConnection (const uint32 sourceNodeId, - const int sourceChannelIndex, - const uint32 destNodeId, - const int destChannelIndex) -{ - if (! canConnect (sourceNodeId, sourceChannelIndex, destNodeId, destChannelIndex)) - return false; - - Connection* const c = new Connection(); - c->sourceNodeId = sourceNodeId; - c->sourceChannelIndex = sourceChannelIndex; - c->destNodeId = destNodeId; - c->destChannelIndex = destChannelIndex; - - connections.add (c); - triggerAsyncUpdate(); - - return true; -} - -void AudioProcessorGraph::removeConnection (const int index) -{ - connections.remove (index); - triggerAsyncUpdate(); -} - -bool AudioProcessorGraph::removeConnection (const uint32 sourceNodeId, const int sourceChannelIndex, - const uint32 destNodeId, const int destChannelIndex) -{ - bool doneAnything = false; - - for (int i = connections.size(); --i >= 0;) - { - const Connection* const c = connections.getUnchecked(i); - - if (c->sourceNodeId == sourceNodeId - && c->destNodeId == destNodeId - && c->sourceChannelIndex == sourceChannelIndex - && c->destChannelIndex == destChannelIndex) - { - removeConnection (i); - doneAnything = true; - triggerAsyncUpdate(); - } - } - - return doneAnything; -} - -bool AudioProcessorGraph::disconnectNode (const uint32 nodeId) -{ - bool doneAnything = false; - - for (int i = connections.size(); --i >= 0;) - { - const Connection* const c = connections.getUnchecked(i); - - if (c->sourceNodeId == nodeId || c->destNodeId == nodeId) - { - removeConnection (i); - doneAnything = true; - triggerAsyncUpdate(); - } - } - - return doneAnything; -} - -bool AudioProcessorGraph::removeIllegalConnections() -{ - bool doneAnything = false; - - for (int i = connections.size(); --i >= 0;) - { - const Connection* const c = connections.getUnchecked(i); - - const Node* const source = getNodeForId (c->sourceNodeId); - const Node* const dest = getNodeForId (c->destNodeId); - - if (source == 0 || dest == 0 - || (c->sourceChannelIndex != midiChannelIndex - && (((unsigned int) c->sourceChannelIndex) >= (unsigned int) source->processor->getNumOutputChannels())) - || (c->sourceChannelIndex == midiChannelIndex - && ! source->processor->producesMidi()) - || (c->destChannelIndex != midiChannelIndex - && (((unsigned int) c->destChannelIndex) >= (unsigned int) dest->processor->getNumInputChannels())) - || (c->destChannelIndex == midiChannelIndex - && ! dest->processor->acceptsMidi())) - { - removeConnection (i); - doneAnything = true; - triggerAsyncUpdate(); - } - } - - return doneAnything; -} - -//============================================================================== -namespace GraphRenderingOps -{ - -//============================================================================== -class AudioGraphRenderingOp -{ -public: - AudioGraphRenderingOp() throw() {} - virtual ~AudioGraphRenderingOp() throw() {} - - virtual void perform (AudioSampleBuffer& sharedBufferChans, - const OwnedArray & sharedMidiBuffers, - const int numSamples) throw() = 0; - - juce_UseDebuggingNewOperator -}; - -//============================================================================== -class ClearChannelOp : public AudioGraphRenderingOp -{ -public: - ClearChannelOp (const int channelNum_) throw() - : channelNum (channelNum_) - {} - - ~ClearChannelOp() throw() {} - - void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray &, const int numSamples) throw() - { - sharedBufferChans.clear (channelNum, 0, numSamples); - } - -private: - const int channelNum; - - ClearChannelOp (const ClearChannelOp&); - const ClearChannelOp& operator= (const ClearChannelOp&); -}; - -//============================================================================== -class CopyChannelOp : public AudioGraphRenderingOp -{ -public: - CopyChannelOp (const int srcChannelNum_, const int dstChannelNum_) throw() - : srcChannelNum (srcChannelNum_), - dstChannelNum (dstChannelNum_) - {} - - ~CopyChannelOp() throw() {} - - void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray &, const int numSamples) throw() - { - sharedBufferChans.copyFrom (dstChannelNum, 0, sharedBufferChans, srcChannelNum, 0, numSamples); - } - -private: - const int srcChannelNum, dstChannelNum; - - CopyChannelOp (const CopyChannelOp&); - const CopyChannelOp& operator= (const CopyChannelOp&); -}; - -//============================================================================== -class AddChannelOp : public AudioGraphRenderingOp -{ -public: - AddChannelOp (const int srcChannelNum_, const int dstChannelNum_) throw() - : srcChannelNum (srcChannelNum_), - dstChannelNum (dstChannelNum_) - {} - - ~AddChannelOp() throw() {} - - void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray &, const int numSamples) throw() - { - sharedBufferChans.addFrom (dstChannelNum, 0, sharedBufferChans, srcChannelNum, 0, numSamples); - } - -private: - const int srcChannelNum, dstChannelNum; - - AddChannelOp (const AddChannelOp&); - const AddChannelOp& operator= (const AddChannelOp&); -}; - -//============================================================================== -class ClearMidiBufferOp : public AudioGraphRenderingOp -{ -public: - ClearMidiBufferOp (const int bufferNum_) throw() - : bufferNum (bufferNum_) - {} - - ~ClearMidiBufferOp() throw() {} - - void perform (AudioSampleBuffer&, const OwnedArray & sharedMidiBuffers, const int) throw() - { - sharedMidiBuffers.getUnchecked (bufferNum)->clear(); - } - -private: - const int bufferNum; - - ClearMidiBufferOp (const ClearMidiBufferOp&); - const ClearMidiBufferOp& operator= (const ClearMidiBufferOp&); -}; - -//============================================================================== -class CopyMidiBufferOp : public AudioGraphRenderingOp -{ -public: - CopyMidiBufferOp (const int srcBufferNum_, const int dstBufferNum_) throw() - : srcBufferNum (srcBufferNum_), - dstBufferNum (dstBufferNum_) - {} - - ~CopyMidiBufferOp() throw() {} - - void perform (AudioSampleBuffer&, const OwnedArray & sharedMidiBuffers, const int) throw() - { - *sharedMidiBuffers.getUnchecked (dstBufferNum) = *sharedMidiBuffers.getUnchecked (srcBufferNum); - } - -private: - const int srcBufferNum, dstBufferNum; - - CopyMidiBufferOp (const CopyMidiBufferOp&); - const CopyMidiBufferOp& operator= (const CopyMidiBufferOp&); -}; - -//============================================================================== -class AddMidiBufferOp : public AudioGraphRenderingOp -{ -public: - AddMidiBufferOp (const int srcBufferNum_, const int dstBufferNum_) throw() - : srcBufferNum (srcBufferNum_), - dstBufferNum (dstBufferNum_) - {} - - ~AddMidiBufferOp() throw() {} - - void perform (AudioSampleBuffer&, const OwnedArray & sharedMidiBuffers, const int numSamples) throw() - { - sharedMidiBuffers.getUnchecked (dstBufferNum) - ->addEvents (*sharedMidiBuffers.getUnchecked (srcBufferNum), 0, numSamples, 0); - } - -private: - const int srcBufferNum, dstBufferNum; - - AddMidiBufferOp (const AddMidiBufferOp&); - const AddMidiBufferOp& operator= (const AddMidiBufferOp&); -}; - -//============================================================================== -class ProcessBufferOp : public AudioGraphRenderingOp -{ -public: - ProcessBufferOp (const AudioProcessorGraph::Node::Ptr& node_, - const Array & audioChannelsToUse_, - const int totalChans_, - const int midiBufferToUse_) throw() - : node (node_), - processor (node_->processor), - audioChannelsToUse (audioChannelsToUse_), - totalChans (totalChans_), - midiBufferToUse (midiBufferToUse_) - { - channels = (float**) juce_calloc (sizeof (float*) * totalChans_); - } - - ~ProcessBufferOp() throw() - { - juce_free (channels); - } - - void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray & sharedMidiBuffers, const int numSamples) throw() - { - for (int i = totalChans; --i >= 0;) - channels[i] = sharedBufferChans.getSampleData (audioChannelsToUse.getUnchecked (i), 0); - - AudioSampleBuffer buffer (channels, totalChans, numSamples); - - processor->processBlock (buffer, *sharedMidiBuffers.getUnchecked (midiBufferToUse)); - } - - const AudioProcessorGraph::Node::Ptr node; - AudioProcessor* const processor; - -private: - Array audioChannelsToUse; - float** channels; - int totalChans; - int midiBufferToUse; - - ProcessBufferOp (const ProcessBufferOp&); - const ProcessBufferOp& operator= (const ProcessBufferOp&); -}; - -//============================================================================== -/** Used to calculate the correct sequence of rendering ops needed, based on - the best re-use of shared buffers at each stage. -*/ -class RenderingOpSequenceCalculator -{ -public: - //============================================================================== - RenderingOpSequenceCalculator (AudioProcessorGraph& graph_, - const VoidArray& orderedNodes_, - VoidArray& renderingOps) - : graph (graph_), - orderedNodes (orderedNodes_) - { - nodeIds.add (-2); // first buffer is read-only zeros - channels.add (0); - - midiNodeIds.add (-2); - - for (int i = 0; i < orderedNodes.size(); ++i) - { - createRenderingOpsForNode ((AudioProcessorGraph::Node*) orderedNodes.getUnchecked(i), - renderingOps, i); - - markAnyUnusedBuffersAsFree (i); - } - } - - int getNumBuffersNeeded() const throw() { return nodeIds.size(); } - - int getNumMidiBuffersNeeded() const throw() { return midiNodeIds.size(); } - - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - AudioProcessorGraph& graph; - const VoidArray& orderedNodes; - Array nodeIds, channels, midiNodeIds; - - //============================================================================== - void createRenderingOpsForNode (AudioProcessorGraph::Node* const node, - VoidArray& renderingOps, - const int ourRenderingIndex) - { - const int numIns = node->processor->getNumInputChannels(); - const int numOuts = node->processor->getNumOutputChannels(); - const int totalChans = jmax (numIns, numOuts); - - Array audioChannelsToUse; - int midiBufferToUse = -1; - - for (int inputChan = 0; inputChan < numIns; ++inputChan) - { - // get a list of all the inputs to this node - Array sourceNodes, sourceOutputChans; - - for (int i = graph.getNumConnections(); --i >= 0;) - { - const AudioProcessorGraph::Connection* const c = graph.getConnection (i); - - if (c->destNodeId == node->id && c->destChannelIndex == inputChan) - { - sourceNodes.add (c->sourceNodeId); - sourceOutputChans.add (c->sourceChannelIndex); - } - } - - int bufIndex = -1; - - if (sourceNodes.size() == 0) - { - // unconnected input channel - - if (inputChan >= numOuts) - { - bufIndex = getReadOnlyEmptyBuffer(); - jassert (bufIndex >= 0); - } - else - { - bufIndex = getFreeBuffer (false); - renderingOps.add (new ClearChannelOp (bufIndex)); - } - } - else if (sourceNodes.size() == 1) - { - // channel with a straightforward single input.. - const int srcNode = sourceNodes.getUnchecked(0); - const int srcChan = sourceOutputChans.getUnchecked(0); - - bufIndex = getBufferContaining (srcNode, srcChan); - - if (bufIndex < 0) - { - // if not found, this is probably a feedback loop - bufIndex = getReadOnlyEmptyBuffer(); - jassert (bufIndex >= 0); - } - - if (inputChan < numOuts - && isBufferNeededLater (ourRenderingIndex, - inputChan, - srcNode, srcChan)) - { - // can't mess up this channel because it's needed later by another node, so we - // need to use a copy of it.. - const int newFreeBuffer = getFreeBuffer (false); - - renderingOps.add (new CopyChannelOp (bufIndex, newFreeBuffer)); - - bufIndex = newFreeBuffer; - } - } - else - { - // channel with a mix of several inputs.. - - // try to find a re-usable channel from our inputs.. - int reusableInputIndex = -1; - - for (int i = 0; i < sourceNodes.size(); ++i) - { - const int sourceBufIndex = getBufferContaining (sourceNodes.getUnchecked(i), - sourceOutputChans.getUnchecked(i)); - - if (sourceBufIndex >= 0 - && ! isBufferNeededLater (ourRenderingIndex, - inputChan, - sourceNodes.getUnchecked(i), - sourceOutputChans.getUnchecked(i))) - { - // we've found one of our input chans that can be re-used.. - reusableInputIndex = i; - bufIndex = sourceBufIndex; - break; - } - } - - if (reusableInputIndex < 0) - { - // can't re-use any of our input chans, so get a new one and copy everything into it.. - bufIndex = getFreeBuffer (false); - jassert (bufIndex != 0); - - const int srcIndex = getBufferContaining (sourceNodes.getUnchecked (0), - sourceOutputChans.getUnchecked (0)); - if (srcIndex < 0) - { - // if not found, this is probably a feedback loop - renderingOps.add (new ClearChannelOp (bufIndex)); - } - else - { - renderingOps.add (new CopyChannelOp (srcIndex, bufIndex)); - } - - reusableInputIndex = 0; - } - - for (int j = 0; j < sourceNodes.size(); ++j) - { - if (j != reusableInputIndex) - { - const int srcIndex = getBufferContaining (sourceNodes.getUnchecked(j), - sourceOutputChans.getUnchecked(j)); - if (srcIndex >= 0) - renderingOps.add (new AddChannelOp (srcIndex, bufIndex)); - } - } - } - - jassert (bufIndex >= 0); - audioChannelsToUse.add (bufIndex); - - if (inputChan < numOuts) - markBufferAsContaining (bufIndex, node->id, inputChan); - } - - for (int outputChan = numIns; outputChan < numOuts; ++outputChan) - { - const int bufIndex = getFreeBuffer (false); - jassert (bufIndex != 0); - audioChannelsToUse.add (bufIndex); - - markBufferAsContaining (bufIndex, node->id, outputChan); - } - - // Now the same thing for midi.. - Array midiSourceNodes; - - for (int i = graph.getNumConnections(); --i >= 0;) - { - const AudioProcessorGraph::Connection* const c = graph.getConnection (i); - - if (c->destNodeId == node->id && c->destChannelIndex == AudioProcessorGraph::midiChannelIndex) - midiSourceNodes.add (c->sourceNodeId); - } - - if (midiSourceNodes.size() == 0) - { - // No midi inputs.. - midiBufferToUse = getFreeBuffer (true); // need to pick a buffer even if the processor doesn't use midi - - if (node->processor->acceptsMidi() || node->processor->producesMidi()) - renderingOps.add (new ClearMidiBufferOp (midiBufferToUse)); - } - else if (midiSourceNodes.size() == 1) - { - // One midi input.. - midiBufferToUse = getBufferContaining (midiSourceNodes.getUnchecked(0), - AudioProcessorGraph::midiChannelIndex); - - if (midiBufferToUse >= 0) - { - if (isBufferNeededLater (ourRenderingIndex, - AudioProcessorGraph::midiChannelIndex, - midiSourceNodes.getUnchecked(0), - AudioProcessorGraph::midiChannelIndex)) - { - // can't mess up this channel because it's needed later by another node, so we - // need to use a copy of it.. - const int newFreeBuffer = getFreeBuffer (true); - renderingOps.add (new CopyMidiBufferOp (midiBufferToUse, newFreeBuffer)); - midiBufferToUse = newFreeBuffer; - } - } - else - { - // probably a feedback loop, so just use an empty one.. - midiBufferToUse = getFreeBuffer (true); // need to pick a buffer even if the processor doesn't use midi - } - } - else - { - // More than one midi input being mixed.. - int reusableInputIndex = -1; - - for (int i = 0; i < midiSourceNodes.size(); ++i) - { - const int sourceBufIndex = getBufferContaining (midiSourceNodes.getUnchecked(i), - AudioProcessorGraph::midiChannelIndex); - - if (sourceBufIndex >= 0 - && ! isBufferNeededLater (ourRenderingIndex, - AudioProcessorGraph::midiChannelIndex, - midiSourceNodes.getUnchecked(i), - AudioProcessorGraph::midiChannelIndex)) - { - // we've found one of our input buffers that can be re-used.. - reusableInputIndex = i; - midiBufferToUse = sourceBufIndex; - break; - } - } - - if (reusableInputIndex < 0) - { - // can't re-use any of our input buffers, so get a new one and copy everything into it.. - midiBufferToUse = getFreeBuffer (true); - jassert (midiBufferToUse >= 0); - - const int srcIndex = getBufferContaining (midiSourceNodes.getUnchecked(0), - AudioProcessorGraph::midiChannelIndex); - if (srcIndex >= 0) - renderingOps.add (new CopyMidiBufferOp (srcIndex, midiBufferToUse)); - else - renderingOps.add (new ClearMidiBufferOp (midiBufferToUse)); - - reusableInputIndex = 0; - } - - for (int j = 0; j < midiSourceNodes.size(); ++j) - { - if (j != reusableInputIndex) - { - const int srcIndex = getBufferContaining (midiSourceNodes.getUnchecked(j), - AudioProcessorGraph::midiChannelIndex); - if (srcIndex >= 0) - renderingOps.add (new AddMidiBufferOp (srcIndex, midiBufferToUse)); - } - } - } - - if (node->processor->producesMidi()) - markBufferAsContaining (midiBufferToUse, node->id, - AudioProcessorGraph::midiChannelIndex); - - renderingOps.add (new ProcessBufferOp (node, audioChannelsToUse, - totalChans, midiBufferToUse)); - } - - //============================================================================== - int getFreeBuffer (const bool forMidi) - { - if (forMidi) - { - for (int i = 1; i < midiNodeIds.size(); ++i) - if (midiNodeIds.getUnchecked(i) < 0) - return i; - - midiNodeIds.add (-1); - return midiNodeIds.size() - 1; - } - else - { - for (int i = 1; i < nodeIds.size(); ++i) - if (nodeIds.getUnchecked(i) < 0) - return i; - - nodeIds.add (-1); - channels.add (0); - return nodeIds.size() - 1; - } - } - - int getReadOnlyEmptyBuffer() const throw() - { - return 0; - } - - int getBufferContaining (const int nodeId, const int outputChannel) const throw() - { - if (outputChannel == AudioProcessorGraph::midiChannelIndex) - { - for (int i = midiNodeIds.size(); --i >= 0;) - if (midiNodeIds.getUnchecked(i) == nodeId) - return i; - } - else - { - for (int i = nodeIds.size(); --i >= 0;) - if (nodeIds.getUnchecked(i) == nodeId - && channels.getUnchecked(i) == outputChannel) - return i; - } - - return -1; - } - - void markAnyUnusedBuffersAsFree (const int stepIndex) - { - int i; - for (i = 0; i < nodeIds.size(); ++i) - { - if (nodeIds.getUnchecked(i) >= 0 - && ! isBufferNeededLater (stepIndex, -1, - nodeIds.getUnchecked(i), - channels.getUnchecked(i))) - { - nodeIds.set (i, -1); - } - } - - for (i = 0; i < midiNodeIds.size(); ++i) - { - if (midiNodeIds.getUnchecked(i) >= 0 - && ! isBufferNeededLater (stepIndex, -1, - midiNodeIds.getUnchecked(i), - AudioProcessorGraph::midiChannelIndex)) - { - midiNodeIds.set (i, -1); - } - } - } - - bool isBufferNeededLater (int stepIndexToSearchFrom, - int inputChannelOfIndexToIgnore, - const int nodeId, - const int outputChanIndex) const throw() - { - while (stepIndexToSearchFrom < orderedNodes.size()) - { - const AudioProcessorGraph::Node* const node = (const AudioProcessorGraph::Node*) orderedNodes.getUnchecked (stepIndexToSearchFrom); - - if (outputChanIndex == AudioProcessorGraph::midiChannelIndex) - { - if (inputChannelOfIndexToIgnore != AudioProcessorGraph::midiChannelIndex - && graph.getConnectionBetween (nodeId, AudioProcessorGraph::midiChannelIndex, - node->id, AudioProcessorGraph::midiChannelIndex) != 0) - return true; - } - else - { - for (int i = 0; i < node->processor->getNumInputChannels(); ++i) - if (i != inputChannelOfIndexToIgnore - && graph.getConnectionBetween (nodeId, outputChanIndex, - node->id, i) != 0) - return true; - } - - inputChannelOfIndexToIgnore = -1; - ++stepIndexToSearchFrom; - } - - return false; - } - - void markBufferAsContaining (int bufferNum, int nodeId, int outputIndex) - { - if (outputIndex == AudioProcessorGraph::midiChannelIndex) - { - jassert (bufferNum > 0 && bufferNum < midiNodeIds.size()); - - midiNodeIds.set (bufferNum, nodeId); - } - else - { - jassert (bufferNum > 0 && bufferNum < nodeIds.size()); - - nodeIds.set (bufferNum, nodeId); - channels.set (bufferNum, outputIndex); - } - } - - RenderingOpSequenceCalculator (const RenderingOpSequenceCalculator&); - const RenderingOpSequenceCalculator& operator= (const RenderingOpSequenceCalculator&); -}; - -} - -//============================================================================== -void AudioProcessorGraph::clearRenderingSequence() -{ - const ScopedLock sl (renderLock); - - for (int i = renderingOps.size(); --i >= 0;) - { - GraphRenderingOps::AudioGraphRenderingOp* const r - = (GraphRenderingOps::AudioGraphRenderingOp*) renderingOps.getUnchecked(i); - - renderingOps.remove (i); - delete r; - } -} - -bool AudioProcessorGraph::isAnInputTo (const uint32 possibleInputId, - const uint32 possibleDestinationId, - const int recursionCheck) const throw() -{ - if (recursionCheck > 0) - { - for (int i = connections.size(); --i >= 0;) - { - const AudioProcessorGraph::Connection* const c = connections.getUnchecked (i); - - if (c->destNodeId == possibleDestinationId - && (c->sourceNodeId == possibleInputId - || isAnInputTo (possibleInputId, c->sourceNodeId, recursionCheck - 1))) - return true; - } - } - - return false; -} - -void AudioProcessorGraph::buildRenderingSequence() -{ - VoidArray newRenderingOps; - int numRenderingBuffersNeeded = 2; - int numMidiBuffersNeeded = 1; - - { - MessageManagerLock mml; - - VoidArray orderedNodes; - - int i; - for (i = 0; i < nodes.size(); ++i) - { - Node* const node = nodes.getUnchecked(i); - - node->prepare (getSampleRate(), getBlockSize(), this); - - int j = 0; - for (; j < orderedNodes.size(); ++j) - if (isAnInputTo (node->id, - ((Node*) orderedNodes.getUnchecked (j))->id, - nodes.size() + 1)) - break; - - orderedNodes.insert (j, node); - } - - GraphRenderingOps::RenderingOpSequenceCalculator calculator (*this, orderedNodes, newRenderingOps); - - numRenderingBuffersNeeded = calculator.getNumBuffersNeeded(); - numMidiBuffersNeeded = calculator.getNumMidiBuffersNeeded(); - } - - VoidArray oldRenderingOps (renderingOps); - - { - // swap over to the new set of rendering sequence.. - const ScopedLock sl (renderLock); - - renderingBuffers.setSize (numRenderingBuffersNeeded, getBlockSize()); - renderingBuffers.clear(); - - for (int i = midiBuffers.size(); --i >= 0;) - midiBuffers.getUnchecked(i)->clear(); - - while (midiBuffers.size() < numMidiBuffersNeeded) - midiBuffers.add (new MidiBuffer()); - - renderingOps = newRenderingOps; - } - - for (int i = oldRenderingOps.size(); --i >= 0;) - delete (GraphRenderingOps::AudioGraphRenderingOp*) oldRenderingOps.getUnchecked(i); -} - -void AudioProcessorGraph::handleAsyncUpdate() -{ - buildRenderingSequence(); -} - -//============================================================================== -void AudioProcessorGraph::prepareToPlay (double /*sampleRate*/, int estimatedSamplesPerBlock) -{ - currentAudioInputBuffer = 0; - currentAudioOutputBuffer.setSize (getNumOutputChannels(), estimatedSamplesPerBlock); - currentMidiInputBuffer = 0; - currentMidiOutputBuffer.clear(); - - clearRenderingSequence(); - buildRenderingSequence(); -} - -void AudioProcessorGraph::releaseResources() -{ - for (int i = 0; i < nodes.size(); ++i) - nodes.getUnchecked(i)->unprepare(); - - renderingBuffers.setSize (1, 1); - midiBuffers.clear(); - - currentAudioInputBuffer = 0; - currentAudioOutputBuffer.setSize (1, 1); - currentMidiInputBuffer = 0; - currentMidiOutputBuffer.clear(); -} - -void AudioProcessorGraph::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) -{ - const int numSamples = buffer.getNumSamples(); - - const ScopedLock sl (renderLock); - - currentAudioInputBuffer = &buffer; - currentAudioOutputBuffer.setSize (buffer.getNumChannels(), numSamples); - currentAudioOutputBuffer.clear(); - currentMidiInputBuffer = &midiMessages; - currentMidiOutputBuffer.clear(); - - for (int i = 0; i < renderingOps.size(); ++i) - { - GraphRenderingOps::AudioGraphRenderingOp* const op - = (GraphRenderingOps::AudioGraphRenderingOp*) renderingOps.getUnchecked(i); - - op->perform (renderingBuffers, midiBuffers, numSamples); - } - - for (int i = 0; i < buffer.getNumChannels(); ++i) - buffer.copyFrom (i, 0, currentAudioOutputBuffer, i, 0, numSamples); -} - -const String AudioProcessorGraph::getInputChannelName (const int channelIndex) const -{ - return "Input " + String (channelIndex + 1); -} - -const String AudioProcessorGraph::getOutputChannelName (const int channelIndex) const -{ - return "Output " + String (channelIndex + 1); -} - -bool AudioProcessorGraph::isInputChannelStereoPair (int /*index*/) const -{ - return true; -} - -bool AudioProcessorGraph::isOutputChannelStereoPair (int /*index*/) const -{ - return true; -} - -bool AudioProcessorGraph::acceptsMidi() const -{ - return true; -} - -bool AudioProcessorGraph::producesMidi() const -{ - return true; -} - -void AudioProcessorGraph::getStateInformation (JUCE_NAMESPACE::MemoryBlock& /*destData*/) -{ -} - -void AudioProcessorGraph::setStateInformation (const void* /*data*/, int /*sizeInBytes*/) -{ -} - - -//============================================================================== -AudioProcessorGraph::AudioGraphIOProcessor::AudioGraphIOProcessor (const IODeviceType type_) - : type (type_), - graph (0) -{ -} - -AudioProcessorGraph::AudioGraphIOProcessor::~AudioGraphIOProcessor() -{ -} - -const String AudioProcessorGraph::AudioGraphIOProcessor::getName() const -{ - switch (type) - { - case audioOutputNode: - return "Audio Output"; - case audioInputNode: - return "Audio Input"; - case midiOutputNode: - return "Midi Output"; - case midiInputNode: - return "Midi Input"; - default: - break; - } - - return String::empty; -} - -void AudioProcessorGraph::AudioGraphIOProcessor::fillInPluginDescription (PluginDescription& d) const -{ - d.name = getName(); - d.uid = d.name.hashCode(); - d.category = "I/O devices"; - d.pluginFormatName = "Internal"; - d.manufacturerName = "Raw Material Software"; - d.version = "1.0"; - d.isInstrument = false; - - d.numInputChannels = getNumInputChannels(); - if (type == audioOutputNode && graph != 0) - d.numInputChannels = graph->getNumInputChannels(); - - d.numOutputChannels = getNumOutputChannels(); - if (type == audioInputNode && graph != 0) - d.numOutputChannels = graph->getNumOutputChannels(); -} - -void AudioProcessorGraph::AudioGraphIOProcessor::prepareToPlay (double, int) -{ - jassert (graph != 0); -} - -void AudioProcessorGraph::AudioGraphIOProcessor::releaseResources() -{ -} - -void AudioProcessorGraph::AudioGraphIOProcessor::processBlock (AudioSampleBuffer& buffer, - MidiBuffer& midiMessages) -{ - jassert (graph != 0); - - switch (type) - { - case audioOutputNode: - { - for (int i = jmin (graph->currentAudioOutputBuffer.getNumChannels(), - buffer.getNumChannels()); --i >= 0;) - { - graph->currentAudioOutputBuffer.addFrom (i, 0, buffer, i, 0, buffer.getNumSamples()); - } - - break; - } - - case audioInputNode: - { - for (int i = jmin (graph->currentAudioInputBuffer->getNumChannels(), - buffer.getNumChannels()); --i >= 0;) - { - buffer.addFrom (i, 0, *graph->currentAudioInputBuffer, i, 0, buffer.getNumSamples()); - } - - break; - } - - case midiOutputNode: - graph->currentMidiOutputBuffer.addEvents (midiMessages, 0, buffer.getNumSamples(), 0); - break; - - case midiInputNode: - midiMessages.addEvents (*graph->currentMidiInputBuffer, 0, buffer.getNumSamples(), 0); - break; - - default: - break; - } -} - -bool AudioProcessorGraph::AudioGraphIOProcessor::acceptsMidi() const -{ - return type == midiOutputNode; -} - -bool AudioProcessorGraph::AudioGraphIOProcessor::producesMidi() const -{ - return type == midiInputNode; -} - -const String AudioProcessorGraph::AudioGraphIOProcessor::getInputChannelName (const int channelIndex) const -{ - switch (type) - { - case audioOutputNode: - return "Output " + String (channelIndex + 1); - case midiOutputNode: - return "Midi Output"; - default: - break; - } - - return String::empty; -} - -const String AudioProcessorGraph::AudioGraphIOProcessor::getOutputChannelName (const int channelIndex) const -{ - switch (type) - { - case audioInputNode: - return "Input " + String (channelIndex + 1); - case midiInputNode: - return "Midi Input"; - default: - break; - } - - return String::empty; -} - -bool AudioProcessorGraph::AudioGraphIOProcessor::isInputChannelStereoPair (int /*index*/) const -{ - return type == audioInputNode || type == audioOutputNode; -} - -bool AudioProcessorGraph::AudioGraphIOProcessor::isOutputChannelStereoPair (int index) const -{ - return isInputChannelStereoPair (index); -} - -bool AudioProcessorGraph::AudioGraphIOProcessor::isInput() const throw() -{ - return type == audioInputNode || type == midiInputNode; -} - -bool AudioProcessorGraph::AudioGraphIOProcessor::isOutput() const throw() -{ - return type == audioOutputNode || type == midiOutputNode; -} - -AudioProcessorEditor* AudioProcessorGraph::AudioGraphIOProcessor::createEditor() -{ - return 0; -} - -int AudioProcessorGraph::AudioGraphIOProcessor::getNumParameters() { return 0; } -const String AudioProcessorGraph::AudioGraphIOProcessor::getParameterName (int) { return String::empty; } - -float AudioProcessorGraph::AudioGraphIOProcessor::getParameter (int) { return 0.0f; } -const String AudioProcessorGraph::AudioGraphIOProcessor::getParameterText (int) { return String::empty; } -void AudioProcessorGraph::AudioGraphIOProcessor::setParameter (int, float) { } - -int AudioProcessorGraph::AudioGraphIOProcessor::getNumPrograms() { return 0; } -int AudioProcessorGraph::AudioGraphIOProcessor::getCurrentProgram() { return 0; } -void AudioProcessorGraph::AudioGraphIOProcessor::setCurrentProgram (int) { } - -const String AudioProcessorGraph::AudioGraphIOProcessor::getProgramName (int) { return String::empty; } -void AudioProcessorGraph::AudioGraphIOProcessor::changeProgramName (int, const String&) { } - -void AudioProcessorGraph::AudioGraphIOProcessor::getStateInformation (JUCE_NAMESPACE::MemoryBlock&) -{ -} - -void AudioProcessorGraph::AudioGraphIOProcessor::setStateInformation (const void*, int) -{ -} - -void AudioProcessorGraph::AudioGraphIOProcessor::setParentGraph (AudioProcessorGraph* const newGraph) throw() -{ - graph = newGraph; - - if (graph != 0) - { - setPlayConfigDetails (type == audioOutputNode ? graph->getNumInputChannels() : 0, - type == audioInputNode ? graph->getNumOutputChannels() : 0, - getSampleRate(), - getBlockSize()); - - updateHostDisplay(); - } -} - - -END_JUCE_NAMESPACE +/* + ============================================================================== + + 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 "../../../juce_core/basics/juce_StandardHeader.h" + +BEGIN_JUCE_NAMESPACE + +#include "juce_AudioProcessorGraph.h" +#include "../../events/juce_MessageManager.h" + + +const int AudioProcessorGraph::midiChannelIndex = 0x1000; + +//============================================================================== +AudioProcessorGraph::Node::Node (const uint32 id_, + AudioProcessor* const processor_) throw() + : id (id_), + processor (processor_), + isPrepared (false) +{ + jassert (processor_ != 0); +} + +AudioProcessorGraph::Node::~Node() +{ + delete processor; +} + +void AudioProcessorGraph::Node::prepare (const double sampleRate, const int blockSize, + AudioProcessorGraph* const graph) +{ + if (! isPrepared) + { + isPrepared = true; + + AudioProcessorGraph::AudioGraphIOProcessor* const ioProc + = dynamic_cast (processor); + + if (ioProc != 0) + ioProc->setParentGraph (graph); + + processor->setPlayConfigDetails (processor->getNumInputChannels(), + processor->getNumOutputChannels(), + sampleRate, blockSize); + + processor->prepareToPlay (sampleRate, blockSize); + } +} + +void AudioProcessorGraph::Node::unprepare() +{ + if (isPrepared) + { + isPrepared = false; + processor->releaseResources(); + } +} + +//============================================================================== +AudioProcessorGraph::AudioProcessorGraph() + : lastNodeId (0), + renderingBuffers (1, 1), + currentAudioOutputBuffer (1, 1) +{ +} + +AudioProcessorGraph::~AudioProcessorGraph() +{ + clearRenderingSequence(); + clear(); +} + +const String AudioProcessorGraph::getName() const +{ + return "Audio Graph"; +} + +//============================================================================== +void AudioProcessorGraph::clear() +{ + nodes.clear(); + connections.clear(); + triggerAsyncUpdate(); +} + +AudioProcessorGraph::Node* AudioProcessorGraph::getNodeForId (const uint32 nodeId) const throw() +{ + for (int i = nodes.size(); --i >= 0;) + if (nodes.getUnchecked(i)->id == nodeId) + return nodes.getUnchecked(i); + + return 0; +} + +AudioProcessorGraph::Node* AudioProcessorGraph::addNode (AudioProcessor* const newProcessor, + uint32 nodeId) +{ + if (newProcessor == 0) + { + jassertfalse + return 0; + } + + if (nodeId == 0) + { + nodeId = ++lastNodeId; + } + else + { + // you can't add a node with an id that already exists in the graph.. + jassert (getNodeForId (nodeId) == 0); + removeNode (nodeId); + } + + lastNodeId = nodeId; + + Node* const n = new Node (nodeId, newProcessor); + nodes.add (n); + triggerAsyncUpdate(); + + AudioProcessorGraph::AudioGraphIOProcessor* const ioProc + = dynamic_cast (n->processor); + + if (ioProc != 0) + ioProc->setParentGraph (this); + + return n; +} + +bool AudioProcessorGraph::removeNode (const uint32 nodeId) +{ + disconnectNode (nodeId); + + for (int i = nodes.size(); --i >= 0;) + { + if (nodes.getUnchecked(i)->id == nodeId) + { + AudioProcessorGraph::AudioGraphIOProcessor* const ioProc + = dynamic_cast (nodes.getUnchecked(i)->processor); + + if (ioProc != 0) + ioProc->setParentGraph (0); + + nodes.remove (i); + triggerAsyncUpdate(); + + return true; + } + } + + return false; +} + +//============================================================================== +const AudioProcessorGraph::Connection* AudioProcessorGraph::getConnectionBetween (const uint32 sourceNodeId, + const int sourceChannelIndex, + const uint32 destNodeId, + const int destChannelIndex) const throw() +{ + for (int i = connections.size(); --i >= 0;) + { + const Connection* const c = connections.getUnchecked(i); + + if (c->sourceNodeId == sourceNodeId + && c->destNodeId == destNodeId + && c->sourceChannelIndex == sourceChannelIndex + && c->destChannelIndex == destChannelIndex) + { + return c; + } + } + + return 0; +} + +bool AudioProcessorGraph::isConnected (const uint32 possibleSourceNodeId, + const uint32 possibleDestNodeId) const throw() +{ + for (int i = connections.size(); --i >= 0;) + { + const Connection* const c = connections.getUnchecked(i); + + if (c->sourceNodeId == possibleSourceNodeId + && c->destNodeId == possibleDestNodeId) + { + return true; + } + } + + return false; +} + +bool AudioProcessorGraph::canConnect (const uint32 sourceNodeId, + const int sourceChannelIndex, + const uint32 destNodeId, + const int destChannelIndex) const throw() +{ + if (sourceChannelIndex < 0 + || destChannelIndex < 0 + || sourceNodeId == destNodeId + || (destChannelIndex == midiChannelIndex) != (sourceChannelIndex == midiChannelIndex)) + return false; + + const Node* const source = getNodeForId (sourceNodeId); + + if (source == 0 + || (sourceChannelIndex != midiChannelIndex && sourceChannelIndex >= source->processor->getNumOutputChannels()) + || (sourceChannelIndex == midiChannelIndex && ! source->processor->producesMidi())) + return false; + + const Node* const dest = getNodeForId (destNodeId); + + if (dest == 0 + || (destChannelIndex != midiChannelIndex && destChannelIndex >= dest->processor->getNumInputChannels()) + || (destChannelIndex == midiChannelIndex && ! dest->processor->acceptsMidi())) + return false; + + return getConnectionBetween (sourceNodeId, sourceChannelIndex, + destNodeId, destChannelIndex) == 0; +} + +bool AudioProcessorGraph::addConnection (const uint32 sourceNodeId, + const int sourceChannelIndex, + const uint32 destNodeId, + const int destChannelIndex) +{ + if (! canConnect (sourceNodeId, sourceChannelIndex, destNodeId, destChannelIndex)) + return false; + + Connection* const c = new Connection(); + c->sourceNodeId = sourceNodeId; + c->sourceChannelIndex = sourceChannelIndex; + c->destNodeId = destNodeId; + c->destChannelIndex = destChannelIndex; + + connections.add (c); + triggerAsyncUpdate(); + + return true; +} + +void AudioProcessorGraph::removeConnection (const int index) +{ + connections.remove (index); + triggerAsyncUpdate(); +} + +bool AudioProcessorGraph::removeConnection (const uint32 sourceNodeId, const int sourceChannelIndex, + const uint32 destNodeId, const int destChannelIndex) +{ + bool doneAnything = false; + + for (int i = connections.size(); --i >= 0;) + { + const Connection* const c = connections.getUnchecked(i); + + if (c->sourceNodeId == sourceNodeId + && c->destNodeId == destNodeId + && c->sourceChannelIndex == sourceChannelIndex + && c->destChannelIndex == destChannelIndex) + { + removeConnection (i); + doneAnything = true; + triggerAsyncUpdate(); + } + } + + return doneAnything; +} + +bool AudioProcessorGraph::disconnectNode (const uint32 nodeId) +{ + bool doneAnything = false; + + for (int i = connections.size(); --i >= 0;) + { + const Connection* const c = connections.getUnchecked(i); + + if (c->sourceNodeId == nodeId || c->destNodeId == nodeId) + { + removeConnection (i); + doneAnything = true; + triggerAsyncUpdate(); + } + } + + return doneAnything; +} + +bool AudioProcessorGraph::removeIllegalConnections() +{ + bool doneAnything = false; + + for (int i = connections.size(); --i >= 0;) + { + const Connection* const c = connections.getUnchecked(i); + + const Node* const source = getNodeForId (c->sourceNodeId); + const Node* const dest = getNodeForId (c->destNodeId); + + if (source == 0 || dest == 0 + || (c->sourceChannelIndex != midiChannelIndex + && (((unsigned int) c->sourceChannelIndex) >= (unsigned int) source->processor->getNumOutputChannels())) + || (c->sourceChannelIndex == midiChannelIndex + && ! source->processor->producesMidi()) + || (c->destChannelIndex != midiChannelIndex + && (((unsigned int) c->destChannelIndex) >= (unsigned int) dest->processor->getNumInputChannels())) + || (c->destChannelIndex == midiChannelIndex + && ! dest->processor->acceptsMidi())) + { + removeConnection (i); + doneAnything = true; + triggerAsyncUpdate(); + } + } + + return doneAnything; +} + +//============================================================================== +namespace GraphRenderingOps +{ + +//============================================================================== +class AudioGraphRenderingOp +{ +public: + AudioGraphRenderingOp() throw() {} + virtual ~AudioGraphRenderingOp() throw() {} + + virtual void perform (AudioSampleBuffer& sharedBufferChans, + const OwnedArray & sharedMidiBuffers, + const int numSamples) throw() = 0; + + juce_UseDebuggingNewOperator +}; + +//============================================================================== +class ClearChannelOp : public AudioGraphRenderingOp +{ +public: + ClearChannelOp (const int channelNum_) throw() + : channelNum (channelNum_) + {} + + ~ClearChannelOp() throw() {} + + void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray &, const int numSamples) throw() + { + sharedBufferChans.clear (channelNum, 0, numSamples); + } + +private: + const int channelNum; + + ClearChannelOp (const ClearChannelOp&); + const ClearChannelOp& operator= (const ClearChannelOp&); +}; + +//============================================================================== +class CopyChannelOp : public AudioGraphRenderingOp +{ +public: + CopyChannelOp (const int srcChannelNum_, const int dstChannelNum_) throw() + : srcChannelNum (srcChannelNum_), + dstChannelNum (dstChannelNum_) + {} + + ~CopyChannelOp() throw() {} + + void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray &, const int numSamples) throw() + { + sharedBufferChans.copyFrom (dstChannelNum, 0, sharedBufferChans, srcChannelNum, 0, numSamples); + } + +private: + const int srcChannelNum, dstChannelNum; + + CopyChannelOp (const CopyChannelOp&); + const CopyChannelOp& operator= (const CopyChannelOp&); +}; + +//============================================================================== +class AddChannelOp : public AudioGraphRenderingOp +{ +public: + AddChannelOp (const int srcChannelNum_, const int dstChannelNum_) throw() + : srcChannelNum (srcChannelNum_), + dstChannelNum (dstChannelNum_) + {} + + ~AddChannelOp() throw() {} + + void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray &, const int numSamples) throw() + { + sharedBufferChans.addFrom (dstChannelNum, 0, sharedBufferChans, srcChannelNum, 0, numSamples); + } + +private: + const int srcChannelNum, dstChannelNum; + + AddChannelOp (const AddChannelOp&); + const AddChannelOp& operator= (const AddChannelOp&); +}; + +//============================================================================== +class ClearMidiBufferOp : public AudioGraphRenderingOp +{ +public: + ClearMidiBufferOp (const int bufferNum_) throw() + : bufferNum (bufferNum_) + {} + + ~ClearMidiBufferOp() throw() {} + + void perform (AudioSampleBuffer&, const OwnedArray & sharedMidiBuffers, const int) throw() + { + sharedMidiBuffers.getUnchecked (bufferNum)->clear(); + } + +private: + const int bufferNum; + + ClearMidiBufferOp (const ClearMidiBufferOp&); + const ClearMidiBufferOp& operator= (const ClearMidiBufferOp&); +}; + +//============================================================================== +class CopyMidiBufferOp : public AudioGraphRenderingOp +{ +public: + CopyMidiBufferOp (const int srcBufferNum_, const int dstBufferNum_) throw() + : srcBufferNum (srcBufferNum_), + dstBufferNum (dstBufferNum_) + {} + + ~CopyMidiBufferOp() throw() {} + + void perform (AudioSampleBuffer&, const OwnedArray & sharedMidiBuffers, const int) throw() + { + *sharedMidiBuffers.getUnchecked (dstBufferNum) = *sharedMidiBuffers.getUnchecked (srcBufferNum); + } + +private: + const int srcBufferNum, dstBufferNum; + + CopyMidiBufferOp (const CopyMidiBufferOp&); + const CopyMidiBufferOp& operator= (const CopyMidiBufferOp&); +}; + +//============================================================================== +class AddMidiBufferOp : public AudioGraphRenderingOp +{ +public: + AddMidiBufferOp (const int srcBufferNum_, const int dstBufferNum_) throw() + : srcBufferNum (srcBufferNum_), + dstBufferNum (dstBufferNum_) + {} + + ~AddMidiBufferOp() throw() {} + + void perform (AudioSampleBuffer&, const OwnedArray & sharedMidiBuffers, const int numSamples) throw() + { + sharedMidiBuffers.getUnchecked (dstBufferNum) + ->addEvents (*sharedMidiBuffers.getUnchecked (srcBufferNum), 0, numSamples, 0); + } + +private: + const int srcBufferNum, dstBufferNum; + + AddMidiBufferOp (const AddMidiBufferOp&); + const AddMidiBufferOp& operator= (const AddMidiBufferOp&); +}; + +//============================================================================== +class ProcessBufferOp : public AudioGraphRenderingOp +{ +public: + ProcessBufferOp (const AudioProcessorGraph::Node::Ptr& node_, + const Array & audioChannelsToUse_, + const int totalChans_, + const int midiBufferToUse_) throw() + : node (node_), + processor (node_->processor), + audioChannelsToUse (audioChannelsToUse_), + totalChans (totalChans_), + midiBufferToUse (midiBufferToUse_) + { + channels = (float**) juce_calloc (sizeof (float*) * totalChans_); + } + + ~ProcessBufferOp() throw() + { + juce_free (channels); + } + + void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray & sharedMidiBuffers, const int numSamples) throw() + { + for (int i = totalChans; --i >= 0;) + channels[i] = sharedBufferChans.getSampleData (audioChannelsToUse.getUnchecked (i), 0); + + AudioSampleBuffer buffer (channels, totalChans, numSamples); + + processor->processBlock (buffer, *sharedMidiBuffers.getUnchecked (midiBufferToUse)); + } + + const AudioProcessorGraph::Node::Ptr node; + AudioProcessor* const processor; + +private: + Array audioChannelsToUse; + float** channels; + int totalChans; + int midiBufferToUse; + + ProcessBufferOp (const ProcessBufferOp&); + const ProcessBufferOp& operator= (const ProcessBufferOp&); +}; + +//============================================================================== +/** Used to calculate the correct sequence of rendering ops needed, based on + the best re-use of shared buffers at each stage. +*/ +class RenderingOpSequenceCalculator +{ +public: + //============================================================================== + RenderingOpSequenceCalculator (AudioProcessorGraph& graph_, + const VoidArray& orderedNodes_, + VoidArray& renderingOps) + : graph (graph_), + orderedNodes (orderedNodes_) + { + nodeIds.add (-2); // first buffer is read-only zeros + channels.add (0); + + midiNodeIds.add (-2); + + for (int i = 0; i < orderedNodes.size(); ++i) + { + createRenderingOpsForNode ((AudioProcessorGraph::Node*) orderedNodes.getUnchecked(i), + renderingOps, i); + + markAnyUnusedBuffersAsFree (i); + } + } + + int getNumBuffersNeeded() const throw() { return nodeIds.size(); } + + int getNumMidiBuffersNeeded() const throw() { return midiNodeIds.size(); } + + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + AudioProcessorGraph& graph; + const VoidArray& orderedNodes; + Array nodeIds, channels, midiNodeIds; + + //============================================================================== + void createRenderingOpsForNode (AudioProcessorGraph::Node* const node, + VoidArray& renderingOps, + const int ourRenderingIndex) + { + const int numIns = node->processor->getNumInputChannels(); + const int numOuts = node->processor->getNumOutputChannels(); + const int totalChans = jmax (numIns, numOuts); + + Array audioChannelsToUse; + int midiBufferToUse = -1; + + for (int inputChan = 0; inputChan < numIns; ++inputChan) + { + // get a list of all the inputs to this node + Array sourceNodes, sourceOutputChans; + + for (int i = graph.getNumConnections(); --i >= 0;) + { + const AudioProcessorGraph::Connection* const c = graph.getConnection (i); + + if (c->destNodeId == node->id && c->destChannelIndex == inputChan) + { + sourceNodes.add (c->sourceNodeId); + sourceOutputChans.add (c->sourceChannelIndex); + } + } + + int bufIndex = -1; + + if (sourceNodes.size() == 0) + { + // unconnected input channel + + if (inputChan >= numOuts) + { + bufIndex = getReadOnlyEmptyBuffer(); + jassert (bufIndex >= 0); + } + else + { + bufIndex = getFreeBuffer (false); + renderingOps.add (new ClearChannelOp (bufIndex)); + } + } + else if (sourceNodes.size() == 1) + { + // channel with a straightforward single input.. + const int srcNode = sourceNodes.getUnchecked(0); + const int srcChan = sourceOutputChans.getUnchecked(0); + + bufIndex = getBufferContaining (srcNode, srcChan); + + if (bufIndex < 0) + { + // if not found, this is probably a feedback loop + bufIndex = getReadOnlyEmptyBuffer(); + jassert (bufIndex >= 0); + } + + if (inputChan < numOuts + && isBufferNeededLater (ourRenderingIndex, + inputChan, + srcNode, srcChan)) + { + // can't mess up this channel because it's needed later by another node, so we + // need to use a copy of it.. + const int newFreeBuffer = getFreeBuffer (false); + + renderingOps.add (new CopyChannelOp (bufIndex, newFreeBuffer)); + + bufIndex = newFreeBuffer; + } + } + else + { + // channel with a mix of several inputs.. + + // try to find a re-usable channel from our inputs.. + int reusableInputIndex = -1; + + for (int i = 0; i < sourceNodes.size(); ++i) + { + const int sourceBufIndex = getBufferContaining (sourceNodes.getUnchecked(i), + sourceOutputChans.getUnchecked(i)); + + if (sourceBufIndex >= 0 + && ! isBufferNeededLater (ourRenderingIndex, + inputChan, + sourceNodes.getUnchecked(i), + sourceOutputChans.getUnchecked(i))) + { + // we've found one of our input chans that can be re-used.. + reusableInputIndex = i; + bufIndex = sourceBufIndex; + break; + } + } + + if (reusableInputIndex < 0) + { + // can't re-use any of our input chans, so get a new one and copy everything into it.. + bufIndex = getFreeBuffer (false); + jassert (bufIndex != 0); + + const int srcIndex = getBufferContaining (sourceNodes.getUnchecked (0), + sourceOutputChans.getUnchecked (0)); + if (srcIndex < 0) + { + // if not found, this is probably a feedback loop + renderingOps.add (new ClearChannelOp (bufIndex)); + } + else + { + renderingOps.add (new CopyChannelOp (srcIndex, bufIndex)); + } + + reusableInputIndex = 0; + } + + for (int j = 0; j < sourceNodes.size(); ++j) + { + if (j != reusableInputIndex) + { + const int srcIndex = getBufferContaining (sourceNodes.getUnchecked(j), + sourceOutputChans.getUnchecked(j)); + if (srcIndex >= 0) + renderingOps.add (new AddChannelOp (srcIndex, bufIndex)); + } + } + } + + jassert (bufIndex >= 0); + audioChannelsToUse.add (bufIndex); + + if (inputChan < numOuts) + markBufferAsContaining (bufIndex, node->id, inputChan); + } + + for (int outputChan = numIns; outputChan < numOuts; ++outputChan) + { + const int bufIndex = getFreeBuffer (false); + jassert (bufIndex != 0); + audioChannelsToUse.add (bufIndex); + + markBufferAsContaining (bufIndex, node->id, outputChan); + } + + // Now the same thing for midi.. + Array midiSourceNodes; + + for (int i = graph.getNumConnections(); --i >= 0;) + { + const AudioProcessorGraph::Connection* const c = graph.getConnection (i); + + if (c->destNodeId == node->id && c->destChannelIndex == AudioProcessorGraph::midiChannelIndex) + midiSourceNodes.add (c->sourceNodeId); + } + + if (midiSourceNodes.size() == 0) + { + // No midi inputs.. + midiBufferToUse = getFreeBuffer (true); // need to pick a buffer even if the processor doesn't use midi + + if (node->processor->acceptsMidi() || node->processor->producesMidi()) + renderingOps.add (new ClearMidiBufferOp (midiBufferToUse)); + } + else if (midiSourceNodes.size() == 1) + { + // One midi input.. + midiBufferToUse = getBufferContaining (midiSourceNodes.getUnchecked(0), + AudioProcessorGraph::midiChannelIndex); + + if (midiBufferToUse >= 0) + { + if (isBufferNeededLater (ourRenderingIndex, + AudioProcessorGraph::midiChannelIndex, + midiSourceNodes.getUnchecked(0), + AudioProcessorGraph::midiChannelIndex)) + { + // can't mess up this channel because it's needed later by another node, so we + // need to use a copy of it.. + const int newFreeBuffer = getFreeBuffer (true); + renderingOps.add (new CopyMidiBufferOp (midiBufferToUse, newFreeBuffer)); + midiBufferToUse = newFreeBuffer; + } + } + else + { + // probably a feedback loop, so just use an empty one.. + midiBufferToUse = getFreeBuffer (true); // need to pick a buffer even if the processor doesn't use midi + } + } + else + { + // More than one midi input being mixed.. + int reusableInputIndex = -1; + + for (int i = 0; i < midiSourceNodes.size(); ++i) + { + const int sourceBufIndex = getBufferContaining (midiSourceNodes.getUnchecked(i), + AudioProcessorGraph::midiChannelIndex); + + if (sourceBufIndex >= 0 + && ! isBufferNeededLater (ourRenderingIndex, + AudioProcessorGraph::midiChannelIndex, + midiSourceNodes.getUnchecked(i), + AudioProcessorGraph::midiChannelIndex)) + { + // we've found one of our input buffers that can be re-used.. + reusableInputIndex = i; + midiBufferToUse = sourceBufIndex; + break; + } + } + + if (reusableInputIndex < 0) + { + // can't re-use any of our input buffers, so get a new one and copy everything into it.. + midiBufferToUse = getFreeBuffer (true); + jassert (midiBufferToUse >= 0); + + const int srcIndex = getBufferContaining (midiSourceNodes.getUnchecked(0), + AudioProcessorGraph::midiChannelIndex); + if (srcIndex >= 0) + renderingOps.add (new CopyMidiBufferOp (srcIndex, midiBufferToUse)); + else + renderingOps.add (new ClearMidiBufferOp (midiBufferToUse)); + + reusableInputIndex = 0; + } + + for (int j = 0; j < midiSourceNodes.size(); ++j) + { + if (j != reusableInputIndex) + { + const int srcIndex = getBufferContaining (midiSourceNodes.getUnchecked(j), + AudioProcessorGraph::midiChannelIndex); + if (srcIndex >= 0) + renderingOps.add (new AddMidiBufferOp (srcIndex, midiBufferToUse)); + } + } + } + + if (node->processor->producesMidi()) + markBufferAsContaining (midiBufferToUse, node->id, + AudioProcessorGraph::midiChannelIndex); + + renderingOps.add (new ProcessBufferOp (node, audioChannelsToUse, + totalChans, midiBufferToUse)); + } + + //============================================================================== + int getFreeBuffer (const bool forMidi) + { + if (forMidi) + { + for (int i = 1; i < midiNodeIds.size(); ++i) + if (midiNodeIds.getUnchecked(i) < 0) + return i; + + midiNodeIds.add (-1); + return midiNodeIds.size() - 1; + } + else + { + for (int i = 1; i < nodeIds.size(); ++i) + if (nodeIds.getUnchecked(i) < 0) + return i; + + nodeIds.add (-1); + channels.add (0); + return nodeIds.size() - 1; + } + } + + int getReadOnlyEmptyBuffer() const throw() + { + return 0; + } + + int getBufferContaining (const int nodeId, const int outputChannel) const throw() + { + if (outputChannel == AudioProcessorGraph::midiChannelIndex) + { + for (int i = midiNodeIds.size(); --i >= 0;) + if (midiNodeIds.getUnchecked(i) == nodeId) + return i; + } + else + { + for (int i = nodeIds.size(); --i >= 0;) + if (nodeIds.getUnchecked(i) == nodeId + && channels.getUnchecked(i) == outputChannel) + return i; + } + + return -1; + } + + void markAnyUnusedBuffersAsFree (const int stepIndex) + { + int i; + for (i = 0; i < nodeIds.size(); ++i) + { + if (nodeIds.getUnchecked(i) >= 0 + && ! isBufferNeededLater (stepIndex, -1, + nodeIds.getUnchecked(i), + channels.getUnchecked(i))) + { + nodeIds.set (i, -1); + } + } + + for (i = 0; i < midiNodeIds.size(); ++i) + { + if (midiNodeIds.getUnchecked(i) >= 0 + && ! isBufferNeededLater (stepIndex, -1, + midiNodeIds.getUnchecked(i), + AudioProcessorGraph::midiChannelIndex)) + { + midiNodeIds.set (i, -1); + } + } + } + + bool isBufferNeededLater (int stepIndexToSearchFrom, + int inputChannelOfIndexToIgnore, + const int nodeId, + const int outputChanIndex) const throw() + { + while (stepIndexToSearchFrom < orderedNodes.size()) + { + const AudioProcessorGraph::Node* const node = (const AudioProcessorGraph::Node*) orderedNodes.getUnchecked (stepIndexToSearchFrom); + + if (outputChanIndex == AudioProcessorGraph::midiChannelIndex) + { + if (inputChannelOfIndexToIgnore != AudioProcessorGraph::midiChannelIndex + && graph.getConnectionBetween (nodeId, AudioProcessorGraph::midiChannelIndex, + node->id, AudioProcessorGraph::midiChannelIndex) != 0) + return true; + } + else + { + for (int i = 0; i < node->processor->getNumInputChannels(); ++i) + if (i != inputChannelOfIndexToIgnore + && graph.getConnectionBetween (nodeId, outputChanIndex, + node->id, i) != 0) + return true; + } + + inputChannelOfIndexToIgnore = -1; + ++stepIndexToSearchFrom; + } + + return false; + } + + void markBufferAsContaining (int bufferNum, int nodeId, int outputIndex) + { + if (outputIndex == AudioProcessorGraph::midiChannelIndex) + { + jassert (bufferNum > 0 && bufferNum < midiNodeIds.size()); + + midiNodeIds.set (bufferNum, nodeId); + } + else + { + jassert (bufferNum > 0 && bufferNum < nodeIds.size()); + + nodeIds.set (bufferNum, nodeId); + channels.set (bufferNum, outputIndex); + } + } + + RenderingOpSequenceCalculator (const RenderingOpSequenceCalculator&); + const RenderingOpSequenceCalculator& operator= (const RenderingOpSequenceCalculator&); +}; + +} + +//============================================================================== +void AudioProcessorGraph::clearRenderingSequence() +{ + const ScopedLock sl (renderLock); + + for (int i = renderingOps.size(); --i >= 0;) + { + GraphRenderingOps::AudioGraphRenderingOp* const r + = (GraphRenderingOps::AudioGraphRenderingOp*) renderingOps.getUnchecked(i); + + renderingOps.remove (i); + delete r; + } +} + +bool AudioProcessorGraph::isAnInputTo (const uint32 possibleInputId, + const uint32 possibleDestinationId, + const int recursionCheck) const throw() +{ + if (recursionCheck > 0) + { + for (int i = connections.size(); --i >= 0;) + { + const AudioProcessorGraph::Connection* const c = connections.getUnchecked (i); + + if (c->destNodeId == possibleDestinationId + && (c->sourceNodeId == possibleInputId + || isAnInputTo (possibleInputId, c->sourceNodeId, recursionCheck - 1))) + return true; + } + } + + return false; +} + +void AudioProcessorGraph::buildRenderingSequence() +{ + VoidArray newRenderingOps; + int numRenderingBuffersNeeded = 2; + int numMidiBuffersNeeded = 1; + + { + MessageManagerLock mml; + + VoidArray orderedNodes; + + int i; + for (i = 0; i < nodes.size(); ++i) + { + Node* const node = nodes.getUnchecked(i); + + node->prepare (getSampleRate(), getBlockSize(), this); + + int j = 0; + for (; j < orderedNodes.size(); ++j) + if (isAnInputTo (node->id, + ((Node*) orderedNodes.getUnchecked (j))->id, + nodes.size() + 1)) + break; + + orderedNodes.insert (j, node); + } + + GraphRenderingOps::RenderingOpSequenceCalculator calculator (*this, orderedNodes, newRenderingOps); + + numRenderingBuffersNeeded = calculator.getNumBuffersNeeded(); + numMidiBuffersNeeded = calculator.getNumMidiBuffersNeeded(); + } + + VoidArray oldRenderingOps (renderingOps); + + { + // swap over to the new set of rendering sequence.. + const ScopedLock sl (renderLock); + + renderingBuffers.setSize (numRenderingBuffersNeeded, getBlockSize()); + renderingBuffers.clear(); + + for (int i = midiBuffers.size(); --i >= 0;) + midiBuffers.getUnchecked(i)->clear(); + + while (midiBuffers.size() < numMidiBuffersNeeded) + midiBuffers.add (new MidiBuffer()); + + renderingOps = newRenderingOps; + } + + for (int i = oldRenderingOps.size(); --i >= 0;) + delete (GraphRenderingOps::AudioGraphRenderingOp*) oldRenderingOps.getUnchecked(i); +} + +void AudioProcessorGraph::handleAsyncUpdate() +{ + buildRenderingSequence(); +} + +//============================================================================== +void AudioProcessorGraph::prepareToPlay (double /*sampleRate*/, int estimatedSamplesPerBlock) +{ + currentAudioInputBuffer = 0; + currentAudioOutputBuffer.setSize (getNumOutputChannels(), estimatedSamplesPerBlock); + currentMidiInputBuffer = 0; + currentMidiOutputBuffer.clear(); + + clearRenderingSequence(); + buildRenderingSequence(); +} + +void AudioProcessorGraph::releaseResources() +{ + for (int i = 0; i < nodes.size(); ++i) + nodes.getUnchecked(i)->unprepare(); + + renderingBuffers.setSize (1, 1); + midiBuffers.clear(); + + currentAudioInputBuffer = 0; + currentAudioOutputBuffer.setSize (1, 1); + currentMidiInputBuffer = 0; + currentMidiOutputBuffer.clear(); +} + +void AudioProcessorGraph::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) +{ + const int numSamples = buffer.getNumSamples(); + + const ScopedLock sl (renderLock); + + currentAudioInputBuffer = &buffer; + currentAudioOutputBuffer.setSize (buffer.getNumChannels(), numSamples); + currentAudioOutputBuffer.clear(); + currentMidiInputBuffer = &midiMessages; + currentMidiOutputBuffer.clear(); + + for (int i = 0; i < renderingOps.size(); ++i) + { + GraphRenderingOps::AudioGraphRenderingOp* const op + = (GraphRenderingOps::AudioGraphRenderingOp*) renderingOps.getUnchecked(i); + + op->perform (renderingBuffers, midiBuffers, numSamples); + } + + for (int i = 0; i < buffer.getNumChannels(); ++i) + buffer.copyFrom (i, 0, currentAudioOutputBuffer, i, 0, numSamples); +} + +const String AudioProcessorGraph::getInputChannelName (const int channelIndex) const +{ + return "Input " + String (channelIndex + 1); +} + +const String AudioProcessorGraph::getOutputChannelName (const int channelIndex) const +{ + return "Output " + String (channelIndex + 1); +} + +bool AudioProcessorGraph::isInputChannelStereoPair (int /*index*/) const +{ + return true; +} + +bool AudioProcessorGraph::isOutputChannelStereoPair (int /*index*/) const +{ + return true; +} + +bool AudioProcessorGraph::acceptsMidi() const +{ + return true; +} + +bool AudioProcessorGraph::producesMidi() const +{ + return true; +} + +void AudioProcessorGraph::getStateInformation (JUCE_NAMESPACE::MemoryBlock& /*destData*/) +{ +} + +void AudioProcessorGraph::setStateInformation (const void* /*data*/, int /*sizeInBytes*/) +{ +} + + +//============================================================================== +AudioProcessorGraph::AudioGraphIOProcessor::AudioGraphIOProcessor (const IODeviceType type_) + : type (type_), + graph (0) +{ +} + +AudioProcessorGraph::AudioGraphIOProcessor::~AudioGraphIOProcessor() +{ +} + +const String AudioProcessorGraph::AudioGraphIOProcessor::getName() const +{ + switch (type) + { + case audioOutputNode: + return "Audio Output"; + case audioInputNode: + return "Audio Input"; + case midiOutputNode: + return "Midi Output"; + case midiInputNode: + return "Midi Input"; + default: + break; + } + + return String::empty; +} + +void AudioProcessorGraph::AudioGraphIOProcessor::fillInPluginDescription (PluginDescription& d) const +{ + d.name = getName(); + d.uid = d.name.hashCode(); + d.category = "I/O devices"; + d.pluginFormatName = "Internal"; + d.manufacturerName = "Raw Material Software"; + d.version = "1.0"; + d.isInstrument = false; + + d.numInputChannels = getNumInputChannels(); + if (type == audioOutputNode && graph != 0) + d.numInputChannels = graph->getNumInputChannels(); + + d.numOutputChannels = getNumOutputChannels(); + if (type == audioInputNode && graph != 0) + d.numOutputChannels = graph->getNumOutputChannels(); +} + +void AudioProcessorGraph::AudioGraphIOProcessor::prepareToPlay (double, int) +{ + jassert (graph != 0); +} + +void AudioProcessorGraph::AudioGraphIOProcessor::releaseResources() +{ +} + +void AudioProcessorGraph::AudioGraphIOProcessor::processBlock (AudioSampleBuffer& buffer, + MidiBuffer& midiMessages) +{ + jassert (graph != 0); + + switch (type) + { + case audioOutputNode: + { + for (int i = jmin (graph->currentAudioOutputBuffer.getNumChannels(), + buffer.getNumChannels()); --i >= 0;) + { + graph->currentAudioOutputBuffer.addFrom (i, 0, buffer, i, 0, buffer.getNumSamples()); + } + + break; + } + + case audioInputNode: + { + for (int i = jmin (graph->currentAudioInputBuffer->getNumChannels(), + buffer.getNumChannels()); --i >= 0;) + { + buffer.addFrom (i, 0, *graph->currentAudioInputBuffer, i, 0, buffer.getNumSamples()); + } + + break; + } + + case midiOutputNode: + graph->currentMidiOutputBuffer.addEvents (midiMessages, 0, buffer.getNumSamples(), 0); + break; + + case midiInputNode: + midiMessages.addEvents (*graph->currentMidiInputBuffer, 0, buffer.getNumSamples(), 0); + break; + + default: + break; + } +} + +bool AudioProcessorGraph::AudioGraphIOProcessor::acceptsMidi() const +{ + return type == midiOutputNode; +} + +bool AudioProcessorGraph::AudioGraphIOProcessor::producesMidi() const +{ + return type == midiInputNode; +} + +const String AudioProcessorGraph::AudioGraphIOProcessor::getInputChannelName (const int channelIndex) const +{ + switch (type) + { + case audioOutputNode: + return "Output " + String (channelIndex + 1); + case midiOutputNode: + return "Midi Output"; + default: + break; + } + + return String::empty; +} + +const String AudioProcessorGraph::AudioGraphIOProcessor::getOutputChannelName (const int channelIndex) const +{ + switch (type) + { + case audioInputNode: + return "Input " + String (channelIndex + 1); + case midiInputNode: + return "Midi Input"; + default: + break; + } + + return String::empty; +} + +bool AudioProcessorGraph::AudioGraphIOProcessor::isInputChannelStereoPair (int /*index*/) const +{ + return type == audioInputNode || type == audioOutputNode; +} + +bool AudioProcessorGraph::AudioGraphIOProcessor::isOutputChannelStereoPair (int index) const +{ + return isInputChannelStereoPair (index); +} + +bool AudioProcessorGraph::AudioGraphIOProcessor::isInput() const throw() +{ + return type == audioInputNode || type == midiInputNode; +} + +bool AudioProcessorGraph::AudioGraphIOProcessor::isOutput() const throw() +{ + return type == audioOutputNode || type == midiOutputNode; +} + +AudioProcessorEditor* AudioProcessorGraph::AudioGraphIOProcessor::createEditor() +{ + return 0; +} + +int AudioProcessorGraph::AudioGraphIOProcessor::getNumParameters() { return 0; } +const String AudioProcessorGraph::AudioGraphIOProcessor::getParameterName (int) { return String::empty; } + +float AudioProcessorGraph::AudioGraphIOProcessor::getParameter (int) { return 0.0f; } +const String AudioProcessorGraph::AudioGraphIOProcessor::getParameterText (int) { return String::empty; } +void AudioProcessorGraph::AudioGraphIOProcessor::setParameter (int, float) { } + +int AudioProcessorGraph::AudioGraphIOProcessor::getNumPrograms() { return 0; } +int AudioProcessorGraph::AudioGraphIOProcessor::getCurrentProgram() { return 0; } +void AudioProcessorGraph::AudioGraphIOProcessor::setCurrentProgram (int) { } + +const String AudioProcessorGraph::AudioGraphIOProcessor::getProgramName (int) { return String::empty; } +void AudioProcessorGraph::AudioGraphIOProcessor::changeProgramName (int, const String&) { } + +void AudioProcessorGraph::AudioGraphIOProcessor::getStateInformation (JUCE_NAMESPACE::MemoryBlock&) +{ +} + +void AudioProcessorGraph::AudioGraphIOProcessor::setStateInformation (const void*, int) +{ +} + +void AudioProcessorGraph::AudioGraphIOProcessor::setParentGraph (AudioProcessorGraph* const newGraph) throw() +{ + graph = newGraph; + + if (graph != 0) + { + setPlayConfigDetails (type == audioOutputNode ? graph->getNumInputChannels() : 0, + type == audioInputNode ? graph->getNumOutputChannels() : 0, + getSampleRate(), + getBlockSize()); + + updateHostDisplay(); + } +} + + +END_JUCE_NAMESPACE diff --git a/src/juce_appframework/audio/processors/juce_AudioProcessorGraph.h b/src/juce_appframework/audio/processors/juce_AudioProcessorGraph.h index 88f4298ec4..bf93c8b01a 100644 --- a/src/juce_appframework/audio/processors/juce_AudioProcessorGraph.h +++ b/src/juce_appframework/audio/processors/juce_AudioProcessorGraph.h @@ -1,442 +1,442 @@ -/* - ============================================================================== - - 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_AUDIOPROCESSORGRAPH_JUCEHEADER__ -#define __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ - -#include "juce_AudioProcessor.h" -#include "../plugins/juce_AudioPluginFormatManager.h" -#include "../plugins/juce_KnownPluginList.h" -#include "../../../juce_core/containers/juce_ReferenceCountedArray.h" - - -//============================================================================== -/** - A type of AudioProcessor which plays back a graph of other AudioProcessors. - - Use one of these objects if you want to wire-up a set of AudioProcessors - and play back the result. - - Processors can be added to the graph as "nodes" using addNode(), and once - added, you can connect any of their input or output channels to other - nodes using addConnection(). - - To play back a graph through an audio device, you might want to use an - AudioProcessorPlayer object. -*/ -class JUCE_API AudioProcessorGraph : public AudioProcessor, - public AsyncUpdater -{ -public: - //============================================================================== - /** Creates an empty graph. - */ - AudioProcessorGraph(); - - /** Destructor. - - Any processor objects that have been added to the graph will also be deleted. - */ - ~AudioProcessorGraph(); - - //============================================================================== - /** Represents one of the nodes, or processors, in an AudioProcessorGraph. - - To create a node, call AudioProcessorGraph::addNode(). - */ - class Node : public ReferenceCountedObject - { - public: - /** Destructor. - */ - ~Node(); - - //============================================================================== - /** The ID number assigned to this node. - - This is assigned by the graph that owns it, and can't be changed. - */ - const uint32 id; - - /** The actual processor object that this node represents. - */ - AudioProcessor* const processor; - - /** A set of user-definable properties that are associated with this node. - - This can be used to attach values to the node for whatever purpose seems - useful. For example, you might store an x and y position if your application - is displaying the nodes on-screen. - */ - PropertySet properties; - - //============================================================================== - /** A convenient typedef for referring to a pointer to a node object. - */ - typedef ReferenceCountedObjectPtr Ptr; - - //============================================================================== - juce_UseDebuggingNewOperator - - private: - friend class AudioProcessorGraph; - - bool isPrepared; - - Node (const uint32 id, AudioProcessor* const processor) throw(); - - void prepare (const double sampleRate, const int blockSize, AudioProcessorGraph* const graph); - void unprepare(); - - Node (const Node&); - const Node& operator= (const Node&); - }; - - //============================================================================== - /** Represents a connection between two channels of two nodes in an AudioProcessorGraph. - - To create a connection, use AudioProcessorGraph::addConnection(). - */ - struct Connection - { - public: - //============================================================================== - /** The ID number of the node which is the input source for this connection. - @see AudioProcessorGraph::getNodeForId - */ - uint32 sourceNodeId; - - /** The index of the output channel of the source node from which this - connection takes its data. - - If this value is the special number AudioProcessorGraph::midiChannelIndex, then - it is referring to the source node's midi output. Otherwise, it is the zero-based - index of an audio output channel in the source node. - */ - int sourceChannelIndex; - - /** The ID number of the node which is the destination for this connection. - @see AudioProcessorGraph::getNodeForId - */ - uint32 destNodeId; - - /** The index of the input channel of the destination node to which this - connection delivers its data. - - If this value is the special number AudioProcessorGraph::midiChannelIndex, then - it is referring to the destination node's midi input. Otherwise, it is the zero-based - index of an audio input channel in the destination node. - */ - int destChannelIndex; - - //============================================================================== - juce_UseDebuggingNewOperator - - private: - }; - - //============================================================================== - /** Deletes all nodes and connections from this graph. - - Any processor objects in the graph will be deleted. - */ - void clear(); - - /** Returns the number of nodes in the graph. */ - int getNumNodes() const throw() { return nodes.size(); } - - /** Returns a pointer to one of the nodes in the graph. - - This will return 0 if the index is out of range. - @see getNodeForId - */ - Node* getNode (const int index) const throw() { return nodes [index]; } - - /** Searches the graph for a node with the given ID number and returns it. - - If no such node was found, this returns 0. - @see getNode - */ - Node* getNodeForId (const uint32 nodeId) const throw(); - - /** Adds a node to the graph. - - This creates a new node in the graph, for the specified processor. Once you have - added a processor to the graph, the graph owns it and will delete it later when - it is no longer needed. - - The optional nodeId parameter lets you specify an ID to use for the node, but - if the value is already in use, this new node will overwrite the old one. - - If this succeeds, it returns a pointer to the newly-created node. - */ - Node* addNode (AudioProcessor* const newProcessor, - uint32 nodeId = 0); - - /** Deletes a node within the graph which has the specified ID. - - This will also delete any connections that are attached to this node. - */ - bool removeNode (const uint32 nodeId); - - //============================================================================== - /** Returns the number of connections in the graph. */ - int getNumConnections() const throw() { return connections.size(); } - - /** Returns a pointer to one of the connections in the graph. */ - const Connection* getConnection (const int index) const throw() { return connections [index]; } - - /** Searches for a connection between some specified channels. - - If no such connection is found, this returns 0. - */ - const Connection* getConnectionBetween (const uint32 sourceNodeId, - const int sourceChannelIndex, - const uint32 destNodeId, - const int destChannelIndex) const throw(); - - /** Returns true if there is a connection between any of the channels of - two specified nodes. - */ - bool isConnected (const uint32 possibleSourceNodeId, - const uint32 possibleDestNodeId) const throw(); - - /** Returns true if it would be legal to connect the specified points. - */ - bool canConnect (const uint32 sourceNodeId, const int sourceChannelIndex, - const uint32 destNodeId, const int destChannelIndex) const throw(); - - /** Attempts to connect two specified channels of two nodes. - - If this isn't allowed (e.g. because you're trying to connect a midi channel - to an audio one or other such nonsense), then it'll return false. - */ - bool addConnection (const uint32 sourceNodeId, const int sourceChannelIndex, - const uint32 destNodeId, const int destChannelIndex); - - /** Deletes the connection with the specified index. - - Returns true if a connection was actually deleted. - */ - void removeConnection (const int index); - - /** Deletes any connection between two specified points. - - Returns true if a connection was actually deleted. - */ - bool removeConnection (const uint32 sourceNodeId, const int sourceChannelIndex, - const uint32 destNodeId, const int destChannelIndex); - - /** Removes all connections from the specified node. - */ - bool disconnectNode (const uint32 nodeId); - - /** Performs a sanity checks of all the connections. - - This might be useful if some of the processors are doing things like changing - their channel counts, which could render some connections obsolete. - */ - bool removeIllegalConnections(); - - //============================================================================== - /** A special number that represents the midi channel of a node. - - This is used as a channel index value if you want to refer to the midi input - or output instead of an audio channel. - */ - static const int midiChannelIndex; - - - //============================================================================== - /** A special type of AudioProcessor that can live inside an AudioProcessorGraph - in order to use the audio that comes into and out of the graph itself. - - If you create an AudioGraphIOProcessor in "input" mode, it will act as a - node in the graph which delivers the audio that is coming into the parent - graph. This allows you to stream the data to other nodes and process the - incoming audio. - - Likewise, one of these in "output" mode can be sent data which it will add to - the sum of data being sent to the graph's output. - - @see AudioProcessorGraph - */ - class AudioGraphIOProcessor : public AudioPluginInstance - { - public: - /** Specifies the mode in which this processor will operate. - */ - enum IODeviceType - { - audioInputNode, /**< In this mode, the processor has output channels - representing all the audio input channels that are - coming into its parent audio graph. */ - audioOutputNode, /**< In this mode, the processor has input channels - representing all the audio output channels that are - going out of its parent audio graph. */ - midiInputNode, /**< In this mode, the processor has a midi output which - delivers the same midi data that is arriving at its - parent graph. */ - midiOutputNode /**< In this mode, the processor has a midi input and - any data sent to it will be passed out of the parent - graph. */ - }; - - //============================================================================== - /** Returns the mode of this processor. */ - IODeviceType getType() const throw() { return type; } - - /** Returns the parent graph to which this processor belongs, or 0 if it - hasn't yet been added to one. */ - AudioProcessorGraph* getParentGraph() const throw() { return graph; } - - /** True if this is an audio or midi input. */ - bool isInput() const throw(); - /** True if this is an audio or midi output. */ - bool isOutput() const throw(); - - //============================================================================== - AudioGraphIOProcessor (const IODeviceType type); - ~AudioGraphIOProcessor(); - - const String getName() const; - void fillInPluginDescription (PluginDescription& d) const; - - void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); - void releaseResources(); - void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); - - const String getInputChannelName (const int channelIndex) const; - const String getOutputChannelName (const int channelIndex) const; - bool isInputChannelStereoPair (int index) const; - bool isOutputChannelStereoPair (int index) const; - bool acceptsMidi() const; - bool producesMidi() const; - - AudioProcessorEditor* createEditor(); - - int getNumParameters(); - const String getParameterName (int); - float getParameter (int); - const String getParameterText (int); - void setParameter (int, float); - - int getNumPrograms(); - int getCurrentProgram(); - void setCurrentProgram (int); - const String getProgramName (int); - void changeProgramName (int, const String&); - - void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); - void setStateInformation (const void* data, int sizeInBytes); - - /** @internal */ - void setParentGraph (AudioProcessorGraph* const graph) throw(); - - juce_UseDebuggingNewOperator - - private: - const IODeviceType type; - AudioProcessorGraph* graph; - - AudioGraphIOProcessor (const AudioGraphIOProcessor&); - const AudioGraphIOProcessor& operator= (const AudioGraphIOProcessor&); - }; - - //============================================================================== - // AudioProcessor methods: - - const String getName() const; - - void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); - void releaseResources(); - void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); - - const String getInputChannelName (const int channelIndex) const; - const String getOutputChannelName (const int channelIndex) const; - bool isInputChannelStereoPair (int index) const; - bool isOutputChannelStereoPair (int index) const; - - bool acceptsMidi() const; - bool producesMidi() const; - - AudioProcessorEditor* createEditor() { return 0; } - - int getNumParameters() { return 0; } - const String getParameterName (int) { return String::empty; } - float getParameter (int) { return 0; } - const String getParameterText (int) { return String::empty; } - void setParameter (int, float) { } - - int getNumPrograms() { return 0; } - int getCurrentProgram() { return 0; } - void setCurrentProgram (int) { } - const String getProgramName (int) { return String::empty; } - void changeProgramName (int, const String&) { } - - void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); - void setStateInformation (const void* data, int sizeInBytes); - - /** @internal */ - void handleAsyncUpdate(); - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - ReferenceCountedArray nodes; - OwnedArray connections; - int lastNodeId; - AudioSampleBuffer renderingBuffers; - OwnedArray midiBuffers; - - CriticalSection renderLock; - VoidArray renderingOps; - - friend class AudioGraphIOProcessor; - AudioSampleBuffer* currentAudioInputBuffer; - AudioSampleBuffer currentAudioOutputBuffer; - MidiBuffer* currentMidiInputBuffer; - MidiBuffer currentMidiOutputBuffer; - - void clearRenderingSequence(); - void buildRenderingSequence(); - - bool isAnInputTo (const uint32 possibleInputId, - const uint32 possibleDestinationId, - const int recursionCheck) const throw(); - - AudioProcessorGraph (const AudioProcessorGraph&); - const AudioProcessorGraph& operator= (const AudioProcessorGraph&); -}; - - -#endif // __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ +/* + ============================================================================== + + 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_AUDIOPROCESSORGRAPH_JUCEHEADER__ +#define __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ + +#include "juce_AudioProcessor.h" +#include "../plugins/juce_AudioPluginFormatManager.h" +#include "../plugins/juce_KnownPluginList.h" +#include "../../../juce_core/containers/juce_ReferenceCountedArray.h" + + +//============================================================================== +/** + A type of AudioProcessor which plays back a graph of other AudioProcessors. + + Use one of these objects if you want to wire-up a set of AudioProcessors + and play back the result. + + Processors can be added to the graph as "nodes" using addNode(), and once + added, you can connect any of their input or output channels to other + nodes using addConnection(). + + To play back a graph through an audio device, you might want to use an + AudioProcessorPlayer object. +*/ +class JUCE_API AudioProcessorGraph : public AudioProcessor, + public AsyncUpdater +{ +public: + //============================================================================== + /** Creates an empty graph. + */ + AudioProcessorGraph(); + + /** Destructor. + + Any processor objects that have been added to the graph will also be deleted. + */ + ~AudioProcessorGraph(); + + //============================================================================== + /** Represents one of the nodes, or processors, in an AudioProcessorGraph. + + To create a node, call AudioProcessorGraph::addNode(). + */ + class Node : public ReferenceCountedObject + { + public: + /** Destructor. + */ + ~Node(); + + //============================================================================== + /** The ID number assigned to this node. + + This is assigned by the graph that owns it, and can't be changed. + */ + const uint32 id; + + /** The actual processor object that this node represents. + */ + AudioProcessor* const processor; + + /** A set of user-definable properties that are associated with this node. + + This can be used to attach values to the node for whatever purpose seems + useful. For example, you might store an x and y position if your application + is displaying the nodes on-screen. + */ + PropertySet properties; + + //============================================================================== + /** A convenient typedef for referring to a pointer to a node object. + */ + typedef ReferenceCountedObjectPtr Ptr; + + //============================================================================== + juce_UseDebuggingNewOperator + + private: + friend class AudioProcessorGraph; + + bool isPrepared; + + Node (const uint32 id, AudioProcessor* const processor) throw(); + + void prepare (const double sampleRate, const int blockSize, AudioProcessorGraph* const graph); + void unprepare(); + + Node (const Node&); + const Node& operator= (const Node&); + }; + + //============================================================================== + /** Represents a connection between two channels of two nodes in an AudioProcessorGraph. + + To create a connection, use AudioProcessorGraph::addConnection(). + */ + struct Connection + { + public: + //============================================================================== + /** The ID number of the node which is the input source for this connection. + @see AudioProcessorGraph::getNodeForId + */ + uint32 sourceNodeId; + + /** The index of the output channel of the source node from which this + connection takes its data. + + If this value is the special number AudioProcessorGraph::midiChannelIndex, then + it is referring to the source node's midi output. Otherwise, it is the zero-based + index of an audio output channel in the source node. + */ + int sourceChannelIndex; + + /** The ID number of the node which is the destination for this connection. + @see AudioProcessorGraph::getNodeForId + */ + uint32 destNodeId; + + /** The index of the input channel of the destination node to which this + connection delivers its data. + + If this value is the special number AudioProcessorGraph::midiChannelIndex, then + it is referring to the destination node's midi input. Otherwise, it is the zero-based + index of an audio input channel in the destination node. + */ + int destChannelIndex; + + //============================================================================== + juce_UseDebuggingNewOperator + + private: + }; + + //============================================================================== + /** Deletes all nodes and connections from this graph. + + Any processor objects in the graph will be deleted. + */ + void clear(); + + /** Returns the number of nodes in the graph. */ + int getNumNodes() const throw() { return nodes.size(); } + + /** Returns a pointer to one of the nodes in the graph. + + This will return 0 if the index is out of range. + @see getNodeForId + */ + Node* getNode (const int index) const throw() { return nodes [index]; } + + /** Searches the graph for a node with the given ID number and returns it. + + If no such node was found, this returns 0. + @see getNode + */ + Node* getNodeForId (const uint32 nodeId) const throw(); + + /** Adds a node to the graph. + + This creates a new node in the graph, for the specified processor. Once you have + added a processor to the graph, the graph owns it and will delete it later when + it is no longer needed. + + The optional nodeId parameter lets you specify an ID to use for the node, but + if the value is already in use, this new node will overwrite the old one. + + If this succeeds, it returns a pointer to the newly-created node. + */ + Node* addNode (AudioProcessor* const newProcessor, + uint32 nodeId = 0); + + /** Deletes a node within the graph which has the specified ID. + + This will also delete any connections that are attached to this node. + */ + bool removeNode (const uint32 nodeId); + + //============================================================================== + /** Returns the number of connections in the graph. */ + int getNumConnections() const throw() { return connections.size(); } + + /** Returns a pointer to one of the connections in the graph. */ + const Connection* getConnection (const int index) const throw() { return connections [index]; } + + /** Searches for a connection between some specified channels. + + If no such connection is found, this returns 0. + */ + const Connection* getConnectionBetween (const uint32 sourceNodeId, + const int sourceChannelIndex, + const uint32 destNodeId, + const int destChannelIndex) const throw(); + + /** Returns true if there is a connection between any of the channels of + two specified nodes. + */ + bool isConnected (const uint32 possibleSourceNodeId, + const uint32 possibleDestNodeId) const throw(); + + /** Returns true if it would be legal to connect the specified points. + */ + bool canConnect (const uint32 sourceNodeId, const int sourceChannelIndex, + const uint32 destNodeId, const int destChannelIndex) const throw(); + + /** Attempts to connect two specified channels of two nodes. + + If this isn't allowed (e.g. because you're trying to connect a midi channel + to an audio one or other such nonsense), then it'll return false. + */ + bool addConnection (const uint32 sourceNodeId, const int sourceChannelIndex, + const uint32 destNodeId, const int destChannelIndex); + + /** Deletes the connection with the specified index. + + Returns true if a connection was actually deleted. + */ + void removeConnection (const int index); + + /** Deletes any connection between two specified points. + + Returns true if a connection was actually deleted. + */ + bool removeConnection (const uint32 sourceNodeId, const int sourceChannelIndex, + const uint32 destNodeId, const int destChannelIndex); + + /** Removes all connections from the specified node. + */ + bool disconnectNode (const uint32 nodeId); + + /** Performs a sanity checks of all the connections. + + This might be useful if some of the processors are doing things like changing + their channel counts, which could render some connections obsolete. + */ + bool removeIllegalConnections(); + + //============================================================================== + /** A special number that represents the midi channel of a node. + + This is used as a channel index value if you want to refer to the midi input + or output instead of an audio channel. + */ + static const int midiChannelIndex; + + + //============================================================================== + /** A special type of AudioProcessor that can live inside an AudioProcessorGraph + in order to use the audio that comes into and out of the graph itself. + + If you create an AudioGraphIOProcessor in "input" mode, it will act as a + node in the graph which delivers the audio that is coming into the parent + graph. This allows you to stream the data to other nodes and process the + incoming audio. + + Likewise, one of these in "output" mode can be sent data which it will add to + the sum of data being sent to the graph's output. + + @see AudioProcessorGraph + */ + class AudioGraphIOProcessor : public AudioPluginInstance + { + public: + /** Specifies the mode in which this processor will operate. + */ + enum IODeviceType + { + audioInputNode, /**< In this mode, the processor has output channels + representing all the audio input channels that are + coming into its parent audio graph. */ + audioOutputNode, /**< In this mode, the processor has input channels + representing all the audio output channels that are + going out of its parent audio graph. */ + midiInputNode, /**< In this mode, the processor has a midi output which + delivers the same midi data that is arriving at its + parent graph. */ + midiOutputNode /**< In this mode, the processor has a midi input and + any data sent to it will be passed out of the parent + graph. */ + }; + + //============================================================================== + /** Returns the mode of this processor. */ + IODeviceType getType() const throw() { return type; } + + /** Returns the parent graph to which this processor belongs, or 0 if it + hasn't yet been added to one. */ + AudioProcessorGraph* getParentGraph() const throw() { return graph; } + + /** True if this is an audio or midi input. */ + bool isInput() const throw(); + /** True if this is an audio or midi output. */ + bool isOutput() const throw(); + + //============================================================================== + AudioGraphIOProcessor (const IODeviceType type); + ~AudioGraphIOProcessor(); + + const String getName() const; + void fillInPluginDescription (PluginDescription& d) const; + + void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); + void releaseResources(); + void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + + const String getInputChannelName (const int channelIndex) const; + const String getOutputChannelName (const int channelIndex) const; + bool isInputChannelStereoPair (int index) const; + bool isOutputChannelStereoPair (int index) const; + bool acceptsMidi() const; + bool producesMidi() const; + + AudioProcessorEditor* createEditor(); + + int getNumParameters(); + const String getParameterName (int); + float getParameter (int); + const String getParameterText (int); + void setParameter (int, float); + + int getNumPrograms(); + int getCurrentProgram(); + void setCurrentProgram (int); + const String getProgramName (int); + void changeProgramName (int, const String&); + + void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); + void setStateInformation (const void* data, int sizeInBytes); + + /** @internal */ + void setParentGraph (AudioProcessorGraph* const graph) throw(); + + juce_UseDebuggingNewOperator + + private: + const IODeviceType type; + AudioProcessorGraph* graph; + + AudioGraphIOProcessor (const AudioGraphIOProcessor&); + const AudioGraphIOProcessor& operator= (const AudioGraphIOProcessor&); + }; + + //============================================================================== + // AudioProcessor methods: + + const String getName() const; + + void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); + void releaseResources(); + void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + + const String getInputChannelName (const int channelIndex) const; + const String getOutputChannelName (const int channelIndex) const; + bool isInputChannelStereoPair (int index) const; + bool isOutputChannelStereoPair (int index) const; + + bool acceptsMidi() const; + bool producesMidi() const; + + AudioProcessorEditor* createEditor() { return 0; } + + int getNumParameters() { return 0; } + const String getParameterName (int) { return String::empty; } + float getParameter (int) { return 0; } + const String getParameterText (int) { return String::empty; } + void setParameter (int, float) { } + + int getNumPrograms() { return 0; } + int getCurrentProgram() { return 0; } + void setCurrentProgram (int) { } + const String getProgramName (int) { return String::empty; } + void changeProgramName (int, const String&) { } + + void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); + void setStateInformation (const void* data, int sizeInBytes); + + /** @internal */ + void handleAsyncUpdate(); + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + ReferenceCountedArray nodes; + OwnedArray connections; + int lastNodeId; + AudioSampleBuffer renderingBuffers; + OwnedArray midiBuffers; + + CriticalSection renderLock; + VoidArray renderingOps; + + friend class AudioGraphIOProcessor; + AudioSampleBuffer* currentAudioInputBuffer; + AudioSampleBuffer currentAudioOutputBuffer; + MidiBuffer* currentMidiInputBuffer; + MidiBuffer currentMidiOutputBuffer; + + void clearRenderingSequence(); + void buildRenderingSequence(); + + bool isAnInputTo (const uint32 possibleInputId, + const uint32 possibleDestinationId, + const int recursionCheck) const throw(); + + AudioProcessorGraph (const AudioProcessorGraph&); + const AudioProcessorGraph& operator= (const AudioProcessorGraph&); +}; + + +#endif // __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ diff --git a/src/juce_appframework/gui/components/controls/juce_ComboBox.cpp b/src/juce_appframework/gui/components/controls/juce_ComboBox.cpp index 25f2658f17..9f2521b66f 100644 --- a/src/juce_appframework/gui/components/controls/juce_ComboBox.cpp +++ b/src/juce_appframework/gui/components/controls/juce_ComboBox.cpp @@ -549,7 +549,7 @@ void ComboBox::showPopup() else if (item->isHeading) menu.addSectionHeader (item->name); else - menu.addItem (item->itemId, item->name, + menu.addItem (item->itemId, item->name, item->isEnabled, item->itemId == currentId); } diff --git a/src/juce_appframework/gui/components/filebrowser/juce_DirectoryContentsList.cpp b/src/juce_appframework/gui/components/filebrowser/juce_DirectoryContentsList.cpp index 57c6681604..46281c7838 100644 --- a/src/juce_appframework/gui/components/filebrowser/juce_DirectoryContentsList.cpp +++ b/src/juce_appframework/gui/components/filebrowser/juce_DirectoryContentsList.cpp @@ -37,7 +37,7 @@ BEGIN_JUCE_NAMESPACE #include "../../graphics/imaging/juce_ImageCache.h" void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile, - bool* isDirectory, bool* isHidden, int64* fileSize, Time* modTime, + bool* isDirectory, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw(); bool juce_findFileNext (void* handle, String& resultFile, bool* isDirectory, bool* isHidden, int64* fileSize, diff --git a/src/juce_appframework/gui/components/windows/juce_ComponentPeer.h b/src/juce_appframework/gui/components/windows/juce_ComponentPeer.h index 2c3c3c3efa..b9c810221a 100644 --- a/src/juce_appframework/gui/components/windows/juce_ComponentPeer.h +++ b/src/juce_appframework/gui/components/windows/juce_ComponentPeer.h @@ -82,7 +82,7 @@ public: do its own repainting, but only to repaint when the performAnyPendingRepaintsNow() method is called. */ windowIsSemiTransparent = (1 << 31) /**< Not intended for public use - makes a window transparent. */ - + }; //============================================================================== diff --git a/src/juce_appframework/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp b/src/juce_appframework/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp index 623258c983..abcb22d57e 100644 --- a/src/juce_appframework/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp +++ b/src/juce_appframework/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp @@ -1,344 +1,344 @@ -/* - ============================================================================== - - 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 "../../../../../juce_core/basics/juce_StandardHeader.h" - -#ifdef _MSC_VER - #pragma warning (push) - #pragma warning (disable: 4390 4611) -#endif - -namespace zlibNamespace -{ - #undef OS_CODE - #undef fdopen - #include "../../../../../juce_core/io/streams/zlib/zlib.h" - #undef OS_CODE -} - -namespace pnglibNamespace -{ - using namespace zlibNamespace; - using ::malloc; - using ::free; - - extern "C" - { - using ::abs; - #define PNG_INTERNAL - #define NO_DUMMY_DECL - #define PNG_SETJMP_NOT_SUPPORTED - - #include "pnglib/png.h" - #include "pnglib/pngconf.h" - - #define PNG_NO_EXTERN - #include "pnglib/png.c" - #include "pnglib/pngerror.c" - #include "pnglib/pngget.c" - #include "pnglib/pngmem.c" - #include "pnglib/pngread.c" - #include "pnglib/pngpread.c" - #include "pnglib/pngrio.c" - #include "pnglib/pngrtran.c" - #include "pnglib/pngrutil.c" - #include "pnglib/pngset.c" - #include "pnglib/pngtrans.c" - #include "pnglib/pngwio.c" - #include "pnglib/pngwrite.c" - #include "pnglib/pngwtran.c" - #include "pnglib/pngwutil.c" - } -} - -#ifdef _MSC_VER - #pragma warning (pop) -#endif - -BEGIN_JUCE_NAMESPACE - - -#include "../juce_Image.h" -#include "../../../../../juce_core/io/juce_InputStream.h" -#include "../../../../../juce_core/io/juce_OutputStream.h" -#include "../../colour/juce_PixelFormats.h" - -using namespace pnglibNamespace; -using ::malloc; -using ::free; - -//============================================================================== -static void pngReadCallback (png_structp pngReadStruct, png_bytep data, png_size_t length) throw() -{ - InputStream* const in = (InputStream*) png_get_io_ptr (pngReadStruct); - in->read (data, (int) length); -} - -struct PNGErrorStruct {}; - -static void pngErrorCallback (png_structp, png_const_charp) -{ - throw PNGErrorStruct(); -} - -//============================================================================== -Image* juce_loadPNGImageFromStream (InputStream& in) throw() -{ - Image* image = 0; - - png_structp pngReadStruct; - png_infop pngInfoStruct; - - pngReadStruct = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); - - if (pngReadStruct != 0) - { - pngInfoStruct = png_create_info_struct (pngReadStruct); - - if (pngInfoStruct == 0) - { - png_destroy_read_struct (&pngReadStruct, 0, 0); - return 0; - } - - png_set_error_fn (pngReadStruct, 0, pngErrorCallback, pngErrorCallback); - - // read the header.. - png_set_read_fn (pngReadStruct, &in, pngReadCallback); - - png_uint_32 width, height; - int bitDepth, colorType, interlaceType; - - try - { - png_read_info (pngReadStruct, pngInfoStruct); - - png_get_IHDR (pngReadStruct, pngInfoStruct, - &width, &height, - &bitDepth, &colorType, - &interlaceType, 0, 0); - } - catch (...) - { - png_destroy_read_struct (&pngReadStruct, 0, 0); - return 0; - } - - if (bitDepth == 16) - png_set_strip_16 (pngReadStruct); - - if (colorType == PNG_COLOR_TYPE_PALETTE) - png_set_expand (pngReadStruct); - - if (bitDepth < 8) - png_set_expand (pngReadStruct); - - if (png_get_valid (pngReadStruct, pngInfoStruct, PNG_INFO_tRNS)) - png_set_expand (pngReadStruct); - - if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb (pngReadStruct); - - png_set_add_alpha (pngReadStruct, 0xff, PNG_FILLER_AFTER); - - const bool hasAlphaChan = (colorType & PNG_COLOR_MASK_ALPHA) != 0 - || pngInfoStruct->num_trans > 0; - - // Load the image into a temp buffer in the pnglib format.. - uint8* const tempBuffer = (uint8*) juce_malloc (height * (width << 2)); - - png_bytepp rows = (png_bytepp) juce_malloc (sizeof (png_bytep) * height); - int y; - for (y = (int) height; --y >= 0;) - rows[y] = (png_bytep) (tempBuffer + (width << 2) * y); - - bool crashed = false; - - try - { - png_read_image (pngReadStruct, rows); - png_read_end (pngReadStruct, pngInfoStruct); - } - catch (...) - { - crashed = true; - } - - juce_free (rows); - png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0); - - if (crashed) - return 0; - - // now convert the data to a juce image format.. - image = new Image (hasAlphaChan ? Image::ARGB : Image::RGB, - width, height, hasAlphaChan); - - int stride, pixelStride; - uint8* const pixels = image->lockPixelDataReadWrite (0, 0, width, height, stride, pixelStride); - uint8* srcRow = tempBuffer; - uint8* destRow = pixels; - - for (y = 0; y < (int) height; ++y) - { - const uint8* src = srcRow; - srcRow += (width << 2); - uint8* dest = destRow; - destRow += stride; - - if (hasAlphaChan) - { - for (int i = width; --i >= 0;) - { - ((PixelARGB*) dest)->setARGB (src[3], src[0], src[1], src[2]); - ((PixelARGB*) dest)->premultiply(); - dest += pixelStride; - src += 4; - } - } - else - { - for (int i = width; --i >= 0;) - { - ((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]); - dest += pixelStride; - src += 4; - } - } - } - - image->releasePixelDataReadWrite (pixels); - juce_free (tempBuffer); - } - - return image; -} - -//============================================================================== -static void pngWriteDataCallback (png_structp png_ptr, png_bytep data, png_size_t length) throw() -{ - OutputStream* const out = (OutputStream*) png_ptr->io_ptr; - - const bool ok = out->write (data, length); - - (void) ok; - jassert (ok); -} - -bool juce_writePNGImageToStream (const Image& image, OutputStream& out) throw() -{ - const int width = image.getWidth(); - const int height = image.getHeight(); - - png_structp pngWriteStruct = png_create_write_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); - - if (pngWriteStruct == 0) - return false; - - png_infop pngInfoStruct = png_create_info_struct (pngWriteStruct); - - if (pngInfoStruct == 0) - { - png_destroy_write_struct (&pngWriteStruct, (png_infopp) 0); - return false; - } - - png_set_write_fn (pngWriteStruct, &out, pngWriteDataCallback, 0); - - png_set_IHDR (pngWriteStruct, pngInfoStruct, width, height, 8, - image.hasAlphaChannel() ? PNG_COLOR_TYPE_RGB_ALPHA - : PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, - PNG_FILTER_TYPE_BASE); - - png_bytep rowData = (png_bytep) juce_malloc (width * 4 * sizeof (png_byte)); - - png_color_8 sig_bit; - sig_bit.red = 8; - sig_bit.green = 8; - sig_bit.blue = 8; - sig_bit.alpha = 8; - png_set_sBIT (pngWriteStruct, pngInfoStruct, &sig_bit); - - png_write_info (pngWriteStruct, pngInfoStruct); - - png_set_shift (pngWriteStruct, &sig_bit); - png_set_packing (pngWriteStruct); - - for (int y = 0; y < height; ++y) - { - uint8* dst = (uint8*) rowData; - int stride, pixelStride; - const uint8* pixels = image.lockPixelDataReadOnly (0, y, width, 1, stride, pixelStride); - const uint8* src = pixels; - - if (image.hasAlphaChannel()) - { - for (int i = width; --i >= 0;) - { - PixelARGB p (*(const PixelARGB*) src); - p.unpremultiply(); - - *dst++ = p.getRed(); - *dst++ = p.getGreen(); - *dst++ = p.getBlue(); - *dst++ = p.getAlpha(); - src += pixelStride; - } - } - else - { - for (int i = width; --i >= 0;) - { - *dst++ = ((const PixelRGB*) src)->getRed(); - *dst++ = ((const PixelRGB*) src)->getGreen(); - *dst++ = ((const PixelRGB*) src)->getBlue(); - src += pixelStride; - } - } - - png_write_rows (pngWriteStruct, &rowData, 1); - image.releasePixelDataReadOnly (pixels); - } - - juce_free (rowData); - - png_write_end (pngWriteStruct, pngInfoStruct); - png_destroy_write_struct (&pngWriteStruct, &pngInfoStruct); - - out.flush(); - - return true; -} - - -END_JUCE_NAMESPACE +/* + ============================================================================== + + 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 "../../../../../juce_core/basics/juce_StandardHeader.h" + +#ifdef _MSC_VER + #pragma warning (push) + #pragma warning (disable: 4390 4611) +#endif + +namespace zlibNamespace +{ + #undef OS_CODE + #undef fdopen + #include "../../../../../juce_core/io/streams/zlib/zlib.h" + #undef OS_CODE +} + +namespace pnglibNamespace +{ + using namespace zlibNamespace; + using ::malloc; + using ::free; + + extern "C" + { + using ::abs; + #define PNG_INTERNAL + #define NO_DUMMY_DECL + #define PNG_SETJMP_NOT_SUPPORTED + + #include "pnglib/png.h" + #include "pnglib/pngconf.h" + + #define PNG_NO_EXTERN + #include "pnglib/png.c" + #include "pnglib/pngerror.c" + #include "pnglib/pngget.c" + #include "pnglib/pngmem.c" + #include "pnglib/pngread.c" + #include "pnglib/pngpread.c" + #include "pnglib/pngrio.c" + #include "pnglib/pngrtran.c" + #include "pnglib/pngrutil.c" + #include "pnglib/pngset.c" + #include "pnglib/pngtrans.c" + #include "pnglib/pngwio.c" + #include "pnglib/pngwrite.c" + #include "pnglib/pngwtran.c" + #include "pnglib/pngwutil.c" + } +} + +#ifdef _MSC_VER + #pragma warning (pop) +#endif + +BEGIN_JUCE_NAMESPACE + + +#include "../juce_Image.h" +#include "../../../../../juce_core/io/juce_InputStream.h" +#include "../../../../../juce_core/io/juce_OutputStream.h" +#include "../../colour/juce_PixelFormats.h" + +using namespace pnglibNamespace; +using ::malloc; +using ::free; + +//============================================================================== +static void pngReadCallback (png_structp pngReadStruct, png_bytep data, png_size_t length) throw() +{ + InputStream* const in = (InputStream*) png_get_io_ptr (pngReadStruct); + in->read (data, (int) length); +} + +struct PNGErrorStruct {}; + +static void pngErrorCallback (png_structp, png_const_charp) +{ + throw PNGErrorStruct(); +} + +//============================================================================== +Image* juce_loadPNGImageFromStream (InputStream& in) throw() +{ + Image* image = 0; + + png_structp pngReadStruct; + png_infop pngInfoStruct; + + pngReadStruct = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); + + if (pngReadStruct != 0) + { + pngInfoStruct = png_create_info_struct (pngReadStruct); + + if (pngInfoStruct == 0) + { + png_destroy_read_struct (&pngReadStruct, 0, 0); + return 0; + } + + png_set_error_fn (pngReadStruct, 0, pngErrorCallback, pngErrorCallback); + + // read the header.. + png_set_read_fn (pngReadStruct, &in, pngReadCallback); + + png_uint_32 width, height; + int bitDepth, colorType, interlaceType; + + try + { + png_read_info (pngReadStruct, pngInfoStruct); + + png_get_IHDR (pngReadStruct, pngInfoStruct, + &width, &height, + &bitDepth, &colorType, + &interlaceType, 0, 0); + } + catch (...) + { + png_destroy_read_struct (&pngReadStruct, 0, 0); + return 0; + } + + if (bitDepth == 16) + png_set_strip_16 (pngReadStruct); + + if (colorType == PNG_COLOR_TYPE_PALETTE) + png_set_expand (pngReadStruct); + + if (bitDepth < 8) + png_set_expand (pngReadStruct); + + if (png_get_valid (pngReadStruct, pngInfoStruct, PNG_INFO_tRNS)) + png_set_expand (pngReadStruct); + + if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb (pngReadStruct); + + png_set_add_alpha (pngReadStruct, 0xff, PNG_FILLER_AFTER); + + const bool hasAlphaChan = (colorType & PNG_COLOR_MASK_ALPHA) != 0 + || pngInfoStruct->num_trans > 0; + + // Load the image into a temp buffer in the pnglib format.. + uint8* const tempBuffer = (uint8*) juce_malloc (height * (width << 2)); + + png_bytepp rows = (png_bytepp) juce_malloc (sizeof (png_bytep) * height); + int y; + for (y = (int) height; --y >= 0;) + rows[y] = (png_bytep) (tempBuffer + (width << 2) * y); + + bool crashed = false; + + try + { + png_read_image (pngReadStruct, rows); + png_read_end (pngReadStruct, pngInfoStruct); + } + catch (...) + { + crashed = true; + } + + juce_free (rows); + png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0); + + if (crashed) + return 0; + + // now convert the data to a juce image format.. + image = new Image (hasAlphaChan ? Image::ARGB : Image::RGB, + width, height, hasAlphaChan); + + int stride, pixelStride; + uint8* const pixels = image->lockPixelDataReadWrite (0, 0, width, height, stride, pixelStride); + uint8* srcRow = tempBuffer; + uint8* destRow = pixels; + + for (y = 0; y < (int) height; ++y) + { + const uint8* src = srcRow; + srcRow += (width << 2); + uint8* dest = destRow; + destRow += stride; + + if (hasAlphaChan) + { + for (int i = width; --i >= 0;) + { + ((PixelARGB*) dest)->setARGB (src[3], src[0], src[1], src[2]); + ((PixelARGB*) dest)->premultiply(); + dest += pixelStride; + src += 4; + } + } + else + { + for (int i = width; --i >= 0;) + { + ((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]); + dest += pixelStride; + src += 4; + } + } + } + + image->releasePixelDataReadWrite (pixels); + juce_free (tempBuffer); + } + + return image; +} + +//============================================================================== +static void pngWriteDataCallback (png_structp png_ptr, png_bytep data, png_size_t length) throw() +{ + OutputStream* const out = (OutputStream*) png_ptr->io_ptr; + + const bool ok = out->write (data, length); + + (void) ok; + jassert (ok); +} + +bool juce_writePNGImageToStream (const Image& image, OutputStream& out) throw() +{ + const int width = image.getWidth(); + const int height = image.getHeight(); + + png_structp pngWriteStruct = png_create_write_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); + + if (pngWriteStruct == 0) + return false; + + png_infop pngInfoStruct = png_create_info_struct (pngWriteStruct); + + if (pngInfoStruct == 0) + { + png_destroy_write_struct (&pngWriteStruct, (png_infopp) 0); + return false; + } + + png_set_write_fn (pngWriteStruct, &out, pngWriteDataCallback, 0); + + png_set_IHDR (pngWriteStruct, pngInfoStruct, width, height, 8, + image.hasAlphaChannel() ? PNG_COLOR_TYPE_RGB_ALPHA + : PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + + png_bytep rowData = (png_bytep) juce_malloc (width * 4 * sizeof (png_byte)); + + png_color_8 sig_bit; + sig_bit.red = 8; + sig_bit.green = 8; + sig_bit.blue = 8; + sig_bit.alpha = 8; + png_set_sBIT (pngWriteStruct, pngInfoStruct, &sig_bit); + + png_write_info (pngWriteStruct, pngInfoStruct); + + png_set_shift (pngWriteStruct, &sig_bit); + png_set_packing (pngWriteStruct); + + for (int y = 0; y < height; ++y) + { + uint8* dst = (uint8*) rowData; + int stride, pixelStride; + const uint8* pixels = image.lockPixelDataReadOnly (0, y, width, 1, stride, pixelStride); + const uint8* src = pixels; + + if (image.hasAlphaChannel()) + { + for (int i = width; --i >= 0;) + { + PixelARGB p (*(const PixelARGB*) src); + p.unpremultiply(); + + *dst++ = p.getRed(); + *dst++ = p.getGreen(); + *dst++ = p.getBlue(); + *dst++ = p.getAlpha(); + src += pixelStride; + } + } + else + { + for (int i = width; --i >= 0;) + { + *dst++ = ((const PixelRGB*) src)->getRed(); + *dst++ = ((const PixelRGB*) src)->getGreen(); + *dst++ = ((const PixelRGB*) src)->getBlue(); + src += pixelStride; + } + } + + png_write_rows (pngWriteStruct, &rowData, 1); + image.releasePixelDataReadOnly (pixels); + } + + juce_free (rowData); + + png_write_end (pngWriteStruct, pngInfoStruct); + png_destroy_write_struct (&pngWriteStruct, &pngInfoStruct); + + out.flush(); + + return true; +} + + +END_JUCE_NAMESPACE diff --git a/src/juce_core/cryptography/juce_BlowFish.h b/src/juce_core/cryptography/juce_BlowFish.h index e2eabf8caa..81ba5ea84b 100644 --- a/src/juce_core/cryptography/juce_BlowFish.h +++ b/src/juce_core/cryptography/juce_BlowFish.h @@ -42,8 +42,8 @@ class JUCE_API BlowFish { public: //============================================================================== - /** Creates an object that can encode/decode based on the specified key. - + /** Creates an object that can encode/decode based on the specified key. + The key data can be up to 72 bytes long. */ BlowFish (const uint8* keyData, int keyBytes); diff --git a/src/juce_core/io/files/juce_DirectoryIterator.cpp b/src/juce_core/io/files/juce_DirectoryIterator.cpp index 45268df818..cade4e138e 100644 --- a/src/juce_core/io/files/juce_DirectoryIterator.cpp +++ b/src/juce_core/io/files/juce_DirectoryIterator.cpp @@ -40,7 +40,7 @@ void* juce_findFileStart (const String& directory, const String& wildCard, Strin bool* isDirectory, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw(); bool juce_findFileNext (void* handle, String& resultFile, - bool* isDirectory, bool* isHidden, int64* fileSize, + bool* isDirectory, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw(); void juce_findFileClose (void* handle) throw(); diff --git a/src/juce_core/io/files/juce_File.cpp b/src/juce_core/io/files/juce_File.cpp index 88d98a8508..ae10027260 100644 --- a/src/juce_core/io/files/juce_File.cpp +++ b/src/juce_core/io/files/juce_File.cpp @@ -86,12 +86,12 @@ const String juce_getVolumeLabel (const String& filenameOnVolume, int& volumeSer // juce_firstResultFile gets the name of the file (not the whole pathname) and // the other pointers, if non-null, are set based on the properties of the file. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile, - bool* isDirectory, bool* isHidden, int64* fileSize, Time* modTime, + bool* isDirectory, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw(); // returns false when no more files are found bool juce_findFileNext (void* handle, String& resultFile, - bool* isDirectory, bool* isHidden, int64* fileSize, + bool* isDirectory, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw(); void juce_findFileClose (void* handle) throw(); diff --git a/src/juce_core/io/network/juce_URL.cpp b/src/juce_core/io/network/juce_URL.cpp index a87c617882..2441a77382 100644 --- a/src/juce_core/io/network/juce_URL.cpp +++ b/src/juce_core/io/network/juce_URL.cpp @@ -191,7 +191,7 @@ public: createHeadersAndPostData (url); headers += extraHeaders; - + if (! headers.endsWithChar (T('\n'))) headers << "\r\n"; diff --git a/src/juce_core/io/streams/zlib/inftrees.c b/src/juce_core/io/streams/zlib/inftrees.c index e508719613..dfc0aa73e0 100644 --- a/src/juce_core/io/streams/zlib/inftrees.c +++ b/src/juce_core/io/streams/zlib/inftrees.c @@ -29,9 +29,9 @@ const char inflate_copyright[] = table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ -int inflate_table (codetype type, - unsigned short FAR *lens, - unsigned codes, +int inflate_table (codetype type, + unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work) diff --git a/src/juce_core/io/streams/zlib/trees.c b/src/juce_core/io/streams/zlib/trees.c index d7dc5ab527..91ed766016 100644 --- a/src/juce_core/io/streams/zlib/trees.c +++ b/src/juce_core/io/streams/zlib/trees.c @@ -1167,7 +1167,7 @@ local void bi_windup (deflate_state *s) * Copy a stored block, storing first the length and its * one's complement if requested. */ -local void copy_block(deflate_state *s, +local void copy_block(deflate_state *s, charf *buf, /* the input data */ unsigned len, /* its length */ int header) /* true if block header must be written */ diff --git a/src/juce_core/misc/juce_ZipFile.cpp b/src/juce_core/misc/juce_ZipFile.cpp index 3572892ffc..7f3b212665 100644 --- a/src/juce_core/misc/juce_ZipFile.cpp +++ b/src/juce_core/misc/juce_ZipFile.cpp @@ -81,7 +81,7 @@ public: char buffer [30]; - if (inputStream != 0 + if (inputStream != 0 && inputStream->setPosition (zei.streamOffset) && inputStream->read (buffer, 30) == 30 && littleEndianInt (buffer) == 0x04034b50) diff --git a/src/juce_core/misc/juce_ZipFile.h b/src/juce_core/misc/juce_ZipFile.h index 288725329f..9c3b43bb3b 100644 --- a/src/juce_core/misc/juce_ZipFile.h +++ b/src/juce_core/misc/juce_ZipFile.h @@ -62,7 +62,7 @@ public: ZipFile (const File& file); /** Creates a ZipFile for an input source. - + The inputSource object will be owned by the zip file, which will delete it later when not needed. */ diff --git a/src/juce_core/text/juce_String.h b/src/juce_core/text/juce_String.h index 7cdac55163..136f321c95 100644 --- a/src/juce_core/text/juce_String.h +++ b/src/juce_core/text/juce_String.h @@ -728,7 +728,7 @@ public: This will replace the contents of the string with the output of this formatted printf. - Note that using the %s token with a juce string is probably a bad idea, as + Note that using the %s token with a juce string is probably a bad idea, as this may expect differect encodings on different platforms. @see formatted @@ -740,7 +740,7 @@ public: This will return a string which is the result of a sprintf using the arguments passed-in. - Note that using the %s token with a juce string is probably a bad idea, as + Note that using the %s token with a juce string is probably a bad idea, as this may expect differect encodings on different platforms. @see printf, vprintf @@ -753,7 +753,7 @@ public: formatted printf. Used by other methods, this is public in case it's useful for other purposes where you want to pass a va_list through directly. - Note that using the %s token with a juce string is probably a bad idea, as + Note that using the %s token with a juce string is probably a bad idea, as this may expect differect encodings on different platforms. @see printf, formatted