在ruby中使用PortAudio包装器将声音录制到.wav

时间:2012-02-06 16:25:02

标签: ruby audio wav portaudio

我最近一直在玩ruby,我决定开始一个简单的项目来编写一个ruby脚本来记录.wav文件的输入声音。我发现ruby不能很好地访问硬件设备(它可能不应该),但PortAudio确实如此,我发现了PA here的一个很好的包装器(我认为它不是宝石)因为它使用ruby的ffi附加到PortAudio,PA库可以在各种各样的地方)。我一直在弄乱PortAudio的文档和示例来弄清楚PA是如何工作的。多年来我没有写过或读过C

我在创建过程中应该将哪些参数传递给流,以及创建期间的缓冲区时遇到了困难。例如,frame究竟是什么,以及它与channelsample rate等其他参数的关系。我对音频编程也很陌生,所以如果有人能指点我一些关于设备级音频的一般教程等,我会很感激。

ruby-portaudio提供了一个创建流和缓冲区的示例,将sin波写入缓冲区,然后将缓冲区发送到要播放的流。我在示例中遇到了一些问题,特别是循环块。

  PortAudio.init

  block_size = 1024
  sr   = 44100
  step = 1.0/sr
  time = 0.0

  stream = PortAudio::Stream.open(
             :sample_rate => sr,
             :frames => block_size,
             :output => {
               :device => PortAudio::Device.default_output,
               :channels => 1,
               :sample_format => :float32
              })

  buffer = PortAudio::SampleBuffer.new(
             :format   => :float32,
             :channels => 1,
             :frames   => block_size)

  playing = true
  Signal.trap('INT') { playing = false }
  puts "Ctrl-C to exit"

  stream.start

  loop do
    stream << buffer.fill { |frame, channel|
      time += step
      Math.cos(time * 2 * Math::PI * 440.0) * Math.cos(time * 2 * Math::PI)
    }

    break unless playing
  end

  stream.stop

如果我要录制,我应该将一个流读入缓冲区,然后操作该缓冲区并将其写入文件,对吧?

另外,如果我在这里咆哮错误的树,并且有更简单的方法(红宝石),那么某个方向会很好。

1 个答案:

答案 0 :(得分:3)

让我们首先澄清您所询问的术语。为此,我将尝试以简化的方式解释音频管道。当您在示例中生成声音时,声卡会定期从您的代码中请求帧(= buffers = blocks),您可以使用示例填充这些帧。采样率定义了您在一秒钟内提供的样本数量,从而定义了样本播放的速度。帧大小(=缓冲区大小=块大小)确定您在声卡的一个请求中提供的样本数。缓冲区通常非常小,因为缓冲区大小直接影响延迟(大缓冲区=&gt;高延迟),大型数组可能很慢(特别是ruby阵列很慢)。

当您从声卡录制声音时会发生类似情况。您的函数会不时被调用,麦克风中的样本通常作为参数传递给函数(或者甚至只是对这样的缓冲区的引用)。然后,您需要处理这些样本,例如将它们写入磁盘。

我知道“在Ruby中做所有事情”的想法很诱人,因为它是如此美妙的语言。当您计划实时进行音频处理时,我建议切换到编译语言(C,C ++,Obj-C,...)。这些可以更好地处理音频,因为它们比Ruby更接近硬件,因此通常更快,这在音频处理中可能是一个很大的问题。这可能也是为什么周围有很少的Ruby音频库的原因,因此Ruby可能不适合这项工作。

顺便说一句,我尝试了ruby-portaudio,ffi-portaudio以及ruby-audio,并且没有一个在我的Macbook上正常工作(试图生成正弦波),这可悲地再次显示,Ruby不是能够处理这些东西(但是?)。