【问题标题】:Importing sound files into Python as NumPy arrays (alternatives to audiolab)将声音文件作为 NumPy 数组导入 Python(audiolab 的替代品)
【发布时间】:2011-01-22 08:13:01
【问题描述】:

我过去一直使用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 有问题?),也许找到一种方法来扩展它以使用不受支持的格式
  • 找到 audiolab 的完整替代品

【问题讨论】:

  • 这个问题是特定于 windows 上的 python 2.6 的(即你不会在 python 2.5 上看到它)。我还没有找到解决方法
  • 我终于在两次飞行之间抽出时间,结果是一个 mingw 错误。我已经发布了一个新的 0.11.0 版本,应该可以解决这个问题。
  • 大卫,你在 audiolab 中制作了一个很棒的工具!我经常使用它。谢谢。

标签: python audio numpy scipy


【解决方案1】:

如果您想为 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(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

【讨论】:

  • 你需要os.close(_)(并且可能将_重命名为fd)来关闭临时文件描述符。否则,在 for 循环中运行时,您最终会得到 [Errno 24] Too many open files
  • 不用导出成wav文件再用scipy重新加载,可以直接转换成numpy数组:data = np.reshape(mp3.get_array_of_samples(), (-1, 2))
  • file_pathFILEPATH 怎么了?
【解决方案2】:

我最近一直在使用 PySoundFile 而不是 Audiolab。使用conda 可以轻松安装。

does not support mp3,和大多数东西一样。 MP3 不再是专利,所以没有理由不支持它;有人只需write support into libsndfile

【讨论】:

    【解决方案3】:

    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))
    

    【讨论】:

      【解决方案4】:

      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
      

      【讨论】:

      • 有趣,虽然有点笨拙而且可能不是跨平台的? pysox 用于直接与 libSoX 库进行交互。看起来像 SoX supports a bunch of formats on its own 并且可以使用其他几个库。我在使 audiolab 工作时遇到了很多问题,而且它不支持 MP3 等,所以 pysox 可能值得一试。
      • 我会看看 pysox...谢谢。虽然使用 sox 的子进程方法不是真正的 Python 或漂亮,但它非常强大且相对可移植(因为大多数系统都可以找到 sox 二进制文件/安装程序)。
      【解决方案5】:

      Audiolab 在 Ubuntu 9.04 和 Python 2.6.2 上为我工作,所以这可能是 Windows 的问题。在您的论坛链接中,作者还暗示这是一个 Windows 错误。

      过去,这个选项也对我有用:

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

      请注意 data 可能具有 int 数据类型,因此它不会在 [-1,1) 范围内缩放。例如,如果 dataint16,则必须将 data 除以 2**15 才能在 [-1,1) 范围内缩放。

      【讨论】:

      • 我不确定。 16 位或 32 位应该没问题,但我不知道 24 位。
      • 它没有读到很多东西。即使是 16 位文件也会出现反转,值为 -1 时出现环绕错误。 24 位得到“TypeError:数据类型不理解”肯定有更好的东西......
      • 你能发布一个给你这个错误的文件吗?此外,测试套件是否正确通过 (scikits.audiolab.test()) ? audiolab 使用 libsndfile,这是迄今为止我所知道的最好和最可靠的音频 IO 库。当然,audiolab 本身可能有错误
      • 我现在看不到环绕错误,但这是 scipy.io 的错误,而不是 audiolab。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-17
      • 2014-09-17
      • 1970-01-01
      • 1970-01-01
      • 2017-04-11
      相关资源
      最近更新 更多