Получение максимальной амплитуды аудиофайла в секунду

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

Моя цель — создать визуализацию формы волны для аудиофайла, похожую на SoundCloud, но не изображение. Я хотел бы иметь данные максимальной амплитуды для каждой секунды (или половины секунды) аудиоклипа в массиве. Затем я мог бы использовать эти данные для создания визуализации на основе CSS.

В идеале я хотел бы получить массив, содержащий все значения амплитуды для каждой секунды в процентах от максимальной амплитуды всего аудиофайла. Вот пример:

[
    0.0,  # Relative max amplitude of first second of audio clip (0%)
    0.04,  # Relative max amplitude of second second of audio clip (4%)
    0.15,  # Relative max amplitude of third second of audio clip (15%)
    # Some more
    1.0,  # The highest amplitude of the whole audio clip will be 1.0 (100%)
]

Я предполагаю, что мне придется использовать как минимум numpy и модуль Python wave, но я не уверен, как получить нужные мне данные. Я хотел бы использовать Python, но я не полностью против использования какого-либо инструмента командной строки.


person Liam    schedule 18.02.2012    source источник
comment
Какой тип файла вы будете читать? только вав?   -  person tito    schedule 19.02.2012
comment
Тип файла будет любым требуемым форматом, так как я все равно использую ffmpeg для преобразования файла без потерь. Я просто использовал wav в качестве примера, потому что решил, что с ним будет проще всего работать.   -  person Liam    schedule 19.02.2012
comment
Вы бы разрешили gstreamer? я работал с ним для получения пика аудиопотока txzone .net/2011/05/using-microphone-peak-as-input, можно очень легко сделать то же самое для любого файла.   -  person tito    schedule 19.02.2012


Ответы (1)


Если вы разрешите gstreamer, вот небольшой скрипт, который может помочь. Он принимает любой аудиофайл, который может обработать gstreamer.

  • Создайте конвейер gstreamer, используйте audioconvert, чтобы уменьшить количество каналов до 1, и используйте модуль уровня, чтобы получить пики.
  • Запустите конвейер, пока не будет достигнут EOS
  • Нормализуйте пики от найденного минимума/максимума.

Фрагмент:

import os, sys, pygst
pygst.require('0.10')
import gst, gobject
gobject.threads_init()

def get_peaks(filename):
    global do_run

    pipeline_txt = (
        'filesrc location="%s" ! decodebin ! audioconvert ! '
        'audio/x-raw-int,channels=1,rate=44100,endianness=1234,'
        'width=32,depth=32,signed=(bool)True !'
        'level name=level interval=1000000000 !'
        'fakesink' % filename)
    pipeline = gst.parse_launch(pipeline_txt)

    level = pipeline.get_by_name('level')
    bus = pipeline.get_bus()
    bus.add_signal_watch()

    peaks = []
    do_run = True

    def show_peak(bus, message):
        global do_run
        if message.type == gst.MESSAGE_EOS:
            pipeline.set_state(gst.STATE_NULL)
            do_run = False
            return
        # filter only on level messages
        if message.src is not level or \
           not message.structure.has_key('peak'):
            return
        peaks.append(message.structure['peak'][0])

    # connect the callback
    bus.connect('message', show_peak)

    # run the pipeline until we got eos
    pipeline.set_state(gst.STATE_PLAYING)
    ctx = gobject.gobject.main_context_default()
    while ctx and do_run:
        ctx.iteration()

    return peaks

def normalize(peaks):
    _min = min(peaks)
    _max = max(peaks)
    d = _max - _min
    return [(x - _min) / d for x in peaks]

if __name__ == '__main__':
    filename = os.path.realpath(sys.argv[1])
    peaks = get_peaks(filename)

    print 'Sample is %d seconds' % len(peaks)
    print 'Minimum is', min(peaks)
    print 'Maximum is', max(peaks)

    peaks = normalize(peaks)
    print peaks

И один пример вывода:

$ python gstreamerpeak.py 01\ Tron\ Legacy\ Track\ 1.mp3 
Sample is 182 seconds
Minimum is -349.999999922
Maximum is -2.10678956719
[0.0, 0.0, 0.9274581631597019, 0.9528318436488018, 0.9492396611762614,
0.9523404330322813, 0.9471685835966183, 0.9537281219301242, 0.9473486577135167,
0.9479292126411365, 0.9538221105563514, 0.9483845795252251, 0.9536790832823281,
0.9477264933378022, 0.9480077366961968, ...
person tito    schedule 19.02.2012
comment
Я пытался заставить ваш скрипт работать, но столкнулся с проблемами. Когда я запускаю конвейерный текст в терминале с помощью gst-launch, я получаю следующее: ERROR: from element /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstMpegAudioParse:mpegaudioparse0: GStreamer encountered a general stream error. Additional debug info: gstbaseparse.c(2695): gst_base_parse_loop (): /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstMpegAudioParse:mpegaudioparse0: streaming stopped, reason not-linked ERROR: pipeline doesn't want to preroll. Есть идеи, в чем может быть проблема? - person Liam; 20.02.2012
comment
Вы можете попробовать добавить сообщение печати в метод show_peak() в начале, вы можете получить больше информации. Или запустите с GST_DEBUG=*:5 (осторожно, много много многословно) - person tito; 20.02.2012
comment
У меня все еще есть проблемы с тем, чтобы это работало, но я подозреваю, что это может быть связано с моей установкой gstreamer, а не с вашим скриптом. Я продолжу и приму ваш ответ на данный момент. Спасибо за помощь! - person Liam; 22.02.2012
comment
Просто к вашему сведению, я наконец-то смог правильно скомпилировать gstreamer на своей машине и успешно запустить ваш скрипт! Огромное спасибо. - person Liam; 16.03.2012