diff --git a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj index 3dff2a000d..ee5e9b7dbe 100644 --- a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj @@ -413,6 +413,7 @@ EBA6B46F7B3C11CA3744A4D0 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioDataConverters.h; path = ../../src/audio/dsp/juce_AudioDataConverters.h; sourceTree = SOURCE_ROOT; }; A1D687AE613A8B61EB63923D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioSampleBuffer.cpp; path = ../../src/audio/dsp/juce_AudioSampleBuffer.cpp; sourceTree = SOURCE_ROOT; }; 812620B53BE820D26A63B65D = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioSampleBuffer.h; path = ../../src/audio/dsp/juce_AudioSampleBuffer.h; sourceTree = SOURCE_ROOT; }; + 11C1A96A35A2F03F8C34BD43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Decibels.h; path = ../../src/audio/dsp/juce_Decibels.h; sourceTree = SOURCE_ROOT; }; E68EB4BC75216B5B56E3F937 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_IIRFilter.cpp; path = ../../src/audio/dsp/juce_IIRFilter.cpp; sourceTree = SOURCE_ROOT; }; EE2259D9768027C2C001EEAD = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_IIRFilter.h; path = ../../src/audio/dsp/juce_IIRFilter.h; sourceTree = SOURCE_ROOT; }; B457515938E7141D5E79B671 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_MidiBuffer.cpp; path = ../../src/audio/midi/juce_MidiBuffer.cpp; sourceTree = SOURCE_ROOT; }; @@ -1111,6 +1112,7 @@ EBA6B46F7B3C11CA3744A4D0, A1D687AE613A8B61EB63923D, 812620B53BE820D26A63B65D, + 11C1A96A35A2F03F8C34BD43, E68EB4BC75216B5B56E3F937, EE2259D9768027C2C001EEAD ); name = dsp; sourceTree = ""; }; 99B60B012D5CCF0BD861011D = { isa = PBXGroup; children = ( diff --git a/Builds/VisualStudio2005/Juce.vcproj b/Builds/VisualStudio2005/Juce.vcproj index c65091856a..4e8c3542bb 100644 --- a/Builds/VisualStudio2005/Juce.vcproj +++ b/Builds/VisualStudio2005/Juce.vcproj @@ -181,6 +181,7 @@ + diff --git a/Builds/VisualStudio2008/Juce.vcproj b/Builds/VisualStudio2008/Juce.vcproj index 4958349e45..3cfa9c6ff9 100644 --- a/Builds/VisualStudio2008/Juce.vcproj +++ b/Builds/VisualStudio2008/Juce.vcproj @@ -181,6 +181,7 @@ + diff --git a/Builds/VisualStudio2008_DLL/Juce.vcproj b/Builds/VisualStudio2008_DLL/Juce.vcproj index 2e5b90d277..465db68f8e 100644 --- a/Builds/VisualStudio2008_DLL/Juce.vcproj +++ b/Builds/VisualStudio2008_DLL/Juce.vcproj @@ -183,6 +183,7 @@ + diff --git a/Builds/VisualStudio2010/Juce.vcxproj b/Builds/VisualStudio2010/Juce.vcxproj index 4437963a89..e54ecca3ba 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj +++ b/Builds/VisualStudio2010/Juce.vcxproj @@ -469,6 +469,7 @@ + diff --git a/Builds/VisualStudio2010/Juce.vcxproj.filters b/Builds/VisualStudio2010/Juce.vcxproj.filters index b199e27517..9088669d98 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj.filters +++ b/Builds/VisualStudio2010/Juce.vcxproj.filters @@ -1329,6 +1329,9 @@ Juce\Source\audio\dsp + + Juce\Source\audio\dsp + Juce\Source\audio\dsp diff --git a/Builds/iPhone/Juce.xcodeproj/project.pbxproj b/Builds/iPhone/Juce.xcodeproj/project.pbxproj index 91aecd946f..907e9ebff7 100644 --- a/Builds/iPhone/Juce.xcodeproj/project.pbxproj +++ b/Builds/iPhone/Juce.xcodeproj/project.pbxproj @@ -413,6 +413,7 @@ EBA6B46F7B3C11CA3744A4D0 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioDataConverters.h; path = ../../src/audio/dsp/juce_AudioDataConverters.h; sourceTree = SOURCE_ROOT; }; A1D687AE613A8B61EB63923D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioSampleBuffer.cpp; path = ../../src/audio/dsp/juce_AudioSampleBuffer.cpp; sourceTree = SOURCE_ROOT; }; 812620B53BE820D26A63B65D = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioSampleBuffer.h; path = ../../src/audio/dsp/juce_AudioSampleBuffer.h; sourceTree = SOURCE_ROOT; }; + 11C1A96A35A2F03F8C34BD43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Decibels.h; path = ../../src/audio/dsp/juce_Decibels.h; sourceTree = SOURCE_ROOT; }; E68EB4BC75216B5B56E3F937 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_IIRFilter.cpp; path = ../../src/audio/dsp/juce_IIRFilter.cpp; sourceTree = SOURCE_ROOT; }; EE2259D9768027C2C001EEAD = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_IIRFilter.h; path = ../../src/audio/dsp/juce_IIRFilter.h; sourceTree = SOURCE_ROOT; }; B457515938E7141D5E79B671 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_MidiBuffer.cpp; path = ../../src/audio/midi/juce_MidiBuffer.cpp; sourceTree = SOURCE_ROOT; }; @@ -1111,6 +1112,7 @@ EBA6B46F7B3C11CA3744A4D0, A1D687AE613A8B61EB63923D, 812620B53BE820D26A63B65D, + 11C1A96A35A2F03F8C34BD43, E68EB4BC75216B5B56E3F937, EE2259D9768027C2C001EEAD ); name = dsp; sourceTree = ""; }; 99B60B012D5CCF0BD861011D = { isa = PBXGroup; children = ( diff --git a/Juce.jucer b/Juce.jucer index 51f3e6304a..a4303b177c 100644 --- a/Juce.jucer +++ b/Juce.jucer @@ -189,6 +189,8 @@ resource="0" file="src/audio/dsp/juce_AudioSampleBuffer.cpp"/> + *> (&text)->exchange (newText)); + StringHolder::release (reinterpret_cast &> (text).exchange (newText)); return *this; } -String::String (const size_t numChars, const int /*dummyVariable*/) - : text (StringHolder::createUninitialised (numChars)) +inline String::Preallocation::Preallocation (const size_t numChars_) : numChars (numChars_) {} + +String::String (const Preallocation& preallocationSize) + : text (StringHolder::createUninitialised (preallocationSize.numChars)) { } @@ -11992,7 +11999,7 @@ String::String (const juce_wchar* const t, const size_t maxChars) const String String::charToString (const juce_wchar character) { - String result ((size_t) 1, (int) 0); + String result (Preallocation (1)); result.text[0] = character; result.text[1] = 0; return result; @@ -12815,7 +12822,7 @@ bool String::matchesWildcard (const String& wildcard, const bool ignoreCase) con const String String::repeatedString (const String& stringToRepeat, int numberOfTimesToRepeat) { const int len = stringToRepeat.length(); - String result ((size_t) (len * numberOfTimesToRepeat + 1), (int) 0); + String result (Preallocation (len * numberOfTimesToRepeat + 1)); juce_wchar* n = result.text; *n = 0; @@ -12836,7 +12843,7 @@ const String String::paddedLeft (const juce_wchar padCharacter, int minimumLengt if (len >= minimumLength || padCharacter == 0) return *this; - String result ((size_t) minimumLength + 1, (int) 0); + String result (Preallocation (minimumLength + 1)); juce_wchar* n = result.text; minimumLength -= len; @@ -12902,7 +12909,7 @@ const String String::replaceSection (int index, int numCharsToReplace, const Str if (newTotalLen <= 0) return String::empty; - String result ((size_t) newTotalLen, (int) 0); + String result (Preallocation ((size_t) newTotalLen)); StringHolder::copyChars (result.text, text, index); @@ -13271,7 +13278,7 @@ const String String::retainCharacters (const String& charactersToRetain) const if (isEmpty()) return empty; - String result (StringHolder::getAllocatedNumChars (text), (int) 0); + String result (Preallocation (StringHolder::getAllocatedNumChars (text))); juce_wchar* dst = result.text; const juce_wchar* src = text; @@ -13292,7 +13299,7 @@ const String String::removeCharacters (const String& charactersToRemove) const if (isEmpty()) return empty; - String result (StringHolder::getAllocatedNumChars (text), (int) 0); + String result (Preallocation (StringHolder::getAllocatedNumChars (text))); juce_wchar* dst = result.text; const juce_wchar* src = text; @@ -13380,7 +13387,7 @@ const String String::formatted (const juce_wchar* const pf, ... ) va_start (args, pf); size_t bufferSize = 256; - String result (bufferSize, (int) 0); + String result (Preallocation ((size_t) bufferSize)); result.text[0] = 0; for (;;) @@ -13505,9 +13512,7 @@ const String String::toHexString (const short number) return toHexString ((int) (unsigned short) number); } -const String String::toHexString (const unsigned char* data, - const int size, - const int groupSize) +const String String::toHexString (const unsigned char* data, const int size, const int groupSize) { if (size <= 0) return empty; @@ -13516,7 +13521,7 @@ const String String::toHexString (const unsigned char* data, if (groupSize > 0) numChars += size / groupSize; - String s ((size_t) numChars, (int) 0); + String s (Preallocation ((size_t) numChars)); juce_wchar* d = s.text; @@ -13769,7 +13774,7 @@ const String String::fromUTF8 (const char* const buffer, int bufferSizeBytes) if (buffer [numBytes] == 0) break; - String result ((size_t) numBytes + 1, (int) 0); + String result (Preallocation (numBytes + 1)); juce_wchar* dest = result.text; size_t i = 0; @@ -22625,8 +22630,10 @@ void AudioThumbnail::saveTo (OutputStream& output) const channels.getUnchecked(chan)->getData(i)->write (output); } -void AudioThumbnail::setDataSource (LevelDataSource* newSource) +bool AudioThumbnail::setDataSource (LevelDataSource* newSource) { + jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); + numSamplesFinished = 0; if (cache.loadThumb (*this, newSource->hashCode) && isFullyLoaded()) @@ -22651,14 +22658,15 @@ void AudioThumbnail::setDataSource (LevelDataSource* newSource) createChannels (1 + (int) (totalSamples / samplesPerThumbSample)); } + + return sampleRate > 0 && totalSamples > 0; } -void AudioThumbnail::setSource (InputSource* const newSource) +bool AudioThumbnail::setSource (InputSource* const newSource) { clear(); - if (newSource != 0) - setDataSource (new LevelDataSource (*this, newSource)); + return newSource != 0 && setDataSource (new LevelDataSource (*this, newSource)); } void AudioThumbnail::setReader (AudioFormatReader* newReader, int64 hash) @@ -22669,6 +22677,11 @@ void AudioThumbnail::setReader (AudioFormatReader* newReader, int64 hash) setDataSource (new LevelDataSource (*this, newReader, hash)); } +int64 AudioThumbnail::getHashCode() const +{ + return source == 0 ? 0 : source->hashCode; +} + void AudioThumbnail::addBlock (const int64 startSample, const AudioSampleBuffer& incoming, int startOffsetInBuffer, int numSamples) { @@ -237848,7 +237861,7 @@ int64 Time::getHighResolutionTicks() throw() LARGE_INTEGER ticks; QueryPerformanceCounter (&ticks); - const int64 mainCounterAsHiResTicks = (GetTickCount() * hiResTicksPerSecond) / 1000; + const int64 mainCounterAsHiResTicks = (juce_millisecondsSinceStartup() * hiResTicksPerSecond) / 1000; const int64 newOffset = mainCounterAsHiResTicks - ticks.QuadPart; // fix for a very obscure PCI hardware bug that can make the counter @@ -255339,27 +255352,6 @@ namespace LinuxStatsHelpers return String::empty; } - - bool getTimeSinceStartup (timeval* const t) throw() - { - if (gettimeofday (t, 0) != 0) - return false; - - static unsigned int calibrate = 0; - static bool calibrated = false; - - if (! calibrated) - { - calibrated = true; - - struct sysinfo sysi; - if (sysinfo (&sysi) == 0) - calibrate = t->tv_sec - sysi.uptime; // Safe to assume system was not brought up earlier than 1970! - } - - t->tv_sec -= calibrate; - return true; - } } const String SystemStats::getCpuVendor() @@ -255423,20 +255415,18 @@ void PlatformUtilities::fpuReset() uint32 juce_millisecondsSinceStartup() throw() { - timeval t; - if (LinuxStatsHelpers::getTimeSinceStartup (&t)) - return (uint32) (t.tv_sec * 1000 + (t.tv_usec / 1000)); + timespec t; + clock_gettime (CLOCK_MONOTONIC, &t); - return 0; + return t.tv_sec * 1000 + t.tv_nsec / 1000000; } int64 Time::getHighResolutionTicks() throw() { - timeval t; - if (LinuxStatsHelpers::getTimeSinceStartup (&t)) - return ((int64) t.tv_sec * (int64) 1000000) + (int64) t.tv_usec; + timespec t; + clock_gettime (CLOCK_MONOTONIC, &t); - return 0; + return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / (int64) 1000); } int64 Time::getHighResolutionTicksPerSecond() throw() diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 5bbe9f0746..a66237ef1e 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -2712,8 +2712,14 @@ private: juce_wchar* text; - // internal constructor that preallocates a certain amount of memory - String (size_t numChars, int dummyVariable); + struct Preallocation + { + explicit Preallocation (size_t); + size_t numChars; + }; + + // This constructor preallocates a certain amount of memory + explicit String (const Preallocation&); String (const String& stringToCopy, size_t charsToAllocate); void createInternal (const juce_wchar* text, size_t numChars); @@ -8937,19 +8943,20 @@ public: */ static int64 currentTimeMillis() throw(); - /** Returns the number of millisecs since system startup. + /** Returns the number of millisecs since a fixed event (usually system startup). - Should be accurate to within a few millisecs, depending on platform, + This returns a monotonically increasing value which it unaffected by changes to the + system clock. It should be accurate to within a few millisecs, depending on platform, hardware, etc. @see getApproximateMillisecondCounter */ static uint32 getMillisecondCounter() throw(); - /** Returns the number of millisecs since system startup. + /** Returns the number of millisecs since a fixed event (usually system startup). - Same as getMillisecondCounter(), but returns a more accurate value, using - the high-res timer. + This has the same function as getMillisecondCounter(), but returns a more accurate + value, using a higher-resolution timer if one is available. @see getMillisecondCounter */ @@ -17113,7 +17120,7 @@ class JUCE_API FileInputSource : public InputSource { public: - FileInputSource (const File& file); + FileInputSource (const File& file, bool useFileTimeInHashGeneration = false); ~FileInputSource(); InputStream* createInputStream(); @@ -17123,6 +17130,7 @@ public: private: const File file; + bool useFileTimeInHashGeneration; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputSource); }; @@ -21641,8 +21649,8 @@ public: { const int x1 = (int) std::floor (static_cast (x)); const int y1 = (int) std::floor (static_cast (y)); - const int x2 = (int) std::floor (static_cast (x + w + 0.9999f)); - const int y2 = (int) std::floor (static_cast (y + h + 0.9999f)); + const int x2 = (int) std::ceil (static_cast (x + w)); + const int y2 = (int) std::ceil (static_cast (y + h)); return Rectangle (x1, y1, x2 - x1, y2 - y1); } @@ -22166,19 +22174,13 @@ public: const Point getCurrentPosition() const; /** Adds a rectangle to the path. - - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). - + The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRoundedRectangle, addTriangle */ void addRectangle (float x, float y, float width, float height); /** Adds a rectangle to the path. - - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). - + The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRoundedRectangle, addTriangle */ template @@ -22189,30 +22191,45 @@ public: } /** Adds a rectangle with rounded corners to the path. - - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). - + The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRectangle, addTriangle */ void addRoundedRectangle (float x, float y, float width, float height, float cornerSize); /** Adds a rectangle with rounded corners to the path. - - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). - + The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRectangle, addTriangle */ void addRoundedRectangle (float x, float y, float width, float height, float cornerSizeX, float cornerSizeY); + /** Adds a rectangle with rounded corners to the path. + The rectangle is added as a new sub-path. (Any currently open paths will be left open). + @see addRectangle, addTriangle + */ + template + void addRoundedRectangle (const Rectangle& rectangle, float cornerSizeX, float cornerSizeY) + { + addRoundedRectangle (static_cast (rectangle.getX()), static_cast (rectangle.getY()), + static_cast (rectangle.getWidth()), static_cast (rectangle.getHeight()), + cornerSizeX, cornerSizeY); + } + + /** Adds a rectangle with rounded corners to the path. + The rectangle is added as a new sub-path. (Any currently open paths will be left open). + @see addRectangle, addTriangle + */ + template + void addRoundedRectangle (const Rectangle& rectangle, float cornerSize) + { + addRoundedRectangle (rectangle, cornerSize, cornerSize); + } + /** Adds a triangle to the path. - The triangle is added as a new closed sub-path. (Any currently open paths will be - left open). + The triangle is added as a new closed sub-path. (Any currently open paths will be left open). Note that whether the vertices are specified in clockwise or anticlockwise order will affect how the triangle is filled when it overlaps other @@ -22224,8 +22241,7 @@ public: /** Adds a quadrilateral to the path. - The quad is added as a new closed sub-path. (Any currently open paths will be - left open). + The quad is added as a new closed sub-path. (Any currently open paths will be left open). Note that whether the vertices are specified in clockwise or anticlockwise order will affect how the quad is filled when it overlaps other @@ -22238,8 +22254,7 @@ public: /** Adds an ellipse to the path. - The shape is added as a new sub-path. (Any currently open paths will be - left open). + The shape is added as a new sub-path. (Any currently open paths will be left open). @see addArc */ @@ -32601,11 +32616,11 @@ public: @endcode You can pass a zero in here to clear the thumbnail. - - The source that is passed in will be deleted by this object when it is no - longer needed + The source that is passed in will be deleted by this object when it is no longer needed. + @returns true if the source could be opened as a valid audio file, false if this failed for + some reason. */ - void setSource (InputSource* newSource); + bool setSource (InputSource* newSource); /** Gives the thumbnail an AudioFormatReader to use directly. This will start parsing the audio in a background thread (unless the hash code @@ -32685,6 +32700,9 @@ public: /** Returns true if the low res preview is fully generated. */ bool isFullyLoaded() const throw(); + /** Returns the hash code that was set by setSource() or setReader(). */ + int64 getHashCode() const; + // (this is only public to avoid a VC6 bug) class LevelDataSource; @@ -32714,7 +32732,7 @@ private: double sampleRate; CriticalSection lock; - void setDataSource (LevelDataSource* newSource); + bool setDataSource (LevelDataSource* newSource); void setLevels (const MinMaxValue* const* values, int thumbIndex, int numChans, int numValues); void createChannels (int length); @@ -39221,6 +39239,88 @@ private: #endif #ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ +#endif +#ifndef __JUCE_DECIBELS_JUCEHEADER__ + +/*** Start of inlined file: juce_Decibels.h ***/ +#ifndef __JUCE_DECIBELS_JUCEHEADER__ +#define __JUCE_DECIBELS_JUCEHEADER__ + +/** + This class contains some helpful static methods for dealing with decibel values. +*/ +class Decibels +{ +public: + + /** Converts a dBFS value to its equivalent gain level. + + A gain of 1.0 = 0 dB, and lower gains map onto negative decibel values. Any + decibel value lower than minusInfinityDb will return a gain of 0. + */ + template + static Type decibelsToGain (const Type decibels, + const Type minusInfinityDb = (Type) defaultMinusInfinitydB) + { + return decibels > minusInfinityDb ? powf ((Type) 10.0, decibels * (Type) 0.05) + : Type(); + } + + /** Converts a gain level into a dBFS value. + + A gain of 1.0 = 0 dB, and lower gains map onto negative decibel values. + If the gain is 0 (or negative), then the method will return the value + provided as minusInfinityDb. + */ + template + static Type gainToDecibels (const Type gain, + const Type minusInfinityDb = (Type) defaultMinusInfinitydB) + { + return gain > Type() ? jmax (minusInfinityDb, (Type) std::log (gain) * (Type) 20.0) + : minusInfinityDb; + } + + /** Converts a decibel reading to a string, with the 'dB' suffix. + If the decibel value is lower than minusInfinityDb, the return value will + be "-INF dB". + */ + template + static const String toString (const Type decibels, + const int decimalPlaces = 2, + const Type minusInfinityDb = (Type) defaultMinusInfinitydB) + { + String s; + + if (decibels <= minusInfinityDb) + { + s = "-INF dB"; + } + else + { + if (decibels >= Type()) + s << '+'; + + s << String (decibels, decimalPlaces) << " dB"; + } + + return s; + } + +private: + + enum + { + defaultMinusInfinitydB = -100 + }; + + Decibels(); // This class can't be instantiated, it's just a holder for static methods.. + JUCE_DECLARE_NON_COPYABLE (Decibels); +}; + +#endif // __JUCE_DECIBELS_JUCEHEADER__ +/*** End of inlined file: juce_Decibels.h ***/ + + #endif #ifndef __JUCE_IIRFILTER_JUCEHEADER__ diff --git a/src/audio/audio_file_formats/juce_AudioThumbnail.cpp b/src/audio/audio_file_formats/juce_AudioThumbnail.cpp index 5d3bf6f4f0..c16f1f7a07 100644 --- a/src/audio/audio_file_formats/juce_AudioThumbnail.cpp +++ b/src/audio/audio_file_formats/juce_AudioThumbnail.cpp @@ -29,6 +29,7 @@ BEGIN_JUCE_NAMESPACE #include "juce_AudioThumbnail.h" #include "juce_AudioThumbnailCache.h" +#include "../../events/juce_MessageManager.h" //============================================================================== @@ -582,8 +583,10 @@ void AudioThumbnail::saveTo (OutputStream& output) const } //============================================================================== -void AudioThumbnail::setDataSource (LevelDataSource* newSource) +bool AudioThumbnail::setDataSource (LevelDataSource* newSource) { + jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); + numSamplesFinished = 0; if (cache.loadThumb (*this, newSource->hashCode) && isFullyLoaded()) @@ -608,14 +611,15 @@ void AudioThumbnail::setDataSource (LevelDataSource* newSource) createChannels (1 + (int) (totalSamples / samplesPerThumbSample)); } + + return sampleRate > 0 && totalSamples > 0; } -void AudioThumbnail::setSource (InputSource* const newSource) +bool AudioThumbnail::setSource (InputSource* const newSource) { clear(); - if (newSource != 0) - setDataSource (new LevelDataSource (*this, newSource)); + return newSource != 0 && setDataSource (new LevelDataSource (*this, newSource)); } void AudioThumbnail::setReader (AudioFormatReader* newReader, int64 hash) @@ -626,6 +630,11 @@ void AudioThumbnail::setReader (AudioFormatReader* newReader, int64 hash) setDataSource (new LevelDataSource (*this, newReader, hash)); } +int64 AudioThumbnail::getHashCode() const +{ + return source == 0 ? 0 : source->hashCode; +} + void AudioThumbnail::addBlock (const int64 startSample, const AudioSampleBuffer& incoming, int startOffsetInBuffer, int numSamples) { diff --git a/src/audio/audio_file_formats/juce_AudioThumbnail.h b/src/audio/audio_file_formats/juce_AudioThumbnail.h index 8b680bc2e9..4a18a4b690 100644 --- a/src/audio/audio_file_formats/juce_AudioThumbnail.h +++ b/src/audio/audio_file_formats/juce_AudioThumbnail.h @@ -91,11 +91,11 @@ public: @endcode You can pass a zero in here to clear the thumbnail. - - The source that is passed in will be deleted by this object when it is no - longer needed + The source that is passed in will be deleted by this object when it is no longer needed. + @returns true if the source could be opened as a valid audio file, false if this failed for + some reason. */ - void setSource (InputSource* newSource); + bool setSource (InputSource* newSource); /** Gives the thumbnail an AudioFormatReader to use directly. This will start parsing the audio in a background thread (unless the hash code @@ -177,6 +177,8 @@ public: /** Returns true if the low res preview is fully generated. */ bool isFullyLoaded() const throw(); + /** Returns the hash code that was set by setSource() or setReader(). */ + int64 getHashCode() const; // (this is only public to avoid a VC6 bug) class LevelDataSource; @@ -207,7 +209,7 @@ private: double sampleRate; CriticalSection lock; - void setDataSource (LevelDataSource* newSource); + bool setDataSource (LevelDataSource* newSource); void setLevels (const MinMaxValue* const* values, int thumbIndex, int numChans, int numValues); void createChannels (int length); diff --git a/src/audio/dsp/juce_Decibels.h b/src/audio/dsp/juce_Decibels.h new file mode 100644 index 0000000000..758008c1e3 --- /dev/null +++ b/src/audio/dsp/juce_Decibels.h @@ -0,0 +1,104 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-10 by Raw Material Software Ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the GNU General + Public License (Version 2), as published by the Free Software Foundation. + A copy of the license is included in the JUCE distribution, or can be found + online at www.gnu.org/licenses. + + JUCE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + ------------------------------------------------------------------------------ + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.rawmaterialsoftware.com/juce for more information. + + ============================================================================== +*/ + +#ifndef __JUCE_DECIBELS_JUCEHEADER__ +#define __JUCE_DECIBELS_JUCEHEADER__ + +//============================================================================== +/** + This class contains some helpful static methods for dealing with decibel values. +*/ +class Decibels +{ +public: + //============================================================================== + /** Converts a dBFS value to its equivalent gain level. + + A gain of 1.0 = 0 dB, and lower gains map onto negative decibel values. Any + decibel value lower than minusInfinityDb will return a gain of 0. + */ + template + static Type decibelsToGain (const Type decibels, + const Type minusInfinityDb = (Type) defaultMinusInfinitydB) + { + return decibels > minusInfinityDb ? powf ((Type) 10.0, decibels * (Type) 0.05) + : Type(); + } + + /** Converts a gain level into a dBFS value. + + A gain of 1.0 = 0 dB, and lower gains map onto negative decibel values. + If the gain is 0 (or negative), then the method will return the value + provided as minusInfinityDb. + */ + template + static Type gainToDecibels (const Type gain, + const Type minusInfinityDb = (Type) defaultMinusInfinitydB) + { + return gain > Type() ? jmax (minusInfinityDb, (Type) std::log (gain) * (Type) 20.0) + : minusInfinityDb; + } + + //============================================================================== + /** Converts a decibel reading to a string, with the 'dB' suffix. + If the decibel value is lower than minusInfinityDb, the return value will + be "-INF dB". + */ + template + static const String toString (const Type decibels, + const int decimalPlaces = 2, + const Type minusInfinityDb = (Type) defaultMinusInfinitydB) + { + String s; + + if (decibels <= minusInfinityDb) + { + s = "-INF dB"; + } + else + { + if (decibels >= Type()) + s << '+'; + + s << String (decibels, decimalPlaces) << " dB"; + } + + return s; + } + + +private: + //============================================================================== + enum + { + defaultMinusInfinitydB = -100 + }; + + Decibels(); // This class can't be instantiated, it's just a holder for static methods.. + JUCE_DECLARE_NON_COPYABLE (Decibels); +}; + + +#endif // __JUCE_DECIBELS_JUCEHEADER__ diff --git a/src/core/juce_Time.h b/src/core/juce_Time.h index 42f2311fc4..55f91c1cd9 100644 --- a/src/core/juce_Time.h +++ b/src/core/juce_Time.h @@ -314,19 +314,20 @@ public: */ static int64 currentTimeMillis() throw(); - /** Returns the number of millisecs since system startup. + /** Returns the number of millisecs since a fixed event (usually system startup). - Should be accurate to within a few millisecs, depending on platform, + This returns a monotonically increasing value which it unaffected by changes to the + system clock. It should be accurate to within a few millisecs, depending on platform, hardware, etc. @see getApproximateMillisecondCounter */ static uint32 getMillisecondCounter() throw(); - /** Returns the number of millisecs since system startup. + /** Returns the number of millisecs since a fixed event (usually system startup). - Same as getMillisecondCounter(), but returns a more accurate value, using - the high-res timer. + This has the same function as getMillisecondCounter(), but returns a more accurate + value, using a higher-resolution timer if one is available. @see getMillisecondCounter */ diff --git a/src/gui/graphics/geometry/juce_Path.h b/src/gui/graphics/geometry/juce_Path.h index 8f4939e599..e2ade518de 100644 --- a/src/gui/graphics/geometry/juce_Path.h +++ b/src/gui/graphics/geometry/juce_Path.h @@ -307,19 +307,13 @@ public: //============================================================================== /** Adds a rectangle to the path. - - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). - + The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRoundedRectangle, addTriangle */ void addRectangle (float x, float y, float width, float height); /** Adds a rectangle to the path. - - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). - + The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRoundedRectangle, addTriangle */ template @@ -330,30 +324,45 @@ public: } /** Adds a rectangle with rounded corners to the path. - - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). - + The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRectangle, addTriangle */ void addRoundedRectangle (float x, float y, float width, float height, float cornerSize); /** Adds a rectangle with rounded corners to the path. - - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). - + The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRectangle, addTriangle */ void addRoundedRectangle (float x, float y, float width, float height, float cornerSizeX, float cornerSizeY); + /** Adds a rectangle with rounded corners to the path. + The rectangle is added as a new sub-path. (Any currently open paths will be left open). + @see addRectangle, addTriangle + */ + template + void addRoundedRectangle (const Rectangle& rectangle, float cornerSizeX, float cornerSizeY) + { + addRoundedRectangle (static_cast (rectangle.getX()), static_cast (rectangle.getY()), + static_cast (rectangle.getWidth()), static_cast (rectangle.getHeight()), + cornerSizeX, cornerSizeY); + } + + /** Adds a rectangle with rounded corners to the path. + The rectangle is added as a new sub-path. (Any currently open paths will be left open). + @see addRectangle, addTriangle + */ + template + void addRoundedRectangle (const Rectangle& rectangle, float cornerSize) + { + addRoundedRectangle (rectangle, cornerSize, cornerSize); + } + /** Adds a triangle to the path. - The triangle is added as a new closed sub-path. (Any currently open paths will be - left open). + The triangle is added as a new closed sub-path. (Any currently open paths will be left open). Note that whether the vertices are specified in clockwise or anticlockwise order will affect how the triangle is filled when it overlaps other @@ -365,8 +374,7 @@ public: /** Adds a quadrilateral to the path. - The quad is added as a new closed sub-path. (Any currently open paths will be - left open). + The quad is added as a new closed sub-path. (Any currently open paths will be left open). Note that whether the vertices are specified in clockwise or anticlockwise order will affect how the quad is filled when it overlaps other @@ -379,8 +387,7 @@ public: /** Adds an ellipse to the path. - The shape is added as a new sub-path. (Any currently open paths will be - left open). + The shape is added as a new sub-path. (Any currently open paths will be left open). @see addArc */ diff --git a/src/gui/graphics/geometry/juce_Rectangle.h b/src/gui/graphics/geometry/juce_Rectangle.h index 2684a10065..93d6b8ddbe 100644 --- a/src/gui/graphics/geometry/juce_Rectangle.h +++ b/src/gui/graphics/geometry/juce_Rectangle.h @@ -621,8 +621,8 @@ public: { const int x1 = (int) std::floor (static_cast (x)); const int y1 = (int) std::floor (static_cast (y)); - const int x2 = (int) std::floor (static_cast (x + w + 0.9999f)); - const int y2 = (int) std::floor (static_cast (y + h + 0.9999f)); + const int x2 = (int) std::ceil (static_cast (x + w)); + const int y2 = (int) std::ceil (static_cast (y + h)); return Rectangle (x1, y1, x2 - x1, y2 - y1); } diff --git a/src/io/streams/juce_FileInputSource.cpp b/src/io/streams/juce_FileInputSource.cpp index f85550c540..4596cf26e5 100644 --- a/src/io/streams/juce_FileInputSource.cpp +++ b/src/io/streams/juce_FileInputSource.cpp @@ -32,8 +32,8 @@ BEGIN_JUCE_NAMESPACE //============================================================================== -FileInputSource::FileInputSource (const File& file_) - : file (file_) +FileInputSource::FileInputSource (const File& file_, bool useFileTimeInHashGeneration_) + : file (file_), useFileTimeInHashGeneration (useFileTimeInHashGeneration_) { } @@ -53,7 +53,12 @@ InputStream* FileInputSource::createInputStreamFor (const String& relatedItemPat int64 FileInputSource::hashCode() const { - return file.hashCode(); + int64 h = file.hashCode(); + + if (useFileTimeInHashGeneration) + h ^= file.getLastModificationTime().toMilliseconds(); + + return h; } diff --git a/src/io/streams/juce_FileInputSource.h b/src/io/streams/juce_FileInputSource.h index 8cb1e4e023..e82e0788fb 100644 --- a/src/io/streams/juce_FileInputSource.h +++ b/src/io/streams/juce_FileInputSource.h @@ -40,7 +40,7 @@ class JUCE_API FileInputSource : public InputSource { public: //============================================================================== - FileInputSource (const File& file); + FileInputSource (const File& file, bool useFileTimeInHashGeneration = false); ~FileInputSource(); InputStream* createInputStream(); @@ -50,6 +50,7 @@ public: private: //============================================================================== const File file; + bool useFileTimeInHashGeneration; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputSource); }; diff --git a/src/juce_app_includes.h b/src/juce_app_includes.h index 9a7aa5213d..7f3eb7db63 100644 --- a/src/juce_app_includes.h +++ b/src/juce_app_includes.h @@ -140,6 +140,9 @@ #ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ #include "audio/dsp/juce_AudioSampleBuffer.h" #endif +#ifndef __JUCE_DECIBELS_JUCEHEADER__ + #include "audio/dsp/juce_Decibels.h" +#endif #ifndef __JUCE_IIRFILTER_JUCEHEADER__ #include "audio/dsp/juce_IIRFilter.h" #endif diff --git a/src/native/linux/juce_linux_SystemStats.cpp b/src/native/linux/juce_linux_SystemStats.cpp index bb8ae0c268..8a3bdf3fcb 100644 --- a/src/native/linux/juce_linux_SystemStats.cpp +++ b/src/native/linux/juce_linux_SystemStats.cpp @@ -69,27 +69,6 @@ namespace LinuxStatsHelpers return String::empty; } - - bool getTimeSinceStartup (timeval* const t) throw() - { - if (gettimeofday (t, 0) != 0) - return false; - - static unsigned int calibrate = 0; - static bool calibrated = false; - - if (! calibrated) - { - calibrated = true; - - struct sysinfo sysi; - if (sysinfo (&sysi) == 0) - calibrate = t->tv_sec - sysi.uptime; // Safe to assume system was not brought up earlier than 1970! - } - - t->tv_sec -= calibrate; - return true; - } } const String SystemStats::getCpuVendor() @@ -156,20 +135,18 @@ void PlatformUtilities::fpuReset() //============================================================================== uint32 juce_millisecondsSinceStartup() throw() { - timeval t; - if (LinuxStatsHelpers::getTimeSinceStartup (&t)) - return (uint32) (t.tv_sec * 1000 + (t.tv_usec / 1000)); + timespec t; + clock_gettime (CLOCK_MONOTONIC, &t); - return 0; + return t.tv_sec * 1000 + t.tv_nsec / 1000000; } int64 Time::getHighResolutionTicks() throw() { - timeval t; - if (LinuxStatsHelpers::getTimeSinceStartup (&t)) - return ((int64) t.tv_sec * (int64) 1000000) + (int64) t.tv_usec; + timespec t; + clock_gettime (CLOCK_MONOTONIC, &t); - return 0; + return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / (int64) 1000); } int64 Time::getHighResolutionTicksPerSecond() throw() diff --git a/src/native/windows/juce_win32_SystemStats.cpp b/src/native/windows/juce_win32_SystemStats.cpp index a10fc7a400..3e41e1d779 100644 --- a/src/native/windows/juce_win32_SystemStats.cpp +++ b/src/native/windows/juce_win32_SystemStats.cpp @@ -224,7 +224,7 @@ int64 Time::getHighResolutionTicks() throw() LARGE_INTEGER ticks; QueryPerformanceCounter (&ticks); - const int64 mainCounterAsHiResTicks = (GetTickCount() * hiResTicksPerSecond) / 1000; + const int64 mainCounterAsHiResTicks = (juce_millisecondsSinceStartup() * hiResTicksPerSecond) / 1000; const int64 newOffset = mainCounterAsHiResTicks - ticks.QuadPart; // fix for a very obscure PCI hardware bug that can make the counter diff --git a/src/text/juce_String.cpp b/src/text/juce_String.cpp index 7613696001..6bb203e78e 100644 --- a/src/text/juce_String.cpp +++ b/src/text/juce_String.cpp @@ -212,12 +212,14 @@ String& String::operator= (const String& other) throw() { juce_wchar* const newText = other.text; StringHolder::retain (newText); - StringHolder::release (reinterpret_cast *> (&text)->exchange (newText)); + StringHolder::release (reinterpret_cast &> (text).exchange (newText)); return *this; } -String::String (const size_t numChars, const int /*dummyVariable*/) - : text (StringHolder::createUninitialised (numChars)) +inline String::Preallocation::Preallocation (const size_t numChars_) : numChars (numChars_) {} + +String::String (const Preallocation& preallocationSize) + : text (StringHolder::createUninitialised (preallocationSize.numChars)) { } @@ -272,7 +274,7 @@ String::String (const juce_wchar* const t, const size_t maxChars) const String String::charToString (const juce_wchar character) { - String result ((size_t) 1, (int) 0); + String result (Preallocation (1)); result.text[0] = character; result.text[1] = 0; return result; @@ -1104,7 +1106,7 @@ bool String::matchesWildcard (const String& wildcard, const bool ignoreCase) con const String String::repeatedString (const String& stringToRepeat, int numberOfTimesToRepeat) { const int len = stringToRepeat.length(); - String result ((size_t) (len * numberOfTimesToRepeat + 1), (int) 0); + String result (Preallocation (len * numberOfTimesToRepeat + 1)); juce_wchar* n = result.text; *n = 0; @@ -1125,7 +1127,7 @@ const String String::paddedLeft (const juce_wchar padCharacter, int minimumLengt if (len >= minimumLength || padCharacter == 0) return *this; - String result ((size_t) minimumLength + 1, (int) 0); + String result (Preallocation (minimumLength + 1)); juce_wchar* n = result.text; minimumLength -= len; @@ -1192,7 +1194,7 @@ const String String::replaceSection (int index, int numCharsToReplace, const Str if (newTotalLen <= 0) return String::empty; - String result ((size_t) newTotalLen, (int) 0); + String result (Preallocation ((size_t) newTotalLen)); StringHolder::copyChars (result.text, text, index); @@ -1566,7 +1568,7 @@ const String String::retainCharacters (const String& charactersToRetain) const if (isEmpty()) return empty; - String result (StringHolder::getAllocatedNumChars (text), (int) 0); + String result (Preallocation (StringHolder::getAllocatedNumChars (text))); juce_wchar* dst = result.text; const juce_wchar* src = text; @@ -1587,7 +1589,7 @@ const String String::removeCharacters (const String& charactersToRemove) const if (isEmpty()) return empty; - String result (StringHolder::getAllocatedNumChars (text), (int) 0); + String result (Preallocation (StringHolder::getAllocatedNumChars (text))); juce_wchar* dst = result.text; const juce_wchar* src = text; @@ -1675,7 +1677,7 @@ const String String::formatted (const juce_wchar* const pf, ... ) va_start (args, pf); size_t bufferSize = 256; - String result (bufferSize, (int) 0); + String result (Preallocation ((size_t) bufferSize)); result.text[0] = 0; for (;;) @@ -1801,9 +1803,7 @@ const String String::toHexString (const short number) return toHexString ((int) (unsigned short) number); } -const String String::toHexString (const unsigned char* data, - const int size, - const int groupSize) +const String String::toHexString (const unsigned char* data, const int size, const int groupSize) { if (size <= 0) return empty; @@ -1812,7 +1812,7 @@ const String String::toHexString (const unsigned char* data, if (groupSize > 0) numChars += size / groupSize; - String s ((size_t) numChars, (int) 0); + String s (Preallocation ((size_t) numChars)); juce_wchar* d = s.text; @@ -2067,7 +2067,7 @@ const String String::fromUTF8 (const char* const buffer, int bufferSizeBytes) if (buffer [numBytes] == 0) break; - String result ((size_t) numBytes + 1, (int) 0); + String result (Preallocation (numBytes + 1)); juce_wchar* dest = result.text; size_t i = 0; diff --git a/src/text/juce_String.h b/src/text/juce_String.h index 2e876d5b49..19aff2aa5b 100644 --- a/src/text/juce_String.h +++ b/src/text/juce_String.h @@ -1042,8 +1042,14 @@ private: juce_wchar* text; //============================================================================== - // internal constructor that preallocates a certain amount of memory - String (size_t numChars, int dummyVariable); + struct Preallocation + { + explicit Preallocation (size_t); + size_t numChars; + }; + + // This constructor preallocates a certain amount of memory + explicit String (const Preallocation&); String (const String& stringToCopy, size_t charsToAllocate); void createInternal (const juce_wchar* text, size_t numChars);