# splitvoices [ -s stafflist ] mup_input_file # # This command looks for Mup input lines for music data on the specified # staffs, or all staffs if no list is given. These lines must not be # specifying voice numbers, and must not be continued onto the next line # by using a backslash. # # The program duplicates these lines, separating them into lines for # voice 1 and voice 2. (It passes other lines through unchanged.) For # chords with one note, both lines get the note. # For chords that have more than one note, # voice 2 gets the first note and voice 1 gets the rest. The program # also outputs lines to set vscheme to 2o for these staffs. # # The program reads the given file name and writes to standard output. # It is not bulletproof. For one thing, it gets confused by notes with # slur angle brackets. But it gets most of the lines right. function usage() { echo "Usage: $0 [ -s comma_separated_list_of_staffs ] mup_input_file" >&2 exit 1 } # Parse the command line options, setting up SL (staff list) and Mup FILE name. case $# in 1) SL=$(gawk ' BEGIN { for (n = 1; n < 32; n++) printf("%d,", n) printf("32") } ' /dev/null ) FILE="$1" ;; 2) if [ $(expr "$1" : '-s[0-9][0-9,]*') -eq 0 ] then usage fi SL=$(echo "$1" | sed -e 's/..//') FILE="$2" ;; 3) if [ "$1" != "-s" ] then usage fi SL="$2" FILE="$3" ;; *) usage ;; esac # Enforce the comma separated list of staff numbers (although we don't try to # block 0 or numbers greater than 40). if [ $(expr "$SL" : '[0-9][0-9,]*') -eq 0 -o $(expr "$SL" : '.*,$') -ne 0 \ -o $(expr "$SL" : '.*,,.*') -ne 0 ] then usage fi if [ ! -f "$FILE" -o ! -r "$FILE" ] then echo "$0: file $FILE is not readable" >&2 exit 1 fi if [ $(grep -c '^[ ]*[0-9][0-9]*[ ]*:.*<[^>]*[a-g]' "$FILE") -ne 0 ] then echo "$0: warning: the results may be bad; we can't handle slurs using '< >' with a note letter inside" >&2 fi # Find the first staffs=X line, if any. Hopefully there won't be more than # one, since things might gets hosed later. Store the number. If no lines # are found, use 0. MAXSTAFF=$(grep 'staffs[ ]*=[ ]*[0-9]' "$FILE" | head -1 | sed -e 's/.*staffs[ ]*=[ ]*//' -e 's/[^0-9].*//') if [ -z "$MAXSTAFF" ] then MAXSTAFF=0 fi # Prefix music lines that should be split, with "VOICE1" and "VOICE2". Also # try to output settings of vscheme at an appropriate place. gawk ' BEGIN { # get the maximum staff number maxstaff = '$MAXSTAFF' if (maxstaff == 0) { # none found, so there is really just one staff, and # we can set vscheme right here at the start print "score" print " vscheme = 2o" print "music" didit = 1 allstaff = 1 } else { # load the si array so that it is indexed by all the # valid staff numbers in $SL split("'$SL'", staff, ",") for (s in staff) { if (staff[s] <= maxstaff) { si[staff[s]] = 1 } } } } # remember that we have seen this line; after this it is safe to set # vscheme for the needed staffs /staffs[ ]*=[ ]*[0-9]/ { gotstaffs = 1 } # at the first "music" after the staffs line, if we have not yet done # this, set the vschemes /^[ ]*music/ && gotstaffs && ! didit { for (s in si) { print "staff " s print " vscheme = 2o" } didit = 1 } # match a line of music data for some staff /^[ ]*[0-9][0-9]*[ ]*:/ { # get the staff number in sn sn = $0 sub(/[^0-9]*/, "", sn) sub(/[^0-9].*/, "", sn) # if it is one of the ones we are to split, duplicate the line, # putting labels on it for sed; otherwise print unchanged if (sn in si || allstaff) { print "VOICE1:" $0 print "VOICE2:" $0 } else { print } next } # Pass all other lines through unchanged. { print } ' "$FILE" | # Try to strip the appropriate note(s) and associated things from each chord. # We translate "tie" to "tiE" and back to avoid getting confused by the "e". sed \ -e 's/tie/tiE/g' \ -e '/^VOICE1:/s/\([a-g][^a-g;]*\)\([a-g][^;]*\)/\2/g' \ -e '/^VOICE1:/s/VOICE1:\([^:]*\)/\1 1/' \ -e '/^VOICE2:/s/\([a-g][^a-g;]*\)\([a-g][^st;]*\)/\1/g' \ -e '/^VOICE2:/s/VOICE2:\([^:]*\)/\1 2/' \ -e 's/tiE/tie/g' exit 0