Example Snack scripts

Some examples of Snack scripts are given below, there is also a number of demonstration scripts included in the distribution. If you want to use Snack scripts embedded in web pages you should follow this link with information on how to use Snack on the web, There are some drawbacks with this method, e.g., disk access is forbidden from applets.

Basic sound handling

Minimal recording application

Sample file format converter

Sample file format converter 2

Batch sample file conversion

Waveform and spectrogram

Moving play marker

Beep generator

Specialized sound applications

Listening test

Prompted sentence recording

Minimal sound spectrum analyzer

Minimal two-channel real-time sound spectrum analyzer

Data plot with spectrogram

Audio streams and Client/Server examples

Using audio streams

Audio client/server applications

Audio client/server applications 2

Sending audio between two applications


Minimal sound recording application

#!/usr/local/bin/wish 

package require snack 

snack::sound s 
pack [ button .a -bitmap record -command {s record} -fg red] -side left
pack [ button .b -bitmap stop -command {s stop}] -side left
pack [ button .c -bitmap play -command {s play}] -side left
snack::createIcons
pack [ button .d -image snackSave -command {s write [tk_getSaveFile]}] -side left


Sample file format converter

The following script converts between the different file formats which Snack can handle. It uses the tclsh script interpreter and the Snack sound package (same as snack but without visualization functionality) The script can only be run from the command line. For example, to convert an AU file to a WAV file simple type:

convert.tcl file.au file.wav

(Assuming you have named the script convert.tcl)

#!/usr/local/bin/tclsh

package require sound

sound::sound snd

snd read  [lindex $argv 0]
snd write [lindex $argv 1]

You could just as well use wish for this script. The exit command at the end prevents the opening of the main window.

#!/usr/local/bin/wish

package require snack

snack::sound snd

snd read  [lindex $argv 0]
snd write [lindex $argv 1]

exit


Sample file format converter 2

This script adds the capability to convert a raw (headerless) sample file to a file with one of the different formats which Snack can handle. For example, to convert a raw file (44100 KHz, 16 bit linear) to a WAV file simple type:

convert2.tcl -frequency 44100 -format LIN16 file.raw file.wav

(Assuming you have named the script convert2.tcl)

#!/usr/local/bin/tclsh

package require sound

sound::sound snd

set args [llength $argv]
eval snd read [lindex $argv [expr $args - 2]] [lrange $argv 0 [expr $args - 3]]
snd write [lindex $argv end]

(This script can be given any of the options which can be given to the sound read command.)


Batch sample file conversion

This script converts all AU sample files in the current directory to WAV files. Also, the sample data is converted to 8000KHz, 16 bit, mono, regardless of the current format.

#!/usr/local/bin/tclsh

package require sound

sound::sound snd

set file_list [glob *.au]

foreach file $file_list {
    snd read $file
    snd convert -format lin16 -channels 1 -frequency 8000
    snd write [file rootname $file].wav
}

If the files are in raw format you can specify their characteristics after the snd read command using, e. g.,
snd configure -format MULAW -frequency 8000.

If you have a file containing a list of the files you want to convert, you would read this file first:
set f [open "filenamnes"]
set file_list [read $f]
close $f

If you modify the snd write command the sound files to convert can reside in different directories.
snd write [lindex [file split [file rootname $file]] end].wav


Waveform and spectrogram

The following script creates a spectrogram of the sound in the file ex1.wav. The output of the script is shown to the right.
 
#!/usr/local/bin/wish 

package require snack 

pack [canvas .c -height 200] 

snack::sound s -load ex1.wav 

.c create spectrogram 0 0 -sound s -height 200

The first command loads the Snack package.
Next, a Tk canvas is created which can be used to draw graphics.
A sound named 's' is created and audio data is read from the file ex1.wav.
The final command creates a spectrogram of the sound with height 200.

To add a waveform of the same sound the line

.c create waveform 0 0 -sound s -height 100

could be added to the script (with some minor modifications), giving:
 
 
#!/usr/local/bin/wish 

package require snack 

pack [canvas .c -height 300] 

snack::sound s -load ex1.wav 

.c create waveform 0 0 -sound s -height 100 

.c create spectrogram 0 100 -sound s -height 200

In these examples the spectrograms have used default values for analysis window length etc. See the manual for more information.


Moving play marker

#!/usr/local/bin/wish

package require snack

snack::sound s
set width 600
set wheight 180
set cheight 200
pack [canvas .c -width $width -height $cheight]
pack [button .p -text Play -command Play]
pack [button .l -text Open -command Open]

.c create waveform 0 0 -sound s -width $width -height $wheight
.c create poly -1 -1 -1 -1 -1 -1 -fill red -tags pm

proc Open {} {
    s read [tk_getOpenFile]
}

proc Play {} {
    s play -command StopPlayMarker
    after 0 PutPlayMarker
}

proc StopPlayMarker {} {
    after cancel PutPlayMarker
}

proc PutPlayMarker {} {
    global width cheight

    set x [expr $width / [s length -units seconds] * [audio elapsed]]
    set y [expr $cheight - 5]
    .c coords pm [expr $x-5] $y $x [expr $y-10] [expr $x+5] $y
    after 50 PutPlayMarker
}


Beep generator

This script generates a 2 second 1KHz sine beep and writes it to a wav file.

#!/usr/local/bin/tclsh

package require sound

sound::sound s -format lin16 -frequency 16000
s length 32000 -units samples

set period 16
set amp 10000

for {set i 0} {$i < [s length]} {incr i} {
    s sample $i [expr int($amp*sin($i*6.283185/$period))]
}

s write "sine1khz.wav"
 


Listening test


 
 
#!/usr/local/bin/wish

package require snack

snack::sound s

set tp 01 
set files {ex1.wav ex2.wav ex1.wav ex2.wav ex1.wav} 

proc Play {filename} {
    s read $filename
    s play
}

pack [ frame .f ] 
pack [ label .f.l -text "Enter test person id" ] -side left 
pack [ entry .f.e -text tp ] -side left 

for {set i 0} {$i < [llength $files]} {incr i} { 
    pack [ frame .f$i ] 
    pack [ button .f$i.b -text "Example $i" -command "Play [lindex $files $i]"] -side left 
    pack [ radiobutton .f$i.y -text Yes          -val yes -var v($i)] -side left 
    pack [ radiobutton .f$i.n -text No           -val no  -var v($i)] -side left 
    pack [ radiobutton .f$i.x -text "Don't know" -val x   -var v($i)] -side left 

pack [button .b -text Ready -command { 
    if [catch {open $tp.res w} fd] { 
        puts $fd 
    } else { 
        for {set i 1} {$i <= [llength $files]} {incr i} { 
            puts $fd $v($i) 
        } 
        close $fd 
    } 
    exit 
}]


Prompted sentence recording


 
 
 
#!/usr/local/bin/wish 

package require snack 

snack::sound s 
set tp 01 
set i 0 

if [catch {open sent.txt r} fd] { 
    puts $fd 
} else { 
    while {[gets $fd str] > 0} { lappend sents $str } 
    close $fd 

pack [ frame .f ] 
pack [ label .f.l -text "Enter test person id" ] -side left 
pack [ entry .f.e -text tp ] -side left 
pack [ label .l -text [lindex $sents 0] -font -*-*-*-*-*--20-180-*-*-*-*-*-*] 
pack [ button .r -text {Press to record}] 
bind .r <ButtonPress-1>   {s record} 
bind .r <ButtonRelease-1> {s stop} 
pack [ button .p -text Play -command {s play}] 
pack [ button .n -text Next -command NextSent] 

proc NextSent {} { 
    global tp sents i

    s write $tp.$i.wav 
    incr i 
    if {$i >= [llength $sents]} { exit } 
    .l config -text [lindex $sents $i] 
}


Minimal sound spectrum analyzer


 
#!/usr/local/bin/wish 

package require snack 

snack::sound s 
set start 0 
set end  -1 
pack [set c [canvas .c -height 200 -width 400]] 

$c create spectrogram 0 0       -sound s -height 100 -width 400 
$c create section     0 100     -sound s -height 100 -width 400 -tags sect 
$c create line        5 0 5 100     -tags m1 
$c create line        395 0 395 100 -tags m2 

bind $c <ButtonPress-1> { 
    $c coords m1 [$c canvasx %x] 0 [$c canvasx %x] 100 
    set start [expr int(16000 * [$c canvasx %x] / 400)] 
    $c itemconf sect -start $start 

bind $c <ButtonRelease-1> { 
    $c coords m2 [$c canvasx %x] 0 [$c canvasx %x] 100 
    set end [expr int(16000 * [$c canvasx %x] / 400)] 
    $c itemconf sect -end $end 

pack [frame .f] 
pack [button .f.b1 -text Open  -command {s read [tk_getOpenFile]}]   -si left 
pack [button .f.b2 -text Play  -command {s play -start $start -end $end}] -si left 
pack [button .f.b3 -text Print -command {$c postscript -file tmp.ps; exec ghostview tmp.ps}] -si left 
pack [button .f.b4 -text Exit  -command exit] -si left 


Minimal two-channel real-time sound spectrum analyzer


This script will create two spectrum sections connected to the left and right channels of a stereo signal. Both spectrum sections will update in real-time. 

#!/usr/local/bin/wish 

package require snack 

snack::sound s -channels 2 

pack [canvas .c -height 256 -width 512] 
pack [button .r -text Record -command {s record}] 
pack [button .s -text Stop   -command {s stop}] 
.c create section   0 0 -sound s -channel 0 -frame 1 
.c create section 256 0 -sound s -channel 1 -frame 1 


Curve plot with spectrogram

This script plots numerical ASCII data together with a sound spectrogram and also saves the output to a postscript file. It is used from the command line as follows 

FilePlot.tcl ex1.wav ex1.dat

where ex1.dat is a file containing one column of ASCII data, see below. 

#!/usr/local/bin/wish 

package require snack 
snack::sound s -load [lindex $argv 0] 

pack [canvas .c -width 350 -height 200] 
set pixpsec 400 
set fstep 0.025 
.c create spectrogram 0 0 -sound s -height 100 -pixelspersec $pixpsec 

if ![catch {open [lindex $argv 1]} in] { 
    set i 0 
    while {[gets $in line] > 0} { 
 scan $line "%f" val 
 lappend coords [expr $i * $fstep * $pixpsec] [expr 100+0.5*(200-$val)] 
 incr i 
    } 
    close $in 
    eval .c create line $coords 

update 
.c postscript -file out.ps 

The ASCII data file (ex1.dat): 
2.3 
1.0 
3.1 
4.0 
2.2 
2.2 
4.1 
145.3 
137.7 
145.5 
156.8 
167.3 
172.1 
182.3 
150.3 
140.2 
135.5 
172.2 
4.1 
145.3 
137.7 
126.3 
129.3 
131.0 
132.0 
137.7 
126.3 
129.3 
1.0 
2.0 
1.3 
2.2 
1.1 
2.4 

 


Using audio streams

The following demonstrates how sound objects can be used to control audio streams. 

This script records audio from the audio device and sends it to stdout. After 8 seconds the recording is stopped and the program exits: 

#!/usr/local/bin/tclsh 

package require sound 

proc stop {} { 
    s stop 
    exit 

after 8000 stop 

sound::sound s -channel stdout 
s record -fileformat wav 

vwait forever 

This script plays audio coming in from stdin and exits at end-of-file: 

#!/usr/local/bin/tclsh 

package require sound

after 1000000 exit 

sound::sound s -channel stdin 
s play -command exit 

vwait forever 
 


Audio client/server applications

This script implements an audio server. It listens for connections at port 23457 and plays the incoming audio data: 

#!/usr/local/bin/tclsh 

package require sound

proc Cmd { sock addr port } { 
    snd stop 
    snd config -channel $sock 
    snd play -command [list close $sock] 

sound::sound snd 
socket -server Cmd 23457 
vwait forever 

This script implements a corresponding client that sends audio data from a file to a server running on the computer host.department.com:

#!/usr/local/bin/tclsh 

package require sound

sound::sound s -load $argv 
set sock [socket host.department.com 23457] 
fconfigure $sock -translation binary 
puts -nonewline $sock [s data -fileformat wav] 
close $sock 
 


Audio client/server applications 2

This simple audio server is included in the Snack distribution (aserver.tcl). It listens for connections at port 23654. The first four bytes are assumed to be a command. The user can also control the volume. 

#!/usr/local/bin/wish

package require snack

snack::sound snd

proc Cmd { sock addr port } {
    global ssock

    snd stop
    set cmd [read $sock 4]
    switch $cmd {
        play {
            snd config -channel $sock
            snd play -command [list close $sock]
        }
        stop {
            close $sock
        }
        exit {
            close $sock
            close $ssock
            exit
        }
    }
}

set ssock [socket -server Cmd 23654]

pack [button .a -text Volume -command {snack::gainBox p}]
pack [button .b -text Quit -command {close $ssock ; exit}]

vwait forever

This remote play command, which uses the audio server, is included in the Snack distribution (rplay.tcl). Customize it for the host it is to be run on (line 3). The first four bytes are assumed to be a command. It can play arbitrarily large files reading them in chunks and sending them one at a time. 

#!/usr/local/bin/tclsh

set host host.speech.kth.se
set port 23654

if {$argv == {}} {
    puts "Usage: rplay.tcl file"
    exit
}

if [catch {set fd [open $argv]} res] {
    puts $res
    exit
}
fconfigure $fd -translation binary

if [catch {set sock [socket $host $port]} res] {
    puts "Make sure that an aserver.tcl is running at $host:$port"
    exit
}
fconfigure $sock -translation binary -blocking 0

puts -nonewline $sock play
fileevent $sock writable PlayHandler

proc PlayHandler {} {
    global fd sock

    set data [read $fd 10000]
    puts -nonewline $sock $data
    if [eof $fd] {
        close $fd
        close $sock
        exit
    }
}

vwait forever
 


Sending audio between two applications (without streams)

The following is an example of how audio data can be sent between two applications, either running on the same computer or on two different ones. You will need to modify the client script and specify the hostname of the computer running the server. 

The server script (server.tcl):

#!/usr/local/bin/wish 

package require snack 

snack::sound s 

socket -server Cmd 23454 

proc Cmd { sock addr port } { 
    fconfigure $sock -translation binary 
    s append [read $sock] 
    close $sock 
    .f.l config -text "Tot: [s length]" 
    update 

pack [canvas .c -width 400 -height 100] 
pack [frame .f] 
pack [button .f.a -bitmap snackPlay -command {s play} -width 40 -height 20] -side left 
pack [button .f.b -text Exit -command exit] -side left 
pack [label .f.l  -text ""] -side left 
.c create waveform 0 0 -sound s -width 400 
 

The client script (client.tcl): 

(modify line 22, host.department.com must be replaced with the hostname of the computer running server.tcl) 

#!/usr/local/bin/wish 

package require snack 

snack::sound s 
set last 0

proc StartRec {} { 
    s record
    after 300 SendData start 

proc StopRec {} { 
    s stop 
    SendData stop 

proc SendData flag { 
    global last 

    if {[s length] > $last} { 
        set sock [socket host.department.com 23454] 
        fconfigure $sock -translation binary 
        puts $sock [s data -start $last -fileformat wav] 
        close $sock 
    } 
    if {$flag != "stop"} { 
        after 300 SendData data 
        set last [s length] 
    } else { 
        after cancel SendData data 
        set last 0 
    } 
    .l config -text Length:[s length] 

pack [label .l -text ""] 
pack [frame .f] 
pack [button .f.a -bitmap snackRecord -command StartRec -wi 40 -he 20 -fg red] -side left 
pack [button .f.b -bitmap snackStop   -command StopRec  -wi 40 -he 20] -side left 
pack [button .f.c -bitmap snackPlay   -command {s play} -wi 40 -he 20] -side left 
pack [button .f.d -text Exit          -command exit] -si left 
 


Snack home

Last updated January 23, 2006