如何使用 ALSA 在缓冲区中录制声音 [英] How to record sound in buffer using ALSA

查看:30
本文介绍了如何使用 ALSA 在缓冲区中录制声音的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始学习 linux 和 ALSA,我想知道是否有办法将我从麦克风 a 录制的声音直接存储到缓冲区.我在这里阅读 http://www.linuxjournal.com/article/6735?page=0,2 如何制作我的录音程序.但我需要的是更复杂一点.我需要录制声音,直到我按下一个键.我需要这个的原因是因为我在搞乱 RaspberryPI(上面有 debian),想看看我是否可以把它变成一个声音监控/检测设备.

I'm begining to learn linux and ALSA and I was wondering if there is a way to store the sound I record from a microphone a directly to the buffer. I read here http://www.linuxjournal.com/article/6735?page=0,2 how to make my recording program. But what I need is a little more complex. I need to record sound untill I hit a key. The reason I need this is because I'm messing with a RaspberryPI(debian on it) and to see if I could turn it into a sound monitoring/detecting device.

我现在的主要问题是,当我尝试使用它来记录 (./Rec >name.raw ) 时,它什么也不做.它只是输出一个空的 .raw 文件.

My main problem is now that when I try to use it to record (./Rec >name.raw ) it does nothing. It just ouputs an empty .raw file.

#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
", snd_strerror(rc));
    exit(1);
  }

  /* Allocate a hardware parameters object. */
  snd_pcm_hw_params_alloca(&params);

  /* 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
", 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
");
      snd_pcm_prepare(handle);
    } 
    else if (rc < 0)
    {
      fprintf(stderr, "error from read: %s
", snd_strerror(rc));
    } 
    else if (rc != (int)frames) 
    {
      fprintf(stderr, "short read, read %d frames
", rc);
    }

    rc = write(1, buffer, size);

    if (rc != size)
      fprintf(stderr, "short write: wrote %d bytes
", rc);
    key = getchar();
  }

  snd_pcm_drain(handle);
  snd_pcm_close(handle);
  free(buffer);

  return 0;
}

推荐答案

以下是我使用 python 的方法.经测试可在我的桌面 Debian 上使用 USB Plantronics 耳机工作.你需要安装 python-qt4python-pyaudio 包才能工作.

Here is how I did that with python. Tested to work on my desktop Debian with USB Plantronics headphones. You need to install python-qt4 and python-pyaudio packages for this to work.

此外,您还需要将输入设备设置为麦克风.在 GNOME 中,我通过 System Tools -> 切换输入和输出设备.系统设置 -> 声音.如果你的树莓上有 Raspbian,而不是 Debian,就像我一样,它会更难,因为有 LXDE 而不是 GNOME.您可以使用alsamixer和F6按钮设置声卡,但问题是ALSA是低级接口,而大多数 Linux 在它上面使用一些声音服务器,例如 PulseAudio 或 JACK.您需要一些运气/花费时间来确保将输入/输出设备切换到麦克风/耳机.

Also, you'll need to set your input device to microphone. In GNOME I switched both input and output devices via System Tools -> System Settings -> Sound. If you have Raspbian, not Debian on your Raspberry, as I do, it's gonna be tougher, cause there's LXDE instead of GNOME. You can use alsamixer and F6 button there to set audio cards, but the problem is that ALSA is low-level interface, while most Linuxes use some sound server on top of it, such as PulseAudio or JACK. You'll need some luck/spent time to make sure you switched input/output device to your mic/headphones.

如果您使用 Jack 麦克风,通过 Raspberry Pi 的 Jack 输入插入,请注意 Raspberry 的 Jack 仅是输入,因此您将无法播放录音,需要一些 USB 耳机来收听您的 wav.

If you use Jack microphone, plugged in through Jack input of your Raspberry Pi, note that Raspberry's Jack is input only, so you won't be able to play back your recordings and need some USB headphones to listen to your wav.

就我个人而言,我觉得 ALSA 的记录很差(我想这是故意的工作保障) 而我不喜欢处理它.

Personally, I feel that ALSA is very poorly documented (I suppose it's intentional job security) and I don't like to deal with it.

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()

这篇关于如何使用 ALSA 在缓冲区中录制声音的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆