#!/bin/bash VERSION="0.3.5" # History: # 0.3.5 : derived from copy left on daughter's computer # fixed issue with mega-outro when no bridge # 0.3: Less dice-like, more song-like # 0.2: Enable --min and min length # 0.1: First song written set -e set -u function showVersion() { echo "$0 Version $VERSION" } MINLENGTH=120 MAXLENGTH=0 CHORUS_REQUIRED=0 FEAT_BRIDGE=1 DEBUG_LEVEL=0 MAX_VERSES=20 MAX_CHORUS=20 # We won't reduce further than this REDUCE_MIN_VERSES=2 function showHelp() { local chorus_req="" local chorus_opt="" local bridge_on="" local bridge_off="" if [ $CHORUS_REQUIRED -gt 0 ] ; then chorus_req="[DEFAULT]" ; else chorus_opt="[DEFAULT]" ; fi if [ $FEAT_BRIDGE -gt 0 ] ; then bridge_on="[DEFAULT]" ; else bridge_off="[DEFAULT]" ; fi cat << FEOF $0 [args] > out-file.ly Arguments include: -m|--min SECONDS ($MINLENGTH) : Require songs to be SECONDS long. Will clear MAX setting, if greater. -M|--max SECONDS ($MAXLENGTH) : Prevent songs from being over SECONDS long. Will clear MIN setting, if lesser. --chorus-required: Number of choruses are 1-6 ${chorus_req} --chorus-optional: Number of choruses are 0-5 ${chorus_opt} --reduce-min-verses REDUCE_LIMIT ($REDUCE_MIN_VERSES) : When reducing to reach the MIN setting, don't reduce to less than REDUCE_LIMIT verses. --feat-bridge : Use a bridge ${bridge_on} Note that if bridges are specified, they will always be present. --no-feat-bridge : Do not use a bridge ${bridge_off} --epic : Same as: -m 180 -M 235 --chorus-required Song length 3:00 to 3:55; without bridge --song : Same as: -m 120 -M 180 --feat-bridge --chorus-required Song length 2:00 to 3:00; with bridge --ringtone : Same as: -m 45 -M 75 --reduce-min-verses 1 --chorus-optional --no-feat-bridge Song length: 0:45 to 1:15; Choruses and Verses optional; No bridge --alert : Same as: -m 25 -M 35 --reduce-min-verses 0 --chorus-optional --no-feat-bridge Song length: 0:25 to 0:35; Choruses and Verses optional; No bridge -d|--debug : add to the debug level -h|--help : show this help message --version : show the version number FEOF } while [ $# -gt 0 ] ; do case "$1" in -d|--debug) DEBUG_LEVEL=$(( $DEBUG_LEVEL + 1 )) ;; -dd) DEBUG_LEVEL=$(( $DEBUG_LEVEL + 2 )) ;; -ddd) DEBUG_LEVEL=$(( $DEBUG_LEVEL + 3 )) ;; -dddd) DEBUG_LEVEL=$(( $DEBUG_LEVEL + 4 )) ;; -ddddd) DEBUG_LEVEL=$(( $DEBUG_LEVEL + 5 )) ;; -h|--help) showHelp ; exit 0 ;; --version) showVersion ; exit 0 ;; --feat-bridge) FEAT_BRIDGE=1 ;; --no-feat-bridge) FEAT_BRIDGE=0 ;; --chorus-required) CHORUS_REQUIRED=1 ;; --chorus-optional) CHORUS_REQUIRED=0 ;; --epic) MINLENGTH=180 MAXLENGTH=235 CHORUS_REQUIRED=1 FEAT_BRIDGE=0 ;; --song) MINLENGTH=120 MAXLENGTH=180 CHORUS_REQUIRED=1 FEAT_BRIDGE=1 ;; --ringtone) MINLENGTH=45 MAXLENGTH=75 CHORUS_REQUIRED=0 FEAT_BRIDGE=0 ;; --alert) MINLENGTH=25 MAXLENGTH=35 CHORUS_REQUIRED=0 FEAT_BRIDGE=0 ;; -m|--min) shift MINLENGTH="$1" if [ $MINLENGTH -ne 0 -a $MINLENGTH -gt $MAXLENGTH ] ; then MAXLENGTH=0 fi ;; -M|--max) shift MAXLENGTH="$1" if [ $MAXLENGTH -ne 0 -a $MAXLENGTH -lt $MINLENGTH ] ; then MINLENGTH=0 fi ;; *) echo "ERROR: Unknown argument: $1" 1>&2 ; exit 1 ;; esac shift done function warning() { echo "$@" 1>&2 } warning "Requested: Song length $MINLENGTH to $MAXLENGTH" warning -n " Features: " if [ $FEAT_BRIDGE -gt 0 ] ; then warning -n "bridges " ; else warning -n "no-bridges " ; fi if [ $CHORUS_REQUIRED -eq 0 ] ; then warning -n "choruses-optional " ; else warning -n "choruses-required " ; fi warning function debug() { local level="$1" shift if [ $level -lt $DEBUG_LEVEL ] ; then echo "$@" 1>&2 fi } function findStructure() { local need1=f local leadwith="c" if [ $VERSE_COUNT -gt $CHORUS_COUNT ] ; then leadwith="v" fi if [ $VERSE_COUNT -eq 0 -a $CHORUS_COUNT -eq 0 ] ; then if [ $FEAT_BRIDGE -eq 1 ] ; then echo -n "b" else echo "WARNING: FEAT_BRIDGE disabled, and VERSE_COUNT and CHORUS_COUNT are 0." 1>&2 echo -n "" fi return fi local cforv=$(( $CHORUS_COUNT / $(( $VERSE_COUNT + 1 )) )) local vforc=$(( $VERSE_COUNT / $(( $CHORUS_COUNT + 1 )) )) local bridge=0 local end=$(( $CHORUS_COUNT + $VERSE_COUNT )) if [ $FEAT_BRIDGE -eq 1 ] ; then if [ $(( $CHORUS_COUNT + $VERSE_COUNT )) -lt 3 ] ; then bridge=$(( $CHORUS_COUNT + $VERSE_COUNT - 1 )) if [ $bridge -le 0 ] ; then bridge=1 fi else bridge=$(( $(( $CHORUS_COUNT + $VERSE_COUNT )) * 2 / 3 )) if [ $bridge -eq 0 ] ; then bridge=1 fi fi fi local relc=0 local relv=0 local i=0 local suffix="" local n="$leadwith" local capc=$(( $CHORUS_COUNT )) local capv=$(( $VERSE_COUNT )) local remc=0 if [ "$leadwith" = "c" ] ; then remc=$(( $CHORUS_COUNT % $(( $VERSE_COUNT + 1 )) )) if [ $remc -lt 0 ] ; then remc=0 ; fi fi local remv=0 if [ "$leadwith" = "v" ] ; then remv=$(( $VERSE_COUNT % $(( $CHORUS_COUNT + 1 )) )) if [ $remv -lt 0 ] ; then remv=0 ; fi fi if [ $CHORUS_COUNT -eq $VERSE_COUNT ] ; then remc=0 ; remv=0 ; fi local didrem=0 local cntv=0 local cntc=0 while [ $capc -gt 0 -o $capv -gt 0 ] ; do if [ $(( $i % 2 )) -eq 1 ] ; then suffix="1" else suffix="" fi if [ $bridge -gt 0 -a $bridge -le $i ] ; then if [[ "$leadwith" == "c" && ( $relc -ge $cforv || ( $capv -eq 0 && ( $relc -gt 0 || $capc -le 0 ) ) ) ]] ; then echo -n "b${suffix} " if [ $capc -gt 0 -a $capc -gt $capv ] ; then n="c" ; else n="v" ; fi relc=0 bridge=0 i=$(( $i + 1 )) continue elif [[ "$leadwith" == "v" && ( $relv -ge $vforc || ( $capc -eq 0 && ( $relv -gt 0 || $capv -le 0 ) ) ) ]] ; then echo -n "b${suffix} " if [ $capv -gt 0 -a $capv -gt $capc ] ; then n="v" ; else n="c" ; fi relv=0 bridge=0 i=$(( $i + 1 )) continue fi fi echo -n "${n}${suffix} " if [ "$n" = "v" ] ; then relc=0 capv=$(( $capv - 1 )) relv=$(( $relv + 1 )) cntv=$(( $cntv + 1 )) if [ $relv -ge $vforc ] ; then if [ $cntc -gt 0 -a $capv -gt 0 -a $remv -gt 0 -a $didrem -eq 0 ] ; then didrem=1 remv=$(( $remv - 1 )) elif [ $capc -gt 0 ] ; then n="c" didrem=0 fi fi elif [ "$n" = "c" ] ; then relv=0 relc=$(( $relc + 1 )) capc=$(( $capc - 1 )) cntc=$(( $cntc + 1 )) if [ $relc -ge $cforv ] ; then if [ $cntv -gt 0 -a $capc -gt 0 -a $remc -gt 0 -a $didrem -eq 0 ] ; then didrem=1 remc=$(( $remc - 1 )) elif [ $capv -gt 0 ] ; then didrem=0 n="v" fi fi fi i=$(( $i + 1 )) done if [ $bridge -gt 0 ] ; then echo -n "b " fi } function randomChord() { local T=$(( $RANDOM % 6 )) case $T in 0) echo -n "c" ;; 1) echo -n "g" ;; 2) echo -n "a:m" ;; 3) echo -n "f" ;; 4) echo -n "d:m" ;; 5) echo -n "e:m" ;; *) echo "ERROR: Unexpected number $T" 1>&2 ; exit 1 esac } function randomChords() { local num="$1" local c=0 while [ $c -lt $num ] ; do randomChord echo -n " " c=$(( $c + 1 )) done } function walkingBaseLine() { while [ $# -gt 0 ] ; do case "$1" in c) echo -n "c,2 g, " ;; g) echo -n "g,2 d, " ;; a:m) echo -n "a,2 e, " ;; f) echo -n "f,2 c, " ;; d:m) echo -n "d,2 a, " ;; e:m) echo -n "e,2 b, " ;; r) echo -n "r1 " ;; *) echo "ERROR: Unknown $1 in walkingBaseLine" 1>&2 ; exit 1 ;; esac shift done } function wholeChords() { while [ $# -gt 0 ] ; do case "$1" in c) echo -n "c1 " ;; g) echo -n "g1 " ;; a:m) echo -n "a1:m " ;; f) echo -n "f1 " ;; d:m) echo -n "d1:m " ;; e:m) echo -n "e1:m " ;; r) echo -n "r1 " ;; *) echo "ERROR: Unknown $1 in wholeChords" 1>&2 ; exit 1 ;; esac shift done } function doReMi() { while [ $# -gt 0 ] ; do local L=1 # Do Re Mi Fa So La Ti # C D E F G A B case "$1" in c|c*[0-9]|c:m) echo -n "Do " ;; d|d*[0-9]|d:m) echo -n "Re " ;; e|e*[0-9]|e:m) echo -n "Mi " ;; f|f*[0-9]|f:m) echo -n "Fa " ;; g|g*[0-9]|g:m) echo -n "So " ;; a|a*[0-9]|a:m) echo -n "La " ;; b|b*[0-9]|b:m) echo -n "Ti " ;; r|r[0-9]) echo -n "" ;; *) echo "ERROR: doReMi does not handle $1." 1>&2 exit 1 ;; esac shift done } # On the chord, but not what the walking-base is using function wholeDrone() { while [ $# -gt 0 ] ; do case "$1" in c) echo -n "e'1 " ;; g) echo -n "b'1 " ;; a:m) echo -n "c'1 " ;; f) echo -n "a'1 " ;; d:m) echo -n "e'1 " ;; e:m) echo -n "g'1 " ;; r) echo -n "r1 " ;; *) echo "ERROR: Unknown $1 in wholeDrone" 1>&2 ; exit 1 ;; esac shift done } function simpleReplace() { local REPLACE_TO="$1" shift while [ $# -gt 0 ] ; do echo -n "${REPLACE_TO} " shift done } function markSegment() { if [ $# -gt 0 ] ; then echo -n "c1 " shift fi while [ $# -gt 0 ] ; do echo -n "r1 " shift done } function percLine() { while [ $# -gt 0 ] ; do case "$1" in r) echo -n "r1 " ;; *) echo -n "sn4 ss ss ss " ;; esac shift done } function randomNote() { local N=$(( $RANDOM % $# )) case "$N" in 0) echo -n "$1 " ;; 1) echo -n "$2 " ;; 2) echo -n "$3 " ;; *) echo "ERROR: randomNote does not know that." 1>&2 exit 1 ;; esac } function randomTune() { while [ $# -gt 0 ] ; do local I for I in 1 2 3 4 ; do case "$1" in c) randomNote c\'4 e\'4 g\'4 ;; g) randomNote g\'4 b\'4 d\'4 ;; a:m) randomNote a\'4 c\'4 e\'4 ;; f) randomNote f\'4 a\'4 c\'4 ;; d:m) randomNote d\'4 e\'4 a\'4 ;; e:m) randomNote e\'4 g\'4 b\'4 ;; r) echo -n "r4 " ;; *) echo "ERROR: randomTune does not know that." 1>&2 exit 1 ;; esac done shift done } function chordTune() { while [ $# -gt 0 ] ; do case "$1" in c) echo -n "4 " echo -n "4 " echo -n "4 " echo -n "4 " ;; g) echo -n "4 " echo -n "4 " echo -n "4 " echo -n "4 " ;; a:m) echo -n "4 " echo -n "4 " echo -n "4 " echo -n "4 " ;; f) echo -n "4 " echo -n "4 " echo -n "4 " echo -n "4 " ;; d:m) echo -n "4 " echo -n "4 " echo -n "4 " echo -n "4 " ;; e:m) echo -n "4 " echo -n "4 " echo -n "4 " echo -n "4 " ;; r) echo -n "r1 " ;; *) echo "ERROR: Unknown $1 in chordTune" 1>&2 ; exit 1 ;; esac shift done } function arpChord() { while [ $# -gt 0 ] ; do case "$1" in c) echo -n "c4 e g c " ;; g) echo -n "g4 b d g " ;; a:m) echo -n "a4 c e a " ;; f) echo -n "f4 a c f " ;; d:m) echo -n "d4 e a d " ;; e:m) echo -n "e4 g b e " ;; r) echo -n "r1 " ;; *) echo "ERROR: Unknown $1 in arpChord" 1>&2 ; exit 1 ;; esac shift done } function leadingElements() { local CNT="$1" shift if [ $CNT -eq 0 ] ; then true elif [ $CNT -gt $# ] ; then echo -n "$@" else while [ $# -gt 0 -a $CNT -gt 0 ] ; do echo -n "$1 " CNT=$(( $CNT - 1 )) shift done fi } function trailingElements() { local CNT="$1" shift if [ $CNT -eq 0 ] ; then true elif [ $CNT -ge $# ] ; then echo -n "$@" else local SKIP=$(( $# - $CNT )) local C=0 while [ $C -lt $# ] ; do if [ $C -ge $SKIP ] ; then echo -n "$1 " fi C=$(( $C + 1 )) done fi } function lastElement() { local LAST="" while [ $# -gt 0 ] ; do LAST="$1" shift done echo "$LAST" } function nextLetter() { case "$1" in A) echo "B" ;; B) echo "C" ;; C) echo "D" ;; D) echo "E" ;; E) echo "F" ;; F) echo "G" ;; G) echo "H" ;; H) echo "I" ;; I) echo "J" ;; J) echo "K" ;; K) echo "L" ;; L) echo "M" ;; M) echo "N" ;; N) echo "O" ;; O) echo "P" ;; P) echo "Q" ;; Q) echo "R" ;; R) echo "S" ;; S) echo "T" ;; T) echo "U" ;; U) echo "V" ;; V) echo "W" ;; W) echo "X" ;; X) echo "Y" ;; Y) echo "Z" ;; Z) echo "ERROR: Too many letters for nextLetter" 1>&2 ; exit 1 ;; esac } function applyStructure() { local localC="" local localB="" local localD="" local localP="" local localM="" local localT="" local localL="" local nameC="$1" ; shift local nameB="$1" ; shift local nameD="$1" ; shift local nameP="$1" ; shift local nameM="$1" ; shift local nameT="$1" ; shift local nameL="$1" ; shift local verse="A" if [ "$1" != "--" ] ; then echo "Insufficient arguments supplied to applyStructure" 1>&2 exit 1 fi shift local FirstThing="$1" local LastThing="$1" # Intro local C="" case "$1" in c|c[1-9]) C="$BaseChorusChords" ;; v|v[1-9]) C="$BaseVerseChords" ;; b|b[1-9]) C="$BaseBridgeChords" ;; *) echo "ERROR: Unknown segment type $1" 1>&2 ; exit 1 ;; esac if [ $IntroChordCnt -eq 0 ] ; then C="r" else C=`leadingElements $IntroChordCnt $C` fi localT="$localT `simpleReplace r1 $C`" localD="$localD `simpleReplace r1 $C`" localM="$localM `simpleReplace r1 $C`" localP="$localP `percLine $C`" localC="$localC `wholeChords $C`" localB="$localB `walkingBaseLine $C`" while [ $# -gt 0 ] ; do local C="" LastThing="$1" case "$1" in c|c[1-9]) C="$BaseChorusChords" localT="$localT $tuneChorus" localL="$localL \\lyricsChorus" ;; v|v[1-9]) C="$BaseVerseChords" localT="$localT $tuneVerse" localL="$localL \\lyricsVerse${verse}" verse=`nextLetter ${verse}` ;; b|b[1-9]) C="$BaseBridgeChords" localT="$localT $tuneBridge" localL="$localL \\lyricsBridge" ;; *) echo "ERROR: Unknown segment type $1" 1>&2 exit 1 ;; esac case "$1" in [a-z]1) localD="$localD `wholeDrone $C`" ;; *) localD="$localD `simpleReplace r1 $C`" ;; esac localM="$localM `markSegment $C`" localP="$localP `percLine $C`" localC="$localC `wholeChords $C`" localB="$localB `walkingBaseLine $C`" shift done # Outro case "$LastThing/$OutroMethod" in c/RE-TAIL|c[0-9]/RE-TAIL|v/NO-NEXT|v[0-9]/NO-NEXT) C="$BaseChorusChords" ;; v/RE-TAIL|v[0-9]/RE-TAIL|c/NO-NEXT|c[0-9]/NO-NEXT) C="$BaseVerseChords" ;; b/RE-TAIL|b[0-9]/RE-TAIL) C="$BaseBridgeChords" ;; b/NO-NEXT|b[0-9]/NO-NEXT) case "$FirstThing" in b|b[0-9]) C="$BaseBridgeChords" ;; c|c[0-9]) C="$BaseChorusChords" ;; v|v[0-9]) C="$BaseVerseChords" ;; esac ;; */NEW) C="$BaseOutroChords" ;; *) echo "ERROR: Unknown LastThing/OutroMethod: $LastThing/$OutroMethod" 1>&2 ; exit 1 ;; esac if [ $OutroMethod = "RE-TAIL" ] ; then C=`trailingElements $OutroChordCnt $C` elif [ $OutroMethod = "NO-NEXT" ] ; then C=`leadingElements $OutroChordCnt $C` else C="$BaseOutroChords" fi localT="$localT `simpleReplace r1 $C`" localD="$localD `simpleReplace r1 $C`" localM="$localM `markSegment $C`" localP="$localP `percLine $C`" localC="$localC `wholeChords $C`" localB="$localB `walkingBaseLine $C`" eval "${nameC}=\"${localC}\"" eval "${nameB}=\"${localB}\"" eval "${nameD}=\"${localD}\"" eval "${nameP}=\"${localP}\"" eval "${nameM}=\"${localM}\"" eval "${nameT}=\"${localT}\"" eval "${nameL}=\"${localL}\"" } # Assigns NEEDBARS, structure, sec, barcnt function recalculateBars() { structure=`findStructure` local cnta=$(( $VERSE_COUNT * $VerseChordCnt )) local cntb=$(( $CHORUS_COUNT * $ChorusChordCnt )) barcnt=$(( $cnta + $cntb + $BridgeChordCnt + $IntroChordCnt + $OutroChordCnt)) sec=$(( $barcnt * 4 * 60 / $TEMPO )) NEEDBARS=0 if [ $MINLENGTH -gt 0 ] ; then NEEDBARS=$(( $MINLENGTH * $TEMPO / 60 / 4 )) debug 3 "TRACE: Min Bars: $NEEDBARS" NEEDBARS=$(( $NEEDBARS - $barcnt )) fi if [ $NEEDBARS -lt 0 ] ; then NEEDBARS=0 ; fi DROPBARS=0 if [ $MAXLENGTH -gt 0 ] ; then DROPBARS=$(( $MAXLENGTH * $TEMPO / 60 / 4 )) debug 3 "TRACE: Max Bars: $DROPBARS" DROPBARS=$(( $barcnt - $DROPBARS )) fi if [ $DROPBARS -lt 0 ] ; then DROPBARS=0 ; fi debug 2 "DEBUG: dropbars: $DROPBARS / needbars: $NEEDBARS" } function cleanNeedBars() { local ADDL if [ $NEEDBARS -gt 0 ] ; then if [ $NEEDBARS -gt $(( $VerseChordCnt + $ChorusChordCnt )) ] ; then ADDL=$(( $VerseChordCnt + $ChorusChordCnt )) ADDL=$(( $NEEDBARS / $ADDL )) CHORUS_COUNT=$(( $CHORUS_COUNT + $ADDL )) VERSE_COUNT=$(( $VERSE_COUNT + $ADDL )) recalculateBars unset ADDL fi if [ $VERSE_COUNT -lt $CHORUS_COUNT ] ; then if [ $NEEDBARS -gt $VerseChordCnt ] ; then ADDL=$(( $NEEDBARS / $VerseChordCnt )) VERSE_COUNT=$(( $VERSE_COUNT + $ADDL )) recalculateBars unset ADDL fi fi if [ $NEEDBARS -gt $ChorusChordCnt ] ; then ADDL=$(( $NEEDBARS / $ChorusChordCnt )) CHORUS_COUNT=$(( $CHORUS_COUNT + $ADDL )) recalculateBars unset ADDL fi if [ $NEEDBARS -gt $VerseChordCnt ] ; then ADDL=$(( $NEEDBARS / $VerseChordCnt )) VERSE_COUNT=$(( $VERSE_COUNT + $ADDL )) recalculateBars unset ADDL fi fi } T=$(( $RANDOM % 6 )) TEMPO=$(( 80 + 10 * $T )) T=1 if [ $MAX_VERSES -gt 0 ] ; then VERSE_COUNT=$(( $RANDOM % $MAX_VERSES + 1 )) else VERSE_COUNT=$(( $RANDOM % 6 + 3 )) fi if [ $MAX_CHORUS -gt 0 ] ; then CHORUS_COUNT=$(( $RANDOM % $MAX_CHORUS + $CHORUS_REQUIRED )) else CHORUS_COUNT=$(( $RANDOM % 6 + $RANDOM % 3 )) fi VerseChordCnt=$(( $RANDOM % 6 + 1 )) ChorusChordCnt=$(( $RANDOM % 6 + 1 )) BridgeChordCnt=0 if [ $FEAT_BRIDGE -gt 0 ] ; then BridgeChordCnt=$(( $RANDOM % 6 + 1 )) fi IntroChordCnt=$(( $RANDOM % 6 )) OutroChordCnt=$(( $RANDOM % 6 )) recalculateBars cleanNeedBars if [ $DROPBARS -gt 0 ] ; then T=$(( $DROPBARS / 2 + 1 )) if [ $IntroChordCnt -gt 0 ] ; then if [ $IntroChordCnt -gt $T ] ; then IntroChordCnt=$(( $IntroChordCnt - $T )) else IntroChordCnt=0 fi fi if [ $OutroChordCnt -gt 0 ] ; then if [ $OutroChordCnt -gt $T ] ; then OutroChordCnt=$(( $OutroChordCnt - $T )) else OutroChordCnt=0 fi fi recalculateBars fi if [ $DROPBARS ] ; then T=$(( $VERSE_COUNT * $VerseChordCnt )) VERSE_COUNT=$(( $VERSE_COUNT / 2 )) if [ $VERSE_COUNT -le $REDUCE_MIN_VERSES ] ; then VERSE_COUNT=$REDUCE_MIN_VERSES if [ $REDUCE_MIN_VERSES -le 0 ] ; then VERSE_COUNT=1 fi fi VerseChordCnt=$(( $T / $VERSE_COUNT )) T=$(( $CHORUS_COUNT * $ChorusChordCnt )) CHORUS_COUNT=$(( $CHORUS_COUNT / 2 )) if [ $CHORUS_COUNT -le $CHORUS_REQUIRED ] ; then if [ $CHORUS_REQUIRED -eq 0 ] ; then CHORUS_COUNT=0 fi fi if [ $CHORUS_COUNT -eq 0 ] ; then ChorusChordCnt=0 else ChorusChordCnt=$(( $T / $CHORUS_COUNT )) fi fi if [ $DROPBARS -ge $(( $VERSE_COUNT + $CHORUS_COUNT )) ] ; then T=0 if [ $VERSE_COUNT -gt 0 ] ; then T=$(( $T + $VERSE_COUNT )) ; fi if [ $CHORUS_COUNT -gt 0 ] ; then T=$(( $T + $CHORUS_COUNT )) ; fi T=$(( $DROPBARS / $T / 2 )) if [ $VERSE_COUNT -gt 0 ] ; then if [ $T -ge $(( $VerseChordCnt / 2 )) ] ; then T=$(( $VerseChordCnt / 2 )) fi fi if [ $CHORUS_COUNT -gt 0 ] ; then if [ $T -ge $(( $ChorusChordCnt / 2 )) ] ; then T=$(( $ChorusChordCnt / 2 )) fi fi if [ $VERSE_COUNT -gt 0 ] ; then VerseChordCnt=$(( $VerseChordCnt - $T )) ; else VerseChordCnt=0 fi if [ $CHORUS_COUNT -gt 0 ] ; then ChorusChordCnt=$(( $ChorusChordCnt - $T )) else ChorusChordCnt=0 fi recalculateBars fi if [ $VERSE_COUNT -gt $VerseChordCnt ] ; then if [ $VerseChordCnt -ge $REDUCE_MIN_VERSES ] ; then T=$VERSE_COUNT VERSE_COUNT=$VerseChordCnt VerseChordCnt=$VERSE_COUNT fi fi if [ $CHORUS_COUNT -gt $ChorusChordCnt ] ; then if [ $ChorusChordCnt -ge $CHORUS_REQUIRED ] ; then T=$CHORUS_COUNT CHORUS_COUNT=$ChorusChordCnt ChorusChordCnt=$CHORUS_COUNT fi fi recalculateBars if [ $DROPBARS -ge $(( $VerseChordCnt + $ChorusChordCnt )) ] ; then T=$(( $VerseChordCnt + $ChorusChordCnt )) T=$(( $DROPBARS / $T / 2 )) if [ $VERSE_COUNT -le $REDUCE_MIN_VERSES ] ; then T=0 elif [ $(( $VERSE_COUNT - $T)) -le $REDUCE_MIN_VERSES ] ; then T=$(( $VERSE_COUNT - $REDUCE_MIN_VERSES )) fi if [ $CHORUS_COUNT -le $CHORUS_REQUIRED ] ; then T=0 elif [ $(( $CHORUS_COUNT - $T)) -lt $CHORUS_REQUIRED ] ; then T=$(( $CHORUS_COUNT - $CHORUS_REQUIRED )) fi if [ $T -gt 0 ] ; then VERSE_COUNT=$(( $VERSE_COUNT - $T )) CHORUS_COUNT=$(( $CHORUS_COUNT - $T )) recalculateBars fi fi if [ $DROPBARS -ge $(( $VERSE_COUNT + $CHORUS_COUNT )) ] ; then T=0 if [ $VERSE_COUNT -gt 0 ] ; then T=$(( $T + $VERSE_COUNT )) ; fi if [ $CHORUS_COUNT -gt 0 ] ; then T=$(( $T + $CHORUS_COUNT )) ; fi T=$(( $DROPBARS / $T / 2 + 1 )) if [ $VERSE_COUNT -gt 0 ] ; then if [ $T -ge $VerseChordCnt ] ; then T=$(( $VerseChordCnt - 1 )) fi fi if [ $CHORUS_COUNT -gt 0 ] ; then if [ $T -ge $ChorusChordCnt ] ; then T=$(( $ChorusChordCnt - 1 )) fi fi if [ $VERSE_COUNT -gt 0 ] ; then VerseChordCnt=$(( $VerseChordCnt - $T )) ; else VerseChordCnt=0 fi if [ $CHORUS_COUNT -gt 0 ] ; then ChorusChordCnt=$(( $ChorusChordCnt - $T )) else ChorusChordCnt=0 fi recalculateBars fi # Extreme measures to reduce size # We know that reducing them together is insufficient if [ $DROPBARS -gt 0 ] ; then IntroChordCnt=0 OutroChordCnt=0 recalculateBars fi if [ $DROPBARS -ge $VerseChordCnt -o $DROPBARS -ge $ChorusChordCnt ] ; then if [ $CHORUS_COUNT -gt $CHORUS_REQUIRED ] ; then T=$(( $(( $DROPBARS + $ChorusChordCnt - 1 )) / $ChorusChordCnt )) if [ $(( $CHORUS_COUNT - $T )) -lt $CHORUS_REQUIRED ] ; then CHORUS_COUNT=$(( $CHORUS_COUNT - $CHORUS_REQUIRED )) else CHORUS_COUNT=$(( $CHORUS_COUNT - $T )) fi fi if [ $VERSE_COUNT -gt $REDUCE_MIN_VERSES ] ; then T=$(( $(( $DROPBARS + $VerseChordCnt - 1 )) / $VerseChordCnt )) if [ $(( $VERSE_COUNT - $T )) -lt $REDUCE_MIN_VERSES ] ; then VERSE_COUNT=$(( $VERSE_COUNT - $REDUCE_MIN_VERSES )) else VERSE_COUNT=$(( $VERSE_COUNT - $T )) fi fi recalculateBars fi if [ $DROPBARS -ge 0 ] ; then # We know that reducing them together is insufficient if [ $FEAT_BRIDGE -gt 0 ] ; then BridgeChordCnt=$(( $BridgeChordCnt - $DROPBARS )) if [ $BridgeChordCnt -lt 1 ] ; then BridgeChordCnt=1 ; fi recalculateBars fi fi if [ $DROPBARS -ge 0 ] ; then if [ $ChorusChordCnt -ge $VerseChordCnt ] ; then T=$(( $(( $DROPBARS + $CHORUS_COUNT - 1 )) / $CHORUS_COUNT )) if [ $(( $ChorusChordCnt - $T )) -lt 2 ] ; then ChorusChordCnt=2 else ChorusChordCnt=$(( $ChorusChordCnt - $T )) fi else T=$(( $(( $DROPBARS + $VERSE_COUNT - 1 )) / $VERSE_COUNT )) if [ $(( $VerseChordCnt - $T )) -lt 2 ] ; then VerseChordCnt=2 else VerseChordCnt=$(( $VerseChordCnt - $T )) fi fi recalculateBars fi if [ $ChorusChordCnt -gt $VerseChordCnt -a $VerseChordCnt -gt 0 -a $OutroChordCnt -gt $VerseChordCnt ] ; then OutroChordCnt=$VerseChordCnt elif [ $ChorusChordCnt -gt 0 -a $OutroChordCnt -gt $ChorusChordCnt ] ; then OutroChordCnt=$ChorusChordCnt fi if [ $ChorusChordCnt -gt $VerseChordCnt -a $VerseChordCnt -gt 0 -a $IntroChordCnt -gt $VerseChordCnt ] ; then IntroChordCnt=$VerseChordCnt elif [ $ChorusChordCnt -gt 0 -a $IntroChordCnt -gt $ChorusChordCnt ] ; then IntroChordCnt=$ChorusChordCnt fi debug 1 "Performed intro/outro cleanup" recalculateBars if [ $NEEDBARS -ge $(( $VERSE_COUNT + $CHORUS_COUNT )) ] ; then T=$(( $VERSE_COUNT + $CHORUS_COUNT )) T=$(( $NEEDBARS / $T / 2 )) if [ $T -gt $VerseChordCnt -o $T -gt $ChorusChordCnt ] ; then T=$(( $T / 2 )) fi VerseChordCnt=$(( $VerseChordCnt + $T )) ChorusChordCnt=$(( $ChorusChordCnt + $T )) debug 1 "Performed song padding." recalculateBars fi if [ $NEEDBARS -ge $(( $VerseChordCnt + $ChorusChordCnt )) ] ; then T=$(( $VerseChordCnt + $ChorusChordCnt )) T=$(( $NEEDBARS / $T )) if [ $VERSE_COUNT -gt 0 -a $CHORUS_COUNT -gt 0 ] ; then T=$(( $T / 2 )) fi if [ $MAX_VERSES -eq 0 -o $MAX_CHORUS -eq 0 ] ; then if [ $MAX_VERSES -gt 0 ] ; then if [ $(( $T + $VERSE_COUNT )) -gt $MAX_VERSES ] ; then VERSE_COUNT=$MAX_VERSES else VERSE_COUNT=$(( $VERSE_COUNT + $T )) fi elif [ $MAX_VERSES -eq 0 ] ; then VERSE_COUNT=$(( $VERSE_COUNT + $T )) fi if [ $MAX_CHORUS -gt 0 ] ; then if [ $(( $T + $CHORUS_COUNT )) -gt $MAX_CHORUS ] ; then CHORUS_COUNT=$MAX_CHORUS else CHORUS_COUNT=$(( $CHORUS_COUNT + $T )) fi elif [ $MAX_CHORUS -eq 0 ] ; then CHORUS_COUNT=$(( $CHORUS_COUNT + $T )) fi elif [ $(( $T + $VERSE_COUNT )) -gt $MAX_VERSES -o $(( $T + $CHORUS_COUNT )) -gt $MAX_CHORUS ] ; then T=$(( $MAX_VERSES - $VERSE_COUNT )) U=$(( $MAX_CHORUS - $CHORUS_COUNT )) if [ $U -lt $T ] ; then T=$U fi if [ $T -gt 0 ] ; then VERSE_COUNT=$(( $VERSE_COUNT + $T )) CHORUS_COUNT=$(( $CHORUS_COUNT + $T )) fi fi debug 1 "Performed structure padding" recalculateBars fi if [ $NEEDBARS -ge $(( $VERSE_COUNT + $CHORUS_COUNT )) ] ; then T=$(( $VERSE_COUNT + $CHORUS_COUNT )) T=$(( $NEEDBARS / $T )) if [ $VERSE_COUNT -gt 0 -a $CHORUS_COUNT -gt 0 ] ; then T=$(( $T / 2 )) fi if [ $T -gt 0 ] ; then if [ $VERSE_COUNT -gt 0 ] ; then VerseChordCnt=$(( $VerseChordCnt + $T )) fi if [ $CHORUS_COUNT -gt 0 ] ; then ChorusChordCnt=$(( $ChorusChordCnt + $T )) fi debug 1 "Added chords to Verse and Chorus" recalculateBars fi fi if [ $NEEDBARS -gt 0 ] ; then if [ $FEAT_BRIDGE -gt 0 ] ; then BridgeChordCnt=$(( $BridgeChordCnt + $NEEDBARS )) else cleanNeedBars OutroChordCnt=$(( $OutroChordCnt + $NEEDBARS )) fi debug 1 "Needed bars shoved in to BRIDGE or OUTRO" recalculateBars fi if [ $ChorusChordCnt -eq 0 ] ; then CHORUS_COUNT=0 fi if [ $VerseChordCnt -eq 0 ] ; then VERSE_COUNT=0 fi debug 1 "About to create song." recalculateBars BaseVerseChords=`randomChords $VerseChordCnt` BaseChorusChords=`randomChords $ChorusChordCnt` BaseBridgeChords=`randomChords $BridgeChordCnt` BaseOutroChords="r" if [ $OutroChordCnt -eq 0 ] ; then OutroMethod="NEW" elif [ $OutroChordCnt -gt $VerseChordCnt -o $OutroChordCnt -gt $ChorusChordCnt ] ; then OutroMethod="NEW" BaseOutroChords=`randomChords $OutroChordCnt` else OutroMethod=$(( $RANDOM % 3 )) lastBlock=`lastElement $structure` case $OutroMethod in 0) OutroMethod="RE-TAIL" ;; 1) OutroMethod="NO-NEXT" ;; 2) BaseOutroChords=`randomChords $OutroChordCnt` OutroMethod="NEW" ;; esac fi tuneVerse=`randomTune $BaseVerseChords` tuneChorus=`randomTune $BaseChorusChords` tuneBridge=`randomTune $BaseBridgeChords` applyStructure CHORDS BASE DRONE DRUM MARKER TUNE LYSTRUX -- $structure VERSE_LYRICS=`doReMi $tuneVerse` CHORUS_LYRICS=`doReMi $tuneChorus` BRIDGE_LYRICS=`doReMi $tuneBridge` nfo="$(( $sec / 60 )) minutes, $(( $sec % 60 )) seconds, or $barcnt bars at $TEMPO" warning "Generated: ${VERSE_COUNT}x verse; ${CHORUS_COUNT}x chorus / Structure: ${structure}" warning -n " Sizes (Chords): " T="" if [ $IntroChordCnt -gt 0 ] ; then warning -n "Intro:${IntroChordCnt}" T=1 fi if [ $VerseChordCnt -gt 0 ] ; then warning -n "${T+; }Verse:${VerseChordCnt}" T=1 fi if [ $ChorusChordCnt -gt 0 ] ; then warning -n "${T+; }Chorus:${ChorusChordCnt}" T=1 fi if [ $BridgeChordCnt -gt 0 ] ; then warning -n "${T+; }Bridge:${BridgeChordCnt}" T=1 fi if [ $OutroChordCnt -gt 0 ] ; then warning -n "${T+; }Outro:${OutroChordCnt}" fi warning warning " Length: $nfo" cat << FEOF \\version "2.14.2" \\include "predefined-guitar-fretboards.ly" \\include "english.ly" % ${structure} % ${nfo} % Verses: ${VERSE_COUNT} % Choruses: ${CHORUS_COUNT} % Intro Chord Count: ${IntroChordCnt} % Verse Chord Count: ${VerseChordCnt} % Chorus Chord Count: ${ChorusChordCnt} % Bridge Chord Count: ${BridgeChordCnt} % Outro Chord Count: ${OutroChordCnt} albumTagline = \\markup { Random songs for random fun. } albumCopyright = \\markup { \\column { \\line { \\abs-fontsize #8 \\column { \\line { \\with-url #"http://creativecommons.org/licenses/by/4.0/" { This work is licensed under a Creative Commons Attribution 4.0 International License. } } } } }} tuneGlobal = { \\key c \\major \\time 4/4 \\tempo 4 = ${TEMPO} } chordMusic = \\chordmode { ${CHORDS} } bassMusic = \\absolute { ${BASE} } droneMusic = \\absolute { ${DRONE} } markerMusic = \\absolute { ${MARKER} } tuneMusic = \\absolute { ${TUNE} } drumMusic = \\drummode { ${DRUM} } lyricsChorus = \\lyricmode { \\set stanza = #"Ch." ${CHORUS_LYRICS} } FEOF v="A" C=0 while [ $C -lt $VERSE_COUNT ] ; do echo 'lyricsVerse'"$v"' = \lyricmode {' v=`nextLetter $v` echo ' \set stanza = #"'$(( $C + 1 ))'. "' echo " ${VERSE_LYRICS}" echo "}" echo C=$(( $C + 1 )) done cat << FEOF lyricsBridge = \\lyricmode { \\set stanza = #"Br." ${BRIDGE_LYRICS} } \\book { \\bookOutputSuffix "import" \\header { copyright = \\albumCopyright tagline = \\albumTagline } \\score { << \\new Staff { \\set Staff.midiInstrument = #"acoustic guitar (steel)" \\set Staff.instrumentName = #"Chords" \\tuneGlobal \\chordMusic } \\new Staff { \\clef bass \\set Staff.midiInstrument = #"acoustic bass" \\set Staff.instrumentName = #"Bass" \\tuneGlobal \\bassMusic } \\new Staff { \\set Staff.instrumentName = #"Drone" \\set Staff.midiInstrument = #"tubular bells" \\droneMusic } \\new Staff << \\clef bass \\set Staff.instrumentName = #"Tune" \\set Staff.midiInstrument = #"flute" \\new Voice = "tune" { \\tuneGlobal \\tuneMusic } >> \\new Lyrics \lyricsto "tune" { ${LYSTRUX} } \\new DrumStaff << \\set Staff.instrumentName = #"Drums" \\drummode { \\drumMusic } >> \\new Staff { \\set Staff.instrumentName = #"Marker" \\set Staff.midiInstrument = #"telephone ring" \\markerMusic } >> \\layout { } \\midi { } } } \\book { \\bookOutputSuffix "lead" \\header { copyright = \\albumCopyright tagline = \\albumTagline } \\score { << \\new ChordNames { \\chordMusic } \\new FretBoards { \\set Staff.midiInstrument = #"acoustic guitar (steel)" \\set Staff.stringTunings = #guitar-tuning \\tuneGlobal \\chordMusic } \\new Staff << \\set Staff.midiInstrument = #"xylophone" \\new Voice = "tune" { \\tuneGlobal \\tuneMusic } >> \\new Lyrics \lyricsto "tune" { ${LYSTRUX} } >> \\layout { } } } FEOF warning "Done."