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