#!/bin/bash
# I bought my children a new piano, you may guess its name and therefore I had to write this script.
clear
echo "		  Utility to split a keyboard of Yamaha ARIUS YDP-142 or YDP-162"
echo "		  --------------------------------------------------------------"
echo "			     writen by Jeronym Klimes (www.klimes.us)"
echo "		Thanks God for the authors of midish, Krusader, Kate, Lubuntu, etc."
echo

usage() {
	echo "Usage:" 
	echo "	$(basename $0) [-l lower instrument number = 9] [-u upper instrument number = 1]"
	echo "		[-s split note number = 52 (f; F2)] [-i interactive mode to select instruments]"
	echo "		[-o just switch local control on]"
	echo
	echo "Yamaha digital piano ARIUS has not a fuction split, so you may use this script to play" 
	echo "two instruments simultaneously at an lower and upper range of your keyboard."
	echo
	echo "Connect your PC to Yamaha ARIUS via USB cable and run this script at the command line."	
	echo "You may need to install small utilities as midish, zenity, aseqdump, usually by a command:"
	echo "		sudo apt-get install nameoftheutility"
	echo "You may easily adapt this script for other instruments. See hints inside the script."
	echo
	echo "Warning! This program switch off so called local control, so keys on keyboard stop to play."
	echo "So after running this program, you have to switch local control yourself by pressing:"
	echo "		DEMO + VOICE + C6 (c'''') on your keyboard"
	echo "You can run this script with parametr -o to switch local control on later:"
	echo "		$(basename $0) -o"
	echo
	echo "You can break this script at any time. Just press CTRL+C on the PC keyboard."
	exit 2
	}

localon() {
	echo "Switching on local control"

	exec midish -b <<EOF 
	dnew 2 "$device" wo #output
	onew lower  {2 3}
	co lower
	print "switching local control on again"
	oaddev  {ctl lower 122 127}
#	p
EOF
# This EOF must start at the first column without any leading or trailing spaces.
	exit
	}
	
bank() {
	case $1 in 
		# Yamaha ARIUS YDP-142 Preset Voice List
		#Name 						MSB 0-127) 	LSB (0-127)	Program Change # (1-128) hex MSB LSB	dec MSB LSB
		1)  name="GrandPiano 1"; 	msb="108"; 	lsb="0"; 	patch="1" ;              hML=3600;	    dML=13824;;
		2)  name="GrandPiano 2"; 	msb="108"; 	lsb="3"; 	patch="1" ;              hML=3603;	    dML=13827;;
		3)  name="GrandPiano 3"; 	msb="108"; 	lsb="2"; 	patch="2" ;              hML=3602;	    dML=13826;;
		4)  name="E.Piano 1   ";	msb="108"; 	lsb="0"; 	patch="6" ;              hML=3600;	    dML=13824;;
		5)  name="E.Piano 2   ";	msb="108"; 	lsb="0"; 	patch="5" ;              hML=3600;	    dML=13824;;
		6)  name="Harpsichord ";	msb="108"; 	lsb="0"; 	patch="7" ;              hML=3600;	    dML=13824;;
		7)  name="Vibraphone  ";	msb="108"; 	lsb="0"; 	patch="12";              hML=3600;	    dML=13824;;
		8)  name="Pipe Organ  ";	msb="108"; 	lsb="1"; 	patch="20";              hML=3601;	    dML=13825;;
		9)  name="Jazz Organ  ";	msb="108"; 	lsb="0"; 	patch="17";              hML=3600;	    dML=13824;;
		10) name="Strings     ";	msb="108"; 	lsb="0"; 	patch="49";              hML=3600;	    dML=13824;;
		# Take care! The byte is only 7 bits here, so 128 and not 256, therefore:
		# dML = msb*128 + lsb
		# See Yamaha ARIUS YDP-162 YDP-142 MIDI Reference
		esac
	
    if [ "$2" == "lower" ]; then 
		lname=$name
		lmsb=$msb
		llsb=$lsb
		lpatch=$(($patch-1))
		ldML=$dML
		lhML=$hML
	    fi
	    
    if [ "$2" == "upper" ]; then 
		uname=$name
		umsb=$msb
		ulsb=$lsb
		upatch=$(($patch-1))
		udML=$dML
		uhML=$hML
	    fi
	}

selectinstruments () {
	options=(\
		"1"  "GrandPiano 1"\
		"2"  "GrandPiano 2"\
		"3"  "GrandPiano 3"\
		"4"  "E.Piano 1   "\
		"5"  "E.Piano 2   "\
		"6"  "Harpsichord "\
		"7"  "Vibraphone  "\
		"8"  "Pipe Organ  "\
		"9"  "Jazz Organ  "\
		"10" "Strings     "\
		)

	selection=$(zenity --height 400 --list "${options[@]}" --column="#" --column="name"\
		--text="Select an instrument for the upper range of the piano" --title="Upper instrument"\
		--print-column="1" --hide-header )
	if [ "${#selection}" == 3 ]; then
		selection=${selection:0:1}
		else
		selection=${selection:0:2}
		fi
	bank $selection upper 

	selection=$(zenity --height 400 --list "${options[@]}" --column="#" --column="name"\
		--text="Select an instrument for the lower range of the piano" --title="Lower instrument"\
		--print-column="1" --hide-header )
	if [ "${#selection}" == 3 ]; then
		selection=${selection:0:1}
		else
		selection=${selection:0:2}
		fi
	bank $selection upper 

	selection=$(zenity --scale --text "Pick a split key! (default 52 (F2; f)" --min-value=1 --max-value=85 --value=52 --step 1 )
		if [[ $selection = *[[:digit:]]* ]]; then # is selection a number?
			split=$selection
			fi
	}

device=$(aseqdump -l | grep "ARIUS" |  awk '{print $1}')
# edit this line if you want to use another musical instrument then ARIUS.

bank 1 upper 	# default upper range is piano
bank 9 lower 	# default lower range is jazz organ
split=52		# default split is f (F2)

while getopts oihl:u:s: optname; do
	case "$optname" in
		u)
			bank $OPTARG upper;;
		l)  
			bank $OPTARG lower;;
		s)
			split=$OPTARG;;
		h)
			usage;;
		i)
			interactive=true;;	
		o)
			localon;;	
		esac
	done

if [ $interactive ]; then 
	selectinstruments 
	fi
	
echo
echo "Instruments' parameters"
echo uname=$uname umsb=$umsb ulsb=$ulsb upatch=$upatch uhML=$uhML udML=$udML
echo lname=$lname lmsb=$lmsb llsb=$llsb lpatch=$lpatch lhML=$uhML ldML=$ldML
echo split=$split
echo device=$device
echo
if [ -z $device ]; then
	echo "The keyboard Yamaha ARIUS is not connected to your PC. Exiting..."
	echo
	exit
	fi

#This is main midish procedure. You can run it by yourself in an interactive mode by runing program rmidish	
exec midish -b <<EOF
dnew 1 "$device" ro #input
inew input {1 0}
ci input

dnew 2 "$device" wo #output - the same keyboard as output divided into two ranges
onew upper 	{2 2}
onew lower  {2 3}

co upper
print "setting upper range instrument - $uname"
oaddev {xpc upper $upatch $udML}
#Other possibilities:
# oaddev {xpc upper upatch (128*$umsb+$ulsb)}
# oaddev {pc upper upatch}

co lower
print "setting lower range instrument - $lname"
oaddev {xpc lower $lpatch $ldML}

print "switching off local control"
oaddev  {ctl lower 122 0}
fnew mysplit
fmap {any input} {any upper}
fmap {any input} {any lower}
print "setting split point - $split"
fmap {note input 0..$split}        {note lower 0..$split}       # split at F2 (f)
fmap {note input ($split+1)..127}  {note upper ($split+1)..127} # split at F2 (f)
cf mysplit
print " "
print "Press key s to stop simulation. (This does not work... :-((( You have to press CTRL+C)"
print " "
i

#Unfortunately the following script does not work because of CTRL+C
#cf lower
#co lower
#print "switching local control on again"
#ls
#oaddev {ctl lower 122 127}

print "This is the very end. "
print "Do not forget to switch local control on by yourself. Press:"
print "DEMO + VOICE + C6 (c'''') on your keyboard"
print "or run this script with parameter -o"
EOF
# This EOF must start at the first column without any leading or trailing spaces.