【问题标题】:Get .wav file length or duration获取 .wav 文件长度或持续时间
【发布时间】:2011-12-11 15:20:24
【问题描述】:

我正在寻找一种方法来找出 python 中音频文件 (.wav) 的持续时间。到目前为止,我查看了 python wave 库、mutagenpymediapymad 我无法获得 wav 文件的持续时间。 Pymad 给了我持续时间,但并不一致。

提前致谢。

【问题讨论】:

    标签: python audio


    【解决方案1】:

    持续时间等于帧数除以帧率(每秒帧数):

    import wave
    import contextlib
    fname = '/tmp/test.wav'
    with contextlib.closing(wave.open(fname,'r')) as f:
        frames = f.getnframes()
        rate = f.getframerate()
        duration = frames / float(rate)
        print(duration)
    

    关于 @edwards 的评论,这里有一些代码可以生成一个 2 通道的波形文件:

    import math
    import wave
    import struct
    FILENAME = "/tmp/test.wav"
    freq = 440.0
    data_size = 40000
    frate = 1000.0
    amp = 64000.0
    nchannels = 2
    sampwidth = 2
    framerate = int(frate)
    nframes = data_size
    comptype = "NONE"
    compname = "not compressed"
    data = [(math.sin(2 * math.pi * freq * (x / frate)),
            math.cos(2 * math.pi * freq * (x / frate))) for x in range(data_size)]
    try:
        wav_file = wave.open(FILENAME, 'w')
        wav_file.setparams(
            (nchannels, sampwidth, framerate, nframes, comptype, compname))
        for values in data:
            for v in values:
                wav_file.writeframes(struct.pack('h', int(v * amp / 2)))
    finally:
        wav_file.close()
    

    如果您在音频播放器中播放生成的文件,您会发现持续时间为 40 秒。如果您运行上面的代码,它还会计算持续时间为 40 秒。所以我相信帧数不受通道数的影响,上面的公式是正确的。

    【讨论】:

    • 这不太正确......每个频道都有一个框架,所以duration=frames/float(rate*f.getnchannels())
    • @edward:我在上面添加了一些代码,用于创建 2 通道波形文件。我的答案中发布的公式计算持续时间为 40 秒,这与我在播放 .wav 文件时看到的内容相吻合。所以在我看来,当你使用2通道时,帧数并没有翻倍,我原来的公式是正确的。
    • 不再需要 contextlib 的东西了。从 2.7 版开始,with 语句为您完成了这项工作。
    • @Lewistrick:我看到wave.open 支持with 声明revision 84932。该更改影响 Python3.4,但不影响 Python2.7。据我所知,the 2.7 branch 不支持with 语句。
    • 对不起,我的错误。这是关于open,而不是wave.open
    【解决方案2】:

    librosa 库可以做到这一点:librosa

    import librosa
    librosa.get_duration(filename='my.wav')
    

    【讨论】:

    • 简洁!它给出了“第二个”度量(浮点数)。谢谢。
    • 请注意,这避免了将内容加载到内存中,因此对于查询长文件的持续时间很有用。 (引自 librosa)
    【解决方案3】:

    一个非常简单的方法是使用soundfile(以前的pysoundfile)。

    下面是一些如何做到这一点的示例代码:

    import soundfile as sf
    f = sf.SoundFile('447c040d.wav')
    print('samples = {}'.format(f.frames))
    print('sample rate = {}'.format(f.samplerate))
    print('seconds = {}'.format(f.frames / f.samplerate))
    

    该特定文件的输出是:

    samples = 232569
    sample rate = 16000
    seconds = 14.5355625
    

    这与 soxi 一致:

    Input File     : '447c040d.wav'
    Channels       : 1
    Sample Rate    : 16000
    Precision      : 16-bit
    Duration       : 00:00:14.54 = 232569 samples ~ 1090.17 CDDA sectors
    File Size      : 465k
    Bit Rate       : 256k
    Sample Encoding: 16-bit Signed Integer PCM
    

    【讨论】:

    • 对我来说,这确实是最好的答案,因为它消除了上述答案的许多复杂性。保持简单!
    • 是的。它确实依赖于第 3 方库,但第 3 方库是著名 C 库 libsndfile 的简单包装器。并且 pysoundfile 与 numpy 集成。赢,赢,赢。
    • @Airenas 这是一个很好的问题:应该是因为SoundFile.len() 返回self.frames,其中 1 帧包含每个通道的音频样本。也就是说,我注意到len API 可能会被弃用:github.com/bastibe/python-soundfile/issues/199 而不是len(f),我会使用f.frames 每个 lambda 函数在这里:github.com/bastibe/python-soundfile/blob/master/… 这样更清楚。
    • @Airenas 我根据您的问题用我建议的更改更新了答案。我希望这能解决问题。
    【解决方案4】:

    我们可以使用 ffmpeg 来获取任何视频或音频文件的时长。

    要安装 ffmpeg,请遵循 link

    import subprocess
    import re
     
    process = subprocess.Popen(['ffmpeg',  '-i', path_of_wav_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    stdout, stderr = process.communicate()
    matches = re.search(r"Duration:\s{1}(?P<hours>\d+?):(?P<minutes>\d+?):(?P<seconds>\d+\.\d+?),", stdout.decode(), re.DOTALL).groupdict()
     
    print(matches['hours'])
    print(matches['minutes'])
    print(matches['seconds'])
    

    【讨论】:

    • 我收到此错误“无法在类似字节的对象上使用字符串模式”。所以我用“stdout.decode()”替换了对“stdout”的调用
    • 对于 Python 3 用户,不要忘记在 print 语句上加上括号,正如@AvielNiego 指出的那样,使用 stdout.decode() 而不是 stdout。
    • 通常 ffprobe 也可用。它可以为任何特定用途定制更多的结果输出格式。我使用的 bash 行: d=$(ffprobe -i "${1}" 2>&1 | grep 'Duration') 产生:"Duration: 01:06:10.61, start: 0.000000, bitrate: 787 kb/s"
    【解决方案5】:
    import os
    path="c:\\windows\\system32\\loopymusic.wav"
    f=open(path,"r")
    
    #read the ByteRate field from file (see the Microsoft RIFF WAVE file format)
    #https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
    #ByteRate is located at the first 28th byte
    f.seek(28)
    a=f.read(4)
    
    #convert string a into integer/longint value
    #a is little endian, so proper conversion is required
    byteRate=0
    for i in range(4):
        byteRate=byteRate + ord(a[i])*pow(256,i)
    
    #get the file size in bytes
    fileSize=os.path.getsize(path)  
    
    #the duration of the data, in milliseconds, is given by
    ms=((fileSize-44)*1000)/byteRate
    
    print "File duration in miliseconds : " % ms
    print "File duration in H,M,S,mS : " % ms/(3600*1000) % "," % ms/(60*1000) % "," % ms/1000 % "," ms%1000
    print "Actual sound data (in bytes) : " % fileSize-44  
    f.close()
    

    【讨论】:

    • 在没有 byteRate 循环的情况下处理文件的二进制内容的更安全的方法可能是: from struct import unpack_from rate, = unpack_from('
    • 小错误:os.path.getsize(path) 应该是os.path.getsize(f)
    • 另一个小错误:ms=((fileSize-44)*1000)/byteRate 但这非常好,因为即使您的 WAV 不是 PCM,它也能正常工作。
    • 这似乎不适用于 Python3,因为 open() 默认使用 encoding="utf-8"。相反,请使用f=open(path, encoding="latin-1")(您不需要"r",因为这是默认打开模式)。
    【解决方案6】:

    令,T 为 2 个连续样本之间的持续时间。所以,我们可以写成 t = nT 或 t = n/Fs。

    from scipy.io import wavfile
    Fs, data = wavfile.read('filename.wav')
    n = data.size
    t = n / Fs
    

    【讨论】:

    • 在两通道波形文件中,此方法将给出实际答案的两倍。使用len(data) 而不是data.size
    【解决方案7】:

    我试图获取除“.wav”之外的不同格式的音频文件的长度,我尝试了一些上述解决方案,但对我不起作用

    这对我有用:

    from pydub.utils import mediainfo
    mediainfo('audiofile')['duration']
    

    【讨论】:

    • 工作但很慢。
    【解决方案8】:

    要查找音乐文件的长度,可以使用audioread模块,

    安装音频阅读器:pip install audioread

    然后使用此代码:

    import audioread
    with audioread.audio_open(filepath) as f:
        totalsec = f.duration
        min,sec = divmod(totalsec,60) # divides total time in minute  and second 
                                        #and store it in min and sec variable respectively
    

    【讨论】:

      【解决方案9】:

      pydub 的另一种解决方案:

      import pydub
      audio_seg = AudioSegment.from_wav('mywav.wav')
      total_in_ms = len(audio_seg)
      

      【讨论】:

      • 在几秒钟内得到它:audio_seg.duration_seconds
      【解决方案10】:

      计算持续时间(一般来说),

      找出音频帧的长度,然后除以它的采样率。

      例如。在 Python 中。

      如果音频 = [1,2,3,4,5],其中帧的长度为 5,sample_rate = 44100。

      duration = len(audio) / sample_rate

      print(duration)

      =&gt; 0.00011337868480725624

      【讨论】:

        【解决方案11】:

        这很短,不需要模块,适用于所有操作系统:

        import os
        os.chdir(foo) # Get into the dir with sound
        statbuf = os.stat('Sound.wav')
        mbytes = statbuf.st_size / 1024
        duration = mbytes / 200
        

        【讨论】:

        • 一般不会工作。假设每个样本有特定数量的字节,以及特定的采样率。忽略标题大小。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多