#!/usr/bin/wish -f # # TiMidity++ -- MIDI to WAVE converter and player # Copyright (C) 1999-2002 Masanao Izumo # Copyright (C) 1995 Tuukka Toivonen # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # TkMidity -- Tcl/Tk Interface for TiMidity # written by Takashi IWAI # # Tk control panel routine # #---------------- # initialize global variables # proc InitGlobal {} { global Stat tk_patchLevel if [catch {expr $Stat(new_tcltk) == 0 || $Stat(new_tcltk) == 1}] { set Stat(new_tcltk) 0 if [regexp "(\[0-9\]+\.\[0-9\]+)" $tk_patchLevel cur] { if {$cur >= 4.0} { set Stat(new_tcltk) 1 } } } # time table and volume set Stat(MaxSecs) 0 set Stat(LastSec) 0 set Stat(TotalTimeStr) "/ 0:00" # message lines set Stat(CurMsgs) 0 set Stat(MaxMsgs) 500 # current status set Stat(Playing) 0 set Stat(Paused) 0 set Stat(Blinking) 0 # MIDI file list set Stat(CurIdx) -1 set Stat(MaxFiles) 0 set Stat(FileList) {} set Stat(ShuffleList) {} set Stat(CurFile) "--------" set Stat(NextFile) "--------" global Config # playing mode set Config(Tracing) 0 set Config(RepeatPlay) 0 set Config(ShufflePlay) 0 set Config(AutoStart) 0 set Config(AutoExit) 0 set Config(ConfirmExit) 1 # display configuration set Config(Disp:file) 1 set Config(Disp:time) 1 set Config(Disp:text) 1 set Config(Disp:volume) 1 set Config(Disp:button) 1 set Config(Disp:trace) 1 set Config(CurFileMode) 0 # current volume set Config(CurVol) 75 wm title . "TkMidity" wm iconname . "TkMidity" global bitmap_path wm iconbitmap . "timidity" } #---------------- # read a message from stdin # proc HandleInput {} { global Stat Config set mlist [gets stdin] set msg [lindex $mlist 0] if {$msg == "RSET"} { if {$Config(Tracing)} { TraceReset } } elseif {$msg == "TIME"} { # set total time set csecs [expr [lindex $mlist 1] / 100] set mins [expr $csecs / 60] set secs [expr $csecs % 60] set Stat(TotalTimeStr) [format "/ %d:%02d" $mins $secs] set Stat(MaxSecs) $csecs set tics [expr $csecs / 8] set tics [expr (($tics + 4) / 5) * 5] .body.time.scale configure -tickinterval $tics -to $csecs SetTime 0 } elseif {$msg == "MVOL"} { # set master volume SetVolume [lindex $mlist 1] } elseif {$msg == "FILE"} { # set playing file set Stat(CurFile) [retrieve-filename [lindex $mlist 1]] wm title . "TkMidity: $Stat(CurFile)" wm iconname . "TkMidity: $Stat(CurFile)" if {$Config(CurFileMode) == 0} { .body.curfile configure -text "$Stat(CurFile) / 00:00" } else { .body.curfile configure -text "$Stat(CurFile) / -$Stat(TotalTimeStr)" } AppendMsg "------" } elseif {$msg == "LIST"} { # set file list .body.file.list delete 0 end set Stat(MaxFiles) [lindex $mlist 1] set Stat(FileList) {} for {set i 0} {$i < $Stat(MaxFiles)} {incr i} { set file [gets stdin] .body.file.list insert end $file lappend Stat(FileList) $file } set Stat(CurIdx) -1 SelectNumber } elseif {$msg == "ALST"} { # append file list set i $Stat(MaxFiles) set Stat(MaxFiles) [expr $i + [lindex $mlist 1]] for {} {$i < $Stat(MaxFiles)} {incr i} { set file [gets stdin] .body.file.list insert end $file if {$Config(ShufflePlay)} { lappend Stat(ShuffleList) [llength $Stat(FileList)] } lappend Stat(FileList) $file } .body.file.list select set $Stat(CurIdx) } elseif {$msg == "ERRR"} { # delete file list .body.file.list delete $Stat(CurIdx) set Stat(MaxFiles) [expr $Stat(MaxFiles) - 1] set tmplist {} for {set i 0} {$i < $Stat(CurIdx)} {incr i} { lappend tmplist [lindex $Stat(FileList) $i] } for {set i $Stat(CurIdx)} {$i < $Stat(MaxFiles)} {incr i} { lappend tmplist [lindex $Stat(FileList) [expr $i + 1]] } set Stat(FileList) {} for {set i 0} {$i < $Stat(MaxFiles)} {incr i} { lappend Stat(FileList) [lindex $tmplist $i] } if {$Stat(CurIdx) >= $Stat(MaxFiles)} { if {$Config(RepeatPlay)} { set Stat(CurIdx) 0 } elseif {$Config(AutoExit)} { QuitCmd } else { StopCmd } } SelectNumber } elseif {$msg == "PREV"} { # previous file set Stat(CurIdx) [expr $Stat(CurIdx) - 1] if {$Stat(CurIdx) < 0} {set Stat(CurIdx) 0} SelectNumber } elseif {$msg == "NEXT"||$msg == "TEND"} { # next file incr Stat(CurIdx) if {$Stat(CurIdx) >= $Stat(MaxFiles)} { if {$Config(RepeatPlay)} { set Stat(CurIdx) 0 } elseif {$Config(AutoExit)} { QuitCmd } else { StopCmd } } SelectNumber } elseif {$msg == "CMSG"} { # put message set type [lindex $mlist 1] set str [gets stdin] AppendMsg $str } elseif {$msg == "LYRC"} { # put message set type [lindex $mlist 1] set str [gets stdin] .body.text.buf insert end $str } elseif {$msg == "CERR"} { error [format "%s: %s" $Stat(NextFile) [gets stdin]] WriteMsg "NEXT" } elseif {$msg == "QUIT"} { # quit exit } elseif {$msg == "RSTA"} { # restart file SelectNumber } } #---------------- # make shuffled list # proc MakeShuffleList {} { global Stat set Stat(ShuffleList) {} for {set i 0} {$i < $Stat(MaxFiles)} {incr i} { lappend Stat(ShuffleList) $i } set len [expr $Stat(MaxFiles) - 1] while {$len > 0} { set pos [my-random [expr $len + 1]] set tmp [lindex $Stat(ShuffleList) $pos] set Stat(ShuffleList) [lreplace $Stat(ShuffleList) $pos $pos \ [lindex $Stat(ShuffleList) $len]] set Stat(ShuffleList) [lreplace $Stat(ShuffleList) $len $len $tmp] set len [expr $len - 1] } } # # append a string to message buffer # proc AppendMsg {str} { global Stat incr Stat(CurMsgs) if {$Stat(CurMsgs) >= $Stat(MaxMsgs)} { ClearMsg } .body.text.buf insert end $str\n .body.text.buf yview -pickplace end } # # clear message buffer # proc ClearMsg {} { global Stat .body.text.buf delete 0.0 end .body.text.buf yview 0 set Stat(CurMsgs) 0 } #---------------- # select the file in listbox and load it # proc SelectNumber {} { global Stat Config if {$Stat(new_tcltk)} { .body.file.list select clear 0 end } else { .body.file.list select clear } set idx -1 if {$Stat(CurIdx) >= 0 && $Stat(CurIdx) < [llength $Stat(FileList)]} { if {$Config(ShufflePlay)} { if {$Stat(ShuffleList) == {}} { MakeShuffleList } set idx [lindex $Stat(ShuffleList) $Stat(CurIdx)] } else { set idx $Stat(CurIdx) } set thefile [lindex $Stat(FileList) $idx] set Stat(NextFile) $thefile } if {$idx >= 0} { if {$Stat(new_tcltk)} { # .body.file.list select set $idx } else { # .body.file.list select from $idx # .body.file.list select to $idx } .body.curfile configure -text\ "Playing: [lindex $Stat(FileList) $idx]" LoadCmd $idx set Stat(Playing) 1 } else { SetTime 0 .body.curfile configure -text "-------- / 00:00" set Stat(Playing) 0 set Stat(Paused) 0 } DispButtonPlay } # # update current time # proc SetTime {val} { global Stat Config if {$Stat(CurIdx) == -1} { return } set Stat(LastSec) $val if {$Config(CurFileMode) == 0} { set curt [sec2time $val] .body.curfile configure\ -text "$Stat(CurFile) / $curt" } else { set curt [sec2time [expr $val - $Stat(MaxSecs)]] .body.curfile configure\ -text "$Stat(CurFile) / $curt" } set curt [sec2time $val] .body.time.label configure\ -text "$curt / $Stat(TotalTimeStr)" .body.time.scale set $val DispButtonPlay } # # colorize buttons with each state # proc DispButtonPlay {} { global Stat if {$Stat(Playing)} { if {$Stat(Blinking)} { set color green set Stat(Blinking) 0 } else { set color red set Stat(Blinking) 1 } .body.button.play configure -fg $color -activeforeground $color } else { .body.button.play configure -fg black -activeforeground black } if {$Stat(Playing) && $Stat(Paused)} { .body.button.pause configure -fg red -activeforeground red } else { .body.button.pause configure -fg black -activeforeground black } } # # update current volume # proc SetVolume {val} { global Config set Config(CurVol) $val .body.volume.scale set $val } #---------------- # write message # messages are: PREV, NEXT, QUIT, FWRD, BACK, RSET, STOP # LOAD\n, JUMP