【问题标题】:How to change playback speed of live audio from microphone (using a buffer)?如何更改麦克风实时音频的播放速度(使用缓冲区)?
【发布时间】:2019-03-20 13:00:42
【问题描述】:

我听说通过改变播放速度我们可以修改音频的频率。我在这里测试过: https://teropa.info/blog/2016/08/10/frequency-and-pitch.html

但问题是我需要一个录制的音频文件才能做到这一点。根据我的发现,网络音频无法改变实时音频的播放速度。我一直在想,如果我们将音频保存在缓冲区中,我们可以改变它的播放速度,从而改变频率。

我是网络音频 API 的新手。我发现一篇文章通过将实时音频保存到缓冲区来记录它。 https://docs.sumerian.amazonaws.com/articles/webaudio-1/

我想要的是:-

  1. 从麦克风获取音频。
  2. 将其保存到缓冲区中。
  3. 更改播放速度。
  4. 在扬声器上播放。

演示如何更改缓冲区节点的播放速度https://mdn.github.io/webaudio-examples/decode-audio-data/

但我希望使用现场麦克风音频代替录制的声音。

这是我对小提琴的尝试

https://jsfiddle.net/5dza62b8/13/

var audioContext = new(window.AudioContext || window.webkitAudioContext)();
var streamSource, scriptNode, bufferSource, audioBuffer;
var playbackControl = document.querySelector('#playback-rate-control');
var playbackValue = document.querySelector('#playback-rate-value');

// define variables

window.start_audio = function() {
  navigator.mediaDevices.getUserMedia({
    audio: true
  }).then((stream) => {

    alert("Got audio stream from microphone!");
    audioContext = new AudioContext();
    // Create an AudioNode from the stream.
    streamSource = audioContext.createMediaStreamSource(stream);
    scriptNode = audioContext.createScriptProcessor(2048, 1, 1);
    bufferSource = audioContext.createBufferSource();


    // Whenever onaudioprocess event is dispatched it creates a buffer array with the length bufferLength
    scriptNode.onaudioprocess = (audioProcessingEvent) => {
      realtimeBuffer = audioProcessingEvent.inputBuffer.getChannelData(0);
      // Create an array of buffer array
      audioBuffer.push(realtimeBuffer);
    }

    bufferSource.buffer = audioBuffer;
    bufferSource.playbackRate.value = 0.8;

    streamSource.connect(scriptNode);
    bufferSource.connect(audioContext.destination);
    bufferSource.start();

  }).catch((e) => {

    alert(e.name + ". " + e.message);

  });
}


// wire up buttons to stop and play audio, and range slider control
playbackControl.addEventListener('input', function() {
  bufferSource.playbackRate.value = playbackControl.value;
  playbackValue.innerHTML = playbackControl.value;
});

【问题讨论】:

  • 嘿嘿,你可能没有注意到,但你要的是时间机器;-)
  • @Kaiido,如果实时音频延迟 t 秒,假设我们将 1 秒的音频保存到缓冲区中,大约需要 1 秒的延迟,通过调整播放速度来考虑 t + 2 秒的不同音高更完整的过程。如果这是可能的,我想这样做,然后我会尝试将延迟从 2 秒减少到大约 30 毫秒。
  • 如果你只是想降低音高,那是非常可行的:jsfiddle.net/08ctfzp1 但是如果你想增加它,那是不可能的:如果你缓冲2s的现场音频,然后播放它的速度为 x2,读取播放开始时缓冲的内容仅需 1 秒,因此在此播放期间,您只需缓冲一秒的实时音频,您将在 50 毫秒内读取,您将在哪里只能缓冲 25 毫秒,您将在 12.5 毫秒等内读取。大约 1.99999 秒后,您将到达现在。
  • 很好,但就像你说的它在几秒钟后开始缓冲。有没有其他方法可以在不使声音机器人化的情况下改变音高?

标签: javascript html web-audio-api


【解决方案1】:

这可能比您想象的更难 - 如果播放速度大于 1,您将尝试播放尚未发生的声音!

一般来说,您可以使用网络音频 API 为实时麦克风输入添加效果 - 这是 MDN 文档中的一个示例,它为输入添加了一个过滤器:https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createMediaStreamSource

如果您想放慢现场音频的速度,可能的——但有一些注意事项。允许您更改播放速率的 Web 音频节点是 BufferSourceNode,它依赖于您之前加载的缓冲区。但是,您可能可以通过使用自定义 AudioWorklet 将数据逐步放入缓冲区并使用 BufferSourceNode 播放来解决此问题。需要考虑的一件事是你要让它持续多久——随着时间的推移,缓冲区会越来越大,迟早你的计算机会耗尽内存!

这涉及很多,可能不适合第一次涉足 Web 音频,但了解音频工作集的最佳起点是:https://developers.google.com/web/updates/2017/12/audio-worklet

使用音频工作集,您还可以研究一些更复杂的算法,这些算法可以让您在不改变声音长度的情况下改变声音的音高。 https://en.wikipedia.org/wiki/Audio_time_stretching_and_pitch_scaling

如果您刚开始使用网络音频,我的建议是您编写一些可以录制声音的东西,然后更改其播放速率。

【讨论】:

  • Here 是使用 MediaSource 和 MediaRecorder 缓冲流的示例(最初用于 this Q/A)请注意,FF 的小提琴有问题...
  • @Anonymous,如果您可以在我的代码中看到,我正在尝试将播放速度从 1 降低到 0.8。我觉得这看起来很可能,你不觉得一样吗?
  • 我想要非常接近人类真实声音的输出,其他方法对我不起作用,因为它们使声音变得机器人化并进行了修改,而不仅仅是改变音高。
猜你喜欢
  • 1970-01-01
  • 2018-06-18
  • 1970-01-01
  • 2018-02-14
  • 1970-01-01
  • 2014-02-22
  • 2011-08-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多