Travis Shirk avatar Travis Shirk committed ae36a98

Ported lame info and stats (what I think will become lint) from old tree.

Comments (0)

Files changed (2)

src/eyed3/plugins/lameinfo.py

+# -*- coding: utf-8 -*-
+################################################################################
+#  Copyright (C) 2009  Travis Shirk <travis@pobox.com>
+#
+#  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
+#
+################################################################################
+import os
+
+from eyed3 import LOCAL_ENCODING as ENCODING
+from eyed3.utils import formatSize, formatTime
+from eyed3.utils.cli import (printMsg, printError, printWarning, boldText,
+                             getColor, RESET, HEADER_COLOR)
+from eyed3.plugins import LoaderPlugin
+
+class LameInfoPlugin(LoaderPlugin):
+    NAMES = ["lameinfo"]
+    SUMMARY = u"Outputs lame header (if one exists) for file."
+
+    def printHeader(self, filePath):
+        from stat import ST_SIZE
+        fileSize = os.stat(filePath)[ST_SIZE]
+        size_str = formatSize(fileSize).encode(ENCODING, 'replace')
+        print "\n%s\t%s[ %s ]%s" % (boldText(os.path.basename(filePath),
+                                             HEADER_COLOR),
+                                    getColor(HEADER_COLOR), size_str,
+                                    getColor(RESET))
+        print ("-" * 79)
+
+    def handleFile(self, f):
+        super(LameInfoPlugin, self).handleFile(f)
+
+        self.printHeader(f)
+        if not self.audio_file or not self.audio_file.info.lame_tag:
+            printMsg('No LAME Tag')
+            return self.R_CONT
+
+        format = '%-20s: %s'
+        lt = self.audio_file.info.lame_tag
+        if not lt.has_key('infotag_crc'):
+            try:
+                printMsg('%s: %s' % ('Encoder Version', lt['encoder_version']))
+            except KeyError:
+                pass
+            return self.R_CONT
+
+        values = []
+
+        values.append(('Encoder Version', lt['encoder_version']))
+        values.append(('LAME Tag Revision', lt['tag_revision']))
+        values.append(('VBR Method', lt['vbr_method']))
+        values.append(('Lowpass Filter', lt['lowpass_filter']))
+
+        if lt.has_key('replaygain'):
+           try:
+               peak = lt['replaygain']['peak_amplitude']
+               db = 20 * math.log10(peak)
+               val = '%.8f (%+.1f dB)' % (peak, db)
+               values.append(('Peak Amplitude', val))
+           except KeyError:
+               pass
+           for type in ['radio', 'audiofile']:
+               try:
+                   gain = lt['replaygain'][type]
+                   name = '%s Replay Gain' % gain['name'].capitalize()
+                   val = '%s dB (%s)' % (gain['adjustment'], gain['originator'])
+                   values.append((name, val))
+               except KeyError:
+                   pass
+
+        values.append(('Encoding Flags', ' '.join((lt['encoding_flags']))))
+        if lt['nogap']:
+            values.append(('No Gap', ' and '.join(lt['nogap'])))
+        values.append(('ATH Type', lt['ath_type']))
+        values.append(('Bitrate (%s)' % lt['bitrate'][1], lt['bitrate'][0]))
+        values.append(('Encoder Delay', '%s samples' % lt['encoder_delay']))
+        values.append(('Encoder Padding', '%s samples' % lt['encoder_padding']))
+        values.append(('Noise Shaping', lt['noise_shaping']))
+        values.append(('Stereo Mode', lt['stereo_mode']))
+        values.append(('Unwise Settings', lt['unwise_settings']))
+        values.append(('Sample Frequency', lt['sample_freq']))
+        values.append(('MP3 Gain', '%s (%+.1f dB)' % (lt['mp3_gain'],
+                                                      lt['mp3_gain'] * 1.5)))
+        values.append(('Preset', lt['preset']))
+        values.append(('Surround Info', lt['surround_info']))
+        values.append(('Music Length', '%s' % formatSize(lt['music_length'])))
+        values.append(('Music CRC-16', '%04X' % lt['music_crc']))
+        values.append(('LAME Tag CRC-16', '%04X' % lt['infotag_crc']))
+
+        for v in values:
+            printMsg(format % (v))
+
+PLUGINS = [LameInfoPlugin]
+

src/eyed3/plugins/statistics.py

+# -*- coding: utf-8 -*-
+################################################################################
+#  Copyright (C) 2009  Travis Shirk <travis@pobox.com>
+#
+#  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
+#
+################################################################################
+import sys, os, operator
+
+from eyed3 import id3
+from eyed3.utils.cli import printMsg, printError
+from eyed3.plugins import LoaderPlugin
+
+ID3_VERSIONS = [id3.ID3_V1_0, id3.ID3_V1_1,
+                id3.ID3_V2_2, id3.ID3_V2_3, id3.ID3_V2_4]
+
+_OP_STRINGS = {operator.le: "<=",
+               operator.lt: "< ",
+               operator.ge: ">=",
+               operator.gt: "> ",
+               operator.eq: "= ",
+               operator.ne: "!=",
+              }
+
+class StatisticsPlugin(LoaderPlugin):
+    NAMES = ['stats']
+    SUMMARY = u"Computes statistics for all audio file and tags "\
+               "encountered. For example, ID3 version, bitrate info, etc."
+
+    def __init__(self, arg_parser):
+        super(StatisticsPlugin, self).__init__(arg_parser)
+
+        self.count = 0
+        self.non_audio_file_count = 0
+        self.hidden_file_count = 0
+
+        self.versions = {}
+        for v in ID3_VERSIONS:
+            self.versions[v] = 0
+
+        self.bitrates = {}
+        self.bitrates["cbr"] = 0
+        self.bitrates["vbr"] = 0
+        self.bitrate_keys = [(operator.le, 96),
+                             (operator.le, 112),
+                             (operator.le, 128),
+                             (operator.le, 160),
+                             (operator.le, 192),
+                             (operator.le, 256),
+                             (operator.le, 320),
+                             (operator.gt, 320),
+                            ]
+        for k in self.bitrate_keys:
+            self.bitrates[k] = 0
+
+    def handleFile(self, f):
+        super(StatisticsPlugin, self).handleFile(f)
+
+        if self.audio_file and self.audio_file.tag:
+            self.count += 1
+            if os.path.basename(f).startswith('.'):
+                self.hidden_file_count += 1
+
+            # ID3 versions
+            id3_version = self.audio_file.tag.version
+            self.versions[id3_version] += 1
+            sys.stdout.write('.')
+            sys.stdout.flush()
+
+            # mp3 bit rates
+            vbr, br =  self.audio_file.info.bit_rate
+            if vbr:
+                self.bitrates["vbr"] += 1
+            else:
+                self.bitrates["cbr"] += 1
+            for key in self.bitrate_keys:
+                key_op, key_br = key
+                if key_op(br, key_br):
+                    self.bitrates[key] += 1
+                    break
+
+        return self.R_CONT
+
+    def handleDone(self):
+        print("\nAnalyzed %d audio files (%d non-audio) (%d hidden)" %
+              (self.count, self.non_audio_file_count, self.hidden_file_count))
+
+        if not self.count:
+            return
+
+        print("\nMP3 bitrates:")
+        for key in ["cbr", "vbr"]:
+            val = self.bitrates[key]
+            print("\t%s   : %d \t%.2f%%" %
+                  (key, val, (float(val) / float(self.count)) * 100))
+
+        for key in self.bitrate_keys:
+            val = self.bitrates[key]
+            key_op, key_br = key
+            print("\t%s%03d : %d \t%.2f%%" %
+                  (_OP_STRINGS[key_op], key_br, val,
+                   (float(val) / float(self.count)) * 100))
+
+        print("\nID3 versions:")
+        for v in ID3_VERSIONS:
+            v_count = self.versions[v]
+            v_percent = (float(v_count) / float(self.count)) * 100
+            print "\t%s : %d \t%.2f%%" % (id3.versionToString(v),
+                                          v_count, v_percent)
+
+
+PLUGINS = [StatisticsPlugin]
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.