【问题标题】:Convert Uint8 (floating-point AUDIO_F32) to int16_t (16bit PCM)将 Uint8(浮点 AUDIO_F32)转换为 int16_t(16 位 PCM)
【发布时间】:2017-08-24 14:10:02
【问题描述】:

我目前正在尝试使用 SDL 录制音频并对其进行处理,但在获取处理步骤所需的 16 位 PCM 音频时遇到了一些麻烦。我运行的设备只支持 AUDIO_F32 格式。所以我的 AudioSpec 如下;

SDL_AudioSpec wanted;
SDL_zero(wanted);

wanted.freq = 48000;
wanted.format = AUDIO_F32SYS;
wanted.channels = 1;
wanted.samples = 4096;
wanted.callback = NULL;

现在我必须关注包含录制音频的缓冲区;

std::vector<Uint8> buffered;

如何将Uint8 转换为 16 位 PCM 格式? Uint8 应该是定义为 unsigned char 的 32 位浮点音频,如果我是正确的。我已经尝试了下面的代码,但它似乎没有给出正确的结果;

std::vector<int16_t> pcm_buffer;
for( const Uint8& sample : buffered )
{
   float sampleFloat = (float) sample;
   sampleFloat *= 32767;

   int16_t sampleInt = (int16_t) sampleFloat;
   pcm_buffer.push_back(sampleInt);
}

我有一种感觉,我完全误解了我在做什么,所以我希望有人能指出我正确的方向。

【问题讨论】:

  • 这是真实的代码吗?我有一种预感,Uint 应该真的是Uint8。如果您手动输入:请考虑复制 + 粘贴。
  • 我不得不编辑部分代码,因为我做了很多实验,我的代码是/是一团糟,但它确实应该是 Uint8。

标签: c++ audio sdl-2


【解决方案1】:

F32 格式是 4 字节浮点数,但您的缓冲区是字节缓冲区。您错过了首先将字节转换为浮点数的步骤。这是错误的行:

float sampleFloat = (float) sample

转换应该在 4 字节块上进行,而不是在单个字节上。比较:

std::vector<Uint8> buffered = ...;
std::vector<int16_t> pcm_buffer;
assert(buffered.size() % 4 == 0);
for(for size_t i = 0; i < buffered.size(); i += 4)
{
     float sampleFloat = *(float*)(buffered.data() + i);
     sampleFloat *= 32767;

     int16_t sampleInt = (int16_t) sampleFloat;
     pcm_buffer.push_back(sampleInt);
}

由于对齐和别名规则,我认为assert(buffered.data() % 4 == 0) 也是合理的。

您还可以将强制转换本身置于循环之外并迭代浮点数组,例如

std::vector<Uint8> buffered = ...;
const float* p = (const float*)buffered.data();
const float* pe = p + buffered.size() / 4;
for (; p < pe; ++p) {
    int16_t sampleInt = *p * 32767;
}

【讨论】:

  • 非常感谢,不过现在感觉有点笨>.
  • 您的第二个建议也给了我以下错误; cannot cast from type 'iterator' (aka '__wrap_iter&lt;unsigned char *&gt;') to pointer type 'const float *'
  • 我修复了代码,end()方法使用不正确。
猜你喜欢
  • 1970-01-01
  • 2020-08-08
  • 2014-08-18
  • 1970-01-01
  • 1970-01-01
  • 2011-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多