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
mainHave 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.