# auto.py """ This module is an integeral part of the program MMA - Musical Midi Accompaniment. 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 Bob van der Poel """ import os import sys import pickle import MMA.midi import MMA.parse import gbl from MMA.common import * grooveDir = {} mmadir = ".mmaDB" # constant, name of the lib database file fileCount = 0 grooveCount = 0 gdDate = None processedFiles = [] mkGrooveList = [] def updateGrooveList(n): """ Called from parse when new grooves are defined in a -g. """ global mkGrooveList mkGrooveList.append(n) def libUpdate(): """ Update the mma library database file(s) with -g or -G option. This is called from the main program after the initialization and other option parsing. No RETURN. """ global fileCount, gdDate, grooveDir, processedfiles print "Creating MMA groove directory database(s). Standby..." """ gbl.libPath points to one main directory tree which should include gbl.autoLib (defaults to 'stdlib'). We create a separate .mmaDB file for each directory found in the main tree. IE. if we have the directories stdlib and bvstuff we end up with stdlib/.mmaDB and bvstuff/.mmaDB. """ for d in os.listdir(gbl.libPath): libpath = os.path.join(gbl.libPath, d) if not os.path.isdir(libpath): # skip files, just process directories continue """ Attempt to read existing database There is a flag gbl.makeGrvDefs set to 0, 1, 2 0 - there was no -g or -G so we're not here 1 - -g - read existing database and update 2 - -G - don't read existing, create new """ grooveDir = {} gdDate = None if gbl.makeGrvDefs == 1: try: infile = os.path.join(libpath, mmadir) f=file(infile, "rb") f.readline() # Read/discard comment line grooveDir = pickle.load(f) f.close() gdDate = os.path.getmtime(infile) except: pass dolibupdate(libpath, '') # Strip out defs of deleted (not found) files. for f in grooveDir.keys(): if f not in processedFiles: print " Deleting: %s" % f del grooveDir[f] try: outpath = file(os.path.join(libpath, mmadir), 'wb') except: error("Error creating lib-database file '%s'. CRITICAL!" % libpath) outpath.write("### mmaDB ... AUTOGENERATED BINARY DATA. " "DO NOT EDIT!!!\n") pickle.dump(grooveDir, outpath, pickle.HIGHEST_PROTOCOL ) outpath.close() print print "Database update complete." print " Files processed: %s" % fileCount print " Total number of grooves: %s" % grooveCount sys.exit(0) def dolibupdate(root, subdir): """ Recursive function to read groove files in a directory. """ global fileCount, grooveCount, gdDate, grooveDir, processedFiles, mkGrooveList if subdir == '.': print "Skipping: '.'" return if subdir: print " Processing library directory '%s'." % subdir """ Get a list of the files in this directory. If the list includes a file called 'MMAIGNORE' the entire directory (and subdirs) is ignored. Otherwise, each file in the directory ending in 'mma' is parsed for groove defs. """ p = os.path.join(root,subdir) dirfiles = os.listdir(p) if "MMAIGNORE" in dirfiles: print "Skipping: %s" % p return for fn in sorted(dirfiles): # Ignore hidden files and emacs auto-save and dead. if fn.startswith('.') or fn.startswith('#'): continue f=os.path.join(root, subdir, fn) # Create full path name if os.path.isdir(f): dolibupdate(root, os.path.join(subdir,fn)) # recursive! elif f.endswith(gbl.ext): ename = os.path.join(subdir, fn) processedFiles.append(ename) if gdDate and ename in grooveDir and os.path.getmtime(f) < gdDate: print " Existing: %s" % f grooveCount += len(grooveDir[ename]) continue if ename in grooveDir: print " Updating: %s" % f else: print " Creating: %s" % f mkGrooveList = [] gbl.mtrks = {} MMA.grooves.aliaslist = {} for c in gbl.midiAssigns.keys(): gbl.midiAssigns[c]=[] for a,v in enumerate(gbl.midiAvail): gbl.midiAvail[a]=0 gbl.mtrks[0]=MMA.midi.Mtrk(0) gbl.tnames = {} MMA.parse.parseFile(f) # read current file, grab grooves fileCount += 1 # just so we can report to user grooveCount += len(mkGrooveList) grooveDir[ename]=mkGrooveList else: if not f.endswith(mmadir): print " Ignoring: %s" % f ################################################################# def loadGrooveDir(g): """ Try to auto-load a groove from the library. The compliation of all the MMADIR files is stored in the dict grooveDir{}. Check the main libpath directory for the MMADIR file. The names of the files and corresponding grooves are extracted. This is stored in a dictionary with the filename as the key and a list of grooves as the data. """ global grooveDir """ If the global dict grooveDir is empty we first load the MMADIR info. We're assuming that not much goes wrong here...if we don't find the database we set grooveDir{} to a BS value to avoid future load attempts. The entire load is in a try, which means it either all works, or not ... """ if not grooveDir: try: infile = os.path.join(gbl.libPath, gbl.autoLib, mmadir) f=file(infile, "rb") f.readline() # Read/discard comment line grooveDir = pickle.load(f) f.close() except: grooveDir[0]='' """ Search the dict for a match. grooveDir{} is a dictionary for lists. Each dictionary key is filename (eg: "lib/rhumba.mma") and the list associated with it is a list of grooves defined in that file. Just a matter of stepping though the dict. and returning the proper filename. RETURN: Lib-Filename if found None if not found """ for filename, namelist in grooveDir.items(): if g in namelist: return filename return None