Эффективный способ сделать программное микширование звука - PullRequest
2 голосов
/ 10 июня 2009

Я сейчас работаю на iPhone с Аудиоустройствами , и я одновременно играю четыре трека . Чтобы улучшить производительность моей установки, я подумал, что было бы неплохо минимизировать количество аудиоустройств / потоков, сведя четыре трека в один .

С помощью следующего кода я обрабатываю следующий буфер, складывая сэмплы четырех дорожек, сохраняя их в диапазоне SInt16 и добавляя их во временный буфер, который позже будет скопирован в ioData.mBuffers of Аудиоустройство.

Хотя это работает, У меня нет впечатления, что это самый эффективный способ сделать это.

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 ]

1 голос
/ 10 июня 2009

Самое большое улучшение, которое вы можете получить из этого кода, - это не использовать арифметику с плавающей запятой. Хотя арифметика сама по себе быстрая, преобразования, которые происходят во вложенных циклах, занимают много времени, особенно на процессоре ARM в iPhone. Вы можете достичь точно таких же результатов, используя 'SInt32' вместо 'float' для переменной 'tempValue'.

Также посмотрите, можете ли вы избавиться от 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;            
}

Изменить: и, пожалуйста, не забудьте измерить производительность до и после, чтобы увидеть, какое из улучшений дало наибольшее влияние. Это лучший способ узнать производительность: испытание и измерение

1 голос
/ 10 июня 2009

Несколько советов, хотя я не очень знаком с разработкой iPhone.

Вы можете размотать внутренний цикл. Вам не нужен цикл for для сложения 4 чисел, хотя, возможно, ваш компилятор сделает это за вас.

Пишите прямо в буфер вашего цикла for. memcpy в конце сделает еще один цикл для копирования буферов.

Не используйте float для tempvalue. В зависимости от аппаратного обеспечения целочисленная математика выполняется быстрее, и для суммирования каналов вам не нужны числа с плавающей точкой.

Удалите if / endif. Цифровое обрезание в любом случае будет звучать ужасно, поэтому постарайтесь избежать этого, прежде чем суммировать каналы вместе. По возможности следует избегать разветвления внутри такой петли.

0 голосов
/ 12 июня 2009

Одна вещь, которую я обнаружил при написании подпрограмм микширования звука для моего приложения, заключается в том, что увеличенные указатели работают намного быстрее, чем индексирование. Некоторые компиляторы могут решить это за вас, но - не уверен на 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 есть какая-то поддержка SIMD (одна инструкция с несколькими данными), называемая VFP. Это позволило бы вам выполнять математику с несколькими образцами в одной инструкции, но я мало что знаю об этом на iPhone.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...