11

我最近一直在玩 ruby​​,我决定开始一个简单的项目来编写一个 ruby​​ 脚本,将 line-in 声音记录到.wav文件中。我发现 ruby​​ 不能很好地访问硬件设备(它可能不应该),但是 PortAudio 可以,我在这里发现了一个很棒的 PA 包装器(我认为它不是宝石,因为它使用了 rubyffi附加到 PortAudio,PA 库可以在各种地方)。我一直在摸索 PortAudio 的文档和示例,以了解 PA 的工作原理。我已经很多年没有写作或阅读C了。

我在创建过程中应该将哪些参数传递给流以及在创建过程中传递给缓冲区时遇到了困难。例如,a 到底是什么frame,它与 和 等其他参数有什么channel关系sample rate。一般来说,我对音频编程也完全陌生,所以如果有人能指出一些关于设备级音频的一般教程等,我将不胜感激。

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

  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

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

另外,如果我在这里叫错了树,并且有一种更简单的方法可以做到这一点(在红宝石中),那么一些方向会很好。

4

1 回答 1

3

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

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

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

顺便说一句,我尝试了 ruby​​-portaudio、ffi-portaudio 以及 ruby​​-audio,但它们都没有在我的 Macbook 上正常工作(试图生成正弦波),遗憾的是再次显示,Ruby 无法处理这东西(还没有?)。

于 2012-10-21T09:05:45.303 回答