mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 11:14:00 +00:00
259 lines
6.1 KiB
Python
Executable File
259 lines
6.1 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
""" mup2mma extracts chords from a MUP music notation file and
|
|
creates a MMA file. For this to work the MUP file must use
|
|
the macro "C" for chord. In my MUP files I have the following:
|
|
|
|
define C bold (11) chord above all: @
|
|
|
|
This script just checks all input lines and assumes that anything
|
|
starting with "C" is a chord line.
|
|
|
|
Additional "features":
|
|
|
|
Lines in the form "// TEMPO: xx" generate a Tempo entry
|
|
"time =" lines are parsed for common time signatures
|
|
repeats are inserted as comment lines
|
|
|
|
0.3 - added options:
|
|
-m add melody lines
|
|
-l add lyrics
|
|
-o overwrite
|
|
|
|
0.4 - reformatted output
|
|
|
|
0.5 - corrected melody/lyric notation.
|
|
|
|
bvdp, Dec/2004
|
|
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import commands
|
|
import getopt
|
|
|
|
# Useful functions
|
|
|
|
def error(m=''):
|
|
print "Error: %s" % m
|
|
sys.exit(1)
|
|
|
|
def usage():
|
|
print "mup2mma - (c) Bob van der Poel"
|
|
print "Extract MMA data from MUP file."
|
|
print "Options:"
|
|
print " -o overwrite existing MMA file"
|
|
print " -m extract melody data"
|
|
print " -l extract lyric data"
|
|
print " -v print version"
|
|
sys.exit(0)
|
|
|
|
# Global variables
|
|
|
|
Version = '0.5'
|
|
|
|
overwrite = 0 # set if overwrite of old mma file okay
|
|
doLyric = 0 # set if we want lyrics output
|
|
doMelody = 0 # set if we want melody output
|
|
|
|
|
|
# Parse command line, open files
|
|
|
|
|
|
try:
|
|
opts, args = getopt.gnu_getopt(sys.argv[1:], "omlv")
|
|
except getopt.GetoptError:
|
|
usage()
|
|
|
|
for o,a in opts:
|
|
if o == '-o':
|
|
overwrite = 1
|
|
elif o == '-l':
|
|
doLyric = 1
|
|
elif o == '-m':
|
|
doMelody = 1
|
|
elif o == '-v':
|
|
print Version
|
|
sys.exit(0)
|
|
else:
|
|
usage()
|
|
|
|
if len(args) != 1:
|
|
error("Exactly 1 filename is required.")
|
|
|
|
infile = args[0]
|
|
|
|
outfile = os.path.basename(infile)
|
|
if outfile.endswith('.mup'):
|
|
outfile=outfile[:-4]
|
|
title=outfile.replace("-", ' ').title()
|
|
outfile += ".mma"
|
|
|
|
try:
|
|
bars = file(infile)
|
|
except:
|
|
error("Can't open input file '%s'." % infile)
|
|
|
|
if os.path.exists(outfile) and not overwrite:
|
|
error("File '%s' already exists." % outfile)
|
|
|
|
try:
|
|
out=file(outfile, "w")
|
|
except:
|
|
error("Can't open output file '%s'." % outfile)
|
|
|
|
# Input and output files open, start processing
|
|
|
|
out.write( "// %s\n\n" % title)
|
|
|
|
bnum = 1
|
|
|
|
donebar = 0
|
|
melody = ''
|
|
lyric = ''
|
|
chordList=[]
|
|
|
|
for b in bars:
|
|
b=b.strip()
|
|
if b=='': # skip empty lines
|
|
continue
|
|
|
|
if b.startswith("// TEMPO:"):
|
|
out.write("Tempo %s\n\n" % b.split()[2])
|
|
continue
|
|
|
|
# Parse out time sig from MUP
|
|
|
|
ck = b.split("=")
|
|
|
|
if len(ck) and ck[0].strip() == 'time':
|
|
ts=ck[1].strip()
|
|
if ts in ('common', '4/4'):
|
|
beats = 4
|
|
posStep = 1
|
|
|
|
elif ts in ('cut', '2/4', '2/2'):
|
|
beats = 2
|
|
posStep = .5
|
|
|
|
elif ts=='3/4':
|
|
beats = 3
|
|
posStep = 1
|
|
|
|
elif ts=='6/8':
|
|
beats = 6
|
|
posStep = 1
|
|
|
|
elif ts=='12/8':
|
|
beats = 12
|
|
posStep = 1
|
|
else:
|
|
error("Uknown time sig, %s" % b)
|
|
|
|
# Parse line number from MUP
|
|
|
|
if b.startswith('// #') or b.startswith('//# '):
|
|
bnum = b[4:]
|
|
|
|
# Parse out melody, lyric and chords.
|
|
# Melody must be a line starting with "M:"
|
|
# Lyric must be a line starting with "L:"
|
|
# Chord must be a line starting with "C "
|
|
|
|
key = b.split()[0]
|
|
|
|
|
|
if key == 'M:' and doMelody:
|
|
melody = b.split(' ', 1)[1]
|
|
|
|
elif key == 'L:' and doLyric:
|
|
lyric = b.split(' ', 1)[1]
|
|
|
|
elif key == 'C':
|
|
ch = b[2:]
|
|
ch=ch.replace ('"', ' ')
|
|
ch=ch.replace('&', 'b')
|
|
ch = ch[:-1]
|
|
ch=ch.split(';')
|
|
|
|
chordList = []
|
|
pos = 1.0
|
|
|
|
for c in ch:
|
|
c = c.split()
|
|
off = c[0]
|
|
|
|
# Strip out printing offset from chord. Since the position
|
|
# has been split off, we just strip out everything after the
|
|
# inital '['. If this doesn't work, then the MUP is wrong as well
|
|
# eg: 1.5[-5] becomes 1.5
|
|
|
|
if off.count('['):
|
|
off=off[:off.index('[')]
|
|
|
|
count = float(off)
|
|
|
|
while pos < count:
|
|
chordList.append('/')
|
|
pos += posStep
|
|
|
|
chord=c[1]
|
|
if chord.upper()=="TACET" or chord.upper()=='N.C':
|
|
chord = 'z'
|
|
|
|
chord = chord.replace('^', 'M')
|
|
chord = chord.replace('o', 'dim')
|
|
chord = chord.replace('\\(dim)', 'dim')
|
|
|
|
chordList.append(chord )
|
|
pos += posStep
|
|
|
|
|
|
elif key in ('bar', 'repeatend', 'endbar', 'dblbar', '(dblbar)',
|
|
'repeatstart', 'repeatboth' ):
|
|
|
|
out.write('%-4s' % bnum)
|
|
|
|
if not chordList:
|
|
chordList = ['/']
|
|
for a in chordList:
|
|
out.write((' %6s' % a).rstrip())
|
|
chordList = []
|
|
|
|
if doMelody and melody:
|
|
out.write((' { %s }' % melody).rstrip())
|
|
melody = ''
|
|
|
|
if doLyric and lyric:
|
|
out.write((' [ %s ]' % lyric).rstrip())
|
|
lyric = ''
|
|
|
|
out.write('\n')
|
|
|
|
if int(bnum) % 4 == 0: # put in blank line every 4 bars
|
|
out.write('\n')
|
|
|
|
if key == 'repeatend':
|
|
out.write( "\n// RepeatEnd\n\n")
|
|
if key == 'repeatboth':
|
|
out.write( "\n// RepeatEnd\n\n")
|
|
out.write( "// Repeat\n\n")
|
|
if key == "repeatstart" or key=='(dblbar)':
|
|
out.write( "\n// Repeat\n\n")
|
|
|
|
rpt = b.split()[1:]
|
|
|
|
if len(rpt) and rpt[0] == "ending":
|
|
out.write( '\n// RepeatEnding\n\n')
|
|
|
|
else:
|
|
pass # Just ignore other MUP stuff
|
|
|
|
out.write('\n')
|
|
out.close()
|
|
|
|
|
|
|
|
|