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 *;
21 from math
import log10
23 #######################################################################
24 class Mp3Exception(Exception):
25 '''Error reading mp3'''
29 SAMPLE_FREQ_TABLE
= ((44100, 22050, 11025),
30 (48000, 24000, 12000),
34 # V1/L1 V1/L2 V1/L3 V2/L1 V2/L2&L3
35 BIT_RATE_TABLE
= ((0, 0, 0, 0, 0),
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));
53 TIME_PER_FRAME_TABLE
= (None, 384, 1152, 1152);
56 EMPHASIS_NONE
= "None";
57 EMPHASIS_5015
= "50/15 ms";
58 EMPHASIS_CCIT
= "CCIT J.17";
61 MODE_STEREO
= "Stereo";
62 MODE_JOINT_STEREO
= "Joint stereo";
63 MODE_DUAL_CHANNEL_STEREO
= "Dual channel stereo";
70 VBR_SCALE_FLAG
= 0x0008
72 #######################################################################
73 # Pass in a 4 byte integer to determine if it matches a valid mp3 frame
75 def is_valid_mp_header(header
):
76 # Test for the mp3 frame sync: 11 set bits.
78 if sync
& 0xFFE0 != 0xFFE0:
79 # ffe0 is 11 sync bits, and supports identifying mpeg v2.5
82 version
= (header
>> 19) & 0x3
84 # This is a "reserved" version
85 TRACE_MSG("invalid mpeg version")
88 layer
= (header
>> 17) & 0x3
90 # This is a "reserved" layer
91 TRACE_MSG("invalid mpeg layer")
94 bitrate
= (header
>> 12) & 0xf
95 if bitrate
in (0, 0xf):
96 # free and bad bitrate values
97 TRACE_MSG("invalid mpeg bitrate")
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")
108 def find_header(fp
, start_pos
=0):
109 def find_sync(fp
, start_pos
=0):
113 data
= fp
.read(CHUNK_SIZE
)
117 sync_pos
= data
.find('\xff', 0)
119 header
= data
[sync_pos
:sync_pos
+ 4]
121 return (start_pos
+ sync_pos
, header
)
122 data
= fp
.read(CHUNK_SIZE
)
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 #######################################################################
139 def __init__(self
, header_data
=None):
142 self
.errorProtection
= None
145 self
.sampleFreq
= None
147 self
.privateBit
= None
148 self
.copyright
= 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
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");
171 self
.layer
= 4 - ((header
>> 17) & 0x3)
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:
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");
193 bitRateIndex
= (header
>> 12) & 0xf;
194 if int(self
.version
) == 1 and self
.layer
== 1:
196 elif int(self
.version
) == 1 and self
.layer
== 2:
198 elif int(self
.version
) == 1 and self
.layer
== 3:
200 elif int(self
.version
) == 2 and self
.layer
== 1:
202 elif int(self
.version
) == 2 and (self
.layer
== 2 or \
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
216 # Emphasis; whatever that means??
219 self
.emphasis
= EMPHASIS_NONE
;
221 self
.emphasis
= EMPHASIS_5015
;
223 self
.emphasis
= EMPHASIS_CCIT
;
225 raise Mp3Exception("Illegal mp3 emphasis value: %d" % emph
);
228 modeBits
= (header
>> 6) & 0x3;
230 self
.mode
= MODE_STEREO
;
232 self
.mode
= MODE_JOINT_STEREO
;
234 self
.mode
= MODE_DUAL_CHANNEL_STEREO
;
236 self
.mode
= MODE_MONO
;
237 self
.modeExtension
= (header
>> 4) & 0x3;
239 # Layer II has restrictions wrt to mode and bit rate. This code
244 if (br
== 32 or br
== 48 or br
== 56 or br
== 80) and \
246 raise Mp3Exception("Invalid mode/bitrate combination for layer "\
248 if (br
== 224 or br
== 256 or br
== 320 or br
== 384) and \
250 raise Mp3Exception("Invalid mode/bitrate combination for layer "\
253 br
= self
.bitRate
* 1000;
254 sf
= self
.sampleFreq
;
257 # Layer 1 uses 32 bit slots for padding.
258 p
= self
.padding
* 4;
259 self
.frameLength
= int((((12 * br
) / sf
) + p
) * 4);
261 # Layer 2 and 3 uses 8 bit slots for padding.
262 p
= self
.padding
* 1;
263 self
.frameLength
= int(((144 * br
) / sf
) + p
);
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 #######################################################################
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
):
293 version
= (ord(frame
[1]) >> 3) & 0x1;
295 mode
= (ord(frame
[3]) >> 6) & 0x3;
297 # Find the start of the Xing header.
308 head
= frame
[pos
:pos
+4]
309 self
.vbr
= (head
== 'Xing') and True or False
310 if head
not in ['Xing', 'Info']:
312 TRACE_MSG("%s header detected @ %x" % (head
, pos
));
316 headFlags
= bin2dec(bytes2bin(frame
[pos
: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]));
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]));
330 TRACE_MSG("%s numBytes: %d" % (head
, self
.numBytes
));
332 # Read TOC header flag and value if present
333 if headFlags
& TOC_FLAG
:
335 self
.toc
= frame
[pos
:pos
+ 100];
337 TRACE_MSG("%s TOC (100 bytes): PRESENT" % head
);
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]));
345 TRACE_MSG("%s vbrScale: %d" % (head
, self
.vbrScale
));
349 #######################################################################
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
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]
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:
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:
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
414 # from the LAME source:
415 # http://lame.cvs.sourceforge.net/*checkout*/lame/lame/libmp3lame/VbrTag.c
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]
451 'NSPSYTUNE' : 0x0001,
452 'NSSAFEJOINT' : 0x0002,
453 'NOGAP_NEXT' : 0x0004,
454 'NOGAP_PREV' : 0x0008,}
458 # 8 to 320 are reserved for ABR bitrates
473 1004: 'standard/fast',
474 1005: 'extreme/fast',
476 1007: 'medium/fast',}
483 REPLAYGAIN_ORIGINATOR
= {
487 3: 'Set automatically',
488 100: 'Set by simple RMS average',}
490 SAMPLE_FREQUENCIES
= {
510 3: 'Ambisonic encoding',
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)',
525 def __init__(self
, frame
):
526 """Read the LAME info tag.
528 frame should be the first frame of an mp3.
532 def _crc16(self
, data
, val
= 0):
533 """Compute a CRC-16 checksum on a data stream."""
535 val
= self
._crc
16_table
[ord(c
) ^
(val
& 0xff)] ^
(val
>> 8)
538 def decode(self
, frame
):
539 """Decode the LAME info tag."""
540 try: pos
= frame
.index("LAME")
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
._crc
16(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)
553 for c
in frame
[pos
:pos
+ 30]:
554 if ord(c
) not in range(32, 127):
557 self
['encoder_version'] = ''.join(lamever
).rstrip('\x55')
558 TRACE_MSG('Lame Encoder Version: %s' % self
['encoder_version'])
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'])
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'])
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'])
581 # Replay Gain, 8 bytes total
584 # Peak signal amplitude, 4 bytes
585 peak
= bin2dec(bytes2bin(frame
[pos
:pos
+ 4])) << 5
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
))
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
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:
606 name
= self
.REPLAYGAIN_NAME
.get(name
, 'Unknown')
607 orig
= self
.REPLAYGAIN_ORIGINATOR
.get(orig
, 'Unknown')
608 replaygain
[gaintype
] = {'name': name
, 'adjustment': adj
,
610 TRACE_MSG('Lame %s Replay Gain: %s dB (%s)' % (name
, adj
, orig
))
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']))
621 TRACE_MSG('Lame No gap: %s' % ' and '.join(self
['nogap']))
622 TRACE_MSG('Lame ATH type: %s' % self
['ath_type'])
625 # if ABR {specified bitrate} else {minimal bitrate}, 1 byte
627 if 'Average' in self
['vbr_method']:
629 elif 'Variable' in self
['vbr_method']:
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]))
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'])
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'])
658 sign
= bytes2bin(frame
[pos
:pos
+ 1])[0]
659 gain
= bin2dec(bytes2bin(frame
[pos
:pos
+ 1])[1:])
662 self
['mp3_gain'] = gain
664 TRACE_MSG('Lame MP3 Gain: %s (%+.1f dB)' % (self
['mp3_gain'], db
))
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
678 preset
= 'CBR %s' % preset
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'])
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'])
693 self
['music_crc'] = bin2dec(bytes2bin(frame
[pos
:pos
+ 2]))
694 TRACE_MSG('Lame Music CRC: %04X' % self
['music_crc'])
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'])
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
= [], []
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')
724 nogap
.append('before')
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.
740 if x
[:5] == y
[:5]: return 0
741 ret
= cmp(x
[:4], y
[:4])
743 xmaj
, xmin
= x
.split('.')[:2]
744 ymaj
, ymin
= y
.split('.')[:2]
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'):
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])