制作程序化音频混音的有效方法

时间:2009-06-09 21:12:08

标签: iphone c performance audio

我目前正在使用音频单元处理iPhone,而我同时播放四首曲目。为了提高我的设置的性能,我认为通过将四个轨道混合为一个来最小化音频单元/线程的数量是个好主意。

使用以下代码我通过将四个轨道的样本相加来处理下一个缓冲区,将它们保存在SInt16范围内并将它们添加到临时缓冲区中,稍后将其复制到ioData.mBuffers中。音频单元。

虽然它有效但我并不认为这是最有效的方法。

SInt16* buffer = bufferToWriteTo; 
int reads      = bufferSize/sizeof(SInt16);         
SInt16** files = circularBuffer->files;

float tempValue;
SInt16 values[reads];
int k,j;                
int numFiles=4;

for (k=0; k<reads; k++)
{
    tempValue=0.f; 
    for (j=0; j<numFiles; j++) 
    {
        tempValue += files[j][packetNumber];        
    }
    if      (tempValue >  32767.f) tempValue =  32767.f;
    else if (tempValue < -32768.f) tempValue =- 32768.f;

    values[k]  = (SInt16) tempValue;
    values[k] += values[k] << 16;
    packetNumber++;
    if (packetNumber >= totalPackets) packetNumber=0;
}
memcpy(buffer,values,bufferSize); 

有什么想法或提示加快速度吗?我是对的吗?

3 个答案:

答案 0 :(得分:1)

虽然我对iPhone的开发并不熟悉,但还有几点需要注意。

你可以解开内循环。你不需要for循环来将4个数字加在一起,尽管你的编译器可能会为你做这个。

直接写入for循环中的缓冲区。末尾的memcpy将执行另一个循环来复制缓冲区。

不要使用浮动值来表示临时值。根据硬件整数,数学运算速度更快,并且您不需要使用浮点数来求和通道。

删除if / endif。无论如何,数字剪辑听起来都很糟糕,所以在将频道总结在一起之前尽量避免它。如果可能的话,应该避免在这样的循环内分支。

答案 1 :(得分:1)

您可以从此代码中获得的最大改进是不使用浮点运算。虽然算术本身很快,但嵌套循环中发生的转换需要很长时间,特别是在iPhone中的ARM处理器上。对于'tempValue'变量,使用'SInt32'而不是'float'可以获得完全相同的结果。

另外,看看你是否可以删除最后一个字符串中的memcpy():也许你可以直接构造'buffer',而不使用名为'values'的临时缓冲区。这样可以节省一份副本,这对于这样的功能来说是一个重大的改进。

其他注意事项:循环的最后两行可能属于循环之外,嵌套循环的主体应该使用'k'作为第二个索引,而不是'packetNumber',但我不确定这个逻辑。

最后一点:你正在挤压你产生的声音的高峰。虽然这似乎是一个好主意,但听起来相当粗糙。您可能希望缩小结果而不是裁剪结果。像那样:而不是这段代码

for (j=0; j<numFiles; j++) 
{
    tempValue += files[j][packetNumber];            
}
if      (tempValue >  32767.f) tempValue =  32767.f;
else if (tempValue < -32768.f) tempValue =- 32768.f;
你可能想要这样的东西:

for (j=0; j<numFiles; j++) 
{
    tempValue += files[j][packetNumber] / numFiles;            
}

编辑,请不要忘记衡量前后的效果,看看哪项改进产生了最大的影响。这是学习绩效的最佳方式:试验和测量

答案 2 :(得分:0)

我为我的应用程序编写音频混合例程时发现的一件事是增量指针的工作速度比索引快得多。有些编译器可能会对你进行排序,但是 - 不确定是否在iphone上 - 但是这肯定会给我的应用程序带来很大的提升,这些紧密的循环(如果我记得的话,大约30%)。

例如:而不是:

for (k=0; k<reads; k++)
{
    // Use buffer[k]
}

这样做:

SInt16* p=buffer;
SInt16* pEnd=buffer+reads;
while (p!=pEnd)
{
    // Use *p
    p++;
}

另外,我相信iPhone有一些称为VFP的SIMD(单指令多数据)支持。这可以让你在一条指令中对大量样本进行数学运算,但我对iPhone知之甚少。