You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
4.4 KiB

  1. /**********************************************************************************
  2. *
  3. * Copyright (C) 2017 MuK IT GmbH
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. **********************************************************************************/
  19. window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
  20. function Visualizer($audio, $container, $canvas) {
  21. var _this = this;
  22. this.$audio = $audio;
  23. this.$container = $container;
  24. this.$canvas = $canvas;
  25. this.audio = $audio.get(0);
  26. this.canvas = $canvas.get(0);
  27. this.audioCtx = new AudioContext();
  28. this.analyser = this.audioCtx.createAnalyser();
  29. this.audioSrc = this.audioCtx.createMediaElementSource(this.audio);
  30. this.frequencyData = new Uint8Array(this.analyser.frequencyBinCount);
  31. this.smoothEndingCounter = 0;
  32. this.audioSrc.connect(this.analyser);
  33. this.analyser.connect(this.audioCtx.destination);
  34. this.ctx = this.canvas.getContext('2d'),
  35. this.capYPositionArray = [];
  36. this.$audio.bind('play', function (e) {
  37. _this.smoothEndingCounter = 0;
  38. _this.calcCanvas();
  39. _this.renderFrame();
  40. });
  41. this.map = function (num, in_min, in_max, out_min, out_max) {
  42. return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  43. }
  44. this.calcCanvas = function() {
  45. _this.canvas.width = _this.$container.width() !== 0 ? _this.$container.width() : 200;
  46. _this.canvas.height = _this.$container.height() !== 0 ? _this.$container.height() : 100;
  47. _this.cwidth = _this.canvas.width;
  48. _this.cheight = _this.canvas.height - 4;
  49. _this.meterWidth = 10;
  50. _this.capHeight = 4;
  51. _this.capStyle = '#FFF';
  52. _this.meterNum = (_this.$container.width() !== 0 ? _this.$container.width() : 650) / (10 + 2);
  53. _this.gradient = _this.ctx.createLinearGradient(0, 0, 0, _this.cheight);
  54. _this.gradient.addColorStop(1, '#1CD5FB');
  55. _this.gradient.addColorStop(0.75, '#19DECA');
  56. _this.gradient.addColorStop(0.5, '#28F5A6');
  57. _this.gradient.addColorStop(0.25, '#19DE5A');
  58. _this.gradient.addColorStop(0, '#1CFB27');
  59. }
  60. this.renderFrame = function() {
  61. if(_this.$container.width() !== _this.cwidth) {
  62. _this.calcCanvas();
  63. }
  64. _this.ctx.clearRect(0, 0, _this.cwidth, _this.cheight);
  65. _this.analyser.getByteFrequencyData(_this.frequencyData);
  66. var step = Math.round(_this.frequencyData.length / _this.meterNum);
  67. for (var i = 0; i < _this.meterNum; i++) {
  68. var valueBar = _this.map(_this.frequencyData[i * step], 0, 255, 0, _this.cheight);
  69. var valueCap = _this.map(_this.frequencyData[i * step], 0, 255, 0, _this.canvas.height);
  70. if (_this.capYPositionArray.length < Math.round(_this.meterNum)) {
  71. _this.capYPositionArray.push(valueCap);
  72. };
  73. _this.ctx.fillStyle = _this.gradient;
  74. _this.ctx.fillRect(i * 12, _this.cheight - valueBar, _this.meterWidth, _this.cheight);
  75. _this.ctx.fillStyle = _this.capStyle;
  76. if (valueCap < _this.capYPositionArray[i]) {
  77. _this.ctx.fillRect(i * 12, _this.canvas.height - (--_this.capYPositionArray[i]), _this.meterWidth, _this.capHeight);
  78. } else {
  79. _this.ctx.fillRect(i * 12, _this.canvas.height - valueCap, _this.meterWidth, _this.capHeight);
  80. _this.capYPositionArray[i] = valueCap;
  81. };
  82. }
  83. if(!_this.audio.paused) {
  84. requestAnimationFrame(_this.renderFrame);
  85. } else {
  86. if(_this.smoothEndingCounter < 500) {
  87. requestAnimationFrame(_this.renderFrame);
  88. }
  89. _this.smoothEndingCounter++;
  90. }
  91. }
  92. };