Add mkogg post.
authorW. Trevor King <wking@drexel.edu>
Tue, 16 Nov 2010 13:43:59 +0000 (08:43 -0500)
committerW. Trevor King <wking@drexel.edu>
Tue, 16 Nov 2010 13:43:59 +0000 (08:43 -0500)
posts/mkogg.mdwn [new file with mode: 0644]
posts/mkogg/mkogg.py [new file with mode: 0755]

diff --git a/posts/mkogg.mdwn b/posts/mkogg.mdwn
new file mode 100644 (file)
index 0000000..0b00b48
--- /dev/null
@@ -0,0 +1,25 @@
+[[!meta  title="mkogg"]]
+
+I keep my music organized by Genre→Artist→Album→Song and try to keep
+as much as possible in [FLAC][] format.  When it comes time to wedge
+this music onto a smaller device, I want to recode the music in [Ogg
+Vorbis][].  [SoX][] is a useful tool for converting between all sorts
+of audio formats, but I wanted the ability to excercise a bit more
+control over maintaning metadata (e.g. via [metaflac][], [id3v2][],
+etc.).  To this end, I've put together a little [[Python]] script,
+[[mkogg.py]], which mirrors a source directory of mixed-format music
+as Ogg-encoded files (or other formats via `--target-extension`) in a
+target directory.
+
+You can use the [[cdrtools]] to burn CD with your recoded music.
+
+[FLAC]: http://flac.sourceforge.net/
+[Ogg Vorbis]: http://www.vorbis.com/
+[SoX]: http://sox.sourceforge.net/
+[metaflac]: http://flac.sourceforge.net/documentation_tools_metaflac.html
+[id3v2]: http://id3v2.sourceforge.net/
+[MP3]: http://en.wikipedia.org/wiki/MP3
+
+[[!tag tags/code]]
+[[!tag tags/fun]]
+[[!tag tags/python.mdwn]]
diff --git a/posts/mkogg/mkogg.py b/posts/mkogg/mkogg.py
new file mode 100755 (executable)
index 0000000..76755c7
--- /dev/null
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009-2010 W. Trevor King <wking@drexel.edu>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 3 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program.  If not, see
+# <http://www.gnu.org/licenses/>.
+
+"""Mirror a tree of mp3/ogg/flac files with ogg-vorbis versions
+"""
+
+import shutil
+from subprocess import Popen, PIPE
+from tempfile import mkstemp
+import os
+import os.path
+
+
+class Converter (object):
+    def __init__(self, source_dir, target_dir, target_extension='ogg'):
+        self.source_dir = source_dir
+        self.target_dir = target_dir
+        self._source_extensions = ['flac', 'mp3', 'ogg', 'wav']
+        self._target_extension = target_extension
+        f,self._tempfile = mkstemp(prefix='mkogg-')
+
+    def cleanup(self):
+        os.remove(self._tempfile)
+
+    def _makedirs(self, target_dir):
+        if not os.path.exists(target_dir):
+            os.makedirs(target_dir)
+
+    def run(self):
+        self._makedirs(self.target_dir)
+        for dirpath,dirnames,filenames in os.walk(self.source_dir):
+            for filename in filenames:
+                root,ext = os.path.splitext(filename)
+                ext = ext.lower()
+                if ext.startswith('.'):
+                    ext = ext[1:]
+                if ext not in self._source_extensions:
+                    print 'skip', filename, ext
+                    continue
+                source_path = os.path.join(dirpath, filename)
+                rel_path = os.path.relpath(dirpath, self.source_dir)
+                target_path = os.path.join(
+                    self.target_dir, rel_path,
+                    '%s.%s' % (root, self._target_extension))
+                target_dir = os.path.dirname(target_path)
+                self._makedirs(target_dir)
+                self._convert(source_path, target_path, ext)
+
+    def _convert(self, source, target, ext):
+        print 'convert %s to %s' % (source, target)
+        if ext == self._target_extension:
+            shutil.copy(source, target)
+        else:
+            convert = getattr(self, 'convert_%s_to_%s'
+                                 % (ext, self._target_extension))
+            convert(source, target)
+
+    def convert_flac_to_mp3(self, source, target):
+        self.convert_flac_to_wav(source, self._tempfile)
+        self.convert_wav_to_mp3(self._tempfile, target)
+
+    def convert_flac_to_wav(self, source, target):
+        p = Popen(['ogg123', '--quiet', '-d', 'wav', '-f', target, source])
+        p.wait()        
+
+    def convert_flac_to_ogg(self, source, target):
+        p = Popen(['oggenc', '-q', '3', source, '-o', target])
+        p.wait()
+
+    def convert_mp3_to_ogg(self, source, target):
+        self.convert_mp3_to_wav(source, self._tempfile)
+        self.convert_wav_to_ogg(self._tempfile, target)
+
+    def convert_mp3_to_wav(self, source, target):
+        p = Popen(['mpg123', source, '-w', target])
+        p.wait()
+
+    def convert_ogg_to_mp3(self, source, target):
+        self.convert_flac_to_mp3(source, target)
+
+    def convert_ogg_to_wav(self, source, target):
+        self.convert_flac_to_wav(source_target)
+
+    def convert_wav_to_mp3(self, source, target):
+        p = Popen(['lame', '--silent', '-V', '4', source, target])
+        p.wait()
+
+    def convert_wav_to_ogg(self, source, target):
+        self.convert_flac_to_ogg(source, target)
+
+
+if __name__ == '__main__':
+    import optparse
+
+    p = optparse.OptionParser('%prog [options] source-dir target-dir')
+    p.add_option('-t', '--target-extension', dest='ext',
+                 default='ogg', metavar='EXT',
+                 help='Conversion target type (e.g. flac, mp3) (%default)')
+
+    options,args = p.parse_args()
+    source_dir,target_dir = args
+
+    c = Converter(source_dir, target_dir, target_extension=options.ext)
+    try:
+        c.run()
+    finally:
+        #c.cleanup()
+        pass