(function () { const graph = document.getElementById('graph') const bars = document.getElementById('bars') const file = document.getElementById('track') const stop = document.getElementById('stop') const gctx = graph.getContext('2d') const bctx = bars.getContext('2d') const rate = 2 let context let analyser let dataArray let bufferLength let source let started = false const gColorTable = [] const bColorTable = [] for (let i = 0; i <= 256; i++) { // include 256 const color = 'rgb(' + i + ',0,0)' const gGrad = gctx.createLinearGradient(0, 0, 0, 1) gGrad.addColorStop(0, color) gGrad.addColorStop(1, color) gColorTable.push(gGrad) const bGrad = bctx.createLinearGradient(0, 0, 0, 1) bGrad.addColorStop(0, color) bGrad.addColorStop(1, color) bColorTable.push(bGrad) } function resize () { const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0) const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0) - 5 graph.width = vw - 100 graph.height = vh bars.height = vh bars.width = 100 } function analyse () { window.requestAnimationFrame(analyse) analyser.getFloatFrequencyData(dataArray) gctx.drawImage(graph, -rate, 0) bctx.clearRect(0, 0, bars.width, bars.height) const dheight = (1 / dataArray.length) * graph.height for (let i = 0; i < dataArray.length; i++) { const p = i / dataArray.length const h = graph.height - p * graph.height const c = Math.max((dataArray[i] - analyser.minDecibels) / 100, 0) // if (c === 0) continue const s = Math.floor(c * 256) gctx.fillStyle = gColorTable[s] gctx.fillRect(graph.width - rate, h, rate, dheight) // const freq = i * context.sampleRate / analyser.fftSize const bar = (dataArray[i] + 100) bctx.fillStyle = bColorTable[s] bctx.fillRect(0, h, bar, dheight) } } async function start (arrayBuffer) { if (!context) context = new window.AudioContext() const audioBuffer = await context.decodeAudioData(arrayBuffer) if (!analyser) { analyser = context.createAnalyser() analyser.connect(context.destination) } if (source) { source.stop() source.disconnect() } source = context.createBufferSource() source.buffer = audioBuffer source.connect(analyser) source.start() bufferLength = analyser.frequencyBinCount dataArray = new Float32Array(bufferLength) if (started) return started = true analyse() } file.addEventListener('change', function (e) { const fp = file.files[0] if (!fp) return window.alert('Invalid file.') const fr = new window.FileReader() fr.addEventListener('loadend', function (e) { if (fr.readyState !== 2) return window.alert('File reading failed.') start(fr.result) }) fr.readAsArrayBuffer(fp) }) stop.addEventListener('click', function (e) { if (!source) return source.stop() source = null }) window.addEventListener('resize', resize) resize() })()