【问题标题】:Dealing With Raw Audio JavaScript处理原始音频 JavaScript
【发布时间】:2020-12-24 17:05:14
【问题描述】:

我的项目的目标是能够操纵原始音频数据,例如这个问题:Play raw audio with JavaScript。有五个步骤:

  • 录制音频
  • 将生成的blob 转换为ArrayBuffer
  • 使用DataView 处理音频数据的ArrayBuffer(例如,使其速度提高一倍或提高两倍)。
  • 转换回 blob
  • 播放经过处理的音频

当我将音频数据块转换为ArrayBuffer,并将ArrayBuffer 转换为Int8Array 以便我可以查看数据时,它看起来像这样(我只显示前几个值,而不是整件事):

[26,69,-33,-93,-97,66,-122,-127,1,66,-9,-127,1,66,-14,-127,4,66,-13,-127,8,66,-126,-124,119,101,98,109,66,-121,-127,4,66,-123,-127,2,24,83,-128,103,1,-1,-1,-1,-1,-1,-1,-1,21,73,-87,102,-103,42,-41,-79,-125,15,66,64,77,-128,-122,67,104,114,111,109,101,87,65,-122,67,104,114,111,109,101,22,84,-82,107,-65,-82,-67,-41,-127,1,115,-59,-121,-103,-103,-9,91,-16,59,77,-125,-127,2,-122,-122,65,95,79,80,85,83,99,-94,-109,79,112,117,115,72,101,97,100,1,1,0,0,-128,-69,0,0,0,0,0,-31,-115,-75,-124,71,59,-128,0,-97,-127,1,98,100,-127,32,31,67,-74,117,1,-1,-1,-1,-1,-1,-1,-1,-25,-127,0,-93,65,52,-127,0,0,-128,-5,-125,2,-60,-1,-2,127,-4,102,-43,102,31,98,87,-112,-55,-17,-20,-88,89,39,108,97,84,44,38,-113,61,36,122,7,39,61,27,-103,-91,-23,80,64,36,9,-4,-51,-127,12,109,38,100,99,-101,-18,74,124,108,59,71,81,23,-30,93...]

由于似乎不可能从Int8Array 回到ArrayBuffer,并最终回到可以作为音频播放的Blob,我决定使用DataView 来操纵@ 987654336@.

当我根本不更改 ArrayBuffer 时,它可以成功地将其转换回 blob 并转换回音频。但是,当我尝试将 ArrayBuffer 更改为 DataView 时,出现以下错误:

index.html:1 
Uncaught (in promise) DOMException: Failed to load because no supported source was found.

在线查看后,该错误似乎是某种CORS问题,但这没有意义,因为当我不更改ArrayBuffer时它可以工作。问题是否与数据类型有关?

这是我的整个 JavaScript:

let AudioContext = window.AudioContext || window.webkitAudioContext;
var mediaRecorder;

function start(){ //start recording
    audio = navigator.mediaDevices.getUserMedia({
        audio: true,
        video: false
    }).then(record);
}

function record(stream) {
    mediaRecorder = new MediaRecorder(stream);
    mediaRecorder.start(); //start recording

    mediaRecorder.addEventListener("dataavailable", event => {
        event.data.arrayBuffer().then(processAudio); //event.data is a blob, converts it into an arrayBuffer
    });
}

function processAudio(buffer){
    var view = new DataView(buffer); //to change the ArrayBuffer
    var array = new Int8Array(buffer); //this typed array contains all of the audio data
    
    view.setInt16(0, 1); //when I comment out this line and don't change the ArrayBuffer at all, it works.

    var newBlob = new Blob([buffer]); //convert back into blob

    var newAud = document.createElement("audio"); //create audio element to play the recording
    newAud.src = URL.createObjectURL(newBlob);
    newAud.play();
    document.body.appendChild(newAud);
}

function done(){ mediaRecorder.stop(); }

我还想提一下,当我尝试绘制 Int8Array 时,我得到如下图所示的随机静态:

我很确定它应该是 8 位编码,因为 ArrayBuffer 的字节长度并不总是两个的倍数。

感谢任何帮助。

【问题讨论】:

    标签: javascript audio blob arraybuffer


    【解决方案1】:

    我认为您在列表中遗漏了一个关键步骤:将传入数据转换为有意义的 PCM 值。

    您似乎收到了一个有符号字节流。这些值都在 -127 和 127 之间是暗示性的。

    实际的 PCM 很可能由每个 PCM 值由两个或三个甚至四个字节组合而成的值组成。最常见的音频格式是 16 位编码。两个字节需要以 little-endian 或 big-endian 顺序连接才能获得您的 PCM 值。

    在 PCM 中表示您的信号后,您就可以对其进行有意义的操作。请注意,您不仅限于减半或加倍:还可以使用线性插值来推断信号中的中间点,这使您有机会以您想要的任何速度播放声音。

    当然,在您对信号进行处理之后,必须将各个 PCM 值分解回您的系统所需的预期字节顺序格式。但是,不知道 JavaScript 音频的细节,也许有一些方法或函数可以让您在不进行字节级转换的情况下流式传输 PCM。

    我的经验是使用 Java,而不是 JavaScript,但这看起来非常相似。例如,我确实知道 Android 允许将 PCM 数据直接流式传输为例如签名的标准化浮点数。

    【讨论】:

    • 我很确定它是 8 位的,因为字节长度有时不是 2 的倍数,所以不可能是 16 位编码。
    • 现在大多数东西都是 16 位或 24 位的。不久前 8 位用于口语录音,但那个时代已经过去了。一些旧的游戏声音芯片使用 8 位,例如 80 年代的街机游戏。我将挑战您确定输入流的位长。请确定,否则您将无法自信地获得有意义的 PCM。必须有可用的规格。
    【解决方案2】:

    对于音频,需要未签名的Uint8Array,而不是签名的Int8Array。作为Phil answered below,您将拥有原始PCM 音频字节。 <audio> 无法播放原始 PCM 字节,但可以播放其他格式,如 WAV。或者您可以直接使用 WebAudio API 播放 PCM 字节。在以下位置查看两者的答案:How to Play RAW Audio Files?

    【讨论】:

      猜你喜欢
      • 2014-05-02
      • 2018-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 2011-04-09
      相关资源
      最近更新 更多