单声道转立体声转换

7
我在这里遇到了以下问题:我得到了一个字节块(uint16_t*),代表音频数据,生成它们的设备正在捕获单声道音频数据,所以显然我有单声道音频数据,只有一个通道。我需要将这些数据传递给另一个设备,该设备期望交错的立体声数据(因此有2个通道)。我想做的就是复制数据中的1个通道,使立体声数据的两个通道都包含相同的字节。你能指点我一个有效的算法来实现这个吗?
谢谢, f.

你正在使用哪种音频格式或框架? - Anders Lindahl
Anders 也要求提供框架。 - Sebastian Mach
框架并不特别,一个设备通过指针(void*)将数据发送给我,并通过回调告诉我样本的数量,另一个设备使用相同的void*和样本数来播放音频(设备号二从此回调中调用)。设备2希望这些数据是交错立体声。 - Ferenc Deak
谢谢大家的回复,问题已解决 :) - Ferenc Deak
5个回答

14

如果你只想要交错的立体声样本,那么你可以使用像这样的函数:

void interleave(const uint16_t * in_L,     // mono input buffer (left channel)
                const uint16_t * in_R,     // mono input buffer (right channel)
                uint16_t * out,            // stereo output buffer
                const size_t num_samples)  // number of samples
{
    for (size_t i = 0; i < num_samples; ++i)
    {
        out[i * 2] = in_L[i];
        out[i * 2 + 1] = in_R[i];
    }
}

如果要从单声道缓冲区生成立体声,则只需将in_L和in_R指针传递相同的地址,例如:

interleave(mono_buffer, mono_buffer, stereo_buffer, num_samples);

下次您删除编辑时,能否至少通知一下做出贡献的人? :-/ - Nikos C.
当然可以,虽然我不确定我该怎么做? - Paul R
我在添加原地版本后忘记添加注释了。我的错。 - Nikos C.
没问题。顺便提一下,我觉得你的编辑虽然包含了有用的信息,但并不适合作为这个答案的一部分,或许应该作为一个单独的答案添加。我看到你已经这样做了:+1! - Paul R
这很接近了,但它只适用于一字节帧深度的特殊情况。我扩展了这个答案,使其适用于任何帧深度。 - Mike Vonn

3

如果设备的内存很小,您可能希望在原地进行转换以节省一些内存。因此,您可能希望使用以下内容而不是Paul R的方法:

void interleave(uint16_t buf[], const int len)
{
    for (int i = len / 2 - 1, j = len - 1; i >= 0; --i) {
        buf[j--] = buf[i];
        buf[j--] = buf[i];
    }
}

从单声道设备获取声音数据时,您需要分配一个比所需大两倍的缓冲区,并将其传递给单声道设备。这将用单声道音频填充缓冲区的一半。然后,将该缓冲区传递给上述函数,该函数将其转换为立体声。最后,将该缓冲区传递给立体声设备。通过这种方式,您可以节省额外的内存分配,因此在转换过程中使用的内存减少了33%。


2

将相同指针传递给两个通道?如果这违反了restrict规则,请使用memcpy()

抱歉,但您的问题过于宽泛。API?操作系统?CPU架构?


这不起作用,我没有为每个通道发送数据,我发送了一堆字节和设备号码2根据其需要将它们分离。 - Ferenc Deak

0
你需要复制缓冲区并进行复制。由于您没有告诉我们格式以及如何终止,我无法提供代码,但它看起来像一个简单的for循环。
int_16* allocateInterleaved(int_16* data, int length)
  int i;
  int *copy = malloc(sizeof(int_16)*length*2);
  if(copy == NULL) {
    /* handle error */
  }
  for(i =0; i<length; i++) {
    copy[2*i] = data[i];
    copy[2*i+1] = data[i]; 
  }
  return copy;
}

请原谅任何明显的拼写错误,我的 C 有些生疏。将所需的 16 位有符号类型定义为 int_16。不要忘记释放复制缓冲区,更好的做法是重用它。

0
你需要交错数据,但如果帧长度大于1,则上述解决方案都不适用。以下代码可以处理可变的帧长度。
void Interleave(BYTE* left, BYTE* right, BYTE* stereo,int numSamples_in, int frameSize)
{
    int writeIndex = 0;
    for (size_t j = 0; j < numSamples_in; j++)
    {
        for (int k = 0; k < frameSize; k++)
        {
            int index = j * frameSize + k;

            stereo[k + writeIndex] = left[index];
            stereo[k + writeIndex + frameSize] = right[index];
        }
        writeIndex += 2 * frameSize;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接