peakcache.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /**
  2. * Caches the decoded peaks data to improve rendering speed for lage audio
  3. *
  4. * Is used if the option parameter `partialRender` is set to `true`
  5. */
  6. export default class PeakCache {
  7. /**
  8. * Instantiate cache
  9. */
  10. constructor() {
  11. this.clearPeakCache();
  12. }
  13. /**
  14. * Empty the cache
  15. */
  16. clearPeakCache() {
  17. /**
  18. * Flat array with entries that are always in pairs to mark the
  19. * beginning and end of each subrange. This is a convenience so we can
  20. * iterate over the pairs for easy set difference operations.
  21. * @private
  22. */
  23. this.peakCacheRanges = [];
  24. /**
  25. * Length of the entire cachable region, used for resetting the cache
  26. * when this changes (zoom events, for instance).
  27. * @private
  28. */
  29. this.peakCacheLength = -1;
  30. }
  31. /**
  32. * Add a range of peaks to the cache
  33. *
  34. * @param {number} length The length of the range
  35. * @param {number} start The x offset of the start of the range
  36. * @param {number} end The x offset of the end of the range
  37. * @return {number[][]}
  38. */
  39. addRangeToPeakCache(length, start, end) {
  40. if (length != this.peakCacheLength) {
  41. this.clearPeakCache();
  42. this.peakCacheLength = length;
  43. }
  44. // Return ranges that weren't in the cache before the call.
  45. let uncachedRanges = [];
  46. let i = 0;
  47. // Skip ranges before the current start.
  48. while (i < this.peakCacheRanges.length && this.peakCacheRanges[i] < start) {
  49. i++;
  50. }
  51. // If |i| is even, |start| falls after an existing range. Otherwise,
  52. // |start| falls between an existing range, and the uncached region
  53. // starts when we encounter the next node in |peakCacheRanges| or
  54. // |end|, whichever comes first.
  55. if (i % 2 == 0) {
  56. uncachedRanges.push(start);
  57. }
  58. while (i < this.peakCacheRanges.length && this.peakCacheRanges[i] <= end) {
  59. uncachedRanges.push(this.peakCacheRanges[i]);
  60. i++;
  61. }
  62. // If |i| is even, |end| is after all existing ranges.
  63. if (i % 2 == 0) {
  64. uncachedRanges.push(end);
  65. }
  66. // Filter out the 0-length ranges.
  67. uncachedRanges = uncachedRanges.filter((item, pos, arr) => {
  68. if (pos == 0) {
  69. return item != arr[pos + 1];
  70. } else if (pos == arr.length - 1) {
  71. return item != arr[pos - 1];
  72. }
  73. return item != arr[pos - 1] && item != arr[pos + 1];
  74. });
  75. // Merge the two ranges together, uncachedRanges will either contain
  76. // wholly new points, or duplicates of points in peakCacheRanges. If
  77. // duplicates are detected, remove both and extend the range.
  78. this.peakCacheRanges = this.peakCacheRanges.concat(uncachedRanges);
  79. this.peakCacheRanges = this.peakCacheRanges.sort((a, b) => a - b).filter((item, pos, arr) => {
  80. if (pos == 0) {
  81. return item != arr[pos + 1];
  82. } else if (pos == arr.length - 1) {
  83. return item != arr[pos - 1];
  84. }
  85. return item != arr[pos - 1] && item != arr[pos + 1];
  86. });
  87. // Push the uncached ranges into an array of arrays for ease of
  88. // iteration in the functions that call this.
  89. const uncachedRangePairs = [];
  90. for (i = 0; i < uncachedRanges.length; i += 2) {
  91. uncachedRangePairs.push([uncachedRanges[i], uncachedRanges[i+1]]);
  92. }
  93. return uncachedRangePairs;
  94. }
  95. /**
  96. * For testing
  97. *
  98. * @return {number[][]}
  99. */
  100. getCacheRanges() {
  101. const peakCacheRangePairs = [];
  102. let i;
  103. for (i = 0; i < this.peakCacheRanges.length; i += 2) {
  104. peakCacheRangePairs.push([this.peakCacheRanges[i], this.peakCacheRanges[i+1]]);
  105. }
  106. return peakCacheRangePairs;
  107. }
  108. }