SourceDataLine 帧率加倍

SourceDataLine doubling framerate

根据我的研究,我似乎找不到任何其他人有同样的问题,这让我相信我只是在犯下邪恶的愚蠢行为。尽管如此,我正在使用 Java 采样声音 API 并尝试播放一个简单的 440Hz 正弦波 5 秒。然而,似乎 SourceDataLine 正在以其给定 AudioFormat 帧速率两倍的速度消耗帧。我使用的样本是:

AudioFormat audioFormat = new AudioFormat(
    AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 22050, false);
SourceDataLine outLine;

int bufferByteLength = 4096;
byte[] b = new byte[4];
final float framePeriod = 1.0f / audioFormat.getFrameRate();
int frame = 0;

outLine = AudioSystem.getSourceDataLine(audioFormat);
outLine.open(audioFormat, bufferByteLength);
outLine.start();

System.out.println("Format: " + audioFormat);

double begin = System.nanoTime();
while((frame * framePeriod) < 5){
    short sample = (short)(0.2 * Math.sin(2 * Math.PI * 440 * frame * framePeriod) * Short.MAX_VALUE);
    b[0] = (byte)(sample & 0xFF);
    b[1] = (byte)((sample >> 8) & 0xFF);
    b[2] = (byte)(sample & 0xFF);
    b[3] = (byte)((sample >> 8) & 0xFF);
    ++frame;
    outLine.write(b, 0, 4);
}
double end = System.nanoTime();

System.out.println("True elapsed (seconds): " + (end - begin) * 1e-9);
System.out.println("Line reported elapsed (seconds): " + outLine.getMicrosecondPosition() * 1e-6);

outLine.drain();
outLine.stop();
outLine.close();

在我的机器上打印出来

Format: PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, 22050.0 frames/second, little-endian
True elapsed (seconds): 2.5011672000000003
Line reported elapsed (seconds): 4.901496

所以正如 880Hz 音高所预期的那样,线条确实以两倍的速度通过帧。我觉得这特别奇怪,因为我清楚地写了单帧所需的 4 个字节,但它似乎需要 8 个字节?事实上,当我使用大小为 8 的 b(并扩展为写入 8 个字节)时,它确实将音高降低到 440Hz,并且奇怪的是不会引起任何“砰砰声”,即使 [= 中的后 4 个字节也是如此14=] 始终为 0。

我注意到的一件有趣的事情是,该行需要 1764 或更高的缓冲区大小,否则它会非常卡顿并使有效帧率显着低于预期的 22050。不过,我希望这是比什么都更 CPU 依赖。

我很纳闷。我不知道是什么原因造成的,所以我希望外面的人以前遇到过这个问题,或者可以提供任何线索来解释为什么会这样。干杯。

您指定的采样率是帧速率的两倍,因此它需要两倍的采样数。这两个速率对于 PCM 通常是相同的。

采样率是每个通道的,而不是所有通道的总和。