#!/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:
	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

	
except:
	print """
    MMA was unable to find the module directory.
    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. Contact Bob if
    you can't figure it out!
""" % moddirs

	sys.exit(1)
	

gbl.version = "0.6"


################################################
# 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			


##########################################
# 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.

gbl.tnames={} 

for f, name in ((Bass,     'BASS'), 
		(Chord,    'CHORD'),
		(Arpeggio, 'ARPEGGIO'),
		(Scale,    'SCALE'),
		(Walk,     'WALK'),
		(Drum,     'DRUM') ):


	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.

for a, chan in (
	('BASS',     3 ),  ('BASS1',     4 ), ('BASS2',  5 ),
	('CHORD',    6 ),  ('CHORD1',    7 ), ('CHORD2', 8 ),
	('ARPEGGIO', 9 ),  ('ARPEGGIO1', 11 ),
	('SCALE',    12 ), ('SCALE1',    13 ),
	('WALK',     14 ), ('WALK1',     15 ), ('WALK2', 16 ) ): 
	
	gbl.tnames[a].setChannel(str(chan))


#######################################
# 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


#################################################
# 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
	sys.exit(0)


################################################
# 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)

	
# 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 remaining tracks

for n in keys:
	if len(gbl.mtrks[n].miditrk) > 1 or n==0:		
		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


