PyXR

c:\python24\lib \ sndhdr.py



0001 """Routines to help recognizing sound files.
0002 
0003 Function whathdr() recognizes various types of sound file headers.
0004 It understands almost all headers that SOX can decode.
0005 
0006 The return tuple contains the following items, in this order:
0007 - file type (as SOX understands it)
0008 - sampling rate (0 if unknown or hard to decode)
0009 - number of channels (0 if unknown or hard to decode)
0010 - number of frames in the file (-1 if unknown or hard to decode)
0011 - number of bits/sample, or 'U' for U-LAW, or 'A' for A-LAW
0012 
0013 If the file doesn't have a recognizable type, it returns None.
0014 If the file can't be opened, IOError is raised.
0015 
0016 To compute the total time, divide the number of frames by the
0017 sampling rate (a frame contains a sample for each channel).
0018 
0019 Function what() calls whathdr().  (It used to also use some
0020 heuristics for raw data, but this doesn't work very well.)
0021 
0022 Finally, the function test() is a simple main program that calls
0023 what() for all files mentioned on the argument list.  For directory
0024 arguments it calls what() for all files in that directory.  Default
0025 argument is "." (testing all files in the current directory).  The
0026 option -r tells it to recurse down directories found inside
0027 explicitly given directories.
0028 """
0029 
0030 # The file structure is top-down except that the test program and its
0031 # subroutine come last.
0032 
0033 __all__ = ["what","whathdr"]
0034 
0035 def what(filename):
0036     """Guess the type of a sound file"""
0037     res = whathdr(filename)
0038     return res
0039 
0040 
0041 def whathdr(filename):
0042     """Recognize sound headers"""
0043     f = open(filename, 'rb')
0044     h = f.read(512)
0045     for tf in tests:
0046         res = tf(h, f)
0047         if res:
0048             return res
0049     return None
0050 
0051 
0052 #-----------------------------------#
0053 # Subroutines per sound header type #
0054 #-----------------------------------#
0055 
0056 tests = []
0057 
0058 def test_aifc(h, f):
0059     import aifc
0060     if h[:4] != 'FORM':
0061         return None
0062     if h[8:12] == 'AIFC':
0063         fmt = 'aifc'
0064     elif h[8:12] == 'AIFF':
0065         fmt = 'aiff'
0066     else:
0067         return None
0068     f.seek(0)
0069     try:
0070         a = aifc.openfp(f, 'r')
0071     except (EOFError, aifc.Error):
0072         return None
0073     return (fmt, a.getframerate(), a.getnchannels(), \
0074             a.getnframes(), 8*a.getsampwidth())
0075 
0076 tests.append(test_aifc)
0077 
0078 
0079 def test_au(h, f):
0080     if h[:4] == '.snd':
0081         f = get_long_be
0082     elif h[:4] in ('\0ds.', 'dns.'):
0083         f = get_long_le
0084     else:
0085         return None
0086     type = 'au'
0087     hdr_size = f(h[4:8])
0088     data_size = f(h[8:12])
0089     encoding = f(h[12:16])
0090     rate = f(h[16:20])
0091     nchannels = f(h[20:24])
0092     sample_size = 1 # default
0093     if encoding == 1:
0094         sample_bits = 'U'
0095     elif encoding == 2:
0096         sample_bits = 8
0097     elif encoding == 3:
0098         sample_bits = 16
0099         sample_size = 2
0100     else:
0101         sample_bits = '?'
0102     frame_size = sample_size * nchannels
0103     return type, rate, nchannels, data_size/frame_size, sample_bits
0104 
0105 tests.append(test_au)
0106 
0107 
0108 def test_hcom(h, f):
0109     if h[65:69] != 'FSSD' or h[128:132] != 'HCOM':
0110         return None
0111     divisor = get_long_be(h[128+16:128+20])
0112     return 'hcom', 22050/divisor, 1, -1, 8
0113 
0114 tests.append(test_hcom)
0115 
0116 
0117 def test_voc(h, f):
0118     if h[:20] != 'Creative Voice File\032':
0119         return None
0120     sbseek = get_short_le(h[20:22])
0121     rate = 0
0122     if 0 <= sbseek < 500 and h[sbseek] == '\1':
0123         ratecode = ord(h[sbseek+4])
0124         rate = int(1000000.0 / (256 - ratecode))
0125     return 'voc', rate, 1, -1, 8
0126 
0127 tests.append(test_voc)
0128 
0129 
0130 def test_wav(h, f):
0131     # 'RIFF' <len> 'WAVE' 'fmt ' <len>
0132     if h[:4] != 'RIFF' or h[8:12] != 'WAVE' or h[12:16] != 'fmt ':
0133         return None
0134     style = get_short_le(h[20:22])
0135     nchannels = get_short_le(h[22:24])
0136     rate = get_long_le(h[24:28])
0137     sample_bits = get_short_le(h[34:36])
0138     return 'wav', rate, nchannels, -1, sample_bits
0139 
0140 tests.append(test_wav)
0141 
0142 
0143 def test_8svx(h, f):
0144     if h[:4] != 'FORM' or h[8:12] != '8SVX':
0145         return None
0146     # Should decode it to get #channels -- assume always 1
0147     return '8svx', 0, 1, 0, 8
0148 
0149 tests.append(test_8svx)
0150 
0151 
0152 def test_sndt(h, f):
0153     if h[:5] == 'SOUND':
0154         nsamples = get_long_le(h[8:12])
0155         rate = get_short_le(h[20:22])
0156         return 'sndt', rate, 1, nsamples, 8
0157 
0158 tests.append(test_sndt)
0159 
0160 
0161 def test_sndr(h, f):
0162     if h[:2] == '\0\0':
0163         rate = get_short_le(h[2:4])
0164         if 4000 <= rate <= 25000:
0165             return 'sndr', rate, 1, -1, 8
0166 
0167 tests.append(test_sndr)
0168 
0169 
0170 #---------------------------------------------#
0171 # Subroutines to extract numbers from strings #
0172 #---------------------------------------------#
0173 
0174 def get_long_be(s):
0175     return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
0176 
0177 def get_long_le(s):
0178     return (ord(s[3])<<24) | (ord(s[2])<<16) | (ord(s[1])<<8) | ord(s[0])
0179 
0180 def get_short_be(s):
0181     return (ord(s[0])<<8) | ord(s[1])
0182 
0183 def get_short_le(s):
0184     return (ord(s[1])<<8) | ord(s[0])
0185 
0186 
0187 #--------------------#
0188 # Small test program #
0189 #--------------------#
0190 
0191 def test():
0192     import sys
0193     recursive = 0
0194     if sys.argv[1:] and sys.argv[1] == '-r':
0195         del sys.argv[1:2]
0196         recursive = 1
0197     try:
0198         if sys.argv[1:]:
0199             testall(sys.argv[1:], recursive, 1)
0200         else:
0201             testall(['.'], recursive, 1)
0202     except KeyboardInterrupt:
0203         sys.stderr.write('\n[Interrupted]\n')
0204         sys.exit(1)
0205 
0206 def testall(list, recursive, toplevel):
0207     import sys
0208     import os
0209     for filename in list:
0210         if os.path.isdir(filename):
0211             print filename + '/:',
0212             if recursive or toplevel:
0213                 print 'recursing down:'
0214                 import glob
0215                 names = glob.glob(os.path.join(filename, '*'))
0216                 testall(names, recursive, 0)
0217             else:
0218                 print '*** directory (use -r) ***'
0219         else:
0220             print filename + ':',
0221             sys.stdout.flush()
0222             try:
0223                 print what(filename)
0224             except IOError:
0225                 print '*** not found ***'
0226 
0227 if __name__ == '__main__':
0228     test()
0229 

Generated by PyXR 0.9.4
SourceForge.net Logo