将PCM_FORMAT_S16_LE中捕获的音频存储到char缓冲区并转换为有用数据

时间:2014-03-04 17:48:29

标签: c audio buffer pcm alsa

所以我使用alsa从麦克风捕获音频,最终我想处理来自每个频道的样本。这种低级编程对我来说很新鲜。

但是我有点困惑,大多数使用alsa的示例都将样本存储在char缓冲区中以PCM_FORMAT_S16_LE格式捕获的音频。我知道它不是一个char缓冲区而是一个字节缓冲区。我正在使用的设备有四个通道,所以根据我的理解,我有一个16位数字存储在char缓冲区的两个字节中。其中2个字节/样本,然后4个通道是交错的。

这是我的捕获代码,我省略了hw设置,因为它对我的问题并不重要。

char *buffer;

进一步推进该计划...

snd_pcm_params_get_period_size(params, &frames, &dir);

size = frames *8; /* 2 bytes/sample, 4 channels */

buffer = (char *) malloc(size);

    snd_pcm_hw_params_get_period_time(params, &val, &dir);

    loops = 5000000 / val;

    while (loops > 0)
    {
        loops--;
        capture = send_pcm_readi(handle, buffer, frames);

        if (capture == -EPIPE)
        {
            fprintf(stderr, "overrun occured");
            snd_pcm_prepare(handle);
        }
        else if (capture <0)
        {
            fprintf(stderr, "error from read: %s\n", snd_strerror(capture));
        }
        else if(capture != (int)frames)
        {
            fprintf(stderr, "short read, read %d frames\n", capture);
        }

        /*  

        Process values

        */


    }

我想要做的是能够将每个样本转换为电压或dB值,以便进行进一步处理。我知道数据是正确的,因为我可以将样本写入文本文件,例如,audacity可以将原始数据解释为四声道音频文件。

但是,我对如何直接从char缓冲区获取此信息感到困惑?

2 个答案:

答案 0 :(得分:1)

签署16位样本后,应该为缓冲区使用带符号的16位数据类型:

typedef short int s16;

s16 *buffer = malloc(size_in_bytes);

(您应该使用SND_PCM_FORMAT_S16来获得正确的字节顺序。)

在缓冲区中,每四个值都是一帧。

for (i = 0; i < capture; i++) {
    ch1 = buffer[i * 4 + 0];
    ch2 = buffer[i * 4 + 1];
    ch3 = buffer[i * 4 + 2];
    ch4 = buffer[i * 4 + 3];
    // or use a loop over 0..3
    ...
}

或者,如果要访问某个特定通道的所有样本,请按以下步骤检查缓冲区:

// for the first channel
for (i = 0; i < capture; i++) {
    sample = buffer[i * 4 + 0];
    ...
}

答案 1 :(得分:1)

short int *outBuffer = malloc(size);

outBuffer[i] = (buffer[i*2] << 8) | buffer[i*2+1];

outBuffer[i] = buffer[i*2] | (buffer[i*2+1] << 8);

取决于您要去的方向。如果您仍然需要对通道进行解交织,那么只需复制出每个第n个16位样本 - 或者您可以将其复制到位。

如果音频和计算机的字节顺序匹配,那么您可以像@ CL的答案一样进行演绎。