2013-02-22 2 views
9

Я создаю инструмент, который должен запускаться на сервере и анализировать звуковые файлы. Я хочу сделать это в Ruby, поскольку все мои другие инструменты также написаны на Ruby. Но мне трудно найти хороший способ этого.Извлечение быстрого преобразования Фурье данные из файла

Множество примеров, которые я нашел, выполняет визуализаторы и графические материалы. Мне просто нужны данные FFT, не более того. Мне нужно как получить аудиоданные, так и сделать БПФ. Моя конечная цель - рассчитать некоторые вещи, такие как средний/средний/режим, 25-процентный и 75-й процентиль по всем частотам (взвешенная амплитуда), BPM и, возможно, некоторые другие хорошие характеристики, чтобы впоследствии могли группировать подобные звуки вместе ,

Сначала я пытался использовать рубиново-аудио и FFTW3, но я никогда не хожу два по-настоящему работать вместе. Документация не была хорошей, так что я действительно не знал, какие данные перетасовываются. Далее я попытался использовать bplay/brec и ограничить свой скрипт Ruby просто использованием STDIN и выполнить FFT на этом (все еще используя fftw3). Но я не мог заставить bplay/brec работать, поскольку на сервере нет звуковой карты, и мне не удалось просто получить звук непосредственно в STDOUT, не перейдя сначала на аудиоустройство.

Вот ближе я получил:

# 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. Так что, возможно, вы, SO, можете мне помочь?

Спасибо!

+0

Возможно, это предыдущее обсуждение может быть полезным: http://stackoverflow.com/questions/2834548/ruby-play-pause-resume -aac-audio-files – fmendez

+0

Не могли бы вы объяснить, почему вы застряли? Пожалуйста, указывайте сообщения об ошибках или пробелы в своем понимании того, как все должно работать. –

+0

До сих пор я добавил свой код. У меня огромный разрыв между чтением данных с использованием ruby-audio и извлечением FFT с использованием fftw3. См. Комментарий с тремя вопросительными знаками. У меня есть данные wav внутри buf, но я не знаю, что данные действительно представляют/представляют. Есть ли там заголовки? Это сжатие/кодирование? и т. д. и т. д. Я хочу получить данные в get_fft (который берется почти дословно из другого сообщения SO). –

ответ

8

Вот окончательное решение того, чего я пытался достичь, благодаря большому совету Randall Cook. Код для извлечения звуковой волны и FFT файла WAV в Ruby:

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... 
+1

Это выглядит правильно. +1 для размещения кода. Я рад, что вы разблокированы и можете создать что-то, что работает. BTW, отличный способ поблагодарить Stack Overflow - это поддержать и/или принять ответ, если вы этого еще не сделали. ;) –

+0

Я поднял ваш пост, но должен был подождать некоторое время, прежде чем я смогу принять свой собственный ответ. :) –

+0

@ ChristofferBrodd-Reijer ваш код отлично подходит для отпечатков пальца wav-файлов, но отпечаток пальца слишком велик. Вы нашли решение для улучшения скорости и сокращения отпечатка пальца? –

7

Я думаю, что здесь есть две проблемы. Один получает образцы, другой выполняет БПФ.

Для получения образцов существуют два основных этапа: декодирование и сведение к минимуму. Чтобы декодировать wav-файлы, вам просто нужно проанализировать заголовок, чтобы вы могли узнать, как интерпретировать образцы. Для mp3-файлов вам необходимо выполнить полное декодирование. После того, как звук будет декодирован, если вы не хотите обрабатывать стереоканалы отдельно, вам может потребоваться понизить его до моно, так как FFT ожидает один канал в качестве входного сигнала. Если вы не против выходить за пределы Ruby, то sox tool легко справляется. Например, sox song.mp3 -b 16 song.raw channels 1 должен преобразовать mp3 в монофайл из чистых образцов PCM (то есть 16-битных целых чисел). BTW, быстрый поиск показал библиотеку ruby/audio (возможно, это тот, что упоминается в вашем сообщении). Это выглядит довольно хорошо, тем более, что он обертывает libsndfile.

Для выполнения БПФ я вижу три варианта. Один из них заключается в использовании this snippet кода, который выполняет БПФ. Я не эксперт по Ruby, но похоже, что все в порядке. Второй вариант - использовать NArray. Он имеет массу математических методов, включая FFTW, доступных в отдельном модуле, tarball, для которого он связан в середине страницы NArray. Третий вариант - написать собственный код FFT. Это не особенно сложный алгоритм и может дать вам большой опыт работы с числовой обработкой в ​​Ruby (если вам это нужно).

Возможно, вы знаете об этом, но FFT ожидает сложный ввод и генерирует сложный вывод. Разумеется, звуковые сигналы реальны, поэтому мнимая составляющая входа всегда должна быть нулевой (a + 0*i). Поскольку ваш вход велик, выход будет симметричным относительно середины выходного массива. Вы можете смело игнорировать верхнюю половину. Если вам нужна энергия в определенном ящике частоты (они линейно распределены до половины частоты дискретизации), вам нужно будет вычислить величину комплексного значения (sqrt(real*real + imag*imag)).

Еще одна вещь: поскольку частота нуля (смещение по постоянному току сигнала) и частота Найквиста (половина частоты дискретизации) не имеют фазовых компонентов, некоторые реализации БПФ объединяют их в один и тот же сложный бит (один в реальном компонент, один в мнимом компоненте, как правило, первого бункера). Вы можете создать несколько простых сигналов (все 1s только для сигнала постоянного тока и чередование +1, -1 для сигнала Nyquist) и посмотреть, как выглядит выход FFT.

+0

Спасибо за длинный ответ. Это во многом то, о чем я думал. Но я не смог собрать все это вместе. Я добавил некоторый код, чтобы показать, что я получил, когда использовал рубиновый звук (тот, который вы связали), и драгоценный камень fftw3. –

+0

Часто, когда у меня возникают проблемы с переносом вещей, я начинаю очень мало и просто добавляю один шаг за раз, добавляя много диагностического кода (или проверяя переменные в отладчике), чтобы убедиться, что все работает как можно раньше: могу ли я открыть файл? могу ли я читать данные? является ли формат данных, что я ожидаю? я могу преобразовать данные? все еще выглядит правильно? и т. д. –

+0

Да, но я застрял в: каковы эти данные, на которые я смотрю, и как мне его подавать в функцию БПФ? Должен ли я просто предоставить ему содержимое буфера (вызов to_a на buf) или мне нужно его обработать раньше? Я не уверен, что представляют данные, которые я получаю от ruby-audio. –

Смежные вопросы