Updated 2011-01-21 23:07:23 by emiliano

GPS: The original version of this is no longer on the public server.

How to use Tcl/Tk in Multimedia Applications for X

This tutorial describes how to play movies, display images, animate images, play audio, and display PNG cursors in Tcl/Tk.


Movies

XAnim [1] has the capability to embed into a Tk window with relative ease, and it supports most common video formats. Several movie extensions to Tcl/Tk can be found in the Neosoft archives. [2] I could not get any of the extensions to work with newer releases of Tcl/Tk. So for now I will cover the usage of XAnim with Tk.

This example will make XAnim draw into the Tk frame:
 #!/usr/local/bin/wish8.2

 frame .movieholder -height 300 -width 300
 .movieholder configure -bg black
 place .movieholder -x 270 -y 120

 #It is very important that update is used here.  It creates the window for us.
 #IIRC in recent versions of Tk winfo id should call Tk_MakeWindowExist.
 update

 set frameid [winfo id .movieholder]

 catch [exec xanim +Ze -Zr +Av75 +W$frameid movie.mov]

 #This is run after the movie.
 #In my game I load a new scene and image.
 destroy .movieholder

The +Ze flag tells XAnim to exit after the movie finishes. The -Zr flag tells XAnim to not have a control interface. The +Av75 flag tells XAnim to play audio in the movie at 75% of the maximum level. The +W flag instructs XAnim to draw into the hexadecimal id of a window.

You can try adding [puts $frameid] to see the id of a frame and learn about X.

MS 2005-01-09: You can also control the movie. Start and Stop can be done with the kill command (Linux). I've found this way in the newsgroup comp.lang.tcl. I wasnot able to control the embedded window in which xanim is running as told in xanim's man-page. But this now works.
 #!/usr/bin/wish -f
 frame .movieholder -height 300 -width 500
 .movieholder configure -bg black
 pack .movieholder
 update
 set frameid [winfo id .movieholder]
 # starting the movie
 catch { set xanim_pid [exec xanim +Ze -Zr  +W$frameid mymovie.avi & ]}
 # stop and start the movie
 after 100
 puts stop
 catch {exec kill -STOP $xanim_pid}
 after 2000
 puts start
 catch {exec kill -CONT $xanim_pid}

I've found Mat Bengstsson's QuickTimeTcl to be easy to use and works very well. It is limited to Windows and Mac though - VPT

PT 2004-05-25: I've got a [DirectX]-based video widget at http://developer.berlios.de/projects/tkvideo. This can play avi and wmv format files and connect to a local webcam device too. Possibly this might merge with the above project - or at least start to look similar. But for now, its more a working demo.

http://tkvideo.berlios.de/ as an alternate URL?

Images With Transparency and Plain Images

(This section now separate, originally because of a bizarre Wikit bug, but the topic is also more widely relevant in Tk applications than the rest of the multimedia phenomenon... DKF)

Audio

Esdplay [3] is an easy to use audio player for Unix platforms that supports playing multiple audio files at once for most systems. It is now included with the Enlightenment Sound Daemon package. [4] It seems to be able to play multiple wave and Sun audio formats. My friend with an AWE64 said that he was unable to play two audio files at once. While it plays two or more files on my system with an ESS 1879 without a problem. So, it seems like it will work for some people and not for others. Hopefully this will be fixed soon. Note: Make sure that you have esd running before you run esdplay, when playing multiple files.

An example using esdplay that plays two audio files at once:
 exec esdplay email.wav &
 exec esdplay send.au &

The Snack sound extension [5] to Tcl/Tk looks promising, but it does not support playing multiple files at once, yet. I contacted the author of Snack and told him that I am interested in using Snack to play two audio files at once for my game. He said that other people had requested that as well. He said he was interested in adding this feature. So hopefully the Tcl/Tk community will eventually have this multiplatform audio tool. Snack has many good features that separate it from Esdplay, such as the ability to play MP3 audio. Update: Snack now supports playing multiple files at once.

US How can I let snack and esd cooperate, e.g. I have a couple of applications using esd and want to add a snack app?

See also the snackAmp MP3 player created by Tom Wilkason.

D. McC WaveSurfer [6] is a soundfile editor based on Snack.

Speech Thanks to tcom using speech synthesis on Windows is trivial. See Speech Synthesis, or Talk to me Tcl

PNG Cursors

Tk doesn't seem to directly support using PNG cursors or XPM cursors. However I found a way around this by having an image follow the cursor around. The window cursor is set to a blank.xbm. Which is simply a bitmap created with the bitmap program with only a hotspot defined. The PNG image follows the invisble cursor around.

Here is an example:
 #! /usr/bin/env wish

 package require Img

 set can .frame.can
 frame .frame
 pack .frame

 canvas $can -width 30c -height 22c
 pack $can

 set default_cursor_image [image create photo \
         -file $imagedir/interface/cursors/def.png]

 proc default_cursor {} {
     bind . <Motion> {default_cursor}
     global can imagedir default_cursor_image

     catch {unset X}
     catch {unset Y}

     set X [expr [winfo pointerx .] -10]
     set Y [winfo pointery .]
     catch {$can delete default_cursor}
     catch {$can delete action_cursor}
     . configure -cursor "@blank.xbm black"
     $can create image $X $Y -image $default_cursor_image -tag default_cursor
 }

 default_cursor

In some ways the example below may be better than the above example. The problem with the example above is that if the window is not at 0,0 from the left top the cursor position is inaccurate. Also the window manager decorations make this inaccurate if it runs on another machine. I have a mouse cursor position setup screen in my game to make it accurate. My setup screen is a square that has bindings for enter and leave that cause the cursor to be displayed. I have a scale on the bottom and side that allows adjusting the amount to subtract or add to the pointerx and pointery values.

This is an example that solves the above problem:
 #! /usr/bin/env wish

 package require Img

 set can .frame.can
 frame .frame
 pack .frame

 canvas $can -width 30c -height 22c
 pack $can

 set default_cursor_image [image create photo -file ./cursor.png]

 bind . <Motion> {cursor_move  %x %y}
 . configure -cursor "@blank.xbm black"

 proc cursor_move {x y} {
     global default_cursor_image can

     #Try removing this if you want to draw some fun pictures.
     catch {$can delete default_cursor}

     set x [$can canvasx $x]
     set y [$can canvasy $y]

     $can create image $x $y -image $default_cursor_image -tag default_cursor
 }

GPS: I wrote that cursor code many years ago. I think we could make the cursor code faster, by not recreating the image.

[IgorNovikov]: Code described above is just a workaround. The best way under XWindow environment is xcursor library usage. We have published such Tkinter extension so there is no problem to convert this code as a tcl extension [7]

EG 2011-01-21: Based on the above Tkinter extension, I've written a bare bones interface to xcursor.

Shaped Windows

Donal K. Fellows has made an extension for Tcl/Tk that supports shaped windows.[8] It seems to work well. I was rather impressed by the finger print demo that is included with it. Do any of you know of other examples that use the Shape extension?

(UPDATE: The next version of the extension which I am working on will support pulling shapes directly from photo images. - DKF)

Audio in Windows With sndrec32

GPS - Richard Suchenwirth demonstrated at news:comp.lang.tcl how to play audio in Windows with the example below.
 set AUDIOPATH {c:\foo\bar} ;# adjust as you need it

 proc saywords {words} {
        global AUDIOPATH
        foreach word $words {
                set file [file join $AUDIOPATH $word.wav]
                exec sndrec32 /play /close [file nativename $file]
        }
 }

Windows Only Multmedia Interface - TMCI

I recently stumbled across an interesting extension for Tcl/Tk on Windows that wraps the built-in Multimedia Interface with a Tcl DLL. It is called the Tcl Media Control Interface (TCMI). You can play/record audo files, video files or anything else the Windows MMI driver provides. The Windows MMI Interface is string based, so the TCMI wrapper provides a bi-directional interface back into Tcl. Neat.

Source and sample scripts are provided. You can find this package at [9]

TFW 2/25/01

PT 2004-JAN-31: For windows only, I have written a Tk control that displays video using the DirectX APIs. This means it can be used to view input from video sources like webcams and file sources including mpeg and avi. At the moment it needs a home but if someones interested they can mail me. This may be something similar to that mentioned above.

Building presentations and visuals

* Check Oil

Remote Control Devices

TFW Jan 31, 2004 LIRC [10] and WinLIRC [11] are two popular programs to connect those infrared/RF remote devices to a computer. It is deceptively easy to connect Tcl to LIRC/WinLIRC to allow the remote controller to interface with Tcl applications. The code below is really all there is too it. I showing an example from snackAmp which will give you the general idea.
 ##
 # LIRC Handler for remote controls
 #
 namespace eval irc {
    variable socket 0
    variable port $snackAmpSettings(ircPort)
    variable host $snackAmpSettings(ircHost)
 }
 proc irc::Server {args} {
    variable socket
    variable port
    variable host
    if {[string length [string trim $host]]==0} {
       set host [info hostname]
    }
    catch {close $socket} result
    if [catch {set socket [socket $host $port]} result] {
       saLog "Error Establishing Server $::errorInfo"
    } else {
       fconfigure $socket -translation auto
       fileevent $socket readable [list irc::Process $socket]
       saLog "IRC Server Established on port $port"
    }
 }
 proc irc:Close {args} {
    variable socket
    catch {close $socket} result
 }
 #########################################################################
 # Function    : irc::Process
 # Description : Called from fileevent on a readable input on my port
 # Author      : Tom Wilkason
 # Date        : 1/31/2004
 #########################################################################
 proc irc::Process {sock} {
    variable socket
    ;# If eof or partial line the close up the channel now
    if {[eof $sock] || [catch {gets $sock line}]} {
       # end of file or abnormal connection drop
       close $sock
       set socket 0
       irc::Server
    } else {
       # Process the received command line
       # The forth param is the remote type e.g. "atiremotewonder"
       set remote [lindex $line 3]
       # The third parameter is the ascii command
       set command [lindex $line 2]
       switch -- [string tolower $command] {
          vol_up {bumpLevel 2}
          vol_down {bumpLevel -2}
          fastforward {Next}
          rewind {Prev}
          1 -
          2 -
          3 -
          4 -
          5 {
             db::setVal $::TA(currentMF) Rating [string repeat * $command]
          }
          pause {Pause}
          stop {Stop}
          play {Play}
          channel_up {bumpScaling .1}
          channel_down {bumpScaling -.1}
          mute {Pause}
          right {macros::skipPlay 10}
          left {macros::skipPlay -10}
          record {taExit}
          default {puts $line}
       }
    } ;#end line
 }
 irc::Server
 package provide ircserver 1.0

Perhaps someone could reorganize this page, so that X and Windows specific information is separated.

DKF: I've found out that AccessGrid uses Tcl internally to do scripting. I do not know the details at this stage. EF Modified the AccessGrid page to quickly reflect what I know and remember, please fill in and develop if necessary. I can probably help in the description process if necessary, I have been using, touching and digging in these tools, but that was years ago.