sly.txt contains the entire distribution. (c)2002 David Raleigh Arnold This software is completely free for all under the rules of GNU. sly is just a tiny trivial bash script which takes a file with extension .sly and splits it into parts to be read by lilypond in an .ly file by means of includes. While it is designed entirely for lilypond, it could probably be useful for any text based music entry where the music can be entered by voices rather than comb fashion. pt1 | pt2 | pt3 etc. pt1 | pt2 | pt3 pt1 | pt2 | pt3 pt1 | pt2 | pt3 etc. Here is sly. Make it executable and put it in bachfrag and run it ./sly, or put it in your path (suggestion: ~/bin) ----begin sly executable. cut here -- #!/bin/bash # sly (c)2002David Raleigh Arnold free for all under GNU etc.etc. # syntax: sly infilename outfilename # Two arguments are required for a good outcome, but they can # be the same. infilename file must have .sly extension but # leave it off in the argument. # outfilename will be the name of outfilename-ptn.ly files. # That's what you include in your .ly file. Nothing messes # with your .ly file, unless you put "-pt" in its name, # an unlikely mistake, we hope. # ptfilter.sed must exist in current directory. It can be # empty though, in case you don't want to use it or I have # screwed it up. touch ptfilter.sed # clobber old $2-ptn.ly files, and get rid of error message # if there are none such files. rm $2-pt* 2> /dev/null # Get the number of fields in the record with the most. fieldnum=$(gawk 'BEGIN{FS=" \\|"}{OFS=" |"} {print NF}' $1.sly | sort -r | head -n1) count=1 while [ $count -le $fieldnum ] do gawk 'BEGIN {FS=" \\|"}{OFS=" |"}{print $i} ' i=$count $1.sly | sed -f ptfilter.sed > $2-pt$count.ly let "count = $count + 1" done ========== end sly cut here To demonstrate its use, here is an .ly file, namely bachfrag.ly. Put this project in its own directory, maybe bachfrag? ----begin bachfrag.ly Put in bachfrag directory. --cut here \version "1.4.13" \header { title = "Bachfrag" composer = "J. S. Bach" copyright = "\center \Public Domain \copyright2002 David Raleigh Arnold. Relinquished under GNU etc.etc.. 22m 1p." } \include "english.ly" \paper { papersize = "letter" } \include "paper20.ly" \score { < \property Score.Stem \override #'thickness = #1.0 \context Staff = guitar < \property Staff.instrument = "Guitar" \property Staff.midiInstrument = #"acoustic guitar (nylon)" \context Voice = upper \notes { \clef "G_8" \time 4/4 \key d \minor \stemUp \include "bachfrag-pt1.ly" } \context Voice = bass \notes { \stemDown \dotsDown \include "bachfrag-pt2.ly" } > > \paper {pagenumber = no linewidth = 19.0 \cm textheight = 10.0 \in } \midi { \tempo 4=90 } } ==========end bachfrag.ly=== cut here ==== That's it for bachfrag.ly. With any luck at all, I won't have to touch it again, hardly. ;-) And here we have a sly file, bachfrag.sly. I started by entering some of the notes in the first six lines of music in the "upper" part. I entered a different time signature so that the result could be checked more easily. Writing music from top to bottom instead of left to right will take no time at all to get used to. To copy a line is to copy a measure, so I only had to type 18 notes below. Because of filtration by the sed program, lilypond does not see the " |"s, which are the field separators. *(1) ---bachfrag.sly Put in bachfrag directory \time 3/8 % bachfrag.sly |% no notes in the 2nd part yet % this is in first part | % this is in 2nd part % lines don't **have** to be measures. | d16 d' f' a' a fs| | % make sure comments d16 d' f' a' a fs| | % **follow** the notes d16 d' g' bf' bf g| | % on a given line d16 d' g' bf' bf g| | d16 cs' e' g' bf g| | d16 cs' e' g' bf g| | ======================== Run sly bachfrag bachfrag, using bachfrag.sly, above. I used the same name for the input bachfrag.sly and the .ly file, but it is not necessary to do so. It is desirable to clobber the included part files when they are changed, and you can include with any -ptn.ly. This arrangement gives you tons of flexibility. You could write your string parts and chorus parts in different files. You don't have to use all the files generated, either, so you could use a dummy part to help coordinate things. You can also back up your parts this way, so a version wouldn't be clobbered. If you haven't put ptfilter.sed in yet, it was created as a 0 byte file when you ran the previous. You want to put it in now, to do the * substitutions. This must be in current directory, so you need a separate copy for each project. Trust me, this is a good idea. -------------- begin ptfilter.sed **current directory** # replace tabs with spaces. s/ / contains a tab, really. # if you lose it, put it back. s/ / /g # remove leading spaces s/^ *//g # remove trailing spaces s/ *$//g # remove double spaces s/ */ /g # this routine stops processing at NoP, resumes at eof or NoNOP /NoP/{ :top s/NoP// n s/NoNOP// t b top } # this comments, adds \mr. Define \mr in .ly /KiLL/{ s/KiLL/\\mr % / :killing n s/NoKILL// t s/^/\\mr % / b killing } # this plugin routine replaces gub gub re* * with regub gub # skip ** if two and write one after this procedure. s/\*\*/TwoAsterisksWriteOne/g :again /\*/{ s/\([^ ]*\)[^\*]*\*/&\1/ s/[^ ]*// s/^ //g s/\*// t again } s/TwoAsterisksWriteOne/\*/g # this is a working example of placing commands before and after following word. # keep this as a template, it is a bit tricky, and not well tested. :domore /@mc/{ s/@mc *\([^ ]*\)/mycommand1 \1 mycommand2 / t domore } # this is a working example of simple substitution. s/lD /\\stemDown /g # persistent forceshift, eg: @s-1.3. Put reverts in .ly s/@s/\\property Voice.NoteColumn \\override #'force-hshift = #/g =============end ptfilter.sed Now we clean up and line up. sly-tidy will line up the "|"s but not the rest. Run it in a buffer. Emacs-xemacs does rectangular editing. How sweet it is! It would probably be quicker and easier to record a keyboard macro and use it on each line, but I want to learn rectangular editing first. Incidently, if you run this, there will be a bachfrag-pt2.ly created. If there were not, lilypond would protest trying to find the nonexistent included file. -----bachfrag.sly d16 d' f' a' a fs | d16 d' f' a' a fs | d16 d' g' bf' bf g | d16 d' g' bf' bf g | d16 cs' e' g' bf g | d16 cs' e' g' bf g | ===================== After rectangular editing and some regular, bachfrag.sly is below. There was no typing of pitches below, just cutting and pasting. What's wrong with using rests instead of the double stem notes? *(2) ptfilter.sed must be in the current directory. It does the "*" substitutions and potentially a lot more, because it makes it possible to pass a value to a lilypond macro by writing the macro with the value into the part. A few alt-key macros could do wonders in emacs also to make rectangular editing (everyone else calls it column copying) go quicker and easier. Cooledit does it really well. It would be a mistake not to make a new copy of ptfilter.sed for each project, because there are likely to be many opportunities to customize it for specific projects, and it is a *very* powerful tool. ---------------------bachfrag.sly d16 d' f' a' f' d' f' d' a d' fs d' | d a fs *4 r4 *8 * d16 d' f' a' f' d' f' d' a d' fs d' | d a fs *4 r4 *8 * d16 d' g' bf' g' d' g' d' bf d' g d' | d bf g *4 r4 *8 * d16 d' g' bf' g' d' g' d' bf d' g d' | d bf g *4 r4 *8 * d16 cs' e' g' e' cs' e' cs' bf cs' g cs' | d bf g *4 r4 *8 * d16 cs' e' g' e' cs' e' cs' bf cs' g cs' | d bf g *4 r4 *8 * =============== I'll do another big chunk, but I won't finish. --------------------bachfrag.sly d16 d' f' a' f' d' f' d' a d' f d' | d a f *4 r4 *8 * d16 d' f' a' f' d' f' d' a d' f d' | d a f *4 r4 *8 * d16 d' g' bf' g' d' g' d' bf d' g d' | d bf g *4 r4 *8 * d16 d' g' bf' g' d' g' d' bf d' g d' | d bf g *4 r4 *8 * d16 cs' e' g' e' cs' e' cs' bf cs' g cs' | d bf g *4 r4 *8 * d16 cs' e' g' e' cs' e' cs' bf cs' g cs' | d bf g *4 r4 *8 * d a d' f' d' a d' a f a d a | d f d *4 r4 *8 * c a d' f' d' a d' a f a d a | c f d *4 r4 *8 * bf, a d' f' d' a d' a f a d a | bf, f d *4 r4 *8 * a, a d' f' d' a d' a f a d a | a, f d *4 r4 *8 * gs, b d' f' d' b d' b f b d b | gs, f d *4 r4 *8 * gs, b d' f' d' b d' b gs b e b | gs, gs e *4 r4 *8 * a, b c' e' c' b c' b e b c b | a, e c *4 r4 *8 * a, a c' e' c' a c' a c a a, a | a, c a, *4 r4 *8 * f, c' e' a' e' c' e' c' a c' f c' | f, a f *4 r4 *8 * d b f' a' f' b f' b d b b, b | d d b, *4 r4 *8 * e, b d' gs' d' b d' b e b b, b | e, e b, *4 r4 *8 * e, b d' gs' d' b d' b e b b, b | e, e b, *4 r4 *8 * e, c' e' a' e' c' e' c' e c' c c' | e, e c *4 r4 *8 * e, d' gs' b' gs' d' gs' d' f d' d d' | e, f d *4 r4 *8 * e, e' a' c'' a' e' a' e' a e' e e' | e, a e *4 r4 *8 * e, e' gs' d'' gs' e' gs' e' b e' gs e' | e, b gs *4 r4 *8 * ================= The advantages of taking the notes out of the .ly file now become very apparent, if you want to repeat or move sections, add fingering, add or remove another part, tweak spacing or collisions, make a midi version, score for different instruments, etc. etc. Those who, like me, have suspended work on large projects because of the difficulty of revising notes in .ly can resume work, and you can finally score that symphony you wrote. An additional luxury is that lilypond will give you the line and column in your -ptn.ly file when it finds errors, so it is super easy to find the offending dot or comma in your score. sly-tidy vertically aligns the field separators by inserting spaces. Syntax: sly-tidy filename sly-pack takes out unnecessary spaces, for shipping or storage. Syntax: sly-pack filename (not done yet) sly-mate performs a matrix transform on the file. Syntax: sly-mate filename (not done yet) All of these simply dump their output to screen or, using emacs-xemacs, to a buffer. :-). Let's run sly-tidy on bachfrag.sly ---------------begin sly-tidy executable #!/bin/bash # sly-tidy (c)2002 David Raleigh Arnold under GNU etc etc etc. A trivial # utility which lines up the | bars in a file which uses a space followed # by a bar as a field separator. If there is no space after the bar it # inserts one. It gets rid of tabs. It does not affect bars not preceded # by a space. # Usage: ptidy filename" # Result: dump to console. Redirect, or use in emacs-xemacs buffer." # This is very ugly, but I am no programmer. cp $1 tempfile0 sed ' s/ / /g s/ |/ | /g s/^ *//g s/ *$//g s/ */ /g /^ $/d /^$/d ' tempfile0 > tempfile1 echo "" >> tempfile1 tac tempfile1 | gawk 'BEGIN {FS=" \\|"}{OFS=" |"}{ for(i = 1; i <= NF; i++ ){ while (len[i] < length($i) ){ len[i]++ } while (len[i] > length($i)){ $i = $i " " } } print $0 > "tempfile2" }' tac tempfile2 | gawk 'BEGIN {FS=" \\|"}{OFS=" |"}{ for(i = 1; i <= NF; i++ ){ while (len[i] < length($i) ){ len[i]++ } while (len[i] > length($i)){ $i = $i " " } } print $0 > "tempfile3" }' sed ' /^$/d ' tempfile3 rm tempfile? ========================= ------------bachfrag.sly d16 d' f' a' f' d' f' d' a d' f d' | d a f *4 r4 *8 * d16 d' f' a' f' d' f' d' a d' f d' | d a f *4 r4 *8 * d16 d' g' bf' g' d' g' d' bf d' g d' | d bf g *4 r4 *8 * d16 d' g' bf' g' d' g' d' bf d' g d' | d bf g *4 r4 *8 * d16 cs' e' g' e' cs' e' cs' bf cs' g cs' | d bf g *4 r4 *8 * d16 cs' e' g' e' cs' e' cs' bf cs' g cs' | d bf g *4 r4 *8 * d a d' f' d' a d' a f a d a | d f d *4 r4 *8 * c a d' f' d' a d' a f a d a | c f d *4 r4 *8 * bf, a d' f' d' a d' a f a d a | bf, f d *4 r4 *8 * a, a d' f' d' a d' a f a d a | a, f d *4 r4 *8 * gs, b d' f' d' b d' b f b d b | gs, f d *4 r4 *8 * gs, b d' f' d' b d' b gs b e b | gs, gs e *4 r4 *8 * a, b c' e' c' b c' b e b c b | a, e c *4 r4 *8 * a, a c' e' c' a c' a c a a, a | a, c a, *4 r4 *8 * f, c' e' a' e' c' e' c' a c' f c' | f, a f *4 r4 *8 * d b f' a' f' b f' b d b b, b | d d b, *4 r4 *8 * e, b d' gs' d' b d' b e b b, b | e, e b, *4 r4 *8 * e, b d' gs' d' b d' b e b b, b | e, e b, *4 r4 *8 * e, c' e' a' e' c' e' c' e c' c c' | e, e c *4 r4 *8 * e, d' gs' b' gs' d' gs' d' f d' d d' | e, f d *4 r4 *8 * e, e' a' c'' a' e' a' e' a e' e e' | e, a e *4 r4 *8 * e, e' gs' d'' gs' e' gs' e' b e' gs e' | e, b gs *4 r4 *8 * ======================== Just a hair prettier, wouldn't you say? %%%%%%%%%%%%%% End Notes (1) If you want to use barchecks, "|" is not a field separator. So " |c4" has one, but "c4| " will cause a barcheck to be present in the part. A "|" at the beginning of a line will also come through as a barcheck. An easier way to use barchecks is to perform a matrix transform on the suspect -ptn.ly files with sly-mate. 1 1 1 becomes 1 | 1 | 1 and vice-versa. Using sly-mate on your score: 1 | 2 1 | 2 1 | 2 becomes 1 | 1 | 1 2 | 2 | 2 and vice-versa. It will also remove excess whitespace from the document. (2) This piece was written in tablature for baroque lute. The first three notes in the top part should all sustain, the way they would on a lute. To write this literally would require four parts on the staff, and certainly look much more complex than it should. This form of notation has the clear implication that the top notes should be sustained severally, and not played as one legato voice. This has been utterly standard practice in guitar music for almost two centuries. Also, the rule is that a rest for an inside part is before a stem even if the stem is down. This way it is always possible to keep track of which voice is in which part, and sometimes it is impossible to do three parts intelligibly in any other way. I would cite the first "prelude" in the Carcassi method, possibly the most successful music book of all time, and also the first "andante", as clear examples of how this practice was supposed to work for the performer. The simple fact is that the "experts" are just plain much more ignorant than they should be, and that therefore every single guitar edition of this piece that I have ever seen is noted wrong. Furthermore, the Carcassi example (1826) used a half note with eighth stem up. Even with a dotted half note it was commonplace, and since the larger time value always got the dot, there was absolutely nothing ambiguous about it. Of course no piano player would sustain those notes, nor should he, he's playing a piano. Nor would he see anything wrong with using two noteheads when there is only one string or key, nor should he, he's playing a piano. But that's no excuse for that level of ignorance in people who consider themselves authorities.