VocalEasel/mma/MMA/auto.py
Matthias Neeracher d599bfbe4e Added MMA
2006-11-10 08:07:56 +00:00

256 lines
6.3 KiB
Python

# 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 <bvdp@xplornet.com>
"""
import os
import sys
import pickle
import MMA.midi
import gbl
import MMA.parse
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
# Create full path name
f=os.path.join(root, subdir, fn)
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 grooveDir.has_key(ename) and \
os.path.getmtime(f) < gdDate:
print " Existing: %s" % f
grooveCount += len(grooveDir[ename])
continue
if grooveDir.has_key(ename):
print " Updating: %s" % f
else:
print " Creating: %s" % f
mkGrooveList = []
gbl.mtrks = {}
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