Back to index

eyed3  0.6.18
mp3.py
Go to the documentation of this file.
00001 ################################################################################
00002 #  Copyright (C) 2002-2005,2007  Travis Shirk <travis@pobox.com>
00003 #
00004 #  This program is free software; you can redistribute it and/or modify
00005 #  it under the terms of the GNU General Public License as published by
00006 #  the Free Software Foundation; either version 2 of the License, or
00007 #  (at your option) any later version.
00008 #
00009 #  This program is distributed in the hope that it will be useful,
00010 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 #  GNU General Public License for more details.
00013 #
00014 #  You should have received a copy of the GNU General Public License
00015 #  along with this program; if not, write to the Free Software
00016 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 #
00018 ################################################################################
00019 from binfuncs import *;
00020 from utils import *;
00021 from math import log10
00022 
00023 #######################################################################
00024 class Mp3Exception(Exception):
00025    '''Error reading mp3'''
00026 
00027 
00028 #                   MPEG1  MPEG2  MPEG2.5
00029 SAMPLE_FREQ_TABLE = ((44100, 22050, 11025),
00030                      (48000, 24000, 12000),
00031                      (32000, 16000, 8000),
00032                      (None,  None,  None));
00033 
00034 #              V1/L1  V1/L2 V1/L3 V2/L1 V2/L2&L3 
00035 BIT_RATE_TABLE = ((0,    0,    0,    0,    0),
00036                   (32,   32,   32,   32,   8),
00037                   (64,   48,   40,   48,   16),
00038                   (96,   56,   48,   56,   24),
00039                   (128,  64,   56,   64,   32),
00040                   (160,  80,   64,   80,   40),
00041                   (192,  96,   80,   96,   44),
00042                   (224,  112,  96,   112,  56),
00043                   (256,  128,  112,  128,  64),
00044                   (288,  160,  128,  144,  80),
00045                   (320,  192,  160,  160,  96),
00046                   (352,  224,  192,  176,  112),
00047                   (384,  256,  224,  192,  128),
00048                   (416,  320,  256,  224,  144),
00049                   (448,  384,  320,  256,  160),
00050                   (None, None, None, None, None));
00051 
00052 #                             L1    L2    L3
00053 TIME_PER_FRAME_TABLE = (None, 384, 1152, 1152);
00054 
00055 # Emphasis constants
00056 EMPHASIS_NONE = "None";
00057 EMPHASIS_5015 = "50/15 ms";
00058 EMPHASIS_CCIT = "CCIT J.17";
00059 
00060 # Mode constants
00061 MODE_STEREO              = "Stereo";
00062 MODE_JOINT_STEREO        = "Joint stereo";
00063 MODE_DUAL_CHANNEL_STEREO = "Dual channel stereo";
00064 MODE_MONO                = "Mono";
00065 
00066 # Xing flag bits
00067 FRAMES_FLAG    = 0x0001
00068 BYTES_FLAG     = 0x0002
00069 TOC_FLAG       = 0x0004
00070 VBR_SCALE_FLAG = 0x0008
00071 
00072 #######################################################################
00073 # Pass in a 4 byte integer to determine if it matches a valid mp3 frame
00074 # header.
00075 def is_valid_mp_header(header):
00076     # Test for the mp3 frame sync: 11 set bits.
00077     sync = (header >> 16)
00078     if sync & 0xFFE0 != 0xFFE0:
00079         # ffe0 is 11 sync bits, and supports identifying mpeg v2.5
00080         return False
00081 
00082     version = (header >> 19) & 0x3
00083     if version == 1:
00084         # This is a "reserved" version
00085         TRACE_MSG("invalid mpeg version")
00086         return False
00087 
00088     layer = (header >> 17) & 0x3
00089     if layer == 0:
00090         # This is a "reserved" layer
00091         TRACE_MSG("invalid mpeg layer")
00092         return False
00093 
00094     bitrate = (header >> 12) & 0xf
00095     if bitrate in (0, 0xf):
00096         # free and bad bitrate values
00097         TRACE_MSG("invalid mpeg bitrate")
00098         return False
00099 
00100     sample_rate = (header >> 10) & 0x3
00101     if sample_rate == 0x3:
00102         # this is a "reserved" sample rate
00103         TRACE_MSG("invalid mpeg sample rate")
00104         return False
00105 
00106     return True
00107 
00108 def find_header(fp, start_pos=0):
00109     def find_sync(fp, start_pos=0):
00110         CHUNK_SIZE = 65536
00111 
00112         fp.seek(start_pos)
00113         data = fp.read(CHUNK_SIZE)
00114         data_len = len(data)
00115 
00116         while data:
00117             sync_pos = data.find('\xff', 0)
00118             if sync_pos >= 0:
00119                 header = data[sync_pos:sync_pos + 4]
00120                 if len(header) == 4:
00121                     return (start_pos + sync_pos, header)
00122             data = fp.read(CHUNK_SIZE)
00123             data_len = len(data)
00124         return (None, None)
00125     sync_pos, header_bytes = find_sync(fp, start_pos)
00126     while sync_pos is not None:
00127         header = bytes2dec(header_bytes)
00128         if is_valid_mp_header(header):
00129             return (sync_pos, header, header_bytes)
00130         sync_pos, header_bytes = find_sync(fp, start_pos + sync_pos + 2)
00131     return (None, None, None)
00132 
00133 def computeTimePerFrame(frameHeader):
00134    return (float(TIME_PER_FRAME_TABLE[frameHeader.layer]) /
00135            float(frameHeader.sampleFreq))
00136 
00137 #######################################################################
00138 class Header:
00139    def __init__(self, header_data=None):
00140        self.version = None
00141        self.layer = None
00142        self.errorProtection = None
00143        self.bitRate = None
00144        self.playTime = None
00145        self.sampleFreq = None
00146        self.padding = None
00147        self.privateBit = None
00148        self.copyright = None
00149        self.original = None
00150        self.emphasis = None
00151        self.mode = None
00152        # This value is left as is: 0<=modeExtension<=3.
00153        # See http://www.dv.co.yu/mpgscript/mpeghdr.htm for how to interpret
00154        self.modeExtension = None
00155 
00156        if header_data:
00157            self.decode(header_data)
00158 
00159    # This may throw an Mp3Exception if the header is malformed.
00160    def decode(self, header):
00161       if not is_valid_mp_header(header):
00162          raise Mp3Exception("Invalid MPEG header");
00163 
00164       # MPEG audio version from bits 19 and 20.
00165       version = (header >> 19) & 0x3
00166       self.version = [2.5, None, 2.0, 1.0][version]
00167       if self.version is None:
00168          raise Mp3Exception("Illegal MPEG version");
00169 
00170       # MPEG layer
00171       self.layer = 4 - ((header >> 17) & 0x3)
00172       if self.layer == 4:
00173          raise Mp3Exception("Illegal MPEG layer");
00174 
00175       # Decode some simple values.
00176       self.errorProtection = not (header >> 16) & 0x1;
00177       self.padding = (header >> 9) & 0x1;
00178       self.privateBit = (header >> 8) & 0x1;
00179       self.copyright = (header >> 3) & 0x1;
00180       self.original = (header >> 2) & 0x1;
00181 
00182       # Obtain sampling frequency.
00183       sampleBits = (header >> 10) & 0x3;
00184       if self.version == 2.5:
00185          freqCol = 2;
00186       else:
00187          freqCol = int(self.version - 1);
00188       self.sampleFreq = SAMPLE_FREQ_TABLE[sampleBits][freqCol];
00189       if not self.sampleFreq:
00190          raise Mp3Exception("Illegal MPEG sampling frequency");
00191 
00192       # Compute bitrate.
00193       bitRateIndex = (header >> 12) & 0xf;
00194       if int(self.version) == 1 and self.layer == 1:
00195          bitRateCol = 0;
00196       elif int(self.version) == 1 and self.layer == 2:
00197          bitRateCol = 1;
00198       elif int(self.version) == 1 and self.layer == 3:
00199          bitRateCol = 2;
00200       elif int(self.version) == 2 and self.layer == 1:
00201          bitRateCol = 3;
00202       elif int(self.version) == 2 and (self.layer == 2 or \
00203                                        self.layer == 3):
00204          bitRateCol = 4;
00205       else:
00206          raise Mp3Exception("Mp3 version %f and layer %d is an invalid "\
00207                             "combination" % (self.version, self.layer));
00208       self.bitRate = BIT_RATE_TABLE[bitRateIndex][bitRateCol];
00209       if self.bitRate == None:
00210          raise Mp3Exception("Invalid bit rate");
00211       # We know know the bit rate specified in this frame, but if the file
00212       # is VBR we need to obtain the average from the Xing header.
00213       # This is done by the caller since right now all we have is the frame
00214       # header.
00215 
00216       # Emphasis; whatever that means??
00217       emph = header & 0x3;
00218       if emph == 0:
00219          self.emphasis = EMPHASIS_NONE;
00220       elif emph == 1:
00221          self.emphasis = EMPHASIS_5015;
00222       elif emph == 2:
00223          self.emphasis = EMPHASIS_CCIT;
00224       elif strictID3():
00225          raise Mp3Exception("Illegal mp3 emphasis value: %d" % emph);
00226 
00227       # Channel mode.
00228       modeBits = (header >> 6) & 0x3;
00229       if modeBits == 0:
00230          self.mode = MODE_STEREO;
00231       elif modeBits == 1:
00232          self.mode = MODE_JOINT_STEREO;
00233       elif modeBits == 2:
00234          self.mode = MODE_DUAL_CHANNEL_STEREO;
00235       else:
00236          self.mode = MODE_MONO;
00237       self.modeExtension = (header >> 4) & 0x3;
00238 
00239       # Layer II has restrictions wrt to mode and bit rate.  This code
00240       # enforces them.
00241       if self.layer == 2:
00242          m = self.mode;
00243          br = self.bitRate;
00244          if (br == 32 or br == 48 or br == 56 or br == 80) and \
00245             (m != MODE_MONO):
00246             raise Mp3Exception("Invalid mode/bitrate combination for layer "\
00247                                "II");
00248          if (br == 224 or br == 256 or br == 320 or br == 384) and \
00249             (m == MODE_MONO):
00250             raise Mp3Exception("Invalid mode/bitrate combination for layer "\
00251                                "II");
00252 
00253       br = self.bitRate * 1000;
00254       sf = self.sampleFreq;
00255       p  = self.padding;
00256       if self.layer == 1:
00257          # Layer 1 uses 32 bit slots for padding.
00258          p  = self.padding * 4;
00259          self.frameLength = int((((12 * br) / sf) + p) * 4);
00260       else:
00261          # Layer 2 and 3 uses 8 bit slots for padding.
00262          p  = self.padding * 1;
00263          self.frameLength = int(((144 * br) / sf) + p);
00264 
00265       # Dump the state.
00266       TRACE_MSG("MPEG audio version: " + str(self.version));
00267       TRACE_MSG("MPEG audio layer: " + ("I" * self.layer));
00268       TRACE_MSG("MPEG sampling frequency: " + str(self.sampleFreq));
00269       TRACE_MSG("MPEG bit rate: " + str(self.bitRate));
00270       TRACE_MSG("MPEG channel mode: " + self.mode);
00271       TRACE_MSG("MPEG channel mode extension: " + str(self.modeExtension));
00272       TRACE_MSG("MPEG CRC error protection: " + str(self.errorProtection));
00273       TRACE_MSG("MPEG original: " + str(self.original));
00274       TRACE_MSG("MPEG copyright: " + str(self.copyright));
00275       TRACE_MSG("MPEG private bit: " + str(self.privateBit));
00276       TRACE_MSG("MPEG padding: " + str(self.padding));
00277       TRACE_MSG("MPEG emphasis: " + str(self.emphasis));
00278       TRACE_MSG("MPEG frame length: " + str(self.frameLength));
00279 
00280 #######################################################################
00281 class XingHeader:
00282    numFrames = int();
00283    numBytes = int();
00284    toc = [0] * 100;
00285    vbrScale = int();
00286 
00287    # Pass in the first mp3 frame from the file as a byte string.
00288    # If an Xing header is present in the file it'll be in the first mp3
00289    # frame.  This method returns true if the Xing header is found in the
00290    # frame, and false otherwise.
00291    def decode(self, frame):
00292       # mp3 version
00293       version = (ord(frame[1]) >> 3) & 0x1;
00294       # channel mode.
00295       mode = (ord(frame[3]) >> 6) & 0x3;
00296 
00297       # Find the start of the Xing header.
00298       if version:
00299          if mode != 3:
00300             pos = 32 + 4;
00301          else:
00302             pos = 17 + 4;
00303       else:
00304          if mode != 3:
00305             pos = 17 + 4;
00306          else:
00307             pos = 9 + 4;
00308       head = frame[pos:pos+4]
00309       self.vbr = (head == 'Xing') and True or False
00310       if head not in ['Xing', 'Info']:
00311           return 0
00312       TRACE_MSG("%s header detected @ %x" % (head, pos));
00313       pos += 4;
00314 
00315       # Read Xing flags.
00316       headFlags = bin2dec(bytes2bin(frame[pos:pos + 4]));
00317       pos += 4;
00318       TRACE_MSG("%s header flags: 0x%x" % (head, headFlags));
00319 
00320       # Read frames header flag and value if present
00321       if headFlags & FRAMES_FLAG:
00322          self.numFrames = bin2dec(bytes2bin(frame[pos:pos + 4]));
00323          pos += 4;
00324          TRACE_MSG("%s numFrames: %d" % (head, self.numFrames));
00325 
00326       # Read bytes header flag and value if present
00327       if headFlags & BYTES_FLAG:
00328          self.numBytes = bin2dec(bytes2bin(frame[pos:pos + 4]));
00329          pos += 4;
00330          TRACE_MSG("%s numBytes: %d" % (head, self.numBytes));
00331 
00332       # Read TOC header flag and value if present
00333       if headFlags & TOC_FLAG:
00334          i = 0;
00335          self.toc = frame[pos:pos + 100];
00336          pos += 100;
00337          TRACE_MSG("%s TOC (100 bytes): PRESENT" % head);
00338       else:
00339          TRACE_MSG("%s TOC (100 bytes): NOT PRESENT" % head);
00340 
00341       # Read vbr scale header flag and value if present
00342       if headFlags & VBR_SCALE_FLAG and head == 'Xing':
00343          self.vbrScale = bin2dec(bytes2bin(frame[pos:pos + 4]));
00344          pos += 4;
00345          TRACE_MSG("%s vbrScale: %d" % (head, self.vbrScale));
00346 
00347       return 1;
00348 
00349 #######################################################################
00350 class LameTag(dict):
00351    """Mp3 Info tag (AKA LAME Tag)
00352 
00353    Lame (and some other encoders) write a tag containing various bits of info
00354    about the options used at encode time.  If available, the following are
00355    parsed and stored in the LameTag dict:
00356 
00357    encoder_version: short encoder version [str]
00358    tag_revision:    revision number of the tag [int]
00359    vbr_method:      VBR method used for encoding [str]
00360    lowpass_filter:  lowpass filter frequency in Hz [int]
00361    replaygain:      if available, radio and audiofile gain (see below) [dict]
00362    encoding_flags:  encoding flags used [list]
00363    nogap:           location of gaps when --nogap was used [list]
00364    ath_type:        ATH type [int]
00365    bitrate:         bitrate and type (Constant, Target, Minimum) [tuple]
00366    encoder_delay:   samples added at the start of the mp3 [int]
00367    encoder_padding: samples added at the end of the mp3 [int]
00368    noise_shaping:   noise shaping method [int]
00369    stereo_mode:     stereo mode used [str]
00370    unwise_settings: whether unwise settings were used [boolean]
00371    sample_freq:     source sample frequency [str]
00372    mp3_gain:        mp3 gain adjustment (rarely used) [float]
00373    preset:          preset used [str]
00374    surround_info:   surround information [str]
00375    music_length:    length in bytes of original mp3 [int]
00376    music_crc:       CRC-16 of the mp3 music data [int]
00377    infotag_crc:     CRC-16 of the info tag [int]
00378 
00379    Prior to ~3.90, Lame simply stored the encoder version in the first frame.
00380    If the infotag_crc is invalid, then we try to read this version string.  A
00381    simple way to tell if the LAME Tag is complete is to check for the
00382    infotag_crc key.
00383 
00384    Replay Gain data is only available since Lame version 3.94b.  If set, the
00385    replaygain dict has the following structure:
00386 
00387       peak_amplitude: peak signal amplitude [float]
00388       radio:
00389          name:       name of the gain adjustment [str]
00390          adjustment: gain adjustment [float]
00391          originator: originator of the gain adjustment [str]
00392       audiofile: [same as radio]
00393 
00394    Note that as of 3.95.1, Lame uses 89dB as a reference level instead of the
00395    83dB that is specified in the Replay Gain spec.  This is not automatically
00396    compensated for.  You can do something like this if you want:
00397 
00398       import eyeD3
00399       af = eyeD3.Mp3AudioFile('/path/to/some.mp3')
00400       lamever = af.lameTag['encoder_version']
00401       name, ver = lamever[:4], lamever[4:]
00402       gain = af.lameTag['replaygain']['radio']['adjustment']
00403       if name == 'LAME' and eyeD3.mp3.lamevercmp(ver, '3.95') > 0:
00404           gain -= 6
00405 
00406    Radio and Audiofile Replay Gain are often referrered to as Track and Album
00407    gain, respectively.  See http://replaygain.hydrogenaudio.org/ for futher
00408    details on Replay Gain.
00409 
00410    See http://gabriel.mp3-tech.org/mp3infotag.html for the gory details of the
00411    LAME Tag.
00412    """
00413 
00414    # from the LAME source:
00415    # http://lame.cvs.sourceforge.net/*checkout*/lame/lame/libmp3lame/VbrTag.c
00416    _crc16_table = [
00417       0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
00418       0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
00419       0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
00420       0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
00421       0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
00422       0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
00423       0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
00424       0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
00425       0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
00426       0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
00427       0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
00428       0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
00429       0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
00430       0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
00431       0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
00432       0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
00433       0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
00434       0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
00435       0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
00436       0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
00437       0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
00438       0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
00439       0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
00440       0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
00441       0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
00442       0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
00443       0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
00444       0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
00445       0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
00446       0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
00447       0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
00448       0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040]
00449 
00450    ENCODER_FLAGS = {
00451       'NSPSYTUNE'   : 0x0001,
00452       'NSSAFEJOINT' : 0x0002,
00453       'NOGAP_NEXT'  : 0x0004,
00454       'NOGAP_PREV'  : 0x0008,}
00455 
00456    PRESETS = {
00457       0:    'Unknown',
00458       # 8 to 320 are reserved for ABR bitrates
00459       410:  'V9',
00460       420:  'V8',
00461       430:  'V7',
00462       440:  'V6',
00463       450:  'V5',
00464       460:  'V4',
00465       470:  'V3',
00466       480:  'V2',
00467       490:  'V1',
00468       500:  'V0',
00469       1000: 'r3mix',
00470       1001: 'standard',
00471       1002: 'extreme',
00472       1003: 'insane',
00473       1004: 'standard/fast',
00474       1005: 'extreme/fast',
00475       1006: 'medium',
00476       1007: 'medium/fast',}
00477 
00478    REPLAYGAIN_NAME = {
00479       0: 'Not set',
00480       1: 'Radio',
00481       2: 'Audiofile',}
00482 
00483    REPLAYGAIN_ORIGINATOR = {
00484       0:   'Not set',
00485       1:   'Set by artist',
00486       2:   'Set by user',
00487       3:   'Set automatically',
00488       100: 'Set by simple RMS average',}
00489 
00490    SAMPLE_FREQUENCIES = {
00491       0: '<= 32 kHz',
00492       1: '44.1 kHz',
00493       2: '48 kHz',
00494       3: '> 48 kHz',}
00495 
00496    STEREO_MODES = {
00497       0: 'Mono',
00498       1: 'Stereo',
00499       2: 'Dual',
00500       3: 'Joint',
00501       4: 'Force',
00502       5: 'Auto',
00503       6: 'Intensity',
00504       7: 'Undefined',}
00505 
00506    SURROUND_INFO = {
00507       0: 'None',
00508       1: 'DPL encoding',
00509       2: 'DPL2 encoding',
00510       3: 'Ambisonic encoding',
00511       8: 'Reserved',}
00512 
00513    VBR_METHODS = {
00514       0:  'Unknown',
00515       1:  'Constant Bitrate',
00516       2:  'Average Bitrate',
00517       3:  'Variable Bitrate method1 (old/rh)',
00518       4:  'Variable Bitrate method2 (mtrh)',
00519       5:  'Variable Bitrate method3 (mt)',
00520       6:  'Variable Bitrate method4',
00521       8:  'Constant Bitrate (2 pass)',
00522       9:  'Average Bitrate (2 pass)',
00523       15: 'Reserved',}
00524 
00525    def __init__(self, frame):
00526       """Read the LAME info tag.
00527 
00528       frame should be the first frame of an mp3.
00529       """
00530       self.decode(frame)
00531 
00532    def _crc16(self, data, val = 0):
00533       """Compute a CRC-16 checksum on a data stream."""
00534       for c in data:
00535          val = self._crc16_table[ord(c) ^ (val & 0xff)] ^ (val >> 8)
00536       return val
00537 
00538    def decode(self, frame):
00539       """Decode the LAME info tag."""
00540       try: pos = frame.index("LAME")
00541       except: return
00542 
00543       # check the info tag crc.  if it's not valid, no point parsing much more.
00544       lamecrc = bin2dec(bytes2bin(frame[190:192]))
00545       if self._crc16(frame[:190]) != lamecrc:
00546          #TRACE_MSG('Lame tag CRC check failed')
00547          # read version string from the first 30 bytes, up to any
00548          # non-ascii chars, then strip padding chars.
00549          #
00550          # XXX (How many bytes is proper to read?  madplay reads 20, but I've
00551          # got files with longer version strings)
00552          lamever = []
00553          for c in frame[pos:pos + 30]:
00554             if ord(c) not in range(32, 127):
00555                break
00556             lamever.append(c)
00557          self['encoder_version'] = ''.join(lamever).rstrip('\x55')
00558          TRACE_MSG('Lame Encoder Version: %s' % self['encoder_version'])
00559          return
00560 
00561       TRACE_MSG('Lame info tag found at position %d' % pos)
00562 
00563       # Encoder short VersionString, 9 bytes
00564       self['encoder_version'] = lamever = frame[pos:pos + 9].rstrip()
00565       TRACE_MSG('Lame Encoder Version: %s' % self['encoder_version'])
00566       pos += 9
00567 
00568       # Info Tag revision + VBR method, 1 byte
00569       self['tag_revision'] = bin2dec(bytes2bin(frame[pos:pos + 1])[:5])
00570       vbr_method = bin2dec(bytes2bin(frame[pos:pos + 1])[5:])
00571       self['vbr_method'] = self.VBR_METHODS.get(vbr_method, 'Unknown')
00572       TRACE_MSG('Lame info tag version: %s' % self['tag_revision'])
00573       TRACE_MSG('Lame VBR method: %s' % self['vbr_method'])
00574       pos += 1
00575 
00576       # Lowpass filter value, 1 byte
00577       self['lowpass_filter'] = bin2dec(bytes2bin(frame[pos:pos + 1])) * 100
00578       TRACE_MSG('Lame Lowpass filter value: %s Hz' % self['lowpass_filter'])
00579       pos += 1
00580 
00581       # Replay Gain, 8 bytes total
00582       replaygain = {}
00583 
00584       # Peak signal amplitude, 4 bytes
00585       peak = bin2dec(bytes2bin(frame[pos:pos + 4])) << 5
00586       if peak > 0:
00587          peak /= float(1 << 28)
00588          db = 20 * log10(peak)
00589          replaygain['peak_amplitude'] = peak
00590          TRACE_MSG('Lame Peak signal amplitude: %.8f (%+.1f dB)' % (peak, db))
00591       pos += 4
00592 
00593       # Radio and Audiofile Gain, AKA track and album, 2 bytes each
00594       for gaintype in ['radio', 'audiofile']:
00595          name = bin2dec(bytes2bin(frame[pos:pos + 2])[:3])
00596          orig = bin2dec(bytes2bin(frame[pos:pos + 2])[3:6])
00597          sign = bin2dec(bytes2bin(frame[pos:pos + 2])[6:7])
00598          adj  = bin2dec(bytes2bin(frame[pos:pos + 2])[7:]) / 10.0
00599          if sign:
00600             adj *= -1
00601          # XXX Lame 3.95.1 and above use 89dB as a reference instead of 83dB
00602          # as defined by the Replay Gain spec.  Should this be compensated for?
00603          #if lamever[:4] == 'LAME' and lamevercmp(lamever[4:], '3.95') > 0:
00604          #   adj -= 6
00605          if orig:
00606             name = self.REPLAYGAIN_NAME.get(name, 'Unknown')
00607             orig = self.REPLAYGAIN_ORIGINATOR.get(orig, 'Unknown')
00608             replaygain[gaintype] = {'name': name, 'adjustment': adj,
00609                                     'originator': orig}
00610             TRACE_MSG('Lame %s Replay Gain: %s dB (%s)' % (name, adj, orig))
00611          pos += 2
00612       if replaygain:
00613          self['replaygain'] = replaygain
00614 
00615       # Encoding flags + ATH Type, 1 byte
00616       encflags = bin2dec(bytes2bin(frame[pos:pos + 1])[:4])
00617       self['encoding_flags'], self['nogap'] = self._parse_encflags(encflags)
00618       self['ath_type'] = bin2dec(bytes2bin(frame[pos:pos + 1])[4:])
00619       TRACE_MSG('Lame Encoding flags: %s' % ' '.join(self['encoding_flags']))
00620       if self['nogap']:
00621          TRACE_MSG('Lame No gap: %s' % ' and '.join(self['nogap']))
00622       TRACE_MSG('Lame ATH type: %s' % self['ath_type'])
00623       pos += 1
00624 
00625       # if ABR {specified bitrate} else {minimal bitrate}, 1 byte
00626       btype = 'Constant'
00627       if 'Average' in self['vbr_method']:
00628          btype = 'Target'
00629       elif 'Variable' in self['vbr_method']:
00630          btype = 'Minimum'
00631       # bitrate may be modified below after preset is read
00632       self['bitrate'] = (bin2dec(bytes2bin(frame[pos:pos + 1])), btype)
00633       TRACE_MSG('Lame Bitrate (%s): %s' % (btype, self['bitrate'][0]))
00634       pos += 1
00635 
00636       # Encoder delays, 3 bytes
00637       self['encoder_delay'] = bin2dec(bytes2bin(frame[pos:pos + 3])[:12])
00638       self['encoder_padding'] = bin2dec(bytes2bin(frame[pos:pos + 3])[12:])
00639       TRACE_MSG('Lame Encoder delay: %s samples' % self['encoder_delay'])
00640       TRACE_MSG('Lame Encoder padding: %s samples' % self['encoder_padding'])
00641       pos += 3
00642 
00643       # Misc, 1 byte
00644       sample_freq = bin2dec(bytes2bin(frame[pos:pos + 1])[:2])
00645       unwise_settings = bin2dec(bytes2bin(frame[pos:pos + 1])[2:3])
00646       stereo_mode = bin2dec(bytes2bin(frame[pos:pos + 1])[3:6])
00647       self['noise_shaping'] = bin2dec(bytes2bin(frame[pos:pos + 1])[6:])
00648       self['sample_freq'] = self.SAMPLE_FREQUENCIES.get(sample_freq, 'Unknown')
00649       self['unwise_settings'] = bool(unwise_settings)
00650       self['stereo_mode'] = self.STEREO_MODES.get(stereo_mode, 'Unknown')
00651       TRACE_MSG('Lame Source Sample Frequency: %s' % self['sample_freq'])
00652       TRACE_MSG('Lame Unwise settings used: %s' % self['unwise_settings'])
00653       TRACE_MSG('Lame Stereo mode: %s' % self['stereo_mode'])
00654       TRACE_MSG('Lame Noise Shaping: %s' % self['noise_shaping'])
00655       pos += 1
00656 
00657       # MP3 Gain, 1 byte
00658       sign = bytes2bin(frame[pos:pos + 1])[0]
00659       gain = bin2dec(bytes2bin(frame[pos:pos + 1])[1:])
00660       if sign:
00661          gain *= -1
00662       self['mp3_gain'] = gain
00663       db = gain * 1.5
00664       TRACE_MSG('Lame MP3 Gain: %s (%+.1f dB)' % (self['mp3_gain'], db))
00665       pos += 1
00666 
00667       # Preset and surround info, 2 bytes
00668       surround = bin2dec(bytes2bin(frame[pos:pos + 2])[2:5])
00669       preset = bin2dec(bytes2bin(frame[pos:pos + 2])[5:])
00670       if preset in range(8, 321):
00671          if self['bitrate'] >= 255:
00672             # the value from preset is better in this case
00673             self['bitrate'] = (preset, btype)
00674             TRACE_MSG('Lame Bitrate (%s): %s' % (btype, self['bitrate'][0]))
00675          if 'Average' in self['vbr_method']:
00676             preset = 'ABR %s' % preset
00677          else:
00678             preset = 'CBR %s' % preset
00679       else:
00680          preset = self.PRESETS.get(preset, preset)
00681       self['surround_info'] = self.SURROUND_INFO.get(surround, surround)
00682       self['preset'] = preset
00683       TRACE_MSG('Lame Surround Info: %s' % self['surround_info'])
00684       TRACE_MSG('Lame Preset: %s' % self['preset'])
00685       pos += 2
00686 
00687       # MusicLength, 4 bytes
00688       self['music_length'] = bin2dec(bytes2bin(frame[pos:pos + 4]))
00689       TRACE_MSG('Lame Music Length: %s bytes' % self['music_length'])
00690       pos += 4
00691 
00692       # MusicCRC, 2 bytes
00693       self['music_crc'] = bin2dec(bytes2bin(frame[pos:pos + 2]))
00694       TRACE_MSG('Lame Music CRC: %04X' % self['music_crc'])
00695       pos += 2
00696 
00697       # CRC-16 of Info Tag, 2 bytes
00698       self['infotag_crc'] = lamecrc # we read this earlier
00699       TRACE_MSG('Lame Info Tag CRC: %04X' % self['infotag_crc'])
00700       pos += 2
00701 
00702    def _parse_encflags(self, flags):
00703       """Parse encoder flags.
00704 
00705       Returns a tuple containing lists of encoder flags and nogap data in
00706       human readable format.
00707       """
00708 
00709       encoder_flags, nogap = [], []
00710 
00711       if not flags:
00712          return encoder_flags, nogap
00713 
00714       if flags & self.ENCODER_FLAGS['NSPSYTUNE']:
00715          encoder_flags.append('--nspsytune')
00716       if flags & self.ENCODER_FLAGS['NSSAFEJOINT']:
00717          encoder_flags.append('--nssafejoint')
00718 
00719       NEXT = self.ENCODER_FLAGS['NOGAP_NEXT']
00720       PREV = self.ENCODER_FLAGS['NOGAP_PREV']
00721       if flags & (NEXT | PREV):
00722          encoder_flags.append('--nogap')
00723          if flags & PREV:
00724             nogap.append('before')
00725          if flags & NEXT:
00726             nogap.append('after')
00727       return encoder_flags, nogap
00728 
00729 def lamevercmp(x, y):
00730    """Compare LAME version strings.
00731 
00732    alpha and beta versions are considered older.
00733    versions with sub minor parts or end with 'r' are considered newer.
00734 
00735    Return negative if x<y, zero if x==y, positive if x>y.
00736    """
00737 
00738    x = x.ljust(5)
00739    y = y.ljust(5)
00740    if x[:5] == y[:5]: return 0
00741    ret = cmp(x[:4], y[:4])
00742    if ret: return ret
00743    xmaj, xmin = x.split('.')[:2]
00744    ymaj, ymin = y.split('.')[:2]
00745    minparts = ['.']
00746    # lame 3.96.1 added the use of r in the very short version for post releases
00747    if (xmaj == '3' and xmin >= '96') or (ymaj == '3' and ymin >= '96'):
00748       minparts.append('r')
00749    if x[4] in minparts: return 1
00750    if y[4] in minparts: return -1
00751    if x[4] == ' ': return 1
00752    if y[4] == ' ': return -1
00753    return cmp(x[4], y[4])