代码之家  ›  专栏  ›  技术社区  ›  endolith

将声音文件作为NumPy数组导入Python(audiolab的替代品)

  •  11
  • endolith  · 技术社区  · 14 年前

    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中不起作用(\u sndfile.pyd有什么问题?),也许可以找到一种方法来扩展它,使其能够使用不受支持的格式
    • 找到audiolab的完全替代品
    5 回复  |  直到 14 年前
        1
  •  14
  •   Steve Tjoa    14 年前

    在过去,这个选择对我也很有效:

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

    data 可能有 int 数据 int16 ,你必须分开 数据 通过 2**15 在[-1,1)范围内缩放。

        2
  •  6
  •   travc    12 年前

    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
    

    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
    
        3
  •  5
  •   Vincent Berthiaume    8 年前

    FFmpeg支持mp3并在Windows上工作( http://zulko.github.io/blog/2013/10/04/read-and-write-audio-files-in-python-using-ffmpeg/ ).

    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))
    
        4
  •  4
  •   Peter    4 年前

    如果你想为MP3做这个

    我用的是:它用 pydub

    完整设置(在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(file_path)
        _, 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
    

    贷记 James Thompson's blog

        5
  •  2
  •   endolith    6 年前

    我一直在用 PySoundFile 而不是音频实验室。它安装起来很容易 conda

    does not support mp3 ,就像大多数事情一样。MP3已经没有专利了,所以没有理由不支持它;总得有人来吧 write support into libsndfile .