title: Determining Bit-Depth of a wav file
body: <p>I am looking for a fast, preferably standard library mechanism to determine the bit-depth of wav file e.g. '16-bit' or '24-bit'.</p>
  
  <p>I am using a subprocess call to Sox to get a plethora of audio metadata but a subprocess call is very slow and the only information I can only currently get reliably from Sox is the bit-depth.</p>
  
  <p>The built in wave module does not have a function like "getbitdepth()" and is also not compatible with 24bit wav files - I could use a 'try except' to access the files metadata using the wave module (if it works, manually record that it is 16bit) then on except call sox instead (where sox will perform the analysis to accurately record its bitdepth). My concern is that that this approach feels like guess work. What if a an 8bit file is read? I would be manually assigning 16-bit when it is not.</p>
  
  <p>SciPy.io.wavefile also is not compatible with 24bit audio so creates a similar issue.</p>
  
  <p>This <a href="http://pythonaudio.blogspot.fr/2014/04/3-reading-wave-file.html" rel="noreferrer">tutorial</a> is really interesting and even includes some really low level (low level for Python at least) scripting examples to extract information from the wav files headers - unfortunately these scripts don't work for 16-bit audio.</p>
  
  <p>Is there any way to simply (and without calling sox) determine what bit-depth the wav file I'm checking has?</p>
  
  <p>The wave header parser script I'm using is as follows:</p>
  
  <pre><code>import struct
  import os
  
  def print_wave_header(f):
      '''
      Function takes an audio file path as a parameter and 
      returns a dictionary of metadata parsed from the header
      '''
      r = {} #the results of the header parse
      r['path'] = f
      fin = open(f,"rb") # Read wav file, "r flag" - read, "b flag" - binary 
      ChunkID=fin.read(4) # First four bytes are ChunkID which must be "RIFF" in ASCII
      r["ChunkID"]=ChunkID
      ChunkSizeString=fin.read(4) # Total Size of File in Bytes - 8 Bytes
      ChunkSize=struct.unpack('I',ChunkSizeString) # 'I' Format is to to treat the 4 bytes as unsigned 32-bit inter
      TotalSize=ChunkSize[0]+8 # The subscript is used because struct unpack returns everything as tuple
      r["TotalSize"]=TotalSize
      DataSize=TotalSize-44 # This is the number of bytes of data
      r["DataSize"]=DataSize
      Format=fin.read(4) # "WAVE" in ASCII
      r["Format"]=Format
      SubChunk1ID=fin.read(4) # "fmt " in ASCII
      r["SubChunk1ID"]=SubChunk1ID
      SubChunk1SizeString=fin.read(4) # Should be 16 (PCM, Pulse Code Modulation)
      SubChunk1Size=struct.unpack("I",SubChunk1SizeString) # 'I' format to treat as unsigned 32-bit integer
      r["SubChunk1Size"]=SubChunk1Size
      AudioFormatString=fin.read(2) # Should be 1 (PCM)
      AudioFormat=struct.unpack("H",AudioFormatString) ## 'H' format to treat as unsigned 16-bit integer
      r["AudioFormat"]=AudioFormat[0]
      NumChannelsString=fin.read(2) # Should be 1 for mono, 2 for stereo
      NumChannels=struct.unpack("H",NumChannelsString) # 'H' unsigned 16-bit integer
      r["NumChannels"]=NumChannels[0]
      SampleRateString=fin.read(4) # Should be 44100 (CD sampling rate)
      SampleRate=struct.unpack("I",SampleRateString)
      r["SampleRate"]=SampleRate[0]
      ByteRateString=fin.read(4) # 44100*NumChan*2 (88200 - Mono, 176400 - Stereo)
      ByteRate=struct.unpack("I",ByteRateString) # 'I' unsigned 32 bit integer
      r["ByteRate"]=ByteRate[0]
      BlockAlignString=fin.read(2) # NumChan*2 (2 - Mono, 4 - Stereo)
      BlockAlign=struct.unpack("H",BlockAlignString) # 'H' unsigned 16-bit integer
      r["BlockAlign"]=BlockAlign[0]
      BitsPerSampleString=fin.read(2) # 16 (CD has 16-bits per sample for each channel)
      BitsPerSample=struct.unpack("H",BitsPerSampleString) # 'H' unsigned 16-bit integer
      r["BitsPerSample"]=BitsPerSample[0]
      SubChunk2ID=fin.read(4) # "data" in ASCII
      r["SubChunk2ID"]=SubChunk2ID
      SubChunk2SizeString=fin.read(4) # Number of Data Bytes, Same as DataSize
      SubChunk2Size=struct.unpack("I",SubChunk2SizeString)
      r["SubChunk2Size"]=SubChunk2Size[0]
      S1String=fin.read(2) # Read first data, number between -32768 and 32767
      S1=struct.unpack("h",S1String)
      r["S1"]=S1[0]
      S2String=fin.read(2) # Read second data, number between -32768 and 32767
      S2=struct.unpack("h",S2String)
      r["S2"]=S2[0]
      S3String=fin.read(2) # Read second data, number between -32768 and 32767
      S3=struct.unpack("h",S3String)
      r["S3"]=S3[0]
      S4String=fin.read(2) # Read second data, number between -32768 and 32767
      S4=struct.unpack("h",S4String)
      r["S4"]=S4[0]
      S5String=fin.read(2) # Read second data, number between -32768 and 32767
      S5=struct.unpack("h",S5String)
      r["S5"]=S5[0]
      fin.close()
      return r
  </code></pre>