将 24 位 USB 音频流转换为 32 位流
Converting 24 bit USB audio stream into 32 bit stream
我正在尝试将 24 位 USB 音频流转换为 32 位流,以便我的微控制器的外围设备可以愉快地播放流(它只能像大多数 mcus 一样处理 16 或 32 位数据...)。
以下代码是我从 mcu 公司获得的...没有按预期工作,我最终得到了非常失真的音频。
// Function takes usb stream and processes the data for our peripherals
// @data - usb stream data
// @byte_count - size of stream
void process_usb_stream(uint8_t *data, uint16_t byte_count) {
// Etc code that gets buffers ready to read the stream...
// Conversion here!
int32_t *buffer;
int sample_count = 0;
for (int i = 0; i < byte_count; i += 3) {
buffer[sample_count++] = data[i] | data[i+1] << 8 | data[i+2] << 16;
}
// Send buffer to peripherals for them to use...
}
任何将数据从 24 位流转换为 32 位流的帮助都将非常棒!这方面的工作对我来说很辛苦:(
这是 DSP 的东西,如果 post 这个问题 http://dsp.stackexchange.com
在 DSP 中,改变位深度的过程称为 缩放
- 16 位分辨率有 65536 个值
- 24位分辨率有16777216
可能的值
- 32 位有 4294967296 个值所以因子是 256
根据https://electronics.stackexchange.com/questions/229268/what-is-name-of-process-used-to-change-sample-bit-depth/229271
从 24 位减少到 16 位称为 缩小 并通过将每个值除以 256 来完成。
这可以通过将每一位按位移动 8 来完成
y = x >> 8
。以这种方式缩小时,LSB 会丢失
向上扩展 到 32 位比较复杂,有几种方法可以做到这一点。它可以通过将值的每一位乘以 2⁰ 和 2⁸ 之间的值来工作。
将 24 位值压入 32 位寄存器,然后将每一位左移 2⁰ 和 2⁸ 之间的值:
data32[31] = data32[23] << 8;
data32[22] = data32[14] << 8;
...
data32[0] = data32[0];
并插入你没有得到的位(线性插值)
也许在 http://dsp.stackexchange.com
上可以询问更好的扩展算法
另请参阅 http://blog.bjornroche.com/2013/05/the-abcs-of-pcm-uncompressed-digital.html 以了解放大问题...
data[...]
是一个 uint8_t。你需要在移动之前转换它,因为 data[...]<<8
和 data[...]<<16
是未定义的。它们要么为 0,要么不变,这都不是您想要的。
此外,您需要再移动 8 位以获得完整范围并将符号位放在正确的位置。
此外,您将数据视为小端格式。确保它是。我假设这是正确的,所以像这样的东西有效:
int32_t *buffer;
int sample_count = 0;
for (int i = 0; i+3 <= byte_count; ) {
int32_t v = ((int32_t)data[i++])<<8;
v |= ((int32_t)data[i++])<<16;
v |= ((int32_t)data[i++])<<24;
buffer[sample_count++] = v;
}
最后,请注意,这假设 byte_count 可以被 3 整除 -- 确保这是真的!
我正在尝试将 24 位 USB 音频流转换为 32 位流,以便我的微控制器的外围设备可以愉快地播放流(它只能像大多数 mcus 一样处理 16 或 32 位数据...)。
以下代码是我从 mcu 公司获得的...没有按预期工作,我最终得到了非常失真的音频。
// Function takes usb stream and processes the data for our peripherals
// @data - usb stream data
// @byte_count - size of stream
void process_usb_stream(uint8_t *data, uint16_t byte_count) {
// Etc code that gets buffers ready to read the stream...
// Conversion here!
int32_t *buffer;
int sample_count = 0;
for (int i = 0; i < byte_count; i += 3) {
buffer[sample_count++] = data[i] | data[i+1] << 8 | data[i+2] << 16;
}
// Send buffer to peripherals for them to use...
}
任何将数据从 24 位流转换为 32 位流的帮助都将非常棒!这方面的工作对我来说很辛苦:(
这是 DSP 的东西,如果 post 这个问题 http://dsp.stackexchange.com
在 DSP 中,改变位深度的过程称为 缩放
- 16 位分辨率有 65536 个值
- 24位分辨率有16777216 可能的值
- 32 位有 4294967296 个值所以因子是 256
根据https://electronics.stackexchange.com/questions/229268/what-is-name-of-process-used-to-change-sample-bit-depth/229271 从 24 位减少到 16 位称为 缩小 并通过将每个值除以 256 来完成。
这可以通过将每一位按位移动 8 来完成
y = x >> 8
。以这种方式缩小时,LSB 会丢失
向上扩展 到 32 位比较复杂,有几种方法可以做到这一点。它可以通过将值的每一位乘以 2⁰ 和 2⁸ 之间的值来工作。
将 24 位值压入 32 位寄存器,然后将每一位左移 2⁰ 和 2⁸ 之间的值:
data32[31] = data32[23] << 8;
data32[22] = data32[14] << 8;
...
data32[0] = data32[0];
并插入你没有得到的位(线性插值)
也许在 http://dsp.stackexchange.com
上可以询问更好的扩展算法另请参阅 http://blog.bjornroche.com/2013/05/the-abcs-of-pcm-uncompressed-digital.html 以了解放大问题...
data[...]
是一个 uint8_t。你需要在移动之前转换它,因为 data[...]<<8
和 data[...]<<16
是未定义的。它们要么为 0,要么不变,这都不是您想要的。
此外,您需要再移动 8 位以获得完整范围并将符号位放在正确的位置。
此外,您将数据视为小端格式。确保它是。我假设这是正确的,所以像这样的东西有效:
int32_t *buffer;
int sample_count = 0;
for (int i = 0; i+3 <= byte_count; ) {
int32_t v = ((int32_t)data[i++])<<8;
v |= ((int32_t)data[i++])<<16;
v |= ((int32_t)data[i++])<<24;
buffer[sample_count++] = v;
}
最后,请注意,这假设 byte_count 可以被 3 整除 -- 确保这是真的!