Импорт звуковых файлов в Python в виде массивов NumPy (альтернативы аудиолабу)
Я использовал Audiolab для импорта звуковых файлов в прошлом, и это сработало довольно хорошо. Однако:
-
In [2]: from scikits import audiolab
--------------------------------------------------------------------
ImportError Traceback (most recent call last)
C:\Python26\Scripts\<ipython console> in <module>()
C:\Python26\lib\site-packages\scikits\audiolab\__init__.py in <module>()
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 <module>()
----> 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.``
Поэтому я хотел бы:
- Подумайте, почему он не работает в версии 2.6 (что-то не так с _sndfile.pyd?) и может найти способ расширить его для работы с неподдерживаемыми форматами.
- Найдите полную замену аудиолаба
Ответы
Ответ 1
Я использовал PySoundFile за последнее время вместо Audiolab. Он легко устанавливается с помощью conda
.
не поддерживает mp3, как и большинство вещей. MP3 больше не запатентован, поэтому нет причин, по которым он не может его поддерживать; кто-то просто должен написать поддержку в libsndfile.
Ответ 2
Audiolab работает для меня на Ubuntu 9.04 с Python 2.6.2, поэтому это может быть проблема с Windows. В вашей ссылке на форум автор также предполагает, что это ошибка Windows.
В прошлом этот параметр работал и на меня:
from scipy.io import wavfile
fs, data = wavfile.read(filename)
Помните, что data
может иметь тип данных int
, поэтому он не масштабируется в пределах [-1,1). Например, если data
- int16
, вы должны разделить data
на 2**15
на шкалу в пределах [-1,1).
Ответ 3
Sox http://sox.sourceforge.net/ может быть для вас другом. Он может читать много разных форматов и выводить их как необработанные в любой тип данных, который вы предпочитаете. На самом деле, я просто написал код для чтения блока данных из аудиофайла в массив numpy.
Я решил пойти на этот маршрут для переносимости (sox очень широко доступен) и максимизировать гибкость входных типов аудио, которые я мог бы использовать. На самом деле, кажется, из первоначального тестирования, что он не заметно медленнее для того, что я использую для... для чтения коротких (несколько секунд) звука из очень длинных (часов) файлов.
Необходимые переменные:
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
Фактический код очень прост. Если вы хотите извлечь весь файл, вы можете удалить файлы start_samp, len_samp и "trim".
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),'<i%d'%(out_byps))
data = data.reshape(len(data)/num_channels, num_channels) # make samples x channels
PS: Вот код для чтения файлов из заголовков аудиофайлов с помощью 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
Ответ 4
FFmpeg поддерживает mp3 и работает в Windows (http://zulko.github.io/blog/2013/10/04/read-and-write-audio-files-in-python-using-ffmpeg/).
Чтение 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)
Форматирование данных в массив 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))
Ответ 5
Если вы хотите сделать это для MP3
Вот что я использую: он использует pydub и scipy.
Полная настройка (на Mac, может отличаться в других системах):
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
Кредит Блог Джеймса Томпсона