#!/bin/ksh
#
# CD Player frontend for CDDA2WAV
#
# Programmed during the rainy feb 12, 2005
# (c) Peter van Eerten - free for all use
#
# 1.0: Initial release
# 1.1: Fixes for CDDA2WAV on OpenBSD (june 1 2005)
# 1.2: Now combobox synchronizes with track (june 4 2005)
# 1.2a: Fixes for CD's with more than 10 tracks (september 9, 2005)
# 1.3:  -Removed ' character from titles (october 18, 2005)
#               -Support for intern. characters (october 18, 2005)
#-------------------------------------------------------------------------------------
#
# Minimalistic frontend to play audio CD's
#
# Required tools:
# -cdda2wav
# -GNU Awk
# -rexima OR aumix
# -...and of course coreutils like 'cat' and 'tr'.
#
#------------------------------------------------ CHECK

function Check_Software
{
# Check on availability of AWK
AWK=`which gawk 2>/dev/null`
if [[ -z $AWK ]]
then
        echo "GNU Awk not found on your system! Exiting..."
        exit 1
fi

# Check on availability of REXIMA or AUMIX
MIXER=`which rexima 2>/dev/null`
if [[ -z $MIXER || $MIXER = "rexima: Command not found." ]]
then
        MIXER=`which aumix 2>/dev/null`
        if [[ -z $MIXER || $MIXER = "aumix: Command not found." ]]
        then
                echo "No mixer found! Exiting..."
                exit 1
        fi
fi

# Check on availability of cdda2wav
CDDA2WAV=`which cdda2wav 2>/dev/null`
if [[ -z $CDDA2WAV ]]
then
        echo "cdda2wav not found on your system! Exiting..."
        exit 1
fi
}

# Check on availability of 'sleep'
SLEEP=`which sleep 2>/dev/null`
if [[ -z $SLEEP ]]
then
        echo "GNU sleep not found on your system! High CPU load granted."
        SLEEP=sleep
fi

#------------------------------------------------ GTK

# Communication function; $1 contains the string to be send
function gtk
{
print -p $1
read -p RESULT
}

#------------------------------------------------ GUI

function Build_Gui
{
# Setup environment for GTK server
#export LC_ALL=nl_NL
export LD_LIBRARY_PATH=/usr/X11R6/lib:/usr/lib:/usr/local/lib

# Start GTK-server in STDIN mode
gtk-server stdin |&

# Check GTK version
gtk "gtk_check_version 2 4 0"
if [[ -n $RESULT ]]
then
        echo "Your GTK installation is too old!"
        echo "GTK version 2.4.0 or higher is required. Exiting..."
        gtk "gtk_exit 0"
        exit 1
fi

# Define GUI - mainwindow
gtk "gtk_init NULL NULL"
gtk "gtk_window_new 0"
WINDOW=$RESULT
gtk "gtk_window_set_title $WINDOW \"CD Player\""
gtk "gtk_window_set_position $WINDOW 1"
# Buttons
gtk "gtk_button_new_from_stock gtk-stop"
G_BUTTON_STOP=$RESULT
gtk "gtk_button_new_from_stock gtk-refresh"
G_BUTTON_REFRESH=$RESULT
gtk "gtk_button_new_from_stock gtk-quit"
G_BUTTON_QUIT=$RESULT
gtk "gtk_button_new_from_stock gtk-help"
G_BUTTON_HELP=$RESULT
# Volume slider
gtk "gtk_vscale_new_with_range 0 100 1"
G_VOLUME=$RESULT
gtk "gtk_scale_set_draw_value $G_VOLUME 0"
gtk "gtk_range_set_value $G_VOLUME 50"
# Combobox with titles of CD
gtk "gtk_combo_box_new_text"
G_COMBO=$RESULT
# Create layout
gtk "gtk_hbox_new 0 0"
H1BOX=$RESULT
gtk "gtk_box_pack_start $H1BOX $G_BUTTON_STOP 1 1 1"
gtk "gtk_box_pack_start $H1BOX $G_BUTTON_REFRESH 1 1 1"
gtk "gtk_box_pack_start $H1BOX $G_BUTTON_HELP 1 1 1"
gtk "gtk_box_pack_end $H1BOX $G_BUTTON_QUIT 1 1 1"
gtk "gtk_vbox_new 0 0"
VBOX=$RESULT
gtk "gtk_box_pack_start $VBOX $H1BOX 1 1 1"
gtk "gtk_box_pack_start $VBOX $G_COMBO 1 1 1"
gtk "gtk_hbox_new 0 0"
HTOPBOX=$RESULT
gtk "gtk_box_pack_start $HTOPBOX $VBOX 1 1 1"
gtk "gtk_box_pack_start $HTOPBOX $G_VOLUME 0 0 0"
gtk "gtk_container_add $WINDOW $HTOPBOX"
gtk "gtk_widget_show_all $WINDOW"
# Create ABOUT box
gtk "gtk_server_version"
TMP="\t*** A simple CD player for XFCE ***\r\rProgrammed with KSH and $RESULT.\r\r Visit http://www.gtk-server.org/ for more info!"
gtk "gtk_message_dialog_new $WINDOW 0 0 2 \"$TMP\""
ABOUT=$RESULT
}

#------------------------------------------------ CDLOOKUP

function Lookup_CD
{
# First remove existing tracks from widget
if [[ $TRACKS -gt 0 ]]
then
        COUNTER=0
        until [[ $COUNTER -eq $TRACKS ]]
        do
                gtk "gtk_combo_box_remove_text $G_COMBO 0"
                let COUNTER=$COUNTER+1
        done
fi
# Lookup information from CDDB
$CDDA2WAV -D $CDROM -J -v titles -L 1 -N -H 2>&1 | tr -d "'" | $AWK '/Album/ {print} /Track/ {print}' > /tmp/CD.txt

# Determine amount of tracks (includes album title)
TRACKS=`cat /tmp/CD.txt | wc -l`

# If no tracks then reread CD
if [[ $TRACKS -lt 2 ]]
then
        # Restore default title
        if [[ $TRACKS -eq 1 ]]
        then
                L_TITLE=`cat /tmp/CD.txt | $AWK '/Album/ {print substr($0, index($0, ":") + 1)}'`
                gtk "gtk_window_set_title $WINDOW \"$L_TITLE\""
        else
                gtk "gtk_window_set_title $WINDOW \"CD Player\""
        fi
        # Find amount of tracks on CD
        $CDDA2WAV -D $CDROM -J -v toc -L 1 -N -H 2>&1 | tr -d "'" | $AWK 'BEGIN {ORS=""} /[0-9]:[0-9]/ {print}' > /tmp/CD.txt
        TRACKS=`cat /tmp/CD.txt | $AWK 'BEGIN {RS=","} {print}' | wc -l`
        # Add track numbering to combobox
        COUNTER=0
        until [[ $COUNTER -eq $TRACKS ]]
        do
                let TMP=$COUNTER+1
                L_TRACK="$TMP - Unknown track"
                gtk "gtk_combo_box_append_text $G_COMBO \"$L_TRACK\""
                let COUNTER=$COUNTER+1
        done
else
        # Add CD title to window title 
        L_TITLE=`cat /tmp/CD.txt | $AWK '/Album/ {print substr($0, index($0, ":") + 1)}'`
        gtk "gtk_window_set_title $WINDOW \"$L_TITLE\""
        # Add tracks to combobox
        COUNTER=1
        until [[ $COUNTER -eq $TRACKS ]]
        do
                L_TRACK=`grep "Track  $COUNTER" /tmp/CD.txt`
                if [[ -z $L_TRACK ]]
                then
                        L_TRACK=`grep "Track $COUNTER" /tmp/CD.txt`
                fi
                TMP=`echo $L_TRACK | $AWK '{gsub(/"/, ""); print}'`
                gtk "g_locale_to_utf8 \"$TMP\" -1 NULL NULL NULL"
                L_TRACK=$RESULT
                gtk "gtk_combo_box_append_text $G_COMBO \"$L_TRACK\""
                let COUNTER=$COUNTER+1
        done
        # Put amount of tracks to real value
        ((TRACKS-=1))
fi

# Put first item as active one
gtk "gtk_combo_box_set_active $G_COMBO 0"
}

#------------------------------------------------ STOP

function Stop_CD
{
# Only if PID exists, kill process
if [[ -n $P_PID ]]
then
        STOPPED=1
        kill -9 $P_PID >/dev/null 2>&1
        $SLEEP 1
        P_PID=""
fi
}

#------------------------------------------------ PLAY

function Play_CD
{
# Get selected track from combo
gtk "gtk_combo_box_get_active $G_COMBO"
let P_TRACK=$RESULT+1

# Kill existing playing process first
Stop_CD

# Start playing and save PID
$CDDA2WAV -D $CDROM -q -e -t$P_TRACK -d0 -N >/dev/null 2>&1 &

# Unset stopped flag
STOPPED=0

# Save ProcessID
P_PID=`jobs -p | head -1`
}

#------------------------------------------------ SELECT NEXT TRACK

function Action_Track
{
# Find out if track currently is being played
TMP=`jobs -l | grep $P_PID 2>/dev/null`

# If not, and not stopped, goto next track
if [[ -z $TMP && $STOPPED -eq 0 ]]
then
        # Get selected track from combo
        gtk "gtk_combo_box_get_active $G_COMBO"
        let P_TRACK=$RESULT+1

        # Put to next track
        if [[ $P_TRACK -lt $TRACKS ]]
        then
                # Put combobox to next track, inducing signal
                gtk "gtk_combo_box_set_active $G_COMBO $P_TRACK"
        fi
fi
}

#------------------------------------------------ VOLUME

function Adjust_Volume
{
# Get current value
gtk "gtk_range_get_value $G_VOLUME"
let V_VOL=100-`$AWK -v VAR=$RESULT 'BEGIN {print int(VAR)}'`

case $MIXER in
        `which rexima 2>/dev/null`) $MIXER pcm $V_VOL;;
        `which aumix 2>/dev/null`) $MIXER -w $V_VOL;;
esac
}

#------------------------------------------------ MAIN

# Set global variables
CDROM=/dev/cdrom

# Check available packages
Check_Software

# Create GUI
Build_Gui

# Get CD info
Lookup_CD

# Put volume to default
Adjust_Volume

# Initialize variables
EVENT=0

# Mainloop
while [[ $EVENT -ne $WINDOW && $EVENT -ne $G_BUTTON_QUIT ]]
do
        # Wait for event
        gtk "gtk_server_callback UPDATE"
        EVENT=$RESULT

        # Check events
        case $EVENT in

                # If refresh button is pressed
                $G_BUTTON_REFRESH)
                        Lookup_CD;;

                # If help button is pressed
                $G_BUTTON_HELP)
                        gtk "gtk_widget_show $ABOUT";;

                # If OK button in HELP dialog is pressed
                $ABOUT)
                        gtk "gtk_widget_hide $ABOUT";;

                # If stop button is pressed
                $G_BUTTON_STOP)
                        Stop_CD;;

                # If volume slider is moved
                $G_VOLUME)
                        Adjust_Volume;;

                # If combobox is changed
                $G_COMBO)
                        Play_CD;;
        esac

        # Check if we need to go to next track
        Action_Track

        # Avoid 99% CPU load
        $SLEEP 0.05

done

# Before exiting, stop playing CD
Stop_CD

# Remove temporary file
rm /tmp/CD.txt

# Exit GTK
gtk "gtk_exit 0"