2010-09-22 6 views
9

¿Cuáles son las formas correctas de inicializar (asignar memoria) y liberar (liberar) un AudioBufferList con 3 AudioBuffers? (Soy consciente de que puede haber más de una forma de hacerlo.)iPhone: inicio y lanzamiento de AudioBufferList

Me gustaría usar esos 3 buffers para leer partes secuenciales de un archivo de audio en ellos y reproducirlos con Audio Units.

Respuesta

15

Aquí es cómo lo hago:

AudioBufferList * 
AllocateABL(UInt32 channelsPerFrame, UInt32 bytesPerFrame, bool interleaved, UInt32 capacityFrames) 
{ 
    AudioBufferList *bufferList = NULL; 

    UInt32 numBuffers = interleaved ? 1 : channelsPerFrame; 
    UInt32 channelsPerBuffer = interleaved ? channelsPerFrame : 1; 

    bufferList = static_cast<AudioBufferList *>(calloc(1, offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * numBuffers))); 

    bufferList->mNumberBuffers = numBuffers; 

    for(UInt32 bufferIndex = 0; bufferIndex < bufferList->mNumberBuffers; ++bufferIndex) { 
     bufferList->mBuffers[bufferIndex].mData = static_cast<void *>(calloc(capacityFrames, bytesPerFrame)); 
     bufferList->mBuffers[bufferIndex].mDataByteSize = capacityFrames * bytesPerFrame; 
     bufferList->mBuffers[bufferIndex].mNumberChannels = channelsPerBuffer; 
    } 

    return bufferList; 
} 
11

En primer lugar, creo que realmente quiere 3 AudioBufferLists, no una AudioBufferList con 3 miembros de AudioBuffer. Un AudioBuffer representa un único canal de datos, por lo que si tiene 3 archivos de audio estéreo, debe ponerlos en 3 AudioBufferLists, con cada lista con 2 AudioBuffers, un buffer para el canal izquierdo y uno para el derecho. Su código luego procesaría cada lista (y sus respectivos datos de canal) por separado, y podría almacenar las listas en un NSArray o algo así.

Técnicamente, no hay razón por la que no se puede tener una sola lista de buffers con 3 canales de audio intercalados (lo que significa que tanto el & canal de la derecha, dejando se almacenan en una única memoria intermedia de datos), pero esto va en contra del uso convencional de la API y será un poco confuso.

De todos modos, esta parte de la API CoreAudio es más C-ish que Objective-C-ish, por lo que utilizaría malloc/free en lugar de alloc/release. El código sería algo como esto:

#define kNumChannels 2 
AudioBufferList *bufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList) * kNumChannels); 
bufferList->mNumberBuffers = kNumChannels; // 2 for stereo, 1 for mono 
for(int i = 0; i < 2; i++) { 
    int numSamples = 123456; // Number of sample frames in the buffer 
    bufferList->mBuffers[i].mNumberChannels = 1; 
    bufferList->mBuffers[i].mDataByteSize = numSamples * sizeof(Float32); 
    bufferList->mBuffers[i].mData = (Float32*)malloc(sizeof(Float32) * numSamples); 
} 

// Do stuff... 

for(int i = 0; i < 2; i++) { 
    free(bufferList->mBuffers[i].mData); 
} 
free(bufferList); 

El código anterior supone que está leyendo en los datos como coma flotante. Si no está realizando ningún procesamiento especial en los archivos, es más eficiente leerlos como SInt16 (datos PCM en bruto), ya que el iPhone no tiene una FPU.

Además, si no está utilizando las listas fuera de un único método, entonces tiene más sentido asignarlas en la pila en lugar del montón al declararlo como un objeto normal, no como un puntero. Aún necesita malloc() el miembro real de mData del AudioBuffer, pero al menos no necesita preocuparse por la libre() de la propia AudioBufferList.

+0

Gracias. Entonces, si tengo canales de audio intercalados, debería crear 3 AudioBufferLists separados con un solo AudioBuffer en ellos, ¿verdad? Pero entonces, ¿de qué sirve usar AudioBufferLists? Si entiendo lo que dice correctamente, estaría mejor con 3 AudioBuffers (y sin AudioBufferLists), en este caso al menos. –

+1

Sí, eso sería correcto. El objetivo de utilizar AudioBufferLists es facilitar la gestión de datos multicanal, ya que los datos entrelazados suelen ser un verdadero dolor para las operaciones DSP. Es mucho mejor tener canales estéreo separados con cada canal en su propio búfer. Imagine trabajar con una señal estéreo de 4.1, ¡entonces tendría un solo buffer con 5 canales entrelazados! No es demasiado divertido trabajar con él. –

+1

Ah, pero no dije que no usara AudioBufferLists por completo. Aunque pueda parecer una tontería pasar un solo AudioBuffer dentro de una AudioBufferList, son mucho más fáciles de pasar dentro de la API de CoreAudio. Además, la estructura de AudioBufferList no impone mucha sobrecarga de memoria. –

Cuestiones relacionadas