| @@ -41,6 +41,10 @@ | |||||
| #define BUILD_AU_CARBON_UI 1 | #define BUILD_AU_CARBON_UI 1 | ||||
| #endif | #endif | ||||
| #if JUCE_64BIT | |||||
| #undef BUILD_AU_CARBON_UI // (not possible in a 64-bit build) | |||||
| #endif | |||||
| #if BUILD_AU_CARBON_UI | #if BUILD_AU_CARBON_UI | ||||
| #undef Button | #undef Button | ||||
| #include "AUCarbonViewBase.h" | #include "AUCarbonViewBase.h" | ||||
| @@ -933,6 +933,7 @@ public: | |||||
| CarbonViewWrapperComponent() | CarbonViewWrapperComponent() | ||||
| : ComponentMovementWatcher (this), | : ComponentMovementWatcher (this), | ||||
| wrapperWindow (0), | wrapperWindow (0), | ||||
| carbonWindow (0), | |||||
| embeddedView (0), | embeddedView (0), | ||||
| recursiveResize (false) | recursiveResize (false) | ||||
| { | { | ||||
| @@ -979,7 +980,7 @@ public: | |||||
| if (wrapperWindow == 0) | if (wrapperWindow == 0) | ||||
| return; | return; | ||||
| NSWindow* carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow]; | |||||
| carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow]; | |||||
| NSWindow* ownerWindow = [((NSView*) getWindowHandle()) window]; | NSWindow* ownerWindow = [((NSView*) getWindowHandle()) window]; | ||||
| [ownerWindow addChildWindow: carbonWindow | [ownerWindow addChildWindow: carbonWindow | ||||
| @@ -1125,8 +1126,7 @@ public: | |||||
| recursiveHIViewRepaint (HIViewGetRoot (wrapperWindow)); | recursiveHIViewRepaint (HIViewGetRoot (wrapperWindow)); | ||||
| } | } | ||||
| OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, | |||||
| EventRef event) | |||||
| OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, EventRef event) | |||||
| { | { | ||||
| switch (GetEventKind (event)) | switch (GetEventKind (event)) | ||||
| { | { | ||||
| @@ -1137,6 +1137,7 @@ public: | |||||
| case kEventWindowGetClickActivation: | case kEventWindowGetClickActivation: | ||||
| { | { | ||||
| getTopLevelComponent()->toFront (false); | getTopLevelComponent()->toFront (false); | ||||
| [carbonWindow makeKeyAndOrderFront: nil]; | |||||
| ClickActivationResult howToHandleClick = kActivateAndHandleClick; | ClickActivationResult howToHandleClick = kActivateAndHandleClick; | ||||
| @@ -1151,14 +1152,14 @@ public: | |||||
| return eventNotHandledErr; | 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); | return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event); | ||||
| } | } | ||||
| protected: | protected: | ||||
| WindowRef wrapperWindow; | WindowRef wrapperWindow; | ||||
| NSWindow* carbonWindow; | |||||
| HIViewRef embeddedView; | HIViewRef embeddedView; | ||||
| bool recursiveResize; | bool recursiveResize; | ||||
| Time creationTime; | Time creationTime; | ||||
| @@ -4833,6 +4834,10 @@ public: | |||||
| return new Subtract (newDest, (input == left ? right : left)->clone()); | return new Subtract (newDest, (input == left ? right : left)->clone()); | ||||
| } | } | ||||
| private: | |||||
| Add (const Add&); | |||||
| Add& operator= (const Add&); | |||||
| }; | }; | ||||
| class Subtract : public BinaryTerm | class Subtract : public BinaryTerm | ||||
| @@ -4856,6 +4861,10 @@ public: | |||||
| else | else | ||||
| return new Subtract (left->clone(), newDest); | return new Subtract (left->clone(), newDest); | ||||
| } | } | ||||
| private: | |||||
| Subtract (const Subtract&); | |||||
| Subtract& operator= (const Subtract&); | |||||
| }; | }; | ||||
| class Multiply : public BinaryTerm | class Multiply : public BinaryTerm | ||||
| @@ -4876,6 +4885,10 @@ public: | |||||
| return new Divide (newDest, (input == left ? right : left)->clone()); | return new Divide (newDest, (input == left ? right : left)->clone()); | ||||
| } | } | ||||
| private: | |||||
| Multiply (const Multiply&); | |||||
| Multiply& operator= (const Multiply&); | |||||
| }; | }; | ||||
| class Divide : public BinaryTerm | class Divide : public BinaryTerm | ||||
| @@ -4899,6 +4912,10 @@ public: | |||||
| else | else | ||||
| return new Divide (left->clone(), newDest); | return new Divide (left->clone(), newDest); | ||||
| } | } | ||||
| private: | |||||
| Divide (const Divide&); | |||||
| Divide& operator= (const Divide&); | |||||
| }; | }; | ||||
| static Term* findDestinationFor (Term* const topLevel, const Term* const inputTerm) | static Term* findDestinationFor (Term* const topLevel, const Term* const inputTerm) | ||||
| @@ -6878,7 +6895,8 @@ DirectoryIterator::DirectoryIterator (const File& directory, | |||||
| index (-1), | index (-1), | ||||
| totalNumFiles (-1), | totalNumFiles (-1), | ||||
| whatToLookFor (whatToLookFor_), | whatToLookFor (whatToLookFor_), | ||||
| isRecursive (isRecursive_) | |||||
| isRecursive (isRecursive_), | |||||
| hasBeenAdvanced (false) | |||||
| { | { | ||||
| // you have to specify the type of files you're looking for! | // you have to specify the type of files you're looking for! | ||||
| jassert ((whatToLookFor_ & (File::findFiles | File::findDirectories)) != 0); | 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, | bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, int64* const fileSize, | ||||
| Time* const modTime, Time* const creationTime, bool* const isReadOnly) | Time* const modTime, Time* const creationTime, bool* const isReadOnly) | ||||
| { | { | ||||
| hasBeenAdvanced = true; | |||||
| if (subIterator != 0) | if (subIterator != 0) | ||||
| { | { | ||||
| if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly)) | 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 | const File DirectoryIterator::getFile() const | ||||
| { | { | ||||
| if (subIterator != 0) | |||||
| if (subIterator != 0 && subIterator->hasBeenAdvanced) | |||||
| return subIterator->getFile(); | return subIterator->getFile(); | ||||
| // You need to call DirectoryIterator::next() before asking it for the file that it found! | |||||
| jassert (hasBeenAdvanced); | |||||
| return currentFile; | return currentFile; | ||||
| } | } | ||||
| @@ -7883,13 +7906,18 @@ public: | |||||
| File::findFileSystemRoots (roots); | File::findFileSystemRoots (roots); | ||||
| expect (roots.size() > 0); | expect (roots.size() > 0); | ||||
| int numRootsExisting = 0; | |||||
| for (int i = 0; i < roots.size(); ++i) | 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"); | beginTest ("Writing"); | ||||
| File demoFolder (temp.getChildFile ("Juce UnitTests Temp Folder")); | |||||
| File demoFolder (temp.getChildFile ("Juce UnitTests Temp Folder.folder")); | |||||
| expect (demoFolder.deleteRecursively()); | expect (demoFolder.deleteRecursively()); | ||||
| expect (demoFolder.createDirectory()); | expect (demoFolder.createDirectory()); | ||||
| expect (demoFolder.isDirectory()); | expect (demoFolder.isDirectory()); | ||||
| @@ -7904,7 +7932,7 @@ public: | |||||
| { | { | ||||
| Array<File> files; | Array<File> files; | ||||
| temp.findChildFiles (files, File::findDirectories, false, "*"); | |||||
| temp.findChildFiles (files, File::findDirectories, true, "*.folder"); | |||||
| expect (files.contains (demoFolder)); | expect (files.contains (demoFolder)); | ||||
| } | } | ||||
| @@ -27180,14 +27208,15 @@ void AudioDataConverters::deinterleaveSamples (const float* const source, | |||||
| } | } | ||||
| } | } | ||||
| /* | |||||
| #if JUCE_UNIT_TESTS | #if JUCE_UNIT_TESTS | ||||
| /*class AudioConversionTests : public UnitTest | |||||
| class AudioConversionTests : public UnitTest | |||||
| { | { | ||||
| public: | public: | ||||
| AudioConversionTests() : UnitTest ("Audio data conversion") {} | AudioConversionTests() : UnitTest ("Audio data conversion") {} | ||||
| template <class SourceType, class DestType> | |||||
| template <class F1, class E1, class F2, class E2> | |||||
| struct Test5 | struct Test5 | ||||
| { | { | ||||
| static void test (UnitTest& unitTest) | static void test (UnitTest& unitTest) | ||||
| @@ -27196,38 +27225,48 @@ public: | |||||
| int32 original [numSamples], converted [numSamples], reversed [numSamples]; | 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) | 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.setAsInt32 (Random::getSystemRandom().nextInt()); | ||||
| d.advance(); | |||||
| ++d; | |||||
| } | } | ||||
| unitTest.expect (! clippingFailed); | |||||
| } | } | ||||
| // convert data from the source to dest format.. | // 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.. | // ..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); | zerostruct (reversed); | ||||
| conv->copySamples (reversed, converted, numSamples); | |||||
| conv->convertSamples (reversed, converted, numSamples); | |||||
| { | { | ||||
| int biggestDiff = 0; | 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) | for (int i = 0; i < numSamples; ++i) | ||||
| { | { | ||||
| biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32())); | biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32())); | ||||
| d1.advance(); | |||||
| d2.advance(); | |||||
| ++d1; | |||||
| ++d2; | |||||
| } | } | ||||
| unitTest.expect (biggestDiff <= errorMargin); | unitTest.expect (biggestDiff <= errorMargin); | ||||
| @@ -27235,26 +27274,26 @@ public: | |||||
| } | } | ||||
| }; | }; | ||||
| template <class SourceType, class FormatType> | |||||
| template <class F1, class E1, class FormatType> | |||||
| struct Test3 | struct Test3 | ||||
| { | { | ||||
| static void test (UnitTest& unitTest) | 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 | struct Test2 | ||||
| { | { | ||||
| static void test (UnitTest& unitTest) | 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) | 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; | static AudioConversionTests audioConversionUnitTests; | ||||
| */ | |||||
| #endif | #endif | ||||
| */ | |||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| /*** End of inlined file: juce_AudioDataConverters.cpp ***/ | /*** End of inlined file: juce_AudioDataConverters.cpp ***/ | ||||
| @@ -64,7 +64,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 52 | #define JUCE_MINOR_VERSION 52 | ||||
| #define JUCE_BUILDNUMBER 68 | |||||
| #define JUCE_BUILDNUMBER 69 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -5930,7 +5930,7 @@ private: | |||||
| long juce_InterlockedExchangeAdd (volatile long* a, long b) throw(); | long juce_InterlockedExchangeAdd (volatile long* a, long b) throw(); | ||||
| long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw(); | long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw(); | ||||
| __int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 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 | #endif | ||||
| #if JUCE_64BIT | #if JUCE_64BIT | ||||
| @@ -15506,6 +15506,7 @@ private: | |||||
| mutable int totalNumFiles; | mutable int totalNumFiles; | ||||
| const int whatToLookFor; | const int whatToLookFor; | ||||
| const bool isRecursive; | const bool isRecursive; | ||||
| bool hasBeenAdvanced; | |||||
| ScopedPointer <DirectoryIterator> subIterator; | ScopedPointer <DirectoryIterator> subIterator; | ||||
| File currentFile; | File currentFile; | ||||
| @@ -37771,246 +37772,234 @@ private: | |||||
| #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ | #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ | ||||
| #define __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) | while (--numSamples >= 0) | ||||
| { | { | ||||
| data.copyFromSameType (source.data); | |||||
| advance(); | |||||
| dest.data.copyFromSameType (source.data); | |||||
| dest.advance(); | |||||
| source.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> | 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) | 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: | private: | ||||
| SampleFormat data; | 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 | class Converter | ||||
| { | { | ||||
| public: | public: | ||||
| virtual ~Converter() {} | 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> | template <class SourceSampleType, class DestSampleType> | ||||
| class ConverterInstance : public Converter | class ConverterInstance : public Converter | ||||
| { | { | ||||
| @@ -38018,11 +38007,11 @@ xxx need to add int range limiting.. | |||||
| ConverterInstance() {} | ConverterInstance() {} | ||||
| ~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); | SourceSampleType s (source); | ||||
| DestSampleType d (dest); | DestSampleType d (dest); | ||||
| d.copySamples (s, numSamples); | |||||
| d.convertSamples (s, numSamples); | |||||
| } | } | ||||
| private: | private: | ||||
| @@ -38030,7 +38019,202 @@ xxx need to add int range limiting.. | |||||
| ConverterInstance& operator= (const ConverterInstance&); | 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 | 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 | #if JUCE_UNIT_TESTS | ||||
| #include "../../utilities/juce_UnitTest.h" | #include "../../utilities/juce_UnitTest.h" | ||||
| #include "../../core/juce_Random.h" | #include "../../core/juce_Random.h" | ||||
| /*class AudioConversionTests : public UnitTest | |||||
| class AudioConversionTests : public UnitTest | |||||
| { | { | ||||
| public: | public: | ||||
| AudioConversionTests() : UnitTest ("Audio data conversion") {} | AudioConversionTests() : UnitTest ("Audio data conversion") {} | ||||
| template <class SourceType, class DestType> | |||||
| template <class F1, class E1, class F2, class E2> | |||||
| struct Test5 | struct Test5 | ||||
| { | { | ||||
| static void test (UnitTest& unitTest) | static void test (UnitTest& unitTest) | ||||
| @@ -550,38 +551,48 @@ public: | |||||
| int32 original [numSamples], converted [numSamples], reversed [numSamples]; | 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) | 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.setAsInt32 (Random::getSystemRandom().nextInt()); | ||||
| d.advance(); | |||||
| ++d; | |||||
| } | } | ||||
| unitTest.expect (! clippingFailed); | |||||
| } | } | ||||
| // convert data from the source to dest format.. | // 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.. | // ..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); | zerostruct (reversed); | ||||
| conv->copySamples (reversed, converted, numSamples); | |||||
| conv->convertSamples (reversed, converted, numSamples); | |||||
| { | { | ||||
| int biggestDiff = 0; | 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) | for (int i = 0; i < numSamples; ++i) | ||||
| { | { | ||||
| biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32())); | biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32())); | ||||
| d1.advance(); | |||||
| d2.advance(); | |||||
| ++d1; | |||||
| ++d2; | |||||
| } | } | ||||
| unitTest.expect (biggestDiff <= errorMargin); | unitTest.expect (biggestDiff <= errorMargin); | ||||
| @@ -589,26 +600,26 @@ public: | |||||
| } | } | ||||
| }; | }; | ||||
| template <class SourceType, class FormatType> | |||||
| template <class F1, class E1, class FormatType> | |||||
| struct Test3 | struct Test3 | ||||
| { | { | ||||
| static void test (UnitTest& unitTest) | 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 | struct Test2 | ||||
| { | { | ||||
| static void test (UnitTest& unitTest) | 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) | 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; | static AudioConversionTests audioConversionUnitTests; | ||||
| */ | |||||
| #endif | #endif | ||||
| */ | |||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| @@ -26,254 +26,242 @@ | |||||
| #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ | #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ | ||||
| #define __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: | 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) | while (--numSamples >= 0) | ||||
| { | { | ||||
| data.copyFromSameType (source.data); | |||||
| advance(); | |||||
| dest.data.copyFromSameType (source.data); | |||||
| dest.advance(); | |||||
| source.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> | 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) | 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: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| SampleFormat data; | 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 | class Converter | ||||
| { | { | ||||
| public: | public: | ||||
| virtual ~Converter() {} | 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> | template <class SourceSampleType, class DestSampleType> | ||||
| class ConverterInstance : public Converter | class ConverterInstance : public Converter | ||||
| { | { | ||||
| @@ -281,11 +269,11 @@ xxx need to add int range limiting.. | |||||
| ConverterInstance() {} | ConverterInstance() {} | ||||
| ~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); | SourceSampleType s (source); | ||||
| DestSampleType d (dest); | DestSampleType d (dest); | ||||
| d.copySamples (s, numSamples); | |||||
| d.convertSamples (s, numSamples); | |||||
| } | } | ||||
| private: | private: | ||||
| @@ -293,7 +281,207 @@ xxx need to add int range limiting.. | |||||
| ConverterInstance& operator= (const ConverterInstance&); | 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()); | return new Subtract (newDest, (input == left ? right : left)->clone()); | ||||
| } | } | ||||
| private: | |||||
| Add (const Add&); | |||||
| Add& operator= (const Add&); | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -341,6 +345,10 @@ public: | |||||
| else | else | ||||
| return new Subtract (left->clone(), newDest); | 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()); | return new Divide (newDest, (input == left ? right : left)->clone()); | ||||
| } | } | ||||
| private: | |||||
| Multiply (const Multiply&); | |||||
| Multiply& operator= (const Multiply&); | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -386,6 +398,10 @@ public: | |||||
| else | else | ||||
| return new Divide (left->clone(), newDest); | 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_InterlockedExchangeAdd (volatile long* a, long b) throw(); | ||||
| long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw(); | long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw(); | ||||
| __int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 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 | #endif | ||||
| #if JUCE_64BIT | #if JUCE_64BIT | ||||
| @@ -33,7 +33,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 52 | #define JUCE_MINOR_VERSION 52 | ||||
| #define JUCE_BUILDNUMBER 68 | |||||
| #define JUCE_BUILDNUMBER 69 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -41,7 +41,8 @@ DirectoryIterator::DirectoryIterator (const File& directory, | |||||
| index (-1), | index (-1), | ||||
| totalNumFiles (-1), | totalNumFiles (-1), | ||||
| whatToLookFor (whatToLookFor_), | whatToLookFor (whatToLookFor_), | ||||
| isRecursive (isRecursive_) | |||||
| isRecursive (isRecursive_), | |||||
| hasBeenAdvanced (false) | |||||
| { | { | ||||
| // you have to specify the type of files you're looking for! | // you have to specify the type of files you're looking for! | ||||
| jassert ((whatToLookFor_ & (File::findFiles | File::findDirectories)) != 0); | 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, | bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, int64* const fileSize, | ||||
| Time* const modTime, Time* const creationTime, bool* const isReadOnly) | Time* const modTime, Time* const creationTime, bool* const isReadOnly) | ||||
| { | { | ||||
| hasBeenAdvanced = true; | |||||
| if (subIterator != 0) | if (subIterator != 0) | ||||
| { | { | ||||
| if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly)) | 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 | const File DirectoryIterator::getFile() const | ||||
| { | { | ||||
| if (subIterator != 0) | |||||
| if (subIterator != 0 && subIterator->hasBeenAdvanced) | |||||
| return subIterator->getFile(); | return subIterator->getFile(); | ||||
| // You need to call DirectoryIterator::next() before asking it for the file that it found! | |||||
| jassert (hasBeenAdvanced); | |||||
| return currentFile; | return currentFile; | ||||
| } | } | ||||
| @@ -146,6 +146,7 @@ private: | |||||
| mutable int totalNumFiles; | mutable int totalNumFiles; | ||||
| const int whatToLookFor; | const int whatToLookFor; | ||||
| const bool isRecursive; | const bool isRecursive; | ||||
| bool hasBeenAdvanced; | |||||
| ScopedPointer <DirectoryIterator> subIterator; | ScopedPointer <DirectoryIterator> subIterator; | ||||
| File currentFile; | File currentFile; | ||||
| @@ -962,13 +962,18 @@ public: | |||||
| File::findFileSystemRoots (roots); | File::findFileSystemRoots (roots); | ||||
| expect (roots.size() > 0); | expect (roots.size() > 0); | ||||
| int numRootsExisting = 0; | |||||
| for (int i = 0; i < roots.size(); ++i) | 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"); | beginTest ("Writing"); | ||||
| File demoFolder (temp.getChildFile ("Juce UnitTests Temp Folder")); | |||||
| File demoFolder (temp.getChildFile ("Juce UnitTests Temp Folder.folder")); | |||||
| expect (demoFolder.deleteRecursively()); | expect (demoFolder.deleteRecursively()); | ||||
| expect (demoFolder.createDirectory()); | expect (demoFolder.createDirectory()); | ||||
| expect (demoFolder.isDirectory()); | expect (demoFolder.isDirectory()); | ||||
| @@ -983,7 +988,7 @@ public: | |||||
| { | { | ||||
| Array<File> files; | Array<File> files; | ||||
| temp.findChildFiles (files, File::findDirectories, false, "*"); | |||||
| temp.findChildFiles (files, File::findDirectories, true, "*.folder"); | |||||
| expect (files.contains (demoFolder)); | expect (files.contains (demoFolder)); | ||||
| } | } | ||||
| @@ -42,6 +42,7 @@ public: | |||||
| CarbonViewWrapperComponent() | CarbonViewWrapperComponent() | ||||
| : ComponentMovementWatcher (this), | : ComponentMovementWatcher (this), | ||||
| wrapperWindow (0), | wrapperWindow (0), | ||||
| carbonWindow (0), | |||||
| embeddedView (0), | embeddedView (0), | ||||
| recursiveResize (false) | recursiveResize (false) | ||||
| { | { | ||||
| @@ -88,7 +89,7 @@ public: | |||||
| if (wrapperWindow == 0) | if (wrapperWindow == 0) | ||||
| return; | return; | ||||
| NSWindow* carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow]; | |||||
| carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow]; | |||||
| NSWindow* ownerWindow = [((NSView*) getWindowHandle()) window]; | NSWindow* ownerWindow = [((NSView*) getWindowHandle()) window]; | ||||
| [ownerWindow addChildWindow: carbonWindow | [ownerWindow addChildWindow: carbonWindow | ||||
| @@ -235,8 +236,7 @@ public: | |||||
| recursiveHIViewRepaint (HIViewGetRoot (wrapperWindow)); | recursiveHIViewRepaint (HIViewGetRoot (wrapperWindow)); | ||||
| } | } | ||||
| OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, | |||||
| EventRef event) | |||||
| OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, EventRef event) | |||||
| { | { | ||||
| switch (GetEventKind (event)) | switch (GetEventKind (event)) | ||||
| { | { | ||||
| @@ -247,6 +247,7 @@ public: | |||||
| case kEventWindowGetClickActivation: | case kEventWindowGetClickActivation: | ||||
| { | { | ||||
| getTopLevelComponent()->toFront (false); | getTopLevelComponent()->toFront (false); | ||||
| [carbonWindow makeKeyAndOrderFront: nil]; | |||||
| ClickActivationResult howToHandleClick = kActivateAndHandleClick; | ClickActivationResult howToHandleClick = kActivateAndHandleClick; | ||||
| @@ -261,14 +262,14 @@ public: | |||||
| return eventNotHandledErr; | 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); | return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event); | ||||
| } | } | ||||
| protected: | protected: | ||||
| WindowRef wrapperWindow; | WindowRef wrapperWindow; | ||||
| NSWindow* carbonWindow; | |||||
| HIViewRef embeddedView; | HIViewRef embeddedView; | ||||
| bool recursiveResize; | bool recursiveResize; | ||||
| Time creationTime; | Time creationTime; | ||||