#!/bin/sh
# the next line restarts using wish \
exec wish8.4 "$0" "$@"

package require -exact snack 2.2

set currentDirectory [pwd]

# Button and Label texts
set ExampleTxt "Example"
set PinyinTxt "Pinyin"
set ClearTxt "Clear"
set SubmitTxt "Submit"
set QuitTxt "Quit"

set WrongTxt "Wrong"
set CorrectTxt "Correct"
set InvalidTxt "Invalid"
set WordListTitleTxt "Open a pinyin word list (one word per line)"

# Initializations
set RecordedSound 0
set pinyin "duo1shao3"
set ExamplePinyin $pinyin
set ExamplesDirectory "examples"
set StandardWordList "SGC_protWordList.txt"
set WordList {}
# This list gets the files path as the second argument in the WordList file
# It will force recognition of these files for debugging
set AutoFileList {}
set standardlogPerf 1
set logPerf $standardlogPerf

# Call initialization routines
if {[file readable $currentDirectory/lastResult.txt]} {
  set fileID [open $currentDirectory/lastResult.txt {RDONLY}]
  gets $fileID lastResult
  close $fileID
  set pinyin [lindex $lastResult 3]
  set ExamplePinyin $pinyin
}

proc ReadWordList {filename} {
    global WordList
    global AutoFileList
    global currentSoundFileName
    global currentExampleFileName
    global pinyin
    global ExamplePinyin
    global logPerf

    if {[file readable $filename]} {
        set WordList {}
        set AutoFileList {}
        
        set f [open $filename]
        foreach line [split [read $f] \n] {
            if {[string length $line]} {
                # Process log files
                if {[llength $line] > 3} {
                    set directory ""
                    if {[regexp "logFile\.txt" $filename]} {set directory "log/"}
                    set line "[lindex $line 1] $directory[lindex $line end]"
                }
                # Also store any file names
                if {[llength $line] > 1} {
                    lappend AutoFileList [lindex $line 1]
                }
                lappend WordList [lindex $line 0]
            }
        }
        close $f
        if {[llength $AutoFileList] > 0} {
            set logPerf 0
        }
        
        # Pick first random word
        if {[llength $WordList] > 0} {
          set i [expr {int(rand()*[llength $WordList])}]
          set pinyin [lindex $WordList $i]
          if {[llength $AutoFileList] > 0} {
            set currentSoundFileName [lindex $AutoFileList $i]
            set currentExampleFileName $currentSoundFileName
            set ExamplePinyin $pinyin
            s configure -file $currentSoundFileName
            SetTime [s length -unit sec]
          }
        }
    }
}

ReadWordList "$currentDirectory/$StandardWordList"

# Where to find the files
set standardSoundFileName "currentSound.wav"
set currentSoundFileName $standardSoundFileName
set standardExampleFileName "lastExample.wav"
set currentExampleFileName $standardExampleFileName

set Platform "MSWindows"

# Platform dependend commands
switch $Platform {
"Linux" {
set PraatCommand "./praatLinux"
set SendPraatCommand "./sendpraatLinux"
set TimeOut 1000
set PraatName "praatLinux"
    }
"Mac" {
set PraatCommand "./praatMac"
set SendPraatCommand "./sendpraatMac"
set TimeOut 1000
set PraatName "praatMac"
}
"MSWindows" -
default {
    set PraatCommand "$currentDirectory/praatWin.exe"
    set SendPraatCommand "$currentDirectory/sendpraatWin.exe"
    set PraatName "Praat"
    set TimeOut 0
    }
}

# Define commands
# (watch out for trailing spaces)
set QuitCommand        [list exec $SendPraatCommand "$PraatName" "Quit" "&"]
if {$TimeOut > 0} {set QuitCommand [linsert $QuitCommand 2 $TimeOut]}
set PlayExampleCommand [list exec $SendPraatCommand "$PraatName" {execute "$currentDirectory/PlayPronExample.praat" "$ExamplesDirectory" $pinyin} "&"]
if {$TimeOut > 0} {set PlayExampleCommand [linsert $PlayExampleCommand 2 $TimeOut]}
set RecognizeCommand   [list exec $SendPraatCommand "$PraatName" {execute "$currentDirectory/SGC_PronProt.praat" "$currentDirectory/$currentSoundFileName" $pinyin $logPerf} ]
if {$TimeOut > 0} {set RecognizeCommand [linsert $RecognizeCommand 2 $TimeOut]}

exec "$PraatCommand" "&"

# Start of Audio SNACK stuff
file delete _tmprec.wav
snack::sound t -debug 0
t write _tmprec.wav
snack::sound s -file _tmprec.wav -debug 0

# Menues
set m [menu .menu]
$m add cascade -label File -menu $m.file -underline 0
menu $m.file -tearoff 0
$m.file add command -label "Open..." -command [list OpenSound]
$m.file add command -label "Save As..." -command [list SaveSound]
$m.file add command -label "$QuitTxt" -command Destroy

$m add cascade -label Audio -menu $m.audio -underline 0
menu $m.audio -tearoff 0
$m.audio add command -label "Settings..." -command Settings
$m.audio add command -label "Mixer..." -command snack::mixerDialog

$m add cascade -label Tools -menu $m.tools -underline 0
menu $m.tools -tearoff 0
$m.tools add command -label "Replay" -command ReplayLogFile
$m.tools add command -label "Open word list..." -command GetWordList
$m.tools add command -label "Close word list" -command "set WordList {}"

. config -menu $m

# UI frames
pack [frame .fa] -pady 5
button .fa.b1 -text "$ExampleTxt" -command PlayExample
label .fa.l1 -text "$PinyinTxt:"
entry .fa.e1 -width 12 -relief sunken -bd 2 -textvariable pinyin
button .fa.b3 -text "$ClearTxt" -command {set pinyin ""}
button .fa.b4 -text "$QuitTxt"  -command Destroy
pack .fa.b1 .fa.l1 .fa.e1 .fa.b3 .fa.b4 -side left

snack::createIcons

pack [frame .f1] -pady 5
button .f1.bp -bitmap snackPlay -command Play
button .f1.bu -bitmap snackPause -command Pause
button .f1.bs -bitmap snackStop -command Stop
button .f1.br -bitmap snackRecord -command Record -fg red
button .f1.b1 -text "$SubmitTxt" -command Recognize
pack .f1.bp .f1.bu .f1.bs .f1.br .f1.b1 -side left

pack [frame .f2] -pady 5
label .f2.time -text "00:00.0" -width 10
snack::levelMeter .f2.lm
pack .f2.time .f2.lm -side left

pack [frame .f5] -pady 5
label .f5.l1 -text "-------"
pack .f5.l1 -side left


wm protocol . WM_DELETE_WINDOW Destroy

# Procedure definitions

proc OpenSound {} {
    set filename [snack::getOpenFile]
    s configure -file $filename
    SetTime [s length -unit sec]
}

proc SaveSound {} {
    set filename [snack::getSaveFile]
    s write $filename
}

proc Settings {} {
 set ::s(rate) [s cget -rate]
 set ::s(enc)  [s cget -encoding]
 set ::s(chan) [s cget -channels]

 set w .conv
 catch {destroy $w}
 toplevel $w
 wm title $w Settings

 frame $w.q
 pack $w.q -expand 1 -fill both -side top
 pack [frame $w.q.f1] -side left -anchor nw -padx 3m -pady 2m
 pack [frame $w.q.f2] -side left -anchor nw -padx 3m -pady 2m
 pack [frame $w.q.f3] -side left -anchor nw -padx 3m -pady 2m
 pack [frame $w.q.f4] -side left -anchor nw -padx 3m -pady 2m
 pack [label $w.q.f1.l -text "Sample Rate"]
 foreach e [snack::audio rates] {
  pack [radiobutton $w.q.f1.r$e -text $e -value $e -variable ::s(rate)] \
	  -anchor w
 }
 pack [entry $w.q.f1.e -textvariable ::s(rate) -width 6] -anchor w
 pack [label $w.q.f2.l -text "Sample Encoding"]
 foreach e [snack::audio encodings] {
  pack [radiobutton $w.q.f2.r$e -text $e -value $e -variable ::s(enc)] \
	  -anchor w
 }
 pack [label $w.q.f3.l -text Channels]
 pack [radiobutton $w.q.f3.1 -text Mono -value 1 -variable ::s(chan)] -anchor w
 pack [radiobutton $w.q.f3.2 -text Stereo -value 2 -variable ::s(chan)] \
	 -anchor w
 pack [entry $w.q.f3.e -textvariable ::s(chan) -width 3] -anchor w

 pack [ frame $w.f3]
 pack [ button $w.f3.b1 -text OK -width 6 \
	 -command "ApplySettings;destroy $w"] -side left
 pack [ button $w.f3.b2 -text Cancel -command "destroy $w"] -side left
}

proc ApplySettings {} {
 s configure -file ""
 s configure -rate $::s(rate) -channels $::s(chan) -encoding $::s(enc)
 t configure -rate $::s(rate) -channels $::s(chan) -encoding $::s(enc)
 t write _tmprec.wav
 s configure -file _tmprec.wav
}

proc SetTime {t} {
 set mmss [clock format [expr int($t)] -format "%M:%S"]
 .f2.time config -text $mmss.[format "%d" [expr int(10*($t-int($t)))]]
}

proc Update {} {
 if {$::op == "p"} {
  set t [audio elapsed]
  set end   [expr int([s cget -rate] * $t)]
  set start [expr $end - [s cget -rate] / 10]
  if {$start < 0} { set start 0}
  if {$end >= [s length]} { set end -1 }
  set l [s max -start $start -end $end]
 } else {
  set l [t max]
  t length 0
  set t [s length -unit sec]
 }
 SetTime $t
 .f2.lm configure -level $l
 
 after 100 Update
}

proc Record {} {
 s stop
 s configure -file _tmprec.wav
 s record
 t record
 set ::op r
 .f1.bp configure -relief raised
 .f1.br configure -relief groove
 
 global RecordedSound
 set RecordedSound 1
 }

proc GetWordList {} {
    global WordListTitleTxt
    set filename [tk_getOpenFile -title "$WordListTitleTxt"]
    ReadWordList "$filename"
}

proc ReplayLogFile {} {
    ReadWordList "logFile.txt"
}

proc CloseWordList {} {
    global WordList
    global AutoFileList
    global currentSoundFileName
    global standardSoundFileName
    global currentExampleFileName
    global standardExampleFileName
    global logPerf
    global standardlogPerf
    
    set WordList {}
    set AutoFileList {}
    set currentSoundFileName $standardSoundFileName
    set currentExampleFileName $standardExampleFileName
    set logPerf $standardlogPerf
}

proc Recognize {} {
  global currentSoundFileName
  global currentExampleFileName
  global register
  global pinyin
  global ExamplePinyin
  global RecognizeCommand
  global currentDirectory
  global CorrectTxt
  global WrongTxt
  global WordList
  global AutoFileList
  global logPerf

# Stop any recording etc
  Stop
    
  set textColor blue
  set Evaluation "---------"
  
  set currentDirectory [pwd]
  eval [subst $RecognizeCommand]

  set ExamplePinyin $pinyin
  set fileID [open $currentDirectory/lastResult.txt {RDONLY}]
  gets $fileID lastResult
  close $fileID
  set Recognition [regsub -all {6} [lindex $lastResult 2] {?}]
  
  if {[lindex $lastResult 0] == "Correct:"} {
    set Evaluation $CorrectTxt
    set textColor {dark green}
  } else {
    set Evaluation $WrongTxt
    set textColor {dark red}
  }
  .f5.l1 configure -fg "$textColor" -text "$pinyin => $Evaluation: $Recognition"
  
  if {[llength $WordList] > 0} {
    set i [expr {int(rand()*[llength $WordList])}]
    set pinyin [lindex $WordList $i]
    if {[llength $AutoFileList] > 0} {
        set currentSoundFileName [lindex $AutoFileList $i]
        set currentExampleFileName $currentSoundFileName
        set ExamplePinyin $pinyin
        s configure -file $currentSoundFileName
        SetTime [s length -unit sec]
    }
  }
}

proc Destroy {} {
  global QuitCommand

  eval [subst $QuitCommand]
  destroy .
}

proc PlayExample {} {
  global currentExampleFileName
  global ExamplesDirectory
  global PlayExampleCommand
  global register
  global pinyin
  global ExamplePinyin
  global currentDirectory
  # Stop any recording etc
  Stop
  
  set currentDirectory [pwd]
  eval [subst $PlayExampleCommand]
}

#############

proc Play {} {
 t stop
 s stop
 s play -command Stop
 set ::op p
 .f1.bp configure -relief groove
 .f1.br configure -relief raised
 .f1.bu configure -relief raised
}

proc Stop {} {
 s stop
 t record
 set ::op s
 .f1.bp configure -relief raised
 .f1.br configure -relief raised
 .f1.bu configure -relief raised
 
 global RecordedSound
 if {$RecordedSound == 1} {
   global standardSoundFileName
   s write $standardSoundFileName
 }
 set RecordedSound 0

}

proc Pause {} {
 s pause
 if {$::op != "s"} {
     if {[.f1.bu cget -relief] == "raised"} {
	 .f1.bu configure -relief groove
     } else {
	 .f1.bu configure -relief raised
     }
 }
}

t record
set op s
Update

