The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
4.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. class AudioThumbnailCache::ThumbnailCacheEntry
  20. {
  21. public:
  22. ThumbnailCacheEntry (const int64 hashCode)
  23. : hash (hashCode),
  24. lastUsed (Time::getMillisecondCounter())
  25. {
  26. }
  27. ThumbnailCacheEntry (InputStream& in)
  28. : hash (in.readInt64()),
  29. lastUsed (0)
  30. {
  31. const int64 len = in.readInt64();
  32. in.readIntoMemoryBlock (data, (ssize_t) len);
  33. }
  34. void write (OutputStream& out)
  35. {
  36. out.writeInt64 (hash);
  37. out.writeInt64 ((int64) data.getSize());
  38. out << data;
  39. }
  40. int64 hash;
  41. uint32 lastUsed;
  42. MemoryBlock data;
  43. private:
  44. JUCE_LEAK_DETECTOR (ThumbnailCacheEntry)
  45. };
  46. //==============================================================================
  47. AudioThumbnailCache::AudioThumbnailCache (const int maxNumThumbs)
  48. : thread ("thumb cache"),
  49. maxNumThumbsToStore (maxNumThumbs)
  50. {
  51. jassert (maxNumThumbsToStore > 0);
  52. thread.startThread (2);
  53. }
  54. AudioThumbnailCache::~AudioThumbnailCache()
  55. {
  56. }
  57. AudioThumbnailCache::ThumbnailCacheEntry* AudioThumbnailCache::findThumbFor (const int64 hash) const
  58. {
  59. for (int i = thumbs.size(); --i >= 0;)
  60. if (thumbs.getUnchecked(i)->hash == hash)
  61. return thumbs.getUnchecked(i);
  62. return nullptr;
  63. }
  64. int AudioThumbnailCache::findOldestThumb() const
  65. {
  66. int oldest = 0;
  67. uint32 oldestTime = Time::getMillisecondCounter() + 1;
  68. for (int i = thumbs.size(); --i >= 0;)
  69. {
  70. const ThumbnailCacheEntry* const te = thumbs.getUnchecked(i);
  71. if (te->lastUsed < oldestTime)
  72. {
  73. oldest = i;
  74. oldestTime = te->lastUsed;
  75. }
  76. }
  77. return oldest;
  78. }
  79. bool AudioThumbnailCache::loadThumb (AudioThumbnailBase& thumb, const int64 hashCode)
  80. {
  81. const ScopedLock sl (lock);
  82. if (ThumbnailCacheEntry* te = findThumbFor (hashCode))
  83. {
  84. te->lastUsed = Time::getMillisecondCounter();
  85. MemoryInputStream in (te->data, false);
  86. thumb.loadFrom (in);
  87. return true;
  88. }
  89. return loadNewThumb (thumb, hashCode);
  90. }
  91. void AudioThumbnailCache::storeThumb (const AudioThumbnailBase& thumb,
  92. const int64 hashCode)
  93. {
  94. const ScopedLock sl (lock);
  95. ThumbnailCacheEntry* te = findThumbFor (hashCode);
  96. if (te == nullptr)
  97. {
  98. te = new ThumbnailCacheEntry (hashCode);
  99. if (thumbs.size() < maxNumThumbsToStore)
  100. thumbs.add (te);
  101. else
  102. thumbs.set (findOldestThumb(), te);
  103. }
  104. {
  105. MemoryOutputStream out (te->data, false);
  106. thumb.saveTo (out);
  107. }
  108. saveNewlyFinishedThumbnail (thumb, hashCode);
  109. }
  110. void AudioThumbnailCache::clear()
  111. {
  112. const ScopedLock sl (lock);
  113. thumbs.clear();
  114. }
  115. void AudioThumbnailCache::removeThumb (const int64 hashCode)
  116. {
  117. const ScopedLock sl (lock);
  118. for (int i = thumbs.size(); --i >= 0;)
  119. if (thumbs.getUnchecked(i)->hash == hashCode)
  120. thumbs.remove (i);
  121. }
  122. static inline int getThumbnailCacheFileMagicHeader() noexcept
  123. {
  124. return (int) ByteOrder::littleEndianInt ("ThmC");
  125. }
  126. bool AudioThumbnailCache::readFromStream (InputStream& source)
  127. {
  128. if (source.readInt() != getThumbnailCacheFileMagicHeader())
  129. return false;
  130. const ScopedLock sl (lock);
  131. clear();
  132. int numThumbnails = jmin (maxNumThumbsToStore, source.readInt());
  133. while (--numThumbnails >= 0 && ! source.isExhausted())
  134. thumbs.add (new ThumbnailCacheEntry (source));
  135. return true;
  136. }
  137. void AudioThumbnailCache::writeToStream (OutputStream& out)
  138. {
  139. const ScopedLock sl (lock);
  140. out.writeInt (getThumbnailCacheFileMagicHeader());
  141. out.writeInt (thumbs.size());
  142. for (int i = 0; i < thumbs.size(); ++i)
  143. thumbs.getUnchecked(i)->write (out);
  144. }
  145. void AudioThumbnailCache::saveNewlyFinishedThumbnail (const AudioThumbnailBase&, int64)
  146. {
  147. }
  148. bool AudioThumbnailCache::loadNewThumb (AudioThumbnailBase&, int64)
  149. {
  150. return false;
  151. }