diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index effde95964..3d4b977203 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -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 + 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 conv (new AudioData::ConverterInstance ()); + conv->copySamples (converted, original, numSamples); + + // ..and back again.. + conv = new AudioData::ConverterInstance (); + 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 + struct Test3 + { + static void test (UnitTest& unitTest) + { + Test5 >::test (unitTest); + Test5 >::test (unitTest); + } + }; + + template + struct Test2 + { + static void test (UnitTest& unitTest) + { + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + } + }; + + template + struct Test1 + { + static void test (UnitTest& unitTest) + { + Test2 >::test (unitTest); + Test2 >::test (unitTest); + } + }; + + void runTest() + { + beginTest ("Round-trip conversion"); + + Test1 ::test (*this); + Test1 ::test (*this); + Test1 ::test (*this); + Test1 ::test (*this); + Test1 ::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) { diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 0b034ce041..740dc6210b 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -64,7 +64,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 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 static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } + template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } + template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } + }; + + struct LittleEndian + { + template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } + template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } + template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromLE (source); } + }; + + #if JUCE_BIG_ENDIAN + typedef BigEndian NativeEndian; + #else + typedef LittleEndian NativeEndian; + #endif + + struct Int8 + { + inline Int8 (void* data_) : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / maxValue)); } + inline float getAsFloatBE() const throw() { return (float) (*data * (1.0 / maxValue)); } + inline void setAsFloatLE (float newValue) throw() { *data = (int8) roundToInt (newValue * (double) maxValue); } + inline void setAsFloatBE (float newValue) throw() { *data = (int8) roundToInt (newValue * (double) maxValue); } + inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); } + inline int32 getAsInt32BE() const throw() { return (int) (*data << 24); } + inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); } + inline void setAsInt32BE (int newValue) throw() { *data = (int8) (newValue >> 24); } + + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int8& source) throw() { *data = *source.data; } + + int8* data; + enum { maxValue = 0x80, resolution = 0x1000000, isFloat = 0 }; + }; + + struct Int16 + { + inline Int16 (void* data_) : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) ((1.0 / maxValue) * (int16) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const throw() { return (float) ((1.0 / maxValue) * (int16) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) roundToInt (newValue * (double) maxValue)); } + inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) roundToInt (newValue * (double) maxValue)); } + inline int32 getAsInt32LE() const throw() { return (int32) (ByteOrder::swapIfBigEndian ((uint16) *data) << 16); } + inline int32 getAsInt32BE() const throw() { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); } + inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); } + inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); } + + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int16& source) throw() { *data = *source.data; } + + uint16* data; + enum { maxValue = 0x8000, resolution = 0x10000, isFloat = 0 }; + }; + + struct Int24 + { + inline Int24 (void* data_) : data (static_cast (data_)) {} + + inline void advance() throw() { data += 3; } + inline void skip (int numSamples) throw() { data += 3 * numSamples; } + + inline float getAsFloatLE() const throw() { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / maxValue)); } + inline float getAsFloatBE() const throw() { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / maxValue)); } + inline void setAsFloatLE (float newValue) throw() { ByteOrder::littleEndian24BitToChars (roundToInt (newValue * (double) maxValue), data); } + inline void setAsFloatBE (float newValue) throw() { ByteOrder::bigEndian24BitToChars (roundToInt (newValue * (double) maxValue), data); } + inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::littleEndian24Bit (data) << 8; } + inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; } + inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); } + inline void setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); } + + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int24& source) throw() { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; } + + char* data; + enum { maxValue = 0x800000, resolution = 0x100, isFloat = 0 }; + }; + + struct Int32 + { + inline Int32 (void* data_) : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) roundToInt (newValue * (1.0 + maxValue))); } + inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (newValue * (1.0 + maxValue))); } + inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::swapIfBigEndian (*data); } + inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); } + inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } + inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); } + + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int32& source) throw() { *data = *source.data; } + + uint32* data; + enum { maxValue = 0x7fffffff, resolution = 1, isFloat = 0 }; + }; + + struct Float32 + { + inline Float32 (void* data_) : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + + #if JUCE_BIG_ENDIAN + inline float getAsFloatBE() const throw() { return *data; } + inline void setAsFloatBE (float newValue) throw() { *data = newValue; } + inline float getAsFloatLE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } + inline void setAsFloatLE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } + #else + inline float getAsFloatLE() const throw() { return *data; } + inline void setAsFloatLE (float newValue) throw() { *data = newValue; } + inline float getAsFloatBE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } + inline void setAsFloatBE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } + #endif + + inline int32 getAsInt32LE() const throw() { return (int32) roundToInt (getAsFloatLE() * (1.0 + maxValue)); } + inline int32 getAsInt32BE() const throw() { return (int32) roundToInt (getAsFloatBE() * (1.0 + maxValue)); } + inline void setAsInt32LE (int32 newValue) throw() { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } + inline void setAsInt32BE (int32 newValue) throw() { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } + + template inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } + template inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); } + inline void copyFromSameType (Float32& source) throw() { *data = *source.data; } + + float* data; + enum { maxValue = 0x7fffffff, resolution = 0x100, isFloat = 1 }; + }; + + struct NonInterleaved + { + inline NonInterleaved () throw() {} + inline NonInterleaved (const int numChannels) throw() + { jassert (numChannels == 1); } // If you hit this assert, you're trying to create a non-interleaved pointer with more than one interleaved channel.. + + template inline void advance (SampleFormatType& s) throw() { s.advance(); } + }; + + struct Interleaved + { + inline Interleaved () throw() : numChannels (1) {} + inline Interleaved (const int numChannels_) throw() : numChannels (numChannels_) {} + template inline void advance (SampleFormatType& s) throw() { s.skip (numChannels); } + + const int numChannels; + }; + + template + class Pointer + { + public: + Pointer (const void* sourceData) + : data (const_cast (sourceData)) + { + } + + Pointer (const void* sourceData, int numInterleavedChannels) + : data (const_cast (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 + 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 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. diff --git a/src/audio/dsp/juce_AudioDataConverters.cpp b/src/audio/dsp/juce_AudioDataConverters.cpp index 7e1db6c4c9..60b10882a8 100644 --- a/src/audio/dsp/juce_AudioDataConverters.cpp +++ b/src/audio/dsp/juce_AudioDataConverters.cpp @@ -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 + 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 conv (new AudioData::ConverterInstance ()); + conv->copySamples (converted, original, numSamples); + + // ..and back again.. + conv = new AudioData::ConverterInstance (); + 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 + struct Test3 + { + static void test (UnitTest& unitTest) + { + Test5 >::test (unitTest); + Test5 >::test (unitTest); + } + }; + + template + struct Test2 + { + static void test (UnitTest& unitTest) + { + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + Test3 ::test (unitTest); + } + }; + + template + struct Test1 + { + static void test (UnitTest& unitTest) + { + Test2 >::test (unitTest); + Test2 >::test (unitTest); + } + }; + + void runTest() + { + beginTest ("Round-trip conversion"); + + Test1 ::test (*this); + Test1 ::test (*this); + Test1 ::test (*this); + Test1 ::test (*this); + Test1 ::test (*this); + } +}; + +static AudioConversionTests audioConversionUnitTests; +*/ + +#endif + END_JUCE_NAMESPACE diff --git a/src/audio/dsp/juce_AudioDataConverters.h b/src/audio/dsp/juce_AudioDataConverters.h index 2c218f254a..040dd3893f 100644 --- a/src/audio/dsp/juce_AudioDataConverters.h +++ b/src/audio/dsp/juce_AudioDataConverters.h @@ -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 static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } + template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } + template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } + }; + + struct LittleEndian + { + template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } + template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } + template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } + template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } + template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromLE (source); } + }; + + #if JUCE_BIG_ENDIAN + typedef BigEndian NativeEndian; + #else + typedef LittleEndian NativeEndian; + #endif + + //============================================================================== + struct Int8 + { + inline Int8 (void* data_) : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / maxValue)); } + inline float getAsFloatBE() const throw() { return (float) (*data * (1.0 / maxValue)); } + inline void setAsFloatLE (float newValue) throw() { *data = (int8) roundToInt (newValue * (double) maxValue); } + inline void setAsFloatBE (float newValue) throw() { *data = (int8) roundToInt (newValue * (double) maxValue); } + inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); } + inline int32 getAsInt32BE() const throw() { return (int) (*data << 24); } + inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); } + inline void setAsInt32BE (int newValue) throw() { *data = (int8) (newValue >> 24); } + + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int8& source) throw() { *data = *source.data; } + + int8* data; + enum { maxValue = 0x80, resolution = 0x1000000, isFloat = 0 }; + }; + + struct Int16 + { + inline Int16 (void* data_) : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) ((1.0 / maxValue) * (int16) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const throw() { return (float) ((1.0 / maxValue) * (int16) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) roundToInt (newValue * (double) maxValue)); } + inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) roundToInt (newValue * (double) maxValue)); } + inline int32 getAsInt32LE() const throw() { return (int32) (ByteOrder::swapIfBigEndian ((uint16) *data) << 16); } + inline int32 getAsInt32BE() const throw() { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); } + inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); } + inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); } + + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int16& source) throw() { *data = *source.data; } + + uint16* data; + enum { maxValue = 0x8000, resolution = 0x10000, isFloat = 0 }; + }; + + struct Int24 + { + inline Int24 (void* data_) : data (static_cast (data_)) {} + + inline void advance() throw() { data += 3; } + inline void skip (int numSamples) throw() { data += 3 * numSamples; } + + inline float getAsFloatLE() const throw() { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / maxValue)); } + inline float getAsFloatBE() const throw() { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / maxValue)); } + inline void setAsFloatLE (float newValue) throw() { ByteOrder::littleEndian24BitToChars (roundToInt (newValue * (double) maxValue), data); } + inline void setAsFloatBE (float newValue) throw() { ByteOrder::bigEndian24BitToChars (roundToInt (newValue * (double) maxValue), data); } + inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::littleEndian24Bit (data) << 8; } + inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; } + inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); } + inline void setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); } + + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int24& source) throw() { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; } + + char* data; + enum { maxValue = 0x800000, resolution = 0x100, isFloat = 0 }; + }; + + struct Int32 + { + inline Int32 (void* data_) : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } + inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } + inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) roundToInt (newValue * (1.0 + maxValue))); } + inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (newValue * (1.0 + maxValue))); } + inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::swapIfBigEndian (*data); } + inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); } + inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } + inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); } + + template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } + template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } + inline void copyFromSameType (Int32& source) throw() { *data = *source.data; } + + uint32* data; + enum { maxValue = 0x7fffffff, resolution = 1, isFloat = 0 }; + }; + + struct Float32 + { + inline Float32 (void* data_) : data (static_cast (data_)) {} + + inline void advance() throw() { ++data; } + inline void skip (int numSamples) throw() { data += numSamples; } + + #if JUCE_BIG_ENDIAN + inline float getAsFloatBE() const throw() { return *data; } + inline void setAsFloatBE (float newValue) throw() { *data = newValue; } + inline float getAsFloatLE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } + inline void setAsFloatLE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } + #else + inline float getAsFloatLE() const throw() { return *data; } + inline void setAsFloatLE (float newValue) throw() { *data = newValue; } + inline float getAsFloatBE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } + inline void setAsFloatBE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } + #endif + + inline int32 getAsInt32LE() const throw() { return (int32) roundToInt (getAsFloatLE() * (1.0 + maxValue)); } + inline int32 getAsInt32BE() const throw() { return (int32) roundToInt (getAsFloatBE() * (1.0 + maxValue)); } + inline void setAsInt32LE (int32 newValue) throw() { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } + inline void setAsInt32BE (int32 newValue) throw() { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } + + template inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } + template inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); } + inline void copyFromSameType (Float32& source) throw() { *data = *source.data; } + + float* data; + enum { maxValue = 0x7fffffff, resolution = 0x100, isFloat = 1 }; + }; + + //============================================================================== + struct NonInterleaved + { + inline NonInterleaved () throw() {} + inline NonInterleaved (const int numChannels) throw() + { jassert (numChannels == 1); } // If you hit this assert, you're trying to create a non-interleaved pointer with more than one interleaved channel.. + + template inline void advance (SampleFormatType& s) throw() { s.advance(); } + }; + + struct Interleaved + { + inline Interleaved () throw() : numChannels (1) {} + inline Interleaved (const int numChannels_) throw() : numChannels (numChannels_) {} + template inline void advance (SampleFormatType& s) throw() { s.skip (numChannels); } + + const int numChannels; + }; + + + //============================================================================== + template + class Pointer + { + public: + Pointer (const void* sourceData) + : data (const_cast (sourceData)) + { + } + + Pointer (const void* sourceData, int numInterleavedChannels) + : data (const_cast (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 + 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 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&); + }; +}; +*/ //============================================================================== /** diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index f6d9234e77..73a5f87d7f 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 67 +#define JUCE_BUILDNUMBER 68 /** Current Juce version number. diff --git a/src/native/common/juce_posix_SharedCode.h b/src/native/common/juce_posix_SharedCode.h index 86e32bee1d..9e31ee3faf 100644 --- a/src/native/common/juce_posix_SharedCode.h +++ b/src/native/common/juce_posix_SharedCode.h @@ -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; diff --git a/src/native/mac/juce_mac_CoreGraphicsContext.mm b/src/native/mac/juce_mac_CoreGraphicsContext.mm index e7e1c4c8d8..d1079ad531 100644 --- a/src/native/mac/juce_mac_CoreGraphicsContext.mm +++ b/src/native/mac/juce_mac_CoreGraphicsContext.mm @@ -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) { diff --git a/src/native/mac/juce_mac_Files.mm b/src/native/mac/juce_mac_Files.mm index 1a1780786d..3e1df31e3b 100644 --- a/src/native/mac/juce_mac_Files.mm +++ b/src/native/mac/juce_mac_Files.mm @@ -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);