# 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 MMA.grooves import MMA.swing import gbl from MMA.common import * grooveDB = [] # when filled in it becomes [['dir', dict-db], ..] mmadir = ".mmaDB" # constant, name of the lib database file fileCount = 0 grooveCount = 0 gdDate = None processedFiles = [] mkGrooveList = [] # a list of grooves defined in current file 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, grooveDB, processedfiles dupMessage = [] print "Creating MMA groove directory database(s). Standby..." """ gbl.libPath points to one main directory tree. 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 dir in os.listdir(gbl.libPath): libpath = os.path.join(gbl.libPath, dir) if not os.path.isdir(libpath): # skip files, just process directories continue gdDate = None grooveDB = [[dir, {}]] # load up our database with this directory's DB file, skip if -G if gbl.makeGrvDefs == 1: g=loadDB(dir) if g: grooveDB=[[dir, g]] gdDate = os.path.getmtime(os.path.join(gbl.libPath, dir, mmadir)) dolibupdate(libpath, '') # update all files in this dir # Strip out defs of deleted (not found) files. db = grooveDB[0][1] for f in db.keys(): if f not in processedFiles: print " Deleting: %s" % f del g[f] try: outpath = file(os.path.join(libpath, mmadir), 'wb') except: error("Error creating lib-database file '%s'. " \ "Do you need to be root?" % libpath) outpath.write("### mmaDB ... AUTOGENERATED BINARY DATA. " "DO NOT EDIT!!!\n") pickle.dump(db, outpath, pickle.HIGHEST_PROTOCOL ) outpath.close() # check the database we just saved for duplicate entries. dprinted = None for f in db: for g in db[f]: for ff in db: if f == ff: continue if g in db[ff]: if not dprinted: dupMessage.append(" Lib %s: %s & %s have dups." % \ (libpath, f, ff)) dprinted=1 if dprinted: break print print "Database update complete." print " Files processed: %s" % fileCount print " Total number of grooves: %s" % grooveCount print if dupMessage: print "Warning: Duplicate groove definitions found." for a in dupMessage: print a sys.exit(0) def dolibupdate(root, subdir): """ Recursive function to read groove files in a directory. """ global fileCount, grooveCount, gdDate, grooveDB, processedFiles, mkGrooveList db = grooveDB[0][1] 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 db and os.path.getmtime(f) < gdDate: print " Existing: %s" % f grooveCount += len(db[ename]) continue if ename in db: print " Updating: %s" % f else: print " Creating: %s" % f mkGrooveList = [] MMA.grooves.grooveClear([]) gbl.mtrks = {} MMA.swing.mode = 0 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) db[ename]=mkGrooveList else: if not f.endswith(mmadir): print " Ignoring: %s" % f def loadDB(dir): """ Read a database file into memory. We're assuming that not much goes wrong here...if we don't find the database we return a Null. """ try: infile = os.path.join(gbl.libPath, dir, mmadir) f=file(infile, "rb") f.readline() # Read/discard comment line g = pickle.load(f) f.close() return g except: pass return None ################################################################# def findGroove(targ): """ Try to auto-load a groove from the library. The compilation of all the MMADIR files is stored in the list of dicts in grooveDir[]. Check the each 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 grooveDB """ If no existing DB we load them from each dir in libpath. """ if not grooveDB: grooveDB=[] for dir in gbl.autoLib: g=loadDB(dir) if g: grooveDB.append([dir, g]) if not grooveDB: # BS value so we don't keep trying to load grooveDB = [['', {}]] """ Search the dict for a match. grooveDir[] structure ... [ [dirname, g], [] ] g ... is a dict. Key = filename, data = list of grooves RETURN: Lib-Filename if found None if not found """ for dir, g in grooveDB: for filename, namelist in g.items(): if targ in namelist: return os.path.join(dir,filename) return None