iOS Core Audio:在kAudioFormatFlagsCanonical和kAudioFormatFlagsAudioUnitCanonical之间转换

我需要在这个格式之间转换:

format.mSampleRate = 44100.0; format.mFormatID = kAudioFormatLinearPCM; format.mFormatFlags = kAudioFormatFlagsCanonical | kLinearPCMFormatFlagIsNonInterleaved; format.mBytesPerPacket = sizeof(AudioUnitSampleType); format.mFramesPerPacket = 1; format.mBytesPerFrame = sizeof(AudioUnitSampleType); format.mChannelsPerFrame = 2 ; format.mBitsPerChannel = sizeof(AudioUnitSampleType)*8; 

和这种格式

 format.mSampleRate = 44100.0; format.mFormatID = kAudioFormatLinearPCM; format.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical; format.mBytesPerPacket = sizeof(AudioUnitSampleType); format.mFramesPerPacket = 1; format.mBytesPerFrame = sizeof(AudioUnitSampleType); format.mChannelsPerFrame = 2; format.mBitsPerChannel = sizeof(AudioUnitSampleType)*8; 

在audio呈现callback的范围内有下面的代码,buffer []是第二种格式,array []需要第一种格式。

 for (k = 0; k < channels; k++){ buffer = (AudioUnitSampleType *) ioData->mBuffers[k].mData; for(j=0; j < samples; j++){ array[j] = buffer[j]; } } 

我知道你可以使用苹果转换器单元,但是我不能在我的情况下使用苹果转换器audio单元(这是有原因的)。

基本上两个格式之间的唯一区别是format.mFormatFlags(kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift)的以下标志。

如何将缓冲区[](包含第二种格式的数据)转换为数组[](包含第一种格式的数据),反之亦然?

谢谢。

那么,如果你参考kAudioFormatFlagsAudioUnitCanonical上的文档,你会看到:

 kAudioFormatFlagsAudioUnitCanonical The flags for the canonical audio unit sample type. This matches AudioUnitSampleType. 

 The canonical audio sample type for audio units and other audio processing in iPhone OS is noninterleaved linear PCM with 8.24-bit fixed-point samples. 

所以, buffer[]数组中的采样点是8.24位的定点格式。 这是什么意思?

8.24位定点格式用于表示具有固定精度的浮点数 – 32位整数,前8位表示整个部分,最后24位表示小数部分(小数点后的数字)。 ( 进一步阅读 )

在iOSaudio单元中,有一个很小的差别 – 这个浮点数(通常)的范围是[-1,1)( [-1.000000000000,+ 0.999969482421875] )。 转换为16位PCM时,此范围之外的值将被简单剪切。 你可以validation前8位大部分是0x00或0xff(在2的恭维中是-1)。

要将此表示转换为16位数字,请使用以下命令:

 SIGN((SInt8)(val >> 24)) * 32768 * (val & 0xFFFFFF)/(float)(1<<24) 

即:从8个MSB中提取符号,从24个LSB中提取小数值,然后除以24位整数(2 ^ 24)的范围,得到0和1之间的浮点数,最后乘以32768得到一个值在期望的范围内。

我自己也没有尝试过 – 你可能需要在这里和那里调整一些东西。

也许是一个迟到的答案,但由于移位方法不适用于我的原因,我发现这个替代方法很好,在audiograph https://github.com/tkzic/audiograph

我从那里调整了一下方法,瞧:

 void ConvertInputToInt16(AudioStreamBasicDescription inFormat, void *buf, void *outputBuf, size_t capacity) { AudioConverterRef converter; OSStatus err; size_t bytesPerSample = sizeof(SInt16); AudioStreamBasicDescription outFormat = {0}; outFormat.mFormatID = kAudioFormatLinearPCM; outFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; outFormat.mBitsPerChannel = 8 * bytesPerSample; outFormat.mFramesPerPacket = 1; outFormat.mChannelsPerFrame = 1; outFormat.mBytesPerPacket = bytesPerSample * outFormat.mFramesPerPacket; outFormat.mBytesPerFrame = bytesPerSample * outFormat.mChannelsPerFrame; outFormat.mSampleRate = inFormat.mSampleRate; NSLog(@"description for in format: %@", descriptionForAudioFormat(inFormat)); NSLog(@"description for out format: %@", descriptionForAudioFormat(outFormat)); UInt32 inSize = capacity*sizeof(SInt32); UInt32 outSize = capacity*sizeof(SInt16); // this is the famed audio converter err = AudioConverterNew(&inFormat, &outFormat, &converter); if(noErr != err) { NSLog(@"error in audioConverterNew: %d", (int)err); } err = AudioConverterConvertBuffer(converter, inSize, buf, &outSize, outputBuf); if(noErr != err) { NSLog(@"error in audioConverterConvertBuffer: %d", err); } }