index.html 波形音乐播放器 选择播放文件: 你这不行啊..不支持canvas style.css html, body { margin: 0; font-family: arial, "Microsoft YaHei"; background-color: #ffffff; color: #000000;}#fileWrapper{transition:all 0.5s ease;
style.css波形音乐播放器
html, body { margin: 0; font-family: arial, "Microsoft YaHei"; background-color: #ffffff; color: #000000; } #fileWrapper{ transition:all 0.5s ease; } #fileWrapper:hover{ opacity: 1!important; } #visualizer_wrapper{ text-align: center; } #bg { position: absolute; width: 1920px; height: 1080px; background: url(../images/index-bg.jpg); margin-left: -960px; left:50%; margin-top:-540px; top:50%; }canvas_draw.js
// JavaScript Document var x = 0; // canvas画布原点x var y = 0; // canvas画布原点y var x_base = x; // 我们要画的波形图的最后一个点的x坐标 var y_base = 250; // 我们要画的波形图的最后一个点的y坐标 var arrPoint = []; // 用于保存已经波形图的轨迹点 var index = 0; // 这个我是用来打日志用的..下面为了看清除了多少次canvas画布 var step = 1; // x轴每次走的步长 var width = 1024; // 这个是画布宽度 var height = 768; // 这个是画图高度 (function () { // 首先让我们的函数周期调用 var canvas = document.getElementById("canvas"); canvas.setAttribute("style", "border:solid 1px #000000;") canvas.width = width + ""; canvas.height = height + ""; var context = canvas.getContext("2d"); context.strokeStyle = "#ccccc"; context.fileStyle = "#ccccc"; var itv = setInterval(function () { context.clearRect(0, 0, x_base - step, height); if (x_base > width) { index++; context.translate(step * -1, 0); } var obj = {}; obj.x = x_base; obj.y = y_base; if (arrPoint.length > (width / step)) { arrPoint.splice(0, 1); } arrPoint.push(obj); context.beginPath(); for (var i = 0; i < arrPoint.length; i++) { context.lineTo(arrPoint[i].x, arrPoint[i].y); } context.stroke(); context.closePath(); x_base += step; y_base = 500 - (window.audio.current_data * 2); }, 100) var a = document.createElement("div"); document.body.appendChild(a); a.setAttribute("style", "height:20px; width:1280px;position:absolute;top:850px;;margin-left:-640px;left:50%;") var led = new Array(1024) var bor = new Array(1024) var b = document.createElement("div"); document.body.appendChild(b); b.setAttribute("style", "height:512px; width:1536px;position:absolute;top:50px;;margin-left:-768px;left:50%;") for (var i = 0; i < 1024; i++) { led[i] = document.createElement("div"); a.appendChild(led[i]); led[i].setAttribute("style", "width:10px;height:5px;float:left; background:#00ff00;opacity:0.0;border:solid 1px #000000;"); } for (var i = 0; i < 512; i++) { bor[i] = document.createElement("div"); b.appendChild(bor[i]); bor[i].setAttribute("style", "width:1px;height:512px;float:left;background:#00ff00;;opacity:1;border:solid 1px #000000;"); } setInterval(function () { document.getElementById("sdf").style.height = (window.audio.current_data * 5) + "px" for (var i = 0; i < 1024; i++) { led[i].style.opacity = ((audio.current_data_array[i] * (100 / 255)) / 100) + ""; led[i].style.background = 'rgb(' + randomNum(0, 255) + ',' + randomNum(0, 255) + ',' + randomNum(0, 255) + ')' if (i % 2 == 0) { bor[i / 2].style.height = (audio.current_data_array[i]) + "px" } } }, 100) function randomNum(minNum, maxNum) { switch (arguments.length) { case 1: return parseInt(Math.random() * minNum + 1, 10); break; case 2: return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10); break; default: return 0; break; } } })()_audio_visualizer.js
window.onload = function() { window.audio=[]; window.audio.current_data_array = new Uint8Array(1024); new Visualizer().ini(); }; var Visualizer = function() { this.file = null; //the current file this.fileName = null; //the current file name this.audioContext = null; this.source = null; //the audio source this.info = document.getElementById('info').innerHTML; //used to upgrade the UI information this.infoUpdateId = null; //to store the setTimeout ID and clear the interval this.animationId = null; this.status = 0; //flag for sound is playing 1 or stopped 0 this.forceStop = false; this.allCapsReachBottom = false; }; Visualizer.prototype = { ini: function() { this._prepareAPI(); this._addEventListner(); }, _prepareAPI: function() { //fix browser vender for AudioContext and requestAnimationFrame window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext; window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame; window.cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.msCancelAnimationFrame; try { this.audioContext = new AudioContext(); } catch (e) { this._updateInfo('!Your browser does not support AudioContext', false); console.log(e); } }, _addEventListner: function() { var that = this, audioInput = document.getElementById('uploadedFile'), dropContainer = document.getElementsByTagName("canvas")[0]; //listen the file upload audioInput.onchange = function() {//打开文件************************************************************************* if (that.audioContext===null) {return;}; //the if statement fixes the file selction cancle, because the onchange will trigger even the file selection been canceled if (audioInput.files.length !== 0) { //only process the first file that.file = audioInput.files[0]; that.fileName = that.file.name; if (that.status === 1) { //the sound is still playing but we upload another file, so set the forceStop flag to true that.forceStop = true; }; document.getElementById('fileWrapper').style.opacity = 1; that._updateInfo('Uploading', true); //once the file is ready,start the visualizer that._start(); }; }; //listen the drag & drop dropContainer.addEventListener("dragenter", function() { document.getElementById('fileWrapper').style.opacity = 1; that._updateInfo('Drop it on the page', true); }, false); dropContainer.addEventListener("dragover", function(e) { e.stopPropagation(); e.preventDefault(); //set the drop mode e.dataTransfer.dropEffect = 'copy'; }, false); dropContainer.addEventListener("dragleave", function() { document.getElementById('fileWrapper').style.opacity = 0.2; that._updateInfo(that.info, false); }, false); dropContainer.addEventListener("drop", function(e) { e.stopPropagation(); e.preventDefault(); if (that.audioContext===null) {return;}; document.getElementById('fileWrapper').style.opacity = 1; that._updateInfo('Uploading', true); //get the dropped file that.file = e.dataTransfer.files[0]; if (that.status === 1) { document.getElementById('fileWrapper').style.opacity = 1; that.forceStop = true; }; that.fileName = that.file.name; //once the file is ready,start the visualizer that._start(); }, false); }, _start: function() { //read and decode the file into audio array buffer var that = this, file = this.file, fr = new FileReader(); fr.onload = function(e) { var fileResult = e.target.result; var audioContext = that.audioContext; if (audioContext === null) { return; }; that._updateInfo('正在解码...', true); audioContext.decodeAudioData(fileResult, function(buffer) { that._updateInfo('解码完成!', true); that._visualize(audioContext, buffer); }, function(e) { that._updateInfo('解码文件失败!', false); console.error(e); }); }; fr.onerror = function(e) { that._updateInfo('读取文件失败!', false); console.error(e); }; //assign the file to the reader this._updateInfo('开始读取文件', true); fr.readAsArrayBuffer(file); }, _visualize: function(audioContext, buffer) { var audioBufferSouceNode = audioContext.createBufferSource(), analyser = audioContext.createAnalyser(), that = this; //链接资源到 analyser audioBufferSouceNode.connect(analyser); //链接 analyser 到 destination(the speaker), or we won't hear the sound analyser.connect(audioContext.destination); //then assign the buffer to the buffer source node audioBufferSouceNode.buffer = buffer; //play the source if (!audioBufferSouceNode.start) { audioBufferSouceNode.start = audioBufferSouceNode.noteOn //in old browsers use noteOn method audioBufferSouceNode.stop = audioBufferSouceNode.noteOff //in old browsers use noteOff method }; //stop the previous sound if any if (this.animationId !== null) { cancelAnimationFrame(this.animationId); } if (this.source !== null) { this.source.stop(0); } audioBufferSouceNode.start(0); this.status = 1; this.source = audioBufferSouceNode; audioBufferSouceNode.onended = function() { that._audioEnd(that); }; this._updateInfo('正在播放 ' + this.fileName, false); this.info = '正在播放 ' + this.fileName; document.getElementById('fileWrapper').style.opacity = 0.2; this._drawSpectrum(analyser); }, _drawSpectrum: function(analyser) { var that = this, meterWidth = 10, //width of the meters in the spectrum gap = 2, //gap between meters capStyle = '#fff', meterNum = 800 / (10 + 2), //count of the meters capYPositionArray = []; ////将hte caps的垂直位置存储在数组里面 var drawMeter = function() {//绘图函数 var array = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(array);//获取数据 //console.info("audio data array:"+array); var val_vd=0; //平均取值 for(var i=0;i<=array.length;i++){ if(i==array.length){ val_vd=val_vd/array.length; }else{ val_vd = array[i]+val_vd; } } //保存一帧音频数据 window.audio.current_data=val_vd; window.audio.current_data_array= array; //console.info(val_vd); if (that.status === 0) { //修正当声音结束时的值仍然不回到 for (var i = array.length - 1; i >= 0; i--) { array[i] = 0; }; allCapsReachBottom = true; for (var i = capYPositionArray.length - 1; i >= 0; i--) { allCapsReachBottom = allCapsReachBottom && (capYPositionArray[i] === 0); }; if (allCapsReachBottom) { cancelAnimationFrame(that.animationId); //由于声音停止,动画完成,停止请求动画以防止潜在的内存泄漏,这是非常重要的! return; }; }; var step = Math.round(array.length / meterNum); //从总数组中取样有限的数据 //console.info("step:" +step); that.animationId = requestAnimationFrame(drawMeter); } this.animationId = requestAnimationFrame(drawMeter); }, _audioEnd: function(instance) {//音频结束 if (this.forceStop) { this.forceStop = false; this.status = 1; return; }; this.status = 0; var text = 'HTML5 Audio API showcase | An Audio Viusalizer'; document.getElementById('fileWrapper').style.opacity = 1; document.getElementById('info').innerHTML = text; instance.info = text; document.getElementById('uploadedFile').value = ''; }, _updateInfo: function(text, processing) { var infoBar = document.getElementById('info'), dots = '...', i = 0, that = this; infoBar.innerHTML = text + dots.substring(0, i++); if (this.infoUpdateId !== null) { clearTimeout(this.infoUpdateId); }; if (processing) { //信息文本末端的动画点 var animateDot = function() { if (i > 3) { i = 0 }; infoBar.innerHTML = text + dots.substring(0, i++); that.infoUpdateId = setTimeout(animateDot, 250); } this.infoUpdateId = setTimeout(animateDot, 250); }; } }