2012-02-06 14 views
11

He estado jugando con ruby ​​recientemente, y decidí comenzar un proyecto simple para escribir un script de ruby ​​que registra el sonido de entrada de línea en un archivo .wav. Descubrí que el ruby ​​no proporciona un acceso muy bueno a los dispositivos de hardware (y probablemente no debería), pero que PortAudio sí, y descubrí una excelente envoltura para PA here (no es una joya, creo que porque usa ruby's ffi para adjuntar a PortAudio, y la biblioteca de PA podría estar en una variedad de lugares). He estado pasando por la documentación y ejemplos de PortAudio para descubrir cómo funciona la PA. No he escrito ni leído C en años.Usando el envoltorio de PortAudio en ruby ​​para grabar sonido en .wav

Tengo problemas con los parámetros que debería pasar a una secuencia durante la creación, y un buffer durante la creación. Por ejemplo, qué es exactamente un frame, y cómo se relaciona con otros parámetros como channel y sample rate. También soy totalmente nuevo en la programación de audio en general, así que si alguien pudiera indicarme algunos tutoriales generales, etc., sobre audio a nivel de dispositivo, lo agradecería.

ruby-portaudio proporciona un único ejemplo que crea una secuencia y un búfer, escribe una onda sinusoidal en el búfer y luego envía el búfer al flujo que se va a reproducir. Parte del rubí con el que estoy teniendo problemas en el ejemplo, específicamente el bloque de bucle.

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 

Si voy a estar grabando, yo debería estar leyendo una corriente en un buffer, y luego manipular ese búfer y escribirlo en un archivo, ¿verdad?

Además, si estoy ladrando el árbol equivocado aquí, y hay una manera más fácil de hacer esto (en rubí), una dirección sería agradable.

+0

Parece ser una pregunta relacionada (no engañosa) aquí http: // stackoverflow.com/questions/2716987/recording-audio-through-rtmp-rails –

Respuesta

3

Primero, aclaremos los términos sobre los que preguntaba. Con este fin, trataré de explicar el canal de audio de una manera simplificada. Cuando está generando un sonido como en su ejemplo, su tarjeta de sonido solicita periódicamente marcos (= buffers = blocks) de su código, que usted llena con sus muestras. La velocidad de muestreo define cuántas muestras proporciona en un segundo y, por lo tanto, la velocidad con la que se reproducen sus muestras. El tamaño del marco (= tamaño del búfer = tamaño del bloque) determina la cantidad de muestras que proporciona en una solicitud de la tarjeta de sonido. Un búfer suele ser bastante pequeño, porque el tamaño del búfer afecta directamente a la latencia (gran búfer => alta latencia) y los grandes arreglos pueden ser lentos (especialmente los arreglos de ruby ​​son lentos).

Suceden cosas similares cuando graba sonido de su tarjeta de sonido. Su función recibe una llamada de vez en cuando, y las muestras del micrófono generalmente se pasan como un argumento a la función (o incluso una referencia a dicho búfer). Luego se espera que procese estas muestras, p. escribiéndolos en el disco.

Sé que la idea de "hacer todo en Ruby" es bastante tentadora, porque es un lenguaje tan hermoso. Cuando esté planeando hacer procesamiento de audio en tiempo real, le recomendaría cambiar a un lenguaje compilado (C, C++, Obj-C, ...). Éstos pueden manejar el audio mucho mejor, porque están mucho más cerca del hardware que Ruby y, por lo tanto, generalmente son más rápidos, lo que puede ser un gran problema en el procesamiento de audio. Esta es probablemente también la razón por la que hay tan pocas bibliotecas de audio Ruby, entonces quizás Ruby no sea la herramienta adecuada para el trabajo.

Por cierto, probé ruby-portaudio, ffi-portaudio y ruby-audio y ninguno de ellos funcionaba correctamente en mi Macbook (traté de generar una onda sinusoidal), lo que tristemente muestra otra vez, cómo es Ruby no es capaz de manejar esto (¿todavía?).

+0

Si puede meterse con el audio a través de una interfaz gráfica de usuario, puede meterse con él a través de un lenguaje de scripting. Por ejemplo, Pure Data es un divertido lenguaje de programación de audio gráfico que, por supuesto, al menos una persona está tratando de [conducir con Ruby] (http://matschaffer.com/2010/11/ruby-midi-pure-data/) Estoy seguro de que hay esfuerzos similares con [otros entornos de síntesis de audio] (http://en.wikipedia.org/wiki/Comparison_of_audio_synthesis_environments). – mgamba

+0

Pero eso sería solo una envoltura alrededor de una biblioteca ajustada al rendimiento que maneja la síntesis real, ¿verdad? Me refiero más bien a un enfoque puro de Ruby. –

+0

Aquí hay un código de Ruby para enviar a .wav: https://github.com/cohena/RAFL/blob/master/RAFL_wav.rb – mgamba

Cuestiones relacionadas