提问人:anti_waxxer 提问时间:11/12/2022 更新时间:11/13/2022 访问量:127
如何使用 Java 中的声音 API 测量 .wav 文件特定时间戳处的声级?
How can the sound level at specific timestamps of a .wav file be measured using the Sound API in Java?
问:
搜索了 12 个多小时后,我找不到任何与此相关的内容。我能找到的就是如何使用声音 API 中的函数来测量和更改设备的音量,而不是 .wav 文件。如果有人能建议我们/告诉我们如何从 .wav 文件本身的特定时间戳获取和/或更改音量,那就太好了,非常感谢!
即使无法更改 .wav 文件本身的音频,我们至少需要知道如何在特定时间戳下测量音量。
答:
要处理声音信号的幅度,您必须检查 .wav 文件中保存的 PCM 数据。不幸的是,Java 没有公开 PCM 值。Java 通过类提供各个 PCM 数据值,但您必须按顺序读取数据点。Java 教程:使用文件和格式转换器中提供了代码示例。Clip
AudioInputStream
以下是页面相关部分的引用:
假设您正在编写一个声音编辑应用程序,该应用程序允许 用户从文件中加载声音数据,显示相应的波形 或频谱图,编辑声音,播放编辑后的数据,然后保存 结果在一个新文件中。或者,也许您的程序将读取数据 存储在文件中,应用某种信号处理(例如 在不改变音高的情况下减慢声音的算法),以及 然后播放处理后的音频。无论哪种情况,您都需要获得访问权限 添加到音频文件中包含的数据。假设您的程序 为用户提供一些选择或指定输入声音的方法 文件,读取该文件的音频数据涉及三个步骤:
- 从文件中获取 AudioInputStream 对象。
- 创建一个字节数组,您将在其中存储文件中的连续数据块。
- 将音频输入流中的字节重复读取到数组中。在每次迭代中,对数组中的字节执行一些有用的操作 (例如,您可以播放它们、过滤它们、分析它们、显示它们 它们,或将它们写入另一个文件)。
以下代码片段概述了这些步骤:
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 计算。
上一个:使用 Java API 将声音输入链接到特定输出设备
下一个:无法播放剪辑声音
评论