11

サーバー上で実行してサウンド ファイルを分析するツールを作成しています。他のすべてのツールも Ruby で作成されているため、これを Ruby で実行したいと考えています。しかし、これを達成する良い方法を見つけるのに苦労しています。

私が見つけた多くの例は、ビジュアライザーとグラフィカルなものを行っています。FFT データだけが必要です。オーディオ データを取得し、FFT を実行する必要があります。私の最終的な目標は、平均/中央値/モード、25 パーセンタイル、75 パーセンタイル、すべての周波数 (重み付けされた振幅)、BPM、および後で同様の音をクラスター化できるようにするためのその他の優れた特性などを計算することです。 .

最初はruby ​​-audioとfftw3を使用しようとしましたが、2 つを実際に連携させることはありませんでした。ドキュメンテーションもよくなかったので、どのデータがシャッフルされているのか本当にわかりませんでした。次に、bplay / brecを使用して、Ruby スクリプトを STDIN のみを使用するように制限し、その上で FFT を実行しようとしました (まだ fftw3 を使用しています)。しかし、サーバーにサウンドカードがなく、最初にオーディオデバイスに行かずにオーディオを直接 STDOUT に送ることができなかったため、bplay/brec を機能させることができませんでした。

これが私が得た最も近いものです:

# extracting audio from wav with ruby-audio
buf = RubyAudio::Buffer.float(1024)
RubyAudio::Sound.open(fname) do |snd|
    while snd.read(buf) != 0
        # ???
    end
end

# performing FFT on audio
def get_fft(input, window_size)
    data = input.read(window_size).unpack("s*")
    na = NArray.to_na(data)
    fft = FFTW3.fft(na).to_a[0, window_size/2]
    return fft
end

だから今、私は立ち往生しており、Googleでこれ以上良い結果を見つけることができません. それで、おそらくあなたたちは私を助けることができますか?

ありがとう!

4

2 に答える 2

9

Randall Cookの有益なアドバイスに感謝し、これが私が達成しようとしていたことに対する最終的な解決策です。Rubyでwavファイルの音波とFFTを抽出するコード:

require "ruby-audio"
require "fftw3"

fname = ARGV[0]
window_size = 1024
wave = Array.new
fft = Array.new(window_size/2,[])

begin
    buf = RubyAudio::Buffer.float(window_size)
    RubyAudio::Sound.open(fname) do |snd|
        while snd.read(buf) != 0
            wave.concat(buf.to_a)
            na = NArray.to_na(buf.to_a)
            fft_slice = FFTW3.fft(na).to_a[0, window_size/2]
            j=0
            fft_slice.each { |x| fft[j] << x; j+=1 }
        end
    end

rescue => err
    log.error "error reading audio file: " + err
    exit
end

# now I can work on analyzing the "fft" and "wave" arrays...
于 2013-02-25T06:39:03.433 に答える
8

ここには2つの問題があると思います。1 つはサンプルの取得、もう 1 つは FFT の実行です。

サンプルを取得するには、デコードとダウンミックスという 2 つの主な手順があります。wav ファイルをデコードするには、ヘッダーを解析するだけで、サンプルの解釈方法を知ることができます。mp3 ファイルの場合は、完全なデコードを行う必要があります。オーディオがデコードされたら、ステレオ チャンネルを個別に処理することに関心がない場合は、FFT が入力として 1 つのチャンネルを想定しているため、モノラルにダウンミックスする必要がある場合があります。Ruby の外に出ることを気にしないのであれば、sox ツールを使えば簡単です。たとえばsox song.mp3 -b 16 song.raw channels 1、mp3 を純粋な PCM サンプル (つまり、16 ビット整数) のモノラル ファイルに変換する必要があります。ところで、簡単な検索でruby​​/audioライブラリが見つかりました (おそらく、投稿で言及されているものです)。特に libsndfile をラップしているので、かなり良さそうです。

FFT を実行するには、3 つのオプションがあります。1 つは、FFT を実行するこのコードスニペットを使用することです。私は Ruby の専門家ではありませんが、問題ないようです。2 番目のオプションは、NArrayを使用することです。FFTW を含む多数の数学的手法があり、別のモジュールで利用できます。そのための tarball は、NArray ページの中央にリンクされています。3 番目のオプションは、独自の FFT コードを作成することです。これは特に複雑なアルゴリズムではなく、Ruby での数値処理を体験するのに最適です (必要な場合)。

おそらくこれに気付いているでしょうが、FFT は複雑な入力を想定し、複雑な出力を生成します。もちろん、オーディオ信号は実数であるため、入力の虚数成分は常にゼロにする必要があります ( a + 0*i)。入力が実数であるため、出力は出力配列の中点に対して対称になります。上半分は無視しても問題ありません。特定の周波数ビン (サンプル レートの半分まで直線的に間隔をあける) のエネルギーが必要な場合は、複素数値 ( sqrt(real*real + imag*imag)) の大きさを計算する必要があります。

もう 1 つ: 周波数ゼロ (信号の DC オフセット) とナイキスト周波数 (サンプル レートの半分) には位相成分がないため、一部の FFT 実装ではそれらを同じ複素ビン (実数成分に 1 つ、実数成分に 1 つ) にまとめます。通常は最初のビンの虚数成分)。いくつかの単純な信号 (DC 信号のみの場合はすべて 1、ナイキスト信号の場合は +1、-1 を交互に使用) を作成し、FFT 出力がどのように見えるかを確認できます。

于 2013-02-22T23:53:55.983 に答える