2009-06-09 2 views
2

Я сейчас работаю на iPhone с Аудиоустройства и я , одновременно играющий на четырех дорожках. Для улучшить производительность моей установки, я подумал, что было бы неплохо свести к минимуму количество аудио-единиц/потоков, используя , смешивая четыре трека в одном.Эффективный способ создания программного аудио Mixdown

С помощью следующего кода я обрабатываю следующий буфер, добавляя образцы четырех дорожек, сохраняя их в диапазоне 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

Самое большое улучшение, которое вы можете получить от этого кода, было бы не использовать арифметику с плавающей запятой. Хотя арифметика сама по себе быстро, преобразования, которые происходят в вложенных циклах, занимают много времени, особенно на процессоре 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;    
} 

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

+0

Спасибо! Эти советы помогли. :) – Kriem

+0

memcopy, определенно. :) – Kriem

+0

Итак, как выглядел окончательный оптимизированный код микширования? – coneybeare

1

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

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

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

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

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

+0

Спасибо за советы! Написание директивы в буфере было хорошим. Тем не менее, я считаю, что математика с плавающей запятой выполняется быстрее на iPhone. – Kriem

+0

Математика может быть быстрой, но переходы из int в float и обратно могут быть медленными. Но Рим уже сказал вам об этом. Просто попробуйте и оцените :-) Профилирование всегда лучше, чем говорить о производительности. – Mendelt

+0

Я вижу. Попробуй это. Благодарю. – Kriem

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