1
#!/usr/local/bin/wishx -f
3
# TkMidity -- Tcl/Tk Interface for TiMidity
4
# written by Takashi IWAI
6
# Tk control panel routine
10
# initialize global variables
14
global Stat tk_patchLevel
16
if [catch {expr $Stat(new_tcltk) == 0 || $Stat(new_tcltk) == 1}] {
18
if [regexp "(\[0-9\]+\.\[0-9\]+)" $tk_patchLevel cur] {
25
# time table and volume
28
set Stat(TotalTimeStr) "/ 0:00"
43
set Stat(ShuffleList) {}
44
set Stat(CurFile) "--------"
45
set Stat(NextFile) "--------"
50
set Config(RepeatPlay) 0
51
set Config(ShufflePlay) 0
52
set Config(AutoStart) 0
53
set Config(AutoExit) 0
54
set Config(ConfirmExit) 1
56
# display configuration
57
set Config(Disp:file) 1
58
set Config(Disp:time) 1
59
set Config(Disp:text) 1
60
set Config(Disp:volume) 1
61
set Config(Disp:button) 1
62
set Config(Disp:trace) 1
64
set Config(CurFileMode) 0
67
set Config(CurVol) 100
69
wm title . "TkAWEMidi"
70
wm iconname . "TkAWEMidi"
72
wm iconbitmap . @$bitmap_path/timidity.xbm
77
# read a message from stdin
82
set mlist [gets stdin]
83
set msg [lindex $mlist 0]
86
if {$Config(Tracing)} {
89
} elseif {$msg == "TIME"} {
91
set csecs [expr [lindex $mlist 1] / 100]
92
set mins [expr $csecs / 60]
93
set secs [expr $csecs % 60]
94
set Stat(TotalTimeStr) [format "/ %d:%02d" $mins $secs]
95
set Stat(MaxSecs) $csecs
96
set tics [expr $csecs / 8]
97
set tics [expr (($tics + 4) / 5) * 5]
98
.body.time.scale configure -tickinterval $tics -to $csecs
101
} elseif {$msg == "MVOL"} {
103
SetVolume [lindex $mlist 1]
105
} elseif {$msg == "FILE"} {
107
set Stat(CurFile) [retrieve-filename [lindex $mlist 1]]
108
wm title . "TkAWEMidi: $Stat(CurFile)"
109
wm iconname . "TkAWEMidi: $Stat(CurFile)"
110
if {$Config(CurFileMode) == 0} {
111
.body.curfile configure -text "$Stat(CurFile) / 00:00"
113
.body.curfile configure -text "$Stat(CurFile) / -$Stat(TotalTimeStr)"
117
} elseif {$msg == "LIST"} {
119
.body.file.list delete 0 end
120
set Stat(MaxFiles) [lindex $mlist 1]
121
set Stat(FileList) {}
122
for {set i 0} {$i < $Stat(MaxFiles)} {incr i} {
123
set file [gets stdin]
124
.body.file.list insert end $file
125
lappend Stat(FileList) $file
132
} elseif {$msg == "PREV"} {
134
set Stat(CurIdx) [expr $Stat(CurIdx) - 1]
135
if {$Stat(CurIdx) < 0} {set Stat(CurIdx) 0}
138
} elseif {$msg == "NEXT" || $msg == "TEND"} {
141
if {$Stat(CurIdx) >= $Stat(MaxFiles)} {
142
if {$Config(RepeatPlay)} {
144
} elseif {$Config(AutoExit)} {
152
} elseif {$msg == "CMSG"} {
154
set type [lindex $mlist 1]
158
} elseif {$msg == "CERR"} {
159
error [format "%s: %s" $Stat(NextFile) [gets stdin]]
162
} elseif {$msg == "QUIT"} {
165
} elseif {$msg == "RSTA"} {
175
proc MakeShuffleList {} {
178
for {set i 0} {$i < $Stat(MaxFiles)} {incr i} {
181
set Stat(ShuffleList) {}
182
set len $Stat(MaxFiles)
184
set pos [my-random $len]
185
lappend Stat(ShuffleList) [lindex $tmplist $pos]
186
set tmplist [lreplace $tmplist $pos $pos]
187
set len [expr $len - 1]
192
# append a string to message buffer
194
proc AppendMsg {str} {
198
if {$Stat(CurMsgs) >= $Stat(MaxMsgs)} { ClearMsg }
200
if [regexp "^(~)(.*)" $str foo til rem] {
208
.body.text.buf insert end $rem\n
210
.body.text.buf insert end $rem
212
.body.text.buf yview -pickplace end
216
# clear message buffer
220
.body.text.buf delete 0.0 end
221
.body.text.buf yview 0
227
# select the file in listbox and load it
229
proc SelectNumber {} {
231
if {$Stat(new_tcltk)} {
232
.body.file.list select clear 0 end
234
.body.file.list select clear
237
if {$Stat(CurIdx) >= 0 && $Stat(CurIdx) < [llength $Stat(FileList)]} {
238
if {$Config(ShufflePlay)} {
239
if {$Stat(ShuffleList) == {}} {
242
set idx [lindex $Stat(ShuffleList) $Stat(CurIdx)]
244
set idx $Stat(CurIdx)
246
set thefile [lindex $Stat(FileList) $idx]
247
set Stat(NextFile) $thefile
249
if {$idx >= 0 && ![file exists $thefile]} {
250
warning "Can't open file \"$thefile\"."
255
if {$Stat(new_tcltk)} {
256
.body.file.list select set $idx
258
.body.file.list select from $idx
259
.body.file.list select to $idx
261
.body.curfile configure -text\
262
"Playing: [lindex $Stat(FileList) $idx]"
267
.body.curfile configure -text "-------- / 00:00"
276
# update current time
280
if {$Stat(CurIdx) == -1} {
283
set Stat(LastSec) $val
284
if {$Config(CurFileMode) == 0} {
285
set curt [sec2time $val]
286
.body.curfile configure\
287
-text "$Stat(CurFile) / $curt"
289
set curt [sec2time [expr $val - $Stat(MaxSecs)]]
290
.body.curfile configure\
291
-text "$Stat(CurFile) / $curt"
293
set curt [sec2time $val]
294
.body.time.label configure\
295
-text "$curt / $Stat(TotalTimeStr)"
296
.body.time.scale set $val
302
# colorize buttons with each state
304
proc DispButtonPlay {} {
306
if {$Stat(Playing)} {
307
if {$Stat(Blinking)} {
314
.body.button.play configure -fg $color -activeforeground $color
316
.body.button.play configure -fg black -activeforeground black
319
if {$Stat(Playing) && $Stat(Paused)} {
320
.body.button.pause configure -fg red -activeforeground red
322
.body.button.pause configure -fg black -activeforeground black
328
# update current volume
330
proc SetVolume {val} {
332
set Config(CurVol) $val
333
.body.volume.scale set $val
339
# messages are: PREV, NEXT, QUIT, FWRD, BACK, RSET, STOP
340
# LOAD\n<filename>, JUMP <time>, VOLM <volume>
343
proc WriteMsg {str} {
354
# jump to specified time
358
if {$val != $Stat(LastSec)} {
359
WriteMsg [format "JUMP %d" [expr $val * 100]]
364
# change volume amplitude
366
proc VolumeCmd {val {force 0}} {
368
if {$val < 0} {set val 0}
369
if {$val > 200} {set val 200}
370
if {$force != 0 || $val != $Config(CurVol)} {
371
WriteMsg [format "VOLM %d" $val]
376
# load the specified file
381
WriteMsg [lindex $Stat(FileList) $idx]
383
VolumeCmd $Config(CurVol) 1
387
# play the first file
391
if {$Stat(Playing) == 0} {
401
if {$Stat(Playing)} {
417
if {$Stat(Playing)} {
422
if {$Config(Tracing)} {
425
wm title . "TkAWEMidi"
426
wm iconname . "TkAWEMidi"
435
if {$Config(AutoExit) || !$Config(ConfirmExit)} {
440
set oldpause $Stat(Paused)
441
if {!$oldpause} {PauseCmd}
442
if {[question "Really Quit TkMidity?" 0]} {
447
if {!$oldpause} {PauseCmd}
455
if {$Stat(Playing)} {
465
if {$Stat(Playing)} {
471
# forward/backward 2 secs
475
if {$Stat(Playing)} {
480
proc BackwardCmd {} {
482
if {$Stat(Playing)} {
493
if {$Stat(Playing)} {
494
VolumeCmd [expr $Config(CurVol) + 5]
500
if {$Stat(Playing)} {
501
VolumeCmd [expr $Config(CurVol) - 5]
506
# display configured tables
510
set allitems {file time text volume button trace}
512
foreach i $allitems {
514
if {$Config(Disp:$i)} {
515
pack .body.$i -side top -fill x
521
# save configuration and playing mode
524
global Config ConfigFile
525
set fd [open $ConfigFile w]
527
puts $fd "global Config"
528
foreach i [array names Config] {
529
puts $fd "set Config($i) $Config($i)"
536
# load configuration file
539
global ConfigFile Stat
540
catch {source $ConfigFile}
546
proc InitCmdLine {argc argv} {
548
set Config(Disp:trace) 0
549
for {set i 0} {$i < $argc} {incr i} {
550
if {[lindex $argv $i] == "-mode"} {
552
set mode [lindex $argv $i]
553
if {$mode == "trace"} {
554
set Config(Tracing) 1
555
set Config(Disp:trace) 1
556
} elseif {$mode == "shuffle"} {
557
set Config(ShufflePlay) 1
558
} elseif {$mode == "normal"} {
559
set Config(ShufflePlay) 0
560
} elseif {$mode == "autostart"} {
561
set Config(AutoStart) 1
562
} elseif {$mode == "autoexit"} {
563
set Config(AutoExit) 1
564
} elseif {$mode == "repeat"} {
565
set Config(RepeatPlay) 1
573
# selection callback of the playing file from listbox
575
proc SelectList {lw pos} {
577
set idx [$lw nearest $pos]
578
if {$idx >= 0 && $idx < $Stat(MaxFiles)} {
579
if {$Config(ShufflePlay)} {
580
set found [lsearch -exact $Stat(ShuffleList) $idx]
582
set Stat(CurIdx) $found
585
set Stat(CurIdx) $idx
598
set files [filebrowser .browser "" "*.mid*"]
600
set Stat(MaxFiles) [expr $Stat(MaxFiles) + [llength $files]]
602
.body.file.list insert end $i
603
lappend Stat(FileList) $i
614
if {[question "Really Clear List?" 0]} {
616
.body.file.list delete 0 end
618
set Stat(FileList) {}
619
set Stat(SuffleList) {}
623
proc ToggleCurFileMode {} {
625
if {$Config(CurFileMode) == 0} {
626
set Config(CurFileMode) 1
628
set Config(CurFileMode) 0
630
SetTime $Stat(LastSec)
637
proc CreateWindow {} {
641
frame .menu -relief raised -bd 1
642
pack .menu -side top -expand 1 -fill x
645
menubutton .menu.file -text "File" -menu .menu.file.m\
648
.menu.file.m add command -label "Open Files" -underline 0\
650
.menu.file.m add command -label "Clear List" -underline 0\
652
.menu.file.m add command -label "Save Config" -underline 0\
654
.menu.file.m add command -label "About" -underline 0\
656
information "TkMidity -- TiMidty Tcl/Tk Version\n written by T.IWAI"
658
.menu.file.m add command -label "Quit" -underline 0\
662
menubutton .menu.mode -text "Mode" -menu .menu.mode.m\
665
.menu.mode.m add check -label "Repeat" -underline 0\
666
-variable Config(RepeatPlay)
667
.menu.mode.m add check -label "Shuffle" -underline 0\
668
-variable Config(ShufflePlay) -command {
669
if {$Config(ShufflePlay)} {MakeShuffleList}
671
.menu.mode.m add check -label "Auto Start" -underline 5\
672
-variable Config(AutoStart)
673
.menu.mode.m add check -label "Auto Exit" -underline 5\
674
-variable Config(AutoExit)
675
.menu.mode.m add check -label "Confirm Quit" -underline 0\
676
-variable Config(ConfirmExit)
679
menubutton .menu.disp -text "Display" -menu .menu.disp.m\
682
.menu.disp.m add check -label "File List" -underline 0\
683
-variable Config(Disp:file) -command "DispTables"
684
.menu.disp.m add check -label "Time" -underline 0\
685
-variable Config(Disp:time) -command "DispTables"
686
.menu.disp.m add check -label "Messages" -underline 0\
687
-variable Config(Disp:text) -command "DispTables"
688
.menu.disp.m add check -label "Volume" -underline 0\
689
-variable Config(Disp:volume) -command "DispTables"
690
.menu.disp.m add check -label "Buttons" -underline 0\
691
-variable Config(Disp:button) -command "DispTables"
692
if {$Config(Tracing)} {
693
.menu.disp.m add check -label "Trace" -underline 1\
694
-variable Config(Disp:trace) -command "DispTables"
697
pack .menu.file .menu.mode .menu.disp -side left
700
if {$Stat(new_tcltk)} {
701
frame .body -relief flat
703
frame .body -relief raised -bd 1
705
pack .body -side top -expand 1 -fill both
707
# current playing file
708
button .body.curfile -text "-------- / 00:00" -relief ridge\
709
-command "ToggleCurFileMode"
710
pack .body.curfile -side top -expand 1 -fill x
713
frame .body.file -relief raised -bd 1
714
scrollbar .body.file.bar -relief sunken\
715
-command ".body.file.list yview"
716
pack .body.file.bar -side right -fill y
717
if {$Stat(new_tcltk)} {
718
listbox .body.file.list -width 36 -height 10 -relief sunken -bd 2\
719
-yscroll ".body.file.bar set"
721
listbox .body.file.list -geometry 36x10 -relief sunken -bd 2\
722
-yscroll ".body.file.bar set"
724
bind .body.file.list <Button-1> {SelectList %W %y}
726
pack .body.file.list -side top -expand 1 -fill both
728
# time label and scale
729
frame .body.time -relief raised -bd 1
730
label .body.time.label -text "0:00 / 0:00"
731
pack .body.time.label -side top
732
scale .body.time.scale -orient horizontal -length 280\
733
-from 0 -to 100 -tickinterval 10
734
bind .body.time.scale <ButtonRelease-1> {JumpCmd [%W get]}
735
pack .body.time.scale -side bottom -expand 1 -fill x
738
frame .body.text -relief raised -bd 1
739
scrollbar .body.text.bar -relief sunken\
740
-command ".body.text.buf yview"
741
pack .body.text.bar -side right -fill y
742
text .body.text.buf -width 36 -height 12 -relief sunken -bd 2\
743
-wrap word -yscroll ".body.text.bar set"
744
bind .body.text.buf <Button-1> { }
745
bind .body.text.buf <Any-Key> { }
746
pack .body.text.buf -side top -expand 1 -fill both
747
button .body.text.clear -text "Clear"\
749
pack .body.text.clear -side bottom
751
# volume label and scale
752
frame .body.volume -relief raised -bd 1
753
label .body.volume.label -text "Volume:"
754
pack .body.volume.label -side top
755
scale .body.volume.scale -orient horizontal -length 280\
756
-from 0 -to 200 -tickinterval 25\
757
-showvalue true -label "Volume"\
759
pack .body.volume.scale -side bottom -expand 1 -fill x
763
frame .body.button -relief raised -bd 1
764
button .body.button.play -bitmap @$bitmap_path/play.xbm\
766
button .body.button.stop -bitmap @$bitmap_path/stop.xbm\
768
button .body.button.prev -bitmap @$bitmap_path/tprev.xbm\
770
button .body.button.back -bitmap @$bitmap_path/tback.xbm\
771
-command "BackwardCmd"
772
button .body.button.fwrd -bitmap @$bitmap_path/fwrd.xbm\
773
-command "ForwardCmd"
774
button .body.button.next -bitmap @$bitmap_path/tnext.xbm\
776
button .body.button.pause -bitmap @$bitmap_path/tpause.xbm\
778
button .body.button.quit -bitmap @$bitmap_path/tquit.xbm\
780
pack .body.button.play .body.button.pause\
781
.body.button.prev .body.button.back\
783
.body.button.fwrd .body.button.next\
785
-side left -ipadx 4 -pady 2 -fill x
787
if {$Config(Tracing)} {
797
tk_menuBar .menu .menu.file .menu.mode .menu.disp
798
bind . <Key-Right> "ForwardCmd"
799
bind . <Key-n> "NextCmd"
800
bind . <Key-Left> "BackwardCmd"
801
bind . <Key-p> "PrevCmd"
802
bind . <Key-s> "PauseCmd"
803
bind . <Key-Down> "VolDownCmd"
804
bind . <Key-v> "VolDownCmd"
805
bind . <Key-Up> "VolUpCmd"
806
bind . <Key-V> "VolUpCmd"
807
bind . <Key-space> "PauseCmd"
808
bind . <Return> "PlayCmd"
809
bind . <Key-c> "StopCmd"
810
bind . <Key-q> "QuitCmd"
812
VolumeCmd $Config(CurVol) 1