#!/bin/bash #=========================================================================== # File serialr.sh # usage .serialr.sh pi|mac # # Three manual options to be set below to configure program operation # For mac operation a further 4 context settings to be adjusted # This version adds random rhythms and works with Pi or Pi+Mac # # Written by Robin Newman, Aug 2013, based on a script by Jonathan Kulp (debug 10Mar2014) #=========================================================================== #three manually defined parameters verbose=FALSE #FALSE or TRUE. TRUE allows full output of process quitbrowser=TRUE #TRUE forces browser to quit at end of script or not if FALSE prefbrowser=netsurf #select midori or netsurf (for pi playback) #pibrowser is set to TRUE for local pi and FALSE to run tune on mac #now set by argument on command line #parse input argument and set pibrowser accordingly if [[ -z $1 || $1 != 'pi' && $1 != 'mac' ]] then echo "usage ./serialr.sh pi or ./serialr.sh mac" exit 1 fi if [ $1 = 'mac' ]; then pibrowser=FALSE;else pibrowser=TRUE;fi #------------ set up context variables for running on Mac ------------ pishare='/home/pi/pishare' #where share is mounted on the Pi macssh="rbn@192.168.1.12" #ssh logon to the Mac macbrowserapp="Firefox.app" #Browser to run on Mac (could be Safari.app,Google Chrome.app) macpathtoshare='/Users/rbn/Documents/pishare' #path to share on the Mac #you shouldn't need to configure anything after this line macbrowser=`echo $macbrowserapp | cut -d'.' -f1` #strips the .app from macbrowserapp quitscript=$PWD/quit.sh #------------ 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 } # ------------ 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 } #------------ 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) } #------------ 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 '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 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 24) \\set Staff.midiInstrument = "violin" \\partial 4 $lilypitches \\bar "|." } \\layout {} \\midi {} } EOFscore pvar 'The completed source lilyfile' lilyfile } # ------------ end of chords --------------- 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 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

EOFhtml if [ $pibrowser = FALSE ] #i.e. not to play on Pi add mp3 playback then cat >> $web << EOFhtml

mp3 file

EOFhtml fi cat >> $web << EOFhtml Generated with bash and Lilypond

generated on $(date)

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 } # ------------ 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 ---------------- mp3(){ #produce mp3 from midi file using timidity and lame. used on mac version `timidity -Ow -o - $midifile 2> /dev/null | lame - $mp3file &>/dev/null` #timidity creates.wav file which is piped to lame to give mp3 file #warning text suppressed from timidity with 2>/dev/null and #text op from lame with &>/dev/null } # ------------ end of mp3 ---------------- #------------ program commands start from here ------------- timestart if [ $pibrowser = "TRUE" ] #displaying on pi then #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 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' randombarnotes #at this stage random rhythm list is complete #assemble final tune getpitches addrhythms chords make_lily_file pvar lilyfile lilyfile timeduration echo 'Compiling lilyfile.ly with lilypond' runlily timeduration if [ $pibrowser = FALSE ] then echo making mp3 mp3 timeduration fi #sleep 25 #sync to next minute (tune this) html if [ $pibrowser = TRUE ] then if [ "$(pidof $prefbrowser)" ] #first kill existing browser if running then killall $prefbrowser fi echo Starting Web Browser if [ $prefbrowser = midori ] then $prefbrowser -e Fullscreen -a $web & # midori -e Fullscreen -a /tmp/tonerow.html & else $prefbrowser file://$web & # netsurf file:///tmp/tonerow.html 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 else #copy files to mac share echo 'move files to mac and open browser there' mkdir $pishare/tonerow 2>/dev/null #make tonerow directory, suppress error if already there cp /tmp/tone* $pishare/tonerow open firefox with html page by ssh to mac cmd='ssh '$macssh' " open -a /Applications/'$macbrowserapp'/ ' cmd+='file://'$macpathtoshare'/tonerow/tonerow.html"' eval $cmd #wait for tune to play sleep 24 #adjust if necessary if [ $quitbrowser = TRUE ] #then force browser to quit then echo 'close mac browser' cp $quitscript $pishare/tonerow #quit.sh used to quit Mac browser #use quit.sh script in tonerow folder to close Firefox again #this script is obtainable at http://mattdturner.com/resources/quit cmd='ssh '$macssh' "sh '$macpathtoshare'/tonerow/quit.sh ' cmd+=$macbrowser' &>/dev/null"' eval $cmd fi fi #clean stuff up rm /tmp/*.ily /tmp/*.eps echo "Finished!" timeduration #------------ end of script -------------