【问题标题】:Converting the sample rate on-the-fly when reading a WAV file into a samples array with Java使用 Java 将 WAV 文件读入样本数组时即时转换采样率
【发布时间】:2011-01-17 13:49:06
【问题描述】:

我有一组简短的 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)的这种转换。而且我想避免对任何外部库的依赖。有没有办法自己做采样率转换?

【问题讨论】:

    标签: java windows audio signal-processing javasound


    【解决方案1】:

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

    【讨论】:

    • 如何计算截止频率?为什么这一步是必要的?
    • 过滤是必要的,因为奈奎斯特效应。简而言之:如果您的 sr 是 11025 赫兹,并且您的输入中有 5572.5 赫兹的音调,那么它将被再现为 60 赫兹的音调。 Nyquist wrap 是完全非谐波的(翻译:听起来真的很丑很糟糕)。您需要过滤掉新 sr 一半以上的所有输入,以消除奈奎斯特噪声。
    • “过滤所有输入超过一半的新 sr”我的意思是确保高于该频率的内容为零 - 过滤量和切断位置可能因来源而异材料 - 听听结果,如果您的滤波器需要更陡峭或需要更低的截止频率,添加的噪音会很明显。
    • 嘿,保罗,请你看看我非常相似的问题stackoverflow.com/questions/51128347/…
    【解决方案2】:

    我相信接受的答案回答了另一个问题——它解决了同样的问题(对音频进行下采样),但以另一种方式(手动而不是使用 java 声音 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 文件后,一切正常(只是一个额外的警告:如果您想同时更改通道数和采样率,仍然不支持一步)。

    【讨论】:

    • 克劳德请你看看我有一个非常相似的问题stackoverflow.com/questions/51128347/…,我正在寻找答案......
    • @GOXR3PLUS 恐怕我已经好几年没有检查 java 声音库了,我希望帮不上什么忙。对不起
    • 它实际上并没有太大变化,几乎什么都没有,只是我需要你在这个答案中使用的代码,我已经添加了 2 个库:)
    猜你喜欢
    • 2016-02-01
    • 2020-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多