vue-waveform
Version:
waveform audio player wavesurfer -waveform js html 音频audio波形图
262 lines (239 loc) • 8.44 kB
JavaScript
import Analysis from './analysis'
// import { extend, debounce } from './util'
import { extend } from './util'
import Tween from './animation'
let defaultOpt = {
WIDTH: 500,
HEIGHT: 300
}
const AudioContext = window.AudioContext || window.webkitAudioContext
const audioContext = new AudioContext()
const analyser = audioContext.createAnalyser()
export default class Drawer {
constructor (options) {
this.opts = Object.assign({}, defaultOpt)
this.tween = new Tween()
extend(this.opts, options || {})
analyser.fftSize = this.opts.fftSize
if (this.opts.type === 'line3') {
this.analysisLine = new Analysis({WIDTH: this.opts.WIDTH / 4, audioContext: audioContext})
} else {
this.analysisLine = new Analysis({WIDTH: this.opts.WIDTH, audioContext: audioContext})
}
this.receive = this.warpperReceive(this.opts.type)
this.drawBar = this.drawBar.bind(this)
this.drawLine = this.drawLine.bind(this)
this.mybuffer = undefined
this.animationStart = false
this.isOpen = false
this.masterArr = []
}
setWidth(v, buffer) {
this.clear()
this.opts.WIDTH = v
}
review(buffer) { // 设置重新绘制
this.analysisLine = new Analysis({WIDTH: this.opts.WIDTH, audioContext: audioContext})
return this.receive(buffer)
}
destory() {
if (this.opts && this.opts.canvasCtx) {
this.opts.canvasCtx.clearRect(0, 0, this.opts.WIDTH, this.opts.HEIGHT)
}
}
warpperReceive(type) {
let _this = this
if (type === 'bar') {
return function (arraybuffer) {
return new Promise((resolve, reject) => {
audioContext.decodeAudioData(arraybuffer, function(buffer) {
_this.analysisBar(buffer, type)
resolve(buffer)
})
})
}
} else if (type === 'line') {
return function (arraybuffer) {
return new Promise((resolve, reject) => {
audioContext.decodeAudioData(arraybuffer, function(buffer) {
_this.analysisBar(buffer, type)
resolve(buffer)
})
})
}
} else if (type === 'line2') {
return function (arraybuffer) {
return new Promise((resolve, reject) => {
audioContext.decodeAudioData(arraybuffer, function(buffer) {
_this.mybuffer = buffer
_this.analysisLine.getPeaks(buffer)
_this.drawLine2()
resolve(buffer)
})
})
}
} else if (type === 'line3') {
return function (arraybuffer) {
return new Promise((resolve, reject) => {
audioContext.decodeAudioData(arraybuffer, function(buffer) {
_this.mybuffer = buffer
_this.analysisLine.getPeaks(buffer)
_this.drawLine3()
resolve(buffer)
})
})
}
}
}
analysisBar(buffer, type) {
this.audioBufferSourceNode = audioContext.createBufferSource()
this.audioBufferSourceNode.connect(analyser)
// this.analyser.connect(this.audioContext.destination)
this.audioBufferSourceNode.buffer = buffer
this.audioBufferSourceNode.start(0)
this.bufferLength = analyser.frequencyBinCount
this.dataArray = new Uint8Array(this.bufferLength)
if (!this.isOpen) {
if (type === 'line') {
this.drawLine()
} else if (type === 'bar') {
this.drawBar()
}
this.isOpen = true
}
}
drawBar() {
if (!this.animationStart) return
if (this.dataArray === null) return
analyser.getByteFrequencyData(this.dataArray)
this.opts.canvasCtx.fillStyle = this.opts.bgColor
this.opts.canvasCtx.fillRect(0, 0, this.opts.WIDTH, this.opts.HEIGHT)
let barWidth = (this.opts.WIDTH / this.bufferLength) * 1.2
let barHeight
let x = 0
let grd = this.opts.canvasCtx.createLinearGradient(0, 0, 0, this.opts.HEIGHT)
grd.addColorStop(0, '#0f0')
grd.addColorStop(0.5, '#ff0')
/* grd.addColorStop(0.5,"rgb(59, 234, 66)");
grd.addColorStop(0.5,"rgb(59, 234, 66)"); */
grd.addColorStop(1, '#f00')
for (var i = 0; i < this.bufferLength; i++) {
barHeight = this.dataArray[i] * this.opts.range
this.opts.canvasCtx.fillStyle = grd
this.opts.canvasCtx.fillRect(x, this.opts.HEIGHT - barHeight, barWidth, barHeight)
x += barWidth + 1
}
// window.requestAnimationFrame(debounce(this.drawBar, 60))
window.requestAnimationFrame(this.drawBar)
}
drawLine() {
if (!this.animationStart) return
if (this.dataArray === null) return
analyser.getByteTimeDomainData(this.dataArray)
this.opts.canvasCtx.fillStyle = 'rgb(0, 0, 0)'
this.opts.canvasCtx.fillRect(0, 0, this.opts.WIDTH, this.opts.HEIGHT)
this.opts.canvasCtx.lineWidth = 1
this.opts.canvasCtx.strokeStyle = 'rgb(59, 234, 46)'
this.opts.canvasCtx.beginPath()
let sliceWidth = this.opts.WIDTH * 1.0 / this.bufferLength
let x = 0
for (let i = 0; i < this.bufferLength; i++) {
let v = this.dataArray[i] / 128.0
let y = v * this.opts.HEIGHT / 2
if (i === 0) {
this.opts.canvasCtx.moveTo(x, y)
} else {
this.opts.canvasCtx.lineTo(x, y)
}
x += sliceWidth
}
this.opts.canvasCtx.lineTo(this.opts.WIDTH, this.opts.HEIGHT / 2)
this.opts.canvasCtx.stroke()
// this.opts.canvasCtx.beginPath()
// this.opts.canvasCtx.strokeStyle = 'rgb(229, 65, 119)'
// window.requestAnimationFrame(this.drawLine.bind(this))
window.requestAnimationFrame(this.drawLine)
}
stopAnimation() {
this.animationStart = false
this.isOpen = false
this.clear()
}
startAnimation() {
this.isOpen = false
this.animationStart = true
}
clear() {
this.opts.canvasCtx.clearRect(0, 0, this.opts.WIDTH, this.opts.HEIGHT)
}
drawLine2() {
let _this = this
let arr = this.analysisLine.mergedPeaks.map(function(item, i) { return item * 1000 })
this.opts.canvasCtx.fillStyle = this.opts.bgColor
this.opts.canvasCtx.fillRect(0, 0, this.opts.WIDTH, this.opts.HEIGHT)
this.opts.canvasCtx.lineWidth = 1
this.opts.canvasCtx.strokeStyle = 'rgb(59, 234, 46)'
this.opts.canvasCtx.beginPath()
let sliceWidth = this.opts.WIDTH * 1.0 / arr.length
let x = 0
let len = arr.length
this.tween.animate({
x: x,
duration: 2000,
sliceWidth,
count: len,
callback: function (i, x, sliceWidth) {
let y = arr[i] * _this.opts.range + (_this.opts.HEIGHT / 2)
if (i === 0) {
_this.opts.canvasCtx.moveTo(x, y)
} else {
_this.opts.canvasCtx.lineTo(x, y)
}
x += sliceWidth
_this.opts.canvasCtx.stroke()
return x
}
})
/*for (let i = 0; i < len; i++) {
let y = arr[i] * this.opts.range + (this.opts.HEIGHT / 2)
if (i === 0) {
this.opts.canvasCtx.moveTo(x, y)
} else {
this.opts.canvasCtx.lineTo(x, y)
}
x += sliceWidth
}*/
this.opts.canvasCtx.lineTo(this.opts.WIDTH, this.opts.HEIGHT / 2)
this.opts.canvasCtx.stroke()
}
drawLine3() {
let _this = this
if (_this.masterArr.length > (this.opts.WIDTH / 2 * 4)) {
let len = _this.masterArr.length - this.opts.WIDTH / 2
_this.masterArr.splice(len)
}
let arr = this.analysisLine.mergedPeaks.map(function(item, i) {
return item * 1000
})
_this.masterArr.unshift.apply(_this.masterArr, arr)
this.opts.canvasCtx.fillStyle = this.opts.bgColor
this.opts.canvasCtx.fillRect(0, 0, this.opts.WIDTH, this.opts.HEIGHT)
this.opts.canvasCtx.lineWidth = 1
this.opts.canvasCtx.strokeStyle = 'rgb(59, 234, 46)'
this.opts.canvasCtx.beginPath()
let sliceWidth = this.opts.WIDTH * 1.0 / _this.masterArr.length
let x = 0
let len = _this.masterArr.length
for (let i = 0; i < len; i++) {
let y = _this.masterArr[i] * this.opts.range + (this.opts.HEIGHT / 2)
if (i === 0) {
this.opts.canvasCtx.moveTo(x, y)
} else {
this.opts.canvasCtx.lineTo(x, y)
}
x += sliceWidth
}
this.opts.canvasCtx.lineTo(this.opts.WIDTH, this.opts.HEIGHT / 2)
this.opts.canvasCtx.stroke()
}
}