3

我正在编写一个需要使用大型音频多样本的应用程序,通常大小约为 50 mb。一个文件包含大约 80 个单独的短录音,我的应用程序可以随时播放这些录音。出于这个原因,所有的音频数据都被加载到内存中以便快速访问。

但是,当加载其中一个文件时,可能需要几秒钟才能放入内存,这意味着我的程序如果暂时冻结。有什么好的方法可以避免这种情况发生?它必须与 Windows 和 OS X 兼容。它冻结在此:myMultiSampleClass->open();必须执行大量动态内存分配并使用 ifstream 从文件中读取。

我想到了两种可能的选择:

  1. 打开文件并将其加载到另一个线程的内存中,这样我的应用程序进程就不会冻结。我已经研究了 Boost 库来做到这一点,但在我准备好实施之前需要做很多阅读。我需要做的就是在线程中调用 open() 函数,然后销毁线程。

  2. 想出一个方案来确保我不会在任何时候将整个文件加载到内存中,我只是动态加载可以这么说。问题是任何样本都可能随时被触发。我知道其他一些软件有这种系统,但我不确定它是如何工作的。这在很大程度上取决于个人计算机的规格,它可以在我的计算机上运行良好,但硬盘/内存速度较慢的人可能会得到非常糟糕的结果。我的一个想法是将每个音频记录的 x 个样本加载到内存中,然后如果我需要播放,开始播放已经存在的样本,同时将其余音频加载到内存中。

有什么想法或批评吗?提前致谢 :-)

4

4 回答 4

1

使用内存映射文件。加载时间最初是“即时的”,I/O 的开销会随着时间的推移而分散。

于 2010-03-03T17:04:32.340 回答
0

您可能需要考虑生产者-消费者方法。这基本上涉及使用一个线程将声音数据读入缓冲区,并使用另一个线程将数据从缓冲区流式传输到您的声卡。

数据读取器是生产者,将数据流式传输到声卡是消费者。您需要高水位和低水位标记,这样,如果缓冲区已满,生产者将停止读取,如果缓冲区变低,生产者将再次开始读取。

一个 C++ 生产者-消费者并发模板库
http://www.bayimage.com/code/pcpaper.html

编辑:我应该补充一点,这种事情很棘手。如果您正在构建一个示例播放器,系统上的负载会随着正在播放的琴键、一次播放的声音数量、每个声音的持续时间、是否踩下延音踏板而不断变化,以及其他因素,例如硬盘速度和缓冲,以及可用的处理器马力。您最终采用的一些编程优化乍一看并不明显。

于 2010-03-03T16:43:09.793 回答
0

我喜欢解决方案 1 作为第一次尝试——简单且切中要害。

如果你在 Windows 下,你可以执行异步文件操作——他们称之为 OVERLAPPED——告诉操作系统加载一个文件并让你知道它什么时候准备好。

于 2010-03-03T16:47:22.653 回答
0

我认为最好的解决方案是在播放期间使用异步 I/O(如 John Dibling 提到的)一次将一小块或单个波形数据样本加载到固定大小的播放缓冲区。

该策略将先填充播放缓冲区然后播放(这会增加少量延迟但保证连续播放),在播放缓冲区时,您可以在不同的线程(重叠)上重新填充另一个播放缓冲区,至少您需要有两个播放缓冲区,一个用于播放,一个用于后台填充,然后实时切换

稍后您可以根据客户端 PC 性能设置播放缓冲区大小(这将在内存大小和处理能力之间进行权衡,最快的 CPU 将需要更小的缓冲区,从而降低延迟)。

于 2010-03-04T08:45:44.687 回答