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

发布于 2024-10-22 12:01:57 字数 467 浏览 2 评论 0原文

我有一大块数据 (void*),它是 2 通道、44100 Hz、'lpcm' 8.24 位小端有符号整数,去交错。 我需要将该块记录为 2 ch、44100 Hz、“lpcm”16 位小端有符号整数的文件。

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

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

但是如何将去交错转换为交错?

I have a chunk of data (void*) which is 2 ch, 44100 Hz, 'lpcm' 8.24-bit little-endian signed integer, deinterleaved.
I need to record that chunk to a file as 2 ch, 44100 Hz, 'lpcm' 16-bit little-endian signed integer.

How do I convert data? I can imagine I need to do something like this:

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

But how do I convert deinterleaved to interleaved?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

双手揣兜 2024-10-29 12:01:58

我已阅读音频记录中的以下片段 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);        
    }    
}

I have read the following clip in audiograph 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);        
    }    
}
谎言 2024-10-29 12:01:58

最好的描述可以在 http://lists.apple.com 找到/archives/coreaudio-api/2011/Feb/msg00083.html

所以,

8.24 数字被解释为范围从 -128.000000000000 到 +127.999999940393

但是!

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

好的?

Best description can be found at http://lists.apple.com/archives/coreaudio-api/2011/Feb/msg00083.html

So,

8.24 numbers are interpreted as ranging from -128.000000000000 to +127.999999940393

But!

The convention in iOS/CoreAudio is to treat -1.000000000000 to +0.999969482421875 as non-clipped values that do not exceed Full Scale for the 16-bit analog audio converters.

Ok?

唠甜嗑 2024-10-29 12:01:58

我测试了移动 9 位的流行方法,但由于某种原因它对我不起作用,因为我进一步使用结果编码为 ogg。结果ogg非常吵。这个函数的作用是基于我在audiograph https://github.com/tkzic/audiograph<中找到的方法/a>

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

}

I tested the popular method with shifting 9 bits and for some reason it does not work for me, as I further use the result to encode to ogg. The resulted ogg was verry noisy. What did work is this function, based on a method I found in 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);
    }

}
明月松间行 2024-10-29 12:01:57

好的,我花了一些时间调查这个问题,并意识到问题包含的信息太少,无法回答 =)
所以协议如下:

首先,关于非交错:
我最初认为它会是这样的:
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 - > 11111111 11111111 (11011011 01110111)
00000000 01101111 00000000 11000001 - > 00000000 00000000 (00110111 10000000)

就是这样。只不过是遍历数组并右移位而已。
希望这能为某人节省几个小时。

Ok, I've spent some time investigating the issue and realized that question contains too few information to be answered =)
So heres the deal:

First, about non-interleaved:
I initially thought that it would look like this:
l1 l2 l3 l4...ln r1 r2 r3 r4...rn
But it turned out that in my data right channel was just missing. It turned out that it wasn't a non-interleaved data, it was just a plain mono data.
And yes, it should always be multiple buffers in case data is actually non-interleaved.
If it's interleaved, it should be
l1 r1 l2 r2 l3 r3 l4 r4...

Second, about actual transformation:
it all depends on the range of samples. In my case (and in any case where core audio is involved if I'm correct) fixed-point 8.24 values should range between (-1, 1), while 16-bit signed values should range between (-32768, 32767).
So 8.24 value will always have its first 8 bits set either to 0 (in case it is positive) or to 1 (in case it is negative). This first 8 bits should be removed (preserving sign ofc). Also you can remove as many trailing bits as you want - it'll just reduce quility of the sound, but it wont ruin the sound. In case of converting to 16 bits signed format, bits 8-22 (15 bits that is) will actually contain the data we need to use for SInt16. Bit 7 can be used as the sign bit.
So to convert 8.24 to SInt16 you just need to shift 9 bits right (9 because you need to preserve the sign) and cast to SInt16

11111111 10110110 11101110 10000011 - > 11111111 11111111 (11011011 01110111)
00000000 01101111 00000000 11000001 - > 00000000 00000000 (00110111 10000000)

That's it. Nothing more then iterating through array and shifting bits right.
Hope that's gonna save someone couple of hours.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文