2012-02-06 12 views
11

Recentemente ho giocato con Ruby e ho deciso di avviare un progetto semplice per scrivere uno script ruby ​​che registra il suono line-in su un file .wav. Ho scoperto che ruby ​​non fornisce un ottimo accesso ai dispositivi hardware (e probabilmente non dovrebbe), ma che PortAudio lo fa, e ho scoperto un ottimo wrapper per PA here (non è una gemma, penso perché usa ruby's ffi da collegare a PortAudio e la libreria PA potrebbe trovarsi in una varietà di posti). Mi sono confuso con la documentazione e gli esempi di PortAudio per capire come funziona la PA. Non ho scritto o letto C in anni.Utilizzo del wrapper PortAudio in ruby ​​per registrare il suono in .wav

Sono in difficoltà con quali parametri dovrei passare a uno stream durante la creazione e un buffer durante la creazione. Ad esempio, che cos'è esattamente un frame e in che modo è correlato ad altri parametri come channel e sample rate. Sono totalmente nuovo alla programmazione audio in generale, quindi se qualcuno mi può indirizzare ad alcune esercitazioni generali, ecc. Sull'audio a livello di dispositivo, lo apprezzerei.

ruby-portaudio fornisce un singolo esempio che crea un flusso e un buffer, scrive un'onda sin nel buffer, quindi invia il buffer al flusso da riprodurre. Alcuni dei rubini con cui ho problemi nell'esempio, in particolare il blocco del ciclo.

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 

Se ho intenzione di essere la registrazione, io dovrei leggere un flusso in un buffer, quindi manipolare tale buffer e la scrittura di file, giusto?

Inoltre, se sto latrando l'albero sbagliato qui, e c'è un modo più semplice per farlo (in ruby), qualche direzione sarebbe carina.

+0

Sembra essere una domanda correlata (non dupe) qui http: // stackoverflow.it/questions/2716987/recording-audio-through-rtmp-rails –

risposta

3

Prima chiariamo i termini che stavi chiedendo. Per questo scopo cercherò di spiegare la pipeline audio in modo semplificato. Quando generi un suono come nel tuo esempio, la tua scheda audio richiede periodicamente telegrammi (= buffer = blocchi) dal tuo codice, che puoi riempire con i tuoi campioni. La frequenza di campionamento definisce quanti campioni fornisci entro un secondo e quindi la velocità con cui i tuoi campioni vengono riprodotti. La dimensione del frame (= dimensione del buffer = dimensione del blocco) determina quanti campioni fornisci in una richiesta dalla scheda audio. Un buffer è in genere piuttosto piccolo, poiché la dimensione del buffer influenza direttamente la latenza (buffer di grandi dimensioni => latenza elevata) e gli array di grandi dimensioni possono essere lenti (in particolare gli array di ruby ​​sono lenti).

Le cose simili accadono quando si registra il suono dalla scheda audio. La tua funzione viene chiamata di tanto in tanto, e i campioni dal microfono vengono tipicamente passati come argomento alla funzione (o anche solo un riferimento a tale buffer). Quindi ci si aspetta che elabori questi campioni, ad es. scrivendoli su disco.

So che il pensiero di "fare tutto in Ruby" è piuttosto allettante, perché è un linguaggio così bello. Tuttavia, quando stai pianificando di eseguire l'elaborazione audio in tempo reale, ti consiglio di passare a un linguaggio compilato (C, C++, Obj-C, ...). Questi possono gestire l'audio molto meglio, perché sono molto più vicini all'hardware di Ruby e quindi generalmente più veloci, il che può rappresentare un problema nell'elaborazione dell'audio. Probabilmente questo è anche il motivo per cui ci sono così poche librerie audio Ruby in giro, quindi forse Ruby non è lo strumento giusto per il lavoro.

A proposito, ho provato ruby-portaudio, ffi-portaudio e ruby-audio e nessuno di questi funzionava correttamente sul mio Macbook (provavo a generare un'onda sinusoidale) che mostra purtroppo ancora, come Ruby è non è in grado di gestire questa roba (ancora?).

+0

Se riesci a fare confusione con l'audio attraverso una GUI, puoi scherzare con esso attraverso un linguaggio di scripting. Ad esempio, Pure Data è un divertente linguaggio di programmazione audio grafico che, sicuramente, almeno una persona sta provando a [guidare con Ruby] (http://matschaffer.com/2010/11/ruby-midi-pure-data/). Sono sicuro che ci sono sforzi simili con [altri ambienti di sintesi audio] (http://en.wikipedia.org/wiki/Comparison_of_audio_synthesis_environments). – mgamba

+0

Ma quello sarebbe solo un involucro attorno a una libreria messa a punto dalle prestazioni che gestisce la sintesi attuale, giusto? Mi riferivo piuttosto a un approccio puro di Ruby. –

+0

Ecco un po 'di codice Ruby per l'output in .wav: https://github.com/cohena/RAFL/blob/master/RAFL_wav.rb – mgamba

Problemi correlati