2011-10-20 99 views
20

我正在尋找一種方法來查找在Python中的音頻文件(.wav)的持續時間。到目前爲止,我看了一下python wave庫,mutagenpymedia,pymad我無法獲得wav文件的持續時間。 Pymad給了我持續時間,但它不一致。獲取.wav文件的長度或短語

在此先感謝。

回答

35

的持續時間等於由幀率除以幀的數量(幀每秒):

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秒。所以我相信幀的數量不受通道數量的影響,上面的公式是正確的。

+0

我看了一下所有的'wave'庫函數,但我忽略了簡單的邏輯'將爲nframes/frame_rate'。謝謝你的方法和代碼:) – Pannu

+2

這是不完全正確的...有一個幀寫入每個通道,所以'duration = frames/float(rate * f.getnchannels())' – edward

+1

@edward :我已經添加了一些代碼,創建一個2通道波形文件。在我的答案中發佈的公式計算出的持續時間爲40秒,這與我在播放.wav文件時看到的一致。所以在我看來,使用雙聲道時幀數不會增加一倍,而且我的原始公式是正確的。 – unutbu

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() 
+0

一個更安全的方法來處理沒有byteRate循環的文件的二進制內容可能是: from struct import unpack_from rate,= unpack_from(' edrabc

+0

小錯誤:'os.path.getsize路徑)'應該是'os.path.getsize(f)'。 – Lewistrick

+0

另一個小錯誤:'ms =((fileSize-44)* 1000)/ byteRate'但是這很好,因爲即使你的WAV不是PCM,它也能工作。 – Jamie

5

我們可以使用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, re.DOTALL).groupdict() 

print matches['hours'] 
print matches['minutes'] 
print matches['seconds'] 
+0

我得到這個錯誤「不能在類似字節的對象上使用字符串模式」。所以我用「stdout.decode()」替換了「stdout」的調用 – AvielNiego

1

一個非常簡單的方法是使用pysoundfile,https://github.com/bastibe/PySoundFile

下面是如何做到這一點的一些示例代碼:

import soundfile as sf 
f = sf.SoundFile('447c040d.wav') 
print('samples = {}'.format(len(f))) 
print('sample rate = {}'.format(f.samplerate)) 
print('seconds = {}'.format(len(f)/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