/* Copyright (C) 2002, 2003 Brian Victor Fernandes This file is part of XMMS mp3cue. XMMS mp3cue is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. XMMS mp3cue is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with XMMS mp3cue; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA XMMS mp3cue: http://brianvictor.tripod.com/mp3cue.htm Email: brianv@phreaker.net Brian Fernandes 503, Miaami Apts. II, St. Vincents Street, Pune 411001 INDIA */ #include #include #include #include "configfile.h" #include #include #include #include #include #include #include "defs.h" #include "xmmsctrl.h" #include #define CONFIGFILE "/.xmms/mp3cue" extern gint time_width; // the funtions static gint mp3cue_thread(gpointer); void mp3cue_init(void); void mp3cue_config(void); void mp3cue_config_save(GtkWidget *wid, gpointer data); void mp3cue_cleanup(void); extern void mp3cue_about(void); extern void fixcolors(gint redrow, gint blackrow); extern int find_cue_sheet(gint); extern void clean_list(); void hide_list(GtkWidget *playlist, gpointer data); void nextsong(); void prevsong(); gint findsong(int time); gboolean play_sub_song(GtkWidget *song_list, gint row, gint column, GdkEvent *event); void showMainMenu(); gboolean update_sub_playlist(GtkWidget *song_list, GdkEventButton *event); void remove_sub_song(GtkWidget *song_list, GdkEventButton *event); void edit_sub_song(GtkWidget *song_list, GdkEventButton *event); //global variables, pertaining to the dialogs extern GtkWidget *song_name; extern GtkWidget *song_artist; extern GtkWidget *album_name; extern GtkWidget *album_artist; extern GtkWidget *song_sec; extern GtkWidget *song_min; extern GtkWidget *song_frame; extern GtkWidget *g_playlist; extern GtkWidget *sub_playlist; extern GtkWidget *song_menu; extern GtkWidget *main_menu; extern void create_About(); extern void create_Add_Song(); extern GtkWidget* create_Playlist (void); gchar *album_name_s; gchar *album_artist_s; //Miscellaneous Global variables static gint timeout_tag = 0; static gint previous_song = -1, previous_length = -2; gint rows = 0, s_row = -1, p_row = -1, n_row = -1; char list_visible = 1; int n_time,c_time; GdkEventButton two_button_event; GeneralPlugin mp3cue = { NULL, NULL, -1, "XMMS mp3cue "VERSION, mp3cue_init, create_About, mp3cue_config, mp3cue_cleanup, }; void hide_list(GtkWidget *playlist, gpointer data) { gtk_widget_hide(playlist); list_visible = 0; } void nextsong() { if(gtk_clist_get_selectable(GTK_CLIST(sub_playlist), p_row+1)) { two_button_event.type = GDK_2BUTTON_PRESS; play_sub_song(sub_playlist, p_row+1, 0,(GdkEvent *) &two_button_event); } } void prevsong() { if(p_row > 0) { two_button_event.type = GDK_2BUTTON_PRESS; play_sub_song(sub_playlist, p_row-1, 0,(GdkEvent *) &two_button_event); } } void fixtimes(gint c_row) { gchar *ntimed; gchar *data; static gchar title[100]; gint min, sec, frame; //also get the time of the next song in the list if(gtk_clist_get_text(GTK_CLIST(sub_playlist), c_row+1, 1, &ntimed)) { SCANTIME(ntimed,min,sec,frame); n_time = MSEC(min, sec, frame); //set the window title } else n_time = xmms_remote_get_playlist_time(mp3cue.xmms_session, xmms_remote_get_playlist_pos(mp3cue.xmms_session)); //now set the title if(gtk_clist_get_text(GTK_CLIST(sub_playlist), c_row, 0, &data)) { strcpy(title, "mp3cue ~ "); strncat(title, strrchr(data,'~')+2,100-strlen(title)-1); gtk_window_set_title(GTK_WINDOW(g_playlist), title); } else gtk_window_set_title(GTK_WINDOW(g_playlist), "mp3cue Playlist"); #ifdef DEBUG printf("\nNext song at %d msec or %d minutes",n_time,n_time/(60*1000)); #endif } gboolean play_sub_song(GtkWidget *song_list, gint row, gint column, GdkEvent *event) { if(!event || event->type == GDK_2BUTTON_PRESS) { //get the text int the selected row gchar *timed; gint min, sec, frame; gtk_clist_get_text(GTK_CLIST(song_list), row, 1, &timed); SCANTIME(timed,min,sec,frame); if(!xmms_remote_is_playing(mp3cue.xmms_session)) xmms_remote_play(mp3cue.xmms_session); xmms_remote_jump_to_time(mp3cue.xmms_session, MSEC(min, sec, frame)); //make playlist changes immediately ... //we need to check whether xmms has jumped in order to accomodate for impossible time data int c_row = findsong(xmms_remote_get_output_time(mp3cue.xmms_session)); fixtimes(c_row); fixcolors(c_row, p_row); p_row = c_row; return TRUE; } return FALSE; } void showMainMenu(GtkWidget *dummy, GdkEventButton *event) { if(event->button == 3) { s_row = -1; gtk_menu_popup(GTK_MENU(main_menu), NULL, NULL, NULL, NULL, 3, event->time); } } gboolean update_sub_playlist(GtkWidget *song_list, GdkEventButton *event) { gint col; s_row = -1; if(event->button == 3) { gtk_clist_get_selection_info(GTK_CLIST(sub_playlist), (gint)event->x, (gint)event->y, &s_row, &col); if(s_row >= 0) gtk_menu_popup(GTK_MENU(song_menu), NULL, NULL, NULL, NULL, 3, event->time); else //okey dokey display the main menu gtk_menu_popup(GTK_MENU(main_menu), NULL, NULL, NULL, NULL, 3, event->time); return TRUE; } return FALSE; } void remove_sub_song(GtkWidget *song_list, GdkEventButton *event) { if(event->button == 1) { gtk_clist_remove(GTK_CLIST(sub_playlist), s_row); rows--; //update our globals //if update or add, we have to fix up the time p_row = findsong(xmms_remote_get_output_time(mp3cue.xmms_session)); fixtimes(p_row); clean_list(); fixcolors(p_row, -1); } } void edit_sub_song(GtkWidget *song_list, GdkEventButton *event) { if(event->button == 1) { create_Add_Song(); } } // simply stop the running thread if running plugin gets disabled void mp3cue_cleanup(void) { if(timeout_tag) gtk_timeout_remove(timeout_tag); timeout_tag = 0; //close the window gtk_widget_destroy(main_menu); gtk_widget_destroy(song_menu); gtk_widget_destroy(g_playlist); //pthread_cancel (tid); } // required by xmms to display info line extern "C" { GeneralPlugin *get_gplugin_info(void) { return (&mp3cue); } } // initialization of the plugin void mp3cue_init(void) { //read_config(NULL, NULL); previous_song = -1; previous_length = -2; timeout_tag = gtk_timeout_add(500, mp3cue_thread, NULL); g_playlist = create_Playlist(); //playlist should be create only once, at the beginning, thereafter, it cannot be deleted but only hidden } gint findsong(int time) { //to find the song that corresponds to the current time gchar *timed; gint row = 0; gint min, sec, frame; while(gtk_clist_get_text(GTK_CLIST(sub_playlist), row++, 1, &timed)) { SCANTIME(timed, min, sec, frame); if(MSEC(min, sec, frame) > time) break; } //the previous row will be the song we want read the time row-=2; if(gtk_clist_get_text(GTK_CLIST(sub_playlist), row, 1, &timed)) { SCANTIME(timed, min, sec, frame); c_time = MSEC(min, sec, frame); } else c_time = 0; #ifdef DEBUG printf("\nFound song at Row:%d , %d mins",row,c_time/(60*1000)); #endif return row; } // the main part static gint mp3cue_thread(gpointer data) { gint pos, length, o_time, c_row; GDK_THREADS_ENTER(); //check whether we should change the highlighting for the currently playing song if(xmms_remote_is_playing(mp3cue.xmms_session)) { o_time = xmms_remote_get_output_time(mp3cue.xmms_session); if(o_time >= n_time || o_time < c_time) { //ok, since we have moved, we must now find the new sub song to highlight c_row = findsong(o_time); fixtimes(c_row); fixcolors(c_row, p_row); p_row = c_row; } } //song change pos = xmms_remote_get_playlist_pos(mp3cue.xmms_session); length = xmms_remote_get_playlist_time(mp3cue.xmms_session, pos); if (pos != previous_song || length != previous_length) { previous_song = pos; previous_length = length; gtk_clist_clear(GTK_CLIST(sub_playlist)); //now we should be loading another playlist if present.. for now, it isn't so.. rows = 0; c_time = 0; n_time = length; p_row = -1; //clear the current album name and artist.. if(album_name_s) free(album_name_s); if(album_artist_s) free(album_artist_s); album_name_s = NULL; album_artist_s = NULL; //get the new name find_cue_sheet(pos); } GDK_THREADS_LEAVE(); return TRUE; } // the config window ... currently just toggles the mp3cue playlist void mp3cue_config(void) { if(list_visible) { gtk_widget_hide(g_playlist); list_visible = 0; } else { gtk_widget_show(g_playlist); list_visible = 1; } } //General algorithm for loading up the correct cue sheets and highlighting the current song in the mp3cue playlist //Every 500 Msec.. check if we have a new song. // if so, then set p_row to -1. Set c_time to 0 and n_time to song end //also check if we have our output time below c_time or above n_time // if so, we must find the song at the current output time. // then fix c_time and n_time for that song. // change the highlighting //if we add a song, then all the p_row info could be messed up, also the currently playing song could change. //so get p_row data (time) before adding. //when we add the data //if p_row will be affected, change it ... highlighting changes automatically //find the song at the new time //set c_time and n_time data //if the current row has changed, then change highlighting