#!/bin/bash #=========================================================================== # File longplay.sh # Can be run in LXDE terminal with ./longplay.sh # Or from a remote ssh connection # This version adds random rhythms # Option verbose FALSE or TRUE to control information out # Option archivesave TRUE or FALSE enables each tune to be saved to an archive # Set archive path appropriately if used, (will be created if necessary) # Written by Robin Newman, Aug 2013, based on a script by Jonathan Kulp (debug 10Mar2014) #=========================================================================== #five manually defined parameters verbose=FALSE #FALSE or TRUE. TRUE allows full output of process prefbrowser=midori #select midori or netsurf quitbrowser=TRUE #TRUE forces browser to quit at end of script or not if FALSE archivesave=FALSE #set TRUE or FALSE to save archived tunes in archivepath archivepath=~/long/archive/ #set path to save timestamped archives (end in /) #------------ set up variables for filenames ------------ pitches=/tmp/pitches.ily #pitches in 12 tone scale random=/tmp/random.ily #pitches in scale in random order lilyfile=/tmp/tonerow.ly #completed source music file for lilypond midifile=/tmp/tonerow.midi #midifile created by lilypond mp3file=/tmp/tonerow.mp3 #mp3 file created from the midi file by timidity stem=$(readlink -f $lilyfile | sed -e 's/\..*$//') #prefix path for tone* files withrhythms=/tmp/withrhythms.ily #used to hold assembled lilypond tune code #following files used in generation of random rhythms for the notes allowed3bars=/tmp/allowed3bars.ily #3 bar patterns of 3/4 bars 11 notes in total barnames=/tmp/barnames.ily #names of the 28 bar structures barlist=/tmp/barlist.ily #all the possible 3/4 bar rhythms #for 1 to 6 notes restricted to lengths 1 2 3 subbarlist=/tmp/subbarlist.ily #used to hold all the bar choices for a given number of notes in the bar chosenlist=/tmp/chosenlist.ily # 3 bar list chosen from barlist rbars=/tmp/rbars.ily #used to hold the chosen 3 bar lengths in random order barnotes=/tmp/tune.ily #bar note values for each of the three bars in turn randombarnotes=/tmp/randomtune.ily #assemble chosen note durations inc upbeat # ------------ end of file variable setup --------------- # ------------ start definition of functions --------------- pvar(){ #used to print a text string, a variable name and cat the contents (if a file) # or echo if not. Uses two supplied arguments $1 and $2 if [ $verbose = TRUE ] #allows suppression if not verbose mode then echo -e '==========\n'$1' (variable name '$2')'; if [ -f ${!2} ] #variable name passed as parameter is dereferenced to get the value #using the format ${!2} then cat ${!2} else echo ${!2} fi echo -e '==========\n' fi } # ------------ end of pvar --------------- getpitches (){ #makes a file of the pitches in the 12 tone scale and then puts in random order # first make a list of all 12 chromatic pitches # using lilypond's naming conventions # one per line b/c it's easier to shuffle, add rhythms, etc cat > $pitches << EOFallpitches c' cis' d' dis' e' f' fis' g' gis' a' bes' b' EOFallpitches # now run them through the shuf command to put them in random order shuf $pitches > $random pvar 'The 12 note pitches in random order' random } # ------------ end of getpitches --------------- getallowedbars () { #read in list of allowed bar patterns for 3 bars of 11 notes total cat > $allowed3bars << EOFallowed3bars 146 155 236 245 335 344 EOFallowed3bars pvar "allowed 3 bar lengths" allowed3bars } #------------ end of getallowedbars ------------ getbarlist () { #generates a file containing the structure of the 28 possible distinct #bar types in the structure name n n n x #first build as a string b="1n1 2. x " b+="2n1 2 4 x 2n2 4. 4. x " b+="3n1 4.. 4 16 x 3n2 4.. 8. 8 x 3n3 4. 4 8 x 3n4 4. 8. 8. x \ 3n5 4 4. 8 x 3n6 4 4 4 x " b+="4n1 2 8 16 16 x 4n2 4.. 8. 16 16 x 4n3 4.. 8 8 16 x 4n4 4. 4 16 16 \ x 4n5 4. 8. 8 16 x 4n6 4 4 8. 16 x 4n7 4 4 8 8 x 4n8 8. 8. 8. 8. x " b+="5n1 2 16 16 16 16 x 5n2 4.. 8 16 16 16 x 5n3 4. 8. 16 16 16 \ x 5n4 4. 8 8 16 16 x 5n5 4 4 8 16 16 x 5n6 4 8. 8 8 16 x 5n7 4 8 8 8 8 x " b+="6n1 4. 8 16 16 16 16 x 6n2 4 4 16 16 16 16 x 6n3 4 8. 8 16 16 16 \ x 6n4 4 8 8 8 16 16 x" echo $b |sed -e 's/\s\s*/\n/g' > $barlist #convert string to file with one entry on each line (spaces replaced by LF) pvar 'list of bar structures' barlist } #------------ end of getbarlist ------------ make_top_lily_file (){ # determine lilypond version for later inclusion version=$(lilypond --version | grep LilyPond | cut -d " " -f3) # make it cat the random list of pitches lilypitches=$(cat $withrhythms) # assemble the lilypond source file, sticking the # pitches in at the right place cat > $lilyfile << EOFscore \\score { { \\version "$version" \\time 3/4 \\tempo 4 = 100 #(set-accidental-style 'dodecaphonic) #(set-global-staff-size 22) \\set Staff.midiInstrument = "violin" \\partial 4 $lilypitches EOFscore } next_tune (){ #add next tune to lilypond file lilypitches=$(cat $withrhythms) cat >> $lilyfile << EOFnotes r 4 r 4 $lilypitches EOFnotes } make_bottom_lily_file (){ # determine lilypond version for later inclusion version=$(lilypond --version | grep LilyPond | cut -d " " -f3) # make it cat the random list of pitches lilypitches=$(cat $withrhythms) # assemble the lilypond source file, sticking the # pitches in at the right place cat >> $lilyfile << EOFscore \\bar "|." } \\layout {} \\midi {} } EOFscore pvar 'The completed source lilyfile' lilyfile } runlilyandcrop(){ # compile the score redirecting all console output to /dev/null lilycmd="lilypond -fpng" $lilycmd $lilyfile &> /dev/null echo 'cropping...' convert tonerow.png -gravity South -chop 0x250 tonerowcropped.png mv tonerowcropped.png tonerow.png } # ------------ end of runlily --------------- html-long(){ #generate html file web="$stem".html image="$stem".preview.png midi="$stem".midi mdate=`date +%Y-%m-%d-%H-%M-%S` #for archive date mdate2=`date` #for html date cat > $web << EOFhtml 12-Tone Tune of the Day

Multiple Random 12-Tone Tunes, with random rhythms

randomly generated 12-tone
rows

Midi file

Generated with bash and Lilypond

generated on $mdate2

Modified and developed by Robin Newman from an original script by Jonathan Kulp

EOFhtml pvar 'The html page' web } # ------------ end of html --------------- initrandombarnotes () { #put 4 (crotchet duration) as first note value of randombarnotes cat > $randombarnotes << EOFnotes 4 EOFnotes } # ------------ end of initrandombarnotes ---------------- getbarnames() { #generate list of barnames from barlist cat $barlist |sed -n /n/p > $barnames #generate list of barnames from barlist pvar 'list of barnames from barlist' barnames } # ------------ end of getbarnames ---------------- makechosenbarsfile() { #generate a file containing the number of notes in each of the three tune bars shuf $allowed3bars > $chosenlist #get allowed bars in random order pvar 'Shuffled list' chosenlist cat $chosenlist |sed q > $rbars #select 1st line of randomised allowed bars list pvar 'Chosen 3 bars' rbars #this is the number we want. Need individual digits shuffled cat $rbars |sed -e 's/\(.\)/\1\n/g'| sed -e '$d' >$chosenlist #write 3 digit number to a file 1 digit per line pvar 'Chosen 3 bars in a list' chosenlist shuf $chosenlist > $rbars #put thes number in random order pvar 'Chosen 3 bars in random order list' rbars } # ------------ end of makechosenbarsfile ---------------- fillbar() { #add random rhythm for bar with number of notes in supplied arg $1 action=`cat $rbars |sed -n "$1{p;q;}"` #select no of notes from the list echo bar $1 has $action notes sed -n /${action}n/p $barnames > $subbarlist #get list of possible barnames pvar 'possible bar names' subbarlist read -r firstchoice < <(shuf $subbarlist) #shuffle and take first one as choice pvar Choice firstchoice cat $barlist | sed -n "/${firstchoice}/{:a;n;/x/q;p;ba}" > $barnotes #extract relevant note durations from barlist to barnotes shuf $barnotes >> $randombarnotes #put durations in random order and add to randombarnotes pvar barnotes barnotes } # ------------ end of fillbar ---------------- addrhythms() { #merges the pitches and durations together to get tune paste -d " " $random $randombarnotes > $withrhythms pvar 'random tune' withrhythms } # ------------ end of addrhythms ---------------- timestart() { #initialise a datetimevariable date1=$(date +"%s") echo "Lapsed time initialised to 0" } # ------------ end of timestart ---------------- timeduration() { #calculate elapsed time from timestart and print date2=$(date +"%s") diff=$(($date2-$date1)) echo "Total $(($diff / 60)) minutes and $(($diff % 60)) seconds elapsed." } # ------------ end of timeduratiopn ---------------- archive(){ #archive the tonerow folder archdir=$archivepath'tone-'$mdate #$made date/time from html function mkdir -p $archdir #-p in case path doesn't exist cp /tmp/tone* $archdir } # ------------ end of archive ---------------- #------------ program commands start from here ------------- timestart #check if Desktop is running if [[ `pidof lxsession` = "" ]] then echo 'no desktop running on the Pi.startx & from this terminal, then rerun' exit else export DISPLAY=:0 fi echo prefbrowser is $prefbrowser #print preferred browser name echo 'Generating source music file lilyfile.ly' cd /tmp #work in temp directory ############ make first 12 bar tune, configured with upbeat getbarlist getbarnames getallowedbars initrandombarnotes makechosenbarsfile fillbar 1 fillbar 2 fillbar 3 pvar 'randomised rhythms for each of the three bars joined to first note' randombarnotes #at this stage random rhythm list is complete #assemble tune getpitches addrhythms make_top_lily_file # create top section of lilypond source file including notes for tune 1 #repeat next section as desired####################################### for i in {1..11} do getallowedbars initrandombarnotes makechosenbarsfile fillbar 1 fillbar 2 fillbar 3 pvar 'randomised rhythms for each of the three bars joined to first note' randombarnotes #at this stage random rhythm list is complete #assemble the notes and add to the existing tune getpitches addrhythms next_tune #this adds the next set of notes, preceded with two crotchet rests 4 4 done #end of repeated section########################################### make_bottom_lily_file #add the remainder of the source file code cat $lilyfile echo 'Compiling lilyfile.ly with lilypond' runlilyandcrop #run lilypond command to generate a png output and crop bottom of image sleep 0.5 timeduration html-long #run code to assemble the html page echo 'html made' if [ "$(pidof $prefbrowser)" ] #first kill existing browser if running then killall $prefbrowser fi echo 'Starting Web Browser' if [ $prefbrowser = midori ] then #rm -f ~/.config/midori/session.xbel $prefbrowser -e Fullscreen -a $web & else $prefbrowser file://$web & fi sleep 4 #allow time for web browser to open echo Playing midi file sleep 2 timidity $midifile &> /dev/null #play midi file #wait before killing browser sleep 2 if [ $quitbrowser = TRUE ] #then force browser to quit then killall $prefbrowser echo browser killed fi #clean stuff up rm /tmp/*.ily if [ $archivesave = "TRUE" ] then echo 'Archiving';archive fi echo "Finished!" timeduration #------------ end of script -------------