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