制作程序化音频混音的有效方法
Posted
技术标签:
【中文标题】制作程序化音频混音的有效方法【英文标题】:Efficient way to make a Programmatic Audio Mixdown 【发布时间】:2009-06-09 21:12:07 【问题描述】:我目前正在使用 Audio Units 开发 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);
有什么想法或建议可以加快速度吗?我说的对吗?
【问题讨论】:
【参考方案1】:您可以从此代码中获得的最大改进是不使用浮点运算。虽然算法本身很快,但在嵌套循环中发生的转换需要很长时间,尤其是在 iPhone 的 ARM 处理器上。您可以通过对“tempValue”变量使用“SInt32”而不是“float”来获得完全相同的结果。
另外,看看你是否可以摆脱最后一个字符串中的 memcpy():也许你可以直接构造“缓冲区”,而不使用名为“值”的临时缓冲区。这样可以节省一份副本,对于这样的功能来说,这将是一个显着的改进。
其他注意事项:循环的最后两行可能属于循环之外,嵌套循环的主体应使用“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】:尽管我对 iPhone 开发不是很熟悉,但请给我一些建议。
您可以展开内部循环。您不需要 for 循环来将 4 个数字相加,尽管您的编译器可能会为您执行此操作。
在 for 循环中直接写入缓冲区。最后的 memcpy 将执行另一个循环来复制缓冲区。
不要对 tempvalue 使用浮点数。取决于硬件整数数学更快,你不需要对通道求和的浮点数。
删除 if/endif。无论如何,数字削波听起来很可怕,所以在将通道加在一起之前尽量避免它。如果可能的话,应该避免在这样的循环内分支。
【讨论】:
感谢您的提示!直接写入缓冲区是一个不错的选择。尽管如此,我相信 iPhone 上的浮点数学运算速度更快。 数学运算可能很快,但从 int 到 float 再返回的转换可能很慢。但是罗姆已经告诉过你了。试一试并衡量 :-) 分析总是比谈论性能更好。 我明白了。会尝试的。谢谢。【参考方案3】:在为我的应用程序编写音频混合例程时,我发现一件事是递增指针的工作速度比索引快得多。一些编译器可能会为您解决这个问题,但 - 在 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 上对此知之甚少。
【讨论】:
以上是关于制作程序化音频混音的有效方法的主要内容,如果未能解决你的问题,请参考以下文章
最实用的虚拟声卡-Windows安装虚拟声卡(有效解决PR音频输入,AU录音,obs多音频原控制等问题)
最实用的虚拟声卡-Windows安装虚拟声卡(有效解决PR音频输入,AU录音,obs多音频原控制等问题)