evodio

Package to play sound files from Tcl, using a simple API common to all architectures. It is part of the eTcl distributions, and available on all platforms supported by eTcl (Win32, Windows Mobile/WinCE, Linux, MacOSX).

Only a very simple API is provided, with no support for asynchronous I/O. However, since all eTcl builds are thread-enabled, one can emulate a non-blocking API using threads.

   package require evodio

   # Procedure to play wave (RIFF) in background
   namespace eval ::evodio {}
   proc ::evodio::playwav {f {usercb ""}} {
     set ns [namespace current]
   
     package require Thread
     set slaveid [::thread::create]
   
     thread::send $slaveid {
       namespace eval ::evodio {}
    
       proc ::evodio::playsub {f {callback ""}} {
         package require evodio
         package require Thread
         
         evodio play -file $f
         if {[string compare "" $callback]} {
           set rc [catch {uplevel \#0 $callback} res]
         }
      
         ::thread::unwind
         return
       }
     }

     set cb [list ::thread::send -async [::thread::id] [list ${ns}::playdone $slaveid $usercb]]
     thread::send -async $slaveid [list ${ns}::playsub $f $cb]

     return
   }

   proc ::evodio::playdone {slaveid cb} {
     set rc [catch {uplevel \#0 $cb} res]
     return
   }

Several audio files can then be played simultaneously:

   set thisdir [file dirname [file normalize [info script]]]
   set w1 [file join $thisdir sample1.wav]
   set w2 [file join $thisdir sample2.wav]

   set ::wcount 0
   set ::nwait 0
   puts "+++ BEGIN"
   ::evodio::playwav $sample1 [list incr ::wcount]
   incr nwait

   if {[string compare "" $sample2]} {
     # Play two sounds concurrently
     ::evodio::playwav $sample2 [list incr ::wcount]
     incr nwait
   }

   # Wait
   while {$wcount<$nwait} {
     puts "+++ WAITING $wcount/$nwait"
     vwait ::wcount
     puts "+++ DONE $wcount/$nwait"
   }
   puts "+++ DONE"