所以我使用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缓冲区获取此信息感到困惑?
答案 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的答案一样进行演绎。