2012-02-06 12 views
11

Ostatnio grałem z rubinem i postanowiłem rozpocząć prosty projekt napisania skryptu ruby, który nagrywa dźwięk line-in do pliku .wav. Odkryłem, że ruby ​​nie zapewnia bardzo dobrego dostępu do urządzeń (i prawdopodobnie nie powinien), ale PortAudio to robi, i odkryłem wspaniałe opakowanie dla PA here (to nie jest klejnot, myślę, że ponieważ używa ruby ffi, aby dołączyć do PortAudio, a biblioteka PA może znajdować się w różnych miejscach). Przekręcałem dokumentację i przykłady PortAudio, aby dowiedzieć się, jak działa PA. Nie pisałem ani nie czytałem w ciągu ostatnich lat C.Używanie opakowania PortAudio w Ruby do nagrywania dźwięku do .wav

Występują problemy z parametrami, które powinienem przekazać do strumienia podczas tworzenia i bufor podczas tworzenia. Na przykład, czym dokładnie jest frame i jak jest on powiązany z innymi parametrami, takimi jak channel i sample rate. Zupełnie nowy jestem także w dziedzinie programowania audio, więc jeśli ktoś mógłby wskazać mi ogólne samouczki, itp., Na temat dźwięku na poziomie urządzenia, byłbym wdzięczny.

ruby-portaudio dostarcza pojedynczy przykład, który tworzy strumień i bufor, zapisuje falę sinową w buforze, a następnie wysyła bufor do odtwarzanego strumienia. Niektóre ruby, z którymi mam problem w tym przykładzie, w szczególności blok pętli.

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 

Jeśli mam być zapis, że należy czytać strumień do bufora, a następnie manipuluje, że bufor i pisanie go złożyć, tak?

Ponadto, jeśli szczeszczę złe drzewo tutaj, i jest łatwiejszy sposób na zrobienie tego (w rubinach), pewien kierunek byłby miły.

+0

Wydaje się być pokrewnym (nie dupe) pytanie tutaj http: // stackoverflow.com/questions/2716987/recording-audio-through-rtmp-rails –

Odpowiedz

3

Najpierw wyjaśnij warunki, o które pytałeś. W tym celu postaram się wyjaśnić uproszczony przebieg audio. Kiedy generujesz dźwięk, jak w twoim przykładzie, twoja karta dźwiękowa okresowo prosi o ramki (= bufory = bloki) z twojego kodu, które wypełniasz samplami. Szybkość próbkowania określa liczbę próbek dostarczanych w ciągu sekundy, a tym samym szybkość, z jaką odtwarzane są próbki. Rozmiar ramki (= rozmiar bufora = rozmiar bloku) określa liczbę próbek, które podajesz w jednym żądaniu z karty dźwiękowej. Bufor jest zwykle dość mały, ponieważ rozmiar bufora wpływa bezpośrednio na opóźnienie (duży bufor => duże opóźnienie), a duże tablice mogą być powolne (szczególnie tablice ruby ​​są wolne).

Podobne rzeczy się zdarzają, gdy nagrywasz dźwięk z karty dźwiękowej. Twoja funkcja jest wywoływana co jakiś czas, a próbki z mikrofonu są zwykle przekazywane jako argument do funkcji (lub nawet tylko do odniesienia do takiego bufora). Następnie oczekuje się przetworzenia tych próbek, np. zapisując je na dysku.

Wiem, że myśl o "robieniu wszystkiego w Ruby" jest dość kusząca, ponieważ jest to piękny język. Kiedy planujesz przetwarzanie dźwięku w czasie rzeczywistym, polecam jednak przełączenie na skompilowany język (C, C++, Obj-C, ...). Mogą one lepiej radzić sobie z dźwiękiem, ponieważ są znacznie bliższe sprzętowi niż Ruby, a zatem generalnie szybsze, co może stanowić problem w przetwarzaniu dźwięku. Jest to prawdopodobnie również powód, dla którego jest tak niewiele bibliotek audio Ruby, więc być może Ruby nie jest odpowiednim narzędziem do tej pracy.

Przy okazji wypróbowałem ruby-portaudio, ffi-portaudio oraz ruby-audio i żaden z nich nie działał poprawnie na moim Macbooku (próbował wygenerować falę sinusoidalną), co niestety znowu pokazuje, jak Ruby nie jest w stanie obsłużyć tych rzeczy (jeszcze?).

+0

Jeśli możesz zadzwonić z dźwiękiem za pomocą gui, możesz zepsuć je za pomocą języka skryptowego. Na przykład Pure Data jest zabawnym graficznym językiem programowania audio, który, na pewno, przynajmniej jedna osoba próbuje [prowadzić z Ruby] (http://matschaffer.com/2010/11/ruby-midi-pure-data/). Jestem pewien, że są podobne wysiłki w [innych środowiskach syntezy audio] (http://en.wikipedia.org/wiki/Comparison_of_audio_synthesis_environments). – mgamba

+0

Ale to byłby po prostu wrapper wokół biblioteki z dostrajaniem wydajności, która obsługuje rzeczywistą syntezę, prawda? Miałem raczej na myśli podejście czysto rubinowe. –

+0

Oto trochę kodu Ruby do wyprowadzenia na .wav: https://github.com/cohena/RAFL/blob/master/RAFL_wav.rb – mgamba

Powiązane problemy