export class musicPlayer { constructor(audioEl) { this.audioEl = audioEl // 音频上下文 this.audioCtx = null // 音源 this.audioSource = null // 时长 this.duration = 0 // 当前播放时间 this.currentTime = 0 // 播放进度 this.progress = 0 // 声音 this.volume = 20 // AnalyserNode 接口表示了一个可以提供实时频域和时域分析信息的节点 this.analyser = null // 音量节点 this.gainNode = null // 缓冲进度 this.timeRange = null // 是否播放中 this.playing = false } init() { // 音频上下文 this.audioCtx = new (window.AudioContext || window.webkitAudioContext)() if (!this.audioCtx) { throw new Error('audioCtx is null') } // 获取音频数据的节点 this.analyser = this.audioCtx.createAnalyser() // 音量节点 this.gainNode = this.audioCtx.createGain() this.gainNode.gain.value = 1 this.audioEl.volume = this.volume / 100 // 从<audio>或<video>元素生成的音频源 this.audioSource = this.audioCtx.createMediaElementSource(this.audioEl) this.audioEl.ontimeupdate = () => { this.currentTime = this.audioEl.currentTime if (this.progress >= this.duration) return this.progress = this.currentTime } this.audioEl.onloadedmetadata = () => { // 时长 this.duration = this.audioEl.duration console.log('onloadedmetadata', this.duration) } this.audioEl.onprogress = () => { // 当浏览器正在下载音频/视频时 this.timeRange = this.audioEl.buffered if (this.timeRange && this.timeRange.length > 0) { console.log( 'buffered', this.audioEl.buffered.start(0), this.audioEl.buffered.end(0) ) } } this.audioEl.oncanplay = () => { console.log('可播放') setTimeout(() => { this.getAudioSource() }, 100) } this.audioEl.onerror = (e) => { console.error('加载出现错误', e) this.onerror(e) } } onerror() {} onended() {} setSrc(src) { this.progress = 0 this.audioEl.src = src } // 调整进度 progressChange(value) { this.audioEl.currentTime = value } // 调整音量 volumeChange(value) { this.volume = value this.audioEl.volume = this.volume / 100 } // 音频波形处理 getAudioSource() { // 节点链接到音源 this.audioSource.connect(this.analyser) // 链接音量节点 this.analyser.connect(this.gainNode) this.gainNode.connect(this.audioCtx.destination) return // 使用快速傅立叶变换(Fast Fourier Transform (FFT) )来捕获音频数据 // this.analyser.fftSize = 2048 this.analyser.fftSize = 256 let bufferLength = this.analyser.frequencyBinCount let dataArray = new Uint8Array(bufferLength) let c = this.boardEl let canvasWidth = c.width let canvasHeight = c.height let ctx = c.getContext('2d') let left = this ctx.strokeStyle = 'rgba(81,167,255, .5)' drawBar() function drawBar() { // 波形绘制 ctx.clearRect(0, 0, canvasWidth, canvasHeight) let barWidth = (canvasWidth / bufferLength) * 1 let barHeight = 0 let x = 0 left.analyser.getByteFrequencyData(dataArray) for (let i = 0; i < bufferLength; i++) { barHeight = dataArray[i] / 2 let tempColor = barHeight * 3 > 255 ? 255 : barHeight * 3 ctx.fillStyle = 'rgba(' + tempColor + ', 160, 255, .5)' ctx.fillRect(x, canvasHeight - barHeight / 2, barWidth, barHeight) x += barWidth + 0.1 } requestAnimationFrame(drawBar) } } }