使用Howler.js创建JavaScript波形可视化

11
我正在尝试使用howler.js生成波形(https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Visualizations_with_Web_Audio_API)。我看到数据数组通过绘制函数进行循环。然而,它只绘制一条直线,因为v变量始终返回1。我基于一个相当常见的MDN示例编写了代码,这让我相信我获取howler数据的方式可能不正确。

HTML

<div id="play">play</div>
<canvas id="canvas"></canvas>
JavaScript
let playing = false
    const playBtn = document.getElementById('play')
    const canvas = document.getElementById('canvas')
    const canvasCtx = canvas.getContext('2d')
    const WIDTH = canvas.width
    const HEIGHT = canvas.height
    let drawVisual = null

    /*
        files
        https://s3-us-west-2.amazonaws.com/s.cdpn.io/481938/Find_My_Way_Home.mp3
    */

    /*
    streams
        'http://rfcmedia.streamguys1.com/MusicPulse.mp3'
    */

    let analyser = null
    let bufferLength = null
    let dataArray = null

    const howler = new Howl({
        html5: true,
        format: ['mp3', 'aac'],
        src:
            'https://s3-us-west-2.amazonaws.com/s.cdpn.io/481938/Find_My_Way_Home.mp3',
        onplay: () => {
            analyser = Howler.ctx.createAnalyser()
            Howler.masterGain.connect(analyser)
            analyser.connect(Howler.ctx.destination)
            analyser.fftSize = 2048
            analyser.minDecibels = -90
            analyser.maxDecibels = -10
            analyser.smoothingTimeConstant = 0.85
            bufferLength = analyser.frequencyBinCount
            dataArray = new Uint8Array(bufferLength)
            canvasCtx.clearRect(0, 0, WIDTH, HEIGHT)

            const draw = () => {
                drawVisual = requestAnimationFrame(draw)
                analyser.getByteTimeDomainData(dataArray)
                canvasCtx.fillStyle = '#000'
                canvasCtx.fillRect(0, 0, WIDTH, HEIGHT)
                canvasCtx.lineWidth = 2
                canvasCtx.strokeStyle = 'limegreen'
                canvasCtx.beginPath()

                let sliceWidth = (WIDTH * 1.0) / bufferLength
                let x = 0

                for (let i = 0; i < bufferLength; i++) {
                    let v = dataArray[i] / 128.0
                    let y = (v * HEIGHT) / 2

                    if (i === 0) {
                        canvasCtx.moveTo(x, y)
                    } else {
                        canvasCtx.lineTo(x, y)
                    }

                    x += sliceWidth
                }

                canvasCtx.lineTo(canvas.width, canvas.height / 2)
                canvasCtx.stroke()
            }

            draw()
        }
    })

    playBtn.addEventListener('click', () => {
        if (!playing) {
            howler.play()
            playing = true
        }
    })

能否请您将一个可工作的示例放到jsfiddle或其他地方?由于缺少HTML,现在无法尝试您的代码。也许您只是因为某些原因未能加载文件。您在控制台中是否收到错误信息? - antont
可以,但是唯一存在的两个元素是<canvas id="canvas">和<div id="play">。 - NicholasByDesign
2个回答

5

使它运行起来:

  1. 删除html5: true
  2. 你的音频源存在CORS设置问题。你的存储桶CORS设置如何?Access to XMLHttpRequest at 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/481938/Find_My_Way_Home.mp3' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

CORS问题导致您的dataArray填满了128,基本上意味着没有声音,尽管音乐正在播放。

这样我就可以让您的可视化程序正常工作。(您可以在Chrome上绕过CORS "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security


3
禁用网络安全对于测试来说可能可行,但这并不理想。如果操作者现在遇到了CORS问题,那么在实际生产中也很可能会出现CORS问题。他们应该尝试解决这个问题,而不是避免它。 - Nicolas
在使用 html5: true 的情况下,有没有办法实现分析器,例如用于流媒体? - xfx
移除 html5: true 的原因是什么? - Petros Kyriakou
这似乎没有修复mp3的直播可视化问题,这里有一个解决方案的链接:https://stackoverflow.com/questions/44479560/creating-an-audio-visualizer-using-html5 - Barak Binyamin

1

这里是波形的代码:

const data = audioBuffer.getChannelData(0)
context.beginPath()
const last = data.length - 1
for (let i = 0; i <= last; i++) {
  context.lineTo(i / last * width, height / 2 - height * data[i])
}
context.strokeStyle = 'white'
context.stroke()

如何从howler中获取audioBuffer?我不建议尝试,因为howler可能没有使用web audio api。文档中也没有任何方法,只能通过挖掘源代码来实现。相反,这里是直接加载此缓冲区的代码:
const url = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/481938/Find_My_Way_Home.mp3'
const getAudioBuffer = async (url) => {
  const context = new AudioContext
  result = await new Promise(resolve => {
    request = new XMLHttpRequest
    request.open "GET", url, true
    request.responseType = 'arraybuffer'
    request.onload = () => resolve(request.response)
    request.send()
  }
  return await context.decodeAudioData(result)
}
audioBuffer = getAudioBuffer(url)
audioBuffer.getChannelData(0) // it can have multiple channels, each channel is Float32Array

但是!这是没有动画的波形图,音轨已经下载并绘制了波形。

在您的示例中,您正在尝试制作动画效果,使用上面的代码可以制作类似于窗口根据播放位置从起点移动到终点的动画效果。

因此,我的答案不是答案,没有动画,没有howler,但希望它有所帮助 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接