JavaScript 音频可视化
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
#upload {
position: fixed;
top: 0;
left: 0;
}
audio {
position: fixed;
top: 0;
right: 0;
}
<input type="file" id="upload" accept="audio/mpeg">
const upload = document.querySelector('#upload')
upload.addEventListener('change', (e) => {
const [file] = e.target.files
if (!file) upload.value = ''
const { type } = file
if (!type.includes('audio')) {
alert('仅支持音频格式文件')
upload.value = ''
return false
}
const url = URL.createObjectURL(file)
draw(url)
})
function draw(url) {
const {
clientWidth: width,
clientHeight: height,
} = document.body
const audio = new Audio
audio.src = url
audio.controls = true
audio.load()
const canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
document.body.appendChild(audio)
document.body.appendChild(canvas)
const canvasCtx = canvas.getContext('2d')
const audioCtx = new AudioContext
const sourceNode = audioCtx.createMediaElementSource(audio)
// 音频分析器
const analyser = audioCtx.createAnalyser()
analyser.fftSize = 128 // FFT
sourceNode.connect(analyser)
analyser.connect(audioCtx.destination)
const len = analyser.frequencyBinCount
const buffer = new Uint8Array(len)
const gap = 2 // 间隙
const pillarWidth = (width / len) - gap
const gradient = canvasCtx.createLinearGradient(0, 0, 0, 500)
gradient.addColorStop(.8, '#1eec1e')
gradient.addColorStop(.5, '#c97a3d')
gradient.addColorStop(0, '#f00f00')
const render = () => {
canvasCtx.fillStyle = '#fff'
canvasCtx.fillRect(0, 0, width, height)
analyser.getByteFrequencyData(buffer)
let x = 0
buffer.forEach(v => {
const pillarHeight = (v / 255) * height
canvasCtx.fillStyle = gradient
canvasCtx.fillRect(x, height - (pillarHeight || 2), pillarWidth, pillarHeight || 2)
x += (pillarWidth + gap)
})
requestAnimationFrame(render)
}
render()
audio.play()
}
为之则易,不为则难。