使用 Java 将 WAV 文件读取到样本数组时即时转换采样率

发布于 2024-08-21 08:35:04 字数 2044 浏览 2 评论 0原文

我有一个短 WAV 文件的集合,我想使用各种数字信号处理算法在 Java 中对其进行处理。为此,我需要获取一个 int 值样本数组,以 11025 Hz 帧速率进行编码。

源文件有多种不同的采样率,包括 11025 Hz 和 44100 Hz。这是我试图用来读取它们的代码:

// read the WAV file
FileInputStream fileInputStream = new FileInputStream(new File("test.wav"));
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(fileInputStream );

// copy the AudioInputStream to a byte array called buffer
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] data = new byte[4096];
int tempBytesRead = 0;
int byteCounter = 0;
while ((tempBytesRead = audioInputStream.read(data, 0, data.length)) != -1) {
  bos.write(data, 0, tempBytesRead);
            byteCounter += tempBytesRead;
}
bos.close();
byte[] buffer = bos.toByteArray();

AudioFileFormat audioFileFormat = new AudioFileFormat(AudioFileFormat.Type.WAVE, audioInputStream.getFormat(), (int)audioInputStream.getFrameLength());

// get the resulting sample array
int[] samples = new int[audioFileFormat.getFrameLength()];
for (int i = 0; i < samples.length; i++) {
  samples[i] = getSampleValue(i); // the getSampleValue method reads the sample values from the "buffer" array, handling different encoding types like PCM unsigned/signed, mono/stereo, 8 bit/16 bit
}

// RESULT: the "samples" array

问题是,代码不能正确处理不同的采样率。因此,对于 44100 Hz 帧速率,我获得的样本数量是 11025 Hz 帧速率的四倍。我希望生成的示例数组使用 11025 Hz 帧速率,而不管源文件的帧速率如何。在读取 AudioInputStream 时,我尝试强制 Java 为我转换帧速率,但出现类似于以下内容的异常:

java.lang.IllegalArgumentException: Unsupported conversion: PCM_SIGNED 11025.0 Hz, 16 bit, mono, 2 bytes/frame, 44100.0 frames/second, little-endian from PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian
    at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:955)

我阅读了 Java Sound API 教程: http://java.sun.com/docs/books/tutorial/sound/converters.html。看来Java Sound API不支持我的操作系统(Windows 7)的这种转换。我想避免对任何外部库的依赖。有什么办法可以自己进行采样率转换吗?

I've got a collection of short WAV files that I would like to process in Java using various digital signal processing algorithms. I need to get an array of int valued samples for this purpose, encoded at the 11025 Hz frame rate.

The source files have several different sample rates, including 11025 Hz and 44100 Hz. Here's the code I'm trying to use to read them:

// read the WAV file
FileInputStream fileInputStream = new FileInputStream(new File("test.wav"));
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(fileInputStream );

// copy the AudioInputStream to a byte array called buffer
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] data = new byte[4096];
int tempBytesRead = 0;
int byteCounter = 0;
while ((tempBytesRead = audioInputStream.read(data, 0, data.length)) != -1) {
  bos.write(data, 0, tempBytesRead);
            byteCounter += tempBytesRead;
}
bos.close();
byte[] buffer = bos.toByteArray();

AudioFileFormat audioFileFormat = new AudioFileFormat(AudioFileFormat.Type.WAVE, audioInputStream.getFormat(), (int)audioInputStream.getFrameLength());

// get the resulting sample array
int[] samples = new int[audioFileFormat.getFrameLength()];
for (int i = 0; i < samples.length; i++) {
  samples[i] = getSampleValue(i); // the getSampleValue method reads the sample values from the "buffer" array, handling different encoding types like PCM unsigned/signed, mono/stereo, 8 bit/16 bit
}

// RESULT: the "samples" array

The problem is, that the code doesn't handle different sample rates properly. So for the 44100 Hz frame rate I get four times as many samples as for the 11025 Hz frame rate. I would like the resulting sample array to use the 11025 Hz frame rate, regardless of the frame rate of the source file. I tried to force Java to convert the frame rate for me when reading the AudioInputStream, but I get an exception similar to the following one:

java.lang.IllegalArgumentException: Unsupported conversion: PCM_SIGNED 11025.0 Hz, 16 bit, mono, 2 bytes/frame, 44100.0 frames/second, little-endian from PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian
    at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:955)

I read the Java Sound API tutorial: http://java.sun.com/docs/books/tutorial/sound/converters.html. It seems that the Java Sound API doesn't support this kind of conversion of my operating system (Windows 7). And I would like to avoid dependencies on any external libraries. Is there any way to do the sampling rate conversion on my own?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

剑心龙吟 2024-08-28 08:35:04

对于采样率> 11025 Hz 您需要下采样,这是一个两阶段的过程。首先,您需要进行低通滤波器以满足奈奎斯特准则,然后您可以进行抽取,例如,对于 44.1 kHz 采样率数据,您需要进行截止频率为 5.5 kHz 的低通滤波器,然后您可以丢弃 3 个输出每 4 个样本的下采样率为 4:1。您需要为您想要支持的每个下采样比率使用不同的过滤器。

For sample rates > 11025 Hz you need to downsample, which is a two stage process. First you need to low pass filter to satisfy the Nyquist criterion, and then you can decimate, e.g. for 44.1 kHz sample rate data you would need to low pass filter with a cut-off frequency of 5.5 kHz and then you can throw away 3 out of every 4 samples for a 4:1 downsampling ratio. You'll need a different filter for each downsampling ratio that you want to support.

梦幻的心爱 2024-08-28 08:35:04

我相信接受的答案回答了另一个问题——它解决了同样的问题(对音频进行下采样),但以另一种方式(手动而不是使用 java sound API)。我也有同样的事情并深入研究。

执行此操作的正确方法(或 java sound API 方法)确实是(如 http://docs .oracle.com/javase/tutorial/sound/converters.html

AudioFormat outDataFormat = new AudioFormat((float) 8000.0, (int) 8, (int) 1, true, false);
AudioInputStream lowResAIS = AudioSystem.getAudioInputStream(outDataFormat, inFileAIS);

问题是标准java不附带重采样(甚至立体声-单声道转换)代码(或者至少不在代码的那部分中) -- 请参阅http://www.jsresources.org/faq_audio.html#convert_sample_rate)。

jsresources 页面也指出了答案:只需安装 2 个插件即可。最简单的方法是将这些插件安装在 Extensions 目录中,在 OSX Lion 上,这可以解决问题(前提是您有 wget):

wget http://www.tritonus.org/tritonus_share-0.3.6.jar -O /Library/Java/Extensions/tritonus_share-0.3.6.jar
wget http://www.tritonus.org/tritonus_remaining-0.3.6.jar -O /Library/Java/Extensions/tritonus_remaining-0.3.6.jar

添加这 2 个 jar 文件后,一切正常(只有一个额外的警告:如果您想更改两个文件的数量)通道和采样率,但仍然不支持作为一步)。

I believe the accepted answer answers another question -- it solves the same problem (downsampling the audio) but in another way (manually in stead of using the java sound API). I had the same thing and dug into it.

The correct way (or java sound API way) to do this is indeed (as suggested in http://docs.oracle.com/javase/tutorial/sound/converters.html)

AudioFormat outDataFormat = new AudioFormat((float) 8000.0, (int) 8, (int) 1, true, false);
AudioInputStream lowResAIS = AudioSystem.getAudioInputStream(outDataFormat, inFileAIS);

Problem is that standard java doesn't ship with resampling (or even stereo-mono conversion) code (or at least not in that part of the code -- see http://www.jsresources.org/faq_audio.html#convert_sample_rate).

The jsresources pages point to the answers as well: simply installing 2 plugins does the trick. Easiest is to install these plugins in the Extensions directory, on OSX Lion this will do the trick (provided you have wget):

wget http://www.tritonus.org/tritonus_share-0.3.6.jar -O /Library/Java/Extensions/tritonus_share-0.3.6.jar
wget http://www.tritonus.org/tritonus_remaining-0.3.6.jar -O /Library/Java/Extensions/tritonus_remaining-0.3.6.jar

After adding these 2 jar files, everything worked (just one extra warning: if you want to change both the number of channels and the sample rate, it's still not supported as one step).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文