#!/bin/bash #=========================================================================== # File serialrpi.sh # Can be run in LXDE terminal with ./serialrpi.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=TRUE #set TRUE or FALSE to save archived tunes in archivepath archivepath=~/tonearchive/ #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 chordOne=/tmp/chord1.ily #lilypond code for the first chord chordTwo=/tmp/chord2.ily #lilypond code for the second chord chordThree=/tmp/chord3.ily #lilypond code for the third chord #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 ------------ chords(){ # stack up the notes of the row in 3 chords of (re -e 'P;D') # 4 notes each #NB modified from original script which didn't work for me cat $random | sed -n '1,4p' \ | sed -e :a -e '$!N;s/\n/ /;ta' \ | sed -e 's/.*/<&>2/' > $chordOne cat $random | sed -n '5,8p' \ | sed -e :a -e '$!N;s/\n/ /;ta' \ | sed -e 's/.*/<&>4/' > $chordTwo cat $random | sed -n '9,12p' \ | sed -e :a -e '$!N;s/\n/ /;ta' \ | sed -e 's/.*/<&>2./' > $chordThree pvar '1st chord' chordOne pvar '2nd chord' chordTwo pvar '3rd chord' chordThree } # ------------ end of chords --------------- make_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 $chordOne $chordTwo $chordThree) # 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 \\bar "|." } \\layout {} \\midi {} } EOFscore pvar 'The completed source lilyfile' lilyfile } # ------------ end of make_lily_file --------------- runlily(){ # compile the score redirecting all console output to /dev/null lilycmd="lilypond -dno-point-and-click -ddelete-intermediate-files -dpreview" $lilycmd $lilyfile &> /dev/null } # ------------ end of runlily --------------- html(){ #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

Random 12-Tone Tune of the Day, with random rhythms

randomly generated 12-tone
row

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 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 final tune getpitches addrhythms chords make_lily_file timeduration echo 'Compiling lilyfile.ly with lilypond' runlily sleep 0.5 timeduration html 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 /tmp/*.eps if [ $archivesave = "TRUE" ] then echo 'Archiving';archive fi echo "Finished!" timeduration #------------ end of script -------------