1#!/bin/sh
2# the next line restarts using wish \
3exec wish8.4 "$0" "$@"
4
5package require -exact snack 2.2
6# Try to load optional file format handlers
7catch { package require snacksphere }
8catch { package require snackogg }
9
10# If they are present add new filetypes to file dialogs
11set extTypes  {}
12set loadTypes {}
13set loadKeys  {}
14set saveTypes {}
15set saveKeys  {}
16if {[info exists snack::snacksphere]} {
17    lappend extTypes {SPHERE .sph} {SPHERE .wav}
18    lappend loadTypes {{SPHERE Files} {.sph}} {{SPHERE Files} {.wav}}
19    lappend loadKeys SPHERE SPHERE
20}
21if {[info exists snack::snackogg]} {
22  lappend extTypes  {OGG .ogg}
23  lappend loadTypes {{Ogg Vorbis Files} {.ogg}}
24  lappend loadKeys  OGG
25  lappend saveTypes {{Ogg Vorbis Files} {.ogg}}
26  lappend saveKeys  OGG
27}
28snack::addExtTypes $extTypes
29snack::addLoadTypes $loadTypes $loadKeys
30snack::addSaveTypes $saveTypes $saveKeys
31
32
33snack::debug 0
34snack::sound s -debug 0
35snack::sound s2
36snack::sound sa
37
38set timestr ""
39option add *font {Helvetica 10 bold}
40wm title . "Play list"
41
42if 0 {
43set draw 1
44pack [frame .f]
45pack [canvas .f.c -width 140 -height 40] -side left
46pack [checkbutton .f.a -text Analyzer -variable draw] -side left
47
48for {set i 0} {$i<16} {incr i} {
49  .f.c create rect [expr 10*$i] 20 [expr 10*$i+10] 40 -fill green  -outline ""
50  .f.c create rect [expr 10*$i] 10 [expr 10*$i+10] 20 -fill yellow -outline ""
51  .f.c create rect [expr 10*$i] 0  [expr 10*$i+10] 10 -fill red   -outline ""
52  .f.c create rect [expr 10*$i] 0  [expr 10*$i+10] 40 -fill black -tag c$i
53}
54for {set i 0} {$i<17} {incr i} {
55  .f.c create line [expr 10*$i] 0 [expr 10*$i] 40 -width 5
56}
57for {set i 0} {$i<7} {incr i} {
58  .f.c create line 0 [expr 6*$i] 140 [expr 6*$i] -width 3
59}
60}
61
62pack [frame .frame] -side top -expand yes -fill both
63scrollbar .frame.scroll -command ".frame.list yview"
64listbox .frame.list -yscroll ".frame.scroll set" -setgrid 1 -selectmode single -exportselection false -height 16
65pack .frame.scroll -side right -fill y
66pack .frame.list -side left -expand 1 -fill both
67bind .frame.list <Double-ButtonPress-1> Play
68bind .frame.list <B1-Motion> {Drag %y}
69bind .frame.list <ButtonPress-1> {Select %y}
70bind . <BackSpace> Cut
71
72snack::createIcons
73pack [frame .panel] -side bottom -before .frame
74pack [button .panel.bp -bitmap snackPlay -command Play] -side left
75pack [button .panel.bs -bitmap snackStop -command Stop] -side left
76pack [button .panel.bo -image snackOpen -command Open] -side left
77set p 0
78pack [scale .panel.ss -show no -orient horiz -len 130 -var p] -side left
79set gain [snack::audio play_gain]
80pack [scale .panel.sv -show no -orient horiz -command {snack::audio play_gain}\
81	-len 70 -var gain] -side left
82set setdrag 1
83bind .panel.ss <ButtonPress-1> {set setdrag 0}
84bind .panel.ss <ButtonRelease-1> {set setdrag 1 ; Play2}
85pack [label .panel.l -textvar timestr]
86
87proc Open {} {
88    global files
89    set file [snack::getOpenFile -format MP3]
90    if {$file != ""} {
91	set name [file tail $file]
92	set files($name) $file
93	.frame.list insert end $name
94    }
95}
96
97proc Play args {
98    global files t0 filelen
99    if {[.frame.list curselection] == ""} {
100	set i 0
101    } else {
102	set i [lindex [.frame.list curselection] 0]
103    }
104    .frame.list selection set $i
105    Stop
106    s config -file $files([.frame.list get $i])
107    sa config -file $files([.frame.list get $i])
108    if {$args == ""} {
109	s play -command Next
110	set t0 [clock scan now]
111    } else {
112	s play -start $args -command Next
113	set t0 [expr [clock scan now] - $args / [s cget -rate]]
114    }
115    set filelen [s length]
116    Timer
117}
118
119proc Play2 {} {
120    global filelen p
121    Play [expr int($p/100.0*[s length])]
122}
123
124proc Stop {} {
125    s stop
126    after cancel Timer
127}
128
129proc Timer {} {
130    global t0 timestr setdrag
131    set time [expr [clock scan now] - $t0]
132    set timestr [clock format $time -format "%M:%S"]
133    if $setdrag {
134	.panel.ss set [expr int(100 * $time / [s length -unit sec])]
135    }
136#    Draw
137    after 100 Timer
138}
139
140sound beep
141set f [snack::filter generator 200 10000 0.0 triangle 1600]
142beep filter $f
143
144proc Next {} {
145    set i [lindex [.frame.list curselection] 0]
146    if {$i == ""} return
147    .frame.list selection clear $i
148    incr i
149    .frame.list selection set $i
150    .frame.list see $i
151    beep play
152    after 100 Play
153}
154
155set cut ""
156proc Cut {} {
157    global cut
158    if {[.frame.list curselection] != ""} {
159	set cut [.frame.list get [.frame.list curselection]]
160	.frame.list delete [.frame.list curselection]
161    }
162}
163
164proc Select y {
165    global old timestr files
166    set old [.frame.list nearest $y]
167    s2 config -file $files([.frame.list get $old])
168    set timestr [clock format [expr int([s2 length -unit sec])] -format "%M:%S"]
169}
170
171proc Drag y {
172    global old
173    set new [.frame.list nearest $y]
174    if {$new == -1} return
175    set tmp [.frame.list get $old]
176    .frame.list delete $old
177    .frame.list insert $new $tmp
178    .frame.list selection set $new
179    set old $new
180}
181
182array set map {
183    0 2
184    1 3
185    2 4
186    3 5
187    4 7
188    5 9
189    6 12
190    7 15
191    8 19
192    9 23
193    10 28
194    11 34
195    12 41
196    13 49
197    14 56
198    15 63
199}
200
201proc Draw {} {
202    global draw
203    if ![snack::audio active] return
204    if {$draw == 1} {
205puts [time {
206	set pos [expr int([s cget -rate] * [snack::audio elapsed])]
207        if {$pos > 1000} {
208         set junk [sa sample [expr $pos - 1000]]
209         set junk [sa sample [expr $pos - 100]]
210         set junk [sa sample [expr $pos]]
211puts $junk
212	}
213	set spec [sa dBPower -start $pos -fftlen 128 -windowlength 128]
214	for {set i 0} {$i < 16} {incr i} {
215	    set val [lindex $spec $::map($i)]
216	    .f.c coords c$i [expr 10*($i-2)] 0 [expr 10*($i-2)+9] \
217		    [expr 100-1.4*($val+100)]
218	}
219    }]
220    }
221}
222
223if [info exists argv] {
224 if [file isdirectory $argv] {
225  catch {cd $argv}
226 }
227}
228
229wm protocol . WM_DELETE_WINDOW exit
230
231if {$::tcl_platform(platform) == "windows"} {
232 set filelist [glob -nocomplain *.mp3 *.wav]
233} else {
234 set filelist [glob -nocomplain *.mp3 *.wav *.MP3 *.WAV]
235}
236if {[info exists snack::snackogg]} {
237  set filelist [concat $filelist [glob -nocomplain *.ogg *.OGG]]
238}
239foreach file [lsort -dictionary $filelist] {
240    set name [file tail $file]
241    set files($name) $file
242    .frame.list insert end $file
243}
244