Attention! Translated article might be found on my English blog.

2016年7月30日土曜日

non-interleaved(kAudioFormatFlagIsNonInterleaved)なデータを扱うためのノウハウ


  1. AudioBufferListの設定方法
  2. AudioStreamBasicDescription(ASBD)の設定方法
  3. frame <-> bytes 変換方法

1. AudioBufferListの設定方法

non-interleavedの場合、チャンネル数の分だけ余分にAudioBuffer領域を確保する必要があります。
例えば、
    AudioBufferList *list = calloc(sizeof(AudioBufferList) + sizeof(AudioBuffer) * (numCh - 1), 1);

とすると良いかもしれません。
参考: Core Audio その1 AudioBufferとAudioBufferList | Objective-Audio

2. AudioStreamBasicDescription(ASBD)の設定方法

non-interleavedの場合、ASBDのmBytesPerFrameは1チャンネルのみのバイトサイズを指定する必要があります。

However, when an ASBD has the kAudioFormatFlagIsNonInterleaved flag, the
                    AudioBufferList has a different structure and semantic. In this case, the ASBD
                    fields will describe the format of ONE of the AudioBuffers that are contained in
                    the list, AND each AudioBuffer in the list is determined to have a single (mono)
                    channel of audio data. Then, the ASBD's mChannelsPerFrame will indicate the
                    total number of AudioBuffers that are contained within the AudioBufferList -
                    where each buffer contains one channel. This is used primarily with the
                    AudioUnit (and AudioConverter) representation of this list - and won't be found
                    in the AudioHardware usage of this structure.


参考: CoreAudioTypes.h


3. frame <-> bytes 変換方法

結果として、non-ineterleavedの場合はLPCMであっても

mBytesPerFrame == (mChannelsPerFrame * mBitsPerChannel / 8)

 という式を満たさなくなってしまいます。

そのため、mBytesPerFrameを使っているコードは
bytesPerFrame = (mChannelsPerFrame * mBitsPerChannel / 8)

という変換を常に行う必要があります。

私は以下のコードを利用しています。

+ (UInt32)BPFofASBD:(ASBD)desc {
    if ((desc.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == kAudioFormatFlagIsNonInterleaved) {
        return desc.mChannelsPerFrame * desc.mBitsPerChannel / 8;
    }
    
    return desc.mBytesPerFrame;
}