如何手动将 8.24 位解交错 lpcm 转换为 16 位 lpcm?
我有一大块数据 (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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我已阅读音频记录中的以下片段 https://github.com/tkzic/audiograph
I have read the following clip in audiograph https://github.com/tkzic/audiograph
最好的描述可以在 http://lists.apple.com 找到/archives/coreaudio-api/2011/Feb/msg00083.html
所以,
但是!
好的?
Best description can be found at http://lists.apple.com/archives/coreaudio-api/2011/Feb/msg00083.html
So,
But!
Ok?
我测试了移动 9 位的流行方法,但由于某种原因它对我不起作用,因为我进一步使用结果编码为 ogg。结果ogg非常吵。这个函数的作用是基于我在audiograph https://github.com/tkzic/audiograph<中找到的方法/a>
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
好的,我花了一些时间调查这个问题,并意识到问题包含的信息太少,无法回答 =)
所以协议如下:
首先,关于非交错:
我最初认为它会是这样的:
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.