2010-09-22 31 views
9

Cách chính xác để khởi tạo (cấp phát bộ nhớ) và phát hành (giải phóng) một AudioBufferList với 3 AudioBuffers là gì? (Tôi biết rằng có thể có nhiều cách để thực hiện việc này.)iPhone: AudioBufferList init và release

Tôi muốn sử dụng 3 bộ đệm đó để đọc các phần tuần tự của tệp âm thanh vào chúng và phát lại bằng cách sử dụng Đơn vị âm thanh.

Trả lời

15

Sau đây là cách tôi làm điều đó:

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

Trước hết, tôi nghĩ rằng bạn thực sự muốn có 3 AudioBufferLists, không phải một AudioBufferList với 3 thành viên AudioBuffer. Một AudioBuffer đại diện cho một kênh dữ liệu duy nhất, vì vậy nếu bạn có 3 tệp âm thanh nổi, bạn nên đặt chúng trong 3 AudioBufferLists, với mỗi danh sách có 2 AudioBuffers, một bộ đệm cho kênh bên trái và một cho bên phải. Mã của bạn sau đó sẽ xử lý mỗi danh sách (và dữ liệu kênh tương ứng của nó) một cách riêng biệt, và bạn có thể lưu trữ các danh sách trong một NSArray hoặc một cái gì đó như thế. Về mặt kỹ thuật, không có lý do gì bạn không thể có một danh sách bộ đệm với 3 kênh âm thanh xen kẽ (nghĩa là cả hai kênh bên trái & đều được lưu trữ trong một bộ đệm dữ liệu), nhưng điều này ngược lại với việc sử dụng thông thường API và sẽ hơi khó hiểu.

Dù sao, phần này của API CoreAudio có nhiều C-ish hơn Objective-C-ish, vì vậy bạn nên sử dụng malloc/free thay vì phân bổ/giải phóng. Mã sẽ trông giống như sau:

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

Mã trên giả định rằng bạn đang đọc dữ liệu dưới dạng dấu phẩy động. Nếu bạn không thực hiện bất kỳ xử lý đặc biệt nào trên các tệp, thì sẽ hiệu quả hơn khi đọc chúng dưới dạng SInt16 (dữ liệu PCM thô), vì iPhone không có FPU.

Ngoài ra, nếu bạn không sử dụng danh sách bên ngoài một phương pháp, thì việc phân bổ chúng trên ngăn xếp thay vì heap bằng cách tuyên bố nó là đối tượng thông thường, không phải là con trỏ. Bạn vẫn cần phải malloc() thành viên mData thực sự của AudioBuffer, nhưng ít nhất bạn không cần phải lo lắng về việc tự do() 'ing chính AudioBufferList thực sự.

+0

Cảm ơn. Vì vậy, nếu tôi có các kênh âm thanh xen kẽ, tôi nên tạo 3 AudioBufferLists riêng biệt với một AudioBuffer duy nhất trong chúng, phải không? Nhưng sau đó, điểm của việc sử dụng AudioBufferLists là gì? Nếu tôi hiểu những gì bạn nói chính xác, tôi sẽ tốt hơn với 3 AudioBuffers (và không có AudioBufferLists) - trong trường hợp này ít nhất. –

+1

Có, điều đó sẽ đúng. Điểm sử dụng AudioBufferLists là giúp việc quản lý dữ liệu đa kênh trở nên dễ dàng hơn, vì dữ liệu xen kẽ thường là một nỗi đau thực sự để thực hiện các thao tác DSP. Thật tuyệt vời khi có các kênh stereo riêng biệt với mỗi kênh trong bộ đệm riêng của nó. Hãy tưởng tượng làm việc với một tín hiệu stereo 4.1 - sau đó bạn sẽ có một bộ đệm đơn với 5 kênh xen kẽ! Không quá vui để làm việc cùng. –

+1

Ah, nhưng tôi đã không nói không sử dụng AudioBufferLists hoàn toàn. Mặc dù có vẻ ngớ ngẩn khi truyền một AudioBuffer duy nhất bên trong một AudioBufferList, chúng dễ dàng hơn nhiều để truyền xung quanh trong API CoreAudio. Bên cạnh đó, chính cấu trúc AudioBufferList không áp đặt quá nhiều bộ nhớ. –

Các vấn đề liên quan