Использование обложек PortAudio в рубине для записи звука в .wav
Недавно я играл с рубином, и я решил запустить простой проект для записи ruby script, который записывает линейный звук в файл .wav
. Я обнаружил, что Ruby не обеспечивает очень хороший доступ к аппаратным устройствам (и это, вероятно, не стоит), но это PortAudio делает, и я обнаружил отличную оболочку для PA здесь (это не жемчужина, я думаю, потому что он использует ruby ffi
для присоединения к PortAudio, а библиотека PA может быть в разных местах). Я пытался запутаться в документации и примерах PortAudio, чтобы выяснить, как работает PA. Я не писал и не читал C
годами.
Я сталкиваюсь с трудностями с тем, какие параметры я должен передавать потоку во время создания, и буфером во время создания. Например, что такое 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
Если я собираюсь записывать, я должен читать поток в буфер, а затем манипулировать этим буфером и записывать его в файл, правильно?
Кроме того, если я лаю здесь неправильное дерево, и есть более простой способ сделать это (в рубине), какое-то направление было бы приятным.
Ответы
Ответ 1
Позвольте сначала уточнить условия, о которых вы спрашивали. Для этого я попытаюсь объяснить аудиопроводку упрощенным способом. Когда вы генерируете звук, как в вашем примере, ваша звуковая карта периодически запрашивает кадры (= буферы = блоки) из вашего кода, которые вы заполняете своими образцами. Частота выборки определяет, сколько образцов вы предоставляете в течение секунды и, следовательно, скорость воспроизведения ваших образцов. Размер кадра (= размер буфера = размер блока) определяет, сколько выборок вы предоставили по одному запросу со звуковой карты. Буфер обычно довольно мал, потому что размер буфера непосредственно влияет на задержку (большой буфер = > высокая латентность), а большие массивы могут быть медленными (особенно рубиновые массивы медленны).
Подобные вещи случаются, когда вы записываете звук с вашей звуковой карты. Ваша функция вызывается время от времени, и образцы из микрофона обычно передаются в качестве аргумента функции (или даже просто ссылки на такой буфер). Затем вы должны обработать эти образцы, например. путем записи их на диск.
Я знаю, что мысль о том, что "все делает в Ruby", довольно соблазнительна, потому что это такой красивый язык. Когда вы планируете обрабатывать аудио в реальном времени, я бы рекомендовал переключиться на скомпилированный язык (C, С++, Obj-C,...). Они могут обрабатывать звук намного лучше, потому что они намного ближе к оборудованию, чем Ruby, и, как правило, быстрее, что может быть довольно проблемой при обработке звука. Вероятно, это также причина, по которой так мало звуковых библиотек Ruby, поэтому Ruby просто не подходит для этой работы.
Кстати, я пробовал ruby-portaudio, ffi-portaudio, а также ruby-audio, и ни один из них не работал должным образом на моем Macbook (пытался генерировать синусоидальную волну), который, к сожалению, снова показывает, как Ruby не способный обрабатывать этот материал (пока?).