| @@ -27180,6 +27180,111 @@ void AudioDataConverters::deinterleaveSamples (const float* const source, | |||
| } | |||
| } | |||
| #if JUCE_UNIT_TESTS | |||
| /*class AudioConversionTests : public UnitTest | |||
| { | |||
| public: | |||
| AudioConversionTests() : UnitTest ("Audio data conversion") {} | |||
| template <class SourceType, class DestType> | |||
| struct Test5 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| const int numSamples = 2048; | |||
| int32 original [numSamples], converted [numSamples], reversed [numSamples]; | |||
| { | |||
| SourceType d (original); | |||
| for (int i = 0; i < numSamples / 2; ++i) | |||
| { | |||
| d.setAsFloat (Random::getSystemRandom().nextFloat() * 2.0f - 1.0f); | |||
| d.advance(); | |||
| d.setAsInt32 (Random::getSystemRandom().nextInt()); | |||
| d.advance(); | |||
| } | |||
| } | |||
| // convert data from the source to dest format.. | |||
| ScopedPointer<AudioData::Converter> conv (new AudioData::ConverterInstance <SourceType, DestType>()); | |||
| conv->copySamples (converted, original, numSamples); | |||
| // ..and back again.. | |||
| conv = new AudioData::ConverterInstance <DestType, SourceType>(); | |||
| zerostruct (reversed); | |||
| conv->copySamples (reversed, converted, numSamples); | |||
| { | |||
| int biggestDiff = 0; | |||
| SourceType d1 (original); | |||
| SourceType d2 (reversed); | |||
| const int errorMargin = 2 * DestType::get32BitResolution() + SourceType::get32BitResolution(); | |||
| for (int i = 0; i < numSamples; ++i) | |||
| { | |||
| biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32())); | |||
| d1.advance(); | |||
| d2.advance(); | |||
| } | |||
| unitTest.expect (biggestDiff <= errorMargin); | |||
| } | |||
| } | |||
| }; | |||
| template <class SourceType, class FormatType> | |||
| struct Test3 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| Test5 <SourceType, AudioData::Pointer <FormatType, AudioData::BigEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| Test5 <SourceType, AudioData::Pointer <FormatType, AudioData::LittleEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| } | |||
| }; | |||
| template <class SourceType> | |||
| struct Test2 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| Test3 <SourceType, AudioData::Int16>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int24>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int32>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Float32>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int8>::test (unitTest); | |||
| } | |||
| }; | |||
| template <class FormatType> | |||
| struct Test1 | |||
| { | |||
| 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); | |||
| } | |||
| }; | |||
| void runTest() | |||
| { | |||
| beginTest ("Round-trip conversion"); | |||
| Test1 <AudioData::Int8>::test (*this); | |||
| Test1 <AudioData::Int16>::test (*this); | |||
| Test1 <AudioData::Int24>::test (*this); | |||
| Test1 <AudioData::Int32>::test (*this); | |||
| Test1 <AudioData::Float32>::test (*this); | |||
| } | |||
| }; | |||
| static AudioConversionTests audioConversionUnitTests; | |||
| */ | |||
| #endif | |||
| END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_AudioDataConverters.cpp ***/ | |||
| @@ -254969,15 +255074,25 @@ bool File::setAsCurrentWorkingDirectory() const | |||
| return chdir (getFullPathName().toUTF8()) == 0; | |||
| } | |||
| static bool juce_stat (const String& fileName, struct stat& info) | |||
| #if JUCE_IOS | |||
| typedef struct stat64 juce_statStruct; // (need to use the 64-bit version to work around a simulator bug) | |||
| #else | |||
| typedef struct stat juce_statStruct; | |||
| #endif | |||
| static bool juce_stat (const String& fileName, juce_statStruct& info) | |||
| { | |||
| return fileName.isNotEmpty() | |||
| #if JUCE_IOS | |||
| && (stat64 (fileName.toUTF8(), &info) == 0); | |||
| #else | |||
| && (stat (fileName.toUTF8(), &info) == 0); | |||
| #endif | |||
| } | |||
| bool File::isDirectory() const | |||
| { | |||
| struct stat info; | |||
| juce_statStruct info; | |||
| return fullPath.isEmpty() | |||
| || (juce_stat (fullPath, info) && ((info.st_mode & S_IFDIR) != 0)); | |||
| @@ -254996,7 +255111,7 @@ bool File::existsAsFile() const | |||
| int64 File::getSize() const | |||
| { | |||
| struct stat info; | |||
| juce_statStruct info; | |||
| return juce_stat (fullPath, info) ? info.st_size : 0; | |||
| } | |||
| @@ -255013,9 +255128,8 @@ bool File::hasWriteAccess() const | |||
| bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const | |||
| { | |||
| struct stat info; | |||
| const int res = stat (fullPath.toUTF8(), &info); | |||
| if (res != 0) | |||
| juce_statStruct info; | |||
| if (! juce_stat (fullPath, info)) | |||
| return false; | |||
| info.st_mode &= 0777; // Just permissions | |||
| @@ -255035,9 +255149,8 @@ void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int | |||
| accessTime = 0; | |||
| creationTime = 0; | |||
| struct stat info; | |||
| const int res = stat (fullPath.toUTF8(), &info); | |||
| if (res == 0) | |||
| juce_statStruct info; | |||
| if (juce_stat (fullPath, info)) | |||
| { | |||
| modificationTime = (int64) info.st_mtime * 1000; | |||
| accessTime = (int64) info.st_atime * 1000; | |||
| @@ -264762,15 +264875,25 @@ bool File::setAsCurrentWorkingDirectory() const | |||
| return chdir (getFullPathName().toUTF8()) == 0; | |||
| } | |||
| static bool juce_stat (const String& fileName, struct stat& info) | |||
| #if JUCE_IOS | |||
| typedef struct stat64 juce_statStruct; // (need to use the 64-bit version to work around a simulator bug) | |||
| #else | |||
| typedef struct stat juce_statStruct; | |||
| #endif | |||
| static bool juce_stat (const String& fileName, juce_statStruct& info) | |||
| { | |||
| return fileName.isNotEmpty() | |||
| #if JUCE_IOS | |||
| && (stat64 (fileName.toUTF8(), &info) == 0); | |||
| #else | |||
| && (stat (fileName.toUTF8(), &info) == 0); | |||
| #endif | |||
| } | |||
| bool File::isDirectory() const | |||
| { | |||
| struct stat info; | |||
| juce_statStruct info; | |||
| return fullPath.isEmpty() | |||
| || (juce_stat (fullPath, info) && ((info.st_mode & S_IFDIR) != 0)); | |||
| @@ -264789,7 +264912,7 @@ bool File::existsAsFile() const | |||
| int64 File::getSize() const | |||
| { | |||
| struct stat info; | |||
| juce_statStruct info; | |||
| return juce_stat (fullPath, info) ? info.st_size : 0; | |||
| } | |||
| @@ -264806,9 +264929,8 @@ bool File::hasWriteAccess() const | |||
| bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const | |||
| { | |||
| struct stat info; | |||
| const int res = stat (fullPath.toUTF8(), &info); | |||
| if (res != 0) | |||
| juce_statStruct info; | |||
| if (! juce_stat (fullPath, info)) | |||
| return false; | |||
| info.st_mode &= 0777; // Just permissions | |||
| @@ -264828,9 +264950,8 @@ void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int | |||
| accessTime = 0; | |||
| creationTime = 0; | |||
| struct stat info; | |||
| const int res = stat (fullPath.toUTF8(), &info); | |||
| if (res == 0) | |||
| juce_statStruct info; | |||
| if (juce_stat (fullPath, info)) | |||
| { | |||
| modificationTime = (int64) info.st_mtime * 1000; | |||
| accessTime = (int64) info.st_atime * 1000; | |||
| @@ -265548,7 +265669,7 @@ public: | |||
| if (isDir != 0 || fileSize != 0 || modTime != 0 || creationTime != 0) | |||
| { | |||
| struct stat info; | |||
| juce_statStruct info; | |||
| const bool statOk = juce_stat (path, info); | |||
| if (isDir != 0) *isDir = statOk && ((info.st_mode & S_IFDIR) != 0); | |||
| @@ -267393,7 +267514,9 @@ const Image juce_loadWithCoreImage (InputStream& input) | |||
| #if JUCE_IOS | |||
| JUCE_AUTORELEASEPOOL | |||
| UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData() length: data.getSize()]]; | |||
| UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData() | |||
| length: data.getSize() | |||
| freeWhenDone: NO]]; | |||
| if (image != nil) | |||
| { | |||
| @@ -272073,7 +272196,9 @@ const Image juce_loadWithCoreImage (InputStream& input) | |||
| #if JUCE_IOS | |||
| JUCE_AUTORELEASEPOOL | |||
| UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData() length: data.getSize()]]; | |||
| UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData() | |||
| length: data.getSize() | |||
| freeWhenDone: NO]]; | |||
| if (image != nil) | |||
| { | |||
| @@ -64,7 +64,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 52 | |||
| #define JUCE_BUILDNUMBER 67 | |||
| #define JUCE_BUILDNUMBER 68 | |||
| /** Current Juce version number. | |||
| @@ -37771,6 +37771,267 @@ private: | |||
| #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ | |||
| #define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ | |||
| /** | |||
| */ | |||
| /* | |||
| struct 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_)) {} | |||
| 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 }; | |||
| }; | |||
| 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(); } | |||
| }; | |||
| 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); } | |||
| const int numChannels; | |||
| }; | |||
| template <class SampleFormat, | |||
| class Endianness, | |||
| class InterleavingType> | |||
| class Pointer | |||
| { | |||
| public: | |||
| Pointer (const void* sourceData) | |||
| : data (const_cast <void*> (sourceData)) | |||
| { | |||
| } | |||
| Pointer (const void* sourceData, int numInterleavedChannels) | |||
| : data (const_cast <void*> (sourceData)), | |||
| interleaving (numInterleavedChannels) | |||
| { | |||
| } | |||
| inline float getAsFloat() const throw() { return Endianness::getAsFloat (data); } | |||
| inline void setAsFloat (float newValue) throw() { Endianness::setAsFloat (data, newValue); } | |||
| inline int32 getAsInt32() const throw() { return Endianness::getAsInt32 (data); } | |||
| inline void setAsInt32 (int32 newValue) throw() { Endianness::setAsInt32 (data, newValue); } | |||
| inline void advance() throw() { interleaving.advance (data); } | |||
| void copySamples (Pointer& source, int numSamples) | |||
| { | |||
| while (--numSamples >= 0) | |||
| { | |||
| data.copyFromSameType (source.data); | |||
| advance(); | |||
| source.advance(); | |||
| } | |||
| } | |||
| template <class OtherPointerType> | |||
| void copySamples (OtherPointerType& source, int numSamples) | |||
| { | |||
| while (--numSamples >= 0) | |||
| { | |||
| Endianness::copyFrom (data, source); | |||
| advance(); | |||
| source.advance(); | |||
| } | |||
| } | |||
| bool isFloatingPoint() const throw() { return (bool) SampleFormat::isFloat; } | |||
| static int get32BitResolution() throw() { return (int) SampleFormat::resolution; } | |||
| typedef Endianness EndiannessType; | |||
| private: | |||
| SampleFormat data; | |||
| InterleavingType interleaving; | |||
| }; | |||
| class Converter | |||
| { | |||
| public: | |||
| virtual ~Converter() {} | |||
| virtual void copySamples (void* dest, const void* source, int numSamples) const = 0; | |||
| }; | |||
| template <class SourceSampleType, class DestSampleType> | |||
| class ConverterInstance : public Converter | |||
| { | |||
| public: | |||
| ConverterInstance() {} | |||
| ~ConverterInstance() {} | |||
| void copySamples (void* const dest, const void* const source, const int numSamples) const | |||
| { | |||
| SourceSampleType s (source); | |||
| DestSampleType d (dest); | |||
| d.copySamples (s, numSamples); | |||
| } | |||
| private: | |||
| ConverterInstance (const ConverterInstance&); | |||
| ConverterInstance& operator= (const ConverterInstance&); | |||
| }; | |||
| }; | |||
| */ | |||
| /** | |||
| A set of routines to convert buffers of 32-bit floating point data to and from | |||
| various integer formats. | |||
| @@ -531,5 +531,113 @@ void AudioDataConverters::deinterleaveSamples (const float* const source, | |||
| } | |||
| } | |||
| #if JUCE_UNIT_TESTS | |||
| #include "../../utilities/juce_UnitTest.h" | |||
| #include "../../core/juce_Random.h" | |||
| /*class AudioConversionTests : public UnitTest | |||
| { | |||
| public: | |||
| AudioConversionTests() : UnitTest ("Audio data conversion") {} | |||
| template <class SourceType, class DestType> | |||
| struct Test5 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| const int numSamples = 2048; | |||
| int32 original [numSamples], converted [numSamples], reversed [numSamples]; | |||
| { | |||
| SourceType d (original); | |||
| for (int i = 0; i < numSamples / 2; ++i) | |||
| { | |||
| d.setAsFloat (Random::getSystemRandom().nextFloat() * 2.0f - 1.0f); | |||
| d.advance(); | |||
| d.setAsInt32 (Random::getSystemRandom().nextInt()); | |||
| d.advance(); | |||
| } | |||
| } | |||
| // convert data from the source to dest format.. | |||
| ScopedPointer<AudioData::Converter> conv (new AudioData::ConverterInstance <SourceType, DestType>()); | |||
| conv->copySamples (converted, original, numSamples); | |||
| // ..and back again.. | |||
| conv = new AudioData::ConverterInstance <DestType, SourceType>(); | |||
| zerostruct (reversed); | |||
| conv->copySamples (reversed, converted, numSamples); | |||
| { | |||
| int biggestDiff = 0; | |||
| SourceType d1 (original); | |||
| SourceType d2 (reversed); | |||
| const int errorMargin = 2 * DestType::get32BitResolution() + SourceType::get32BitResolution(); | |||
| for (int i = 0; i < numSamples; ++i) | |||
| { | |||
| biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32())); | |||
| d1.advance(); | |||
| d2.advance(); | |||
| } | |||
| unitTest.expect (biggestDiff <= errorMargin); | |||
| } | |||
| } | |||
| }; | |||
| template <class SourceType, class FormatType> | |||
| struct Test3 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| Test5 <SourceType, AudioData::Pointer <FormatType, AudioData::BigEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| Test5 <SourceType, AudioData::Pointer <FormatType, AudioData::LittleEndian, AudioData::NonInterleaved> >::test (unitTest); | |||
| } | |||
| }; | |||
| template <class SourceType> | |||
| struct Test2 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| { | |||
| Test3 <SourceType, AudioData::Int16>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int24>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int32>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Float32>::test (unitTest); | |||
| Test3 <SourceType, AudioData::Int8>::test (unitTest); | |||
| } | |||
| }; | |||
| template <class FormatType> | |||
| struct Test1 | |||
| { | |||
| 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); | |||
| } | |||
| }; | |||
| void runTest() | |||
| { | |||
| beginTest ("Round-trip conversion"); | |||
| Test1 <AudioData::Int8>::test (*this); | |||
| Test1 <AudioData::Int16>::test (*this); | |||
| Test1 <AudioData::Int24>::test (*this); | |||
| Test1 <AudioData::Int32>::test (*this); | |||
| Test1 <AudioData::Float32>::test (*this); | |||
| } | |||
| }; | |||
| static AudioConversionTests audioConversionUnitTests; | |||
| */ | |||
| #endif | |||
| END_JUCE_NAMESPACE | |||
| @@ -26,6 +26,274 @@ | |||
| #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ | |||
| #define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ | |||
| //============================================================================== | |||
| /** | |||
| */ | |||
| /* | |||
| struct 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_)) {} | |||
| 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 }; | |||
| }; | |||
| //============================================================================== | |||
| 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(); } | |||
| }; | |||
| 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); } | |||
| const int numChannels; | |||
| }; | |||
| //============================================================================== | |||
| template <class SampleFormat, | |||
| class Endianness, | |||
| class InterleavingType> | |||
| class Pointer | |||
| { | |||
| public: | |||
| Pointer (const void* sourceData) | |||
| : data (const_cast <void*> (sourceData)) | |||
| { | |||
| } | |||
| Pointer (const void* sourceData, int numInterleavedChannels) | |||
| : data (const_cast <void*> (sourceData)), | |||
| interleaving (numInterleavedChannels) | |||
| { | |||
| } | |||
| //============================================================================== | |||
| inline float getAsFloat() const throw() { return Endianness::getAsFloat (data); } | |||
| inline void setAsFloat (float newValue) throw() { Endianness::setAsFloat (data, newValue); } | |||
| inline int32 getAsInt32() const throw() { return Endianness::getAsInt32 (data); } | |||
| inline void setAsInt32 (int32 newValue) throw() { Endianness::setAsInt32 (data, newValue); } | |||
| inline void advance() throw() { interleaving.advance (data); } | |||
| void copySamples (Pointer& source, int numSamples) | |||
| { | |||
| while (--numSamples >= 0) | |||
| { | |||
| data.copyFromSameType (source.data); | |||
| advance(); | |||
| source.advance(); | |||
| } | |||
| } | |||
| template <class OtherPointerType> | |||
| void copySamples (OtherPointerType& source, int numSamples) | |||
| { | |||
| while (--numSamples >= 0) | |||
| { | |||
| Endianness::copyFrom (data, source); | |||
| advance(); | |||
| source.advance(); | |||
| } | |||
| } | |||
| bool isFloatingPoint() const throw() { return (bool) SampleFormat::isFloat; } | |||
| static int get32BitResolution() throw() { return (int) SampleFormat::resolution; } | |||
| typedef Endianness EndiannessType; | |||
| private: | |||
| //============================================================================== | |||
| SampleFormat data; | |||
| InterleavingType interleaving; | |||
| }; | |||
| //============================================================================== | |||
| class Converter | |||
| { | |||
| public: | |||
| virtual ~Converter() {} | |||
| virtual void copySamples (void* dest, const void* source, int numSamples) const = 0; | |||
| }; | |||
| //============================================================================== | |||
| template <class SourceSampleType, class DestSampleType> | |||
| class ConverterInstance : public Converter | |||
| { | |||
| public: | |||
| ConverterInstance() {} | |||
| ~ConverterInstance() {} | |||
| void copySamples (void* const dest, const void* const source, const int numSamples) const | |||
| { | |||
| SourceSampleType s (source); | |||
| DestSampleType d (dest); | |||
| d.copySamples (s, numSamples); | |||
| } | |||
| private: | |||
| ConverterInstance (const ConverterInstance&); | |||
| ConverterInstance& operator= (const ConverterInstance&); | |||
| }; | |||
| }; | |||
| */ | |||
| //============================================================================== | |||
| /** | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 52 | |||
| #define JUCE_BUILDNUMBER 67 | |||
| #define JUCE_BUILDNUMBER 68 | |||
| /** Current Juce version number. | |||
| @@ -220,15 +220,25 @@ bool File::setAsCurrentWorkingDirectory() const | |||
| } | |||
| //============================================================================== | |||
| static bool juce_stat (const String& fileName, struct stat& info) | |||
| #if JUCE_IOS | |||
| typedef struct stat64 juce_statStruct; // (need to use the 64-bit version to work around a simulator bug) | |||
| #else | |||
| typedef struct stat juce_statStruct; | |||
| #endif | |||
| static bool juce_stat (const String& fileName, juce_statStruct& info) | |||
| { | |||
| return fileName.isNotEmpty() | |||
| #if JUCE_IOS | |||
| && (stat64 (fileName.toUTF8(), &info) == 0); | |||
| #else | |||
| && (stat (fileName.toUTF8(), &info) == 0); | |||
| #endif | |||
| } | |||
| bool File::isDirectory() const | |||
| { | |||
| struct stat info; | |||
| juce_statStruct info; | |||
| return fullPath.isEmpty() | |||
| || (juce_stat (fullPath, info) && ((info.st_mode & S_IFDIR) != 0)); | |||
| @@ -247,7 +257,7 @@ bool File::existsAsFile() const | |||
| int64 File::getSize() const | |||
| { | |||
| struct stat info; | |||
| juce_statStruct info; | |||
| return juce_stat (fullPath, info) ? info.st_size : 0; | |||
| } | |||
| @@ -265,9 +275,8 @@ bool File::hasWriteAccess() const | |||
| bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const | |||
| { | |||
| struct stat info; | |||
| const int res = stat (fullPath.toUTF8(), &info); | |||
| if (res != 0) | |||
| juce_statStruct info; | |||
| if (! juce_stat (fullPath, info)) | |||
| return false; | |||
| info.st_mode &= 0777; // Just permissions | |||
| @@ -287,9 +296,8 @@ void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int | |||
| accessTime = 0; | |||
| creationTime = 0; | |||
| struct stat info; | |||
| const int res = stat (fullPath.toUTF8(), &info); | |||
| if (res == 0) | |||
| juce_statStruct info; | |||
| if (juce_stat (fullPath, info)) | |||
| { | |||
| modificationTime = (int64) info.st_mtime * 1000; | |||
| accessTime = (int64) info.st_atime * 1000; | |||
| @@ -779,7 +779,9 @@ const Image juce_loadWithCoreImage (InputStream& input) | |||
| #if JUCE_IOS | |||
| JUCE_AUTORELEASEPOOL | |||
| UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData() length: data.getSize()]]; | |||
| UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData() | |||
| length: data.getSize() | |||
| freeWhenDone: NO]]; | |||
| if (image != nil) | |||
| { | |||
| @@ -309,7 +309,7 @@ public: | |||
| if (isDir != 0 || fileSize != 0 || modTime != 0 || creationTime != 0) | |||
| { | |||
| struct stat info; | |||
| juce_statStruct info; | |||
| const bool statOk = juce_stat (path, info); | |||
| if (isDir != 0) *isDir = statOk && ((info.st_mode & S_IFDIR) != 0); | |||