TclMixer , by Googie, provides SDL_mixer (SDL) bindings for Tcl. It allows to play multiple sounds simultaneously using a built-in software mixer.


LGPL (same as SDL)
latest release

Androwish Fork

The Androwish project contains a fork of Tclmixer-1.2.3. In particular, it improves on the callback handling. This fork is probably what you want to use.


TclMixer supports following sound formats: WAV/RIFF, MP3, OGG, MID (midi), MOD (including standard MOD modules, but also S3M, IT, XM).

There are basic effects implemented, which would be very useful, such as individual sound volume level, 3D sound source positioning, stereo balance, fading in/out and sound source distance. All these goodies closed in well known, simple Tcl syntax.

To make this extension work, end-user has to got installed SDL [L1 ] (in version 1.2.x) and SDL_mixer [L2 ] (in version 1.2.x), which are quiet famous and presents on most Unix desktop machines (in future could be linked statically with these libraries to takes dependencies off).

Generaly, it's low-latency alternative for Snack package. It's excellent for a game sound system, but not only.

PYK 2015-10-13: Although test/test.tcl file in the latest release is is outdated and no longer works because tclmixer::setCallback doesn't exist, Tclmixer itself is functional. See examples below that do work.


There is also Windows binary package available at extension homepage!
In-Hak Min TclMixer 1.2.3 Win32 binary :
Googie 2009-05-01 Can I put this win32 binary at TclMixer homepage?
In-Hak Min Of course. ^_^


Get some supported sound file. If it's some effect (gun shot, or explosion or sth) load it as short sound (which gives very low latency):

#!/usr/bin/env wish
package require TclMixer
set snd [tclmixer::sound file.<mp3|wav|ogg>]
tclmixer::play $snd

if file is big (usually some music), then load it as long sound, to prevent loading it into memory:

#!/usr/bin/env wish
package require TclMixer
set music [tclmixer::music file.<mp3|wav|ogg|mid|mod>]
tclmixer::play $music

There is 'wish' used, not 'tclsh', because we need some event loop, since SDL_mixer hasn't its own. If you want to use 'tclsh', you need to create some event loop, to let SDL_mixer play whole sound. You can use CALLBACK mechanism:

#!/usr/bin/env tclsh
package require TclMixer
set done 0
proc musicFinished {} {
    variable done
    set done 1

# Arrange for [musicFinished] to be called when he music is done
tclmixer::mixConfig -music [namespace current]::musicFinished

set music [tclmixer::music file.<mp3|wav|ogg|mid|mod>]
tclmixer::play $music
while {!$done} {
    after 500

PYK 2015-10-13: vwait can not be used in the case, because the callblacks registered via tclmixer::mixConfig are called in a thread created by SDL, but access the Tcl interpreter in the other thread, which is a generally a no-no. However, the convention illustrated above should work as long as nothing else sets the semaphore variable

chw 2015-10-13: Maybe the tclmixer in AndroWish is of help here (see ). It should fix many threading issues and hopefully still compile on non Androids, too.

PYK 2015-10-13:

I spent quite a while today studying this code to acquaint myself with the Tcl_Async* functions. I haven't seen any other information anywhere about the application of these functions to enable callback capabilities between Tcl threads and threads managed by another library. Thank you!

In the original Tclmixer-1.2.3, an alternative to using the callbacks is to poll using tclmixer::musicType, which returns NONE when there is no music playing or paused:


package require TclMixer

proc playing semaphore {
    if {[tclmixer::musicType] eq {NONE}} {
        puts [list {Done playing audio}]
        set $semaphore 1
    } else {
        after 500 [list after idle [namespace code [info level 0]]]


set music  [tclmixer::music test.mod]
tclmixer::play $music

variable forever
after idle [list [namespace which playing] [namespace which -variable forever]]
vwait forever

However, using the original Tclmixer-1.2.3, simultaneous playback on multiple channels isn't working in my environment. I'm going to try the Androwish TclMixer now.

PYK 2015-10-13: I wasn't able to get the Androwish version of Tclmixer to produce sound under Cygwin. It Probably has something to do with SDL2 being configured to use NAS (Network Audio Server), and NAS not being correctly configured. I'll have to come back to it some other time.

chw 2015-10-14: The motivation to use the Tcl_Async* APIs is the similarity of SDL2_mixer's callback functions to UN*X signals, i.e. SDL2_mixer starts a background thread for mixing the playback of OGG/MP3 data or plain sampled sounds and invokes the user provided callback functions from within that thread. Tcl_AsyncMark() is used for both kinds of sound and music callbacks to trigger another short function which adds after idle handlers (Tcl_DoWhenIdle()) carrying out the Tcl level callbacks. Another addition to the original TclMixer: one specific Tcl interpreter is allowed to deal with the SDL2_mixer library at any one time. This is the interpreter which first performed the "package require TclMixer". The owning interpreter can relinquish ownership of the mixer by calling "tclmixer::release". Other interpreters (potentially running in other threads) can obtain the mixer by calling "tclmixer::acquire".

nb Is there a win binary of the AW fork of this package anywhere? TIA