java - 如何将字节数组中的pcm样本转换为-1.0到1.0范围内的 float 并返回?

标签 java android floating-point signal-processing

我使用的重采样算法期望 float 数组,其中包含 -1.0到1.0 范围内的输入样本。音频数据为 16位 PCM,采样率为 22khz

我想将音频从22khz下采样到8khz,如何将字节数组中的样本表示为浮点数> = -1和<= 1 并返回字节数组?

最佳答案

您问两个问题:

  • 如何将采样率从22kHz下调至8kHz?
  • 如何从float [-1,1]转换为16位int并返回?

  • 请注意,该问题已更新,以指示#1已在其他地方处理,但我将保留我的回答的那一部分,以防它对其他人有帮助。
    1.如何将采样率从22kHz下调至8kHz?
    一个评论者暗示这可以通过FFT解决。这是不正确的(重新采样的第一步是过滤。如果您感兴趣,我在这里提到为什么不使用FFT进行过滤:http://blog.bjornroche.com/2012/08/when-to-not-use-fft.html)。
    对信号重新采样的一种非常好的方法是使用polyphase filter。但是,即使对于有信号处理经验的人来说,这也相当复杂。您还有其他几种选择:
  • 使用实现高质量重采样的库,例如libsamplerate
  • 快速又肮脏地做些事

  • 听起来您已经采用第一种方法,这很棒。
    快速而肮脏的解决方案听起来不那么好,但是由于您将频率降至8 kHz,因此我认为音质不是您的首要任务。一种快速而肮脏的选择是:
  • 对信号应用低通滤波器。尝试消除4 kHz以上的音频。您可以使用描述为here的过滤器(尽管理想情况下,您想要比这些过滤器更陡峭的东西,但它们至少总比没有要好)。
  • 从原始信号中每隔2.75个采样中选择一个,以产生新的,重新采样的信号。当需要非整数样本时,请使用线性插值。如果您需要线性插值方面的帮助,请尝试here

  • 对于语音应用来说,这种技术应该已经足够好了。但是,我还没有尝试过,所以我不确定,因此我强烈建议您使用其他人的库。
    如果您确实想实现自己的高质量采样率转换(例如多相滤波器),则应该对其进行研究,然后再对https://dsp.stackexchange.com/提出任何问题,而不是此处。
    2.如何从float [-1,1]转换为16位int并返回?
    这已经由c.fogelklou开始,但是让我修饰一下。
    首先,16位整数的范围是-32768到32767(通常对16位音频进行签名)。要将int转换为float,请执行以下操作:
    float f;
    int16 i = ...;
    f = ((float) i) / (float) 32768
    if( f > 1 ) f = 1;
    if( f < -1 ) f = -1;
    
    通常,您不需要执行额外的“边界”操作(实际上,如果确实使用的是16位整数,则不需要这样做),但是如果您出于某些原因拥有一些> 16位整数,就可以使用它。
    要转换回去,您可以执行以下操作:
    float f = ...;
    int16 i;
    f = f * 32768 ;
    if( f > 32767 ) f = 32767;
    if( f < -32768 ) f = -32768;
    i = (int16) f;
    
    在这种情况下,通常需要注意超出范围的值,尤其是大于32767的值。您可能会提示说,这会导致f = 1产生一些失真。有关此问题的一些(不完整的)讨论,请参见this blog post
    这不仅仅是“足以胜任政府工作”。换句话说,除非您担心最终的声音质量,否则它将正常工作。由于您要达到8kHz,因此我认为事实并非如此,因此此答案很好。
    但是,为了完整起见,我必须添加以下内容:如果您要使事情绝对原始,请记住,这种转换会导致失真。为什么?因为从float转换为int时的误差与信号相关。事实证明,该错误的相关性非常糟糕,即使它很小,您实际上也可以听到。 (幸运的是,它足够小,对于语音和低动态范围的音乐来说,无关紧要)。要消除此错误,必须在从float到int的转换中使用称为dither的东西。同样,如果您对此很在意,请对其进行研究并在https://dsp.stackexchange.com/上询问相关的特定问题,而不是在此处。
    您可能也对我在数字音频编程基础上的幻灯片中的幻灯片感兴趣,该幻灯片也有关于此主题的幻灯片,尽管它基本上说的是同一件事(甚至比我刚才说的还要少):http://blog.bjornroche.com/2011/11/slides-from-fundamentals-of-audio.html

    关于java - 如何将字节数组中的pcm样本转换为-1.0到1.0范围内的 float 并返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15087668/

    相关文章:

    android - 在 ContentProvider 中关闭数据库

    c - 在 C 中处理大 float 据

    c++ - C++ 11:将 `double`打印为十六进制?

    java - Selenium 2(WebDriver) 还是 Geb?

    java - 阻止 Hibernate 在每次启动时尝试重新创建索引

    android - 如何使编辑文本 float 在工具栏和主布局的顶部

    python - Pandas 中的浮点索引的目的是什么?

    java - NoRouteToHostException 而 hadoop fs -copyFromLocal

    java - 使用 Clear 解析器进行语义角色标记

    android - TabHost 颜色在 Android 版本之间发生了变化