python-2.5.2/win32/Lib/sndhdr.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 """Routines to help recognizing sound files.
       
     2 
       
     3 Function whathdr() recognizes various types of sound file headers.
       
     4 It understands almost all headers that SOX can decode.
       
     5 
       
     6 The return tuple contains the following items, in this order:
       
     7 - file type (as SOX understands it)
       
     8 - sampling rate (0 if unknown or hard to decode)
       
     9 - number of channels (0 if unknown or hard to decode)
       
    10 - number of frames in the file (-1 if unknown or hard to decode)
       
    11 - number of bits/sample, or 'U' for U-LAW, or 'A' for A-LAW
       
    12 
       
    13 If the file doesn't have a recognizable type, it returns None.
       
    14 If the file can't be opened, IOError is raised.
       
    15 
       
    16 To compute the total time, divide the number of frames by the
       
    17 sampling rate (a frame contains a sample for each channel).
       
    18 
       
    19 Function what() calls whathdr().  (It used to also use some
       
    20 heuristics for raw data, but this doesn't work very well.)
       
    21 
       
    22 Finally, the function test() is a simple main program that calls
       
    23 what() for all files mentioned on the argument list.  For directory
       
    24 arguments it calls what() for all files in that directory.  Default
       
    25 argument is "." (testing all files in the current directory).  The
       
    26 option -r tells it to recurse down directories found inside
       
    27 explicitly given directories.
       
    28 """
       
    29 
       
    30 # The file structure is top-down except that the test program and its
       
    31 # subroutine come last.
       
    32 
       
    33 __all__ = ["what","whathdr"]
       
    34 
       
    35 def what(filename):
       
    36     """Guess the type of a sound file"""
       
    37     res = whathdr(filename)
       
    38     return res
       
    39 
       
    40 
       
    41 def whathdr(filename):
       
    42     """Recognize sound headers"""
       
    43     f = open(filename, 'rb')
       
    44     h = f.read(512)
       
    45     for tf in tests:
       
    46         res = tf(h, f)
       
    47         if res:
       
    48             return res
       
    49     return None
       
    50 
       
    51 
       
    52 #-----------------------------------#
       
    53 # Subroutines per sound header type #
       
    54 #-----------------------------------#
       
    55 
       
    56 tests = []
       
    57 
       
    58 def test_aifc(h, f):
       
    59     import aifc
       
    60     if h[:4] != 'FORM':
       
    61         return None
       
    62     if h[8:12] == 'AIFC':
       
    63         fmt = 'aifc'
       
    64     elif h[8:12] == 'AIFF':
       
    65         fmt = 'aiff'
       
    66     else:
       
    67         return None
       
    68     f.seek(0)
       
    69     try:
       
    70         a = aifc.openfp(f, 'r')
       
    71     except (EOFError, aifc.Error):
       
    72         return None
       
    73     return (fmt, a.getframerate(), a.getnchannels(), \
       
    74             a.getnframes(), 8*a.getsampwidth())
       
    75 
       
    76 tests.append(test_aifc)
       
    77 
       
    78 
       
    79 def test_au(h, f):
       
    80     if h[:4] == '.snd':
       
    81         f = get_long_be
       
    82     elif h[:4] in ('\0ds.', 'dns.'):
       
    83         f = get_long_le
       
    84     else:
       
    85         return None
       
    86     type = 'au'
       
    87     hdr_size = f(h[4:8])
       
    88     data_size = f(h[8:12])
       
    89     encoding = f(h[12:16])
       
    90     rate = f(h[16:20])
       
    91     nchannels = f(h[20:24])
       
    92     sample_size = 1 # default
       
    93     if encoding == 1:
       
    94         sample_bits = 'U'
       
    95     elif encoding == 2:
       
    96         sample_bits = 8
       
    97     elif encoding == 3:
       
    98         sample_bits = 16
       
    99         sample_size = 2
       
   100     else:
       
   101         sample_bits = '?'
       
   102     frame_size = sample_size * nchannels
       
   103     return type, rate, nchannels, data_size/frame_size, sample_bits
       
   104 
       
   105 tests.append(test_au)
       
   106 
       
   107 
       
   108 def test_hcom(h, f):
       
   109     if h[65:69] != 'FSSD' or h[128:132] != 'HCOM':
       
   110         return None
       
   111     divisor = get_long_be(h[128+16:128+20])
       
   112     return 'hcom', 22050/divisor, 1, -1, 8
       
   113 
       
   114 tests.append(test_hcom)
       
   115 
       
   116 
       
   117 def test_voc(h, f):
       
   118     if h[:20] != 'Creative Voice File\032':
       
   119         return None
       
   120     sbseek = get_short_le(h[20:22])
       
   121     rate = 0
       
   122     if 0 <= sbseek < 500 and h[sbseek] == '\1':
       
   123         ratecode = ord(h[sbseek+4])
       
   124         rate = int(1000000.0 / (256 - ratecode))
       
   125     return 'voc', rate, 1, -1, 8
       
   126 
       
   127 tests.append(test_voc)
       
   128 
       
   129 
       
   130 def test_wav(h, f):
       
   131     # 'RIFF' <len> 'WAVE' 'fmt ' <len>
       
   132     if h[:4] != 'RIFF' or h[8:12] != 'WAVE' or h[12:16] != 'fmt ':
       
   133         return None
       
   134     style = get_short_le(h[20:22])
       
   135     nchannels = get_short_le(h[22:24])
       
   136     rate = get_long_le(h[24:28])
       
   137     sample_bits = get_short_le(h[34:36])
       
   138     return 'wav', rate, nchannels, -1, sample_bits
       
   139 
       
   140 tests.append(test_wav)
       
   141 
       
   142 
       
   143 def test_8svx(h, f):
       
   144     if h[:4] != 'FORM' or h[8:12] != '8SVX':
       
   145         return None
       
   146     # Should decode it to get #channels -- assume always 1
       
   147     return '8svx', 0, 1, 0, 8
       
   148 
       
   149 tests.append(test_8svx)
       
   150 
       
   151 
       
   152 def test_sndt(h, f):
       
   153     if h[:5] == 'SOUND':
       
   154         nsamples = get_long_le(h[8:12])
       
   155         rate = get_short_le(h[20:22])
       
   156         return 'sndt', rate, 1, nsamples, 8
       
   157 
       
   158 tests.append(test_sndt)
       
   159 
       
   160 
       
   161 def test_sndr(h, f):
       
   162     if h[:2] == '\0\0':
       
   163         rate = get_short_le(h[2:4])
       
   164         if 4000 <= rate <= 25000:
       
   165             return 'sndr', rate, 1, -1, 8
       
   166 
       
   167 tests.append(test_sndr)
       
   168 
       
   169 
       
   170 #---------------------------------------------#
       
   171 # Subroutines to extract numbers from strings #
       
   172 #---------------------------------------------#
       
   173 
       
   174 def get_long_be(s):
       
   175     return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
       
   176 
       
   177 def get_long_le(s):
       
   178     return (ord(s[3])<<24) | (ord(s[2])<<16) | (ord(s[1])<<8) | ord(s[0])
       
   179 
       
   180 def get_short_be(s):
       
   181     return (ord(s[0])<<8) | ord(s[1])
       
   182 
       
   183 def get_short_le(s):
       
   184     return (ord(s[1])<<8) | ord(s[0])
       
   185 
       
   186 
       
   187 #--------------------#
       
   188 # Small test program #
       
   189 #--------------------#
       
   190 
       
   191 def test():
       
   192     import sys
       
   193     recursive = 0
       
   194     if sys.argv[1:] and sys.argv[1] == '-r':
       
   195         del sys.argv[1:2]
       
   196         recursive = 1
       
   197     try:
       
   198         if sys.argv[1:]:
       
   199             testall(sys.argv[1:], recursive, 1)
       
   200         else:
       
   201             testall(['.'], recursive, 1)
       
   202     except KeyboardInterrupt:
       
   203         sys.stderr.write('\n[Interrupted]\n')
       
   204         sys.exit(1)
       
   205 
       
   206 def testall(list, recursive, toplevel):
       
   207     import sys
       
   208     import os
       
   209     for filename in list:
       
   210         if os.path.isdir(filename):
       
   211             print filename + '/:',
       
   212             if recursive or toplevel:
       
   213                 print 'recursing down:'
       
   214                 import glob
       
   215                 names = glob.glob(os.path.join(filename, '*'))
       
   216                 testall(names, recursive, 0)
       
   217             else:
       
   218                 print '*** directory (use -r) ***'
       
   219         else:
       
   220             print filename + ':',
       
   221             sys.stdout.flush()
       
   222             try:
       
   223                 print what(filename)
       
   224             except IOError:
       
   225                 print '*** not found ***'
       
   226 
       
   227 if __name__ == '__main__':
       
   228     test()