| @@ -295,7 +295,7 @@ static XmlElement* createNodeXml (AudioProcessorGraph::Node* const node) noexcep | |||||
| } | } | ||||
| XmlElement* e = new XmlElement ("FILTER"); | XmlElement* e = new XmlElement ("FILTER"); | ||||
| e->setAttribute ("uid", (int) node->id); | |||||
| e->setAttribute ("uid", (int) node->nodeId); | |||||
| e->setAttribute ("x", node->properties ["x"].toString()); | e->setAttribute ("x", node->properties ["x"].toString()); | ||||
| e->setAttribute ("y", node->properties ["y"].toString()); | e->setAttribute ("y", node->properties ["y"].toString()); | ||||
| e->setAttribute ("uiLastX", node->properties ["uiLastX"].toString()); | e->setAttribute ("uiLastX", node->properties ["uiLastX"].toString()); | ||||
| @@ -55,7 +55,7 @@ PluginWindow::PluginWindow (Component* const uiComp, | |||||
| void PluginWindow::closeCurrentlyOpenWindowsFor (const uint32 nodeId) | void PluginWindow::closeCurrentlyOpenWindowsFor (const uint32 nodeId) | ||||
| { | { | ||||
| for (int i = activePluginWindows.size(); --i >= 0;) | for (int i = activePluginWindows.size(); --i >= 0;) | ||||
| if (activePluginWindows.getUnchecked(i)->owner->id == nodeId) | |||||
| if (activePluginWindows.getUnchecked(i)->owner->nodeId == nodeId) | |||||
| delete activePluginWindows.getUnchecked(i); | delete activePluginWindows.getUnchecked(i); | ||||
| } | } | ||||
| @@ -839,9 +839,9 @@ void GraphEditorPanel::updateComponents() | |||||
| { | { | ||||
| const AudioProcessorGraph::Node::Ptr f (graph.getNode (i)); | const AudioProcessorGraph::Node::Ptr f (graph.getNode (i)); | ||||
| if (getComponentForFilter (f->id) == 0) | |||||
| if (getComponentForFilter (f->nodeId) == 0) | |||||
| { | { | ||||
| FilterComponent* const comp = new FilterComponent (graph, f->id); | |||||
| FilterComponent* const comp = new FilterComponent (graph, f->nodeId); | |||||
| addAndMakeVisible (comp); | addAndMakeVisible (comp); | ||||
| comp->update(); | comp->update(); | ||||
| } | } | ||||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 53 | #define JUCE_MINOR_VERSION 53 | ||||
| #define JUCE_BUILDNUMBER 73 | |||||
| #define JUCE_BUILDNUMBER 74 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -23112,8 +23112,9 @@ public: | |||||
| /** Returns one of the registered clients. */ | /** Returns one of the registered clients. */ | ||||
| TimeSliceClient* getClient (int index) const; | TimeSliceClient* getClient (int index) const; | ||||
| /** @internal */ | |||||
| #ifndef DOXYGEN | |||||
| void run(); | void run(); | ||||
| #endif | |||||
| private: | private: | ||||
| CriticalSection callbackLock, listLock; | CriticalSection callbackLock, listLock; | ||||
| @@ -33344,8 +33345,7 @@ public: | |||||
| @see MessageManager, DeletedAtShutdown | @see MessageManager, DeletedAtShutdown | ||||
| */ | */ | ||||
| class JUCE_API JUCEApplication : public ApplicationCommandTarget, | |||||
| private ActionListener | |||||
| class JUCE_API JUCEApplication : public ApplicationCommandTarget | |||||
| { | { | ||||
| protected: | protected: | ||||
| @@ -33497,18 +33497,9 @@ public: | |||||
| */ | */ | ||||
| const String getCommandLineParameters() const noexcept { return commandLineParameters; } | const String getCommandLineParameters() const noexcept { return commandLineParameters; } | ||||
| // These are used by the START_JUCE_APPLICATION() macro and aren't for public use. | |||||
| /** @internal */ | |||||
| static int main (const String& commandLine); | |||||
| /** @internal */ | |||||
| static int main (int argc, const char* argv[]); | |||||
| /** @internal */ | |||||
| static void sendUnhandledException (const std::exception* e, const char* sourceFile, int lineNumber); | |||||
| /** Returns true if this executable is running as an app (as opposed to being a plugin | /** Returns true if this executable is running as an app (as opposed to being a plugin | ||||
| or other kind of shared library. */ | or other kind of shared library. */ | ||||
| static inline bool isStandaloneApp() noexcept { return createInstance != 0; } | |||||
| static inline bool isStandaloneApp() noexcept { return createInstance != 0; } | |||||
| /** @internal */ | /** @internal */ | ||||
| ApplicationCommandTarget* getNextCommandTarget(); | ApplicationCommandTarget* getNextCommandTarget(); | ||||
| @@ -33518,26 +33509,28 @@ public: | |||||
| void getAllCommands (Array <CommandID>& commands); | void getAllCommands (Array <CommandID>& commands); | ||||
| /** @internal */ | /** @internal */ | ||||
| bool perform (const InvocationInfo& info); | bool perform (const InvocationInfo& info); | ||||
| /** @internal */ | |||||
| void actionListenerCallback (const String& message); | |||||
| /** @internal */ | |||||
| #ifndef DOXYGEN | |||||
| // The following methods are internal calls - not for public use. | |||||
| static int main (const String& commandLine); | |||||
| static int main (int argc, const char* argv[]); | |||||
| static void sendUnhandledException (const std::exception* e, const char* sourceFile, int lineNumber); | |||||
| bool initialiseApp (const String& commandLine); | bool initialiseApp (const String& commandLine); | ||||
| /** @internal */ | |||||
| int shutdownApp(); | int shutdownApp(); | ||||
| /** @internal */ | |||||
| static void appWillTerminateByForce(); | static void appWillTerminateByForce(); | ||||
| /** @internal */ | |||||
| typedef JUCEApplication* (*CreateInstanceFunction)(); | typedef JUCEApplication* (*CreateInstanceFunction)(); | ||||
| /** @internal */ | |||||
| static CreateInstanceFunction createInstance; | static CreateInstanceFunction createInstance; | ||||
| #endif | |||||
| private: | private: | ||||
| static JUCEApplication* appInstance; | |||||
| String commandLineParameters; | String commandLineParameters; | ||||
| ScopedPointer<InterProcessLock> appLock; | |||||
| ScopedPointer<ActionListener> broadcastCallback; | |||||
| int appReturnValue; | int appReturnValue; | ||||
| bool stillInitialising; | bool stillInitialising; | ||||
| ScopedPointer<InterProcessLock> appLock; | |||||
| static JUCEApplication* appInstance; | |||||
| JUCE_DECLARE_NON_COPYABLE (JUCEApplication); | JUCE_DECLARE_NON_COPYABLE (JUCEApplication); | ||||
| }; | }; | ||||
| @@ -36550,9 +36543,10 @@ public: | |||||
| const Array <int> getPossibleBitDepths(); | const Array <int> getPossibleBitDepths(); | ||||
| bool canDoStereo(); | bool canDoStereo(); | ||||
| bool canDoMono(); | bool canDoMono(); | ||||
| #if JUCE_MAC | |||||
| #if JUCE_MAC | |||||
| bool canHandleFile (const File& fileToTest); | bool canHandleFile (const File& fileToTest); | ||||
| #endif | |||||
| #endif | |||||
| AudioFormatReader* createReaderFor (InputStream* sourceStream, | AudioFormatReader* createReaderFor (InputStream* sourceStream, | ||||
| bool deleteStreamIfOpeningFails); | bool deleteStreamIfOpeningFails); | ||||
| @@ -37224,12 +37218,19 @@ public: | |||||
| */ | */ | ||||
| float getApproximatePeak() const; | float getApproximatePeak() const; | ||||
| /** Reads the approximate min and max levels from a section of the thumbnail. | |||||
| The lowest and highest samples are returned in minValue and maxValue, but obviously | |||||
| because the thumb only stores low-resolution data, these numbers will only be a rough | |||||
| approximation of the true values. | |||||
| */ | |||||
| void getApproximateMinMax (double startTime, double endTime, int channelIndex, | |||||
| float& minValue, float& maxValue) const noexcept; | |||||
| /** Returns the hash code that was set by setSource() or setReader(). */ | /** Returns the hash code that was set by setSource() or setReader(). */ | ||||
| int64 getHashCode() const; | int64 getHashCode() const; | ||||
| #ifndef DOXYGEN | #ifndef DOXYGEN | ||||
| // (this is only public to avoid a VC6 bug) | |||||
| class LevelDataSource; | |||||
| class LevelDataSource; // (this is only public to avoid a VC6 bug) | |||||
| #endif | #endif | ||||
| private: | private: | ||||
| @@ -47098,10 +47099,9 @@ public: | |||||
| public: | public: | ||||
| /** The ID number assigned to this node. | /** The ID number assigned to this node. | ||||
| This is assigned by the graph that owns it, and can't be changed. | This is assigned by the graph that owns it, and can't be changed. | ||||
| */ | */ | ||||
| const uint32 id; | |||||
| const uint32 nodeId; | |||||
| /** The actual processor object that this node represents. */ | /** The actual processor object that this node represents. */ | ||||
| AudioProcessor* getProcessor() const noexcept { return processor; } | AudioProcessor* getProcessor() const noexcept { return processor; } | ||||
| @@ -47125,7 +47125,7 @@ public: | |||||
| const ScopedPointer<AudioProcessor> processor; | const ScopedPointer<AudioProcessor> processor; | ||||
| bool isPrepared; | bool isPrepared; | ||||
| Node (uint32 id, AudioProcessor* processor); | |||||
| Node (uint32 nodeId, AudioProcessor* processor) noexcept; | |||||
| void prepare (double sampleRate, int blockSize, AudioProcessorGraph* graph); | void prepare (double sampleRate, int blockSize, AudioProcessorGraph* graph); | ||||
| void unprepare(); | void unprepare(); | ||||
| @@ -47141,6 +47141,9 @@ public: | |||||
| { | { | ||||
| public: | public: | ||||
| Connection (uint32 sourceNodeId, int sourceChannelIndex, | |||||
| uint32 destNodeId, int destChannelIndex) noexcept; | |||||
| /** The ID number of the node which is the input source for this connection. | /** The ID number of the node which is the input source for this connection. | ||||
| @see AudioProcessorGraph::getNodeForId | @see AudioProcessorGraph::getNodeForId | ||||
| */ | */ | ||||
| @@ -48766,8 +48769,7 @@ public: | |||||
| @returns the value that the callback function returns. | @returns the value that the callback function returns. | ||||
| @see MessageManagerLock | @see MessageManagerLock | ||||
| */ | */ | ||||
| void* callFunctionOnMessageThread (MessageCallbackFunction* callback, | |||||
| void* userData); | |||||
| void* callFunctionOnMessageThread (MessageCallbackFunction* callback, void* userData); | |||||
| /** Returns true if the caller-thread is the message thread. */ | /** Returns true if the caller-thread is the message thread. */ | ||||
| bool isThisTheMessageThread() const noexcept; | bool isThisTheMessageThread() const noexcept; | ||||
| @@ -48815,12 +48817,12 @@ public: | |||||
| /** Deregisters a broadcast listener. */ | /** Deregisters a broadcast listener. */ | ||||
| void deregisterBroadcastListener (ActionListener* listener); | void deregisterBroadcastListener (ActionListener* listener); | ||||
| /** @internal */ | |||||
| #ifndef DOXYGEN | |||||
| // Internal methods - do not use! | |||||
| void deliverMessage (Message*); | void deliverMessage (Message*); | ||||
| /** @internal */ | |||||
| void deliverBroadcastMessage (const String&); | void deliverBroadcastMessage (const String&); | ||||
| /** @internal */ | |||||
| ~MessageManager() noexcept; | ~MessageManager() noexcept; | ||||
| #endif | |||||
| private: | private: | ||||
| @@ -48946,7 +48948,6 @@ public: | |||||
| ~MessageManagerLock() noexcept; | ~MessageManagerLock() noexcept; | ||||
| /** Returns true if the lock was successfully acquired. | /** Returns true if the lock was successfully acquired. | ||||
| (See the constructor that takes a Thread for more info). | (See the constructor that takes a Thread for more info). | ||||
| */ | */ | ||||
| bool lockWasGained() const noexcept { return locked; } | bool lockWasGained() const noexcept { return locked; } | ||||
| @@ -56566,7 +56567,7 @@ protected: | |||||
| /** @internal */ | /** @internal */ | ||||
| int getDesktopWindowStyleFlags() const; | int getDesktopWindowStyleFlags() const; | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| /** Overridden to warn people about adding components directly to this component | /** Overridden to warn people about adding components directly to this component | ||||
| instead of using setContentOwned(). | instead of using setContentOwned(). | ||||
| @@ -56581,7 +56582,7 @@ protected: | |||||
| a base-class method call to Component::addAndMakeVisible(), to side-step this warning. | a base-class method call to Component::addAndMakeVisible(), to side-step this warning. | ||||
| */ | */ | ||||
| void addAndMakeVisible (Component* child, int zOrder = -1); | void addAndMakeVisible (Component* child, int zOrder = -1); | ||||
| #endif | |||||
| #endif | |||||
| ScopedPointer <ResizableCornerComponent> resizableCorner; | ScopedPointer <ResizableCornerComponent> resizableCorner; | ||||
| ScopedPointer <ResizableBorderComponent> resizableBorder; | ScopedPointer <ResizableBorderComponent> resizableBorder; | ||||
| @@ -59438,6 +59439,7 @@ public: | |||||
| and feel class how this is used. */ | and feel class how this is used. */ | ||||
| }; | }; | ||||
| #ifndef DOXYGEN | |||||
| /** @internal */ | /** @internal */ | ||||
| void paint (Graphics& g); | void paint (Graphics& g); | ||||
| /** @internal */ | /** @internal */ | ||||
| @@ -59460,6 +59462,7 @@ public: | |||||
| void parentHierarchyChanged(); | void parentHierarchyChanged(); | ||||
| /** @internal */ | /** @internal */ | ||||
| const Rectangle<int> getTitleBarArea(); | const Rectangle<int> getTitleBarArea(); | ||||
| #endif | |||||
| private: | private: | ||||
| @@ -66942,8 +66945,9 @@ public: | |||||
| void removeListener (Listener* listenerToRemove); | void removeListener (Listener* listenerToRemove); | ||||
| protected: | protected: | ||||
| /** @internal */ | |||||
| #ifndef DOXYGEN | |||||
| CameraDevice (const String& name, int index); | CameraDevice (const String& name, int index); | ||||
| #endif | |||||
| private: | private: | ||||
| void* internal; | void* internal; | ||||
| @@ -38,6 +38,22 @@ BEGIN_JUCE_NAMESPACE | |||||
| extern void juce_initialiseMacMainMenu(); | extern void juce_initialiseMacMainMenu(); | ||||
| #endif | #endif | ||||
| //============================================================================== | |||||
| class AppBroadcastCallback : public ActionListener | |||||
| { | |||||
| public: | |||||
| AppBroadcastCallback() { MessageManager::getInstance()->registerBroadcastListener (this); } | |||||
| ~AppBroadcastCallback() { MessageManager::getInstance()->deregisterBroadcastListener (this); } | |||||
| void actionListenerCallback (const String& message) | |||||
| { | |||||
| JUCEApplication* const app = JUCEApplication::getInstance(); | |||||
| if (app != 0 && message.startsWith (app->getApplicationName() + "/")) | |||||
| app->anotherInstanceStarted (message.substring (app->getApplicationName().length() + 1)); | |||||
| } | |||||
| }; | |||||
| //============================================================================== | //============================================================================== | ||||
| JUCEApplication::JUCEApplication() | JUCEApplication::JUCEApplication() | ||||
| : appReturnValue (0), | : appReturnValue (0), | ||||
| @@ -87,12 +103,6 @@ void JUCEApplication::setApplicationReturnValue (const int newReturnValue) noexc | |||||
| appReturnValue = newReturnValue; | appReturnValue = newReturnValue; | ||||
| } | } | ||||
| void JUCEApplication::actionListenerCallback (const String& message) | |||||
| { | |||||
| if (message.startsWith (getApplicationName() + "/")) | |||||
| anotherInstanceStarted (message.substring (getApplicationName().length() + 1)); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| void JUCEApplication::unhandledException (const std::exception*, | void JUCEApplication::unhandledException (const std::exception*, | ||||
| const String&, | const String&, | ||||
| @@ -149,7 +159,7 @@ bool JUCEApplication::initialiseApp (const String& commandLine) | |||||
| { | { | ||||
| commandLineParameters = commandLine.trim(); | commandLineParameters = commandLine.trim(); | ||||
| #if ! JUCE_IOS | |||||
| #if ! JUCE_IOS | |||||
| jassert (appLock == nullptr); // initialiseApp must only be called once! | jassert (appLock == nullptr); // initialiseApp must only be called once! | ||||
| if (! moreThanOneInstanceAllowed()) | if (! moreThanOneInstanceAllowed()) | ||||
| @@ -165,17 +175,18 @@ bool JUCEApplication::initialiseApp (const String& commandLine) | |||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| #endif | |||||
| #endif | |||||
| // let the app do its setting-up.. | // let the app do its setting-up.. | ||||
| initialise (commandLineParameters); | initialise (commandLineParameters); | ||||
| #if JUCE_MAC | |||||
| #if JUCE_MAC | |||||
| juce_initialiseMacMainMenu(); // needs to be called after the app object has created, to get its name | juce_initialiseMacMainMenu(); // needs to be called after the app object has created, to get its name | ||||
| #endif | |||||
| #endif | |||||
| // register for broadcast new app messages | |||||
| MessageManager::getInstance()->registerBroadcastListener (this); | |||||
| #if ! JUCE_IOS | |||||
| broadcastCallback = new AppBroadcastCallback(); | |||||
| #endif | |||||
| stillInitialising = false; | stillInitialising = false; | ||||
| return true; | return true; | ||||
| @@ -185,7 +196,7 @@ int JUCEApplication::shutdownApp() | |||||
| { | { | ||||
| jassert (appInstance == this); | jassert (appInstance == this); | ||||
| MessageManager::getInstance()->deregisterBroadcastListener (this); | |||||
| broadcastCallback = nullptr; | |||||
| JUCE_TRY | JUCE_TRY | ||||
| { | { | ||||
| @@ -249,20 +260,20 @@ int JUCEApplication::main (int argc, const char* argv[]) | |||||
| { | { | ||||
| JUCE_AUTORELEASEPOOL | JUCE_AUTORELEASEPOOL | ||||
| #if ! JUCE_WINDOWS | |||||
| #if ! JUCE_WINDOWS | |||||
| jassert (createInstance != nullptr); | jassert (createInstance != nullptr); | ||||
| juce_Argv0 = argv[0]; | juce_Argv0 = argv[0]; | ||||
| #endif | |||||
| #endif | |||||
| #if JUCE_IOS | |||||
| #if JUCE_IOS | |||||
| return juce_iOSMain (argc, argv); | return juce_iOSMain (argc, argv); | ||||
| #else | |||||
| #else | |||||
| String cmd; | String cmd; | ||||
| for (int i = 1; i < argc; ++i) | for (int i = 1; i < argc; ++i) | ||||
| cmd << argv[i] << ' '; | cmd << argv[i] << ' '; | ||||
| return JUCEApplication::main (cmd); | return JUCEApplication::main (cmd); | ||||
| #endif | |||||
| #endif | |||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -87,8 +87,7 @@ | |||||
| @see MessageManager, DeletedAtShutdown | @see MessageManager, DeletedAtShutdown | ||||
| */ | */ | ||||
| class JUCE_API JUCEApplication : public ApplicationCommandTarget, | |||||
| private ActionListener | |||||
| class JUCE_API JUCEApplication : public ApplicationCommandTarget | |||||
| { | { | ||||
| protected: | protected: | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -244,20 +243,11 @@ public: | |||||
| */ | */ | ||||
| const String getCommandLineParameters() const noexcept { return commandLineParameters; } | const String getCommandLineParameters() const noexcept { return commandLineParameters; } | ||||
| //============================================================================== | |||||
| // These are used by the START_JUCE_APPLICATION() macro and aren't for public use. | |||||
| /** @internal */ | |||||
| static int main (const String& commandLine); | |||||
| /** @internal */ | |||||
| static int main (int argc, const char* argv[]); | |||||
| /** @internal */ | |||||
| static void sendUnhandledException (const std::exception* e, const char* sourceFile, int lineNumber); | |||||
| /** Returns true if this executable is running as an app (as opposed to being a plugin | /** Returns true if this executable is running as an app (as opposed to being a plugin | ||||
| or other kind of shared library. */ | or other kind of shared library. */ | ||||
| static inline bool isStandaloneApp() noexcept { return createInstance != 0; } | |||||
| static inline bool isStandaloneApp() noexcept { return createInstance != 0; } | |||||
| //============================================================================== | |||||
| /** @internal */ | /** @internal */ | ||||
| ApplicationCommandTarget* getNextCommandTarget(); | ApplicationCommandTarget* getNextCommandTarget(); | ||||
| /** @internal */ | /** @internal */ | ||||
| @@ -266,26 +256,29 @@ public: | |||||
| void getAllCommands (Array <CommandID>& commands); | void getAllCommands (Array <CommandID>& commands); | ||||
| /** @internal */ | /** @internal */ | ||||
| bool perform (const InvocationInfo& info); | bool perform (const InvocationInfo& info); | ||||
| /** @internal */ | |||||
| void actionListenerCallback (const String& message); | |||||
| /** @internal */ | |||||
| //============================================================================== | |||||
| #ifndef DOXYGEN | |||||
| // The following methods are internal calls - not for public use. | |||||
| static int main (const String& commandLine); | |||||
| static int main (int argc, const char* argv[]); | |||||
| static void sendUnhandledException (const std::exception* e, const char* sourceFile, int lineNumber); | |||||
| bool initialiseApp (const String& commandLine); | bool initialiseApp (const String& commandLine); | ||||
| /** @internal */ | |||||
| int shutdownApp(); | int shutdownApp(); | ||||
| /** @internal */ | |||||
| static void appWillTerminateByForce(); | static void appWillTerminateByForce(); | ||||
| /** @internal */ | |||||
| typedef JUCEApplication* (*CreateInstanceFunction)(); | typedef JUCEApplication* (*CreateInstanceFunction)(); | ||||
| /** @internal */ | |||||
| static CreateInstanceFunction createInstance; | static CreateInstanceFunction createInstance; | ||||
| #endif | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| static JUCEApplication* appInstance; | |||||
| String commandLineParameters; | String commandLineParameters; | ||||
| ScopedPointer<InterProcessLock> appLock; | |||||
| ScopedPointer<ActionListener> broadcastCallback; | |||||
| int appReturnValue; | int appReturnValue; | ||||
| bool stillInitialising; | bool stillInitialising; | ||||
| ScopedPointer<InterProcessLock> appLock; | |||||
| static JUCEApplication* appInstance; | |||||
| JUCE_DECLARE_NON_COPYABLE (JUCEApplication); | JUCE_DECLARE_NON_COPYABLE (JUCEApplication); | ||||
| }; | }; | ||||
| @@ -29,6 +29,7 @@ BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_AiffAudioFormat.h" | #include "juce_AiffAudioFormat.h" | ||||
| #include "../../io/streams/juce_BufferedInputStream.h" | #include "../../io/streams/juce_BufferedInputStream.h" | ||||
| #include "../../io/streams/juce_MemoryOutputStream.h" | |||||
| #include "../../core/juce_PlatformUtilities.h" | #include "../../core/juce_PlatformUtilities.h" | ||||
| #include "../../text/juce_LocalisedStrings.h" | #include "../../text/juce_LocalisedStrings.h" | ||||
| @@ -37,6 +38,215 @@ BEGIN_JUCE_NAMESPACE | |||||
| static const char* const aiffFormatName = "AIFF file"; | static const char* const aiffFormatName = "AIFF file"; | ||||
| static const char* const aiffExtensions[] = { ".aiff", ".aif", 0 }; | static const char* const aiffExtensions[] = { ".aiff", ".aif", 0 }; | ||||
| //============================================================================== | |||||
| namespace AiffFileHelpers | |||||
| { | |||||
| inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); } | |||||
| #if JUCE_MSVC | |||||
| #pragma pack (push, 1) | |||||
| #define PACKED | |||||
| #elif JUCE_GCC | |||||
| #define PACKED __attribute__((packed)) | |||||
| #else | |||||
| #define PACKED | |||||
| #endif | |||||
| //============================================================================== | |||||
| struct InstChunk | |||||
| { | |||||
| struct Loop | |||||
| { | |||||
| uint16 type; // these are different in AIFF and WAV | |||||
| uint16 startIdentifier; | |||||
| uint16 endIdentifier; | |||||
| } PACKED; | |||||
| int8 baseNote; | |||||
| int8 detune; | |||||
| int8 lowNote; | |||||
| int8 highNote; | |||||
| int8 lowVelocity; | |||||
| int8 highVelocity; | |||||
| int16 gain; | |||||
| Loop sustainLoop; | |||||
| Loop releaseLoop; | |||||
| void copyTo (StringPairArray& values) const | |||||
| { | |||||
| values.set ("MidiUnityNote", String (baseNote)); | |||||
| values.set ("Detune", String (detune)); | |||||
| values.set ("LowNote", String (lowNote)); | |||||
| values.set ("HighNote", String (highNote)); | |||||
| values.set ("LowVelocity", String (lowVelocity)); | |||||
| values.set ("HighVelocity", String (highVelocity)); | |||||
| values.set ("Gain", String ((int16) ByteOrder::swapIfLittleEndian ((uint16) gain))); | |||||
| values.set ("NumSampleLoops", String (2)); // always 2 with AIFF, WAV can have more | |||||
| values.set ("Loop0Type", String (ByteOrder::swapIfLittleEndian (sustainLoop.type))); | |||||
| values.set ("Loop0StartIdentifier", String (ByteOrder::swapIfLittleEndian (sustainLoop.startIdentifier))); | |||||
| values.set ("Loop0EndIdentifier", String (ByteOrder::swapIfLittleEndian (sustainLoop.endIdentifier))); | |||||
| values.set ("Loop1Type", String (ByteOrder::swapIfLittleEndian (releaseLoop.type))); | |||||
| values.set ("Loop1StartIdentifier", String (ByteOrder::swapIfLittleEndian (releaseLoop.startIdentifier))); | |||||
| values.set ("Loop1EndIdentifier", String (ByteOrder::swapIfLittleEndian (releaseLoop.endIdentifier))); | |||||
| } | |||||
| static void create (MemoryBlock& block, const StringPairArray& values) | |||||
| { | |||||
| if (values.getAllKeys().contains ("MidiUnityNote", true)) | |||||
| { | |||||
| block.setSize ((sizeof (InstChunk) + 3) & ~3, true); | |||||
| InstChunk* const inst = static_cast <InstChunk*> (block.getData()); | |||||
| inst->baseNote = (int8) values.getValue ("MidiUnityNote", "60").getIntValue(); | |||||
| inst->detune = (int8) values.getValue ("Detune", "0").getIntValue(); | |||||
| inst->lowNote = (int8) values.getValue ("LowNote", "0").getIntValue(); | |||||
| inst->highNote = (int8) values.getValue ("HighNote", "127").getIntValue(); | |||||
| inst->lowVelocity = (int8) values.getValue ("LowVelocity", "1").getIntValue(); | |||||
| inst->highVelocity = (int8) values.getValue ("HighVelocity", "127").getIntValue(); | |||||
| inst->gain = (int16) ByteOrder::swapIfLittleEndian ((uint16) values.getValue ("Gain", "0").getIntValue()); | |||||
| inst->sustainLoop.type = ByteOrder::swapIfLittleEndian ((uint16) values.getValue ("Loop0Type", "0").getIntValue()); | |||||
| inst->sustainLoop.startIdentifier = ByteOrder::swapIfLittleEndian ((uint16) values.getValue ("Loop0StartIdentifier", "0").getIntValue()); | |||||
| inst->sustainLoop.endIdentifier = ByteOrder::swapIfLittleEndian ((uint16) values.getValue ("Loop0EndIdentifier", "0").getIntValue()); | |||||
| inst->releaseLoop.type = ByteOrder::swapIfLittleEndian ((uint16) values.getValue ("Loop1Type", "0").getIntValue()); | |||||
| inst->releaseLoop.startIdentifier = ByteOrder::swapIfLittleEndian ((uint16) values.getValue ("Loop1StartIdentifier", "0").getIntValue()); | |||||
| inst->releaseLoop.endIdentifier = ByteOrder::swapIfLittleEndian ((uint16) values.getValue ("Loop1EndIdentifier", "0").getIntValue()); | |||||
| } | |||||
| } | |||||
| } PACKED; | |||||
| #if JUCE_MSVC | |||||
| #pragma pack (pop) | |||||
| #endif | |||||
| #undef PACKED | |||||
| //============================================================================== | |||||
| namespace MarkChunk | |||||
| { | |||||
| bool metaDataContainsZeroIdentifiers (const StringPairArray& values) | |||||
| { | |||||
| // (zero cue identifiers are valid for WAV but not for AIFF) | |||||
| const String cueString ("Cue"); | |||||
| const String noteString ("CueNote"); | |||||
| const String identifierString ("Identifier"); | |||||
| const StringArray& keys = values.getAllKeys(); | |||||
| for (int i = 0; i < keys.size(); ++i) | |||||
| { | |||||
| const String key (keys[i]); | |||||
| if (key.startsWith (noteString)) | |||||
| continue; // zero identifier IS valid in a COMT chunk | |||||
| if (key.startsWith (cueString) && key.contains (identifierString)) | |||||
| { | |||||
| const int value = values.getValue (key, "-1").getIntValue(); | |||||
| if (value == 0) | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| void create (MemoryBlock& block, const StringPairArray& values) | |||||
| { | |||||
| const int numCues = values.getValue ("NumCuePoints", "0").getIntValue(); | |||||
| if (numCues > 0) | |||||
| { | |||||
| MemoryOutputStream out (block, false); | |||||
| out.writeShortBigEndian ((short) numCues); | |||||
| const int numCueLabels = values.getValue ("NumCueLabels", "0").getIntValue(); | |||||
| const int idOffset = metaDataContainsZeroIdentifiers (values) ? 1 : 0; // can't have zero IDs in AIFF | |||||
| #if JUCE_DEBUG | |||||
| Array<int> identifiers; | |||||
| #endif | |||||
| for (int i = 0; i < numCues; ++i) | |||||
| { | |||||
| const String prefixCue ("Cue" + String (i)); | |||||
| const String prefixLabel ("CueLabel" + String (i)); | |||||
| const int identifier = idOffset + values.getValue (prefixCue + "Identifier", "1").getIntValue(); | |||||
| #if JUCE_DEBUG | |||||
| jassert (! identifiers.contains (identifier)); | |||||
| identifiers.add (identifier); | |||||
| #endif | |||||
| const int offset = values.getValue (prefixCue + "Offset", "0").getIntValue(); | |||||
| String label (prefixLabel); | |||||
| for (int labelIndex = 0; labelIndex < numCueLabels; ++labelIndex) | |||||
| { | |||||
| const String prefixLabel ("CueLabel" + String (labelIndex)); | |||||
| const int labelIdentifier = idOffset + values.getValue (prefixLabel + "Identifier", "1").getIntValue(); | |||||
| if (labelIdentifier == identifier) | |||||
| { | |||||
| label = values.getValue (prefixLabel + "Text", label); | |||||
| break; | |||||
| } | |||||
| } | |||||
| out.writeShortBigEndian ((short) identifier); | |||||
| out.writeIntBigEndian (offset); | |||||
| const int labelLength = jmin (254, label.getNumBytesAsUTF8()); // seems to need null terminator even though it's a pstring | |||||
| out.writeByte ((char) labelLength + 1); | |||||
| out.write (label.toUTF8(), labelLength); | |||||
| out.writeByte (0); | |||||
| } | |||||
| if ((out.getDataSize() & 1) != 0) | |||||
| out.writeByte (0); | |||||
| } | |||||
| } | |||||
| } | |||||
| //============================================================================== | |||||
| namespace COMTChunk | |||||
| { | |||||
| void create (MemoryBlock& block, const StringPairArray& values) | |||||
| { | |||||
| const int numNotes = values.getValue ("NumCueNotes", "0").getIntValue(); | |||||
| if (numNotes > 0) | |||||
| { | |||||
| MemoryOutputStream out (block, false); | |||||
| out.writeShortBigEndian ((short) numNotes); | |||||
| for (int i = 0; i < numNotes; ++i) | |||||
| { | |||||
| const String prefix ("CueNote" + String (i)); | |||||
| out.writeIntBigEndian (values.getValue (prefix + "TimeStamp", "0").getIntValue()); | |||||
| out.writeShortBigEndian ((short) values.getValue (prefix + "Identifier", "0").getIntValue()); | |||||
| const String comment (values.getValue (prefix + "Text", String::empty)); | |||||
| out.write (comment.toUTF8(), jmin (comment.getNumBytesAsUTF8(), 65534)); | |||||
| out.writeByte (0); | |||||
| if ((out.getDataSize() & 1) != 0) | |||||
| out.writeByte (0); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| class AiffAudioFormatReader : public AudioFormatReader | class AiffAudioFormatReader : public AudioFormatReader | ||||
| @@ -50,6 +260,8 @@ public: | |||||
| AiffAudioFormatReader (InputStream* in) | AiffAudioFormatReader (InputStream* in) | ||||
| : AudioFormatReader (in, TRANS (aiffFormatName)) | : AudioFormatReader (in, TRANS (aiffFormatName)) | ||||
| { | { | ||||
| using namespace AiffFileHelpers; | |||||
| if (input->readInt() == chunkName ("FORM")) | if (input->readInt() == chunkName ("FORM")) | ||||
| { | { | ||||
| const int len = input->readIntBigEndian(); | const int len = input->readIntBigEndian(); | ||||
| @@ -131,6 +343,67 @@ public: | |||||
| dataChunkStart = input->getPosition() + 4 + offset; | dataChunkStart = input->getPosition() + 4 + offset; | ||||
| lengthInSamples = (bytesPerFrame > 0) ? jmin (lengthInSamples, (int64) (length / bytesPerFrame)) : 0; | lengthInSamples = (bytesPerFrame > 0) ? jmin (lengthInSamples, (int64) (length / bytesPerFrame)) : 0; | ||||
| } | } | ||||
| else if (type == chunkName ("MARK")) | |||||
| { | |||||
| const uint16 numCues = (uint16) input->readShortBigEndian(); | |||||
| // these two are always the same for AIFF-read files | |||||
| metadataValues.set ("NumCuePoints", String (numCues)); | |||||
| metadataValues.set ("NumCueLabels", String (numCues)); | |||||
| for (uint16 i = 0; i < numCues; ++i) | |||||
| { | |||||
| uint16 identifier = (uint16) input->readShortBigEndian(); | |||||
| uint32 offset = (uint32) input->readIntBigEndian(); | |||||
| uint8 stringLength = (uint8) input->readByte(); | |||||
| MemoryBlock textBlock; | |||||
| input->readIntoMemoryBlock (textBlock, stringLength); | |||||
| // if the stringLength is even then read one more byte as the | |||||
| // string needs to be an even number of bytes INCLUDING the | |||||
| // leading length character in the pascal string | |||||
| if ((stringLength & 1) == 0) | |||||
| input->readByte(); | |||||
| const String text = String::fromUTF8 ((const char*)textBlock.getData(), stringLength); | |||||
| const String prefixCue ("Cue" + String (i)); | |||||
| metadataValues.set (prefixCue + "Identifier", String (identifier)); | |||||
| metadataValues.set (prefixCue + "Offset", String (offset)); | |||||
| const String prefixLabel ("CueLabel" + String (i)); | |||||
| metadataValues.set (prefixLabel + "Identifier", String (identifier)); | |||||
| metadataValues.set (prefixLabel + "Text", text); | |||||
| } | |||||
| } | |||||
| else if (type == chunkName ("COMT")) | |||||
| { | |||||
| const uint16 numNotes = (uint16) input->readShortBigEndian(); | |||||
| metadataValues.set ("NumCueNotes", String (numNotes)); | |||||
| for (uint16 i = 0; i < numNotes; ++i) | |||||
| { | |||||
| uint32 timestamp = (uint32) input->readIntBigEndian(); | |||||
| uint16 identifier = (uint16) input->readShortBigEndian(); // may be zero in this case | |||||
| uint16 stringLength = (uint16) input->readShortBigEndian(); | |||||
| MemoryBlock textBlock; | |||||
| input->readIntoMemoryBlock (textBlock, stringLength + (stringLength & 1)); | |||||
| const String text = String::fromUTF8 ((const char*)textBlock.getData(), stringLength); | |||||
| const String prefix ("CueNote" + String (i)); | |||||
| metadataValues.set (prefix + "TimeStamp", String (timestamp)); | |||||
| metadataValues.set (prefix + "Identifier", String (identifier)); | |||||
| metadataValues.set (prefix + "Text", text); | |||||
| } | |||||
| } | |||||
| else if (type == chunkName ("INST")) | |||||
| { | |||||
| HeapBlock <InstChunk> inst; | |||||
| inst.calloc (jmax ((size_t) length + 1, sizeof (InstChunk)), 1); | |||||
| input->read (inst, length); | |||||
| inst->copyTo (metadataValues); | |||||
| } | |||||
| else if ((hasGotVer && hasGotData && hasGotType) | else if ((hasGotVer && hasGotData && hasGotType) | ||||
| || chunkEnd < input->getPosition() | || chunkEnd < input->getPosition() | ||||
| || input->isExhausted()) | || input->isExhausted()) | ||||
| @@ -142,6 +415,9 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (metadataValues.size() > 0) | |||||
| metadataValues.set ("MetaDataSource", "AIFF"); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -211,8 +487,6 @@ public: | |||||
| } | } | ||||
| private: | private: | ||||
| static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); } | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AiffAudioFormatReader); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AiffAudioFormatReader); | ||||
| }; | }; | ||||
| @@ -221,12 +495,28 @@ class AiffAudioFormatWriter : public AudioFormatWriter | |||||
| { | { | ||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| AiffAudioFormatWriter (OutputStream* out, double sampleRate_, unsigned int numChans, int bits) | |||||
| AiffAudioFormatWriter (OutputStream* out, double sampleRate_, | |||||
| unsigned int numChans, int bits, | |||||
| const StringPairArray& metadataValues) | |||||
| : AudioFormatWriter (out, TRANS (aiffFormatName), sampleRate_, numChans, bits), | : AudioFormatWriter (out, TRANS (aiffFormatName), sampleRate_, numChans, bits), | ||||
| lengthInSamples (0), | lengthInSamples (0), | ||||
| bytesWritten (0), | bytesWritten (0), | ||||
| writeFailed (false) | writeFailed (false) | ||||
| { | { | ||||
| using namespace AiffFileHelpers; | |||||
| if (metadataValues.size() > 0) | |||||
| { | |||||
| // The meta data should have been santised for the AIFF format. | |||||
| // If it was originally sourced from a WAV file the MetaDataSource | |||||
| // key should be removed (or set to "AIFF") once this has been done | |||||
| jassert (metadataValues.getValue ("MetaDataSource", "None") != "WAV"); | |||||
| MarkChunk::create (markChunk, metadataValues); | |||||
| COMTChunk::create (comtChunk, metadataValues); | |||||
| InstChunk::create (instChunk, metadataValues); | |||||
| } | |||||
| headerPosition = out->getPosition(); | headerPosition = out->getPosition(); | ||||
| writeHeader(); | writeHeader(); | ||||
| } | } | ||||
| @@ -279,15 +569,15 @@ public: | |||||
| } | } | ||||
| private: | private: | ||||
| MemoryBlock tempBlock; | |||||
| MemoryBlock tempBlock, markChunk, comtChunk, instChunk; | |||||
| uint32 lengthInSamples, bytesWritten; | uint32 lengthInSamples, bytesWritten; | ||||
| int64 headerPosition; | int64 headerPosition; | ||||
| bool writeFailed; | bool writeFailed; | ||||
| static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); } | |||||
| void writeHeader() | void writeHeader() | ||||
| { | { | ||||
| using namespace AiffFileHelpers; | |||||
| const bool couldSeekOk = output->setPosition (headerPosition); | const bool couldSeekOk = output->setPosition (headerPosition); | ||||
| (void) couldSeekOk; | (void) couldSeekOk; | ||||
| @@ -295,7 +585,9 @@ private: | |||||
| // to be able to seek back to write the header | // to be able to seek back to write the header | ||||
| jassert (couldSeekOk); | jassert (couldSeekOk); | ||||
| const int headerLen = 54; | |||||
| const int headerLen = 54 + (markChunk.getSize() > 0 ? markChunk.getSize() + 8 : 0) | |||||
| + (comtChunk.getSize() > 0 ? comtChunk.getSize() + 8 : 0) | |||||
| + (instChunk.getSize() > 0 ? instChunk.getSize() + 8 : 0); | |||||
| int audioBytes = lengthInSamples * ((bitsPerSample * numChannels) / 8); | int audioBytes = lengthInSamples * ((bitsPerSample * numChannels) / 8); | ||||
| audioBytes += (audioBytes & 1); | audioBytes += (audioBytes & 1); | ||||
| @@ -351,6 +643,27 @@ private: | |||||
| output->write (sampleRateBytes, 10); | output->write (sampleRateBytes, 10); | ||||
| if (markChunk.getSize() > 0) | |||||
| { | |||||
| output->writeInt (chunkName ("MARK")); | |||||
| output->writeIntBigEndian ((int) markChunk.getSize()); | |||||
| output->write (markChunk.getData(), (int) markChunk.getSize()); | |||||
| } | |||||
| if (comtChunk.getSize() > 0) | |||||
| { | |||||
| output->writeInt (chunkName ("COMT")); | |||||
| output->writeIntBigEndian ((int) comtChunk.getSize()); | |||||
| output->write (comtChunk.getData(), (int) comtChunk.getSize()); | |||||
| } | |||||
| if (instChunk.getSize() > 0) | |||||
| { | |||||
| output->writeInt (chunkName ("INST")); | |||||
| output->writeIntBigEndian ((int) instChunk.getSize()); | |||||
| output->write (instChunk.getData(), (int) instChunk.getSize()); | |||||
| } | |||||
| output->writeInt (chunkName ("SSND")); | output->writeInt (chunkName ("SSND")); | ||||
| output->writeIntBigEndian (audioBytes + 8); | output->writeIntBigEndian (audioBytes + 8); | ||||
| output->writeInt (0); | output->writeInt (0); | ||||
| @@ -416,11 +729,11 @@ AudioFormatWriter* AiffAudioFormat::createWriterFor (OutputStream* out, | |||||
| double sampleRate, | double sampleRate, | ||||
| unsigned int numberOfChannels, | unsigned int numberOfChannels, | ||||
| int bitsPerSample, | int bitsPerSample, | ||||
| const StringPairArray& /*metadataValues*/, | |||||
| const StringPairArray& metadataValues, | |||||
| int /*qualityOptionIndex*/) | int /*qualityOptionIndex*/) | ||||
| { | { | ||||
| if (getPossibleBitDepths().contains (bitsPerSample)) | if (getPossibleBitDepths().contains (bitsPerSample)) | ||||
| return new AiffAudioFormatWriter (out, sampleRate, numberOfChannels, bitsPerSample); | |||||
| return new AiffAudioFormatWriter (out, sampleRate, numberOfChannels, bitsPerSample, metadataValues); | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| @@ -50,9 +50,10 @@ public: | |||||
| const Array <int> getPossibleBitDepths(); | const Array <int> getPossibleBitDepths(); | ||||
| bool canDoStereo(); | bool canDoStereo(); | ||||
| bool canDoMono(); | bool canDoMono(); | ||||
| #if JUCE_MAC | |||||
| #if JUCE_MAC | |||||
| bool canHandleFile (const File& fileToTest); | bool canHandleFile (const File& fileToTest); | ||||
| #endif | |||||
| #endif | |||||
| //============================================================================== | //============================================================================== | ||||
| AudioFormatReader* createReaderFor (InputStream* sourceStream, | AudioFormatReader* createReaderFor (InputStream* sourceStream, | ||||
| @@ -38,7 +38,7 @@ struct AudioThumbnail::MinMaxValue | |||||
| char minValue; | char minValue; | ||||
| char maxValue; | char maxValue; | ||||
| MinMaxValue() : minValue (0), maxValue (0) | |||||
| MinMaxValue() noexcept : minValue (0), maxValue (0) | |||||
| { | { | ||||
| } | } | ||||
| @@ -281,7 +281,7 @@ public: | |||||
| return data.size(); | return data.size(); | ||||
| } | } | ||||
| void getMinMax (int startSample, int endSample, MinMaxValue& result) noexcept | |||||
| void getMinMax (int startSample, int endSample, MinMaxValue& result) const noexcept | |||||
| { | { | ||||
| if (startSample >= 0) | if (startSample >= 0) | ||||
| { | { | ||||
| @@ -323,12 +323,12 @@ public: | |||||
| dest[i] = source[i]; | dest[i] = source[i]; | ||||
| } | } | ||||
| void resetPeak() | |||||
| void resetPeak() noexcept | |||||
| { | { | ||||
| peakLevel = -1; | peakLevel = -1; | ||||
| } | } | ||||
| int getPeak() | |||||
| int getPeak() noexcept | |||||
| { | { | ||||
| if (peakLevel < 0) | if (peakLevel < 0) | ||||
| { | { | ||||
| @@ -743,6 +743,24 @@ float AudioThumbnail::getApproximatePeak() const | |||||
| return jlimit (0, 127, peak) / 127.0f; | return jlimit (0, 127, peak) / 127.0f; | ||||
| } | } | ||||
| void AudioThumbnail::getApproximateMinMax (const double startTime, const double endTime, const int channelIndex, | |||||
| float& minValue, float& maxValue) const noexcept | |||||
| { | |||||
| MinMaxValue result; | |||||
| const ThumbData* const data = channels [channelIndex]; | |||||
| if (data != nullptr && sampleRate > 0) | |||||
| { | |||||
| const int firstThumbIndex = (int) ((startTime * sampleRate) / samplesPerThumbSample); | |||||
| const int lastThumbIndex = (int) (((endTime * sampleRate) + samplesPerThumbSample - 1) / samplesPerThumbSample); | |||||
| data->getMinMax (jmax (0, firstThumbIndex), lastThumbIndex, result); | |||||
| } | |||||
| minValue = result.minValue / 128.0f; | |||||
| maxValue = result.maxValue / 128.0f; | |||||
| } | |||||
| void AudioThumbnail::drawChannel (Graphics& g, const Rectangle<int>& area, double startTime, | void AudioThumbnail::drawChannel (Graphics& g, const Rectangle<int>& area, double startTime, | ||||
| double endTime, int channelNum, float verticalZoomFactor) | double endTime, int channelNum, float verticalZoomFactor) | ||||
| { | { | ||||
| @@ -186,12 +186,19 @@ public: | |||||
| */ | */ | ||||
| float getApproximatePeak() const; | float getApproximatePeak() const; | ||||
| /** Reads the approximate min and max levels from a section of the thumbnail. | |||||
| The lowest and highest samples are returned in minValue and maxValue, but obviously | |||||
| because the thumb only stores low-resolution data, these numbers will only be a rough | |||||
| approximation of the true values. | |||||
| */ | |||||
| void getApproximateMinMax (double startTime, double endTime, int channelIndex, | |||||
| float& minValue, float& maxValue) const noexcept; | |||||
| /** Returns the hash code that was set by setSource() or setReader(). */ | /** Returns the hash code that was set by setSource() or setReader(). */ | ||||
| int64 getHashCode() const; | int64 getHashCode() const; | ||||
| #ifndef DOXYGEN | #ifndef DOXYGEN | ||||
| // (this is only public to avoid a VC6 bug) | |||||
| class LevelDataSource; | |||||
| class LevelDataSource; // (this is only public to avoid a VC6 bug) | |||||
| #endif | #endif | ||||
| private: | private: | ||||
| @@ -29,6 +29,7 @@ BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_WavAudioFormat.h" | #include "juce_WavAudioFormat.h" | ||||
| #include "../../io/streams/juce_BufferedInputStream.h" | #include "../../io/streams/juce_BufferedInputStream.h" | ||||
| #include "../../io/streams/juce_MemoryOutputStream.h" | |||||
| #include "../../text/juce_LocalisedStrings.h" | #include "../../text/juce_LocalisedStrings.h" | ||||
| #include "../../io/files/juce_FileInputStream.h" | #include "../../io/files/juce_FileInputStream.h" | ||||
| #include "../../io/files/juce_TemporaryFile.h" | #include "../../io/files/juce_TemporaryFile.h" | ||||
| @@ -156,7 +157,7 @@ struct SMPLChunk | |||||
| struct SampleLoop | struct SampleLoop | ||||
| { | { | ||||
| uint32 identifier; | uint32 identifier; | ||||
| uint32 type; | |||||
| uint32 type; // these are different in AIFF and WAV | |||||
| uint32 start; | uint32 start; | ||||
| uint32 end; | uint32 end; | ||||
| uint32 fraction; | uint32 fraction; | ||||
| @@ -214,8 +215,6 @@ struct SMPLChunk | |||||
| SMPLChunk* const s = static_cast <SMPLChunk*> (data.getData()); | SMPLChunk* const s = static_cast <SMPLChunk*> (data.getData()); | ||||
| // Allow these calls to overwrite an extra byte at the end, which is fine as long | |||||
| // as they get called in the right order.. | |||||
| s->manufacturer = ByteOrder::swapIfBigEndian ((uint32) values.getValue ("Manufacturer", "0").getIntValue()); | s->manufacturer = ByteOrder::swapIfBigEndian ((uint32) values.getValue ("Manufacturer", "0").getIntValue()); | ||||
| s->product = ByteOrder::swapIfBigEndian ((uint32) values.getValue ("Product", "0").getIntValue()); | s->product = ByteOrder::swapIfBigEndian ((uint32) values.getValue ("Product", "0").getIntValue()); | ||||
| s->samplePeriod = ByteOrder::swapIfBigEndian ((uint32) values.getValue ("SamplePeriod", "0").getIntValue()); | s->samplePeriod = ByteOrder::swapIfBigEndian ((uint32) values.getValue ("SamplePeriod", "0").getIntValue()); | ||||
| @@ -241,6 +240,52 @@ struct SMPLChunk | |||||
| } | } | ||||
| } PACKED; | } PACKED; | ||||
| //============================================================================== | |||||
| struct InstChunk | |||||
| { | |||||
| int8 baseNote; | |||||
| int8 detune; | |||||
| int8 gain; | |||||
| int8 lowNote; | |||||
| int8 highNote; | |||||
| int8 lowVelocity; | |||||
| int8 highVelocity; | |||||
| void copyTo (StringPairArray& values) const | |||||
| { | |||||
| values.set ("MidiUnityNote", String (baseNote)); | |||||
| values.set ("Detune", String (detune)); | |||||
| values.set ("Gain", String (gain)); | |||||
| values.set ("LowNote", String (lowNote)); | |||||
| values.set ("HighNote", String (highNote)); | |||||
| values.set ("LowVelocity", String (lowVelocity)); | |||||
| values.set ("HighVelocity", String (highVelocity)); | |||||
| } | |||||
| static MemoryBlock createFrom (const StringPairArray& values) | |||||
| { | |||||
| const StringArray& keys = values.getAllKeys(); | |||||
| if (! (keys.contains ("LowNote", true) && keys.contains ("HighNote", true))) | |||||
| return MemoryBlock(); | |||||
| MemoryBlock data (8); | |||||
| data.fillWith (0); | |||||
| InstChunk* const inst = static_cast <InstChunk*> (data.getData()); | |||||
| inst->baseNote = (int8) values.getValue ("MidiUnityNote", "60").getIntValue(); | |||||
| inst->detune = (int8) values.getValue ("Detune", "0").getIntValue(); | |||||
| inst->gain = (int8) values.getValue ("Gain", "0").getIntValue(); | |||||
| inst->lowNote = (int8) values.getValue ("LowNote", "0").getIntValue(); | |||||
| inst->highNote = (int8) values.getValue ("HighNote", "127").getIntValue(); | |||||
| inst->lowVelocity = (int8) values.getValue ("LowVelocity", "1").getIntValue(); | |||||
| inst->highVelocity = (int8) values.getValue ("HighVelocity", "127").getIntValue(); | |||||
| return data; | |||||
| } | |||||
| } PACKED; | |||||
| //============================================================================== | //============================================================================== | ||||
| struct CueChunk | struct CueChunk | ||||
| { | { | ||||
| @@ -276,39 +321,118 @@ struct CueChunk | |||||
| } | } | ||||
| } | } | ||||
| static MemoryBlock createFrom (const StringPairArray& values) | |||||
| static void create (MemoryBlock& data, const StringPairArray& values) | |||||
| { | { | ||||
| const int numCues = values.getValue ("NumCuePoints", "0").getIntValue(); | const int numCues = values.getValue ("NumCuePoints", "0").getIntValue(); | ||||
| if (numCues <= 0) | |||||
| return MemoryBlock(); | |||||
| if (numCues > 0) | |||||
| { | |||||
| const size_t sizeNeeded = sizeof (CueChunk) + (numCues - 1) * sizeof (Cue); | |||||
| data.setSize ((sizeNeeded + 3) & ~3, true); | |||||
| const size_t sizeNeeded = sizeof (CueChunk) + (numCues - 1) * sizeof (Cue); | |||||
| MemoryBlock data ((sizeNeeded + 3) & ~3); | |||||
| data.fillWith (0); | |||||
| CueChunk* const c = static_cast <CueChunk*> (data.getData()); | |||||
| CueChunk* const c = static_cast <CueChunk*> (data.getData()); | |||||
| c->numCues = ByteOrder::swapIfBigEndian ((uint32) numCues); | |||||
| c->numCues = ByteOrder::swapIfBigEndian ((uint32) numCues); | |||||
| const String dataChunkID (chunkName ("data")); | |||||
| const String dataChunkID (chunkName ("data")); | |||||
| int nextOrder = 0; | |||||
| for (int i = 0; i < numCues; ++i) | |||||
| { | |||||
| const String prefix ("Cue" + String(i)); | |||||
| c->cues[i].identifier = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "Identifier", "0").getIntValue()); | |||||
| c->cues[i].order = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "Order", "0").getIntValue()); | |||||
| c->cues[i].chunkID = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "ChunkID", dataChunkID).getIntValue()); | |||||
| c->cues[i].chunkStart = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "ChunkStart", "0").getIntValue()); | |||||
| c->cues[i].blockStart = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "BlockStart", "0").getIntValue()); | |||||
| c->cues[i].offset = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "Offset", "0").getIntValue()); | |||||
| } | |||||
| #if JUCE_DEBUG | |||||
| Array<int> identifiers; | |||||
| #endif | |||||
| return data; | |||||
| for (int i = 0; i < numCues; ++i) | |||||
| { | |||||
| const String prefix ("Cue" + String (i)); | |||||
| uint32 identifier = values.getValue (prefix + "Identifier", "0").getIntValue(); | |||||
| #if JUCE_DEBUG | |||||
| jassert (! identifiers.contains (identifier)); | |||||
| identifiers.add (identifier); | |||||
| #endif | |||||
| c->cues[i].identifier = ByteOrder::swapIfBigEndian ((uint32) identifier); | |||||
| const int order = values.getValue (prefix + "Order", String (nextOrder)).getIntValue(); | |||||
| nextOrder = jmax (nextOrder, order) + 1; | |||||
| c->cues[i].order = ByteOrder::swapIfBigEndian ((uint32) order); | |||||
| c->cues[i].chunkID = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "ChunkID", dataChunkID).getIntValue()); | |||||
| c->cues[i].chunkStart = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "ChunkStart", "0").getIntValue()); | |||||
| c->cues[i].blockStart = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "BlockStart", "0").getIntValue()); | |||||
| c->cues[i].offset = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "Offset", "0").getIntValue()); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } PACKED; | } PACKED; | ||||
| //============================================================================== | |||||
| namespace ListChunk | |||||
| { | |||||
| void appendLabelOrNoteChunk (const StringPairArray& values, const String& prefix, | |||||
| const int chunkType, MemoryOutputStream& out) | |||||
| { | |||||
| const String label (values.getValue (prefix + "Text", prefix)); | |||||
| const int labelLength = label.getNumBytesAsUTF8() + 1; | |||||
| const int chunkLength = 4 + labelLength + (labelLength & 1); | |||||
| out.writeInt (chunkType); | |||||
| out.writeInt (chunkLength); | |||||
| out.writeInt (values.getValue (prefix + "Identifier", "0").getIntValue()); | |||||
| out.write (label.toUTF8(), labelLength); | |||||
| if ((out.getDataSize() & 1) != 0) | |||||
| out.writeByte (0); | |||||
| } | |||||
| void appendExtraChunk (const StringPairArray& values, const String& prefix, MemoryOutputStream& out) | |||||
| { | |||||
| const String text (values.getValue (prefix + "Text", prefix)); | |||||
| const int textLength = text.getNumBytesAsUTF8() + 1; // include null terminator | |||||
| uint32 chunkLength = textLength + 20 + (textLength & 1); | |||||
| out.writeInt (chunkName ("ltxt")); | |||||
| out.writeInt (chunkLength); | |||||
| out.writeInt (values.getValue (prefix + "Identifier", "0").getIntValue()); | |||||
| out.writeInt (values.getValue (prefix + "SampleLength", "0").getIntValue()); | |||||
| out.writeInt (values.getValue (prefix + "Purpose", "0").getIntValue()); | |||||
| out.writeShort ((short) values.getValue (prefix + "Country", "0").getIntValue()); | |||||
| out.writeShort ((short) values.getValue (prefix + "Language", "0").getIntValue()); | |||||
| out.writeShort ((short) values.getValue (prefix + "Dialect", "0").getIntValue()); | |||||
| out.writeShort ((short) values.getValue (prefix + "CodePage", "0").getIntValue()); | |||||
| out.write (text.toUTF8(), textLength); | |||||
| if ((out.getDataSize() & 1) != 0) | |||||
| out.writeByte (0); | |||||
| } | |||||
| void create (MemoryBlock& block, const StringPairArray& values) | |||||
| { | |||||
| const int numCueLabels = values.getValue ("NumCueLabels", "0").getIntValue(); | |||||
| const int numCueNotes = values.getValue ("NumCueNotes", "0").getIntValue(); | |||||
| const int numCueRegions = values.getValue ("NumCueRegions", "0").getIntValue(); | |||||
| if (numCueLabels > 0 || numCueNotes > 0 || numCueRegions > 0) | |||||
| { | |||||
| MemoryOutputStream out (block, false); | |||||
| int i; | |||||
| for (i = 0; i < numCueLabels; ++i) | |||||
| appendLabelOrNoteChunk (values, "CueLabel" + String (i), chunkName ("labl"), out); | |||||
| for (i = 0; i < numCueNotes; ++i) | |||||
| appendLabelOrNoteChunk (values, "CueNote" + String (i), chunkName ("note"), out); | |||||
| for (i = 0; i < numCueRegions; ++i) | |||||
| appendExtraChunk (values, "CueRegion" + String (i), out); | |||||
| } | |||||
| } | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| struct ExtensibleWavSubFormat | struct ExtensibleWavSubFormat | ||||
| { | { | ||||
| @@ -355,6 +479,9 @@ public: | |||||
| int64 end = 0; | int64 end = 0; | ||||
| bool hasGotType = false; | bool hasGotType = false; | ||||
| bool hasGotData = false; | bool hasGotData = false; | ||||
| int cueNoteIndex = 0; | |||||
| int cueLabelIndex = 0; | |||||
| int cueRegionIndex = 0; | |||||
| const int firstChunkType = input->readInt(); | const int firstChunkType = input->readInt(); | ||||
| @@ -479,6 +606,13 @@ public: | |||||
| input->read (smpl, length); | input->read (smpl, length); | ||||
| smpl->copyTo (metadataValues, length); | smpl->copyTo (metadataValues, length); | ||||
| } | } | ||||
| else if (chunkType == chunkName ("inst") || chunkType == chunkName ("INST")) // need to check which... | |||||
| { | |||||
| HeapBlock <InstChunk> inst; | |||||
| inst.calloc (jmax ((size_t) length + 1, sizeof (InstChunk)), 1); | |||||
| input->read (inst, length); | |||||
| inst->copyTo (metadataValues); | |||||
| } | |||||
| else if (chunkType == chunkName ("cue ")) | else if (chunkType == chunkName ("cue ")) | ||||
| { | { | ||||
| HeapBlock <CueChunk> cue; | HeapBlock <CueChunk> cue; | ||||
| @@ -486,6 +620,65 @@ public: | |||||
| input->read (cue, length); | input->read (cue, length); | ||||
| cue->copyTo (metadataValues, length); | cue->copyTo (metadataValues, length); | ||||
| } | } | ||||
| else if (chunkType == chunkName ("LIST")) | |||||
| { | |||||
| if (input->readInt() == chunkName ("adtl")) | |||||
| { | |||||
| while (input->getPosition() < chunkEnd) | |||||
| { | |||||
| const int adtlChunkType = input->readInt(); | |||||
| const uint32 adtlLength = (uint32) input->readInt(); | |||||
| const int64 adtlChunkEnd = input->getPosition() + (adtlLength + (adtlLength & 1)); | |||||
| if (adtlChunkType == chunkName ("labl") || adtlChunkType == chunkName ("note")) | |||||
| { | |||||
| String prefix; | |||||
| if (adtlChunkType == chunkName ("labl")) | |||||
| prefix << "CueLabel" << cueLabelIndex++; | |||||
| else if (adtlChunkType == chunkName ("note")) | |||||
| prefix << "CueNote" << cueNoteIndex++; | |||||
| const uint32 identifier = (uint32) input->readInt(); | |||||
| const uint32 stringLength = adtlLength - 4; | |||||
| MemoryBlock textBlock; | |||||
| input->readIntoMemoryBlock (textBlock, stringLength); | |||||
| const String text (String::fromUTF8 (static_cast <const char*> (textBlock.getData()), textBlock.getSize())); | |||||
| metadataValues.set (prefix + "Identifier", String (identifier)); | |||||
| metadataValues.set (prefix + "Text", text); | |||||
| } | |||||
| else if (adtlChunkType == chunkName ("ltxt")) | |||||
| { | |||||
| const String prefix ("CueRegion" + String (cueRegionIndex++)); | |||||
| const uint32 identifier = (uint32) input->readInt(); | |||||
| const uint32 sampleLength = (uint32) input->readInt(); | |||||
| const uint32 purpose = (uint32) input->readInt(); | |||||
| const uint16 country = (uint16) input->readInt(); | |||||
| const uint16 language = (uint16) input->readInt(); | |||||
| const uint16 dialect = (uint16) input->readInt(); | |||||
| const uint16 codePage = (uint16) input->readInt(); | |||||
| const uint32 stringLength = adtlLength - 20; | |||||
| MemoryBlock textBlock; | |||||
| input->readIntoMemoryBlock (textBlock, stringLength); | |||||
| const String text = String::fromUTF8 ((const char*)textBlock.getData(), textBlock.getSize()); | |||||
| metadataValues.set (prefix + "Identifier", String (identifier)); | |||||
| metadataValues.set (prefix + "SampleLength", String (sampleLength)); | |||||
| metadataValues.set (prefix + "Purpose", String (purpose)); | |||||
| metadataValues.set (prefix + "Country", String (country)); | |||||
| metadataValues.set (prefix + "Language", String (language)); | |||||
| metadataValues.set (prefix + "Dialect", String (dialect)); | |||||
| metadataValues.set (prefix + "CodePage", String (codePage)); | |||||
| metadataValues.set (prefix + "Text", text); | |||||
| } | |||||
| input->setPosition (adtlChunkEnd); | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (chunkEnd <= input->getPosition()) | else if (chunkEnd <= input->getPosition()) | ||||
| { | { | ||||
| break; | break; | ||||
| @@ -494,6 +687,11 @@ public: | |||||
| input->setPosition (chunkEnd); | input->setPosition (chunkEnd); | ||||
| } | } | ||||
| } | } | ||||
| if (cueLabelIndex > 0) metadataValues.set ("NumCueLabels", String (cueLabelIndex)); | |||||
| if (cueNoteIndex > 0) metadataValues.set ("NumCueNotes", String (cueNoteIndex)); | |||||
| if (cueRegionIndex > 0) metadataValues.set ("NumCueRegions", String (cueRegionIndex)); | |||||
| if (metadataValues.size() > 0) metadataValues.set ("MetaDataSource", "WAV"); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -576,9 +774,16 @@ public: | |||||
| if (metadataValues.size() > 0) | if (metadataValues.size() > 0) | ||||
| { | { | ||||
| // The meta data should have been santised for the WAV format. | |||||
| // If it was originally sourced from an AIFF file the MetaDataSource | |||||
| // key should be removed (or set to "WAV") once this has been done | |||||
| jassert (metadataValues.getValue ("MetaDataSource", "None") != "AIFF"); | |||||
| bwavChunk = BWAVChunk::createFrom (metadataValues); | bwavChunk = BWAVChunk::createFrom (metadataValues); | ||||
| smplChunk = SMPLChunk::createFrom (metadataValues); | smplChunk = SMPLChunk::createFrom (metadataValues); | ||||
| cueChunk = CueChunk ::createFrom (metadataValues); | |||||
| instChunk = InstChunk::createFrom (metadataValues); | |||||
| CueChunk ::create (cueChunk, metadataValues); | |||||
| ListChunk::create (listChunk, metadataValues); | |||||
| } | } | ||||
| headerPosition = out->getPosition(); | headerPosition = out->getPosition(); | ||||
| @@ -636,7 +841,7 @@ public: | |||||
| private: | private: | ||||
| ScopedPointer<AudioData::Converter> converter; | ScopedPointer<AudioData::Converter> converter; | ||||
| MemoryBlock tempBlock, bwavChunk, smplChunk, cueChunk; | |||||
| MemoryBlock tempBlock, bwavChunk, smplChunk, instChunk, cueChunk, listChunk; | |||||
| uint64 lengthInSamples, bytesWritten; | uint64 lengthInSamples, bytesWritten; | ||||
| int64 headerPosition; | int64 headerPosition; | ||||
| bool writeFailed; | bool writeFailed; | ||||
| @@ -675,7 +880,9 @@ private: | |||||
| + 8 + audioDataSize + (audioDataSize & 1) | + 8 + audioDataSize + (audioDataSize & 1) | ||||
| + (bwavChunk.getSize() > 0 ? (8 + bwavChunk.getSize()) : 0) | + (bwavChunk.getSize() > 0 ? (8 + bwavChunk.getSize()) : 0) | ||||
| + (smplChunk.getSize() > 0 ? (8 + smplChunk.getSize()) : 0) | + (smplChunk.getSize() > 0 ? (8 + smplChunk.getSize()) : 0) | ||||
| + (instChunk.getSize() > 0 ? (8 + instChunk.getSize()) : 0) | |||||
| + (cueChunk .getSize() > 0 ? (8 + cueChunk .getSize()) : 0) | + (cueChunk .getSize() > 0 ? (8 + cueChunk .getSize()) : 0) | ||||
| + (listChunk.getSize() > 0 ? (12 + listChunk.getSize()) : 0) | |||||
| + (8 + 28); // (ds64 chunk) | + (8 + 28); // (ds64 chunk) | ||||
| riffChunkSize += (riffChunkSize & 0x1); | riffChunkSize += (riffChunkSize & 0x1); | ||||
| @@ -754,6 +961,13 @@ private: | |||||
| output->write (smplChunk.getData(), (int) smplChunk.getSize()); | output->write (smplChunk.getData(), (int) smplChunk.getSize()); | ||||
| } | } | ||||
| if (instChunk.getSize() > 0) | |||||
| { | |||||
| output->writeInt (chunkName ("inst")); | |||||
| output->writeInt (7); | |||||
| output->write (instChunk.getData(), (int) instChunk.getSize()); | |||||
| } | |||||
| if (cueChunk.getSize() > 0) | if (cueChunk.getSize() > 0) | ||||
| { | { | ||||
| output->writeInt (chunkName ("cue ")); | output->writeInt (chunkName ("cue ")); | ||||
| @@ -761,6 +975,14 @@ private: | |||||
| output->write (cueChunk.getData(), (int) cueChunk.getSize()); | output->write (cueChunk.getData(), (int) cueChunk.getSize()); | ||||
| } | } | ||||
| if (listChunk.getSize() > 0) | |||||
| { | |||||
| output->writeInt (chunkName ("LIST")); | |||||
| output->writeInt ((int) listChunk.getSize() + 4); | |||||
| output->writeInt (chunkName ("adtl")); | |||||
| output->write (listChunk.getData(), (int) listChunk.getSize()); | |||||
| } | |||||
| output->writeInt (chunkName ("data")); | output->writeInt (chunkName ("data")); | ||||
| output->writeInt (isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame)); | output->writeInt (isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame)); | ||||
| @@ -24,6 +24,9 @@ | |||||
| */ | */ | ||||
| #include "juce_IncludeCharacteristics.h" | #include "juce_IncludeCharacteristics.h" | ||||
| #define DONT_AUTOLINK_TO_JUCE_LIBRARY 1 | |||||
| #include "../../../juce.h" | #include "../../../juce.h" | ||||
| #ifndef __JUCE_PLUGINHEADERS_JUCEHEADER__ | #ifndef __JUCE_PLUGINHEADERS_JUCEHEADER__ | ||||
| @@ -71,10 +71,9 @@ public: | |||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| /** The ID number assigned to this node. | /** The ID number assigned to this node. | ||||
| This is assigned by the graph that owns it, and can't be changed. | This is assigned by the graph that owns it, and can't be changed. | ||||
| */ | */ | ||||
| const uint32 id; | |||||
| const uint32 nodeId; | |||||
| /** The actual processor object that this node represents. */ | /** The actual processor object that this node represents. */ | ||||
| AudioProcessor* getProcessor() const noexcept { return processor; } | AudioProcessor* getProcessor() const noexcept { return processor; } | ||||
| @@ -99,7 +98,7 @@ public: | |||||
| const ScopedPointer<AudioProcessor> processor; | const ScopedPointer<AudioProcessor> processor; | ||||
| bool isPrepared; | bool isPrepared; | ||||
| Node (uint32 id, AudioProcessor* processor); | |||||
| Node (uint32 nodeId, AudioProcessor* processor) noexcept; | |||||
| void prepare (double sampleRate, int blockSize, AudioProcessorGraph* graph); | void prepare (double sampleRate, int blockSize, AudioProcessorGraph* graph); | ||||
| void unprepare(); | void unprepare(); | ||||
| @@ -115,6 +114,10 @@ public: | |||||
| struct JUCE_API Connection | struct JUCE_API Connection | ||||
| { | { | ||||
| public: | public: | ||||
| //============================================================================== | |||||
| Connection (uint32 sourceNodeId, int sourceChannelIndex, | |||||
| uint32 destNodeId, int destChannelIndex) noexcept; | |||||
| //============================================================================== | //============================================================================== | ||||
| /** The ID number of the node which is the input source for this connection. | /** The ID number of the node which is the input source for this connection. | ||||
| @see AudioProcessorGraph::getNodeForId | @see AudioProcessorGraph::getNodeForId | ||||
| @@ -42,10 +42,9 @@ static const int quitMessageId = 0xfffff321; | |||||
| MessageManager::MessageManager() noexcept | MessageManager::MessageManager() noexcept | ||||
| : quitMessagePosted (false), | : quitMessagePosted (false), | ||||
| quitMessageReceived (false), | quitMessageReceived (false), | ||||
| messageThreadId (Thread::getCurrentThreadId()), | |||||
| threadWithLock (0) | threadWithLock (0) | ||||
| { | { | ||||
| messageThreadId = Thread::getCurrentThreadId(); | |||||
| if (JUCEApplication::isStandaloneApp()) | if (JUCEApplication::isStandaloneApp()) | ||||
| Thread::setCurrentThreadName ("Juce Message Thread"); | Thread::setCurrentThreadName ("Juce Message Thread"); | ||||
| } | } | ||||
| @@ -106,8 +106,7 @@ public: | |||||
| @returns the value that the callback function returns. | @returns the value that the callback function returns. | ||||
| @see MessageManagerLock | @see MessageManagerLock | ||||
| */ | */ | ||||
| void* callFunctionOnMessageThread (MessageCallbackFunction* callback, | |||||
| void* userData); | |||||
| void* callFunctionOnMessageThread (MessageCallbackFunction* callback, void* userData); | |||||
| /** Returns true if the caller-thread is the message thread. */ | /** Returns true if the caller-thread is the message thread. */ | ||||
| bool isThisTheMessageThread() const noexcept; | bool isThisTheMessageThread() const noexcept; | ||||
| @@ -157,12 +156,12 @@ public: | |||||
| void deregisterBroadcastListener (ActionListener* listener); | void deregisterBroadcastListener (ActionListener* listener); | ||||
| //============================================================================== | //============================================================================== | ||||
| /** @internal */ | |||||
| #ifndef DOXYGEN | |||||
| // Internal methods - do not use! | |||||
| void deliverMessage (Message*); | void deliverMessage (Message*); | ||||
| /** @internal */ | |||||
| void deliverBroadcastMessage (const String&); | void deliverBroadcastMessage (const String&); | ||||
| /** @internal */ | |||||
| ~MessageManager() noexcept; | ~MessageManager() noexcept; | ||||
| #endif | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -294,12 +293,10 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns true if the lock was successfully acquired. | /** Returns true if the lock was successfully acquired. | ||||
| (See the constructor that takes a Thread for more info). | (See the constructor that takes a Thread for more info). | ||||
| */ | */ | ||||
| bool lockWasGained() const noexcept { return locked; } | bool lockWasGained() const noexcept { return locked; } | ||||
| private: | private: | ||||
| class BlockingMessage; | class BlockingMessage; | ||||
| friend class ReferenceCountedObjectPtr<BlockingMessage>; | friend class ReferenceCountedObjectPtr<BlockingMessage>; | ||||
| @@ -229,6 +229,7 @@ public: | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| #ifndef DOXYGEN | |||||
| /** @internal */ | /** @internal */ | ||||
| void paint (Graphics& g); | void paint (Graphics& g); | ||||
| /** @internal */ | /** @internal */ | ||||
| @@ -251,6 +252,7 @@ public: | |||||
| void parentHierarchyChanged(); | void parentHierarchyChanged(); | ||||
| /** @internal */ | /** @internal */ | ||||
| const Rectangle<int> getTitleBarArea(); | const Rectangle<int> getTitleBarArea(); | ||||
| #endif | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -340,7 +340,7 @@ protected: | |||||
| /** @internal */ | /** @internal */ | ||||
| int getDesktopWindowStyleFlags() const; | int getDesktopWindowStyleFlags() const; | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| /** Overridden to warn people about adding components directly to this component | /** Overridden to warn people about adding components directly to this component | ||||
| instead of using setContentOwned(). | instead of using setContentOwned(). | ||||
| @@ -355,7 +355,7 @@ protected: | |||||
| a base-class method call to Component::addAndMakeVisible(), to side-step this warning. | a base-class method call to Component::addAndMakeVisible(), to side-step this warning. | ||||
| */ | */ | ||||
| void addAndMakeVisible (Component* child, int zOrder = -1); | void addAndMakeVisible (Component* child, int zOrder = -1); | ||||
| #endif | |||||
| #endif | |||||
| ScopedPointer <ResizableCornerComponent> resizableCorner; | ScopedPointer <ResizableCornerComponent> resizableCorner; | ||||
| ScopedPointer <ResizableBorderComponent> resizableBorder; | ScopedPointer <ResizableBorderComponent> resizableBorder; | ||||
| @@ -140,8 +140,9 @@ public: | |||||
| protected: | protected: | ||||
| /** @internal */ | |||||
| #ifndef DOXYGEN | |||||
| CameraDevice (const String& name, int index); | CameraDevice (const String& name, int index); | ||||
| #endif | |||||
| private: | private: | ||||
| void* internal; | void* internal; | ||||
| @@ -123,8 +123,9 @@ public: | |||||
| TimeSliceClient* getClient (int index) const; | TimeSliceClient* getClient (int index) const; | ||||
| //============================================================================== | //============================================================================== | ||||
| /** @internal */ | |||||
| #ifndef DOXYGEN | |||||
| void run(); | void run(); | ||||
| #endif | |||||
| //============================================================================== | //============================================================================== | ||||
| private: | private: | ||||