在我的一个项目中,我需要将 PCM 音频数据重新采样为不同的采样率。我正在使用 javax.sound.sampled.AudioSystem 来完成这项任务。重新采样似乎会在帧的开头和结尾添加额外的样本。下面是一个最小的工作示例:
import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Arrays; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem;
public class ResamplingTest {
public static void main(final String[] args) throws IOException { final int nrOfSamples = 4; final int bytesPerSample = 2; final byte[] data = new byte[nrOfSamples * bytesPerSample]; Arrays.fill(data, (byte) 10); final AudioFormat inputFormat = new AudioFormat(32000, bytesPerSample * 8, 1, true, false); final AudioInputStream inputStream = new AudioInputStream(new ByteArrayInputStream(data), inputFormat, data.length); final AudioFormat outputFormat = new AudioFormat(24000, bytesPerSample * 8, 1, true, false); final AudioInputStream outputStream = AudioSystem.getAudioInputStream(outputFormat, inputStream); final var resampledBytes = outputStream.readAllBytes(); System.out.println("Expected number of samples after resampling " + (int) (nrOfSamples * outputFormat.getSampleRate() / inputFormat.getSampleRate())); System.out.println("Actual number of samples after resampling " + resampledBytes.length / bytesPerSample); System.out.println(Arrays.toString(resampledBytes)); } }
我期望将从 32kHz 到 24kHz 重新采样的 4 个样本精确地变为 3 个样本。然而,上述代码生成了 5 个样本。额外样本的数量似乎取决于输入和输出采样率。例如,如果我将采样率从 8kHz 重新采样到 32kHz,则会生成额外的 8 个样本。为什么重新采样会添加额外的样本,我如何知道帧的开头和结尾添加了多少个样本?
问题翻译:
- 需要对 PCM 音频数据进行重新采样到不同的采样率,使用了
javax.sound.sampled.AudioSystem
类库。但重新采样后,似乎会在帧的开头和结尾添加额外的样本。提供了一个最小工作示例,期望从 32kHz 到 24kHz 重新采样的 4 个样本精确地变为 3 个样本,但实际生成了 5 个样本。为什么重新采样会添加额外的样本,如何知道帧的开头和结尾添加了多少个样本?
回答:
重新采样带来额外的样本是因为新采样速率可能不是旧采样速率的整数倍,会有样本之间的间距出现。这可能会导致重新采样后添加一些额外的样本,以适应新的采样速率。例如,如果您将 4 个样本从采样率为 32000 Hz 重新采样为采样率为 24000 Hz,则每秒钟必须输出更少的样本。如果在 32000 Hz 中有一个样本,它必须被分成 0.75 个样本(40毫秒/样本)来适应 24000 Hz 的输出。如果将其向上舍入,则会将其分成一个样本和 0.25 个样本,然后必须通过插入一个额外的样本来适应输出样本的整数数量。
要了解添加了多少个样本,需要知道采样率和输出后的采样长度。要计算需要多少个输出样本,可以使用以下公式:
outputSamples = inputSamples * outputSampleRate / inputSampleRate
在给定上面的例子之后,此公式变为:
outputSamples = 4 * 24000 / 32000 = 3
这意味着输出应该只有 3 个样本。但是,因为重新采样导致额外的 2 个样本被添加到输出中,因此最终样本数为 5。
为了知道帧的开头和结尾添加了多少个样本,您需要检查读取的数据中的前几个和最后几个样本是否与期望的值匹配。如果开头或结尾添加了额外的样本,则可以从读取的数据中看到这些样本。您还可以通过手动计算输出数组中的每个样本来确定哪些是额外添加的样本。
标签:Java ,音频 From: