Importación de archivos de sonido en Python como arreglos NumPy (alternativas a audiolab)

He estado usando Audiolab para importar archivos de sonido en el pasado, y funcionó bastante bien. Sin embargo:

  • No admite algunos formatos, como mp3, porque el archivo subyacente libsndfile se niega a admitirlos
  • No funciona en Python 2.6 en Windows , y el autor no está ahí para solucionarlo

In [2]: from scikits import audiolab -------------------------------------------------------------------- ImportError Traceback (most recent call last) C:\Python26\Scripts\ in () C:\Python26\lib\site-packages\scikits\audiolab\__init__.py in () 23 __version__ = _version 24 ---> 25 from pysndfile import formatinfo, sndfile 26 from pysndfile import supported_format, supported_endianness, \ 27 supported_encoding, PyaudioException, \ C:\Python26\lib\site-packages\scikits\audiolab\pysndfile\__init__.py in () ----> 1 from _sndfile import Sndfile, Format, available_file_formats, available_encodings 2 from compat import formatinfo, sndfile, PyaudioException, PyaudioIOError 3 from compat import supported_format, supported_endianness, supported_encoding ImportError: DLL load failed: The specified module could not be found.`` 

Así que me gustaría:

  • Averigüe por qué no funciona en 2.6 (¿hay algún problema con _sndfile.pyd?) Y quizás encuentre una manera de extenderlo para que funcione con formatos no compatibles
  • Encuentre un reemplazo completo para audiolab

Audiolab me está funcionando en Ubuntu 9.04 con Python 2.6.2, por lo que podría ser un problema de Windows. En su enlace al foro, el autor también sugiere que es un error de Windows.

En el pasado, esta opción también me ha funcionado:

 from scipy.io import wavfile fs, data = wavfile.read(filename) 

Solo tenga en cuenta que los data pueden tener un tipo de datos int , por lo que no se escalan dentro de [-1,1). Por ejemplo, si los data son int16 , debe dividir los data por 2**15 para escalar dentro de [-1,1).

Sox http://sox.sourceforge.net/ puede ser tu amigo para esto. Puede leer muchos formatos diferentes y mostrarlos como sin formato en el tipo de datos que prefiera. De hecho, acabo de escribir el código para leer un bloque de datos de un archivo de audio en una matriz numpy.

Decidí ir a esta ruta para la portabilidad (sox está muy disponible) y para maximizar la flexibilidad de los tipos de audio de entrada que podría usar. En realidad, a partir de las pruebas iniciales, parece que no es notablemente más lento para lo que lo estoy usando … que es la lectura corta (unos pocos segundos) de audio de archivos muy largos (horas).

Variables que necesitas:

 SOX_EXEC # the sox / sox.exe executable filename filename # the audio filename of course num_channels # duh... the number of channels out_byps # Bytes per sample you want, must be 1, 2, 4, or 8 start_samp # sample number to start reading at len_samp # number of samples to read 

El código real es realmente simple. Si desea extraer todo el archivo, puede eliminar las cosas start_samp, len_samp y ‘recortar’.

 import subprocess # need the subprocess module import numpy as NP # I'm lazy and call numpy NP cmd = [SOX_EXEC, filename, # input filename '-t','raw', # output file type raw '-e','signed-integer', # output encode as signed ints '-L', # output little endin '-b',str(out_byps*8), # output bytes per sample '-', # output to stdout 'trim',str(start_samp)+'s',str(len_samp)+'s'] # only extract requested part data = NP.fromstring(subprocess.check_output(cmd),' 

PD: Aquí está el código para leer cosas de los encabezados de archivos de audio usando sox ...

  info = subprocess.check_output([SOX_EXEC,'--i',filename]) reading_comments_flag = False for l in info.splitlines(): if( not l.strip() ): continue if( reading_comments_flag and l.strip() ): if( comments ): comments += '\n' comments += l else: if( l.startswith('Input File') ): input_file = l.split(':',1)[1].strip()[1:-1] elif( l.startswith('Channels') ): num_channels = int(l.split(':',1)[1].strip()) elif( l.startswith('Sample Rate') ): sample_rate = int(l.split(':',1)[1].strip()) elif( l.startswith('Precision') ): bits_per_sample = int(l.split(':',1)[1].strip()[0:-4]) elif( l.startswith('Duration') ): tmp = l.split(':',1)[1].strip() tmp = tmp.split('=',1) duration_time = tmp[0] duration_samples = int(tmp[1].split(None,1)[0]) elif( l.startswith('Sample Encoding') ): encoding = l.split(':',1)[1].strip() elif( l.startswith('Comments') ): comments = '' reading_comments_flag = True else: if( other ): other += '\n'+l else: other = l if( output_unhandled ): print >>sys.stderr, "Unhandled:",l pass 

FFmpeg admite archivos mp3 y funciona en Windows ( http://zulko.github.io/blog/2013/10/04/read-and-write-audio-files-in-python-using-ffmpeg/ ).

Leyendo un archivo mp3:

 import subprocess as sp FFMPEG_BIN = "ffmpeg.exe" command = [ FFMPEG_BIN, '-i', 'mySong.mp3', '-f', 's16le', '-acodec', 'pcm_s16le', '-ar', '44100', # ouput will have 44100 Hz '-ac', '2', # stereo (set to '1' for mono) '-'] pipe = sp.Popen(command, stdout=sp.PIPE, bufsize=10**8) 

Formato de datos en una matriz numpy:

 raw_audio = pipe.proc.stdout.read(88200*4) import numpy audio_array = numpy.fromstring(raw_audio, dtype="int16") audio_array = audio_array.reshape((len(audio_array)/2,2)) 

En caso de que quieras hacer esto por MP3

Esto es lo que estoy usando: usa pydub y scipy.

Configuración completa (en Mac, puede diferir en otros sistemas):

 import tempfile import os import pydub import scipy import scipy.io.wavfile def read_mp3(file_path, as_float = False): """ Read an MP3 File into numpy data. :param file_path: String path to a file :param as_float: Cast data to float and normalize to [-1, 1] :return: Tuple(rate, data), where rate is an integer indicating samples/s data is an ndarray(n_samples, 2)[int16] if as_float = False otherwise ndarray(n_samples, 2)[float] in range [-1, 1] """ path, ext = os.path.splitext(file_path) assert ext=='.mp3' mp3 = pydub.AudioSegment.from_mp3(FILEPATH) _, path = tempfile.mkstemp() mp3.export(path, format="wav") rate, data = scipy.io.wavfile.read(path) os.remove(path) if as_float: data = data/(2**15) return rate, data 

Crédito al blog de James Thompson.

He estado usando PySoundFile últimamente en lugar de Audiolab. Se instala fácilmente con conda .

No soporta mp3 , como la mayoría de las cosas. El MP3 ya no está patentado, por lo que no hay razón para que no pueda soportarlo; alguien solo tiene que escribir soporte en libsndfile .