12 Stimmen

Das iPhone: AudioBufferList initiieren und freigeben

Wie wird eine AudioBufferList mit 3 AudioBuffers korrekt initialisiert (Speicher zugewiesen) und freigegeben (freigegeben)? (Ich bin mir bewusst, dass es mehr als eine Möglichkeit gibt, dies zu tun).

Ich möchte diese 3 Puffer verwenden, um sequentielle Teile einer Audiodatei in sie zu lesen und sie mit Audio Units wiederzugeben.

17voto

sbooth Punkte 16258

Ich mache es folgendermaßen:

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;
}

14voto

Nik Reiman Punkte 37385

Zunächst einmal denke ich, dass Sie tatsächlich 3 AudioBufferLists, nicht eine AudioBufferList mit 3 AudioBuffer Mitglieder wollen. Ein AudioBuffer stellt einen einzelnen Kanal von Daten, so dass, wenn Sie 3 Stereo-Audio-Dateien haben, sollten Sie sie in 3 AudioBufferLists, mit jeder Liste mit 2 AudioBuffers, ein Puffer für den linken Kanal und eine für den rechten setzen. Ihr Code würde dann jede Liste (und ihre jeweiligen Kanaldaten) separat verarbeiten, und Sie könnten die Listen in einem NSArray oder etwas Ähnlichem speichern.

Technisch gesehen gibt es keinen Grund, warum man nicht eine einzelne Pufferliste mit 3 verschachtelten Audiokanälen haben kann (was bedeutet, dass sowohl der linke als auch der rechte Kanal in einem einzigen Datenpuffer gespeichert werden), aber das widerspricht der konventionellen Verwendung der API und wird etwas verwirrend sein.

Wie auch immer, dieser Teil der CoreAudio-API ist mehr C-ish als Objective-C-ish, so dass Sie malloc/Free anstelle von alloc/release verwenden würden. Der Code würde etwa so aussehen:

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

Der obige Code geht davon aus, dass Sie die Daten als Fließkommazahlen einlesen. Wenn Sie keine spezielle Verarbeitung auf die Dateien tun, ist es effizienter, sie in als SInt16 (rohe PCM-Daten) zu lesen, wie das iPhone nicht über eine FPU.

Wenn Sie die Listen nicht außerhalb einer einzelnen Methode verwenden, ist es außerdem sinnvoller, sie auf dem Stack statt auf dem Heap zuzuweisen, indem Sie sie als reguläres Objekt und nicht als Zeiger deklarieren. Sie müssen immer noch malloc() die tatsächliche mData Mitglied des AudioBuffer, aber zumindest müssen Sie nicht über free()'ing die tatsächliche AudioBufferList selbst zu kümmern.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X