#!/usr/bin/env python


import sys
import os
import profile

# Ensure a proper version is available.

pyMaj=2
pyMin=2

try:
	if sys.version_info[0] < pyMaj or sys.version_info[1] < pyMin:
		raise
except:
	print
	print "You need a more current version of Python to run MMA."
	print "We're looking for something equal or greater than version %s.%s" % (pyMaj,pyMin)
	print "Current Python version is ", sys.version
	print
	sys.exit(0)

""" MMA uses a number of application specific modules. These can
	be placed in a number of locations. Some people like application
	specific modules to be in an application directory....for these
	people mma appends the moddirs[] list to the current sys.path[].
	Otherwise, the modules should be in the site-packages directory
	of the main python tree. The imports are surrounded by a try/expect.
	If any of the imports fail, the error message is printed (note, we
	can't use the normal error() routine here since it's in a module that
	we can't find.
"""

moddirs=["/usr/local/share/mma/modules", "/usr/share/mma/modules", "./modules"] 
sys.path.extend(moddirs)

""" Try to load the nesc. modules for mma. Catch ONLY ImportErrors.
	This means that if there is an error in the found module, that
	error will dump out of python and let python report; however,
	if we can't find the modules, then the expect will print our
	"you installed wrong" message.
"""

for a in [
	"import MMAglobals ; gbl = MMAglobals",
	"from MMAcommon import *",
	"import MMAoptions",
	"import MMAmidi",
	"import MMAdocs",
	"import MMAfile",
	"import MMAauto",
	"from MMApats import *",
	"from MMAparse import parseFile, parseFileInc" ]:

	try:
		exec(a)
	
	except ImportError:
		print """
   MMA was unable to find the module directory (or a
   specific module). The module directory contains Python
   extensions necessary for operation. In addition to the
   standard site-packages tree, mma tried the additional
   directories:

      %s
      
   Please review the installation. 
		    
   Error occured with module: %s
		    
   Contact Bob if you can't figure it out!
	""" % (moddirs, a.split()[1])

		sys.exit(1)
	

gbl.version = "0.7"


################################################
# Set the default libPath


t=["/usr/local/share/mma/lib", "/usr/share/mma/lib", "./lib"]
for p in t:
	if os.path.isdir(p):
		gbl.libPath=[p]
		break

################################################
# Set the default incPath


t=["/usr/local/share/mma/includes", "/usr/share/mma/includes", "./includes"]
for p in t:
	if os.path.isdir(p):
		gbl.incPath=[p]
		break


########################################
########################################

# Start of Program

###########################
# Get our command line stuff

MMAoptions.opts()


if gbl.debug:
	print "Initialization has set LibPath set to", gbl.libPath			
	print "Initialization has set IncPath set to", gbl.incPath			

###################################################
# Maintain a list of the midi track assignments.

for c in range(1,17):
	gbl.midiAssigns[c]=[]
	

##########################################
# Each mma track has a tnames{} entry. 
# Create a class instance for each possible track. There are
# 10 tracks for each type. Names of the tracks are BASS, BASS1..BASS9, etc.

for c in range(2,17):
	gbl.midiAssigns[c]=[]
	
gbl.tnames={} 

for f, name in (
		(Bass,     'BASS'     ), 
		(Chord,    'CHORD'    ),
		(Arpeggio, 'ARPEGGIO' ),
		(Scale,    'SCALE'    ),
		(Walk,     'WALK'     ),
		(Drum,     'DRUM'     ),
		(Melody,   'MELODY'   ),
		(Solo,     'SOLO'     ) ):
		
	gbl.tnames[name] = f( name ) 
	for a in range(1,10):
		n = name + str(a)
		gbl.tnames[n] = f( n )


# Assign Midi channels for selected tracks.
# Note that __init__() has already assigned track 10 to drum.

z = gbl.noWarn
gbl.noWarn = 1
gbl.tnames['DRUM'].setChannel('10')
for a in range(1,10):
	gbl.tnames[ "DRUM"+str(a)].setChShare('DRUM')
gbl.noWarn = z


#######################################
# Set up initial meta track stuff. Track 0 == meta

m = gbl.mtrks[0]=MMAmidi.Mtrk(0)

m.addTrkName(0,'MetaTrack')
m.addTempo(0,gbl.tempo) 
m.addTimeSig(0, 4, 2, 48, 8) 
m.addText(0, "Created by MMA") 

#####################################
# Read an RC file. All found files are processed.

# Disable doc printing for RC file

docOption = gbl.docs
gbl.docs = 0

rcread=0
for i in ('/etc/mmarc', '/usr/local/etc/mmarc',
		os.path.expanduser("~/.mmarc"),	'mmarc' ):

	if os.path.exists(i) or os.path.exists(i + gbl.ext):
		if gbl.showrun:
			print "Reading RC file '%s'" % i
		parseFile(i)
		rcread+=1

if not rcread:
	warning("No RC file was found or processed")


# Check for a valid libpath. It could have been set during
# initialization or in the mmarc file file.

if not gbl.libPath:
	warning("Running MMA with no library path.\n"
		"  You probably have a non-standard installation\n"
		"  and have not used a SetLibPath directive\n"
		"  in a 'mmarc' file.\n")		

	
# Outfile prefix is current dir if not set in rc files

if not gbl.outPath:
	gbl.outPath = '.'

gbl.docs = docOption



################################################
# Update the library database file(s) (-g option)

if gbl.makeGrvDefs:
	if gbl.infile:
		error("No filename is permitted with the -g option")
	MMAauto.libUpdate()		# update and EXIT
	

################################
# Ready, set, go.
	
if not gbl.infile:
	MMAoptions.usage("No input filename specified.")

if docOption:
	parseFile(gbl.infile)
	sys.exit(0)
	
# Add filename to meta track. Strip off the .mma extension

t=gbl.infile
if t.endswith(gbl.ext):
	t = t[:len(t)-len(gbl.ext)]
gbl.mtrks[0].addTrkName(0, t) 	# add infile name to meta track


# Create the output filename. If -f<file> was used we don't strip
# off the '.mma', even if it's there (VERY unlikely). But, if the default
# outfile==infile+'.mid' is used, then that extension is first removed.
# Note, we don't add .mid either if a using -f.

if gbl.outfile:
	outfile = "%s/%s" % (gbl.outPath, gbl.outfile)
else:
	t=gbl.infile
	if t.endswith(gbl.ext):
		t=t[:len(t)-4]
	outfile = "%s/%s.mid" % (gbl.outPath, t)

outfile=os.path.expanduser(outfile)

# Read/process the mmaStart, data and mmaEnd files.

for f in gbl.mmaStart:
	if not parseFileInc(f):
		gbl.lineno = -1
		warning("MmaStart file '%s' not processed." % f)
	

parseFile(gbl.infile)

for f in gbl.mmaEnd:
	if not parseFileInc(f):
		gbl.lineno = -1
		warning("MmaEnd file '%s' not processed." % f)


#################################################
# Just display the channel assignments and exit.

if gbl.chshow:
	print "MMA channel assignments:"
	for c in range(1,17):
		k=gbl.tnames.keys()
		k.sort()
		for a in k:
			if gbl.tnames[a].channel == c:
				print " %2s  %s" % (c, gbl.tnames[a].name)
				break
	print "File parsed, but no MIDI file produced!"
	sys.exit(0)


	
# Create the output file

gbl.lineno=-1	# disable line nums for error/warning

if gbl.noOutput:
	warning( "Input file parsed successfully. No midi file generated.")
	sys.exit(0)


fileExist = os.path.exists(outfile)
if fileExist:
	warning( "Overwriting existing file '%s'" % outfile )
	
# Check all the tracks and find total number used.
# When initializing each track (class) we made an initial entry
# in the track at offset 0 for the track name, etc. So, if the
# track only has one entry we can safely skip the entire track.

keys=gbl.mtrks.keys()
keys.sort()
trackCount=1	# account for meta track

for n in keys[1:]:	 # check all but 0 (meta)
	if len(gbl.mtrks[n].miditrk) > 1:
		trackCount += 1

if trackCount == 1:	# only meta track
	if fileExist:
		print
	print "No data created. Did you remember to set a groove/sequence?"
	if fileExist:
		print "Existing file '%s' has not been modified." % outfile
	sys.exit(1)


print "Creating midi file '%s'" % outfile

try:
	out = open(outfile, 'w')
except:
	error("Can't open file '%s' for writing." % outfile)

# Write Midi file header.

out.write( MMAmidi.mkHeader(trackCount, gbl.BperQ) )

# Write the tracks

for n in keys:
	if len(gbl.mtrks[n].miditrk):
		if gbl.debug:
			print "Writing <%s> ch=%s;" % \
				(gbl.mtrks[n].miditrk[0][0][3:], n),
		gbl.mtrks[n].writeMidiTrack(out)	

out.close()

if gbl.debug:
	print "Completed processing file '%s'." % outfile


