Audio Visualizer For Youtube

A simple audio visualizer for Youtube.

  1. // ==UserScript==
  2. // @name Audio Visualizer For Youtube
  3. // @namespace https://github.com/MrAnyone/YouTube-Audio-Visualizer
  4. // @version 0.6 BETA
  5. // @description A simple audio visualizer for Youtube.
  6. // @author MrAnyone
  7. // @match https://www.youtube.com/watch?v=*
  8. // @require http://code.jquery.com/jquery-latest.js
  9. // @require https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.10/pixi.min.js
  10. // @grant Thank you very much for the inspiration! https://www.youtube.com/watch?v=okMfwg15lz0
  11. // ==/UserScript==
  12. /* jshint -W097 */
  13. 'use strict';
  14.  
  15. /****************
  16. SETUP VARS
  17. ****************/
  18.  
  19. //Do debug
  20. var doDebug = true;
  21.  
  22. //Used to remove some "dead bars"
  23. var excludeRatio = 33;
  24.  
  25. //Version
  26. var version = "0.6 BETA";
  27.  
  28. /**********************
  29. VISUALIZER VARS
  30. **********************/
  31.  
  32. //Audio handler variables
  33. var audioCtx = null;
  34. var analyser = null;
  35. var dataArray = null;
  36. var source = null;
  37. var $video = null;
  38.  
  39. //Pixi vars
  40. var container = null;
  41. var renderer = null;
  42. var g = null;
  43.  
  44. //Visualization variables
  45. var barWidth = null;
  46. var sizeControl = null;
  47. var i = null;
  48. var playerAPIDiv = null;
  49. var widthConstant = null;
  50. var smoothInput = null;
  51. var smoothPelmt = null;
  52. var smoothCountText = null;
  53.  
  54.  
  55. /****************
  56. FUNCTIONS
  57. ****************/
  58.  
  59. $(document).ready(function() {
  60. init();
  61. setElementSource("video");
  62. setupView();
  63. requestAnimationFrame(animate);
  64. });
  65.  
  66. //Init function
  67. function init() {
  68. try {
  69.  
  70. //Get audio apis from different browsers
  71. if (!(navigator.getUserMedia)) {
  72. navigator.getUserMedia = (navigator.getUserMedia ||
  73. navigator.webkitGetUserMedia ||
  74. navigator.mozGetUserMedia ||
  75. navigator.msGetUserMedia);
  76. }
  77.  
  78. if (!(window.AudioContext)) {
  79. window.AudioContext = window.AudioContext || window.webkitAudioContext;
  80. }
  81.  
  82. //Create the audio context
  83. if (!(audioCtx)) {
  84. audioCtx = new AudioContext();
  85. }
  86.  
  87. //Setup the analyser node
  88. if (!(analyser)) {
  89. analyser = audioCtx.createAnalyser();
  90. analyser.fftSize = 256;
  91. analyser.minDecibels = -80;
  92. analyser.maxDecibels = 0;
  93. analyser.smoothingTimeConstant = 0.8;
  94. }
  95.  
  96. //Generate the dataArray
  97. if (!(dataArray)) {
  98. dataArray = new Uint8Array(analyser.fftSize / 2);
  99. }
  100.  
  101. //Simple function to map values from one range to another
  102. Number.prototype.map = function(in_min, in_max, out_min, out_max) {
  103. return (this - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  104. };
  105.  
  106. debug("Init successfull!", "INFO");
  107. } catch (e) {
  108. alert("Error! Probably your browser doesn't support the Web Audio API!");
  109. debug(e, "ERROR");
  110. }
  111. }
  112.  
  113. //Try to find the video DOM with given ID and create an audio source
  114. function setElementSource(id) {
  115. //Try to find the video
  116. $video = $(id);
  117.  
  118. if ($video) {
  119. //Create audio element
  120. source = audioCtx.createMediaElementSource($video[0]);
  121.  
  122. //Route source to analyser & speakers
  123. source.connect(analyser);
  124. source.connect(audioCtx.destination);
  125.  
  126. debug("setElementSource successfull!", "INFO");
  127. } else {
  128. debug("The video element was not found!", "WARNING");
  129. }
  130. }
  131.  
  132. //Setup the visualizer
  133. function setupView() {
  134. try {
  135. //A div to get the video size
  136. playerAPIDiv = $("#player-api");
  137.  
  138. //Generate "PIXI stuff"
  139. if (!(container || renderer || g)) {
  140. //The container
  141. container = new PIXI.Container(0x66FF99);
  142.  
  143. //The renderer
  144. renderer = PIXI.autoDetectRenderer(playerAPIDiv.width(), playerAPIDiv.height());
  145.  
  146. //Setup the ytav div
  147. $("#player").prepend($("<div>", {
  148. id: "ytav"
  149. }));
  150.  
  151. //Add the view (canvas) of the renderer
  152. $("#ytav").prepend(renderer.view);
  153.  
  154. //Setup ytav-controls
  155. $("#ytav").append($("<div>", {
  156. id: "ytav-controls"
  157. }).css({
  158. float: "right",
  159. width: ($("#ytav").width() - renderer.width) * 0.9 + "px",
  160. margin: "0px"
  161. }));
  162.  
  163. $("#ytav-controls").append($("<div>", {
  164. id: "ytav-title"
  165. }).css({
  166. width: "70%",
  167. margin: "0 0 5% 0"
  168. }));
  169.  
  170. $("#ytav-title").append($("<h1>").text("Youtube Audio Visualizer").css("color", "black"));
  171.  
  172. $("#ytav-title").append($("<p>").text("v. " + version + " By MrAnyone").css({
  173. color: "red",
  174. float: "right",
  175. fontSize: "0.8em"
  176. }));
  177.  
  178. $("#ytav-controls").append($("<div>", {
  179. id: "ytav-controls-input"
  180. }));
  181.  
  182. smoothPelmt = $("<p>").css({
  183. color: "black"
  184. }).text("Smoothness: ");
  185.  
  186. smoothCountText = $("<b>", {
  187. id: "smoothCount"
  188. }).text("80");
  189.  
  190. smoothPelmt.append(smoothCountText);
  191.  
  192. $("#ytav-controls-input").append(smoothPelmt);
  193.  
  194. smoothInput = $("<input>", {
  195. type: "range",
  196. min: "0",
  197. max: "99",
  198. value: "80"
  199. }).css({
  200. display: "block"
  201. });
  202. $("#ytav-controls-input > p").append(smoothInput);
  203.  
  204. //Generate PIXI graphics for bar draw
  205. g = new PIXI.Graphics();
  206. }
  207.  
  208. //A constant to calcule the bar width responsively
  209. widthConstant = (100 / (dataArray.length - excludeRatio));
  210.  
  211. debug("Setup view successfull!", "INFO");
  212. } catch (e) {
  213. debug("Failed to setup the view!\n" + e, "ERROR");
  214. }
  215. }
  216.  
  217. //The animate loop
  218. function animate() {
  219. //Animate loop
  220. requestAnimationFrame(animate);
  221.  
  222. //Get the audio data
  223. passByteFrequencyData(dataArray);
  224.  
  225. //Removes the "older bars" from graphics
  226. g.clear();
  227.  
  228. //Starts drawing with a color & oppacity
  229. g.beginFill(0x5CE6FF, 1);
  230.  
  231. //Resize the view when necessary
  232. if (playerAPIDiv.width() != renderer.width || playerAPIDiv.height() != renderer.height) {
  233. renderer.resize(playerAPIDiv.width(), playerAPIDiv.height());
  234. $("#ytav-controls").css("width", ($("#ytav").width() - renderer.width) * 0.9);
  235. }
  236.  
  237. //Update the smoothness when necessary
  238. if (smoothInput.val() / 100 != analyser.smoothingTimeConstant) {
  239. analyser.smoothingTimeConstant = smoothInput.val() / 100;
  240. smoothCountText.text(smoothInput.val());
  241. }
  242.  
  243. //Generate the bars based on i dataArray audio size
  244. for (i = 0; i < dataArray.length - excludeRatio; i++) {
  245. //The barWidth based on a percent of the view based on the dataArray
  246. barWidth = widthConstant * (renderer.width / 100);
  247.  
  248. sizeControl = dataArray[i].map(0, 255, 0, renderer.height);
  249. g.drawRect(barWidth * i, renderer.height - sizeControl, barWidth, sizeControl);
  250. }
  251.  
  252. //Finally, add the generated stuff to container
  253. container.addChild(g);
  254.  
  255. //Render the Container
  256. renderer.render(container);
  257. }
  258.  
  259. /************
  260. UTILS
  261. ************/
  262.  
  263. //A debug function
  264. function debug(msg, type) {
  265. if (doDebug) {
  266. switch (type) {
  267. case "ERROR":
  268. console.log("[ERROR] YTMV > " + msg);
  269. break;
  270. case "INFO":
  271. console.log("[INFO] YTMV > " + msg);
  272. break;
  273. case "WARNING":
  274. console.log("[WARNING] YTMV > " + msg);
  275. break;
  276. default:
  277. console.log("[DEBUG] YTMV > " + msg);
  278. break;
  279. }
  280. }
  281. }
  282.  
  283. //Get the data from the running analyser
  284. function passByteFrequencyData(array) {
  285. try {
  286. analyser.getByteFrequencyData(array);
  287. } catch (e) {
  288. debug("Error passing the ByteFrequencyData!", "ERROR");
  289. }
  290. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址