#!/usr/bin/env python # -*- coding: utf-8 -*- import optparse, sys, os, zipfile, shutil, tempfile, xml.dom.minidom version = '0.2.0' date = '2010-12-29' changelog = """ --- Version 0.2.0 - 2010-12-29 --- * added -r (reports non-native instruments and DSP devices) --- Version 0.1.1 - 2009-08-22 --- * added -q (ogg compresseion quality) * zip compresses (not just stores) --- Version 0.1.0 - 2009-08-20 --- * initial release """ defaultMinCompress = 100000 def searchPath(cmdname, path = None): if path is None: path = os.environ["PATH"] if os.name in ["nt", "os2"]: short = [cmdname + "." + ext for ext in ["exe","com","bat"]] else: short = [cmdname] for scmd in short: for dir in path.split(os.pathsep): fcmd = os.path.abspath(os.path.join(dir,scmd)) if os.path.isfile(fcmd): return fcmd return None def humanReadableSize(size): if size >= 1024 and size < 1024*1024: size = str(size/1024) + 'K' elif size >= 1024*1024: size = str(size/1024/1024) + 'M' else: size = str(size) return size def checkExternalProgram(prg): path = searchPath(prg) if path == None: print 'error, program not found: ' + prg sys.exit() def listFiles(file): zip = zipfile.ZipFile(file, 'r') for name in zip.namelist(): size = humanReadableSize(zip.getinfo(name).file_size) if 'Song.xml' in name: print name + ': ' + size else: print name[24:].replace('(','').replace(')','') + ': ' + size def getNonNativeInstruments(dom): nonNativeInstruments = [] for child in dom.childNodes[0].childNodes: if child.nodeType != child.TEXT_NODE and child.tagName == 'Instruments': for instrument in child.childNodes: instrumentName = None if instrument.nodeType != instrument.TEXT_NODE: for part in instrument.childNodes: if part.nodeType != part.TEXT_NODE and part.tagName == 'Name': instrumentName = part.childNodes[0].nodeValue elif part.nodeType != part.TEXT_NODE and part.tagName == 'PluginProperties' and instrumentName: for pluginProperty in part.childNodes: if pluginProperty.nodeType != pluginProperty.TEXT_NODE and pluginProperty.tagName == 'PluginDevice': nonNativeInstruments.append(instrumentName) return nonNativeInstruments def getNonNativeDSP(dom): nonNativeDSP = [] for child in dom.childNodes[0].childNodes: if child.nodeType != child.TEXT_NODE and child.tagName == 'Tracks': for track in child.childNodes: trackName = None if track.nodeType != track.TEXT_NODE: for part in track.childNodes: if part.nodeType != part.TEXT_NODE and part.tagName == 'Name': trackName = part.childNodes[0].nodeValue elif part.nodeType != part.TEXT_NODE and part.tagName == 'FilterDevices': for filterDevices in part.childNodes: if filterDevices.nodeType != filterDevices.TEXT_NODE and filterDevices.tagName == 'Devices': for device in filterDevices.childNodes: if device.nodeType != device.TEXT_NODE and device.tagName == 'AudioPluginDevice': for one in device.childNodes: if one.nodeType != one.TEXT_NODE and one.tagName == 'PluginDisplayName': pluginDisplayName = one.childNodes[0].nodeValue nonNativeDSP.append('(Track:'+ trackName + ') ' + pluginDisplayName) return nonNativeDSP def listNonNative(file): file = os.path.abspath(file) zip = zipfile.ZipFile(file, 'r') tmpDir = tempfile.mkdtemp() os.chdir(tmpDir) zip.extract('Song.xml') XMLPath = tmpDir + '/Song.xml' XMLFile = open(XMLPath,'r').read() shutil.rmtree(tmpDir) dom = xml.dom.minidom.parseString(XMLFile) nonNativeInstruments = getNonNativeInstruments(dom) if len(nonNativeInstruments) > 0: print 'Instruments:' for instrument in nonNativeInstruments: print instrument nonNativeDSP = getNonNativeDSP(dom) if len(nonNativeDSP) > 0: print 'DSP:' for dsp in nonNativeDSP: print dsp def flac2ogg(file): checkExternalProgram('sox') if options.oggQuality != None and options.oggQuality >= -1 and options.oggQuality <= 11: oggQ = ' -C ' + str(options.oggQuality) + ' ' else: oggQ = ' ' basename = os.path.splitext(file)[0] oggFile = basename + '.ogg' soxCommand = 'sox "' + file + '" ' + oggQ + ' "' + oggFile + '"' os.system(soxCommand) return oggFile def xrnsExtract(file, dir): file = os.path.abspath(file) if os.path.exists(dir): if not os.path.isdir(dir): print dir + ' exists and is not a directory, exitting...' sys.exit() else: os.mkdir(dir) os.chdir(dir) zip = zipfile.ZipFile(file, 'r') for name in zip.namelist(): print 'extracting ' + name zip.extract(name) def xrnsCompress(dir, file): if os.path.exists(file) and not options.force: print file + ' exists, use -f to force overwrite, exitting...' sys.exit() if os.path.exists(file): os.remove(file) try: newZip = zipfile.ZipFile(file, 'w', zipfile.ZIP_DEFLATED) except: newZip = zipfile.ZipFile(file, 'w') os.chdir(dir) if not os.path.exists('Song.xml'): print 'Song.xml not found in ' + dir + ', exitting...' sys.exit() if not os.path.exists('SampleData'): print 'SampleData not found in ' + dir + ', exitting...' sys.exit() if not os.path.isdir('SampleData'): print 'SampleData in ' + dir + ' is not directory, exitting...' sys.exit() for top, dirs, files in os.walk('./'): for nm in files: oneFile = os.path.join(top, nm) print oneFile newZip.write(oneFile) def oggCompress(dir): if not os.path.exists(dir) or not os.path.isdir(dir): print "directory for compression doesn't exist" for top, dirs, files in os.walk(dir): for nm in files: name = os.path.join(top, nm) if 'flac' in name and os.path.getsize(name) > options.minCompressSize: print 'converting to ogg: ' + name oggName = flac2ogg(name) os.remove(name) name = oggName def xrnsOggCompress(file, resultFile): tmpDir = tempfile.mkdtemp() if resultFile == None and not options.force: print 'use -f to overwrite source file, or add a target file name, exitting...' sys.exit() if resultFile != None and os.path.exists(resultFile) and not options.force: print 'use -f to overwrite esisting file (' + resultFile + '), exitting...' sys.exit() if resultFile == None: resultFile = file tmpDir = os.path.abspath(tmpDir) file = os.path.abspath(file) resultFile = os.path.abspath(resultFile) xrnsExtract(file,tmpDir) oggCompress(tmpDir) xrnsCompress(tmpDir,resultFile) shutil.rmtree(tmpDir) # show help if no input + if -? if len(sys.argv) == 1: sys.argv.append('-h') elif '-?' in sys.argv: sys.argv.remove('-?') sys.argv.append('-h') # parse args parser = optparse.OptionParser() xrnsGroup = optparse.OptionGroup(parser, 'xrns','') helpGroup = optparse.OptionGroup(parser, 'help','') xrnsGroup.add_option('-l', '--list', action="store_true", dest='listFiles', help='list files in xrns', default=False) xrnsGroup.add_option('-n', '--list-non-native', action="store_true", dest='listNonNative', help='list non-native instruments and DSP devices in xrns', default=False) xrnsGroup.add_option('-x', '--extract', type='string', dest='extractDir', help='extract xrns to directory', default='') xrnsGroup.add_option('-z', '--zip', type='string', dest='compressDir', help='zip, create xrns from directory', default='') xrnsGroup.add_option('-o', '--ogg', action='store_true', dest='oggCompress', help='compress samples with ogg vorbis', default=False) xrnsGroup.add_option('-s', '', type='int', dest='minCompressSize', help='compress flac larger than this size', default=defaultMinCompress) xrnsGroup.add_option('-q', '', type='int', dest='oggQuality', help='use this quality with ogg compresseion (-1-10)', default=None) xrnsGroup.add_option('-f', '--force', action='store_true', dest='force', help='overwrite any destination files', default=False) helpGroup.add_option('-v', '--version', action='store_true', dest='printVersion', help='print version', default=False) helpGroup.add_option('', '--changelog', action='store_true', dest='printChangelog', help='print changelog', default=False) parser.add_option_group(xrnsGroup) parser.add_option_group(helpGroup) (options, args) = parser.parse_args() if len(args) < 1: file = None else: file = args[0] if len(args) < 2: resultFile = None else: resultFile = args[1] if options.printVersion: print 'version ' + version + ', ' + date sys.exit() if options.printChangelog: print changelog sys.exit() # from here at least one xrns file is required as argument if file == None: print 'missing file, exitting...' sys.exit() if options.compressDir: xrnsCompress(options.compressDir, os.path.abspath(file)) sys.exit() if options.extractDir: xrnsExtract(os.path.abspath(file), options.extractDir) sys.exit() if options.listFiles: listFiles(file) sys.exit() if options.listNonNative: listNonNative(file) sys.exit() if options.oggCompress: xrnsOggCompress(file, resultFile) sys.exit()