2012-02-06 3 views
11

Недавно я играл с рубином, и я решил запустить простой проект для записи рубинового скрипта, который записывает линейный звук в файл .wav. Я обнаружил, что Ruby не обеспечивает очень хороший доступ к аппаратным устройствам (и это, вероятно, не стоит), но это PortAudio делает, и я обнаружил отличную оболочку для PA here (это не самоцвет, я думаю, потому что он использует рубины ffi для подключения к PortAudio, а библиотека PA может быть в разных местах). Я пытался запутаться в документации и примерах PortAudio, чтобы выяснить, как работает PA. Я не писал или читал C годами.Использование обложек PortAudio в рубине для записи звука в .wav

Я сталкиваюсь с трудностями с тем, какие параметры я должен передавать в поток во время создания, и буфер во время создания. Например, что такое 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 

Если я буду записывать, я должен читать поток в буфер, а затем манипулировать этот буфер и записи его в файл, верно?

Кроме того, если я лаю по неправильному дереву здесь, и есть более простой способ сделать это (в рубине), какое-то направление будет приятным.

+0

Кажется, что связанный (не обманывающий) вопрос здесь http: // stackoverflow.com/questions/2716987/record-audio-through-rtmp-rails –

ответ

3

Давайте сначала уточним условия, о которых вы просили. Для этого я попытаюсь объяснить аудиопроводку упрощенным способом. Когда вы генерируете звук, как в вашем примере, ваша звуковая карта периодически запрашивает кадры (= буферы = блоки) из вашего кода, которые вы заполняете своими образцами. Частота выборки определяет, сколько образцов вы предоставляете в течение секунды и, следовательно, скорость воспроизведения ваших образцов. Размер кадра (= размер буфера = размер блока) определяет, сколько выборок вы предоставили по одному запросу со звуковой карты. Буфер обычно довольно мал, поскольку размер буфера непосредственно влияет на задержку (большой буфер => высокая латентность), а большие массивы могут быть медленными (особенно рубиновые массивы медленны).

Подобные вещи случаются, когда вы записываете звук с вашей звуковой карты. Ваша функция вызывается время от времени, и образцы из микрофона обычно передаются в качестве аргумента функции (или даже просто ссылки на такой буфер). Затем вы должны обработать эти образцы, например. записывая их на диск.

Я знаю, что мысль о том, что «все делает в Рубине», довольно соблазнительна, потому что это такой красивый язык. Когда вы планируете обрабатывать аудио в реальном времени, я бы рекомендовал переключиться на скомпилированный язык (C, C++, Obj-C, ...). Они могут обрабатывать звук намного лучше, потому что они намного ближе к оборудованию, чем Ruby, и, как правило, быстрее, что может быть довольно проблемой при обработке звука. Вероятно, это также причина, по которой так мало звуковых библиотек Ruby, поэтому Ruby просто не подходит для этой работы.

Кстати, я попробовал Ruby-portaudio, ffi-portaudio, а также ruby-audio, и никто из них не работал должным образом на моем Macbook (пытался генерировать синусоидальную волну), который, к сожалению, снова показывает, как Ruby не способен обрабатывать этот материал (пока?).

+0

Если вы можете общаться со звуком через gui, вы можете общаться с ним через язык сценариев. Например, Pure Data - это веселый графический язык звукового программирования, который, конечно же, по крайней мере один человек пытается [управлять с Ruby] (http://matschaffer.com/2010/11/ruby-midi-pure-data/). Я уверен, что есть аналогичные усилия с [другими средами синтеза аудио] (http://en.wikipedia.org/wiki/Comparison_of_audio_synthesis_environments). – mgamba

+0

Но это будет просто обертка вокруг настраиваемой библиотеки, которая обрабатывает фактический синтез, правильно? Я скорее имел в виду чистый подход Ruby. –

+0

Вот код Ruby для вывода на .wav: https://github.com/cohena/RAFL/blob/master/RAFL_wav.rb – mgamba