Description
This is a small round-the-clock random shuffle player for ogg-files. Switching to mp3 is trivial.
In the beginning (after my real-world alarm clock broke) I (= Andreas Kupries) used cron and a wakeup script using wish and the bell to wake me up.
Then I switched to
find . -name '*.ogg' -print | xargs /usr/local/bin/ogg123 -z
for random play now that I ogg'ified quite a number of my CDs.
The deficiency of this command pipe: I can play about 220-230 songs in a day, but there are over 1000 in my catalog now. This means that the find/xargs combo will only reach about a quarter of all songs as random play is only in the groups created by xargs and not over the whole set.
I finally decided to tackle this and created the script below. It features random shuffle over all songs (using code from the wiki) and a persistent storage containing which songs were already played, so that they are excluded the next time the musicbox starts, thus giving every song a fair chance to be played.
It should be trivial to switch this over to a commandline mp3 player (for example mpg123), or snack. I hope that snack will support Ogg Vorbis soon, so that I can remove the dependency on an external application. snack now (Aug 2002) supports Ogg
#!/usr/local/bin/tclsh # Musicbox application, playing round the clock, all of the music I # have in certain directories. No arguments. Use ~/.musicboxrc to store # persistent information. # # Internal information: # # 1. Array containing the names of all the files which were already # played as keys. The values are not relevant. # # 2. List of files to play. Filled via 'find', but only with files not # already played. Shuffled in random order. # # Only (1) is persistent. # # *future* Rewrite to use the snack extension (when it incorporates # *ogg support). proc main {} { global played array set played {} # Get persistent playing information. catch {source ~/.musicboxrc} cd ~/.mydata/CDs # Forever while {1} { # Search the music directories for unplayed files and shuffle them set playlist [shuffle [unplayed_files]] # If there were no new files then use the files which were # already played as list of songs to play and reset the 'played' # information. if {[llength $playlist] == 0} { set playlist [shuffle [lsort [array names played]]] clear_played } play $playlist #exit } } proc unplayed_files {} { set playlist [list] set p [open "|find . -name *.ogg" r] while {![eof $p]} { if {[gets $p line] < 0} {continue} set line [string trim $line] if {$line == {}} {continue} if {[isplayed $line]} {continue} lappend playlist $line } return $playlist } proc isplayed {file} { global played return [info exists played($file)] } proc clear_played {} { global played unset played array set played {} save_played return } proc K {x y} {return $x} proc shuffle {list} { set n [llength $list] set slist [list] while {$n>0} { set j [expr {int(rand()*$n)}] lappend slist [lindex $list $j] incr n -1 set temp [lindex $list $n] set list [lreplace [K $list [set list {}]] $j $j $temp] } return $slist } proc play {list} { global played foreach file $list { puts stdout "Playing $file ..." catch {exec /usr/local/bin/ogg123 $file > /dev/null} set played($file) . save_played } return } proc save_played {} { global played set f [open ~/.musicboxrc.new w] puts $f "array set played \{[array get played]\}" close $f catch {file copy -force ~/.musicboxrc ~/.musicboxrc.old} file copy -force ~/.musicboxrc.new ~/.musicboxrc return } # ... go main
Have fun.
And now a little shell function giving me a command line interface to the musicbox (partially linux and site specific).
function music () { case $1 in on) if [ 0 -eq `ps auxw | grep musicbox | grep -v grep | wc -l` ] then #No musicbox running, start it. musicbox > "$HOME/.mydata/CDs/db/collections/played.`date`" & else echo "Musicbox already running, ignoring command" fi ;; off) killall musicbox ogg123 ;; pause) killall -STOP ogg123 musicbox ;; cont) killall -CONT ogg123 musicbox ;; stat) here=`pwd` cd $HOME/.mydata/CDs find . -name '*.m3u' -print | wc -l | xargs echo '#Albums = ' find . -name '*.ogg' -print | wc -l | xargs echo '#Songs = ' cd $here ;; played) if [ -r $HOME/.musicboxrc ] then echo 'source ~/.musicboxrc ;puts "Played: [array size played]"; exit' | tclsh else echo "Nothing played" fi ;; vol) rexima -v | grep pcm ;; clear) rm -f $HOME/.musicboxrc rm -f $HOME/.musicboxrc.new rm -f $HOME/.musicboxrc.old ;; *) # Assume a number and use it to control the mixer rexima pcm $1 ;; esac }
See also peterc's Tcl MP3 Alarm Clock.
TV (Nov 28 ' 08) I didn't know about this page, but I made an audio player based on tcl-cgi for use with a mobile internet device and a server which I think could pass as cool: Jukebox based on webserver with Tcl cgi scripts. If combined with Random worklist generator a correct shuffle should result, contrary to the above link, I think comparable to AK's version.