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