如何在 AppsScript 中混合 8bit/8kHz 无符号线性 PCM 数据?

信息处理 声音的 pcm
2022-01-27 18:17:59

我在 JavaScript (AppsScript) 中混合简单的无符号 8 位/8kHz 线性 PCM 音频样本时遇到了最困难的情况。我已经尝试了这里列出的所有基本数学,使用基本数字数组。

  1. 签名、添加、剪辑、取消签名。从每个字节中减去 128,添加它们,剪辑,然后添加 128。
  2. 产生平均值,每个样本只有 a[x]+b[x]/2
  3. Viktor T. Toth的,数学相关。

完整示例如下。这将要求您授权 Google Drive 访问音频样本(不,它不会触及您的任何内容): https ://script.google.com/macros/s/AKfycbzMOWV5Z5soG3uinrFc0WcscNXxsDq9elE9rzG0t703vsvDJZMS/exec

如您所见,这 3 个混合结果非常可怕。我一直认为无符号字节只是偏移了 128。不是这样吗? 我是否需要折叠一半字节才能获得真正的线性表示?JavaScript 中的基本数字是否不能正确转换为有符号/无符号表示? 如果是这种情况,Java/AppsScript 会以某种方式正确地处理两个真实样本。


更新 下面是一些特定的代码,其输出在上面的链接中。唉,它根本不起作用(JavaScript 中的字节折叠)?

   var vegaArray = DriveApp.getFileById('0B-e9EqGm0pWPQ3RUTXFyUERDVTA').getBlob().getBytes();
   var fdraArray = DriveApp.getFileById('0B-e9EqGm0pWPaUJQUmFRQWctNG8').getBlob().getBytes();

   for(var i=44;i<vegaArray.length;i++)
     vegaArray[i] = Math.round( ( 2 * (vegaArray[i] + fdraArray[i]) )
       - ( vegaArray[i] * fdraArray[i] / 128 )
       - 256
     ); // for
   // vegaArray[] is the mixed output
2个回答

假设abyte[]bbyte[]是两个样本值来自 的数组0-255,这就是解决方案:

combined = [];
for(i = 0; i < abyte.length; i++)
{   
    sample =  2*(abyte[i] + bbyte[i]) - ((abyte[i]*bbyte[i])/128) - 256
    combined[i] = Math.round(sample);
}

我有一个完整的示例,其中两个 wav 文件都提取到数组中(我使用 matlab 完成了此操作)。我还验证了它使用 matlab 可以正常播放。

https://jsfiddle.net/4hsfo96g/

通过一些试错找到了答案。 字节被折叠AppsScript 将数字(此处以字节示例)表示为 2 补码,这意味着这个 8 位整数 [128,255]的逻辑高 7 位按升序排列为 [-128,-1]。因此,按原样平均或添加是没有意义的。

AppsScript 中的逐步代码:

   // See code above from where vegaArray and fdraArray come
   for(var i=44;i<vegaArray.length;i++) {
     // flop the bytes atop
     vegaArray[i] = vegaArray[i]<0?vegaArray[i]+256:vegaArray[i];
     fdraArray[i] = fdraArray[i]<0?fdraArray[i]+256:fdraArray[i];

     // now do the unsigned 8-bit stuff (avg, add)
     vegaArray[i] += fdraArray[i];
     vegaArray[i] /= 2 ;

     // flop back the bytes abaft
     vegaArray[i] = vegaArray[i]<128?vegaArray[i]:vegaArray[i]-256;

   } // for