使用 AudioContext 时如何获得常规 <audio> 功能?

How do you get the regular <audio> features when using AudioContext?

以下代码可作为从远程 url 加载声音并通过一些音高移动循环播放的方法。尽管我将 AudioContext 附加到 <audio> 节点并且它正在播放声音,但我有 none 的 UI 功能,例如 play/pause、搜索、音量、下载等

屏幕截图(声音正在播放,但 HTML5 <audio> 功能的 none 有效):

我有这个几乎是空的HTML:

<div id="audios"></div>

然后我有一个添加<audio>元素的函数:

 $ -> Mixer.$audios = $("#audios")

 Mixer.add_audio = (url) ->
    $audio_box = $ """
      <div class='audio'>
        <audio controls loop></audio>      
      </div>
    """
    Mixer.$audios.append($audio_box)
    audio = $audio_box.find("audio")[0]
    Mixer.source_with_pitch_shift(audio, url).then (args) ->
      [audio_context, source, buffer_src] = args
      Mixer.start_playing(buffer_src)

  Mixer.start_playing = (buffer_src) ->
    buffer_src.loop = true
    buffer_src.start()

Mixer.source_with_pitch_shift 从缓冲区源(通过 HTTP 请求的音频文件)创建 AudioContext。它还会创建一个附加到该上下文的 PitchShift 节点(引擎盖下的 GainNode)。最后,我正在创建一个 MediaElementAudioSourceNode 连接音频上下文和 DOM <audio>,但它似乎没有效果,我不知道我应该做什么它。

Mixer.source_with_pitch_shift = (audio, url) ->
    Mixer.build_audio_context(url).then (args) ->
        [audio_context, buffer_src] = args
        # Not sure what to do with this:
        source = audio_context.createMediaElementSource(audio)
        pitchShift = PitchShift(audio_context)
        pitchShift.transpose = 12
        pitchShift.connect(audio_context.destination)
        Promise.resolve([audio_context, source, buffer_src])

Mixer.build_audio_context = (url) ->
    audioSrc = url
    audio_context = new AudioContext()    
    Mixer.bufferSound(audio_context, audioSrc).then (buffer) ->
        g = audio_context.createGain()
        g.gain.value = 5
        g.connect(audio_context.destination)
        bq = audio_context.createBiquadFilter()
        bq.detune.value = 0
        setInterval ->
          bq.detune.value += 200
        , 1000
        bq.connect(g)
        buffer_src = audio_context.createBufferSource()
        buffer_src.buffer = buffer
        buffer_src.connect(bq)
        Promise.resolve([audio_context, buffer_src])

Mixer.bufferSound = (ctx, url) ->
    new Promise (resolve, reject) ->
        req = new XMLHttpRequest()
        req.open('GET', url, true)
        req.responseType = 'arraybuffer'
        req.onload = ->
          ctx.decodeAudioData(req.response, resolve, reject)
        req.send()

调用它(这是一个 public url 并且页面最终循环播放这个 1 秒的示例并提高每个循环的音调):

 Mixer.add_audio "https://mixer-music.s3.amazonaws.com/tPEE9ZwTmy0.mp3"

我可以获得标准的 UI 功能吗?或者有什么方法可以用 AudioBufferSourceNode?

重新实现它

原来我需要修复 3 个问题:

  1. <audio> 中包含 <source> 标签,即将其更改为:

    <div class="audio">
      <audio controls loop>
        <source src="#{url}"></source>
      </audio>  
    </div>
    
  2. pitchShift.connect(audio_context.destination)之前添加source.connect(pitchShift)

  3. 运行 audio.crossOrigin = "anonymous" 在音频元素上

此外,由于我添加了 <source> 标签,因此无需通过 HTTP 加载歌曲。所以我删除了它。