Domanda

So che ci sono alcune domande simili qui, ma la maggior parte di esse riguarda la generazione della forma d'onda immagini, che non è quello che voglio.

Il mio obiettivo è generare una visualizzazione della forma d'onda per un file audio, simile a SoundCloud, ma non a un'immagine. Vorrei avere i dati di ampiezza massima per ogni secondo (o mezzo secondo) di una clip audio in un array. Potrei quindi utilizzare questi dati per creare una visualizzazione basata su CSS.

Idealmente vorrei ottenere un array che abbia tutti i valori di ampiezza per ogni secondo in percentuale della massima ampiezza dell'intero file audio. Ecco un esempio:

[
    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%)
]

Presumo che dovrò usare almeno numpy e Python's wave Modulo, ma non sono sicuro di come ottenere i dati che desidero. Vorrei usare Python ma non sono completamente contrario a usare una sorta di strumento di comando.

È stato utile?

Soluzione

Se permetti GStreamer, ecco una piccola sceneggiatura che potrebbe fare il trucco. Accetta qualsiasi file audio che Gstreamer può gestire.

  • Costruire una pipeline GStreamer, utilizzare Audioconvert per ridurre i canali a 1 e utilizzare il modulo a livello per ottenere picchi
  • Esegui la pipeline fino a quando EOS non viene colpito
  • Normalizza i picchi dal min/max trovato.

Frammento:

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

E un esempio di output:

$ 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, ...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top