/* 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 "xmmsctrl.h" #include "defs.h" #include #include #include using namespace std; #define MAXX 1024 typedef unsigned char BOOL; extern void quick_message(gchar *message); extern void fixtimes(gint c_row); extern void fixcolors(gint redrow, gint blackrow); extern BOOL LoadID3(const char *fname); extern gint findsong(int time); extern GeneralPlugin mp3cue; extern gchar *album_name_s; extern gchar *album_artist_s; extern GtkWidget *sub_playlist; extern gint p_row, rows; typedef enum { CTFILE, TITLE, PERFORMER, TRACK, INDEX, PREGAP, POSTGAP, SONGWRITER, FLAGS, ISRC, REM, CDTEXTFILE, CATALOG } CUE_TAGS; gchar *get_cue_name(gchar *o_fname); int tagnum(const gchar *tag); void free_n_fname(GtkWidget *save_cue); void save_cue_sheet(GtkWidget *save_cue); int find_cue_sheet(gint pos); void parse_cue_sheet(FILE *cue_sheet, char *cue_mem = NULL); void export_cue_sheet(); void import_cue_sheet(); void load_cue_sheet(GtkWidget *open_cue, gpointer data); string Make_Cue_String(); void addrow(gchar *s_name, gchar *a_name, gchar *timed); void get_q_data(const gchar *instring, gchar *outstring); int tagnum(const gchar *tag); gchar *o_fname, *n_fname; gchar *get_cue_name(gchar *o_fname) { gchar *cue_name, *temp; //find the extension for(temp = o_fname+strlen(o_fname)-1; *temp != '.' && temp != o_fname; temp--); //has it got a 3 letter extension ?, if so , replace the extension with .cue if(temp != o_fname && strlen(temp) == 4) { cue_name = (gchar *)malloc(strlen(o_fname)+1); strcpy(cue_name, o_fname); strcpy(cue_name + strlen(cue_name)-4, ".cue"); } else { cue_name = (gchar *)malloc(strlen(o_fname)+5); strcpy(cue_name,o_fname); strcat(cue_name,".cue"); } return cue_name; } gchar *get_cue_name1(const gchar *o_fname) { gchar *cue_name; if(!(strcasecmp(o_fname+strlen(o_fname)-4,".mp3"))) { cue_name = (gchar *)malloc(strlen(o_fname)+1); strcpy(cue_name, o_fname); strcpy(cue_name+strlen(cue_name)-4,".cue"); } else { cue_name = (gchar *)malloc(strlen(o_fname)+5); strcpy(cue_name,o_fname); strcat(cue_name,".cue"); } return cue_name; } int tagnum(const gchar *tag) { if(!strcasecmp(tag,"FILE")) return CTFILE; else if(!strcasecmp(tag,"TRACK")) return TRACK; else if(!strcasecmp(tag,"TITLE")) return TITLE; else if(!strcasecmp(tag,"PERFORMER")) return PERFORMER; else if(!strcasecmp(tag,"TRACK")) return TRACK; else if(!strcasecmp(tag,"INDEX")) return INDEX; else if(!strcasecmp(tag,"PREGAP")) return PREGAP; else if(!strcasecmp(tag,"POSTGAP")) return POSTGAP; else if(!strcasecmp(tag,"SONGWRITER")) return SONGWRITER; else if(!strcasecmp(tag,"FLAGS")) return FLAGS; else if(!strcasecmp(tag,"ISRC")) return ISRC; else if(!strcasecmp(tag,"REM")) return REM; else if(!strcasecmp(tag,"CDTEXTFILE")) return CDTEXTFILE; else if(!strcasecmp(tag,"CATALOG")) return CATALOG; else return -1; } void get_q_data(const gchar *instring, gchar *outstring) { //find the data enclosed by the quotes gchar *qstart = strchr(instring,'\"'); gchar *qend = strrchr(instring,'\"'); if(qstart && qend) { if(qend-qstart-1 < MAXX && qend-qstart-1 > 0) { strncpy(outstring, qstart+1, (qend-qstart-1)); outstring[qend-qstart-1] = 0; } else { strncpy(outstring, qstart+1, MAXX-1); outstring[MAXX-1] = 0; } } else *outstring = 0; } void addrow(gchar *s_name, gchar *a_name, gchar *timed) { static gchar *rdata[2]; static gchar data[MAXX]; static gint min, sec, frame; rows++; //check for completeness of previous data sprintf(data, "%s ~ %s", a_name, s_name); *s_name = *a_name = 0; rdata[0] = data; if(*timed) { SCANTIME(timed,min,sec,frame); PTIME(timed, min, sec, frame); } else PTIME(timed, 0, 0, 0); rdata[1] = timed; gtk_clist_append(GTK_CLIST(sub_playlist), rdata); *timed = 0; } void parse_cue_sheet(FILE *cue_sheet,char *cue_mem) { gboolean track_started = FALSE; gchar lined[MAXX]; gchar tag[MAXX]; gchar s_name[MAXX], a_name[MAXX]; gchar timed[10]; rows = 0; *a_name = 0; *s_name = 0; *timed = 0; char *d_ptr=cue_mem, *d_end=NULL; if(cue_mem) d_end = cue_mem + strlen(cue_mem); while(1) { if(!cue_mem) { //if we are reading from the cue file if(!fgets(lined, MAXX, cue_sheet)) break; } else { //if we are reading from memory if(d_ptr >= d_end) break; if(!sscanf(d_ptr, "%[^\r\n]s",lined)) { #ifdef DEBUG printf("Invalid Input ...\n%s\n",lined); #endif d_ptr++; } else { #ifdef DEBUG printf("Line scanned \n%s\n",lined); #endif d_ptr += strlen(lined) + 2; } } *tag = 0; sscanf(lined, "%s", tag); #ifdef DEBUG printf("Tag is %s\n",tag); #endif switch(tagnum(tag)) { case PERFORMER: get_q_data(lined, a_name); if(!track_started) { album_artist_s = (gchar *)malloc(strlen(a_name)+1); strcpy(album_artist_s, a_name); *a_name = 0; } break; case TITLE: get_q_data(lined, s_name); if(!track_started) { album_name_s = (gchar *)malloc(strlen(s_name)+1); strcpy(album_name_s, s_name); *s_name = 0; } break; case INDEX: sscanf(lined,"%*s %*s %s",timed); #ifdef DEBUG printf("Time is %s\n",timed); #endif break; //when we reach this tag, we know that the previous track has ended and a new track has begun, so store the old track case TRACK: if(!track_started) track_started = TRUE; else { if(*a_name || *s_name || *timed) addrow(s_name, a_name, timed); } break; #ifdef DEBUG default: printf("No matching data\n"); #endif } } //if we still have some info left over, add it also if(*s_name || *a_name || *timed) addrow(s_name, a_name, timed); //now fix the times p_row = findsong(xmms_remote_get_output_time(mp3cue.xmms_session)); fixtimes(p_row); fixcolors(p_row, -1); } int find_cue_sheet(gint pos) { gchar *o_name, *n_name; FILE *cue_file; o_name = xmms_remote_get_playlist_file(mp3cue.xmms_session,pos); o_fname = o_name; if(o_name) { n_name = get_cue_name(o_name); #ifdef DEBUG printf("Locating Cue file: %s\n",n_name); #endif if( (cue_file=fopen(n_name,"rt")) ) { parse_cue_sheet(cue_file); free(n_name); fclose(cue_file); } else { #ifdef DEBUG printf("Cue file not found, checking mp3\n"); #endif LoadID3(o_name); } return 1; } return 0; } void free_n_fname(GtkWidget *save_cue) { if(n_fname) free(n_fname); } void load_cue_sheet(GtkWidget *open_cue, gpointer data) { gchar *nfname; FILE *cue_file; nfname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(open_cue)); if( (cue_file=fopen(nfname,"rt")) ) { gtk_clist_clear(GTK_CLIST(sub_playlist)); if(album_name_s) free(album_name_s); if(album_artist_s) free(album_artist_s); album_name_s = NULL; album_artist_s = NULL; parse_cue_sheet(cue_file); fclose(cue_file); } #ifdef DEBUG else printf("Cue file not found\n"); #endif } void import_cue_sheet() { //display the dialog box to get the new sheet GtkWidget *open_cue; //if the extension is mp3, then just change mp3 to cue n_fname = get_cue_name(o_fname); open_cue = gtk_file_selection_new("Import Cue Sheet"); gtk_file_selection_set_filename(GTK_FILE_SELECTION(open_cue), n_fname); gtk_signal_connect_object((GtkObject *)GTK_FILE_SELECTION(open_cue)->ok_button, "clicked", GTK_SIGNAL_FUNC(load_cue_sheet), (GtkObject *) open_cue); gtk_signal_connect_object((GtkObject *)GTK_FILE_SELECTION(open_cue)->ok_button, "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), (GtkObject *) open_cue); gtk_signal_connect_object((GtkObject *)GTK_FILE_SELECTION(open_cue)->cancel_button, "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), (GtkObject *) open_cue); gtk_widget_show(open_cue); free(n_fname); } void export_cue_sheet() { GtkWidget *save_cue; //if the extension is mp3, then just change mp3 to cue n_fname = get_cue_name(o_fname); save_cue = gtk_file_selection_new("Export Cue Sheet"); gtk_file_selection_set_filename(GTK_FILE_SELECTION(save_cue), n_fname); gtk_signal_connect_object((GtkObject *)GTK_FILE_SELECTION(save_cue)->ok_button, "clicked", GTK_SIGNAL_FUNC(save_cue_sheet), (GtkObject *) save_cue); gtk_signal_connect_object((GtkObject *)GTK_FILE_SELECTION(save_cue)->ok_button, "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), (GtkObject *) save_cue); gtk_signal_connect_object((GtkObject *)GTK_FILE_SELECTION(save_cue)->cancel_button, "clicked", GTK_SIGNAL_FUNC(free_n_fname), (GtkObject *) save_cue); gtk_signal_connect_object((GtkObject *)GTK_FILE_SELECTION(save_cue)->cancel_button, "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), (GtkObject *) save_cue); gtk_widget_show(save_cue); } void save_cue_sheet(GtkWidget *save_cue) { gchar *nfname; FILE *cuefile; //if we aren't writing into the mp3, fine the appropriate file name and save in that nfname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(save_cue)); if(strcasecmp(n_fname, nfname)) quick_message("Warning: File Name differs from original\nmp3cue will not be able to locate the cuesheet automatically"); free(n_fname); #ifdef DEBUG printf("File chosen is %s\n",nfname); #endif cuefile = fopen(nfname, "wt"); if(!cuefile) { quick_message("Error: Cannot create cuefile\nCheck write access"); return; } fprintf(cuefile, "%s", Make_Cue_String().data()); fclose(cuefile); #ifdef DEBUG //print the cue file string printf("The cue file contents: \n%s\n", Make_Cue_String().data()); #endif } string Make_Cue_String() { //create a string consisting of the essential parts of a cue sheet file gint row = 0, whole, second; gchar *songart, *tilda; gchar *timed; string cue_string; gchar buffer[512]; gchar artist_buffer[512]; sprintf(buffer,"FILE \"%s\"\r\n",o_fname); cue_string = buffer; if(album_name_s) sprintf(buffer, "TITLE \"%s\"\r\n",album_name_s); else sprintf(buffer, "TITLE \"\"\r\n"); cue_string += buffer; if(album_artist_s) sprintf(buffer, "PERFORMER \"%s\"\r\n",album_artist_s); else sprintf(buffer, "PERFORMER \"\"\r\n"); cue_string += buffer; for(int i=0;i