# main.py """ The program "MMA - Musical Midi Accompaniment" and the associated modules distributed with it are protected by copyright. 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 MMA.midi import MMA.midifuncs import MMA.parse import MMA.file import MMA.options import MMA.auto import MMA.docs import gbl from MMA.common import * from MMA.lyric import lyric import MMA.paths ######################################## ######################################## # This is the program mainline. It is called/executed # exactly once from a call in the stub program mma.py. ########################### # Get our command line stuff MMA.options.opts() """ LibPath and IncPath are set in MMA.globals. Debug setting isn't set when the default is done. """ if gbl.debug: print "Initialization has set LibPath set to", gbl.libPath print "Initialization has set IncPath set to", gbl.incPath ####################################### # Set up initial meta track stuff. Track 0 == meta m = gbl.mtrks[0] = MMA.midi.Mtrk(0) if gbl.infile: fileName=MMA.file.locFile(gbl.infile, None) if fileName: # needed for certain doc commands. m.addTrkName(0, "%s" % fileName.rstrip(".mma") ) m.addText(0, "Created by MMA. Input filename: %s" % fileName) m.addTempo(0, gbl.tempo) # most user files will override this MMA.midifuncs.setTimeSig(['4','4']) # most stdlib (and/or user) files will override this ##################################### # Read an RC file. All found files are processed. docOption = gbl.createDocs # Disable doc printing for RC file gbl.createDocs = 0 #rcread=0 rcfiles = ('mmarc', 'c:\\mma\\mmarc', '~/.mmarc', '/usr/local/etc/mmarc', '/etc/mmarc' ) if gbl.mmaRC: rcfiles = [ gbl.mmaRC ] for i in rcfiles: f = MMA.file.locFile(i, None) if f: if gbl.showrun: print "Reading RC file '%s'" % f MMA.parse.parseFile(f) #rcread+=1 break else: if gbl.mmaRC: error("Specified init file '%s' not found" % gbl.mmaRC) else: #if not rcread: if gbl.debug: gbl.lineno = -1 warning("No RC file was found or processed") gbl.createDocs = docOption # Restore doc options ################################################ # Update the library database file(s) (-g option) # Note: This needs to be here, after reading of RC files if gbl.makeGrvDefs: if gbl.infile: error("No filename is permitted with the -g option") MMA.auto.libUpdate() # update and EXIT ################################ # We need an input file for anything after this point. if not gbl.infile: MMA.options.usage("No input filename specified.") ################################ # Just extract docs (-Dxh, etc) to stdout. if docOption: if docOption == 4: MMA.docs.htmlGraph(gbl.infile) else: f=MMA.file.locFile(gbl.infile, None) if not f: error("File '%s' not found" % gbl.infile) MMA.parse.parseFile(f) MMA.docs.docDump() sys.exit(0) ######################################################### # These cmdline options override settings in RC files if gbl.cmdSMF: gbl.lineno = -1 MMA.midifuncs.setMidiFileType(['SMF=%s' % gbl.cmdSMF]) ###################################### # Create the output filename MMA.paths.createOutfileName(".mid") ################################################ # Read/process files.... # First the mmastart files for f in gbl.mmaStart: fn = MMA.file.locFile(f, gbl.incPath) if not fn: warning("MmaStart file '%s' not found/processed" % fn) MMA.parse.parseFile(fn) gbl.lineno = -1 # The song file specified on the command line f = MMA.file.locFile(gbl.infile, None) if not f: gbl.lineno = -1 error("Input file '%s' not found" % gbl.infile) MMA.parse.parseFile(f) # Finally, the mmaend files for f in gbl.mmaEnd: fn = MMA.file.locFile(f, None) if not fn: warning("MmaEnd file '%s' not found/processed" % f) MMA.parse.parseFile(fn) ################################################# # Just display the channel assignments (-c) and exit... if gbl.chshow: print "\nFile '%s' parsed, but no MIDI file produced!" % gbl.infile print print "Tracks allocated:" k=gbl.tnames.keys() k.sort() max=0 for a in k + gbl.deletedTracks: if len(a)>max: max = len(a) max+=1 wrap=0 for a in k: wrap += max if wrap>60: wrap = max print print " %-*s" %( max, a), print print if gbl.deletedTracks: print "Deleted Tracks:" wrap=0 for a in gbl.deletedTracks: wrap += max if wrap>60: wrap=max print print " %-*s" %( max,a), print print print "Channel assignments:" for c, n in sorted(gbl.midiAssigns.items()): if n: wrap = 3 print " %2s" % c, for nn in n: wrap += max if wrap>63: print "\n ", wrap=max+3 print "%-*s" % (max,nn), print print sys.exit(0) #################################### # Dry run, no output if gbl.noOutput: warning( "Input file parsed successfully. No midi file generated") sys.exit(0) ############################## # Create the output (MIDI) file gbl.lineno=-1 # disable line nums for error/warning """ We fix the outPath now. This lets you set outpath in the song file. The filename "outfile" was created in paths, get a copy. It is either the input filename with '.mma' changed to '.mid' (or kar) OR if -f was used then it's just . If any of the following is true we skip inserting the outputpath into the filename: - if outfile starts with a '/' - if outPath was not set - if -f was used Next, the outPath is inserted into the filename. If outPath starts with a ".", "/" or "\ " then it is inserted at the start of the path; otherwise it is inserted before the filename portion. """ outfile = MMA.paths.outfile if (not outfile.startswith('/')) and gbl.outPath and not gbl.outfile and not gbl.playFile: if gbl.outPath[0] in '.\\/': outfile = "%s/%s" % (gbl.outPath, outfile) else: head, tail = os.path.split(outfile) outfile = "%s/%s/%s" % (head, gbl.outPath, tail) fileExist = os.path.exists(outfile) """ Check if any pending midi events are still around. Mostly this will be a DRUM event which was assigned to the 'DRUM' track, but no DRUM track was used, just DRUM-xx tracks used. """ for n in gbl.tnames.values(): if n.channel: n.doMidiClear() n.clearPending() n.doChannelReset() if n.riff: warning("%s has pending Riff(s)" % n.name) """ 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. """ trackCount=1 # account for meta track for n in sorted(gbl.mtrks.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) lyric.leftovers() if fileExist: print "Overwriting existing", else: print "Creating new", print "midi file (%s bars, %.2f min): '%s'" % (gbl.barNum, gbl.totTime, outfile) try: out = file(outfile, 'wb') except: error("Can't open file '%s' for writing" % outfile) MMA.midi.writeTracks(out) out.close() if gbl.playFile: import MMA.player MMA.player.playMidi(outfile) if gbl.debug: print "Completed processing file '%s'." % outfile