Using FS mtime to reload non recursive cache.
[pyTivo.git] / eyeD3 / mp3.py
blobef26cd90281b39ae8c972bac1d4878d683c2eb76
1 ################################################################################
3 # Copyright (C) 2002-2005 Travis Shirk <travis@pobox.com>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ################################################################################
20 from binfuncs import *;
21 from utils import *;
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 # Flag bits
67 FRAMES_FLAG = 0x0001
68 BYTES_FLAG = 0x0002
69 TOC_FLAG = 0x0004
70 VBR_SCALE_FLAG = 0x0008
72 #######################################################################
73 def computeTimePerFrame(frameHeader):
74 tpf = TIME_PER_FRAME_TABLE[frameHeader.layer];
75 tpf = float(tpf) / float(frameHeader.sampleFreq);
76 return tpf;
78 #######################################################################
79 class Header:
80 version = float();
81 layer = int();
82 errorProtection = 0;
83 bitRate = int();
84 playTime = long();
85 sampleFreq = int();
86 padding = 0;
87 privateBit = 0;
88 copyright = 0;
89 original = 0;
90 emphasis = str();
91 mode = str();
92 # This value is left as is: 0 <= modeExtension <= 3. Consult the
93 # mp3 spec here http://www.dv.co.yu/mpgscript/mpeghdr.htm if you wish to
94 # interpret it.
95 modeExtension = 0;
97 # Pass in a 4 byte integer to determine if it matches a valid mp3 frame
98 # header.
99 def isValid(self, header):
100 # Test for the mp3 frame sync: 11 set bits.
101 if (header & 0xffe00000L) != 0xffe00000L:
102 return 0;
103 if not ((header >> 17) & 3):
104 return 0;
105 if ((header >> 12) & 0xf) == 0xf:
106 return 0;
107 if not ((header >> 12) & 0xf):
108 return 0;
109 if ((header >> 10) & 0x3) == 0x3:
110 return 0;
111 if (((header >> 19) & 1) == 1) and (((header >> 17) & 3) == 3) and \
112 (((header >> 16) & 1) == 1):
113 return 0;
114 if (header & 0xffff0000L) == 0xfffe0000L:
115 return 0;
117 return 1;
119 # This may throw an Mp3Exception if the header is malformed.
120 def decode(self, header):
121 # MPEG audio version from bits 19 and 20.
122 if not header & (1 << 20) and header & (1 << 19):
123 raise Mp3Exception("Illegal MPEG audio version");
124 elif not header & (1 << 20) and not header & (1 << 19):
125 self.version = 2.5;
126 else:
127 if not header & (1 << 19):
128 self.version = 2.0;
129 else:
130 self.version = 1.0;
133 # MPEG audio layer from bits 18 and 17.
134 if not header & (1 << 18) and not header & (1 << 17):
135 raise Mp3Exception("Illegal MPEG layer value");
136 elif not header & (1 << 18) and header & (1 << 17):
137 self.layer = 3;
138 elif header & (1 << 18) and not header & (1 << 17):
139 self.layer = 2;
140 else:
141 self.layer = 1;
143 # Decode some simple values.
144 self.errorProtection = not (header >> 16) & 0x1;
145 self.padding = (header >> 9) & 0x1;
146 self.privateBit = (header >> 8) & 0x1;
147 self.copyright = (header >> 3) & 0x1;
148 self.original = (header >> 2) & 0x1;
150 # Obtain sampling frequency.
151 sampleBits = (header >> 10) & 0x3;
152 if self.version == 2.5:
153 freqCol = 2;
154 else:
155 freqCol = int(self.version - 1);
156 self.sampleFreq = SAMPLE_FREQ_TABLE[sampleBits][freqCol];
157 if not self.sampleFreq:
158 raise Mp3Exception("Illegal MPEG sampling frequency");
161 # Compute bitrate.
162 bitRateIndex = (header >> 12) & 0xf;
163 if int(self.version) == 1 and self.layer == 1:
164 bitRateCol = 0;
165 elif int(self.version) == 1 and self.layer == 2:
166 bitRateCol = 1;
167 elif int(self.version) == 1 and self.layer == 3:
168 bitRateCol = 2;
169 elif int(self.version) == 2 and self.layer == 1:
170 bitRateCol = 3;
171 elif int(self.version) == 2 and (self.layer == 2 or \
172 self.layer == 3):
173 bitRateCol = 4;
174 else:
175 raise Mp3Exception("Mp3 version %f and layer %d is an invalid "\
176 "combination" % (self.version, self.layer));
177 self.bitRate = BIT_RATE_TABLE[bitRateIndex][bitRateCol];
178 if self.bitRate == None:
179 raise Mp3Exception("Invalid bit rate");
180 # We know know the bit rate specified in this frame, but if the file
181 # is VBR we need to obtain the average from the Xing header.
182 # This is done by the caller since right now all we have is the frame
183 # header.
185 # Emphasis; whatever that means??
186 emph = header & 0x3;
187 if emph == 0:
188 self.emphasis = EMPHASIS_NONE;
189 elif emph == 1:
190 self.emphasis = EMPHASIS_5015;
191 elif emph == 2:
192 self.emphasis = EMPHASIS_CCIT;
193 elif strictID3():
194 raise Mp3Exception("Illegal mp3 emphasis value: %d" % emph);
196 # Channel mode.
197 modeBits = (header >> 6) & 0x3;
198 if modeBits == 0:
199 self.mode = MODE_STEREO;
200 elif modeBits == 1:
201 self.mode = MODE_JOINT_STEREO;
202 elif modeBits == 2:
203 self.mode = MODE_DUAL_CHANNEL_STEREO;
204 else:
205 self.mode = MODE_MONO;
206 self.modeExtension = (header >> 4) & 0x3;
208 # Layer II has restrictions wrt to mode and bit rate. This code
209 # enforces them.
210 if self.layer == 2:
211 m = self.mode;
212 br = self.bitRate;
213 if (br == 32 or br == 48 or br == 56 or br == 80) and \
214 (m != MODE_MONO):
215 raise Mp3Exception("Invalid mode/bitrate combination for layer "\
216 "II");
217 if (br == 224 or br == 256 or br == 320 or br == 384) and \
218 (m == MODE_MONO):
219 raise Mp3Exception("Invalid mode/bitrate combination for layer "\
220 "II");
222 br = self.bitRate * 1000;
223 sf = self.sampleFreq;
224 p = self.padding;
225 if self.layer == 1:
226 # Layer 1 uses 32 bit slots for padding.
227 p = self.padding * 4;
228 self.frameLength = int((((12 * br) / sf) + p) * 4);
229 else:
230 # Layer 2 and 3 uses 8 bit slots for padding.
231 p = self.padding * 1;
232 self.frameLength = int(((144 * br) / sf) + p);
234 # Dump the state.
235 TRACE_MSG("MPEG audio version: " + str(self.version));
236 TRACE_MSG("MPEG audio layer: " + ("I" * self.layer));
237 TRACE_MSG("MPEG sampling frequency: " + str(self.sampleFreq));
238 TRACE_MSG("MPEG bit rate: " + str(self.bitRate));
239 TRACE_MSG("MPEG channel mode: " + self.mode);
240 TRACE_MSG("MPEG channel mode extension: " + str(self.modeExtension));
241 TRACE_MSG("MPEG CRC error protection: " + str(self.errorProtection));
242 TRACE_MSG("MPEG original: " + str(self.original));
243 TRACE_MSG("MPEG copyright: " + str(self.copyright));
244 TRACE_MSG("MPEG private bit: " + str(self.privateBit));
245 TRACE_MSG("MPEG padding: " + str(self.padding));
246 TRACE_MSG("MPEG emphasis: " + str(self.emphasis));
247 TRACE_MSG("MPEG frame length: " + str(self.frameLength));
249 #######################################################################
250 class XingHeader:
251 numFrames = int();
252 numBytes = int();
253 toc = [0] * 100;
254 vbrScale = int();
256 # Pass in the first mp3 frame from the file as a byte string.
257 # If an Xing header is present in the file it'll be in the first mp3
258 # frame. This method returns true if the Xing header is found in the
259 # frame, and false otherwise.
260 def decode(self, frame):
261 # mp3 version
262 id = (ord(frame[1]) >> 3) & 0x1;
263 # channel mode.
264 mode = (ord(frame[3]) >> 6) & 0x3;
266 # Find the start of the Xing header.
267 if id:
268 if mode != 3:
269 pos = 32 + 4;
270 else:
271 pos = 17 + 4;
272 else:
273 if mode != 3:
274 pos = 17 + 4;
275 else:
276 pos = 9 + 4;
277 if frame[pos] != 'X' or frame[pos + 1] != 'i' or \
278 frame[pos + 2] != 'n' or frame[pos + 3] != 'g':
279 return 0;
280 TRACE_MSG("Xing header detected");
281 pos += 4;
283 # Read Xing flags.
284 headFlags = bin2dec(bytes2bin(frame[pos:pos + 4]));
285 pos += 4;
286 TRACE_MSG("Xing header flags: 0x%x" % headFlags);
288 # Read frames header flag and value if present
289 if headFlags & FRAMES_FLAG:
290 self.numFrames = bin2dec(bytes2bin(frame[pos:pos + 4]));
291 pos += 4;
292 TRACE_MSG("Xing numFrames: %d" % self.numFrames);
294 # Read bytes header flag and value if present
295 if headFlags & BYTES_FLAG:
296 self.numBytes = bin2dec(bytes2bin(frame[pos:pos + 4]));
297 pos += 4;
298 TRACE_MSG("Xing numBytes: %d" % self.numBytes);
300 # Read TOC header flag and value if present
301 if headFlags & TOC_FLAG:
302 i = 0;
303 self.toc = frame[pos:pos + 100];
304 pos += 100;
305 TRACE_MSG("Xing TOC (100 bytes): PRESENT");
306 else:
307 TRACE_MSG("Xing TOC (100 bytes): NOT PRESENT");
309 # Read vbr scale header flag and value if present
310 if headFlags & VBR_SCALE_FLAG:
311 self.vbrScale = bin2dec(bytes2bin(frame[pos:pos + 4]));
312 pos += 4;
313 TRACE_MSG("Xing vbrScale: %d" % self.vbrScale);
315 return 1;