Merge branch 'master' of git://repo.or.cz/pyTivo/wmcbrine
[pyTivo/wgw.git] / eyeD3 / mp3.py
blobf3770864a25cee95fc6046ad219395c170469bbd
1 ################################################################################
2 # Copyright (C) 2002-2005,2007 Travis Shirk <travis@pobox.com>
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ################################################################################
19 from binfuncs import *;
20 from utils import *;
21 from math import log10
23 #######################################################################
24 class Mp3Exception(Exception):
25 '''Error reading mp3'''
28 # MPEG1 MPEG2 MPEG2.5
29 SAMPLE_FREQ_TABLE = ((44100, 22050, 11025),
30 (48000, 24000, 12000),
31 (32000, 16000, 8000),
32 (None, None, None));
34 # V1/L1 V1/L2 V1/L3 V2/L1 V2/L2&L3
35 BIT_RATE_TABLE = ((0, 0, 0, 0, 0),
36 (32, 32, 32, 32, 8),
37 (64, 48, 40, 48, 16),
38 (96, 56, 48, 56, 24),
39 (128, 64, 56, 64, 32),
40 (160, 80, 64, 80, 40),
41 (192, 96, 80, 96, 44),
42 (224, 112, 96, 112, 56),
43 (256, 128, 112, 128, 64),
44 (288, 160, 128, 144, 80),
45 (320, 192, 160, 160, 96),
46 (352, 224, 192, 176, 112),
47 (384, 256, 224, 192, 128),
48 (416, 320, 256, 224, 144),
49 (448, 384, 320, 256, 160),
50 (None, None, None, None, None));
52 # L1 L2 L3
53 TIME_PER_FRAME_TABLE = (None, 384, 1152, 1152);
55 # Emphasis constants
56 EMPHASIS_NONE = "None";
57 EMPHASIS_5015 = "50/15 ms";
58 EMPHASIS_CCIT = "CCIT J.17";
60 # Mode constants
61 MODE_STEREO = "Stereo";
62 MODE_JOINT_STEREO = "Joint stereo";
63 MODE_DUAL_CHANNEL_STEREO = "Dual channel stereo";
64 MODE_MONO = "Mono";
66 # Xing flag bits
67 FRAMES_FLAG = 0x0001
68 BYTES_FLAG = 0x0002
69 TOC_FLAG = 0x0004
70 VBR_SCALE_FLAG = 0x0008
72 #######################################################################
73 # Pass in a 4 byte integer to determine if it matches a valid mp3 frame
74 # header.
75 def is_valid_mp_header(header):
76 # Test for the mp3 frame sync: 11 set bits.
77 sync = (header >> 16)
78 if sync & 0xFFE0 != 0xFFE0:
79 # ffe0 is 11 sync bits, and supports identifying mpeg v2.5
80 return False
82 version = (header >> 19) & 0x3
83 if version == 1:
84 # This is a "reserved" version
85 TRACE_MSG("invalid mpeg version")
86 return False
88 layer = (header >> 17) & 0x3
89 if layer == 0:
90 # This is a "reserved" layer
91 TRACE_MSG("invalid mpeg layer")
92 return False
94 bitrate = (header >> 12) & 0xf
95 if bitrate in (0, 0xf):
96 # free and bad bitrate values
97 TRACE_MSG("invalid mpeg bitrate")
98 return False
100 sample_rate = (header >> 10) & 0x3
101 if sample_rate == 0x3:
102 # this is a "reserved" sample rate
103 TRACE_MSG("invalid mpeg sample rate")
104 return False
106 return True
108 def find_header(fp, start_pos=0):
109 def find_sync(fp, start_pos=0):
110 CHUNK_SIZE = 65536
112 fp.seek(start_pos)
113 data = fp.read(CHUNK_SIZE)
114 data_len = len(data)
116 while data:
117 sync_pos = data.find('\xff', 0)
118 if sync_pos >= 0:
119 header = data[sync_pos:sync_pos + 4]
120 if len(header) == 4:
121 return (start_pos + sync_pos, header)
122 data = fp.read(CHUNK_SIZE)
123 data_len = len(data)
124 return (None, None)
125 sync_pos, header_bytes = find_sync(fp, start_pos)
126 while sync_pos is not None:
127 header = bytes2dec(header_bytes)
128 if is_valid_mp_header(header):
129 return (sync_pos, header, header_bytes)
130 sync_pos, header_bytes = find_sync(fp, start_pos + sync_pos + 2)
131 return (None, None, None)
133 def computeTimePerFrame(frameHeader):
134 return (float(TIME_PER_FRAME_TABLE[frameHeader.layer]) /
135 float(frameHeader.sampleFreq))
137 #######################################################################
138 class Header:
139 def __init__(self, header_data=None):
140 self.version = None
141 self.layer = None
142 self.errorProtection = None
143 self.bitRate = None
144 self.playTime = None
145 self.sampleFreq = None
146 self.padding = None
147 self.privateBit = None
148 self.copyright = None
149 self.original = None
150 self.emphasis = None
151 self.mode = None
152 # This value is left as is: 0<=modeExtension<=3.
153 # See http://www.dv.co.yu/mpgscript/mpeghdr.htm for how to interpret
154 self.modeExtension = None
156 if header_data:
157 self.decode(header_data)
159 # This may throw an Mp3Exception if the header is malformed.
160 def decode(self, header):
161 if not is_valid_mp_header(header):
162 raise Mp3Exception("Invalid MPEG header");
164 # MPEG audio version from bits 19 and 20.
165 version = (header >> 19) & 0x3
166 self.version = [2.5, None, 2.0, 1.0][version]
167 if self.version is None:
168 raise Mp3Exception("Illegal MPEG version");
170 # MPEG layer
171 self.layer = 4 - ((header >> 17) & 0x3)
172 if self.layer == 4:
173 raise Mp3Exception("Illegal MPEG layer");
175 # Decode some simple values.
176 self.errorProtection = not (header >> 16) & 0x1;
177 self.padding = (header >> 9) & 0x1;
178 self.privateBit = (header >> 8) & 0x1;
179 self.copyright = (header >> 3) & 0x1;
180 self.original = (header >> 2) & 0x1;
182 # Obtain sampling frequency.
183 sampleBits = (header >> 10) & 0x3;
184 if self.version == 2.5:
185 freqCol = 2;
186 else:
187 freqCol = int(self.version - 1);
188 self.sampleFreq = SAMPLE_FREQ_TABLE[sampleBits][freqCol];
189 if not self.sampleFreq:
190 raise Mp3Exception("Illegal MPEG sampling frequency");
192 # Compute bitrate.
193 bitRateIndex = (header >> 12) & 0xf;
194 if int(self.version) == 1 and self.layer == 1:
195 bitRateCol = 0;
196 elif int(self.version) == 1 and self.layer == 2:
197 bitRateCol = 1;
198 elif int(self.version) == 1 and self.layer == 3:
199 bitRateCol = 2;
200 elif int(self.version) == 2 and self.layer == 1:
201 bitRateCol = 3;
202 elif int(self.version) == 2 and (self.layer == 2 or \
203 self.layer == 3):
204 bitRateCol = 4;
205 else:
206 raise Mp3Exception("Mp3 version %f and layer %d is an invalid "\
207 "combination" % (self.version, self.layer));
208 self.bitRate = BIT_RATE_TABLE[bitRateIndex][bitRateCol];
209 if self.bitRate == None:
210 raise Mp3Exception("Invalid bit rate");
211 # We know know the bit rate specified in this frame, but if the file
212 # is VBR we need to obtain the average from the Xing header.
213 # This is done by the caller since right now all we have is the frame
214 # header.
216 # Emphasis; whatever that means??
217 emph = header & 0x3;
218 if emph == 0:
219 self.emphasis = EMPHASIS_NONE;
220 elif emph == 1:
221 self.emphasis = EMPHASIS_5015;
222 elif emph == 2:
223 self.emphasis = EMPHASIS_CCIT;
224 elif strictID3():
225 raise Mp3Exception("Illegal mp3 emphasis value: %d" % emph);
227 # Channel mode.
228 modeBits = (header >> 6) & 0x3;
229 if modeBits == 0:
230 self.mode = MODE_STEREO;
231 elif modeBits == 1:
232 self.mode = MODE_JOINT_STEREO;
233 elif modeBits == 2:
234 self.mode = MODE_DUAL_CHANNEL_STEREO;
235 else:
236 self.mode = MODE_MONO;
237 self.modeExtension = (header >> 4) & 0x3;
239 # Layer II has restrictions wrt to mode and bit rate. This code
240 # enforces them.
241 if self.layer == 2:
242 m = self.mode;
243 br = self.bitRate;
244 if (br == 32 or br == 48 or br == 56 or br == 80) and \
245 (m != MODE_MONO):
246 raise Mp3Exception("Invalid mode/bitrate combination for layer "\
247 "II");
248 if (br == 224 or br == 256 or br == 320 or br == 384) and \
249 (m == MODE_MONO):
250 raise Mp3Exception("Invalid mode/bitrate combination for layer "\
251 "II");
253 br = self.bitRate * 1000;
254 sf = self.sampleFreq;
255 p = self.padding;
256 if self.layer == 1:
257 # Layer 1 uses 32 bit slots for padding.
258 p = self.padding * 4;
259 self.frameLength = int((((12 * br) / sf) + p) * 4);
260 else:
261 # Layer 2 and 3 uses 8 bit slots for padding.
262 p = self.padding * 1;
263 self.frameLength = int(((144 * br) / sf) + p);
265 # Dump the state.
266 TRACE_MSG("MPEG audio version: " + str(self.version));
267 TRACE_MSG("MPEG audio layer: " + ("I" * self.layer));
268 TRACE_MSG("MPEG sampling frequency: " + str(self.sampleFreq));
269 TRACE_MSG("MPEG bit rate: " + str(self.bitRate));
270 TRACE_MSG("MPEG channel mode: " + self.mode);
271 TRACE_MSG("MPEG channel mode extension: " + str(self.modeExtension));
272 TRACE_MSG("MPEG CRC error protection: " + str(self.errorProtection));
273 TRACE_MSG("MPEG original: " + str(self.original));
274 TRACE_MSG("MPEG copyright: " + str(self.copyright));
275 TRACE_MSG("MPEG private bit: " + str(self.privateBit));
276 TRACE_MSG("MPEG padding: " + str(self.padding));
277 TRACE_MSG("MPEG emphasis: " + str(self.emphasis));
278 TRACE_MSG("MPEG frame length: " + str(self.frameLength));
280 #######################################################################
281 class XingHeader:
282 numFrames = int();
283 numBytes = int();
284 toc = [0] * 100;
285 vbrScale = int();
287 # Pass in the first mp3 frame from the file as a byte string.
288 # If an Xing header is present in the file it'll be in the first mp3
289 # frame. This method returns true if the Xing header is found in the
290 # frame, and false otherwise.
291 def decode(self, frame):
292 # mp3 version
293 version = (ord(frame[1]) >> 3) & 0x1;
294 # channel mode.
295 mode = (ord(frame[3]) >> 6) & 0x3;
297 # Find the start of the Xing header.
298 if version:
299 if mode != 3:
300 pos = 32 + 4;
301 else:
302 pos = 17 + 4;
303 else:
304 if mode != 3:
305 pos = 17 + 4;
306 else:
307 pos = 9 + 4;
308 head = frame[pos:pos+4]
309 self.vbr = (head == 'Xing') and True or False
310 if head not in ['Xing', 'Info']:
311 return 0
312 TRACE_MSG("%s header detected @ %x" % (head, pos));
313 pos += 4;
315 # Read Xing flags.
316 headFlags = bin2dec(bytes2bin(frame[pos:pos + 4]));
317 pos += 4;
318 TRACE_MSG("%s header flags: 0x%x" % (head, headFlags));
320 # Read frames header flag and value if present
321 if headFlags & FRAMES_FLAG:
322 self.numFrames = bin2dec(bytes2bin(frame[pos:pos + 4]));
323 pos += 4;
324 TRACE_MSG("%s numFrames: %d" % (head, self.numFrames));
326 # Read bytes header flag and value if present
327 if headFlags & BYTES_FLAG:
328 self.numBytes = bin2dec(bytes2bin(frame[pos:pos + 4]));
329 pos += 4;
330 TRACE_MSG("%s numBytes: %d" % (head, self.numBytes));
332 # Read TOC header flag and value if present
333 if headFlags & TOC_FLAG:
334 i = 0;
335 self.toc = frame[pos:pos + 100];
336 pos += 100;
337 TRACE_MSG("%s TOC (100 bytes): PRESENT" % head);
338 else:
339 TRACE_MSG("%s TOC (100 bytes): NOT PRESENT" % head);
341 # Read vbr scale header flag and value if present
342 if headFlags & VBR_SCALE_FLAG and head == 'Xing':
343 self.vbrScale = bin2dec(bytes2bin(frame[pos:pos + 4]));
344 pos += 4;
345 TRACE_MSG("%s vbrScale: %d" % (head, self.vbrScale));
347 return 1;
349 #######################################################################
350 class LameTag(dict):
351 """Mp3 Info tag (AKA LAME Tag)
353 Lame (and some other encoders) write a tag containing various bits of info
354 about the options used at encode time. If available, the following are
355 parsed and stored in the LameTag dict:
357 encoder_version: short encoder version [str]
358 tag_revision: revision number of the tag [int]
359 vbr_method: VBR method used for encoding [str]
360 lowpass_filter: lowpass filter frequency in Hz [int]
361 replaygain: if available, radio and audiofile gain (see below) [dict]
362 encoding_flags: encoding flags used [list]
363 nogap: location of gaps when --nogap was used [list]
364 ath_type: ATH type [int]
365 bitrate: bitrate and type (Constant, Target, Minimum) [tuple]
366 encoder_delay: samples added at the start of the mp3 [int]
367 encoder_padding: samples added at the end of the mp3 [int]
368 noise_shaping: noise shaping method [int]
369 stereo_mode: stereo mode used [str]
370 unwise_settings: whether unwise settings were used [boolean]
371 sample_freq: source sample frequency [str]
372 mp3_gain: mp3 gain adjustment (rarely used) [float]
373 preset: preset used [str]
374 surround_info: surround information [str]
375 music_length: length in bytes of original mp3 [int]
376 music_crc: CRC-16 of the mp3 music data [int]
377 infotag_crc: CRC-16 of the info tag [int]
379 Prior to ~3.90, Lame simply stored the encoder version in the first frame.
380 If the infotag_crc is invalid, then we try to read this version string. A
381 simple way to tell if the LAME Tag is complete is to check for the
382 infotag_crc key.
384 Replay Gain data is only available since Lame version 3.94b. If set, the
385 replaygain dict has the following structure:
387 peak_amplitude: peak signal amplitude [float]
388 radio:
389 name: name of the gain adjustment [str]
390 adjustment: gain adjustment [float]
391 originator: originator of the gain adjustment [str]
392 audiofile: [same as radio]
394 Note that as of 3.95.1, Lame uses 89dB as a reference level instead of the
395 83dB that is specified in the Replay Gain spec. This is not automatically
396 compensated for. You can do something like this if you want:
398 import eyeD3
399 af = eyeD3.Mp3AudioFile('/path/to/some.mp3')
400 lamever = af.lameTag['encoder_version']
401 name, ver = lamever[:4], lamever[4:]
402 gain = af.lameTag['replaygain']['radio']['adjustment']
403 if name == 'LAME' and eyeD3.mp3.lamevercmp(ver, '3.95') > 0:
404 gain -= 6
406 Radio and Audiofile Replay Gain are often referrered to as Track and Album
407 gain, respectively. See http://replaygain.hydrogenaudio.org/ for futher
408 details on Replay Gain.
410 See http://gabriel.mp3-tech.org/mp3infotag.html for the gory details of the
411 LAME Tag.
414 # from the LAME source:
415 # http://lame.cvs.sourceforge.net/*checkout*/lame/lame/libmp3lame/VbrTag.c
416 _crc16_table = [
417 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
418 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
419 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
420 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
421 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
422 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
423 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
424 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
425 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
426 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
427 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
428 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
429 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
430 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
431 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
432 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
433 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
434 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
435 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
436 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
437 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
438 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
439 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
440 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
441 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
442 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
443 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
444 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
445 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
446 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
447 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
448 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040]
450 ENCODER_FLAGS = {
451 'NSPSYTUNE' : 0x0001,
452 'NSSAFEJOINT' : 0x0002,
453 'NOGAP_NEXT' : 0x0004,
454 'NOGAP_PREV' : 0x0008,}
456 PRESETS = {
457 0: 'Unknown',
458 # 8 to 320 are reserved for ABR bitrates
459 410: 'V9',
460 420: 'V8',
461 430: 'V7',
462 440: 'V6',
463 450: 'V5',
464 460: 'V4',
465 470: 'V3',
466 480: 'V2',
467 490: 'V1',
468 500: 'V0',
469 1000: 'r3mix',
470 1001: 'standard',
471 1002: 'extreme',
472 1003: 'insane',
473 1004: 'standard/fast',
474 1005: 'extreme/fast',
475 1006: 'medium',
476 1007: 'medium/fast',}
478 REPLAYGAIN_NAME = {
479 0: 'Not set',
480 1: 'Radio',
481 2: 'Audiofile',}
483 REPLAYGAIN_ORIGINATOR = {
484 0: 'Not set',
485 1: 'Set by artist',
486 2: 'Set by user',
487 3: 'Set automatically',
488 100: 'Set by simple RMS average',}
490 SAMPLE_FREQUENCIES = {
491 0: '<= 32 kHz',
492 1: '44.1 kHz',
493 2: '48 kHz',
494 3: '> 48 kHz',}
496 STEREO_MODES = {
497 0: 'Mono',
498 1: 'Stereo',
499 2: 'Dual',
500 3: 'Joint',
501 4: 'Force',
502 5: 'Auto',
503 6: 'Intensity',
504 7: 'Undefined',}
506 SURROUND_INFO = {
507 0: 'None',
508 1: 'DPL encoding',
509 2: 'DPL2 encoding',
510 3: 'Ambisonic encoding',
511 8: 'Reserved',}
513 VBR_METHODS = {
514 0: 'Unknown',
515 1: 'Constant Bitrate',
516 2: 'Average Bitrate',
517 3: 'Variable Bitrate method1 (old/rh)',
518 4: 'Variable Bitrate method2 (mtrh)',
519 5: 'Variable Bitrate method3 (mt)',
520 6: 'Variable Bitrate method4',
521 8: 'Constant Bitrate (2 pass)',
522 9: 'Average Bitrate (2 pass)',
523 15: 'Reserved',}
525 def __init__(self, frame):
526 """Read the LAME info tag.
528 frame should be the first frame of an mp3.
530 self.decode(frame)
532 def _crc16(self, data, val = 0):
533 """Compute a CRC-16 checksum on a data stream."""
534 for c in data:
535 val = self._crc16_table[ord(c) ^ (val & 0xff)] ^ (val >> 8)
536 return val
538 def decode(self, frame):
539 """Decode the LAME info tag."""
540 try: pos = frame.index("LAME")
541 except: return
543 # check the info tag crc. if it's not valid, no point parsing much more.
544 lamecrc = bin2dec(bytes2bin(frame[190:192]))
545 if self._crc16(frame[:190]) != lamecrc:
546 #TRACE_MSG('Lame tag CRC check failed')
547 # read version string from the first 30 bytes, up to any
548 # non-ascii chars, then strip padding chars.
550 # XXX (How many bytes is proper to read? madplay reads 20, but I've
551 # got files with longer version strings)
552 lamever = []
553 for c in frame[pos:pos + 30]:
554 if ord(c) not in range(32, 127):
555 break
556 lamever.append(c)
557 self['encoder_version'] = ''.join(lamever).rstrip('\x55')
558 TRACE_MSG('Lame Encoder Version: %s' % self['encoder_version'])
559 return
561 TRACE_MSG('Lame info tag found at position %d' % pos)
563 # Encoder short VersionString, 9 bytes
564 self['encoder_version'] = lamever = frame[pos:pos + 9].rstrip()
565 TRACE_MSG('Lame Encoder Version: %s' % self['encoder_version'])
566 pos += 9
568 # Info Tag revision + VBR method, 1 byte
569 self['tag_revision'] = bin2dec(bytes2bin(frame[pos:pos + 1])[:5])
570 vbr_method = bin2dec(bytes2bin(frame[pos:pos + 1])[5:])
571 self['vbr_method'] = self.VBR_METHODS.get(vbr_method, 'Unknown')
572 TRACE_MSG('Lame info tag version: %s' % self['tag_revision'])
573 TRACE_MSG('Lame VBR method: %s' % self['vbr_method'])
574 pos += 1
576 # Lowpass filter value, 1 byte
577 self['lowpass_filter'] = bin2dec(bytes2bin(frame[pos:pos + 1])) * 100
578 TRACE_MSG('Lame Lowpass filter value: %s Hz' % self['lowpass_filter'])
579 pos += 1
581 # Replay Gain, 8 bytes total
582 replaygain = {}
584 # Peak signal amplitude, 4 bytes
585 peak = bin2dec(bytes2bin(frame[pos:pos + 4])) << 5
586 if peak > 0:
587 peak /= float(1 << 28)
588 db = 20 * log10(peak)
589 replaygain['peak_amplitude'] = peak
590 TRACE_MSG('Lame Peak signal amplitude: %.8f (%+.1f dB)' % (peak, db))
591 pos += 4
593 # Radio and Audiofile Gain, AKA track and album, 2 bytes each
594 for gaintype in ['radio', 'audiofile']:
595 name = bin2dec(bytes2bin(frame[pos:pos + 2])[:3])
596 orig = bin2dec(bytes2bin(frame[pos:pos + 2])[3:6])
597 sign = bin2dec(bytes2bin(frame[pos:pos + 2])[6:7])
598 adj = bin2dec(bytes2bin(frame[pos:pos + 2])[7:]) / 10.0
599 if sign:
600 adj *= -1
601 # XXX Lame 3.95.1 and above use 89dB as a reference instead of 83dB
602 # as defined by the Replay Gain spec. Should this be compensated for?
603 #if lamever[:4] == 'LAME' and lamevercmp(lamever[4:], '3.95') > 0:
604 # adj -= 6
605 if orig:
606 name = self.REPLAYGAIN_NAME.get(name, 'Unknown')
607 orig = self.REPLAYGAIN_ORIGINATOR.get(orig, 'Unknown')
608 replaygain[gaintype] = {'name': name, 'adjustment': adj,
609 'originator': orig}
610 TRACE_MSG('Lame %s Replay Gain: %s dB (%s)' % (name, adj, orig))
611 pos += 2
612 if replaygain:
613 self['replaygain'] = replaygain
615 # Encoding flags + ATH Type, 1 byte
616 encflags = bin2dec(bytes2bin(frame[pos:pos + 1])[:4])
617 self['encoding_flags'], self['nogap'] = self._parse_encflags(encflags)
618 self['ath_type'] = bin2dec(bytes2bin(frame[pos:pos + 1])[4:])
619 TRACE_MSG('Lame Encoding flags: %s' % ' '.join(self['encoding_flags']))
620 if self['nogap']:
621 TRACE_MSG('Lame No gap: %s' % ' and '.join(self['nogap']))
622 TRACE_MSG('Lame ATH type: %s' % self['ath_type'])
623 pos += 1
625 # if ABR {specified bitrate} else {minimal bitrate}, 1 byte
626 btype = 'Constant'
627 if 'Average' in self['vbr_method']:
628 btype = 'Target'
629 elif 'Variable' in self['vbr_method']:
630 btype = 'Minimum'
631 # bitrate may be modified below after preset is read
632 self['bitrate'] = (bin2dec(bytes2bin(frame[pos:pos + 1])), btype)
633 TRACE_MSG('Lame Bitrate (%s): %s' % (btype, self['bitrate'][0]))
634 pos += 1
636 # Encoder delays, 3 bytes
637 self['encoder_delay'] = bin2dec(bytes2bin(frame[pos:pos + 3])[:12])
638 self['encoder_padding'] = bin2dec(bytes2bin(frame[pos:pos + 3])[12:])
639 TRACE_MSG('Lame Encoder delay: %s samples' % self['encoder_delay'])
640 TRACE_MSG('Lame Encoder padding: %s samples' % self['encoder_padding'])
641 pos += 3
643 # Misc, 1 byte
644 sample_freq = bin2dec(bytes2bin(frame[pos:pos + 1])[:2])
645 unwise_settings = bin2dec(bytes2bin(frame[pos:pos + 1])[2:3])
646 stereo_mode = bin2dec(bytes2bin(frame[pos:pos + 1])[3:6])
647 self['noise_shaping'] = bin2dec(bytes2bin(frame[pos:pos + 1])[6:])
648 self['sample_freq'] = self.SAMPLE_FREQUENCIES.get(sample_freq, 'Unknown')
649 self['unwise_settings'] = bool(unwise_settings)
650 self['stereo_mode'] = self.STEREO_MODES.get(stereo_mode, 'Unknown')
651 TRACE_MSG('Lame Source Sample Frequency: %s' % self['sample_freq'])
652 TRACE_MSG('Lame Unwise settings used: %s' % self['unwise_settings'])
653 TRACE_MSG('Lame Stereo mode: %s' % self['stereo_mode'])
654 TRACE_MSG('Lame Noise Shaping: %s' % self['noise_shaping'])
655 pos += 1
657 # MP3 Gain, 1 byte
658 sign = bytes2bin(frame[pos:pos + 1])[0]
659 gain = bin2dec(bytes2bin(frame[pos:pos + 1])[1:])
660 if sign:
661 gain *= -1
662 self['mp3_gain'] = gain
663 db = gain * 1.5
664 TRACE_MSG('Lame MP3 Gain: %s (%+.1f dB)' % (self['mp3_gain'], db))
665 pos += 1
667 # Preset and surround info, 2 bytes
668 surround = bin2dec(bytes2bin(frame[pos:pos + 2])[2:5])
669 preset = bin2dec(bytes2bin(frame[pos:pos + 2])[5:])
670 if preset in range(8, 321):
671 if self['bitrate'] >= 255:
672 # the value from preset is better in this case
673 self['bitrate'] = (preset, btype)
674 TRACE_MSG('Lame Bitrate (%s): %s' % (btype, self['bitrate'][0]))
675 if 'Average' in self['vbr_method']:
676 preset = 'ABR %s' % preset
677 else:
678 preset = 'CBR %s' % preset
679 else:
680 preset = self.PRESETS.get(preset, preset)
681 self['surround_info'] = self.SURROUND_INFO.get(surround, surround)
682 self['preset'] = preset
683 TRACE_MSG('Lame Surround Info: %s' % self['surround_info'])
684 TRACE_MSG('Lame Preset: %s' % self['preset'])
685 pos += 2
687 # MusicLength, 4 bytes
688 self['music_length'] = bin2dec(bytes2bin(frame[pos:pos + 4]))
689 TRACE_MSG('Lame Music Length: %s bytes' % self['music_length'])
690 pos += 4
692 # MusicCRC, 2 bytes
693 self['music_crc'] = bin2dec(bytes2bin(frame[pos:pos + 2]))
694 TRACE_MSG('Lame Music CRC: %04X' % self['music_crc'])
695 pos += 2
697 # CRC-16 of Info Tag, 2 bytes
698 self['infotag_crc'] = lamecrc # we read this earlier
699 TRACE_MSG('Lame Info Tag CRC: %04X' % self['infotag_crc'])
700 pos += 2
702 def _parse_encflags(self, flags):
703 """Parse encoder flags.
705 Returns a tuple containing lists of encoder flags and nogap data in
706 human readable format.
709 encoder_flags, nogap = [], []
711 if not flags:
712 return encoder_flags, nogap
714 if flags & self.ENCODER_FLAGS['NSPSYTUNE']:
715 encoder_flags.append('--nspsytune')
716 if flags & self.ENCODER_FLAGS['NSSAFEJOINT']:
717 encoder_flags.append('--nssafejoint')
719 NEXT = self.ENCODER_FLAGS['NOGAP_NEXT']
720 PREV = self.ENCODER_FLAGS['NOGAP_PREV']
721 if flags & (NEXT | PREV):
722 encoder_flags.append('--nogap')
723 if flags & PREV:
724 nogap.append('before')
725 if flags & NEXT:
726 nogap.append('after')
727 return encoder_flags, nogap
729 def lamevercmp(x, y):
730 """Compare LAME version strings.
732 alpha and beta versions are considered older.
733 versions with sub minor parts or end with 'r' are considered newer.
735 Return negative if x<y, zero if x==y, positive if x>y.
738 x = x.ljust(5)
739 y = y.ljust(5)
740 if x[:5] == y[:5]: return 0
741 ret = cmp(x[:4], y[:4])
742 if ret: return ret
743 xmaj, xmin = x.split('.')[:2]
744 ymaj, ymin = y.split('.')[:2]
745 minparts = ['.']
746 # lame 3.96.1 added the use of r in the very short version for post releases
747 if (xmaj == '3' and xmin >= '96') or (ymaj == '3' and ymin >= '96'):
748 minparts.append('r')
749 if x[4] in minparts: return 1
750 if y[4] in minparts: return -1
751 if x[4] == ' ': return 1
752 if y[4] == ' ': return -1
753 return cmp(x[4], y[4])