【发布时间】:2014-05-28 04:52:01
【问题描述】:
我开始学习 linux 和 ALSA,我想知道是否有办法将我从麦克风 a 录制的声音直接存储到缓冲区。我在这里阅读http://www.linuxjournal.com/article/6735?page=0,2 如何制作我的录音程序。但我需要的是更复杂一点。我需要录制声音,直到我按下一个键。我需要这个的原因是因为我弄乱了一个 RaspberryPI(它上面的 debian),看看我是否可以把它变成一个声音监控/检测设备。
我现在的主要问题是,当我尝试使用它来录制 (./Rec >name.raw ) 时,它什么也没做。它只是输出一个空的 .raw 文件。
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <termios.h>
#include <alsa/asoundlib.h>
struct termios stdin_orig; // Structure to save parameters
void term_reset() {
tcsetattr(STDIN_FILENO,TCSANOW,&stdin_orig);
tcsetattr(STDIN_FILENO,TCSAFLUSH,&stdin_orig);
}
void term_nonblocking() {
struct termios newt;
tcgetattr(STDIN_FILENO, &stdin_orig);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // non-blocking
newt = stdin_orig;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
atexit(term_reset);
}
int main() {
int key=0;
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(¶ms);
/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);
/* Set the desired hardware parameters. */
/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
/* One channel (mono) */
snd_pcm_hw_params_set_channels(handle, params, 1);
/* 16000 bits/second sampling rate */
val = 16000;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
/* Set period size to 2048 frames. */
frames = 2048;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
exit(1);
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
size = frames * 2; /* 2 bytes/sample, 1 channels */
buffer = (char *) malloc(size);
while (key == 0)
{
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE)
{
/* EPIPE means overrun */
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(handle);
}
else if (rc < 0)
{
fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
}
else if (rc != (int)frames)
{
fprintf(stderr, "short read, read %d frames\n", rc);
}
rc = write(1, buffer, size);
if (rc != size)
fprintf(stderr, "short write: wrote %d bytes\n", rc);
key = getchar();
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
【问题讨论】:
-
您是否只需在 while 循环内以非阻塞模式读取键盘然后退出循环?目前,缓冲区在每个时期都会被覆盖。如果要将所有内容都记录到缓冲区中,则必须将其放大很多,并在每个周期将缓冲区指针推进大小。
-
snd_pcm_readi已经这样做了。 -
@CL。你可以再详细一点吗?还有 snd_pcm_readn 是做什么的?
-
snd_pcm_readi将样本读入缓冲区。在您展示的程序中,该变量恰好被命名为buffer。 -
@CL。是的,它确实。但请阅读整个问题。我有点笨,不知道如何进行修改以使循环在键盘输入处停止。
标签: c audio while-loop recording alsa