如何手动将8.24位解交织的lpcm转换为16位lpcm?

时间:2011-03-16 10:10:17

标签: core-audio

我有一大块数据(void *),它是2 ch,44100 Hz,'lpcm'8.24位little-endian有符号整数,deinterleaved。 我需要将该块记录为2 ch,44100 Hz,'lpcm'16位little-endian有符号整数。

如何转换数据?我可以想象我需要做这样的事情:

uint dataByteSize = sizeof(UInt32) * samplesCount;
UInt32* source = ...;
UInt32* dest = (UInt32*)malloc(dataByteSize);
for (int i = 0; i < samplesCount; ++i) {
    UInt32 sourceSample = source[i];
    UInt32 destSample = sourceSample>>24;
    dest[i] = destSample;
}

但是如何将deinterleaved转换为interleaved?

4 个答案:

答案 0 :(得分:11)

好的,我花了一些时间调查这个问题并意识到这个问题包含的信息太少而无法回答=) 这是交易的一部分:

首先,关于非交错: 我最初认为它看起来像这样: l1 l2 l3 l4 ... ln r1 r2 r3 r4 ... rn 但事实证明,在我的数据中,正确的渠道刚刚丢失。事实证明,它不是一个非交错数据,它只是一个普通的单声道数据。 是的,如果数据实际上是非交错的,它应该总是多个缓冲区。 如果它是交错的,它应该是 l1 r1 l2 r2 l3 r3 l4 r4 ...

第二,关于实际转型: 这一切都取决于样品的范围。在我的情况下(在任何情况下,如果我是正确的,涉及核心音频)定点8.24值应该在(-1,1)之间,而16位有符号值应该在(-32768,32767)之间。 因此,8.24值将始终将其前8位设置为0(如果是正数)或1(如果它是负数)。应删除前8位(保留符号ofc)。你也可以根据需要删除任意数量的尾随位 - 它只会降低声音的质量,但它不会破坏声音。在转换为16位有符号格式的情况下,位8-22(即15位)实际上将包含我们需要用于SInt16的数据。位7可用作符号位。 因此,要将8.24转换为SInt16,您只需要向右移9位(9因为您需要保留符号)并转换为SInt16

11111111 10110110 11101110 10000011 - &gt; 11111111 11111111(11011011 01110111)
00000000 01101111 00000000 11000001 - &gt; 00000000 00000000(00110111 10000000)

就是这样。没有什么比通过数组迭代和正确移位。 希望能节省几个小时。

答案 1 :(得分:3)

我已在听力图https://github.com/tkzic/audiograph

中阅读了以下片段
/* convert sample vector from fixed point 8.24 to SInt16 */
void fixedPointToSInt16( SInt32 * source, SInt16 * target, int length ) {    
    int i;

    for(i = 0;i < length; i++ ) {
        target[i] =  (SInt16) (source[i] >> 9);        
    }    
}

答案 2 :(得分:0)

最佳描述可在http://lists.apple.com/archives/coreaudio-api/2011/Feb/msg00083.html

找到

所以,

  

8.24号码被解释为-128.000000000000至+127.999999940393

但是!

  

iOS / CoreAudio中的约定是将-1.000000000000视为+0.999969482421875作为16位模拟音频转换器不超过满量程的非限幅值。

好吗?

答案 3 :(得分:0)

我测试了流行的方法,移位9位,由于某种原因它不适合我,因为我进一步使用结果编码到ogg。结果ogg很吵。根据我在录音机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);
    }

}