微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SourceDataLine 帧率翻倍

如何解决SourceDataLine 帧率翻倍

从我的研究来看,我似乎找不到其他人有同样的问题,这让我相信我只是犯了一种不圣洁的愚蠢。尽管如此,我正在使用 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,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 个字节1}} 总是 0。

我注意到的一件有趣的事情是,该行需要 1764 或更高的缓冲区大小,否则它会非常明显地断断续续,并使有效帧率显着低于预期的 22050。不过,我预计这会占用更多 cpu依赖比什么都重要。

我很困惑。我不知道是什么原因导致了这种情况,所以我希望有人以前遇到过这个问题,或者可以提供有关为什么会发生这种情况的任何线索。干杯。

解决方法

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。