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