将大型多样本音频文件加载到内存中进行播放 - 如何避免临时冻结

时间:2010-03-03 16:39:17

标签: c++ audio memory-management sampling

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

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

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

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

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

  3. 任何想法或批评?在此先感谢: - )

4 个答案:

答案 0 :(得分:1)

使用memory mapped file。加载时间最初是“即时”的,I / O的开销将随着时间的推移而扩散。

答案 1 :(得分:0)

您可能需要考虑producer-consumer方法。这主要涉及使用一个线程将声音数据读入缓冲区,并使用另一个线程将数据从缓冲区传输到声卡。

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

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

编辑:我应该补充一点,这类事情很棘手。如果您正在构建一个样本播放器,系统上的负载会根据正在播放的键,一次播放的声音,每个声音的持续时间,持续踏板是否被按下的持续时间而不断变化,和其他因素,如硬盘速度和缓冲,以及可用的处理器马力。最初使用的一些编程优化乍一看并不明显。

答案 2 :(得分:0)

我喜欢解决方案1作为第一次尝试 - 简单&到了这一点。

如果你在Windows下,你可以进行异步文件操作 - what they call OVERLAPPED - 告诉操作系统加载文件&让它知道什么时候准备就绪。

答案 3 :(得分:0)

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

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

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