PageRenderTime 105ms CodeModel.GetById 40ms app.highlight 33ms RepoModel.GetById 27ms app.codeStats 1ms

/thirdparty/liblastfm2/src/fingerprint/fplib/fp_helper_fun.h

http://github.com/tomahawk-player/tomahawk
C++ Header | 443 lines | 299 code | 84 blank | 60 comment | 64 complexity | b3db8e0f82575800ce3173804b9c726c MD5 | raw file
  1/*
  2   Copyright 2005-2009 Last.fm Ltd. <mir@last.fm>
  3
  4   This file is part of liblastfm.
  5
  6   liblastfm is free software: you can redistribute it and/or modify
  7   it under the terms of the GNU General Public License as published by
  8   the Free Software Foundation, either version 3 of the License, or
  9   (at your option) any later version.
 10
 11   liblastfm is distributed in the hope that it will be useful,
 12   but WITHOUT ANY WARRANTY; without even the implied warranty of
 13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14   GNU General Public License for more details.
 15
 16   You should have received a copy of the GNU General Public License
 17   along with liblastfm.  If not, see <http://www.gnu.org/licenses/>.
 18*/
 19#ifndef __FINGERPRINT_HELPER_FUNCTIONS_H
 20#define __FINGERPRINT_HELPER_FUNCTIONS_H
 21
 22#include <vector>
 23#include <deque>
 24#include <set>
 25
 26namespace fingerprint
 27{
 28
 29// -----------------------------------------------------------------------------
 30
 31static const size_t FINGERPRINT_LIB_VERSION = 1;
 32static const float  QUERY_START_SECS = 20;
 33static const float  QUERY_SIZE_SECS = 14;
 34static const float  UPDATE_SIZE_SECS = 10;
 35//FFT needs also a buffer that depends on the input freq. 3 secs should be enough up to 48Khz 
 36static const float  GUARD_SIZE_SECS = 3; 
 37static const float  NORMALIZATION_SKIP_SECS = 2.5;
 38static const int    MIN_UNIQUE_KEYS = 75;
 39static const unsigned int MAX_GOOD_GROUP_SIZE = 200;
 40static const int    SHA_SIZE = 32;
 41
 42/////////////////////////////////////////////////////
 43// For FFT. DO NOT TOUCH THEM!
 44// number of samples in a frame
 45static const int FRAMESIZE = 2048;
 46static const int OVERLAP = 32;
 47static const int OVERLAPSAMPLES = (FRAMESIZE/OVERLAP); // 64
 48
 49// down-sampled frequency
 50static const int DFREQ = 5512;
 51static const float FDFREQ = 5512.5f;
 52
 53// -----------------------------------------------------------------------------
 54
 55struct GroupData
 56{
 57   unsigned int key;    // the key (or local descriptor)
 58   unsigned int count;  // the number of frames sharing this key
 59};
 60
 61// -----------------------------------------------------------------------------
 62// -----------------------------------------------------------------------------
 63
 64inline 
 65unsigned int getTotalKeys( 
 66   int mSecs )
 67{
 68   return static_cast<unsigned int>((static_cast<double>(mSecs) / (1000.0 * OVERLAPSAMPLES) ) * DFREQ ) + 1;
 69}
 70
 71// -----------------------------------------------------------------------------
 72
 73template <typename GroupDataIt>
 74void simpleSkip( 
 75   GroupDataIt& begIt, const GroupDataIt& endIt,
 76   unsigned int numSkipKeys )
 77{
 78   if ( numSkipKeys <= 0 )
 79      return;
 80
 81   unsigned int nKeys;
 82   for ( nKeys = 0; nKeys < numSkipKeys && begIt != endIt; ++begIt )
 83      nKeys += begIt->count;
 84
 85   // clear crop at the end
 86   if ( nKeys > numSkipKeys )
 87   {
 88      --begIt;
 89      begIt->count = nKeys - numSkipKeys;
 90   }
 91
 92}
 93
 94// -----------------------------------------------------------------------------
 95
 96template <typename TGroupData>
 97void cutGroups( 
 98   std::vector<TGroupData>& groups, 
 99   const unsigned int startMS, 
100   const unsigned int lengthMS )
101{
102   typename  std::vector<TGroupData>::iterator itBeg = groups.begin(), itEnd = groups.begin();
103
104   unsigned int keys_begin, keys_end;
105
106   for (keys_begin = getTotalKeys(startMS);
107                  itBeg != groups.end() && keys_begin > itBeg->count; ++itBeg)
108      keys_begin -= itBeg->count;
109
110   for (keys_end = getTotalKeys(startMS + lengthMS);
111        itEnd != groups.end() && keys_end > itEnd->count; ++itEnd)
112      keys_end -= itEnd->count;
113
114   if (itBeg == groups.end())  // in the umpossible scenario that you try to cut past the size of the groups
115   {
116      groups.clear();
117      return;
118   }
119
120   itBeg->count -= keys_begin;
121   if (keys_end > 0 && itEnd != groups.end())
122   {
123      itEnd->count = keys_end;
124      ++itEnd;
125   }
126
127   copy(itBeg, itEnd, groups.begin());
128   groups.resize(itEnd - itBeg);
129
130   keys_begin = getTotalKeys(lengthMS);
131   for (typename std::vector<TGroupData>::iterator it = groups.begin(); it != groups.end(); ++it)
132      keys_begin -= it->count;
133}
134
135// -------------------------------------------------------------------------
136
137template <typename TGroupData>
138void keys2GroupData( 
139   const std::vector<unsigned int>& keys, // in
140   std::vector<TGroupData>& groupData,
141   bool clearDst = true ) // out
142{
143   if (clearDst)
144      groupData.clear();
145
146   if (keys.empty())
147      return;
148
149   TGroupData tmpGroup;
150   std::vector<unsigned int>::const_iterator it = keys.begin();
151
152   if ( !groupData.empty() )
153   {
154      // get the last group 
155      tmpGroup = groupData.back();
156      groupData.pop_back();
157   }
158   else
159   {
160      // new group!
161      tmpGroup.key = *it;
162      tmpGroup.count = 1;
163      ++it; // move to the next key
164   }
165
166   for (; it != keys.end(); ++it)
167   {
168      if ( *it != tmpGroup.key )
169      {
170         // new group ready!
171         groupData.push_back( tmpGroup );
172         tmpGroup.key = *it;
173         tmpGroup.count = 0;
174      }
175
176      ++tmpGroup.count;
177   }
178
179   // last group
180   groupData.push_back( tmpGroup );
181}
182
183// -------------------------------------------------------------------------
184
185template <typename TGroupData>
186void keys2GroupData( 
187   const std::vector<unsigned int>& keys, // in
188   std::deque<TGroupData>& groupData,
189   bool clearDst = true ) // out
190{
191   if (clearDst)
192      groupData.clear();
193
194   if (keys.empty())
195      return;
196
197   TGroupData tmpGroup;
198   std::vector<unsigned int>::const_iterator it = keys.begin();
199
200   if ( !groupData.empty() )
201   {
202      // get the last group 
203      tmpGroup = groupData.back();
204      groupData.pop_back();
205   }
206   else
207   {
208      // new group!
209      tmpGroup.key = *it;
210      tmpGroup.count = 1;
211      ++it; // move to the next key
212   }
213
214   for (; it != keys.end(); ++it)
215   {
216      if ( *it != tmpGroup.key )
217      {
218         // new group ready!
219         groupData.push_back( tmpGroup );
220         tmpGroup.key = *it;
221         tmpGroup.count = 0;
222      }
223
224      ++tmpGroup.count;
225   }
226
227   // last group
228   groupData.push_back( tmpGroup );
229}
230
231// -------------------------------------------------------------------------
232
233template <typename TGroupData>
234inline 
235void groupData2Keys( 
236   const std::vector<TGroupData>& groupData, // in
237   std::vector<unsigned int>& keys ) // out
238{
239   keys.clear();
240
241   typename std::vector<TGroupData>::const_iterator it;
242   
243   for (it = groupData.begin(); it != groupData.end(); ++it)
244   {
245      for (unsigned int j = 0; j < it->count; ++j)
246         keys.push_back(it->key);
247   }
248}
249
250// -------------------------------------------------------------------------
251
252template <typename GroupDataIt>
253bool findSignificantGroups(
254   GroupDataIt& beg, GroupDataIt& end, unsigned int& offset_left, unsigned int& offset_right,
255   unsigned int windowKeySize, unsigned int subWindowKeySize, unsigned int minUniqueKeys)
256{
257   GroupDataIt itBeg = beg, itEnd = beg, itWindowBeg = beg, itWindowEnd = beg;
258
259   offset_left = 0;
260   unsigned int window_offset_left;
261   unsigned int window_offset_right;
262
263   // this amounts to around a 500 ms hop for, say, a 20 second sub-window
264   unsigned int key_hop_size = subWindowKeySize / 40;  
265
266   // trail out itEnd
267   for (offset_right = windowKeySize; itEnd != end && offset_right > itEnd->count; ++itEnd)
268      offset_right -= itEnd->count;
269
270   // dang man, we don't even have enough groups to span the window size
271   if (itEnd == end && offset_right > 0)
272      return false;
273
274   // 0 window size means just scan the whole range
275   if (windowKeySize == 0)
276      itEnd = end;
277
278   // trail out itWindowBeg
279   for (window_offset_left = (windowKeySize - subWindowKeySize) / 2;
280        window_offset_left > itWindowBeg->count; ++itWindowBeg)
281      window_offset_left -= itWindowBeg->count;
282
283   // trail out itWindowEnd
284   for (window_offset_right = (windowKeySize + subWindowKeySize) / 2;
285      window_offset_right > itWindowEnd->count; ++itWindowEnd)
286      window_offset_right -= itWindowEnd->count;
287
288   while (itEnd != end)
289   {
290      if (enoughUniqueGoodGroups(itWindowBeg, itWindowEnd, minUniqueKeys))
291      {
292         beg = itBeg;
293         end = itEnd;
294         return true;
295      }
296
297      // okay, jump key_hop_size on end iterator
298      for (offset_right += key_hop_size; itEnd != end && offset_right > itEnd->count; ++itEnd)
299         offset_right -= itEnd->count;
300
301      // if we didn't hop the full hop size, modify the hop size to only hop as far as we hopped
302      if (itEnd == end)
303         key_hop_size -= offset_right;
304
305      for (offset_left += key_hop_size; offset_left > itBeg->count; ++itBeg)
306         offset_left -= itBeg->count;
307      for (window_offset_right += key_hop_size; window_offset_right > itWindowEnd->count; ++itWindowEnd)
308         window_offset_right -= itWindowEnd->count;
309      for (window_offset_left += key_hop_size; window_offset_left > itWindowBeg->count; ++itWindowBeg)
310         window_offset_left -= itWindowBeg->count;
311   }
312
313   beg = itBeg;
314   end = itEnd;
315
316   return enoughUniqueGoodGroups(itWindowBeg, itWindowEnd, minUniqueKeys);
317}
318
319// -----------------------------------------------------------------------------
320
321template <typename TGroupData>
322bool
323reduceGroups( 
324  std::vector<TGroupData>& groups, unsigned int startKeySize,
325  unsigned int windowKeySize, unsigned int subWindowKeySize, unsigned int minUniqueKeys )
326{
327   unsigned int offset_left = 0;
328   unsigned int offset_right = 0;
329
330   typename std::vector<TGroupData>::iterator begIt = groups.begin();
331   typename std::vector<TGroupData>::iterator endIt = groups.end();
332
333   simpleSkip(begIt, endIt, startKeySize);
334   bool result = findSignificantGroups( begIt, endIt, 
335      offset_left, offset_right, 
336      windowKeySize, subWindowKeySize, minUniqueKeys );
337
338   if ( !result )
339   {
340      groups.clear();
341      return false;
342   }
343
344   begIt->count -= offset_left;
345   if (offset_right > 0 && endIt != groups.end())
346   {
347      endIt->count = offset_right;
348      ++endIt;
349   }
350
351   std::vector<TGroupData> resGrups(begIt, endIt);
352   groups.swap(resGrups);
353
354   return true;
355}
356
357
358// -------------------------------------------------------------------------
359
360template <typename GroupDataIt>
361inline bool enoughUniqueGoodGroups(
362   const GroupDataIt& beg, 
363   const GroupDataIt& end, 
364   unsigned int minUniqueKeys)
365{
366   std::set<unsigned int> groupKeys;
367
368   for (GroupDataIt it = beg; it != end && static_cast<unsigned int>(groupKeys.size()) < minUniqueKeys; ++it)
369   {
370      if (it->count > MAX_GOOD_GROUP_SIZE)
371         return false;
372
373      groupKeys.insert(it->key);
374   }
375   
376   return static_cast<unsigned int>(groupKeys.size()) >= minUniqueKeys;
377}
378
379// -----------------------------------------------------------------------------
380//////////////////////////////////////////////////////////////////////////
381//////////////////////////////////////////////////////////////////////////
382// Used by the fingerprint keys operation
383
384// minimum and maximum frequency to consider
385#define MINFREQ 300
386#define MAXFREQ 2000
387
388// amount of time in a frame
389#define FRAME_TLEN ((float) FRAMESIZE / (float) DFREQ)
390#define MINCOEF (FRAME_TLEN * MINFREQ)
391
392#define round__(x)  ((int)(x + .5))
393
394struct RawFilter
395{
396   unsigned int ftid;
397   float thresh;
398    float weight;
399};
400
401const RawFilter rFilters[] = {
402   { 26752, -4.37515e-07f, 0.260836f }, // filterID, threshold, alpha (weight)
403   { 23871, -2.44615e-05f, 0.263986f },
404   { 26777, -3.69244e-08f, 0.267763f },
405   { 4635,  -1.13672e-05f, 0.269428f },
406   { 2937,   5.28804e-09f, 0.271896f },
407   { 27405, -0.000126494f, 0.272362f },
408   { 10782,  4.27478e-08f, 0.272609f },
409   { 21033, -6.7912e-07f,  0.276099f },
410   { 27117,  8.07178e-06f, 0.277762f },
411   { 27072,  2.46044e-05f, 0.27883f  },
412   { 24228,  4.11255e-07f, 0.281743f },
413   { 23838,  0.000228396f, 0.284479f },
414   { 17165, -1.19495e-07f, 0.286304f },
415   { 25263,  0.000398279f, 0.287066f },
416   { 20721,  7.15095e-07f, 0.288913f },
417   { 8502,  -2.78361e-07f, 0.290424f },
418   { 17175, -1.08429e-08f, 0.292219f },
419   { 17811, -3.29527e-08f, 0.292554f },
420   { 27495, -4.47575e-07f, 0.290119f },
421   { 23538, -3.04273e-09f, 0.294539f },
422   { 8205,   4.02691e-07f, 0.293525f },
423   { 12177,  1.16873e-06f, 0.293832f },
424   { 27051, -0.000902544f, 0.296453f },
425   { 27111, -2.38425e-05f, 0.297428f },
426   { 21779, -1.0669e-07f,  0.297302f },
427   { 14817, -9.52849e-09f, 0.299f    },
428   { 27087,  1.22163e-05f, 0.296502f },
429   { 27081, -2.8758e-09f,  0.300112f },
430   { 20394,  1.28237e-06f, 0.298693f },
431   { 28209,  0.000624447f, 0.29812f  },
432   { 23533, -2.19406e-06f, 0.299773f },
433   { 23865, -1.28037e-08f, 0.300777f } // this is iteration 1
434};
435
436// -----------------------------------------------------------------------------
437
438}
439
440// -----------------------------------------------------------------------------
441
442#endif // __FINGERPRINT_HELPER_FUNCTIONS_H
443