我开始学习linux和ALSA,我想知道是否有一种方法可以将我从麦克风录制的声音直接存储到缓冲区。我在这里读到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;
}
最佳答案
这是我如何使用 python 做到这一点的。已测试可在我的桌面 Debian 上使用 USB Plantronics 耳机运行。您需要安装 python-qt4
和 python-pyaudio
软件包才能正常工作。
此外,您还需要将输入设备设置为麦克风。在 GNOME 中,我通过系统工具 -> 系统设置
-> 声音
切换输入和输出设备。如果你的 Raspberry 上有 Raspbian
,而不是 Debian
,就像我一样,这会更困难,因为有 LXDE 而不是 GNOME。你可以使用alsamixer
和F6按钮来设置声卡,但问题是ALSA是低级接口(interface),而most Linuxes use some sound server on top of it ,例如 PulseAudio 或 JACK。您需要一些运气/花费时间来确保将输入/输出设备切换到麦克风/耳机。
如果您使用 Jack 麦克风,通过 Raspberry Pi 的 Jack 输入插入,请注意,Raspberry Pi 的 Jack 仅用于输入,因此您将无法播放录音,并且需要一些 USB 耳机来收听您的 wav。
就我个人而言,我觉得 ALSA 的文档非常少(我认为这是故意的 job security ),而且我不喜欢处理它。
import pyaudio
import wave
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# This is Qt part: we create a window, which has a "stop" flag.
# Stop flag defaults to False, but is set to True, when you press a key.
# Value of that flag is checked in main loop and loop exits when flag is True.
app = QApplication(sys.argv)
class MyWindow(QWidget):
def __init__(self):
super(QWidget, self).__init__()
self.stop = False
def keyPressEvent(self, event):
print "keyPressedEvent caught!"
self.stop = True
window = MyWindow()
window.show()
# This is sound processing part: we create an input stream to read from microphone.
p = pyaudio.PyAudio()
stream = p.open(format = p.get_format_from_width(2),
channels = 2,
rate=44100,
input=True,
output=False,
frames_per_buffer=1024)
# This is main loop: we iteratively poll audio and gui: audio data are stored in output_buffer,
# whereas gui is checked for stop flag value (if keyPressedEvent happened, flag will be set
# to True and break our main loop).
output_buffer = ""
while True:
app.processEvents()
data = stream.read(1024)
output_buffer += data
if window.stop: break
stream.stop_stream()
stream.close()
# Here we output contents of output_buffer as .wav file
output_wav = wave.open("output.wav", 'w')
output_wav.setparams((2, 2, 44100, len(output_buffer),"NONE","not compressed"))
output_wav.writeframesraw(output_buffer)
p.terminate()
关于c - 如何使用 ALSA 在缓冲区中录制声音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23060155/