Update of /cvsroot/freevo/kaa/metadata/src/audio/eyeD3
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14035/src/audio/eyeD3
Added Files:
.cvsignore __init__.py binfuncs.py frames.py mp3.py tag.py
utils.py
Log Message:
move current mmpython cvs to kaa.metadata
--- NEW FILE: .cvsignore ---
*.pyc *.pyo
--- NEW FILE: tag.py ---
###############################################################################
#
# Copyright (C) 2002-2005 Travis Shirk <[EMAIL PROTECTED]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
################################################################################
[...1755 lines suppressed...]
tune = "<tune xmlns='http://jabber.org/protocol/tune'>\n";
if tag.getArtist():
tune += " <artist>" + tag.getArtist() + "</artist>\n";
if tag.getTitle():
tune += " <title>" + tag.getTitle() + "</title>\n";
if tag.getAlbum():
tune += " <source>" + tag.getAlbum() + "</source>\n";
tune += " <track>" + "file://" + os.path.abspath(tag.linkedFile.name) +\
"</track>\n";
if audio_file:
tune += " <length>" + str(audio_file.getPlayTime()) + "</length>\n";
tune += "</tune>\n";
return tune;
#
# Module level globals.
#
genres = GenreMap();
--- NEW FILE: mp3.py ---
################################################################################
#
# Copyright (C) 2002-2005 Travis Shirk <[EMAIL PROTECTED]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
################################################################################
from binfuncs import *;
from utils import *;
#######################################################################
class Mp3Exception(Exception):
'''Error reading mp3'''
# MPEG1 MPEG2 MPEG2.5
SAMPLE_FREQ_TABLE = ((44100, 22050, 11025),
(48000, 24000, 12000),
(32000, 16000, 8000),
(None, None, None));
# V1/L1 V1/L2 V1/L3 V2/L1 V2/L2&L3
BIT_RATE_TABLE = ((0, 0, 0, 0, 0),
(32, 32, 32, 32, 8),
(64, 48, 40, 48, 16),
(96, 56, 48, 56, 24),
(128, 64, 56, 64, 32),
(160, 80, 64, 80, 40),
(192, 96, 80, 96, 44),
(224, 112, 96, 112, 56),
(256, 128, 112, 128, 64),
(288, 160, 128, 144, 80),
(320, 192, 160, 160, 96),
(352, 224, 192, 176, 112),
(384, 256, 224, 192, 128),
(416, 320, 256, 224, 144),
(448, 384, 320, 256, 160),
(None, None, None, None, None));
# L1 L2 L3
TIME_PER_FRAME_TABLE = (None, 384, 1152, 1152);
# Emphasis constants
EMPHASIS_NONE = "None";
EMPHASIS_5015 = "50/15 ms";
EMPHASIS_CCIT = "CCIT J.17";
# Mode constants
MODE_STEREO = "Stereo";
MODE_JOINT_STEREO = "Joint stereo";
MODE_DUAL_CHANNEL_STEREO = "Dual channel stereo";
MODE_MONO = "Mono";
# Flag bits
FRAMES_FLAG = 0x0001
BYTES_FLAG = 0x0002
TOC_FLAG = 0x0004
VBR_SCALE_FLAG = 0x0008
#######################################################################
def computeTimePerFrame(frameHeader):
tpf = TIME_PER_FRAME_TABLE[frameHeader.layer];
tpf = float(tpf) / float(frameHeader.sampleFreq);
return tpf;
#######################################################################
class Header:
version = float();
layer = int();
errorProtection = 0;
bitRate = int();
playTime = long();
sampleFreq = int();
padding = 0;
privateBit = 0;
copyright = 0;
original = 0;
emphasis = str();
mode = str();
# This value is left as is: 0 <= modeExtension <= 3. Consult the
# mp3 spec here http://www.dv.co.yu/mpgscript/mpeghdr.htm if you wish to
# interpret it.
modeExtension = 0;
# Pass in a 4 byte integer to determine if it matches a valid mp3 frame
# header.
def isValid(self, header):
# Test for the mp3 frame sync: 11 set bits.
if (header & 0xffe00000L) != 0xffe00000L:
return 0;
if not ((header >> 17) & 3):
return 0;
if ((header >> 12) & 0xf) == 0xf:
return 0;
if not ((header >> 12) & 0xf):
return 0;
if ((header >> 10) & 0x3) == 0x3:
return 0;
if (((header >> 19) & 1) == 1) and (((header >> 17) & 3) == 3) and \
(((header >> 16) & 1) == 1):
return 0;
if (header & 0xffff0000L) == 0xfffe0000L:
return 0;
return 1;
# This may throw an Mp3Exception if the header is malformed.
def decode(self, header):
# MPEG audio version from bits 19 and 20.
if not header & (1 << 20) and header & (1 << 19):
raise Mp3Exception("Illegal MPEG audio version");
elif not header & (1 << 20) and not header & (1 << 19):
self.version = 2.5;
else:
if not header & (1 << 19):
self.version = 2.0;
else:
self.version = 1.0;
# MPEG audio layer from bits 18 and 17.
if not header & (1 << 18) and not header & (1 << 17):
raise Mp3Exception("Illegal MPEG layer value");
elif not header & (1 << 18) and header & (1 << 17):
self.layer = 3;
elif header & (1 << 18) and not header & (1 << 17):
self.layer = 2;
else:
self.layer = 1;
# Decode some simple values.
self.errorProtection = not (header >> 16) & 0x1;
self.padding = (header >> 9) & 0x1;
self.privateBit = (header >> 8) & 0x1;
self.copyright = (header >> 3) & 0x1;
self.original = (header >> 2) & 0x1;
# Obtain sampling frequency.
sampleBits = (header >> 10) & 0x3;
if self.version == 2.5:
freqCol = 2;
else:
freqCol = int(self.version - 1);
self.sampleFreq = SAMPLE_FREQ_TABLE[sampleBits][freqCol];
if not self.sampleFreq:
raise Mp3Exception("Illegal MPEG sampling frequency");
# Compute bitrate.
bitRateIndex = (header >> 12) & 0xf;
if int(self.version) == 1 and self.layer == 1:
bitRateCol = 0;
elif int(self.version) == 1 and self.layer == 2:
bitRateCol = 1;
elif int(self.version) == 1 and self.layer == 3:
bitRateCol = 2;
elif int(self.version) == 2 and self.layer == 1:
bitRateCol = 3;
elif int(self.version) == 2 and (self.layer == 2 or \
self.layer == 3):
bitRateCol = 4;
else:
raise Mp3Exception("Mp3 version %f and layer %d is an invalid "\
"combination" % (self.version, self.layer));
self.bitRate = BIT_RATE_TABLE[bitRateIndex][bitRateCol];
if self.bitRate == None:
raise Mp3Exception("Invalid bit rate");
# We know know the bit rate specified in this frame, but if the file
# is VBR we need to obtain the average from the Xing header.
# This is done by the caller since right now all we have is the frame
# header.
# Emphasis; whatever that means??
emph = header & 0x3;
if emph == 0:
self.emphasis = EMPHASIS_NONE;
elif emph == 1:
self.emphasis = EMPHASIS_5015;
elif emph == 2:
self.emphasis = EMPHASIS_CCIT;
elif strictID3():
raise Mp3Exception("Illegal mp3 emphasis value: %d" % emph);
# Channel mode.
modeBits = (header >> 6) & 0x3;
if modeBits == 0:
self.mode = MODE_STEREO;
elif modeBits == 1:
self.mode = MODE_JOINT_STEREO;
elif modeBits == 2:
self.mode = MODE_DUAL_CHANNEL_STEREO;
else:
self.mode = MODE_MONO;
self.modeExtension = (header >> 4) & 0x3;
# Layer II has restrictions wrt to mode and bit rate. This code
# enforces them.
if self.layer == 2:
m = self.mode;
br = self.bitRate;
if (br == 32 or br == 48 or br == 56 or br == 80) and \
(m != MODE_MONO):
raise Mp3Exception("Invalid mode/bitrate combination for layer "\
"II");
if (br == 224 or br == 256 or br == 320 or br == 384) and \
(m == MODE_MONO):
raise Mp3Exception("Invalid mode/bitrate combination for layer "\
"II");
br = self.bitRate * 1000;
sf = self.sampleFreq;
p = self.padding;
if self.layer == 1:
# Layer 1 uses 32 bit slots for padding.
p = self.padding * 4;
self.frameLength = int((((12 * br) / sf) + p) * 4);
else:
# Layer 2 and 3 uses 8 bit slots for padding.
p = self.padding * 1;
self.frameLength = int(((144 * br) / sf) + p);
# Dump the state.
TRACE_MSG("MPEG audio version: " + str(self.version));
TRACE_MSG("MPEG audio layer: " + ("I" * self.layer));
TRACE_MSG("MPEG sampling frequency: " + str(self.sampleFreq));
TRACE_MSG("MPEG bit rate: " + str(self.bitRate));
TRACE_MSG("MPEG channel mode: " + self.mode);
TRACE_MSG("MPEG channel mode extension: " + str(self.modeExtension));
TRACE_MSG("MPEG CRC error protection: " + str(self.errorProtection));
TRACE_MSG("MPEG original: " + str(self.original));
TRACE_MSG("MPEG copyright: " + str(self.copyright));
TRACE_MSG("MPEG private bit: " + str(self.privateBit));
TRACE_MSG("MPEG padding: " + str(self.padding));
TRACE_MSG("MPEG emphasis: " + str(self.emphasis));
TRACE_MSG("MPEG frame length: " + str(self.frameLength));
#######################################################################
class XingHeader:
numFrames = int();
numBytes = int();
toc = [0] * 100;
vbrScale = int();
# Pass in the first mp3 frame from the file as a byte string.
# If an Xing header is present in the file it'll be in the first mp3
# frame. This method returns true if the Xing header is found in the
# frame, and false otherwise.
def decode(self, frame):
# mp3 version
id = (ord(frame[1]) >> 3) & 0x1;
# channel mode.
mode = (ord(frame[3]) >> 6) & 0x3;
# Find the start of the Xing header.
if id:
if mode != 3:
pos = 32 + 4;
else:
pos = 17 + 4;
else:
if mode != 3:
pos = 17 + 4;
else:
pos = 9 + 4;
if frame[pos] != 'X' or frame[pos + 1] != 'i' or \
frame[pos + 2] != 'n' or frame[pos + 3] != 'g':
return 0;
TRACE_MSG("Xing header detected");
pos += 4;
# Read Xing flags.
headFlags = bin2dec(bytes2bin(frame[pos:pos + 4]));
pos += 4;
TRACE_MSG("Xing header flags: 0x%x" % headFlags);
# Read frames header flag and value if present
if headFlags & FRAMES_FLAG:
self.numFrames = bin2dec(bytes2bin(frame[pos:pos + 4]));
pos += 4;
TRACE_MSG("Xing numFrames: %d" % self.numFrames);
# Read bytes header flag and value if present
if headFlags & BYTES_FLAG:
self.numBytes = bin2dec(bytes2bin(frame[pos:pos + 4]));
pos += 4;
TRACE_MSG("Xing numBytes: %d" % self.numBytes);
# Read TOC header flag and value if present
if headFlags & TOC_FLAG:
i = 0;
self.toc = frame[pos:pos + 100];
pos += 100;
TRACE_MSG("Xing TOC (100 bytes): PRESENT");
else:
TRACE_MSG("Xing TOC (100 bytes): NOT PRESENT");
# Read vbr scale header flag and value if present
if headFlags & VBR_SCALE_FLAG:
self.vbrScale = bin2dec(bytes2bin(frame[pos:pos + 4]));
pos += 4;
TRACE_MSG("Xing vbrScale: %d" % self.vbrScale);
return 1;
--- NEW FILE: frames.py ---
################################################################################
#
# Copyright (C) 2002-2005 Travis Shirk <[EMAIL PROTECTED]>
# Copyright (C) 2001 Ryan Finne <[EMAIL PROTECTED]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
[...1761 lines suppressed...]
# Play count
elif PLAYCOUNT_FRAME_RX.match(frameHeader.id):
f = PlayCountFrame(frameHeader, data = data);
# Unique file identifier
elif UNIQUE_FILE_ID_FRAME_RX.match(frameHeader.id):
f = UniqueFileIDFrame(frameHeader, data = data);
if f == None:
f = UnknownFrame(frameHeader, data);
return f;
def map2_2FrameId(originalId):
if not TAGS2_2_TO_TAGS_2_3_AND_4.has_key(originalId): return originalId
return TAGS2_2_TO_TAGS_2_3_AND_4[originalId]
--- NEW FILE: utils.py ---
################################################################################
# Copyright (C) 2003-2005 Travis Shirk <[EMAIL PROTECTED]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id: utils.py,v 1.1 2005/07/02 16:33:11 dischi Exp $
################################################################################
from kaa.metadata.audio.eyeD3 import *;
def versionsToConstant(v):
major = v[0];
minor = v[1];
rev = v[2];
if major == 1:
if minor == 0:
return ID3_V1_0;
elif minor == 1:
return ID3_V1_1;
elif major == 2:
if minor == 2:
return ID3_V2_2;
if minor == 3:
return ID3_V2_3;
elif minor == 4:
return ID3_V2_4;
raise str("Invalid ID3 version: %s" % str(v));
def versionToString(v):
if v & ID3_V1:
if v == ID3_V1_0:
return "v1.0";
elif v == ID3_V1_1:
return "v1.1";
elif v == ID3_V1:
return "v1.x";
elif v & ID3_V2:
if v == ID3_V2_2:
return "v2.2";
elif v == ID3_V2_3:
return "v2.3";
elif v == ID3_V2_4:
return "v2.4";
elif v == ID3_V2:
return "v2.x";
if v == ID3_ANY_VERSION:
return "v1.x/v2.x";
raise str("versionToString - Invalid ID3 version constant: %s" % hex(v));
def constantToVersions(v):
if v & ID3_V1:
if v == ID3_V1_0:
return [1, 0, 0];
elif v == ID3_V1_1:
return [1, 1, 0];
elif v == ID3_V1:
return [1, 1, 0];
elif v & ID3_V2:
if v == ID3_V2_2:
return [2, 2, 0];
elif v == ID3_V2_3:
return [2, 3, 0];
elif v == ID3_V2_4:
return [2, 4, 0];
elif v == ID3_V2:
return [2, 4, 0];
raise str("constantToVersions - Invalid ID3 version constant: %s" % hex(v));
################################################################################
TRACE = 0
prefix = "eyeD3 trace> ";
def TRACE_MSG(msg):
if TRACE:
try:
print prefix + msg;
except UnicodeEncodeError:
pass;
STRICT_ID3 = 0;
def strictID3():
return STRICT_ID3;
--- NEW FILE: binfuncs.py ---
################################################################################
#
# Copyright (C) 2002-2005 Travis Shirk <[EMAIL PROTECTED]>
# Copyright (C) 2001 Ryan Finne <[EMAIL PROTECTED]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
################################################################################
# Accepts a string of bytes (chars) and returns an array of bits
# representing the bytes in big endian byte (Most significant byte/bit first)
# order. Each byte can have it's higher bits ignored by passing an sz arg.
def bytes2bin(bytes, sz = 8):
if sz < 1 or sz > 8:
raise ValueError("Invalid sz value: " + str(sz));
retVal = [];
for b in bytes:
bits = [];
b = ord(b);
while b > 0:
bits.append(b & 1);
b >>= 1;
if len(bits) < sz:
bits.extend([0] * (sz - len(bits)));
elif len(bits) > sz:
bits = bits[:sz];
# Big endian byte order.
bits.reverse();
retVal.extend(bits);
if len(retVal) == 0:
retVal = [0];
return retVal;
# Convert am array of bits (MSB first) into a string of characters.
def bin2bytes(x):
bits = [];
bits.extend(x);
bits.reverse();
i = 0;
out = '';
multi = 1;
ttl = 0;
for b in bits:
i += 1;
ttl += b * multi;
multi *= 2;
if i == 8:
i = 0;
out += chr(ttl);
multi = 1;
ttl = 0;
if multi > 1:
out += chr(ttl);
out = list(out);
out.reverse();
out = ''.join(out);
return out;
# Convert and array of "bits" (MSB first) to it's decimal value.
def bin2dec(x):
bits = [];
bits.extend(x);
bits.reverse();
multi = 1;
value = long(0);
for b in bits:
value += b * multi;
multi *= 2;
return value;
def bytes2dec(bytes, sz = 8):
return bin2dec(bytes2bin(bytes, sz));
# Convert a decimal value to an array of bits (MSB first), optionally
# padding the overall size to p bits.
def dec2bin(n, p = 0):
retVal = [];
while n > 0:
retVal.append(n & 1);
n >>= 1;
if p > 0:
retVal.extend([0] * (p - len(retVal)));
retVal.reverse();
return retVal;
def dec2bytes(n, p = 0):
return bin2bytes(dec2bin(n, p));
# Convert a list of bits (MSB first) to a synch safe list of bits (section 6.2
# of the ID3 2.4 spec).
def bin2synchsafe(x):
if len(x) > 32 or bin2dec(x) > 268435456: # 2^28
raise ValueError("Invalid value");
elif len(x) < 8:
return x;
n = bin2dec(x);
bites = "";
bites += chr((n >> 21) & 0x7f);
bites += chr((n >> 14) & 0x7f);
bites += chr((n >> 7) & 0x7f);
bites += chr((n >> 0) & 0x7f);
bits = bytes2bin(bites);
if len(bits) < 32:
bits = ([0] * (32 - len(x))) + bits;
return bits;
--- NEW FILE: __init__.py ---
################################################################################
#
# Copyright (C) 2002-2005 Travis Shirk <[EMAIL PROTECTED]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
################################################################################
eyeD3Version = "0.6.5";
eyeD3Maintainer = "Travis Shirk <[EMAIL PROTECTED]>";
# Version constants
ID3_CURRENT_VERSION = 0x00; # The version of the linked tag, if any.
ID3_V1 = 0x10;
ID3_V1_0 = 0x11;
ID3_V1_1 = 0x12;
ID3_V2 = 0x20;
ID3_V2_2 = 0x21;
ID3_V2_3 = 0x22;
ID3_V2_4 = 0x24;
#ID3_V2_5 = 0x28; # This does not seem imminent.
ID3_DEFAULT_VERSION = ID3_V2_4;
ID3_ANY_VERSION = ID3_V1 | ID3_V2;
import locale;
LOCAL_ENCODING = locale.getpreferredencoding();
if not LOCAL_ENCODING or LOCAL_ENCODING == "ANSI_X3.4-1968":
LOCAL_ENCODING = 'latin1';
import frames;
import mp3;
import tag;
from tag import *;
import utils;
-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog