如何使用 Java 中的声音 API 测量 .wav 文件特定时间戳处的声级?

How can the sound level at specific timestamps of a .wav file be measured using the Sound API in Java?

提问人:anti_waxxer 提问时间:11/12/2022 更新时间:11/13/2022 访问量:127

问:

搜索了 12 个多小时后,我找不到任何与此相关的内容。我能找到的就是如何使用声音 API 中的函数来测量和更改设备的音量,而不是 .wav 文件。如果有人能建议我们/告诉我们如何从 .wav 文件本身的特定时间戳获取和/或更改音量,那就太好了,非常感谢!

即使无法更改 .wav 文件本身的音频,我们至少需要知道如何在特定时间戳下测量音量。

Java 音频 javasound

评论

1赞 tgdavies 11/12/2022
您可以读取 .wav 文件并检查数据。您使用的“体积”定义是什么?
0赞 anti_waxxer 11/12/2022
如何读取 .wav 文件?对于定义,我的意思是声音有多大,以分贝或线性刻度(计算机提供的任何一种为单位)表示。
1赞 tgdavies 11/12/2022
请参阅 stackoverflow.com/questions/3297749/...

答:

0赞 Phil Freihofner 11/13/2022 #1

要处理声音信号的幅度,您必须检查 .wav 文件中保存的 PCM 数据。不幸的是,Java 没有公开 PCM 值。Java 通过类提供各个 PCM 数据值,但您必须按顺序读取数据点。Java 教程:使用文件和格式转换器中提供了代码示例。ClipAudioInputStream

以下是页面相关部分的引用:

假设您正在编写一个声音编辑应用程序,该应用程序允许 用户从文件中加载声音数据,显示相应的波形 或频谱图,编辑声音,播放编辑后的数据,然后保存 结果在一个新文件中。或者,也许您的程序将读取数据 存储在文件中,应用某种信号处理(例如 在不改变音高的情况下减慢声音的算法),以及 然后播放处理后的音频。无论哪种情况,您都需要获得访问权限 添加到音频文件中包含的数据。假设您的程序 为用户提供一些选择或指定输入声音的方法 文件,读取该文件的音频数据涉及三个步骤:

  1. 从文件中获取 AudioInputStream 对象。
  2. 创建一个字节数组,您将在其中存储文件中的连续数据块。
  3. 将音频输入流中的字节重复读取到数组中。在每次迭代中,对数组中的字节执行一些有用的操作 (例如,您可以播放它们、过滤它们、分析它们、显示它们 它们,或将它们写入另一个文件)。

以下代码片段概述了这些步骤:

int totalFramesRead = 0;
File fileIn = new File(somePathName);
// somePathName is a pre-existing string whose value was
// based on a user selection.
try {
  AudioInputStream audioInputStream = 
    AudioSystem.getAudioInputStream(fileIn);
  int bytesPerFrame = 
    audioInputStream.getFormat().getFrameSize();
    if (bytesPerFrame == AudioSystem.NOT_SPECIFIED) {
    // some audio formats may have unspecified frame size
    // in that case we may read any amount of bytes
    bytesPerFrame = 1;
  } 
  // Set an arbitrary buffer size of 1024 frames.
  int numBytes = 1024 * bytesPerFrame; 
  byte[] audioBytes = new byte[numBytes];
  try {
    int numBytesRead = 0;
    int numFramesRead = 0;
    // Try to read numBytes bytes from the file.
    while ((numBytesRead = 
      audioInputStream.read(audioBytes)) != -1) {
      // Calculate the number of frames actually read.
      numFramesRead = numBytesRead / bytesPerFrame;
      totalFramesRead += numFramesRead;
      // Here, do something useful with the audio data that's 
      // now in the audioBytes array...
    }
  } catch (Exception ex) { 
    // Handle the error...
  }
} catch (Exception e) {
  // Handle the error...
}

报价结束

在成为 PCM 之前,这些值本身需要另一个转换步骤。如果文件使用 16 位编码(最常见),则必须连接两个字节才能生成单个 PCM 值。对于两个字节,值的范围是从 -32778 到 32767(范围为 2^16)。

将这些值归一化为 -1 到 1 的范围是很常见的。这是通过使用分母中的 32767 或 32768 进行浮点除法来完成的。我真的不确定哪个更正确(或者完全正确有多重要)。我只是使用 32768 来避免在信号有任何数据点达到最小可能值时得到小于 -1 的结果。floats

我不完全清楚如何将 PCM 值转换为分贝。我认为这些公式可用于相对调整,例如,如果您想将音量降低 6 dBs。更改音量是将每个 PCM 值乘以与您希望进行的音量更改相匹配的所需系数的问题。

就测量给定点的体积而言,由于 PCM 信号值在 0 上来回曲折时范围很广,因此通常的操作是取许多 PCM 值的绝对值的平均值。该过程称为获取均方根。要包含在 RMS 计算中的值数可能会有所不同。我认为主要考虑因素是使滚动平均值中的值数量足够大,以便它们大于信号中包含的最低频率的周期。

HackAudio 网站上有一些很好的教程。此链接用于 RMS 计算