将2个sint16s样本表示为单个uint32样本

时间:2010-11-26 08:53:47

标签: c type-conversion pcm

我的问题与这个问题有关,但反过来了。

Split UInt32 (audio frame) into two SInt16s (left and right)?

在上面的链接中,op希望将32位帧分成2个16位样本(左和右)。

我有2个16位样本,我想将它们表示为单个32位交错帧。

到目前为止,我的尝试看起来像这样。

UInt32* ar = malloc(totalFramesInFile * sizeof (ar));

for (int b=0; b < totalFramesInFile; b++)
{
  UInt32 l = soundStructArray[audioFile].audioDataLeft[b];
  UInt32 r = soundStructArray[audioFile].audioDataRight[b];

  UInt32 t = (UInt32) l + r;

  ar[b] = t;
}
soundStructArray[audioFile].audioData = ar;

这是合法和正确的吗?由于我的经验不足,我不确定。我的音频输出听起来有点奇怪,我正在尝试通过消除过程来确定哪些是错误的。

如果有人能够确认我正在做的是将2个16位采样表示为32位帧或建议正确的方法,那将会很有帮助。

我有一种感觉,我所做的是错的。我认为这是因为32位帧的前16位应该是左边,后面的16位应该是右边的。整个事情不应该是两者的总和......我想。

2 个答案:

答案 0 :(得分:4)

您需要更改::

UInt32 t = (UInt32) l + r;

为:

UInt32 t = (l << 16) | (r & 0xffff);

这会将l置于t的最重要的16位和最低16位的r中。

详细说明

如果您有两个16位样本,lr,它们在二进制文件中如下所示:

l: LLLLLLLLLLLLLLLL
r: RRRRRRRRRRRRRRRR

让我们首先将它们扩展到32位:

l: 0000000000000000LLLLLLLLLLLLLLLL
r: 0000000000000000RRRRRRRRRRRRRRRR

现在让我们将l向左移动16位(l << 16

l: LLLLLLLLLLLLLLLL0000000000000000
r: 0000000000000000RRRRRRRRRRRRRRRR

现在让我们将OR(|)放在一起:

t: LLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRR

Voilà!现在您将lr组合成一个32位值,以后可以轻松地再次提取它们。

答案 1 :(得分:2)

我会接受这一点作为Paul R答案的补充,但是发表评论的时间太长了。

可能更“明显”的替代解决方案是在32位值中明确设置顶部或底部16位值。您可以使用联合执行此操作,即

typedef union {
    struct {
        SInt16 high;
        SInt16 low;
    } parts;
    UInt32 word;
} IntConverter;

用法:

IntConverter * ar = malloc(totalFramesInFile * sizeof (IntConverter));

for (int b=0; b < totalFramesInFile; b++)
{
    ar[b].parts.high = soundStructArray[audioFile].audioDataLeft[b];
    ar[b].parts.low = soundStructArray[audioFile].audioDataRight[b];
}
soundStructArray[audioFile].audioData = (UInt32 *) ar;

但是,这种方法要求您更多地了解底层平台,因为它依赖于数据实际存储在内存中的方式。但是,根据目标平台和编译器,它可能更有效。