diff --git a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm index 960c26aed8..0133bb60e8 100644 --- a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm +++ b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm @@ -41,6 +41,10 @@ #define BUILD_AU_CARBON_UI 1 #endif +#if JUCE_64BIT + #undef BUILD_AU_CARBON_UI // (not possible in a 64-bit build) +#endif + #if BUILD_AU_CARBON_UI #undef Button #include "AUCarbonViewBase.h" diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 3d4b977203..22599b5761 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -933,6 +933,7 @@ public: CarbonViewWrapperComponent() : ComponentMovementWatcher (this), wrapperWindow (0), + carbonWindow (0), embeddedView (0), recursiveResize (false) { @@ -979,7 +980,7 @@ public: if (wrapperWindow == 0) return; - NSWindow* carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow]; + carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow]; NSWindow* ownerWindow = [((NSView*) getWindowHandle()) window]; [ownerWindow addChildWindow: carbonWindow @@ -1125,8 +1126,7 @@ public: recursiveHIViewRepaint (HIViewGetRoot (wrapperWindow)); } - OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, - EventRef event) + OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, EventRef event) { switch (GetEventKind (event)) { @@ -1137,6 +1137,7 @@ public: case kEventWindowGetClickActivation: { getTopLevelComponent()->toFront (false); + [carbonWindow makeKeyAndOrderFront: nil]; ClickActivationResult howToHandleClick = kActivateAndHandleClick; @@ -1151,14 +1152,14 @@ public: return eventNotHandledErr; } - static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef, - EventRef event, void* userData) + static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef, EventRef event, void* userData) { return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event); } protected: WindowRef wrapperWindow; + NSWindow* carbonWindow; HIViewRef embeddedView; bool recursiveResize; Time creationTime; @@ -4833,6 +4834,10 @@ public: return new Subtract (newDest, (input == left ? right : left)->clone()); } + + private: + Add (const Add&); + Add& operator= (const Add&); }; class Subtract : public BinaryTerm @@ -4856,6 +4861,10 @@ public: else return new Subtract (left->clone(), newDest); } + + private: + Subtract (const Subtract&); + Subtract& operator= (const Subtract&); }; class Multiply : public BinaryTerm @@ -4876,6 +4885,10 @@ public: return new Divide (newDest, (input == left ? right : left)->clone()); } + + private: + Multiply (const Multiply&); + Multiply& operator= (const Multiply&); }; class Divide : public BinaryTerm @@ -4899,6 +4912,10 @@ public: else return new Divide (left->clone(), newDest); } + + private: + Divide (const Divide&); + Divide& operator= (const Divide&); }; static Term* findDestinationFor (Term* const topLevel, const Term* const inputTerm) @@ -6878,7 +6895,8 @@ DirectoryIterator::DirectoryIterator (const File& directory, index (-1), totalNumFiles (-1), whatToLookFor (whatToLookFor_), - isRecursive (isRecursive_) + isRecursive (isRecursive_), + hasBeenAdvanced (false) { // you have to specify the type of files you're looking for! jassert ((whatToLookFor_ & (File::findFiles | File::findDirectories)) != 0); @@ -6897,6 +6915,8 @@ bool DirectoryIterator::next() bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, int64* const fileSize, Time* const modTime, Time* const creationTime, bool* const isReadOnly) { + hasBeenAdvanced = true; + if (subIterator != 0) { if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly)) @@ -6955,9 +6975,12 @@ bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResul const File DirectoryIterator::getFile() const { - if (subIterator != 0) + if (subIterator != 0 && subIterator->hasBeenAdvanced) return subIterator->getFile(); + // You need to call DirectoryIterator::next() before asking it for the file that it found! + jassert (hasBeenAdvanced); + return currentFile; } @@ -7883,13 +7906,18 @@ public: File::findFileSystemRoots (roots); expect (roots.size() > 0); + int numRootsExisting = 0; for (int i = 0; i < roots.size(); ++i) - expect (roots[i].exists()); + if (roots[i].exists()) + ++numRootsExisting; + + // (on windows, some of the drives may not contain media, so as long as at least one is ok..) + expect (numRootsExisting > 0); } beginTest ("Writing"); - File demoFolder (temp.getChildFile ("Juce UnitTests Temp Folder")); + File demoFolder (temp.getChildFile ("Juce UnitTests Temp Folder.folder")); expect (demoFolder.deleteRecursively()); expect (demoFolder.createDirectory()); expect (demoFolder.isDirectory()); @@ -7904,7 +7932,7 @@ public: { Array files; - temp.findChildFiles (files, File::findDirectories, false, "*"); + temp.findChildFiles (files, File::findDirectories, true, "*.folder"); expect (files.contains (demoFolder)); } @@ -27180,14 +27208,15 @@ void AudioDataConverters::deinterleaveSamples (const float* const source, } } +/* #if JUCE_UNIT_TESTS -/*class AudioConversionTests : public UnitTest +class AudioConversionTests : public UnitTest { public: AudioConversionTests() : UnitTest ("Audio data conversion") {} - template + template struct Test5 { static void test (UnitTest& unitTest) @@ -27196,38 +27225,48 @@ public: int32 original [numSamples], converted [numSamples], reversed [numSamples]; { - SourceType d (original); + AudioData::Pointer d (original); + bool clippingFailed = false; for (int i = 0; i < numSamples / 2; ++i) { - d.setAsFloat (Random::getSystemRandom().nextFloat() * 2.0f - 1.0f); - d.advance(); + d.setAsFloat (Random::getSystemRandom().nextFloat() * 2.2f - 1.1f); + + if (! d.isFloatingPoint()) + clippingFailed = d.getAsFloat() > 1.0f || d.getAsFloat() < -1.0f || clippingFailed; + + ++d; d.setAsInt32 (Random::getSystemRandom().nextInt()); - d.advance(); + ++d; } + + unitTest.expect (! clippingFailed); } // convert data from the source to dest format.. - ScopedPointer conv (new AudioData::ConverterInstance ()); - conv->copySamples (converted, original, numSamples); + ScopedPointer conv (new AudioData::ConverterInstance , + AudioData::Pointer >()); + conv->convertSamples (converted, original, numSamples); // ..and back again.. - conv = new AudioData::ConverterInstance (); + conv = new AudioData::ConverterInstance , + AudioData::Pointer >(); zerostruct (reversed); - conv->copySamples (reversed, converted, numSamples); + conv->convertSamples (reversed, converted, numSamples); { int biggestDiff = 0; - SourceType d1 (original); - SourceType d2 (reversed); + AudioData::Pointer d1 (original); + AudioData::Pointer d2 (reversed); - const int errorMargin = 2 * DestType::get32BitResolution() + SourceType::get32BitResolution(); + const int errorMargin = 2 * AudioData::Pointer::get32BitResolution() + + AudioData::Pointer::get32BitResolution(); for (int i = 0; i < numSamples; ++i) { biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32())); - d1.advance(); - d2.advance(); + ++d1; + ++d2; } unitTest.expect (biggestDiff <= errorMargin); @@ -27235,26 +27274,26 @@ public: } }; - template + template struct Test3 { static void test (UnitTest& unitTest) { - Test5 >::test (unitTest); - Test5 >::test (unitTest); + Test5 ::test (unitTest); + Test5 ::test (unitTest); } }; - template + template struct Test2 { static void test (UnitTest& unitTest) { - Test3 ::test (unitTest); - Test3 ::test (unitTest); - Test3 ::test (unitTest); - Test3 ::test (unitTest); - Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); } }; @@ -27263,8 +27302,8 @@ public: { static void test (UnitTest& unitTest) { - Test2 >::test (unitTest); - Test2 >::test (unitTest); + Test2 ::test (unitTest); + Test2 ::test (unitTest); } }; @@ -27281,9 +27320,9 @@ public: }; static AudioConversionTests audioConversionUnitTests; -*/ #endif +*/ END_JUCE_NAMESPACE /*** End of inlined file: juce_AudioDataConverters.cpp ***/ diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 740dc6210b..7f6aa63f6b 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -64,7 +64,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 68 +#define JUCE_BUILDNUMBER 69 /** Current Juce version number. @@ -5930,7 +5930,7 @@ private: long juce_InterlockedExchangeAdd (volatile long* a, long b) throw(); long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw(); __int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) throw(); - static void juce_MemoryBarrier() throw() { long x = 0; juce_InterlockedIncrement (&x); } + void juce_MemoryBarrier() throw() { long x = 0; juce_InterlockedIncrement (&x); } #endif #if JUCE_64BIT @@ -15506,6 +15506,7 @@ private: mutable int totalNumFiles; const int whatToLookFor; const bool isRecursive; + bool hasBeenAdvanced; ScopedPointer subIterator; File currentFile; @@ -37771,246 +37772,234 @@ private: #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ #define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ +#if 0 + /** + This class a container which holds all the classes pertaining to the AudioData::Pointer + audio sample format class. + @see AudioData::Pointer. */ -/* -struct JUCE_API AudioData +class JUCE_API AudioData { -xxx need to add int range limiting.. - - struct BigEndian - { - template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } - template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } - template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } - template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } - template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } - }; - - struct LittleEndian - { - template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } - template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } - template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } - template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } - template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromLE (source); } - }; - - #if JUCE_BIG_ENDIAN - typedef BigEndian NativeEndian; - #else - typedef LittleEndian NativeEndian; - #endif - - struct Int8 - { - inline Int8 (void* data_) : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / maxValue)); } - inline float getAsFloatBE() const throw() { return (float) (*data * (1.0 / maxValue)); } - inline void setAsFloatLE (float newValue) throw() { *data = (int8) roundToInt (newValue * (double) maxValue); } - inline void setAsFloatBE (float newValue) throw() { *data = (int8) roundToInt (newValue * (double) maxValue); } - inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); } - inline int32 getAsInt32BE() const throw() { return (int) (*data << 24); } - inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); } - inline void setAsInt32BE (int newValue) throw() { *data = (int8) (newValue >> 24); } - - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } - inline void copyFromSameType (Int8& source) throw() { *data = *source.data; } - - int8* data; - enum { maxValue = 0x80, resolution = 0x1000000, isFloat = 0 }; - }; - - struct Int16 - { - inline Int16 (void* data_) : data (static_cast (data_)) {} +public: - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - inline float getAsFloatLE() const throw() { return (float) ((1.0 / maxValue) * (int16) ByteOrder::swapIfBigEndian (*data)); } - inline float getAsFloatBE() const throw() { return (float) ((1.0 / maxValue) * (int16) ByteOrder::swapIfLittleEndian (*data)); } - inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) roundToInt (newValue * (double) maxValue)); } - inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) roundToInt (newValue * (double) maxValue)); } - inline int32 getAsInt32LE() const throw() { return (int32) (ByteOrder::swapIfBigEndian ((uint16) *data) << 16); } - inline int32 getAsInt32BE() const throw() { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); } - inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); } - inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); } + // These types can be used as the SampleFormat template parameter for the AudioData::Pointer class. - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } - inline void copyFromSameType (Int16& source) throw() { *data = *source.data; } + class Int8; /**< Used as a template parameter for AudioData::Pointer. Indicates an 8-bit integer packed data format. */ + class Int16; /**< Used as a template parameter for AudioData::Pointer. Indicates an 16-bit integer packed data format. */ + class Int24; /**< Used as a template parameter for AudioData::Pointer. Indicates an 24-bit integer packed data format. */ + class Int32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit integer packed data format. */ + class Float32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit float data format. */ - uint16* data; - enum { maxValue = 0x8000, resolution = 0x10000, isFloat = 0 }; - }; + // These types can be used as the Endianness template parameter for the AudioData::Pointer class. - struct Int24 - { - inline Int24 (void* data_) : data (static_cast (data_)) {} + class BigEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in big-endian order. */ + class LittleEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in little-endian order. */ + class NativeEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in the CPU's native endianness. */ - inline void advance() throw() { data += 3; } - inline void skip (int numSamples) throw() { data += 3 * numSamples; } + // These types can be used as the InterleavingType template parameter for the AudioData::Pointer class. - inline float getAsFloatLE() const throw() { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / maxValue)); } - inline float getAsFloatBE() const throw() { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / maxValue)); } - inline void setAsFloatLE (float newValue) throw() { ByteOrder::littleEndian24BitToChars (roundToInt (newValue * (double) maxValue), data); } - inline void setAsFloatBE (float newValue) throw() { ByteOrder::bigEndian24BitToChars (roundToInt (newValue * (double) maxValue), data); } - inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::littleEndian24Bit (data) << 8; } - inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; } - inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); } - inline void setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); } + class NonInterleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored contiguously. */ + class Interleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are interleaved with a number of other channels. */ - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } - inline void copyFromSameType (Int24& source) throw() { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; } + // These types can be used as the Constness template parameter for the AudioData::Pointer class. - char* data; - enum { maxValue = 0x800000, resolution = 0x100, isFloat = 0 }; - }; + class NonConst; /**< Used as a template parameter for AudioData::Pointer. Indicates that the pointer can be used for non-const data. */ + class Const; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples can only be used for const data.. */ - struct Int32 - { - inline Int32 (void* data_) : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } - inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } - inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) roundToInt (newValue * (1.0 + maxValue))); } - inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (newValue * (1.0 + maxValue))); } - inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::swapIfBigEndian (*data); } - inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); } - inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } - inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); } + /** + A pointer to a block of audio data with a particular encoding. - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } - inline void copyFromSameType (Int32& source) throw() { *data = *source.data; } + This object can be used to read and write from blocks of encoded audio samples. To create one, you specify + the audio format as a series of template parameters, e.g. + @code + // this creates a pointer for reading from a const array of 16-bit little-endian packed samples. + AudioData::Pointer pointer (someRawAudioData); + + // These methods read the sample that is being pointed to + float firstSampleAsFloat = pointer.getAsFloat(); + int32 firstSampleAsInt = pointer.getAsInt32(); + ++pointer; // moves the pointer to the next sample. + pointer += 3; // skips the next 3 samples. + @endcode - uint32* data; - enum { maxValue = 0x7fffffff, resolution = 1, isFloat = 0 }; - }; + The convertSamples() method lets you copy a range of samples from one format to another, automatically + converting its format. - struct Float32 + @see AudioData::Converter + */ + template + class Pointer : private InterleavingType { - inline Float32 (void* data_) : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - - #if JUCE_BIG_ENDIAN - inline float getAsFloatBE() const throw() { return *data; } - inline void setAsFloatBE (float newValue) throw() { *data = newValue; } - inline float getAsFloatLE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } - inline void setAsFloatLE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } - #else - inline float getAsFloatLE() const throw() { return *data; } - inline void setAsFloatLE (float newValue) throw() { *data = newValue; } - inline float getAsFloatBE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } - inline void setAsFloatBE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } - #endif - - inline int32 getAsInt32LE() const throw() { return (int32) roundToInt (getAsFloatLE() * (1.0 + maxValue)); } - inline int32 getAsInt32BE() const throw() { return (int32) roundToInt (getAsFloatBE() * (1.0 + maxValue)); } - inline void setAsInt32LE (int32 newValue) throw() { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } - inline void setAsInt32BE (int32 newValue) throw() { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } + public: - template inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } - template inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); } - inline void copyFromSameType (Float32& source) throw() { *data = *source.data; } + /** Creates a non-interleaved pointer from some raw data in the appropriate format. + This constructor is only used if you've specified the AudioData::NonInterleaved option - + for interleaved formats, use the constructor that also takes a number of channels. + */ + Pointer (typename Constness::VoidType* sourceData) throw() + : data (Constness::toVoidPtr (sourceData)) + { + // If you're using interleaved data, call the other constructor! If you're using non-interleaved data, + // you should pass NonInterleaved as the template parameter for the interleaving type! + static_jassert (InterleavingType::isInterleavedType == 0); + } - float* data; - enum { maxValue = 0x7fffffff, resolution = 0x100, isFloat = 1 }; - }; + /** Creates a pointer from some raw data in the appropriate format with the specified number of interleaved channels. + For non-interleaved data, use the other constructor. + */ + Pointer (typename Constness::VoidType* sourceData, int numInterleavedChannels) throw() + : InterleavingType (numInterleavedChannels), + data (Constness::toVoidPtr (sourceData)) + { + // If you're using non-interleaved data, call the other constructor! If you're using non-interleaved data, + // you should pass NonInterleaved as the template parameter for the interleaving type! + static_jassert (InterleavingType::isInterleavedType != 0); + } - struct NonInterleaved - { - inline NonInterleaved () throw() {} - inline NonInterleaved (const int numChannels) throw() - { jassert (numChannels == 1); } // If you hit this assert, you're trying to create a non-interleaved pointer with more than one interleaved channel.. + /** Creates a copy of another pointer. */ + Pointer (const Pointer& other) throw() + : data (other.data) + { + } - template inline void advance (SampleFormatType& s) throw() { s.advance(); } - }; + Pointer& operator= (const Pointer& other) throw() + { + data = other.data; + return *this; + } - struct Interleaved - { - inline Interleaved () throw() : numChannels (1) {} - inline Interleaved (const int numChannels_) throw() : numChannels (numChannels_) {} - template inline void advance (SampleFormatType& s) throw() { s.skip (numChannels); } + /** Returns the value of the first sample as a floating point value. + The value will be in the range -1.0 to 1.0 for integer formats. For floating point + formats, the value could be outside that range, although -1 to 1 is the standard range. + */ + inline float getAsFloat() const throw() { return Endianness::getAsFloat (data); } - const int numChannels; - }; + /** Sets the value of the first sample as a floating point value. - template - class Pointer - { - public: - Pointer (const void* sourceData) - : data (const_cast (sourceData)) + (This method can only be used if the AudioData::NonConst option was used). + The value should be in the range -1.0 to 1.0 - for integer formats, values outside that + range will be clipped. For floating point formats, any value passed in here will be + written directly, although -1 to 1 is the standard range. + */ + inline void setAsFloat (float newValue) throw() { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + Endianness::setAsFloat (data, newValue); } - Pointer (const void* sourceData, int numInterleavedChannels) - : data (const_cast (sourceData)), - interleaving (numInterleavedChannels) + /** Returns the value of the first sample as a 32-bit integer. + The value returned will be in the range 0x80000000 to 0x7fffffff, and shorter values will be + shifted to fill this range (e.g. if you're reading from 24-bit data, the values will be shifted up + by 8 bits when returned here). If the source data is floating point, values beyond -1.0 to 1.0 will + be clipped so that -1.0 maps onto -0x7fffffff and 1.0 maps to 0x7fffffff. + */ + inline int32 getAsInt32() const throw() { return Endianness::getAsInt32 (data); } + + /** Sets the value of the first sample as a 32-bit integer. + This will be mapped to the range of the format that is being written - see getAsInt32(). + */ + inline void setAsInt32 (int32 newValue) throw() { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + Endianness::setAsInt32 (data, newValue); } - inline float getAsFloat() const throw() { return Endianness::getAsFloat (data); } - inline void setAsFloat (float newValue) throw() { Endianness::setAsFloat (data, newValue); } + /** Adds a number of samples to the pointer's position. */ + inline Pointer& operator++() throw() { advance(); return *this; } - inline int32 getAsInt32() const throw() { return Endianness::getAsInt32 (data); } - inline void setAsInt32 (int32 newValue) throw() { Endianness::setAsInt32 (data, newValue); } + /** Adds a number of samples to the pointer's position. */ + Pointer& operator+= (int samplesToJump) throw() { advanceDataBy (data, samplesToJump); return *this; } - inline void advance() throw() { interleaving.advance (data); } - - void copySamples (Pointer& source, int numSamples) + /** Writes a stream of samples into this pointer from another pointer. + This will copy the specified number of samples, converting between formats appropriately. + */ + void convertSamples (Pointer source, int numSamples) const throw() { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + + Pointer dest (*this); while (--numSamples >= 0) { - data.copyFromSameType (source.data); - advance(); + dest.data.copyFromSameType (source.data); + dest.advance(); source.advance(); } } + /** Writes a stream of samples into this pointer from another pointer. + This will copy the specified number of samples, converting between formats appropriately. + */ template - void copySamples (OtherPointerType& source, int numSamples) + void convertSamples (OtherPointerType source, int numSamples) const throw() { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + + Pointer dest (*this); while (--numSamples >= 0) { - Endianness::copyFrom (data, source); - advance(); - source.advance(); + Endianness::copyFrom (dest.data, source); + dest.advance(); + ++source; } } - bool isFloatingPoint() const throw() { return (bool) SampleFormat::isFloat; } - static int get32BitResolution() throw() { return (int) SampleFormat::resolution; } + /** Returns true if the pointer is using a floating-point format. */ + static bool isFloatingPoint() throw() { return (bool) SampleFormat::isFloat; } + + /** Returns true if the format is big-endian. */ + static bool isBigEndian() throw() { return (bool) Endianness::isBigEndian; } + + /** Returns the number of interleaved channels in the format. */ + int getNumInterleavedChannels() const throw() { return (int) this->numInterleavedChannels; } - typedef Endianness EndiannessType; + /** Returns the accuracy of this format when represented as a 32-bit integer. + This is the smallest number above 0 that can be represented in the sample format, converted to + a 32-bit range. E,g. if the format is 8-bit, its resolution is 0x01000000; if the format is 24-bit, + its resolution is 0x100. + */ + static int get32BitResolution() throw() { return (int) SampleFormat::resolution; } private: SampleFormat data; - InterleavingType interleaving; + + inline void advance() throw() { advanceData (data); } }; + /** A base class for objects that are used to convert between two different sample formats. + + The AudioData::ConverterInstance implements this base class and can be templated, so + you can create an instance that converts between two particular formats, and then + store this in the abstract base class. + + @see AudioData::ConverterInstance + */ class Converter { public: virtual ~Converter() {} - virtual void copySamples (void* dest, const void* source, int numSamples) const = 0; + /** + */ + virtual void convertSamples (void* dest, const void* source, int numSamples) const = 0; }; + /** + A class that converts between two templated AudioData::Pointer types, and which + implements the AudioData::Converter interface. + + This can be used as a concrete instance of the AudioData::Converter abstract class. + + @see AudioData::Converter + */ template class ConverterInstance : public Converter { @@ -38018,11 +38007,11 @@ xxx need to add int range limiting.. ConverterInstance() {} ~ConverterInstance() {} - void copySamples (void* const dest, const void* const source, const int numSamples) const + void convertSamples (void* dest, const void* source, int numSamples) const { SourceSampleType s (source); DestSampleType d (dest); - d.copySamples (s, numSamples); + d.convertSamples (s, numSamples); } private: @@ -38030,7 +38019,202 @@ xxx need to add int range limiting.. ConverterInstance& operator= (const ConverterInstance&); }; }; -*/ + +#ifndef DOXYGEN + +class AudioData::BigEndian +{ +public: + template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } + template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } + template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } + enum { isBigEndian = 1 }; +}; + +class AudioData::LittleEndian +{ +public: + template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } + template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } + template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromLE (source); } + enum { isBigEndian = 0 }; +}; + +#if JUCE_BIG_ENDIAN + class AudioData::NativeEndian : public AudioData::BigEndian {}; +#else + class AudioData::NativeEndian : public AudioData::LittleEndian {}; +#endif + +class AudioData::Int8 +{ +public: + inline Int8 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / (1.0 + maxValue))); } + inline float getAsFloatBE() const throw() { return getAsFloatLE(); } + inline void setAsFloatLE (float newValue) throw() { *data = jlimit ((int8) -maxValue, (int8) maxValue, (int8) roundToInt (newValue * (1.0 + maxValue))); } + inline void setAsFloatBE (float newValue) throw() { setAsFloatLE (newValue); } + inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); } + inline int32 getAsInt32BE() const throw() { return getAsInt32LE(); } + inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); } + inline void setAsInt32BE (int newValue) throw() { setAsInt32LE (newValue); } + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int8& source) throw() { *data = *source.data; } + + int8* data; + enum { maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 }; +}; + +class AudioData::Int16 +{ +public: + inline Int16 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) jlimit ((int16) -maxValue, (int16) maxValue, (int16) roundToInt (newValue * (1.0 + maxValue)))); } + inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) jlimit ((int16) -maxValue, (int16) maxValue, (int16) roundToInt (newValue * (1.0 + maxValue)))); } + inline int32 getAsInt32LE() const throw() { return (int32) (ByteOrder::swapIfBigEndian ((uint16) *data) << 16); } + inline int32 getAsInt32BE() const throw() { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); } + inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); } + inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); } + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int16& source) throw() { *data = *source.data; } + + uint16* data; + enum { maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 }; +}; + +class AudioData::Int24 +{ +public: + inline Int24 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { data += 3; } + inline void skip (int numSamples) throw() { data += 3 * numSamples; } + inline float getAsFloatLE() const throw() { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } + inline float getAsFloatBE() const throw() { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } + inline void setAsFloatLE (float newValue) throw() { ByteOrder::littleEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } + inline void setAsFloatBE (float newValue) throw() { ByteOrder::bigEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } + inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::littleEndian24Bit (data) << 8; } + inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; } + inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); } + inline void setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); } + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int24& source) throw() { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; } + + char* data; + enum { maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 }; +}; + +class AudioData::Int32 +{ +public: + inline Int32 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } + inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } + inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::swapIfBigEndian (*data); } + inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); } + inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } + inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); } + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int32& source) throw() { *data = *source.data; } + + uint32* data; + enum { maxValue = 0x7fffffff, resolution = 1, isFloat = 0 }; +}; + +class AudioData::Float32 +{ +public: + inline Float32 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + #if JUCE_BIG_ENDIAN + inline float getAsFloatBE() const throw() { return *data; } + inline void setAsFloatBE (float newValue) throw() { *data = newValue; } + inline float getAsFloatLE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } + inline void setAsFloatLE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } + #else + inline float getAsFloatLE() const throw() { return *data; } + inline void setAsFloatLE (float newValue) throw() { *data = newValue; } + inline float getAsFloatBE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } + inline void setAsFloatBE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } + #endif + inline int32 getAsInt32LE() const throw() { return (int32) roundToInt (jlimit (-1.0f, 1.0f, getAsFloatLE()) * (1.0 + maxValue)); } + inline int32 getAsInt32BE() const throw() { return (int32) roundToInt (jlimit (-1.0f, 1.0f, getAsFloatBE()) * (1.0 + maxValue)); } + inline void setAsInt32LE (int32 newValue) throw() { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } + inline void setAsInt32BE (int32 newValue) throw() { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } + template inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } + template inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); } + inline void copyFromSameType (Float32& source) throw() { *data = *source.data; } + + float* data; + enum { maxValue = 0x7fffffff, resolution = (1 << 8), isFloat = 1 }; +}; + +class AudioData::NonInterleaved +{ +public: + inline NonInterleaved() throw() {} + inline NonInterleaved (const int) throw() {} + template inline void advanceData (SampleFormatType& s) throw() { s.advance(); } + template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); } + enum { isInterleavedType = 0, numInterleavedChannels = 1 }; +}; + +class AudioData::Interleaved +{ +public: + inline Interleaved() throw() : numInterleavedChannels (1) {} + inline Interleaved (const int numInterleavedChannels_) throw() : numInterleavedChannels (numInterleavedChannels_) {} + template inline void advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); } + template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numInterleavedChannels * numSamples); } + const int numInterleavedChannels; + enum { isInterleavedType = 1 }; + +private: + Interleaved& operator= (const Interleaved&); +}; + +class AudioData::NonConst +{ +public: + typedef void VoidType; + static inline void* toVoidPtr (VoidType* v) throw() { return v; } + enum { isConst = 0 }; +}; + +class AudioData::Const +{ +public: + typedef const void VoidType; + static inline void* toVoidPtr (VoidType* v) throw() { return const_cast (v); } + enum { isConst = 1 }; +}; + +#endif + +#endif /** A set of routines to convert buffers of 32-bit floating point data to and from diff --git a/src/audio/dsp/juce_AudioDataConverters.cpp b/src/audio/dsp/juce_AudioDataConverters.cpp index 60b10882a8..a886ca1217 100644 --- a/src/audio/dsp/juce_AudioDataConverters.cpp +++ b/src/audio/dsp/juce_AudioDataConverters.cpp @@ -531,17 +531,18 @@ void AudioDataConverters::deinterleaveSamples (const float* const source, } } +/* #if JUCE_UNIT_TESTS #include "../../utilities/juce_UnitTest.h" #include "../../core/juce_Random.h" -/*class AudioConversionTests : public UnitTest +class AudioConversionTests : public UnitTest { public: AudioConversionTests() : UnitTest ("Audio data conversion") {} - template + template struct Test5 { static void test (UnitTest& unitTest) @@ -550,38 +551,48 @@ public: int32 original [numSamples], converted [numSamples], reversed [numSamples]; { - SourceType d (original); + AudioData::Pointer d (original); + bool clippingFailed = false; for (int i = 0; i < numSamples / 2; ++i) { - d.setAsFloat (Random::getSystemRandom().nextFloat() * 2.0f - 1.0f); - d.advance(); + d.setAsFloat (Random::getSystemRandom().nextFloat() * 2.2f - 1.1f); + + if (! d.isFloatingPoint()) + clippingFailed = d.getAsFloat() > 1.0f || d.getAsFloat() < -1.0f || clippingFailed; + + ++d; d.setAsInt32 (Random::getSystemRandom().nextInt()); - d.advance(); + ++d; } + + unitTest.expect (! clippingFailed); } // convert data from the source to dest format.. - ScopedPointer conv (new AudioData::ConverterInstance ()); - conv->copySamples (converted, original, numSamples); + ScopedPointer conv (new AudioData::ConverterInstance , + AudioData::Pointer >()); + conv->convertSamples (converted, original, numSamples); // ..and back again.. - conv = new AudioData::ConverterInstance (); + conv = new AudioData::ConverterInstance , + AudioData::Pointer >(); zerostruct (reversed); - conv->copySamples (reversed, converted, numSamples); + conv->convertSamples (reversed, converted, numSamples); { int biggestDiff = 0; - SourceType d1 (original); - SourceType d2 (reversed); + AudioData::Pointer d1 (original); + AudioData::Pointer d2 (reversed); - const int errorMargin = 2 * DestType::get32BitResolution() + SourceType::get32BitResolution(); + const int errorMargin = 2 * AudioData::Pointer::get32BitResolution() + + AudioData::Pointer::get32BitResolution(); for (int i = 0; i < numSamples; ++i) { biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32())); - d1.advance(); - d2.advance(); + ++d1; + ++d2; } unitTest.expect (biggestDiff <= errorMargin); @@ -589,26 +600,26 @@ public: } }; - template + template struct Test3 { static void test (UnitTest& unitTest) { - Test5 >::test (unitTest); - Test5 >::test (unitTest); + Test5 ::test (unitTest); + Test5 ::test (unitTest); } }; - template + template struct Test2 { static void test (UnitTest& unitTest) { - Test3 ::test (unitTest); - Test3 ::test (unitTest); - Test3 ::test (unitTest); - Test3 ::test (unitTest); - Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); } }; @@ -617,8 +628,8 @@ public: { static void test (UnitTest& unitTest) { - Test2 >::test (unitTest); - Test2 >::test (unitTest); + Test2 ::test (unitTest); + Test2 ::test (unitTest); } }; @@ -635,9 +646,8 @@ public: }; static AudioConversionTests audioConversionUnitTests; -*/ #endif - +*/ END_JUCE_NAMESPACE diff --git a/src/audio/dsp/juce_AudioDataConverters.h b/src/audio/dsp/juce_AudioDataConverters.h index 040dd3893f..08a86bd16e 100644 --- a/src/audio/dsp/juce_AudioDataConverters.h +++ b/src/audio/dsp/juce_AudioDataConverters.h @@ -26,254 +26,242 @@ #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ #define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ +#if 0 + //============================================================================== /** + This class a container which holds all the classes pertaining to the AudioData::Pointer + audio sample format class. + @see AudioData::Pointer. */ -/* -struct JUCE_API AudioData +class JUCE_API AudioData { -xxx need to add int range limiting.. +public: //============================================================================== - struct BigEndian - { - template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } - template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } - template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } - template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } - template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } - }; - - struct LittleEndian - { - template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } - template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } - template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } - template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } - template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromLE (source); } - }; + // These types can be used as the SampleFormat template parameter for the AudioData::Pointer class. - #if JUCE_BIG_ENDIAN - typedef BigEndian NativeEndian; - #else - typedef LittleEndian NativeEndian; - #endif + class Int8; /**< Used as a template parameter for AudioData::Pointer. Indicates an 8-bit integer packed data format. */ + class Int16; /**< Used as a template parameter for AudioData::Pointer. Indicates an 16-bit integer packed data format. */ + class Int24; /**< Used as a template parameter for AudioData::Pointer. Indicates an 24-bit integer packed data format. */ + class Int32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit integer packed data format. */ + class Float32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit float data format. */ //============================================================================== - struct Int8 - { - inline Int8 (void* data_) : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / maxValue)); } - inline float getAsFloatBE() const throw() { return (float) (*data * (1.0 / maxValue)); } - inline void setAsFloatLE (float newValue) throw() { *data = (int8) roundToInt (newValue * (double) maxValue); } - inline void setAsFloatBE (float newValue) throw() { *data = (int8) roundToInt (newValue * (double) maxValue); } - inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); } - inline int32 getAsInt32BE() const throw() { return (int) (*data << 24); } - inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); } - inline void setAsInt32BE (int newValue) throw() { *data = (int8) (newValue >> 24); } - - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } - inline void copyFromSameType (Int8& source) throw() { *data = *source.data; } - - int8* data; - enum { maxValue = 0x80, resolution = 0x1000000, isFloat = 0 }; - }; + // These types can be used as the Endianness template parameter for the AudioData::Pointer class. - struct Int16 - { - inline Int16 (void* data_) : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - inline float getAsFloatLE() const throw() { return (float) ((1.0 / maxValue) * (int16) ByteOrder::swapIfBigEndian (*data)); } - inline float getAsFloatBE() const throw() { return (float) ((1.0 / maxValue) * (int16) ByteOrder::swapIfLittleEndian (*data)); } - inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) roundToInt (newValue * (double) maxValue)); } - inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) roundToInt (newValue * (double) maxValue)); } - inline int32 getAsInt32LE() const throw() { return (int32) (ByteOrder::swapIfBigEndian ((uint16) *data) << 16); } - inline int32 getAsInt32BE() const throw() { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); } - inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); } - inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); } - - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } - inline void copyFromSameType (Int16& source) throw() { *data = *source.data; } - - uint16* data; - enum { maxValue = 0x8000, resolution = 0x10000, isFloat = 0 }; - }; - - struct Int24 - { - inline Int24 (void* data_) : data (static_cast (data_)) {} - - inline void advance() throw() { data += 3; } - inline void skip (int numSamples) throw() { data += 3 * numSamples; } - - inline float getAsFloatLE() const throw() { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / maxValue)); } - inline float getAsFloatBE() const throw() { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / maxValue)); } - inline void setAsFloatLE (float newValue) throw() { ByteOrder::littleEndian24BitToChars (roundToInt (newValue * (double) maxValue), data); } - inline void setAsFloatBE (float newValue) throw() { ByteOrder::bigEndian24BitToChars (roundToInt (newValue * (double) maxValue), data); } - inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::littleEndian24Bit (data) << 8; } - inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; } - inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); } - inline void setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); } - - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } - inline void copyFromSameType (Int24& source) throw() { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; } - - char* data; - enum { maxValue = 0x800000, resolution = 0x100, isFloat = 0 }; - }; - - struct Int32 - { - inline Int32 (void* data_) : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } - inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } - inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) roundToInt (newValue * (1.0 + maxValue))); } - inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (newValue * (1.0 + maxValue))); } - inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::swapIfBigEndian (*data); } - inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); } - inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } - inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); } - - template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } - template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } - inline void copyFromSameType (Int32& source) throw() { *data = *source.data; } - - uint32* data; - enum { maxValue = 0x7fffffff, resolution = 1, isFloat = 0 }; - }; - - struct Float32 - { - inline Float32 (void* data_) : data (static_cast (data_)) {} - - inline void advance() throw() { ++data; } - inline void skip (int numSamples) throw() { data += numSamples; } - - #if JUCE_BIG_ENDIAN - inline float getAsFloatBE() const throw() { return *data; } - inline void setAsFloatBE (float newValue) throw() { *data = newValue; } - inline float getAsFloatLE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } - inline void setAsFloatLE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } - #else - inline float getAsFloatLE() const throw() { return *data; } - inline void setAsFloatLE (float newValue) throw() { *data = newValue; } - inline float getAsFloatBE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } - inline void setAsFloatBE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } - #endif - - inline int32 getAsInt32LE() const throw() { return (int32) roundToInt (getAsFloatLE() * (1.0 + maxValue)); } - inline int32 getAsInt32BE() const throw() { return (int32) roundToInt (getAsFloatBE() * (1.0 + maxValue)); } - inline void setAsInt32LE (int32 newValue) throw() { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } - inline void setAsInt32BE (int32 newValue) throw() { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } - - template inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } - template inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); } - inline void copyFromSameType (Float32& source) throw() { *data = *source.data; } - - float* data; - enum { maxValue = 0x7fffffff, resolution = 0x100, isFloat = 1 }; - }; + class BigEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in big-endian order. */ + class LittleEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in little-endian order. */ + class NativeEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in the CPU's native endianness. */ //============================================================================== - struct NonInterleaved - { - inline NonInterleaved () throw() {} - inline NonInterleaved (const int numChannels) throw() - { jassert (numChannels == 1); } // If you hit this assert, you're trying to create a non-interleaved pointer with more than one interleaved channel.. - - template inline void advance (SampleFormatType& s) throw() { s.advance(); } - }; + // These types can be used as the InterleavingType template parameter for the AudioData::Pointer class. - struct Interleaved - { - inline Interleaved () throw() : numChannels (1) {} - inline Interleaved (const int numChannels_) throw() : numChannels (numChannels_) {} - template inline void advance (SampleFormatType& s) throw() { s.skip (numChannels); } + class NonInterleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored contiguously. */ + class Interleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are interleaved with a number of other channels. */ - const int numChannels; - }; + //============================================================================== + // These types can be used as the Constness template parameter for the AudioData::Pointer class. + class NonConst; /**< Used as a template parameter for AudioData::Pointer. Indicates that the pointer can be used for non-const data. */ + class Const; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples can only be used for const data.. */ //============================================================================== - template - class Pointer + /** + A pointer to a block of audio data with a particular encoding. + + This object can be used to read and write from blocks of encoded audio samples. To create one, you specify + the audio format as a series of template parameters, e.g. + @code + // this creates a pointer for reading from a const array of 16-bit little-endian packed samples. + AudioData::Pointer pointer (someRawAudioData); + + // These methods read the sample that is being pointed to + float firstSampleAsFloat = pointer.getAsFloat(); + int32 firstSampleAsInt = pointer.getAsInt32(); + ++pointer; // moves the pointer to the next sample. + pointer += 3; // skips the next 3 samples. + @endcode + + The convertSamples() method lets you copy a range of samples from one format to another, automatically + converting its format. + + @see AudioData::Converter + */ + template + class Pointer : private InterleavingType { public: - Pointer (const void* sourceData) - : data (const_cast (sourceData)) + //============================================================================== + /** Creates a non-interleaved pointer from some raw data in the appropriate format. + This constructor is only used if you've specified the AudioData::NonInterleaved option - + for interleaved formats, use the constructor that also takes a number of channels. + */ + Pointer (typename Constness::VoidType* sourceData) throw() + : data (Constness::toVoidPtr (sourceData)) + { + // If you're using interleaved data, call the other constructor! If you're using non-interleaved data, + // you should pass NonInterleaved as the template parameter for the interleaving type! + static_jassert (InterleavingType::isInterleavedType == 0); + } + + /** Creates a pointer from some raw data in the appropriate format with the specified number of interleaved channels. + For non-interleaved data, use the other constructor. + */ + Pointer (typename Constness::VoidType* sourceData, int numInterleavedChannels) throw() + : InterleavingType (numInterleavedChannels), + data (Constness::toVoidPtr (sourceData)) + { + // If you're using non-interleaved data, call the other constructor! If you're using non-interleaved data, + // you should pass NonInterleaved as the template parameter for the interleaving type! + static_jassert (InterleavingType::isInterleavedType != 0); + } + + /** Creates a copy of another pointer. */ + Pointer (const Pointer& other) throw() + : data (other.data) { } - Pointer (const void* sourceData, int numInterleavedChannels) - : data (const_cast (sourceData)), - interleaving (numInterleavedChannels) + Pointer& operator= (const Pointer& other) throw() { + data = other.data; + return *this; } //============================================================================== - inline float getAsFloat() const throw() { return Endianness::getAsFloat (data); } - inline void setAsFloat (float newValue) throw() { Endianness::setAsFloat (data, newValue); } + /** Returns the value of the first sample as a floating point value. + The value will be in the range -1.0 to 1.0 for integer formats. For floating point + formats, the value could be outside that range, although -1 to 1 is the standard range. + */ + inline float getAsFloat() const throw() { return Endianness::getAsFloat (data); } + + /** Sets the value of the first sample as a floating point value. + + (This method can only be used if the AudioData::NonConst option was used). + The value should be in the range -1.0 to 1.0 - for integer formats, values outside that + range will be clipped. For floating point formats, any value passed in here will be + written directly, although -1 to 1 is the standard range. + */ + inline void setAsFloat (float newValue) throw() + { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + Endianness::setAsFloat (data, newValue); + } - inline int32 getAsInt32() const throw() { return Endianness::getAsInt32 (data); } - inline void setAsInt32 (int32 newValue) throw() { Endianness::setAsInt32 (data, newValue); } + /** Returns the value of the first sample as a 32-bit integer. + The value returned will be in the range 0x80000000 to 0x7fffffff, and shorter values will be + shifted to fill this range (e.g. if you're reading from 24-bit data, the values will be shifted up + by 8 bits when returned here). If the source data is floating point, values beyond -1.0 to 1.0 will + be clipped so that -1.0 maps onto -0x7fffffff and 1.0 maps to 0x7fffffff. + */ + inline int32 getAsInt32() const throw() { return Endianness::getAsInt32 (data); } + + /** Sets the value of the first sample as a 32-bit integer. + This will be mapped to the range of the format that is being written - see getAsInt32(). + */ + inline void setAsInt32 (int32 newValue) throw() + { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + Endianness::setAsInt32 (data, newValue); + } - inline void advance() throw() { interleaving.advance (data); } + /** Adds a number of samples to the pointer's position. */ + inline Pointer& operator++() throw() { advance(); return *this; } - void copySamples (Pointer& source, int numSamples) + /** Adds a number of samples to the pointer's position. */ + Pointer& operator+= (int samplesToJump) throw() { advanceDataBy (data, samplesToJump); return *this; } + + /** Writes a stream of samples into this pointer from another pointer. + This will copy the specified number of samples, converting between formats appropriately. + */ + void convertSamples (Pointer source, int numSamples) const throw() { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + + Pointer dest (*this); while (--numSamples >= 0) { - data.copyFromSameType (source.data); - advance(); + dest.data.copyFromSameType (source.data); + dest.advance(); source.advance(); } } + /** Writes a stream of samples into this pointer from another pointer. + This will copy the specified number of samples, converting between formats appropriately. + */ template - void copySamples (OtherPointerType& source, int numSamples) + void convertSamples (OtherPointerType source, int numSamples) const throw() { + static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! + + Pointer dest (*this); while (--numSamples >= 0) { - Endianness::copyFrom (data, source); - advance(); - source.advance(); + Endianness::copyFrom (dest.data, source); + dest.advance(); + ++source; } } - bool isFloatingPoint() const throw() { return (bool) SampleFormat::isFloat; } - static int get32BitResolution() throw() { return (int) SampleFormat::resolution; } + /** Returns true if the pointer is using a floating-point format. */ + static bool isFloatingPoint() throw() { return (bool) SampleFormat::isFloat; } - typedef Endianness EndiannessType; + /** Returns true if the format is big-endian. */ + static bool isBigEndian() throw() { return (bool) Endianness::isBigEndian; } + + /** Returns the number of interleaved channels in the format. */ + int getNumInterleavedChannels() const throw() { return (int) this->numInterleavedChannels; } + + /** Returns the accuracy of this format when represented as a 32-bit integer. + This is the smallest number above 0 that can be represented in the sample format, converted to + a 32-bit range. E,g. if the format is 8-bit, its resolution is 0x01000000; if the format is 24-bit, + its resolution is 0x100. + */ + static int get32BitResolution() throw() { return (int) SampleFormat::resolution; } private: //============================================================================== SampleFormat data; - InterleavingType interleaving; + + inline void advance() throw() { advanceData (data); } }; //============================================================================== + /** A base class for objects that are used to convert between two different sample formats. + + The AudioData::ConverterInstance implements this base class and can be templated, so + you can create an instance that converts between two particular formats, and then + store this in the abstract base class. + + @see AudioData::ConverterInstance + */ class Converter { public: virtual ~Converter() {} - virtual void copySamples (void* dest, const void* source, int numSamples) const = 0; + /** + */ + virtual void convertSamples (void* dest, const void* source, int numSamples) const = 0; }; //============================================================================== + /** + A class that converts between two templated AudioData::Pointer types, and which + implements the AudioData::Converter interface. + + This can be used as a concrete instance of the AudioData::Converter abstract class. + + @see AudioData::Converter + */ template class ConverterInstance : public Converter { @@ -281,11 +269,11 @@ xxx need to add int range limiting.. ConverterInstance() {} ~ConverterInstance() {} - void copySamples (void* const dest, const void* const source, const int numSamples) const + void convertSamples (void* dest, const void* source, int numSamples) const { SourceSampleType s (source); DestSampleType d (dest); - d.copySamples (s, numSamples); + d.convertSamples (s, numSamples); } private: @@ -293,7 +281,207 @@ xxx need to add int range limiting.. ConverterInstance& operator= (const ConverterInstance&); }; }; -*/ + + +#ifndef DOXYGEN + +//============================================================================== +class AudioData::BigEndian +{ +public: + template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } + template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } + template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } + enum { isBigEndian = 1 }; +}; + +class AudioData::LittleEndian +{ +public: + template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } + template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } + template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromLE (source); } + enum { isBigEndian = 0 }; +}; + +#if JUCE_BIG_ENDIAN + class AudioData::NativeEndian : public AudioData::BigEndian {}; +#else + class AudioData::NativeEndian : public AudioData::LittleEndian {}; +#endif + +//============================================================================== +class AudioData::Int8 +{ +public: + inline Int8 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / (1.0 + maxValue))); } + inline float getAsFloatBE() const throw() { return getAsFloatLE(); } + inline void setAsFloatLE (float newValue) throw() { *data = jlimit ((int8) -maxValue, (int8) maxValue, (int8) roundToInt (newValue * (1.0 + maxValue))); } + inline void setAsFloatBE (float newValue) throw() { setAsFloatLE (newValue); } + inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); } + inline int32 getAsInt32BE() const throw() { return getAsInt32LE(); } + inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); } + inline void setAsInt32BE (int newValue) throw() { setAsInt32LE (newValue); } + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int8& source) throw() { *data = *source.data; } + + int8* data; + enum { maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 }; +}; + +class AudioData::Int16 +{ +public: + inline Int16 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) jlimit ((int16) -maxValue, (int16) maxValue, (int16) roundToInt (newValue * (1.0 + maxValue)))); } + inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) jlimit ((int16) -maxValue, (int16) maxValue, (int16) roundToInt (newValue * (1.0 + maxValue)))); } + inline int32 getAsInt32LE() const throw() { return (int32) (ByteOrder::swapIfBigEndian ((uint16) *data) << 16); } + inline int32 getAsInt32BE() const throw() { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); } + inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); } + inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); } + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int16& source) throw() { *data = *source.data; } + + uint16* data; + enum { maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 }; +}; + +class AudioData::Int24 +{ +public: + inline Int24 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { data += 3; } + inline void skip (int numSamples) throw() { data += 3 * numSamples; } + inline float getAsFloatLE() const throw() { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } + inline float getAsFloatBE() const throw() { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } + inline void setAsFloatLE (float newValue) throw() { ByteOrder::littleEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } + inline void setAsFloatBE (float newValue) throw() { ByteOrder::bigEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } + inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::littleEndian24Bit (data) << 8; } + inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; } + inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); } + inline void setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); } + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int24& source) throw() { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; } + + char* data; + enum { maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 }; +}; + +class AudioData::Int32 +{ +public: + inline Int32 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } + inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } + inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::swapIfBigEndian (*data); } + inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); } + inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } + inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); } + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int32& source) throw() { *data = *source.data; } + + uint32* data; + enum { maxValue = 0x7fffffff, resolution = 1, isFloat = 0 }; +}; + +class AudioData::Float32 +{ +public: + inline Float32 (void* data_) throw() : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + #if JUCE_BIG_ENDIAN + inline float getAsFloatBE() const throw() { return *data; } + inline void setAsFloatBE (float newValue) throw() { *data = newValue; } + inline float getAsFloatLE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } + inline void setAsFloatLE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } + #else + inline float getAsFloatLE() const throw() { return *data; } + inline void setAsFloatLE (float newValue) throw() { *data = newValue; } + inline float getAsFloatBE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } + inline void setAsFloatBE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } + #endif + inline int32 getAsInt32LE() const throw() { return (int32) roundToInt (jlimit (-1.0f, 1.0f, getAsFloatLE()) * (1.0 + maxValue)); } + inline int32 getAsInt32BE() const throw() { return (int32) roundToInt (jlimit (-1.0f, 1.0f, getAsFloatBE()) * (1.0 + maxValue)); } + inline void setAsInt32LE (int32 newValue) throw() { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } + inline void setAsInt32BE (int32 newValue) throw() { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } + template inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } + template inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); } + inline void copyFromSameType (Float32& source) throw() { *data = *source.data; } + + float* data; + enum { maxValue = 0x7fffffff, resolution = (1 << 8), isFloat = 1 }; +}; + +//============================================================================== +class AudioData::NonInterleaved +{ +public: + inline NonInterleaved() throw() {} + inline NonInterleaved (const int) throw() {} + template inline void advanceData (SampleFormatType& s) throw() { s.advance(); } + template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); } + enum { isInterleavedType = 0, numInterleavedChannels = 1 }; +}; + +class AudioData::Interleaved +{ +public: + inline Interleaved() throw() : numInterleavedChannels (1) {} + inline Interleaved (const int numInterleavedChannels_) throw() : numInterleavedChannels (numInterleavedChannels_) {} + template inline void advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); } + template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numInterleavedChannels * numSamples); } + const int numInterleavedChannels; + enum { isInterleavedType = 1 }; + +private: + Interleaved& operator= (const Interleaved&); +}; + +//============================================================================== +class AudioData::NonConst +{ +public: + typedef void VoidType; + static inline void* toVoidPtr (VoidType* v) throw() { return v; } + enum { isConst = 0 }; +}; + +class AudioData::Const +{ +public: + typedef const void VoidType; + static inline void* toVoidPtr (VoidType* v) throw() { return const_cast (v); } + enum { isConst = 1 }; +}; + +#endif + +#endif //============================================================================== /** diff --git a/src/containers/juce_Expression.cpp b/src/containers/juce_Expression.cpp index c685b13e9c..09a994fe08 100644 --- a/src/containers/juce_Expression.cpp +++ b/src/containers/juce_Expression.cpp @@ -317,6 +317,10 @@ public: return new Subtract (newDest, (input == left ? right : left)->clone()); } + + private: + Add (const Add&); + Add& operator= (const Add&); }; //============================================================================== @@ -341,6 +345,10 @@ public: else return new Subtract (left->clone(), newDest); } + + private: + Subtract (const Subtract&); + Subtract& operator= (const Subtract&); }; //============================================================================== @@ -362,6 +370,10 @@ public: return new Divide (newDest, (input == left ? right : left)->clone()); } + + private: + Multiply (const Multiply&); + Multiply& operator= (const Multiply&); }; //============================================================================== @@ -386,6 +398,10 @@ public: else return new Divide (left->clone(), newDest); } + + private: + Divide (const Divide&); + Divide& operator= (const Divide&); }; //============================================================================== diff --git a/src/core/juce_Atomic.h b/src/core/juce_Atomic.h index cc4cf7da29..5b5d4a18b3 100644 --- a/src/core/juce_Atomic.h +++ b/src/core/juce_Atomic.h @@ -207,7 +207,7 @@ private: long juce_InterlockedExchangeAdd (volatile long* a, long b) throw(); long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw(); __int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) throw(); - static void juce_MemoryBarrier() throw() { long x = 0; juce_InterlockedIncrement (&x); } + void juce_MemoryBarrier() throw() { long x = 0; juce_InterlockedIncrement (&x); } #endif #if JUCE_64BIT diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index 73a5f87d7f..1e457a2f6e 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 68 +#define JUCE_BUILDNUMBER 69 /** Current Juce version number. diff --git a/src/io/files/juce_DirectoryIterator.cpp b/src/io/files/juce_DirectoryIterator.cpp index 2fce8875b9..857d1a62b8 100644 --- a/src/io/files/juce_DirectoryIterator.cpp +++ b/src/io/files/juce_DirectoryIterator.cpp @@ -41,7 +41,8 @@ DirectoryIterator::DirectoryIterator (const File& directory, index (-1), totalNumFiles (-1), whatToLookFor (whatToLookFor_), - isRecursive (isRecursive_) + isRecursive (isRecursive_), + hasBeenAdvanced (false) { // you have to specify the type of files you're looking for! jassert ((whatToLookFor_ & (File::findFiles | File::findDirectories)) != 0); @@ -60,6 +61,8 @@ bool DirectoryIterator::next() bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, int64* const fileSize, Time* const modTime, Time* const creationTime, bool* const isReadOnly) { + hasBeenAdvanced = true; + if (subIterator != 0) { if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly)) @@ -118,9 +121,12 @@ bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResul const File DirectoryIterator::getFile() const { - if (subIterator != 0) + if (subIterator != 0 && subIterator->hasBeenAdvanced) return subIterator->getFile(); + // You need to call DirectoryIterator::next() before asking it for the file that it found! + jassert (hasBeenAdvanced); + return currentFile; } diff --git a/src/io/files/juce_DirectoryIterator.h b/src/io/files/juce_DirectoryIterator.h index 133a1f190d..619920ad0d 100644 --- a/src/io/files/juce_DirectoryIterator.h +++ b/src/io/files/juce_DirectoryIterator.h @@ -146,6 +146,7 @@ private: mutable int totalNumFiles; const int whatToLookFor; const bool isRecursive; + bool hasBeenAdvanced; ScopedPointer subIterator; File currentFile; diff --git a/src/io/files/juce_File.cpp b/src/io/files/juce_File.cpp index 76f0b0c3f5..7ab7ea89d6 100644 --- a/src/io/files/juce_File.cpp +++ b/src/io/files/juce_File.cpp @@ -962,13 +962,18 @@ public: File::findFileSystemRoots (roots); expect (roots.size() > 0); + int numRootsExisting = 0; for (int i = 0; i < roots.size(); ++i) - expect (roots[i].exists()); + if (roots[i].exists()) + ++numRootsExisting; + + // (on windows, some of the drives may not contain media, so as long as at least one is ok..) + expect (numRootsExisting > 0); } beginTest ("Writing"); - File demoFolder (temp.getChildFile ("Juce UnitTests Temp Folder")); + File demoFolder (temp.getChildFile ("Juce UnitTests Temp Folder.folder")); expect (demoFolder.deleteRecursively()); expect (demoFolder.createDirectory()); expect (demoFolder.isDirectory()); @@ -983,7 +988,7 @@ public: { Array files; - temp.findChildFiles (files, File::findDirectories, false, "*"); + temp.findChildFiles (files, File::findDirectories, true, "*.folder"); expect (files.contains (demoFolder)); } diff --git a/src/native/mac/juce_mac_CarbonViewWrapperComponent.h b/src/native/mac/juce_mac_CarbonViewWrapperComponent.h index 1d480e1c54..20ca911ee5 100644 --- a/src/native/mac/juce_mac_CarbonViewWrapperComponent.h +++ b/src/native/mac/juce_mac_CarbonViewWrapperComponent.h @@ -42,6 +42,7 @@ public: CarbonViewWrapperComponent() : ComponentMovementWatcher (this), wrapperWindow (0), + carbonWindow (0), embeddedView (0), recursiveResize (false) { @@ -88,7 +89,7 @@ public: if (wrapperWindow == 0) return; - NSWindow* carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow]; + carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow]; NSWindow* ownerWindow = [((NSView*) getWindowHandle()) window]; [ownerWindow addChildWindow: carbonWindow @@ -235,8 +236,7 @@ public: recursiveHIViewRepaint (HIViewGetRoot (wrapperWindow)); } - OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, - EventRef event) + OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, EventRef event) { switch (GetEventKind (event)) { @@ -247,6 +247,7 @@ public: case kEventWindowGetClickActivation: { getTopLevelComponent()->toFront (false); + [carbonWindow makeKeyAndOrderFront: nil]; ClickActivationResult howToHandleClick = kActivateAndHandleClick; @@ -261,14 +262,14 @@ public: return eventNotHandledErr; } - static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef, - EventRef event, void* userData) + static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef, EventRef event, void* userData) { return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event); } protected: WindowRef wrapperWindow; + NSWindow* carbonWindow; HIViewRef embeddedView; bool recursiveResize; Time creationTime;