#!/usr/bin/perl # # route66 - front end for database driven mp3 player # by: Anders Brownworth (anders@imaginemedia.com) # contributors: Michael Kidd (kiddo@elmer.imaginemedia.com) # # this program drives a Matrix Orbital 20 character by 4 line display # module connected to a serial port. they cost about $200 but are not # necessary if you set the $display_type to "console". you should go set # basic options in Settings.pm such as the serial port and control keys # that you intend to use. # # modifications by Jim Kershner # Added support for a random play mode 6/1/2001 use Settings; use Database; use Display; use Menu; use playerlib; my ( $display_type, $serial_port, $up_key, $down_key, $forward_key, $back_key, $setvol_cmd, $mixer_cmd, $halt_cmd ) = settings_get ( ); $version = "0.5.3.jrk.01"; $filesystemid = 1; $main_pos = 0; $options_pos = 0; $select_pos = 0; $exit = 0; $time_mode = "up"; $play_menu_mode = "play"; # Added flag for random mode on/off - jrk 6/1/2001 $random_mode = 0; ######################################################### display_init ( ); display_write ( "route66 - v$version" ); ( $dbh, $version ) = database_open (); display_write "db version: $version"; $player = playerlib::new_playerlib (); display_write "soundsystem init"; set_environment ( ); sleep 1; display_clear ( ); display_time ( ); ################################ # main menu loop ################################ while ( !$exit ) { @menu = ( "Select", "Play", "Radio", "Options", "Exit" ); display_clear(); menu_title ( "Main Menu" ); display_time ( ); $main_pos = menu_navigate ( @menu, $main_pos, 0 ); if ( $main_pos == 0 ) { select_menu ( ); } elsif ( $main_pos == 1 ) { play_menu ( ); } elsif ( $main_pos == 2 ) { radio_menu ( ); } elsif ( $main_pos == 3 ) { options_menu ( ); } elsif ( $main_pos == 4 ) { $exit = 1; } } $result = menu_yes_no ( "Halt the computer?", 0 ); if ( $result ) { system "$halt_cmd"; } display_clear (); display_close (); #################################### # subroutines #################################### # # set_environment : sets current username, path and set. # sub set_environment { ( $usernameid, $pathid, $setid ) = database_get_current ( $dbh ); $username = database_get_username ( $dbh, $usernameid ); if ( ! $username ) { @usernames = database_get_all_usernames ( $dbh ); display_clear ( ); display_time ( ); menu_title ( "Select a Username" ); $usernameid = menu_navigate ( @usernames, 0, 0 ); $username = @usernames[$usernameid]; $usernameid ++; database_update_current ( $dbh, $usernameid, $pathid, $setid ); } @genres = database_get_all_genres ( $dbh ); @artists = database_get_all_artists ( $dbh ); @albums = database_get_all_albums ( $dbh ); @genres = sort @genres; @artists = sort @artists; @albums = sort @albums; return ( $usernameid, $pathid, $setid ); } # # select_menu : deals with stuff in the select menu # sub select_menu { my $exit = 0; while ( ! $exit ) { @menu = ( "by Genre", "by Artist", "by Album", "by Tempo", "by Preference", "by Saved Set", "Save This Set", "Unselect All" ); menu_title ( "Select" ); $result = menu_navigate ( @menu, $select_pos, 1 ); $select_pos = $result unless ( $result == -1 ); if ( $result == -1 ) { $exit = 1; } elsif ( $result == 0 ) { select_genre_menu ( ); } elsif ( $result == 1 ) { select_artist_menu ( ); } elsif ( $result == 2 ) { select_album_menu ( ); } elsif ( $result == 3 ) { # select_tempo_menu ( ); } elsif ( $result == 4 ) { # select_preference_menu ( ); } elsif ( $result == 5 ) { # select_set_menu ( ); } elsif ( $result == 6 ) { # select_saved_set ( ); } elsif ( $result == 7 ) { # unselect all undef @genres_selected; undef @albums_selected; undef @artists_selected; menu_info ( "Unselected", 2 ); } else { print "$result - out of bounds in select menu\n"; } } } sub select_genre_menu { menu_title ( "Genres" ); $select_genre_pos = menu_select ( \@genres, \@genres_selected, $select_genre_pos ); } sub select_album_menu { menu_title ( "Albums" ); $select_albums_pos = menu_select ( \@albums, \@albums_selected, $select_albums_pos ); } sub select_artist_menu { menu_title ( "Artists" ); $select_artists_pos = menu_select ( \@artists, \@artists_selected, $select_artists_pos ); } # # play_menu : deals with the play screen # sub play_menu { my $total = $x = $stop = $result = 0; menu_title ( "Play Music" ); @pathids = select_pathids ( ); $total = @pathids; if ( $total < 1 ) { menu_info ( "No music is selected", 2 ); } else { @songnames = build_songnames ( @pathids ); $stop = 0; $current_song = 1; while ( !$stop ) { # added code to randomize play - jrk 6/1/2001 if ( $random_mode == 1) { srand; $current_song = int (rand scalar ($total)); } my ( $result, $track ) = play ( \@pathids, \@songnames, $current_song ); if ( $result == 1 ) { # hard quit. exit to main menu. $stop = 1; } elsif ( $result == 2 ) { # go back one track. $current_song --; } elsif ( $result == 3 ) { # go to next track. $current_song ++; } else { # go to $track. $current_song = $track; } if ( $current_song > $total ) { $current_song = 1; # start over at the beginning } elsif ( $current_song < 1 ) { $current_song = $total; # go to the end of the list } } } } # # @songnames = build_songnames ( @pathids ); # spin through the array of songs and get the names # sub build_songnames { my @pathids = @_; my @songnames, @pathinfo; my $counter = 0; my $total = @pathids; while ( $counter < $total ) { @pathinfo = database_get_path ( $dbh, @pathids [ $counter ] ); $songid = @pathinfo [ 4 ]; @songinfo = database_get_song ( $dbh, $songid ); push @songnames, @songinfo [ 5 ]; $counter ++; } return @songnames; } # # @pathids = select_pathids ( ); # builds a playlist from the selections in @artists_selected, # @albums_selected, @genres_selected which I consider to be global. # sub select_pathids { my @pathids; my $albums_total, $artists_total, $genres_total, $junk, $time, $path, $pathid, $x; my $sql = $x = $genre_sql = $artist_sql = $album_sql = 0; $albums_total = @albums; while ( $x < $albums_total ) { if ( @albums_selected[$x] == 1 ) { $total ++; if ( $album_sql ) { $album_sql = $album_sql . ", '@albums[$x]'"; } else { $album_sql = "'@albums[$x]'"; } } $x ++; } $x = 0; $genres_total = @genres; while ( $x < $genres_total ) { if ( @genres_selected[$x] == 1 ) { $total ++; if ( $genre_sql ) { $genre_sql = $genre_sql . ", '@genres[$x]'"; } else { $genre_sql = "'@genres[$x]'"; } } $x ++; } $x = 0; $artists_total = @artists; while ( $x < $artists_total ) { if ( @artists_selected[$x] == 1 ) { $total ++; if ( $artist_sql ) { $artist_sql = $artist_sql . ", '@artists[$x]'"; } else { $artist_sql = "'@artists[$x]'"; } } $x ++; } if ( $total > 0 ) { $sqlbase = "select distinct paths.pathid from paths"; if ( $artist_sql ) { $sqlbase = $sqlbase . ", artists"; $sql = " ( artists.artistid = paths.artistid and artists.artist in ( $artist_sql ) )"; if ( $album_sql ) { $sqlbase = $sqlbase . ", albums"; $sql = $sql . " or ( albums.albumid = paths.albumid and albums.album in ( $album_sql ) )"; } if ( $genre_sql ) { $sqlbase = $sqlbase . ", genres"; $sql = $sql . " or ( genres.genreid = paths.genreid and genres.genre in ( $genre_sql ) )"; } } elsif ( $album_sql ) { $sqlbase = $sqlbase . ", albums"; $sql = " ( albums.albumid = paths.albumid and albums.album in ( $album_sql ) )"; if ( $genre_sql ) { $sqlbase = $sqlbase . ", genres"; $sql = $sql . " or ( genres.genreid = paths.genreid and genres.genre in ( $genre_sql ) )"; } } elsif ($genre_sql) { $sqlbase = $sqlbase . ", genres"; $sql = "select distinct paths.pathid from paths, artists, albums, genres where ( genres.genreid = paths.genreid and genres.genre in ( $genre_sql ))"; } $sqlbase = $sqlbase . " where"; $sql = $sqlbase . $sql . ";"; menu_info ( "Building Playlist...", 0 ); @pathids = database_raw_sql ( $dbh, $sql ); } return ( @pathids ); } # # options_menu : deals with stuff in the options menu # sub options_menu { my $exit = 0; my @menu; while ( !$exit ) { @menu = ( "Set User [$username]", "Add User", "Delete User", "Set Filesystem", "Random", "Time Mode", "Adjust Display", "Screensaver" ); menu_title ( "Options" ); $result = menu_navigate ( @menu, $options_pos, 1 ); $options_pos = $result unless ( $result == -1 ); if ( $result == -1 ) { $exit = 1; } elsif ( $result == 0 ) { options_set_user_menu ( ); } elsif ( $result == 1 ) { options_add_user_menu ( ); } elsif ( $result == 2 ) { menu_info ( "Delete not done", 2 ); } elsif ( $result == 3 ) { menu_info ( "Filesystem not done", 2 ); } elsif ( $result == 4 ) { # added random mode code - jrk - 6/1/2001 if ($random_mode == 1){ menu_info ("Random Mode Off",2); $random_mode = 0; } else { menu_info ("Random Mode On",2); $random_mode = 1; } } elsif ( $result == 5 ) { @menu = ( "Count Up", "Count Down" ); menu_title ( "Time Mode" ); if ( $time_mode eq "up" ) { $result = menu_navigate ( @menu, 0, 1 ); } else { $result = menu_navigate ( @menu, 1, 1 ); } if ( $result == 0 ) { $time_mode = "up"; } else { $time_mode = "down"; } } elsif ( $result == 6 ) { menu_info ( "Adjust not done", 2 ); } else { menu_info ( "Screensaver not done", 2 ); } } } # # options_set_user_menu : select the current user # sub options_set_user_menu { my @usernames = database_get_all_usernames ( $dbh ); my $x = 0; $username = database_get_username ( $dbh, $usernameid ); $max = @usernames; while ( ( $username ne @usernames[$x] ) && ( $x >= $max ) ) { $x ++; } print "Warning!! User not found!" if ( $x > $max ); menu_title ( "Current User" ); $result = menu_navigate ( @usernames, $x, 1 ); if ( $result > -1 ) { $username = @usernames[$result]; $usernameid = database_get_usernameid ( $dbh, @usernames[$result] ); database_update_current ( $dbh, $usernameid, $pathid, $setid ); } } # # options_add_user_menu : add another user to the system # sub options_add_user_menu { my $name; menu_title ( "Add User" ); $name = menu_text_entry ( "Enter a Username", 20 ); $name =~ s/\s*$//; if ( $name ne "" ) { if ( menu_yes_no ( "Shall I add $name?", 1 ) ) { database_put_username ( $dbh, $name ); menu_info ( "$name added", 1 ); } } } # # $result = play ( \@pathids, \@song_names, $song_number ); # pulls up all the info for the pathid and plays the file. # sub play { my ( $pathids, $song_names, $song_number ) = @_; my ( $filesystemid, $contributorid, $artistid, $albumid, $songid, $genreid, $volume, $timestamp, $path ) = database_get_path ( $dbh, @$pathids [$song_number - 1] ); my ( $mood, $tempo, $endsilence, $tracknumber, $year, $song ) = database_get_song ( $dbh, $songid ); my ( $artistid, $album, $year ) = database_get_album ( $dbh, $albumid ); my ( $artist ) = database_get_artist ( $dbh, $artistid ); my ( $pref ) = database_get_preference ( $dbh, $pathid, $usernameid ); my $total_songs = @$pathids; my $stop = $total = $stat = $minutes = $seconds = $percent = $key = 0; my $last_seconds = $last_percent = $last_barval = ""; my $barval = $wait = 0; my $start_volume = $volume; my $start_pref = $pref; my $char = ":"; my $old_song_number_selected = $song_number_selected = $song_number - 1; my $display = "progress"; my $old_play_menu_mode = $play_menu_mode; my $progress_up = 1; if ( $volume < 1 ) { $volume = $volume * 100; # normalize volume } database_put_history ( $dbh, $usernameid, @$pathids [$song_number - 1] ); system "$setvol_cmd $volume"; display_clear ( ); display_init_bargraph ( ); display_position ( 1, 1 ); display_write ( fit ( "$artist:$album", 20 ) ); display_position ( 1, 2 ); display_write ( fit ( "$song_number/$total_songs:$song", 20 ) ); display_bargraph ( 3, 0, 1, 75 ); if ( $play_menu_mode eq "play" ) { @mini_options = ( "Prev", "Play", "Next" ); } elsif ( $play_menu_mode eq "select" ) { @mini_options = ( "Exit", "Select", "Song" ); } else { @menu_options = ( "whoops", "somthin", "broke" ); } menu_mini ( @mini_options ); if ( !-e $path ) { die "The database returned an invalid path: [$path]\n"; } $player->playerlib::playerlib_set_file( $path ); $total = $player->playerlib::playerlib_total_frames(); $stat = $player->playerlib::playerlib_current_frame(); if ( $total < 1 ) { # total frames less than 1 $stop = 3; # continue to next track. } while ( !$stop ) { if ( !$player->playerlib::playerlib_run() ) { $stop = 3; # song finished. continue to next track. } else { $key = display_check_for_key ( 0 ); if ( $key eq $forward_key ) { if ( $display eq "progress" ) { if ( $play_menu_mode eq "play" ) { $stop = 3; # continue to next track. $player->playerlib::playerlib_stop(); } elsif ( $play_menu_mode eq "volume" ) { $volume++; if ( $volume > 100 ) { $volume = 100; } else { system "$setvol_cmd $volume"; @mini_options = ( "Down", "Vol:$volume%", "Up" ); menu_mini ( @mini_options ); } } elsif ( $play_menu_mode eq "pref" ) { $pref = $pref + 5; if ( $pref > 100 ) { $pref = 100; } else { @mini_options = ( "Down", "Pref:$pref", "Up" ); menu_mini ( @mini_options ); } } elsif ( $play_menu_mode eq "select" ) { $display = "songlist"; $menu_up = 0; $progress_up = 0; } } elsif ( $display eq "songlist" ) { $new_song_number = $song_number_selected + 1; $stop = 4; $player->playerlib::playerlib_stop(); $menu_up = 0; } } elsif ( $key eq $back_key ) { if ( $display eq "progress" ) { if ( $play_menu_mode eq "play" ) { $stop = 2; $player->playerlib::playerlib_stop(); } elsif ( $play_menu_mode eq "volume" ) { $volume --; if ( $volume < 0 ) { $volume = 0; } else { system "$setvol_cmd $volume"; @mini_options = ( "Down", "Vol:$volume%", "Up" ); menu_mini ( @mini_options ); } } elsif ( $play_menu_mode eq "pref" ) { $pref = $pref - 5; if ( $pref < 0 ) { $pref = 0; } else { @mini_options = ( "Down", "Pref:$pref", "Up" ); menu_mini ( @mini_options ); } } elsif ( $play_menu_mode eq "select" ) { $stop = 1; $player->playerlib::playerlib_stop(); } } elsif ( $display eq "songlist" ) { $display = "progress"; $progress_up = 0; $menu_up = 0; } } elsif ( $key eq $up_key ) { if ( $display eq "progress" ) { if ( $play_menu_mode eq "select" ) { $play_menu_mode = "pref"; @mini_options = ( "Down", "Pref:$pref", "Up" ); menu_mini ( @mini_options ); } elsif ( $play_menu_mode eq "play" ) { $play_menu_mode = "select"; @mini_options = ( "Exit", "Select", "Song" ); menu_mini ( @mini_options ); } elsif ( $play_menu_mode eq "pref" ) { $play_menu_mode = "volume"; @mini_options = ( "Down", "Vol:$volume%", "Up" ); menu_mini ( @mini_options ); } elsif ( $play_menu_mode eq "volume" ) { $play_menu_mode = "play"; @mini_options = ( "Prev", "Play", "Next" ); menu_mini ( @mini_options ); } } elsif ( $display eq "songlist" ) { $song_number_selected -- unless ( $song_number_selected < 1 ); } } elsif ( $key eq $down_key ) { if ( $display eq "progress" ) { if ( $play_menu_mode eq "play" ) { $play_menu_mode = "volume"; @mini_options = ( "Down", "Vol:$volume%", "Up" ); menu_mini ( @mini_options ); } elsif ( $play_menu_mode eq "volume" ) { $play_menu_mode = "pref"; @mini_options = ( "Down", "Pref:$pref", "Up" ); menu_mini ( @mini_options ); } elsif ( $play_menu_mode eq "pref" ) { $play_menu_mode = "select"; @mini_options = ( "Exit", "Select", "Song" ); menu_mini ( @mini_options ); } elsif ( $play_menu_mode eq "select" ) { $play_menu_mode = "play"; @mini_options = ( "Prev", "Play", "Next" ); menu_mini ( @mini_options ); } } elsif ( $display eq "songlist" ) { $song_number_selected ++ unless ( $song_number_selected >= ( $total_songs - 1 ) ); } } $stat = $player->playerlib::playerlib_current_frame(); if ( $time_mode eq "up" ) { $seconds = int ( $stat / 38 ); } else { $seconds = int ( ( $total - $stat ) / 38 ); } $minutes = int ( $seconds / 60 ); $seconds = $seconds - ( $minutes * 60 ); $seconds = sprintf ( "%.2d", $seconds ); $barval = int ( ( $stat / $total ) * 75 ) + 1; if ( $display eq "progress" ) { if ( ( $seconds != $last_seconds ) || ( $barval != $last_barval ) ) { if ( !$progress_up ) { display_clear ( ); display_init_bargraph ( ) unless ( $display_type eq "console" ); display_position ( 1, 1 ); display_write ( fit ( "$artist:$album", 20 ) ); display_position ( 1, 2 ); display_write ( fit ( "$song_number/$total_songs:$song", 20 ) ); menu_mini ( @mini_options ); $progress_up = 1; } display_bargraph ( 3, 1, $barval, 75 ); display_position ( 17, 3 ); display_write ( "$minutes:$seconds" ); $last_seconds = $seconds; $last_barval = $barval; } } elsif ( ( $display eq "songlist" ) && ( ( $song_number_selected != $old_song_number_selected ) || ( !$menu_up ) ) ) { menu_title ( "Song Select" ); display_time ( ); menu_render ( @$song_names, 1, $song_number_selected ); $old_song_number_selected = $song_number_selected; $menu_up = 1; } } } $player->playerlib::playerlib_unset_file(); if ( $pref != $start_pref ) { database_update_preference ( $dbh, $songid, $usernameid, $pref ); } if ( $volume != $start_volume ) { database_set_volume ( $dbh, $pathid, $volume ); } return ( $stop, $new_song_number ); } # # rips through an array and returns 1 if there is a number # higher than 0 in it. # sub any_selected { my @ary = @_; my $key = $found = 0; while ( defined ( $key = pop ( @ary ) ) ) { if ( $key > 0 ) { $found = 1; } } return ( $found ); } # # radio_menu ( ); # sets up the radio pass-through untill the user hits the back_key # sub radio_menu { system ("$mixer_cmd -v 70,70"); system ("$mixer_cmd -l 70,70"); system ("$mixer_cmd -w 0,0"); # turn radio passthrough on menu_until_keypress ( "Radio Pass-through" ); system ("$mixer_cmd -w 100,100"); # turn radio passthrough off }