Back to index

eyed3  0.6.18
Public Member Functions | Static Public Attributes | Private Member Functions | Static Private Attributes
mp3.LameTag Class Reference

List of all members.

Public Member Functions

def __init__
def decode

Static Public Attributes

dictionary ENCODER_FLAGS
dictionary PRESETS
dictionary REPLAYGAIN_NAME
dictionary REPLAYGAIN_ORIGINATOR
dictionary SAMPLE_FREQUENCIES
dictionary STEREO_MODES
dictionary SURROUND_INFO
dictionary VBR_METHODS

Private Member Functions

def _crc16
def _parse_encflags

Static Private Attributes

list _crc16_table

Detailed Description

Mp3 Info tag (AKA LAME Tag)

Lame (and some other encoders) write a tag containing various bits of info
about the options used at encode time.  If available, the following are
parsed and stored in the LameTag dict:

encoder_version: short encoder version [str]
tag_revision:    revision number of the tag [int]
vbr_method:      VBR method used for encoding [str]
lowpass_filter:  lowpass filter frequency in Hz [int]
replaygain:      if available, radio and audiofile gain (see below) [dict]
encoding_flags:  encoding flags used [list]
nogap:           location of gaps when --nogap was used [list]
ath_type:        ATH type [int]
bitrate:         bitrate and type (Constant, Target, Minimum) [tuple]
encoder_delay:   samples added at the start of the mp3 [int]
encoder_padding: samples added at the end of the mp3 [int]
noise_shaping:   noise shaping method [int]
stereo_mode:     stereo mode used [str]
unwise_settings: whether unwise settings were used [boolean]
sample_freq:     source sample frequency [str]
mp3_gain:        mp3 gain adjustment (rarely used) [float]
preset:          preset used [str]
surround_info:   surround information [str]
music_length:    length in bytes of original mp3 [int]
music_crc:       CRC-16 of the mp3 music data [int]
infotag_crc:     CRC-16 of the info tag [int]

Prior to ~3.90, Lame simply stored the encoder version in the first frame.
If the infotag_crc is invalid, then we try to read this version string.  A
simple way to tell if the LAME Tag is complete is to check for the
infotag_crc key.

Replay Gain data is only available since Lame version 3.94b.  If set, the
replaygain dict has the following structure:

   peak_amplitude: peak signal amplitude [float]
   radio:
      name:       name of the gain adjustment [str]
      adjustment: gain adjustment [float]
      originator: originator of the gain adjustment [str]
   audiofile: [same as radio]

Note that as of 3.95.1, Lame uses 89dB as a reference level instead of the
83dB that is specified in the Replay Gain spec.  This is not automatically
compensated for.  You can do something like this if you want:

   import eyeD3
   af = eyeD3.Mp3AudioFile('/path/to/some.mp3')
   lamever = af.lameTag['encoder_version']
   name, ver = lamever[:4], lamever[4:]
   gain = af.lameTag['replaygain']['radio']['adjustment']
   if name == 'LAME' and eyeD3.mp3.lamevercmp(ver, '3.95') > 0:
       gain -= 6

Radio and Audiofile Replay Gain are often referrered to as Track and Album
gain, respectively.  See http://replaygain.hydrogenaudio.org/ for futher
details on Replay Gain.

See http://gabriel.mp3-tech.org/mp3infotag.html for the gory details of the
LAME Tag.

Definition at line 350 of file mp3.py.


Constructor & Destructor Documentation

def mp3.LameTag.__init__ (   self,
  frame 
)
Read the LAME info tag.

frame should be the first frame of an mp3.

Definition at line 525 of file mp3.py.

00525 
00526    def __init__(self, frame):
00527       """Read the LAME info tag.
00528 
00529       frame should be the first frame of an mp3.
00530       """
00531       self.decode(frame)

Here is the call graph for this function:


Member Function Documentation

def mp3.LameTag._crc16 (   self,
  data,
  val = 0 
) [private]
Compute a CRC-16 checksum on a data stream.

Definition at line 532 of file mp3.py.

00532 
00533    def _crc16(self, data, val = 0):
00534       """Compute a CRC-16 checksum on a data stream."""
00535       for c in data:
00536          val = self._crc16_table[ord(c) ^ (val & 0xff)] ^ (val >> 8)
00537       return val

Here is the caller graph for this function:

def mp3.LameTag._parse_encflags (   self,
  flags 
) [private]
Parse encoder flags.

Returns a tuple containing lists of encoder flags and nogap data in
human readable format.

Definition at line 702 of file mp3.py.

00702 
00703    def _parse_encflags(self, flags):
00704       """Parse encoder flags.
00705 
00706       Returns a tuple containing lists of encoder flags and nogap data in
00707       human readable format.
00708       """
00709 
00710       encoder_flags, nogap = [], []
00711 
00712       if not flags:
00713          return encoder_flags, nogap
00714 
00715       if flags & self.ENCODER_FLAGS['NSPSYTUNE']:
00716          encoder_flags.append('--nspsytune')
00717       if flags & self.ENCODER_FLAGS['NSSAFEJOINT']:
00718          encoder_flags.append('--nssafejoint')
00719 
00720       NEXT = self.ENCODER_FLAGS['NOGAP_NEXT']
00721       PREV = self.ENCODER_FLAGS['NOGAP_PREV']
00722       if flags & (NEXT | PREV):
00723          encoder_flags.append('--nogap')
00724          if flags & PREV:
00725             nogap.append('before')
00726          if flags & NEXT:
00727             nogap.append('after')
00728       return encoder_flags, nogap

Here is the caller graph for this function:

def mp3.LameTag.decode (   self,
  frame 
)
Decode the LAME info tag.

Definition at line 538 of file mp3.py.

00538 
00539    def decode(self, frame):
00540       """Decode the LAME info tag."""
00541       try: pos = frame.index("LAME")
00542       except: return
00543 
00544       # check the info tag crc.  if it's not valid, no point parsing much more.
00545       lamecrc = bin2dec(bytes2bin(frame[190:192]))
00546       if self._crc16(frame[:190]) != lamecrc:
00547          #TRACE_MSG('Lame tag CRC check failed')
00548          # read version string from the first 30 bytes, up to any
00549          # non-ascii chars, then strip padding chars.
00550          #
00551          # XXX (How many bytes is proper to read?  madplay reads 20, but I've
00552          # got files with longer version strings)
00553          lamever = []
00554          for c in frame[pos:pos + 30]:
00555             if ord(c) not in range(32, 127):
00556                break
00557             lamever.append(c)
00558          self['encoder_version'] = ''.join(lamever).rstrip('\x55')
00559          TRACE_MSG('Lame Encoder Version: %s' % self['encoder_version'])
00560          return
00561 
00562       TRACE_MSG('Lame info tag found at position %d' % pos)
00563 
00564       # Encoder short VersionString, 9 bytes
00565       self['encoder_version'] = lamever = frame[pos:pos + 9].rstrip()
00566       TRACE_MSG('Lame Encoder Version: %s' % self['encoder_version'])
00567       pos += 9
00568 
00569       # Info Tag revision + VBR method, 1 byte
00570       self['tag_revision'] = bin2dec(bytes2bin(frame[pos:pos + 1])[:5])
00571       vbr_method = bin2dec(bytes2bin(frame[pos:pos + 1])[5:])
00572       self['vbr_method'] = self.VBR_METHODS.get(vbr_method, 'Unknown')
00573       TRACE_MSG('Lame info tag version: %s' % self['tag_revision'])
00574       TRACE_MSG('Lame VBR method: %s' % self['vbr_method'])
00575       pos += 1
00576 
00577       # Lowpass filter value, 1 byte
00578       self['lowpass_filter'] = bin2dec(bytes2bin(frame[pos:pos + 1])) * 100
00579       TRACE_MSG('Lame Lowpass filter value: %s Hz' % self['lowpass_filter'])
00580       pos += 1
00581 
00582       # Replay Gain, 8 bytes total
00583       replaygain = {}
00584 
00585       # Peak signal amplitude, 4 bytes
00586       peak = bin2dec(bytes2bin(frame[pos:pos + 4])) << 5
00587       if peak > 0:
00588          peak /= float(1 << 28)
00589          db = 20 * log10(peak)
00590          replaygain['peak_amplitude'] = peak
00591          TRACE_MSG('Lame Peak signal amplitude: %.8f (%+.1f dB)' % (peak, db))
00592       pos += 4
00593 
00594       # Radio and Audiofile Gain, AKA track and album, 2 bytes each
00595       for gaintype in ['radio', 'audiofile']:
00596          name = bin2dec(bytes2bin(frame[pos:pos + 2])[:3])
00597          orig = bin2dec(bytes2bin(frame[pos:pos + 2])[3:6])
00598          sign = bin2dec(bytes2bin(frame[pos:pos + 2])[6:7])
00599          adj  = bin2dec(bytes2bin(frame[pos:pos + 2])[7:]) / 10.0
00600          if sign:
00601             adj *= -1
00602          # XXX Lame 3.95.1 and above use 89dB as a reference instead of 83dB
00603          # as defined by the Replay Gain spec.  Should this be compensated for?
00604          #if lamever[:4] == 'LAME' and lamevercmp(lamever[4:], '3.95') > 0:
00605          #   adj -= 6
00606          if orig:
00607             name = self.REPLAYGAIN_NAME.get(name, 'Unknown')
00608             orig = self.REPLAYGAIN_ORIGINATOR.get(orig, 'Unknown')
00609             replaygain[gaintype] = {'name': name, 'adjustment': adj,
00610                                     'originator': orig}
00611             TRACE_MSG('Lame %s Replay Gain: %s dB (%s)' % (name, adj, orig))
00612          pos += 2
00613       if replaygain:
00614          self['replaygain'] = replaygain
00615 
00616       # Encoding flags + ATH Type, 1 byte
00617       encflags = bin2dec(bytes2bin(frame[pos:pos + 1])[:4])
00618       self['encoding_flags'], self['nogap'] = self._parse_encflags(encflags)
00619       self['ath_type'] = bin2dec(bytes2bin(frame[pos:pos + 1])[4:])
00620       TRACE_MSG('Lame Encoding flags: %s' % ' '.join(self['encoding_flags']))
00621       if self['nogap']:
00622          TRACE_MSG('Lame No gap: %s' % ' and '.join(self['nogap']))
00623       TRACE_MSG('Lame ATH type: %s' % self['ath_type'])
00624       pos += 1
00625 
00626       # if ABR {specified bitrate} else {minimal bitrate}, 1 byte
00627       btype = 'Constant'
00628       if 'Average' in self['vbr_method']:
00629          btype = 'Target'
00630       elif 'Variable' in self['vbr_method']:
00631          btype = 'Minimum'
00632       # bitrate may be modified below after preset is read
00633       self['bitrate'] = (bin2dec(bytes2bin(frame[pos:pos + 1])), btype)
00634       TRACE_MSG('Lame Bitrate (%s): %s' % (btype, self['bitrate'][0]))
00635       pos += 1
00636 
00637       # Encoder delays, 3 bytes
00638       self['encoder_delay'] = bin2dec(bytes2bin(frame[pos:pos + 3])[:12])
00639       self['encoder_padding'] = bin2dec(bytes2bin(frame[pos:pos + 3])[12:])
00640       TRACE_MSG('Lame Encoder delay: %s samples' % self['encoder_delay'])
00641       TRACE_MSG('Lame Encoder padding: %s samples' % self['encoder_padding'])
00642       pos += 3
00643 
00644       # Misc, 1 byte
00645       sample_freq = bin2dec(bytes2bin(frame[pos:pos + 1])[:2])
00646       unwise_settings = bin2dec(bytes2bin(frame[pos:pos + 1])[2:3])
00647       stereo_mode = bin2dec(bytes2bin(frame[pos:pos + 1])[3:6])
00648       self['noise_shaping'] = bin2dec(bytes2bin(frame[pos:pos + 1])[6:])
00649       self['sample_freq'] = self.SAMPLE_FREQUENCIES.get(sample_freq, 'Unknown')
00650       self['unwise_settings'] = bool(unwise_settings)
00651       self['stereo_mode'] = self.STEREO_MODES.get(stereo_mode, 'Unknown')
00652       TRACE_MSG('Lame Source Sample Frequency: %s' % self['sample_freq'])
00653       TRACE_MSG('Lame Unwise settings used: %s' % self['unwise_settings'])
00654       TRACE_MSG('Lame Stereo mode: %s' % self['stereo_mode'])
00655       TRACE_MSG('Lame Noise Shaping: %s' % self['noise_shaping'])
00656       pos += 1
00657 
00658       # MP3 Gain, 1 byte
00659       sign = bytes2bin(frame[pos:pos + 1])[0]
00660       gain = bin2dec(bytes2bin(frame[pos:pos + 1])[1:])
00661       if sign:
00662          gain *= -1
00663       self['mp3_gain'] = gain
00664       db = gain * 1.5
00665       TRACE_MSG('Lame MP3 Gain: %s (%+.1f dB)' % (self['mp3_gain'], db))
00666       pos += 1
00667 
00668       # Preset and surround info, 2 bytes
00669       surround = bin2dec(bytes2bin(frame[pos:pos + 2])[2:5])
00670       preset = bin2dec(bytes2bin(frame[pos:pos + 2])[5:])
00671       if preset in range(8, 321):
00672          if self['bitrate'] >= 255:
00673             # the value from preset is better in this case
00674             self['bitrate'] = (preset, btype)
00675             TRACE_MSG('Lame Bitrate (%s): %s' % (btype, self['bitrate'][0]))
00676          if 'Average' in self['vbr_method']:
00677             preset = 'ABR %s' % preset
00678          else:
00679             preset = 'CBR %s' % preset
00680       else:
00681          preset = self.PRESETS.get(preset, preset)
00682       self['surround_info'] = self.SURROUND_INFO.get(surround, surround)
00683       self['preset'] = preset
00684       TRACE_MSG('Lame Surround Info: %s' % self['surround_info'])
00685       TRACE_MSG('Lame Preset: %s' % self['preset'])
00686       pos += 2
00687 
00688       # MusicLength, 4 bytes
00689       self['music_length'] = bin2dec(bytes2bin(frame[pos:pos + 4]))
00690       TRACE_MSG('Lame Music Length: %s bytes' % self['music_length'])
00691       pos += 4
00692 
00693       # MusicCRC, 2 bytes
00694       self['music_crc'] = bin2dec(bytes2bin(frame[pos:pos + 2]))
00695       TRACE_MSG('Lame Music CRC: %04X' % self['music_crc'])
00696       pos += 2
00697 
00698       # CRC-16 of Info Tag, 2 bytes
00699       self['infotag_crc'] = lamecrc # we read this earlier
00700       TRACE_MSG('Lame Info Tag CRC: %04X' % self['infotag_crc'])
00701       pos += 2

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

list mp3.LameTag._crc16_table [static, private]

Definition at line 416 of file mp3.py.

dictionary mp3.LameTag.ENCODER_FLAGS [static]
Initial value:
{
      'NSPSYTUNE'   : 0x0001,
      'NSSAFEJOINT' : 0x0002,
      'NOGAP_NEXT'  : 0x0004,
      'NOGAP_PREV'  : 0x0008,}

Definition at line 450 of file mp3.py.

dictionary mp3.LameTag.PRESETS [static]
Initial value:
{
      0:    'Unknown',
      # 8 to 320 are reserved for ABR bitrates
      410:  'V9',
      420:  'V8',
      430:  'V7',
      440:  'V6',
      450:  'V5',
      460:  'V4',
      470:  'V3',
      480:  'V2',
      490:  'V1',
      500:  'V0',
      1000: 'r3mix',
      1001: 'standard',
      1002: 'extreme',
      1003: 'insane',
      1004: 'standard/fast',
      1005: 'extreme/fast',
      1006: 'medium',
      1007: 'medium/fast',}

Definition at line 456 of file mp3.py.

dictionary mp3.LameTag.REPLAYGAIN_NAME [static]
Initial value:
{
      0: 'Not set',
      1: 'Radio',
      2: 'Audiofile',}

Definition at line 478 of file mp3.py.

dictionary mp3.LameTag.REPLAYGAIN_ORIGINATOR [static]
Initial value:
{
      0:   'Not set',
      1:   'Set by artist',
      2:   'Set by user',
      3:   'Set automatically',
      100: 'Set by simple RMS average',}

Definition at line 483 of file mp3.py.

dictionary mp3.LameTag.SAMPLE_FREQUENCIES [static]
Initial value:
{
      0: '<= 32 kHz',
      1: '44.1 kHz',
      2: '48 kHz',
      3: '> 48 kHz',}

Definition at line 490 of file mp3.py.

dictionary mp3.LameTag.STEREO_MODES [static]
Initial value:
{
      0: 'Mono',
      1: 'Stereo',
      2: 'Dual',
      3: 'Joint',
      4: 'Force',
      5: 'Auto',
      6: 'Intensity',
      7: 'Undefined',}

Definition at line 496 of file mp3.py.

dictionary mp3.LameTag.SURROUND_INFO [static]
Initial value:
{
      0: 'None',
      1: 'DPL encoding',
      2: 'DPL2 encoding',
      3: 'Ambisonic encoding',
      8: 'Reserved',}

Definition at line 506 of file mp3.py.

dictionary mp3.LameTag.VBR_METHODS [static]
Initial value:
{
      0:  'Unknown',
      1:  'Constant Bitrate',
      2:  'Average Bitrate',
      3:  'Variable Bitrate method1 (old/rh)',
      4:  'Variable Bitrate method2 (mtrh)',
      5:  'Variable Bitrate method3 (mt)',
      6:  'Variable Bitrate method4',
      8:  'Constant Bitrate (2 pass)',
      9:  'Average Bitrate (2 pass)',
      15: 'Reserved',}

Definition at line 513 of file mp3.py.


The documentation for this class was generated from the following file: