以 <50 毫秒的延迟一次播放 15 个音轨?
Playing 15 audio tracks at once with <50ms latency?
总而言之,我的问题是:是否有可能同时解码和播放 15 条有损压缩的音轨,延迟低于 50 毫秒且没有卡顿?
背景
我正在用纯 C 为我正在创建的游戏编写一个声音库。我希望同时播放多达 15 条音轨且延迟小于 50 毫秒。
截至目前,该库能够播放原始 PCM 文件(48000Hz 打包的 16 位样本),并且可以轻松地以 45 毫秒的延迟同时播放 15 种声音,而不会出现卡顿现象,并且 CPU 使用率极低。这是在我相对较旧的 Intel Q9300 + SSD 机器上。
尽管原始音频文件很大,但我扩充了我的库以支持使用 opusfile (https://mf4.xiph.org/jenkins/view/opus/job/opusfile-unix/ws/doc/html/index.html) 播放 OPUS 文件。我希望我仍然能够同时播放 15 种声音,而音频文件不会占用 200MB 以上的空间。我错了——我一次只能播放 3 或 4 首 OPUS 曲目,然后才能听到卡顿和其他缓冲区不足的症状。 CPU 与原始 PCM 播放相比,使用量也大大增加。
我还尝试使用 vorbisfile (http://www.xiph.org/vorbis/doc/vorbisfile/) 包括 VORBIS 支持。我认为也许即时解码 VORBIS 不会像 CPU 那样密集。 VORBIS 比 OPUS 好一点——我可以一次播放 5 或 6 个声音,然后才能听到卡顿(我想 VORBIS 确实更容易解码)——但这仍然远不及播放原始 PCM 文件。
在我深入研究低级 libvorbis/libopus API 并研究其他音频压缩格式之前,同时解码和播放 15 个有损压缩的音轨是否真的可行低于 50 毫秒的延迟并且在中低端台式计算机上没有卡顿?
如果有帮助,我的声音库目前大约每 15 毫秒调用一个函数,该函数基本上执行以下操作(为清楚起见省略了错误处理和 post 处理):
void onBufferUpdateNeeded(int numSounds, struct Sound *sounds,
uint16_t *bufferToUpdate, int numSamplesNeeded, uint16_t *tmpBuffer) {
int i, j;
memset(bufferToUpdate, 0, numSamplesNeeded * sizeof(uint16_t));
for (i = 0; i < numSounds; ++i) {
/* Seek to the specified sample number in the already-opened
file handle. The implementation of this depends on the file
type (vorbis, opus, raw PCM). */
seekToSample(sounds[i].fileHandle, sounds[i].currentSample);
/* Read numSamplesNeeded samples from the file handle into
tmpBuffer. */
readSamples(tmpBuffer, sounds[i].fileHandle, numSamplesNeeded);
/* Add the samples into the buffer. */
for (j = 0; j < numSamplesNeeded; ++j) {
bufferToUpdate[j] += tmpBuffer[j];
}
}
}
在此先感谢您的帮助!
听起来您已经知道自己问题的答案:没有。 通常,对于此类问题(尤其是与性能相关的查询),我唯一的建议是尝试一下,看看是否可行。但是您已经收集了该数据。
的确,perceptual/lossy 音频编解码器往往需要大量计算才能解码。听起来您想避免原始 PCM 的存储开销。在这种情况下,如果您可以安全地假设您将为您的应用程序保留足够的内存,您可以提前解码音频流,或使用一些缓存机制来处理内存限制。也许这可以卸载到不同的线程(因为你的问题中提到的 Q9300 CPU 是双核)。
否则,您将需要寻找计算要求较低的压缩器。您可能对 FLAC 感兴趣,它由与 Vorbis 和 Opus 相同的组织赞助。它是无损的,因此它不会像有损算法那样压缩得很好,但它的解码速度应该快得多。
如果仍然不合适,请在 this big list of ~150 audio codecs 上四处浏览,直到找到符合您标准的。由于您控制客户端软件,因此您有很多选择(与流式传输到 Web 浏览器相比)。
总而言之,我的问题是:是否有可能同时解码和播放 15 条有损压缩的音轨,延迟低于 50 毫秒且没有卡顿?
背景
我正在用纯 C 为我正在创建的游戏编写一个声音库。我希望同时播放多达 15 条音轨且延迟小于 50 毫秒。
截至目前,该库能够播放原始 PCM 文件(48000Hz 打包的 16 位样本),并且可以轻松地以 45 毫秒的延迟同时播放 15 种声音,而不会出现卡顿现象,并且 CPU 使用率极低。这是在我相对较旧的 Intel Q9300 + SSD 机器上。
尽管原始音频文件很大,但我扩充了我的库以支持使用 opusfile (https://mf4.xiph.org/jenkins/view/opus/job/opusfile-unix/ws/doc/html/index.html) 播放 OPUS 文件。我希望我仍然能够同时播放 15 种声音,而音频文件不会占用 200MB 以上的空间。我错了——我一次只能播放 3 或 4 首 OPUS 曲目,然后才能听到卡顿和其他缓冲区不足的症状。 CPU 与原始 PCM 播放相比,使用量也大大增加。
我还尝试使用 vorbisfile (http://www.xiph.org/vorbis/doc/vorbisfile/) 包括 VORBIS 支持。我认为也许即时解码 VORBIS 不会像 CPU 那样密集。 VORBIS 比 OPUS 好一点——我可以一次播放 5 或 6 个声音,然后才能听到卡顿(我想 VORBIS 确实更容易解码)——但这仍然远不及播放原始 PCM 文件。
在我深入研究低级 libvorbis/libopus API 并研究其他音频压缩格式之前,同时解码和播放 15 个有损压缩的音轨是否真的可行低于 50 毫秒的延迟并且在中低端台式计算机上没有卡顿?
如果有帮助,我的声音库目前大约每 15 毫秒调用一个函数,该函数基本上执行以下操作(为清楚起见省略了错误处理和 post 处理):
void onBufferUpdateNeeded(int numSounds, struct Sound *sounds,
uint16_t *bufferToUpdate, int numSamplesNeeded, uint16_t *tmpBuffer) {
int i, j;
memset(bufferToUpdate, 0, numSamplesNeeded * sizeof(uint16_t));
for (i = 0; i < numSounds; ++i) {
/* Seek to the specified sample number in the already-opened
file handle. The implementation of this depends on the file
type (vorbis, opus, raw PCM). */
seekToSample(sounds[i].fileHandle, sounds[i].currentSample);
/* Read numSamplesNeeded samples from the file handle into
tmpBuffer. */
readSamples(tmpBuffer, sounds[i].fileHandle, numSamplesNeeded);
/* Add the samples into the buffer. */
for (j = 0; j < numSamplesNeeded; ++j) {
bufferToUpdate[j] += tmpBuffer[j];
}
}
}
在此先感谢您的帮助!
听起来您已经知道自己问题的答案:没有。 通常,对于此类问题(尤其是与性能相关的查询),我唯一的建议是尝试一下,看看是否可行。但是您已经收集了该数据。
的确,perceptual/lossy 音频编解码器往往需要大量计算才能解码。听起来您想避免原始 PCM 的存储开销。在这种情况下,如果您可以安全地假设您将为您的应用程序保留足够的内存,您可以提前解码音频流,或使用一些缓存机制来处理内存限制。也许这可以卸载到不同的线程(因为你的问题中提到的 Q9300 CPU 是双核)。
否则,您将需要寻找计算要求较低的压缩器。您可能对 FLAC 感兴趣,它由与 Vorbis 和 Opus 相同的组织赞助。它是无损的,因此它不会像有损算法那样压缩得很好,但它的解码速度应该快得多。
如果仍然不合适,请在 this big list of ~150 audio codecs 上四处浏览,直到找到符合您标准的。由于您控制客户端软件,因此您有很多选择(与流式传输到 Web 浏览器相比)。