| @@ -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" | |||
| @@ -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<File> 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 <class SourceType, class DestType> | |||
| template <class F1, class E1, class F2, class E2> | |||
| struct Test5 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| @@ -27196,38 +27225,48 @@ public: | |||
| int32 original [numSamples], converted [numSamples], reversed [numSamples]; | |||
| { | |||
| SourceType d (original); | |||
| AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> 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<AudioData::Converter> conv (new AudioData::ConverterInstance <SourceType, DestType>()); | |||
| conv->copySamples (converted, original, numSamples); | |||
| ScopedPointer<AudioData::Converter> conv (new AudioData::ConverterInstance <AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>, | |||
| AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst> >()); | |||
| conv->convertSamples (converted, original, numSamples); | |||
| // ..and back again.. | |||
| conv = new AudioData::ConverterInstance <DestType, SourceType>(); | |||
| conv = new AudioData::ConverterInstance <AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>, | |||
| AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> >(); | |||
| zerostruct (reversed); | |||
| conv->copySamples (reversed, converted, numSamples); | |||
| conv->convertSamples (reversed, converted, numSamples); | |||
| { | |||
| int biggestDiff = 0; | |||
| SourceType d1 (original); | |||
| SourceType d2 (reversed); | |||
| AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d1 (original); | |||
| AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d2 (reversed); | |||
| const int errorMargin = 2 * DestType::get32BitResolution() + SourceType::get32BitResolution(); | |||
| const int errorMargin = 2 * AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution() | |||
| + AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>::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 <class SourceType, class FormatType> | |||
| template <class F1, class E1, class FormatType> | |||
| struct Test3 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| Test5 <SourceType, AudioData::Pointer <FormatType, AudioData::BigEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| Test5 <SourceType, AudioData::Pointer <FormatType, AudioData::LittleEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest); | |||
| Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest); | |||
| } | |||
| }; | |||
| template <class SourceType> | |||
| template <class FormatType, class Endianness> | |||
| struct Test2 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| Test3 <SourceType, AudioData::Int16>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int24>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int32>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Float32>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int8>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest); | |||
| } | |||
| }; | |||
| @@ -27263,8 +27302,8 @@ public: | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| Test2 <AudioData::Pointer <FormatType, AudioData::BigEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| Test2 <AudioData::Pointer <FormatType, AudioData::LittleEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| Test2 <FormatType, AudioData::BigEndian>::test (unitTest); | |||
| Test2 <FormatType, AudioData::LittleEndian>::test (unitTest); | |||
| } | |||
| }; | |||
| @@ -27281,9 +27320,9 @@ public: | |||
| }; | |||
| static AudioConversionTests audioConversionUnitTests; | |||
| */ | |||
| #endif | |||
| */ | |||
| END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_AudioDataConverters.cpp ***/ | |||
| @@ -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 <DirectoryIterator> 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 <class SampleFormatType> static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } | |||
| template <class SampleFormatType> static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } | |||
| template <class SampleFormatType> static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } | |||
| template <class SampleFormatType> static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } | |||
| template <class SourceType, class DestType> static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } | |||
| }; | |||
| struct LittleEndian | |||
| { | |||
| template <class SampleFormatType> static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } | |||
| template <class SampleFormatType> static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } | |||
| template <class SampleFormatType> static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } | |||
| template <class SampleFormatType> static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } | |||
| template <class SourceType, class DestType> 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 <int8*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <uint16*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <char*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <uint32*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <AudioData::Int16, | |||
| AudioData::LittleEndian, | |||
| AudioData::NonInterleaved, | |||
| AudioData::Const> 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 <typename SampleFormat, | |||
| typename Endianness, | |||
| typename InterleavingType, | |||
| typename Constness> | |||
| class Pointer : private InterleavingType | |||
| { | |||
| inline Float32 (void* data_) : data (static_cast <float*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } | |||
| template <class SourceType> 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 <class SampleFormatType> 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 <class SampleFormatType> 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 SampleFormat, | |||
| class Endianness, | |||
| class InterleavingType> | |||
| class Pointer | |||
| { | |||
| public: | |||
| Pointer (const void* sourceData) | |||
| : data (const_cast <void*> (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 <void*> (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 <class OtherPointerType> | |||
| 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 SourceSampleType, class DestSampleType> | |||
| 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 <class SampleFormatType> static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } | |||
| template <class SampleFormatType> static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } | |||
| template <class SampleFormatType> static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } | |||
| template <class SampleFormatType> static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } | |||
| template <class SourceType, class DestType> static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } | |||
| enum { isBigEndian = 1 }; | |||
| }; | |||
| class AudioData::LittleEndian | |||
| { | |||
| public: | |||
| template <class SampleFormatType> static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } | |||
| template <class SampleFormatType> static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } | |||
| template <class SampleFormatType> static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } | |||
| template <class SampleFormatType> static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } | |||
| template <class SourceType, class DestType> 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 <int8*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <uint16*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <char*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <uint32*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <float*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } | |||
| template <class SourceType> 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 <class SampleFormatType> inline void advanceData (SampleFormatType& s) throw() { s.advance(); } | |||
| template <class SampleFormatType> 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 <class SampleFormatType> inline void advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); } | |||
| template <class SampleFormatType> 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<void*> (v); } | |||
| enum { isConst = 1 }; | |||
| }; | |||
| #endif | |||
| #endif | |||
| /** | |||
| A set of routines to convert buffers of 32-bit floating point data to and from | |||
| @@ -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 <class SourceType, class DestType> | |||
| template <class F1, class E1, class F2, class E2> | |||
| struct Test5 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| @@ -550,38 +551,48 @@ public: | |||
| int32 original [numSamples], converted [numSamples], reversed [numSamples]; | |||
| { | |||
| SourceType d (original); | |||
| AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> 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<AudioData::Converter> conv (new AudioData::ConverterInstance <SourceType, DestType>()); | |||
| conv->copySamples (converted, original, numSamples); | |||
| ScopedPointer<AudioData::Converter> conv (new AudioData::ConverterInstance <AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>, | |||
| AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst> >()); | |||
| conv->convertSamples (converted, original, numSamples); | |||
| // ..and back again.. | |||
| conv = new AudioData::ConverterInstance <DestType, SourceType>(); | |||
| conv = new AudioData::ConverterInstance <AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>, | |||
| AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> >(); | |||
| zerostruct (reversed); | |||
| conv->copySamples (reversed, converted, numSamples); | |||
| conv->convertSamples (reversed, converted, numSamples); | |||
| { | |||
| int biggestDiff = 0; | |||
| SourceType d1 (original); | |||
| SourceType d2 (reversed); | |||
| AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d1 (original); | |||
| AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d2 (reversed); | |||
| const int errorMargin = 2 * DestType::get32BitResolution() + SourceType::get32BitResolution(); | |||
| const int errorMargin = 2 * AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution() | |||
| + AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>::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 <class SourceType, class FormatType> | |||
| template <class F1, class E1, class FormatType> | |||
| struct Test3 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| Test5 <SourceType, AudioData::Pointer <FormatType, AudioData::BigEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| Test5 <SourceType, AudioData::Pointer <FormatType, AudioData::LittleEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest); | |||
| Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest); | |||
| } | |||
| }; | |||
| template <class SourceType> | |||
| template <class FormatType, class Endianness> | |||
| struct Test2 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| Test3 <SourceType, AudioData::Int16>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int24>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int32>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Float32>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int8>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest); | |||
| } | |||
| }; | |||
| @@ -617,8 +628,8 @@ public: | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| Test2 <AudioData::Pointer <FormatType, AudioData::BigEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| Test2 <AudioData::Pointer <FormatType, AudioData::LittleEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| Test2 <FormatType, AudioData::BigEndian>::test (unitTest); | |||
| Test2 <FormatType, AudioData::LittleEndian>::test (unitTest); | |||
| } | |||
| }; | |||
| @@ -635,9 +646,8 @@ public: | |||
| }; | |||
| static AudioConversionTests audioConversionUnitTests; | |||
| */ | |||
| #endif | |||
| */ | |||
| END_JUCE_NAMESPACE | |||
| @@ -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 <class SampleFormatType> static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } | |||
| template <class SampleFormatType> static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } | |||
| template <class SampleFormatType> static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } | |||
| template <class SampleFormatType> static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } | |||
| template <class SourceType, class DestType> static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } | |||
| }; | |||
| struct LittleEndian | |||
| { | |||
| template <class SampleFormatType> static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } | |||
| template <class SampleFormatType> static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } | |||
| template <class SampleFormatType> static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } | |||
| template <class SampleFormatType> static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } | |||
| template <class SourceType, class DestType> 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 <int8*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <uint16*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <char*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <uint32*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <float*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } | |||
| template <class SourceType> 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 <class SampleFormatType> 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 <class SampleFormatType> 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 SampleFormat, | |||
| class Endianness, | |||
| class InterleavingType> | |||
| 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 <AudioData::Int16, | |||
| AudioData::LittleEndian, | |||
| AudioData::NonInterleaved, | |||
| AudioData::Const> 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 <typename SampleFormat, | |||
| typename Endianness, | |||
| typename InterleavingType, | |||
| typename Constness> | |||
| class Pointer : private InterleavingType | |||
| { | |||
| public: | |||
| Pointer (const void* sourceData) | |||
| : data (const_cast <void*> (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 <void*> (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 <class OtherPointerType> | |||
| 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 SourceSampleType, class DestSampleType> | |||
| 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 <class SampleFormatType> static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } | |||
| template <class SampleFormatType> static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } | |||
| template <class SampleFormatType> static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } | |||
| template <class SampleFormatType> static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } | |||
| template <class SourceType, class DestType> static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } | |||
| enum { isBigEndian = 1 }; | |||
| }; | |||
| class AudioData::LittleEndian | |||
| { | |||
| public: | |||
| template <class SampleFormatType> static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } | |||
| template <class SampleFormatType> static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } | |||
| template <class SampleFormatType> static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } | |||
| template <class SampleFormatType> static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } | |||
| template <class SourceType, class DestType> 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 <int8*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <uint16*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <char*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <uint32*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } | |||
| template <class SourceType> 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 <float*> (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 <class SourceType> inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } | |||
| template <class SourceType> 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 <class SampleFormatType> inline void advanceData (SampleFormatType& s) throw() { s.advance(); } | |||
| template <class SampleFormatType> 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 <class SampleFormatType> inline void advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); } | |||
| template <class SampleFormatType> 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<void*> (v); } | |||
| enum { isConst = 1 }; | |||
| }; | |||
| #endif | |||
| #endif | |||
| //============================================================================== | |||
| /** | |||
| @@ -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&); | |||
| }; | |||
| //============================================================================== | |||
| @@ -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 | |||
| @@ -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. | |||
| @@ -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; | |||
| } | |||
| @@ -146,6 +146,7 @@ private: | |||
| mutable int totalNumFiles; | |||
| const int whatToLookFor; | |||
| const bool isRecursive; | |||
| bool hasBeenAdvanced; | |||
| ScopedPointer <DirectoryIterator> subIterator; | |||
| File currentFile; | |||
| @@ -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<File> files; | |||
| temp.findChildFiles (files, File::findDirectories, false, "*"); | |||
| temp.findChildFiles (files, File::findDirectories, true, "*.folder"); | |||
| expect (files.contains (demoFolder)); | |||
| } | |||
| @@ -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; | |||