将 PCM 音频采样从 44100 降低到 8000

2023-12-29

我从事音频识别演示已经有一段时间了,API 需要我传递一个采样率为 的 .wav 文件8000 or 16000,所以我必须对其进行下采样。我尝试了以下两种算法。虽然他们都没有像我希望的那样解决问题,但结果存在一些差异,我希望这会让事情变得更清楚。

这是我第一次尝试,效果很好采样率 % 输出采样率 = 0,但是当输出采样率 = 8000 或 1600,结果音频文件是silent(这意味着输出数组的每个元素的值为0):

function interleave(inputL){
  var compression = sampleRate / outputSampleRate;
  var length = inputL.length / compression;
  var result = new Float32Array(length);

  var index = 0,
  inputIndex = 0;

  while (index < length){
    result[index++] = inputL[inputIndex];
    inputIndex += compression;
  }
  return result;
}

这是我的第二次尝试,来自一家大公司,但也不起作用。更重要的是,当我设置采样率 % 输出采样率 = 0它仍然输出一个silent file:

function interleave(e){
  var t = e.length;
  var n = new Float32Array(t),
    r = 0,
    i;
  for (i = 0; i < e.length; i++){
    n[r] = e[i];
    r += e[i].length;
  }
  sampleRate += 0.0;
  outputSampleRate += 0.0;
  var s = 0,
  o = sampleRate / outputSampleRate,
  u = Math.ceil(t * outputSampleRate / sampleRate),
  a = new Float32Array(u);
  for (i = 0; i < u; i++) {
    a[i] = n[Math.floor(s)];
    s += o;
  }

  return a
}

如果我的设置错误,这里是编码WAV功能:

function encodeWAV(samples){
  var sampleBits = 16;
  var dataLength = samples.length*(sampleBits/8);

  var buffer = new ArrayBuffer(44 + dataLength);
  var view = new DataView(buffer);

  var offset = 0;

  /* RIFF identifier */
  writeString(view, offset, 'RIFF'); offset += 4;
  /* file length */
  view.setUint32(offset, 32 + dataLength, true); offset += 4;
  /* RIFF type */
  writeString(view, offset, 'WAVE'); offset += 4;
  /* format chunk identifier */
  writeString(view, offset, 'fmt '); offset += 4;
  /* format chunk length */
  view.setUint32(offset, 16, true); offset += 4;
  /* sample format (raw) */
  view.setUint16(offset, 1, true); offset += 2;
  /* channel count */
  view.setUint16(offset, outputChannels, true); offset += 2;
  /* sample rate */
  view.setUint32(offset, outputSampleRate, true); offset += 4;
  /* byte rate (sample rate * block align) */
  view.setUint32(offset, outputSampleRate*outputChannels*(sampleBits/8), true); offset += 4;
  /* block align (channel count * bytes per sample) */
  view.setUint16(offset, outputChannels*(sampleBits/8), true); offset += 2;
  /* bits per sample */
  view.setUint16(offset, sampleBits, true); offset += 2;
  /* data chunk identifier */
  writeString(view, offset, 'data'); offset += 4;
  /* data chunk length */
  view.setUint32(offset, dataLength, true); offset += 4;

  floatTo16BitPCM(view, offset, samples);

  return view;
}

这件事困扰了我很长时间,请告诉我我错过了什么......

--------------------------------------解决之后------------------ --------------

我很高兴它现在运行良好,这是正确的函数版本交错():

    function interleave(e){
      var t = e.length;
      sampleRate += 0.0;
      outputSampleRate += 0.0;
      var s = 0,
      o = sampleRate / outputSampleRate,
      u = Math.ceil(t * outputSampleRate / sampleRate),
      a = new Float32Array(u);
      for (i = 0; i < u; i++) {
        a[i] = e[Math.floor(s)];
        s += o;
      }

      return a;
    }

所以你可以看到我传递给它的变量的类型不正确~ 再次感谢亲爱的@jaket和其他朋友~虽然我自己想通了,但他们让我更好地了解了原来的东西~~~:)


采样率转换不仅仅是简单地丢弃或插入样本。

让我们以 2 倍下采样为例(例如 44100->22050)。一种幼稚的方法是扔掉所有其他样本。但想象一下,在原始 44.1kHz 文件中存在一个 20khz 的正弦波。该采样率完全在奈奎斯特 (fs/2=22050) 范围内。在您扔掉所有其他样本后,它仍然会处于 10kHz,但现在它将高于奈奎斯特 (fs/2=11025),并且它将混叠到您的输出信号中。最终结果是您将得到一个频率为 8975 Hz 的大正弦波!

为了避免在下采样过程中出现这种混叠,您需要首先设计一个低通滤波器,并根据您的抽取比选择截止值。对于上面的示例,您将首先切断 11025 以上的所有内容,然后进行抽取。

硬币的另一面称为上采样和插值。假设您想要将采样率提高 2 倍。首先,您在每个输入样本之间插入零,然后运行插值滤波器来计算值,以使用周围样本替换零。

速率改变通常涉及抽取和插值的某种组合——因为两者都通过整数个样本来工作。以48000->32000为例。输出/输入比为32000/48000或2/3。因此,您可以将 48000 上采样 2 倍以获得 96000,然后将其下采样 3 倍到 32000。另一件事是您可以将这些过程链接在一起。所以如果你想从 48000->16000 你会上升 3,下降 2,下降 2。而且,44100 特别困难。例如,要从 48000 移动到 44100,您需要上升 147,下降 160,并且您无法将其分解为更小的术语。

我建议您找到一些代码或库来为您执行此操作。您需要寻找的是多相滤波器或采样率转换器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 PCM 音频采样从 44100 降低到 8000 的相关文章

  • onclick 函数上的 CSS 选择器

    有没有办法让CSS选择器onclick function 您可以在onclick https stackoverflow com questions 24365416 select element which have specific a
  • 使用 Ajax 在输入时提交 Textarea,然后渲染部分内容而不刷新整个页面

    目前我正在尝试通过 JS 和 Ajax 在没有提交按钮的情况下发表评论 并且它有效 问题是当帖子提交时 页面重新加载到 post id comment页面 我希望它呈现部分内容 而不是刷新整个页面或将我带到不同的页面 我对 JS 不熟悉 任
  • 如何在react-select v2中创建optgroup?

    我想在我的反应选择列表中包含 optgroups 但它似乎没有记录在任何地方 我有以下结构 是从评论中提取的https github com JedWatson react select issues 59 https github com
  • NodeJs读取JSON文件

    我正在使用 NodeJs 读取 json 文件 我的代码非常基本 var obj require sample json console log obj 0 Sample json 文件包含这样的字符串化 JSON sample good
  • Visual Studio IDE 中功能后的空间

    如何设置 Visual Studio 中的设计以在我的 javascript 函数后面放置一个空格 目前 当我按下返回键时 我得到了这个 var myfunc function 当我想要这个的时候 var myfunc function 知
  • SVG 中三角形的圆角

    我正在尝试制作一个具有圆角的三角形 三角形将如下所示 左下角是唯一看起来相当容易制作的角 主要是因为这是一个 90 度的 转弯 该转弯是使用QSVG 中的命令具有以下参数 Q x y height x y height RADIUS从我正在
  • 如何删除从 javascript var 转义的反斜杠?

    我有这个变量 var x div class Which is div class 但是我需要 div class abcdef 我怎样才能 unes cape 这个变量来删除所有转义字符 您可以通过正则表达式将反斜杠后跟引号替换为仅引号
  • FormData 中的 Blob 为 null

    我正在尝试通过远程 API 通过 ajax 在 android 中发送创建的照片 我在用着相机图片背景 https github com an rahulpandey cordova plugin camerapicturebackgrou
  • AngularJS - 服务、工厂、过滤器等中的依赖注入

    因此 我想在我的 Angular 应用程序中使用一些插件和库 目前 我只是引用这些函数 方法 因为它们是在 99 的应用程序中以完全忽略依赖注入的方式使用的 我有 例如 javascript 库 MomentJS 它处理格式化和验证日期 并
  • 属性访问器(getter)的扩展运算符问题

    我很难理解为什么以下代码存在一些问题https jsfiddle net q4w6e3n3 3 https jsfiddle net q4w6e3n3 3 Note 所有示例均在 chrome 版本 52 0 2743 116 中进行测试
  • 将数组中的所有元素相乘

    我在这里找不到我真正想要的例子 我想将所有数组元素相乘 因此如果数组包含 1 2 3 总和将为 123 6 到目前为止 我已经得到了这段代码 但它返回未定义 function multiply array var sum 1 for var
  • 当表格在 IE 中获得焦点时,表格滚动条会向上跳跃

    问题 我有一个table有包装的div with overflow y auto 一旦table获得焦点 滚动条向上跳 我怎样才能防止这种情况发生 我经历过这种行为IE9 不在 Chrome 中 请注意 我已添加tabindex到桌子上 以
  • 更改特定字符串的颜色

    有谁知道如果将特定单词输入文本区域 我如何更改它的颜色 例如 如果用户输入 你好我的朋友 它会动态地将 你好 更改为绿色 在google上花了很多时间 找不到任何相关的东西 谢谢 textareas 的设计目的不是选择性着色
  • selenium-webdriver 与 webdriverjs 有什么区别(以及何时使用)?

    我是一位使用 selenium webdriver 的经验丰富的专业人士 我正在探索有关如何测试 javascript 应用程序的更多选项 我发现了 webdriverJs 不幸的是 我不明白这两者 2 之间有什么区别 有人可以解释一下何时
  • Promise 构造函数回调的主体何时执行?

    假设我有以下代码构造一个Promise function doSomethingAsynchronous return new Promise resolve gt const result doSomeWork setTimeout gt
  • javascript/jquery 禁用点击提交按钮,防止重复提交

    所以我的提交按钮如下所示 a href img src images user create product png border 0 a 当我双击它时 显然会双重提交 问题是 我将信息保存在数据库中 因此那里会有重复的信息 我不想那样 这
  • 当选项卡重新加载(chrome 扩展)时,如何运行此脚本?

    所以我想在指定 URL 中重新加载选项卡时运行脚本 它几乎可以工作 但实际上 id 不能 这是我的清单文件 manifest version 2 name Sample Extension description Sample Chrome
  • 如何仅突出显示嵌套表的最里面的表行?

    我有几个嵌套表 我想突出显示鼠标指针下方的最里面的行 我怎样才能做到这一点 一些提示 我使用嵌套表来显示递归表格数据 表可以嵌套 10 层 嵌套正如您所期望的那样 table tr td table tr td table tr td 可能
  • 无法从 JSON 请求获取数据,尽管我知道它已返回

    我试图获取从 getJSON 返回的数据 但我无法让它工作 我已经在 search twitter API 上尝试了相同的代码 效果很好 但它不适用于其他网站 我知道数据已返回 因为我在使用检查器时可以找到它 我通过检查器找到的值是 id
  • 在 Firefox 中使用 Javascript 检测键盘布局

    有没有办法在 Firefox 中检测客户端的键盘布局 我知道 Chrome 的答案是肯定的 请参阅https developer mozilla org en US docs Web API Navigator keyboard https

随机推荐