2010-09-22 12 views
9

Quali sono i modi corretti per inizializzare (allocare memoria) e rilasciare (liberare) una Lista AudioBuffer con 3 AudioBuffer? (Sono consapevole che potrebbero esserci più di un modo per farlo.)iPhone: AudioBufferList init e release

Mi piacerebbe utilizzare questi 3 buffer per leggere parti sequenziali di un file audio e riprodurli utilizzando Audio Units.

risposta

15

Ecco come lo faccio:

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

Prima di tutto, penso che in realtà desideri 3 elenchi AudioBuffer, non un elenco AudioBuffer con 3 membri AudioBuffer. Un AudioBuffer rappresenta un singolo canale di dati, quindi se hai 3 file audio stereo, dovresti inserirli in 3 elenchi AudioBuffer, con ciascun elenco con 2 AudioBuffer, un buffer per il canale sinistro e uno per il diritto. Il tuo codice elaborerebbe quindi ogni lista (e i suoi rispettivi dati di canale) separatamente, e potresti memorizzare gli elenchi in un NSArray o qualcosa del genere.

Tecnicamente, non c'è ragione per cui non si può avere un unico elenco buffer con 3 canali audio interfogliati (nel senso che sia la sinistra & canale destro vengono memorizzati in un singolo buffer di dati), ma questo va contro l'uso convenzionale di l'API e sarà un po 'confuso.

In ogni caso, questa parte dell'API CoreAudio è più C-ish di Objective-C-ish, quindi si dovrebbe usare malloc/free invece di alloc/release. Il codice dovrebbe essere simile a questa:

#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); 

Il codice di cui sopra è supponendo che si sta leggendo i dati come virgola mobile. Se non si sta eseguendo alcuna elaborazione speciale sui file, è più efficiente leggerli come SInt16 (dati PCM non elaborati), poiché l'iPhone non ha una FPU.

Inoltre, se non si utilizzano gli elenchi al di fuori di un singolo metodo, ha più senso allocarli nello stack anziché nell'heap dichiarandolo come un oggetto normale, non un puntatore. Hai ancora bisogno di malloc() l'effettivo membro mData di AudioBuffer, ma almeno non ti devi preoccupare di liberare() l'effettivo AudioBufferList stesso.

+0

Grazie. Quindi, se ho canali audio intercalati, dovrei creare 3 distinti AudioBufferList con un singolo AudioBuffer, giusto? Ma allora qual è il punto di usare AudioBufferLists? Se capisco quello che dici correttamente, starei meglio con 3 AudioBuffer (e senza AudioBufferLists) - almeno in questo caso. –

+1

Sì, sarebbe corretto. Il punto di utilizzo di AudioBufferList è quello di semplificare la gestione dei dati multicanale, in quanto solitamente i dati interlacciati sono un vero problema per le operazioni DSP. È molto più bello avere canali stereo separati con ciascun canale nel proprio buffer. Immagina di lavorare con un segnale stereo 4.1 - allora avresti un buffer singolo con 5 canali interlacciati! Non troppo divertente con cui lavorare. –

+1

Ah, ma non ho detto di non utilizzare interamente AudioBufferList. Anche se può sembrare sciocco passare un singolo AudioBuffer all'interno di una AudioBufferList, è molto più facile passare all'interno dell'API CoreAudio. Inoltre, la struttura AudioBufferList non impone un sovraccarico di memoria. –