Browse Source

improve cue handling a bit

notaz 10 years ago
parent
commit
e71fae1f13
7 changed files with 157 additions and 63 deletions
  1. 2 1
      pico/cd/buffering.c
  2. 17 15
      pico/cd/cd_file.c
  3. 0 5
      pico/cd/cd_file.h
  4. 1 3
      pico/cd/cd_sys.h
  5. 124 28
      pico/cd/cue.c
  6. 9 8
      pico/media.c
  7. 4 3
      pico/sound/sound.c

+ 2 - 1
pico/cd/buffering.c

@@ -7,6 +7,7 @@
  */
 
 #include "../pico_int.h"
+#include "../cd/cue.h"
 
 int PicoCDBuffers = 0;
 static unsigned char *cd_buffer = NULL;
@@ -66,7 +67,7 @@ PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba)
 	int is_bin, offs, read_len, moved = 0;
 	reads++;
 
-	is_bin = Pico_mcd->TOC.Tracks[0].ftype == TYPE_BIN;
+	is_bin = Pico_mcd->TOC.Tracks[0].ftype == CT_BIN;
 
 	if (PicoCDBuffers <= 0)
 	{

+ 17 - 15
pico/cd/cd_file.c

@@ -59,7 +59,7 @@ static int audio_track_mp3(const char *fname, int index)
 	Tracks[index].F = tmp_file;
 
 	// MP3 File
-	Tracks[index].ftype = TYPE_MP3;
+	Tracks[index].ftype = CT_MP3;
 	fs *= 75;
 	fs /= Tracks[index].KBtps * 1000;
 	Tracks[index].Length = fs;
@@ -70,9 +70,10 @@ static int audio_track_mp3(const char *fname, int index)
 
 PICO_INTERNAL int Load_CD_Image(const char *cd_img_name, cd_img_type type)
 {
-	int i, j, num_track, Cur_LBA, index, ret, iso_name_len, missed, cd_img_sectors;
+	int i, j, num_track, Cur_LBA, index, ret;
+	int iso_name_len, missed, cd_img_sectors;
 	_scd_track *Tracks = Pico_mcd->TOC.Tracks;
-	char tmp_name[1024], tmp_ext[10], tmp_ext_u[10];
+	char tmp_name[256], tmp_ext[10], tmp_ext_u[10];
 	cue_data_t *cue_data = NULL;
 	pm_file *pmf;
 	static const char *exts[] = {
@@ -85,14 +86,14 @@ PICO_INTERNAL int Load_CD_Image(const char *cd_img_name, cd_img_type type)
 
 	Unload_ISO();
 
-	/* is this .cue? */
-	ret = strlen(cd_img_name);
-	if (ret >= 3 && strcasecmp(cd_img_name + ret - 3, "cue") == 0)
-		cue_data = cue_parse(cd_img_name);
-	if (cue_data != NULL)
+	/* is this a .cue? */
+	cue_data = cue_parse(cd_img_name);
+	if (cue_data != NULL) {
 		cd_img_name = cue_data->tracks[1].fname;
-
-	Tracks[0].ftype = type == CIT_BIN ? TYPE_BIN : TYPE_ISO;
+		Tracks[0].ftype = cue_data->tracks[1].type;
+	}
+	else
+		Tracks[0].ftype = type == CIT_BIN ? CT_BIN : CT_ISO;
 
 	Tracks[0].F = pmf = pm_open(cd_img_name);
 	if (Tracks[0].F == NULL)
@@ -104,7 +105,7 @@ PICO_INTERNAL int Load_CD_Image(const char *cd_img_name, cd_img_type type)
 		return -1;
 	}
 
-	if (Tracks[0].ftype == TYPE_ISO)
+	if (Tracks[0].ftype == CT_ISO)
 	     cd_img_sectors = pmf->size >>= 11;	// size in sectors
 	else cd_img_sectors = pmf->size /= 2352;
 	Tracks[0].Offset = 0;
@@ -113,8 +114,9 @@ PICO_INTERNAL int Load_CD_Image(const char *cd_img_name, cd_img_type type)
 	Tracks[0].MSF.S = 2; // seconds
 	Tracks[0].MSF.F = 0; // frames
 
-	elprintf(EL_STATUS, "Track  1: %02d:%02d:%02d %9i DATA",
-		Tracks[0].MSF.M, Tracks[0].MSF.S, Tracks[0].MSF.F, Tracks[0].Length);
+	elprintf(EL_STATUS, "Track  1: %02d:%02d:%02d %9i DATA  %s",
+		Tracks[0].MSF.M, Tracks[0].MSF.S, Tracks[0].MSF.F,
+		Tracks[0].Length, cd_img_name);
 
 	Cur_LBA = Tracks[0].Length = cd_img_sectors;
 
@@ -173,7 +175,7 @@ PICO_INTERNAL int Load_CD_Image(const char *cd_img_name, cd_img_type type)
 			LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
 			Cur_LBA += Tracks[index].Length;
 
-			elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO - %s", num_track, Tracks[index].MSF.M,
+			elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO %s", num_track, Tracks[index].MSF.M,
 				Tracks[index].MSF.S, Tracks[index].MSF.F, Tracks[index].Length,
 				cue_data->tracks[num_track].fname);
 		}
@@ -267,7 +269,7 @@ PICO_INTERNAL void Unload_ISO(void)
 	{
 		if (Pico_mcd->TOC.Tracks[i].F != NULL)
 		{
-			if (Pico_mcd->TOC.Tracks[i].ftype == TYPE_MP3)
+			if (Pico_mcd->TOC.Tracks[i].ftype == CT_MP3)
 #ifdef _PSP_FW_VERSION
 				free(Pico_mcd->TOC.Tracks[i].F);
 #else

+ 0 - 5
pico/cd/cd_file.h

@@ -5,11 +5,6 @@
 extern "C" {
 #endif
 
-#define TYPE_ISO 1
-#define TYPE_BIN 2
-#define TYPE_MP3 3
-#define TYPE_WAV 4
-
 typedef enum
 {
 	CIT_NOT_CD = 0,

+ 1 - 3
pico/cd/cd_sys.h

@@ -39,11 +39,9 @@ typedef struct
 
 typedef struct
 {
-//	unsigned char Type; // always 1 (data) for 1st track, 0 (audio) for others
-//	unsigned char Num; // unused
 	_msf MSF;
 	//
-	char ftype; // TYPE_ISO, TYPE_BIN, TYPE_MP3
+	char ftype; // cue_track_type
 	void *F;
 	int Length;
 	int Offset;  // sector offset, when single file is used for multiple virtual tracks

+ 124 - 28
pico/cd/cue.c

@@ -62,49 +62,113 @@ static int get_token(const char *buff, char *dest, int len)
 	return d + skip;
 }
 
-static char *get_ext(char *fname)
+static int get_ext(const char *fname, char ext[4],
+	char *base, size_t base_size)
 {
-	int len = strlen(fname);
-	return (len >= 3) ? (fname + len - 3) : fname;
+	int len, pos = 0;
+	
+	len = strlen(fname);
+	if (len >= 3)
+		pos = len - 3;
+
+	strcpy(ext, fname + pos);
+
+	if (base != NULL) {
+		len = pos;
+		if (len + 1 < base_size)
+			len = base_size - 1;
+		memcpy(base, fname, len);
+		base[len] = 0;
+	}
+	return pos;
+}
+
+static void change_case(char *p, int to_upper)
+{
+	for (; *p != 0; p++) {
+		if (to_upper && 'a' <= *p && *p <= 'z')
+			*p += 'A' - 'a';
+		else if (!to_upper && 'A' <= *p && *p <= 'Z')
+			*p += 'a' - 'A';
+	}
 }
 
+static int file_openable(const char *fname)
+{
+	FILE *f = fopen(fname, "rb");
+	if (f == NULL)
+		return 0;
+	fclose(f);
+	return 1;
+}
 
 #define BEGINS(buff,str) (strncmp(buff,str,sizeof(str)-1) == 0)
 
 /* note: tracks[0] is not used */
 cue_data_t *cue_parse(const char *fname)
 {
-	char buff[256], current_file[256], buff2[32], *current_filep;
-	FILE *f, *tmpf;
+	char current_file[256], *current_filep, cue_base[256];
+	char buff[256], buff2[32], ext[4], *p;
 	int ret, count = 0, count_alloc = 2, pending_pregap = 0;
-	cue_data_t *data;
+	size_t current_filep_size, fname_len;
+	cue_data_t *data = NULL;
+	FILE *f = NULL;
 	void *tmp;
 
-	f = fopen(fname, "r");
-	if (f == NULL) return NULL;
+	if (fname == NULL || (fname_len = strlen(fname)) == 0)
+		return NULL;
+
+	ret = get_ext(fname, ext, cue_base, sizeof(cue_base));
+	if (strcasecmp(ext, "cue") == 0) {
+		f = fopen(fname, "r");
+	}
+	else {
+		// not a .cue, try one with the same base name
+		if (ret + 3 < sizeof(cue_base)) {
+			strcpy(cue_base + ret, "cue");
+			f = fopen(cue_base, "r");
+			if (f == NULL) {
+				strcpy(cue_base + ret, "CUE");
+				f = fopen(cue_base, "r");
+			}
+		}
+	}
+
+	if (f == NULL)
+		return NULL;
 
 	snprintf(current_file, sizeof(current_file), "%s", fname);
-	for (current_filep = current_file + strlen(current_file); current_filep > current_file; current_filep--)
-		if (current_filep[-1] == '/' || current_filep[-1] == '\\') break;
+	current_filep = current_file + strlen(current_file);
+	for (; current_filep > current_file; current_filep--)
+		if (current_filep[-1] == '/' || current_filep[-1] == '\\')
+			break;
+
+	current_filep_size = sizeof(current_file) - (current_filep - current_file);
+
+	// the basename of cuefile, no path
+	snprintf(cue_base, sizeof(cue_base), "%s", current_filep);
+	p = cue_base + strlen(cue_base);
+	if (p - 3 >= cue_base)
+		p[-3] = 0;
 
 	data = calloc(1, sizeof(*data) + count_alloc * sizeof(cue_track));
-	if (data == NULL) {
-		fclose(f);
-		return NULL;
-	}
+	if (data == NULL)
+		goto out;
 
 	while (!feof(f))
 	{
 		tmp = fgets(buff, sizeof(buff), f);
-		if (tmp == NULL) break;
+		if (tmp == NULL)
+			break;
 
 		mystrip(buff);
-		if (buff[0] == 0) continue;
+		if (buff[0] == 0)
+			continue;
 		if      (BEGINS(buff, "TITLE ") || BEGINS(buff, "PERFORMER ") || BEGINS(buff, "SONGWRITER "))
 			continue;	/* who would put those here? Ignore! */
 		else if (BEGINS(buff, "FILE "))
 		{
-			get_token(buff+5, current_filep, sizeof(current_file) - (current_filep - current_file));
+			get_token(buff + 5, current_filep, current_filep_size);
 		}
 		else if (BEGINS(buff, "TRACK "))
 		{
@@ -112,21 +176,48 @@ cue_data_t *cue_parse(const char *fname)
 			if (count >= count_alloc) {
 				count_alloc *= 2;
 				tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cue_track));
-				if (tmp == NULL) { count--; break; }
+				if (tmp == NULL) {
+					count--;
+					break;
+				}
 				data = tmp;
 			}
 			memset(&data->tracks[count], 0, sizeof(data->tracks[0]));
+
 			if (count == 1 || strcmp(data->tracks[1].fname, current_file) != 0)
 			{
-				data->tracks[count].fname = strdup(current_file);
-				if (data->tracks[count].fname == NULL) break;
-
-				tmpf = fopen(current_file, "rb");
-				if (tmpf == NULL) {
-					elprintf(EL_STATUS, "cue: bad/missing file: \"%s\"", current_file);
-					count--; break;
+				if (file_openable(current_file))
+					goto file_ok;
+
+				elprintf(EL_STATUS, "cue: bad/missing file: \"%s\"", current_file);
+				if (count == 1) {
+					int cue_ucase;
+					char v;
+
+					get_ext(current_file, ext, NULL, 0);
+					snprintf(current_filep, current_filep_size,
+						"%s%s", cue_base, ext);
+					if (file_openable(current_file))
+						goto file_ok;
+
+					// try with the same case (for unix)
+					v = fname[fname_len - 1];
+					cue_ucase = ('A' <= v && v <= 'Z');
+					change_case(ext, cue_ucase);
+
+					snprintf(current_filep, current_filep_size,
+						"%s%s", cue_base, ext);
+					if (file_openable(current_file))
+						goto file_ok;
 				}
-				fclose(tmpf);
+
+				count--;
+				break;
+
+file_ok:
+				data->tracks[count].fname = strdup(current_file);
+				if (data->tracks[count].fname == NULL)
+					break;
 			}
 			data->tracks[count].pregap = pending_pregap;
 			pending_pregap = 0;
@@ -146,7 +237,7 @@ cue_data_t *cue_parse(const char *fname)
 				if (data->tracks[count].fname != NULL)
 				{
 					// rely on extension, not type in cue..
-					char *ext = get_ext(data->tracks[count].fname);
+					get_ext(data->tracks[count].fname, ext, NULL, 0);
 					if      (strcasecmp(ext, "mp3") == 0)
 						data->tracks[count].type = CT_MP3;
 					else if (strcasecmp(ext, "wav") == 0)
@@ -233,10 +324,15 @@ cue_data_t *cue_parse(const char *fname)
 			if (data->tracks[count].fname != NULL)
 				free(data->tracks[count].fname);
 		free(data);
-		return NULL;
+		data = NULL;
+		goto out;
 	}
 
 	data->track_count = count;
+
+out:
+	if (f != NULL)
+		fclose(f);
 	return data;
 }
 

+ 9 - 8
pico/media.c

@@ -132,14 +132,15 @@ int PicoCdCheck(const char *fname_in, int *pregion)
   cue_track_type type = CT_UNKNOWN;
   cue_data_t *cue_data = NULL;
 
-  get_ext(fname_in, ext);
-  if (strcasecmp(ext, ".cue") == 0) {
-    cue_data = cue_parse(fname_in);
-    if (cue_data != NULL) {
-      fname = cue_data->tracks[1].fname;
-      type  = cue_data->tracks[1].type;
-    }
-    else
+  // opens a cue, or searches for one
+  cue_data = cue_parse(fname_in);
+  if (cue_data != NULL) {
+    fname = cue_data->tracks[1].fname;
+    type  = cue_data->tracks[1].type;
+  }
+  else {
+    get_ext(fname_in, ext);
+    if (strcasecmp(ext, ".cue") == 0)
       return -1;
   }
 

+ 4 - 3
pico/sound/sound.c

@@ -12,6 +12,7 @@
 #include "sn76496.h"
 #include "../pico_int.h"
 #include "../cd/pcm.h"
+#include "../cd/cue.h"
 #include "mix.h"
 
 #define SIMPLE_WRITE_SOUND 0
@@ -260,7 +261,7 @@ PICO_INTERNAL void cdda_start_play(void)
     return;
   }
 
-  if (Pico_mcd->TOC.Tracks[i].ftype == TYPE_MP3)
+  if (Pico_mcd->TOC.Tracks[i].ftype == CT_MP3)
   {
     int pos1024 = 0;
 
@@ -280,7 +281,7 @@ PICO_INTERNAL void cdda_start_play(void)
   cdda_stream = Pico_mcd->TOC.Tracks[i].F;
   PicoCDBufferFlush(); // buffering relies on fp not being touched
   pm_seek(cdda_stream, lba_offset * 2352, SEEK_SET);
-  if (Pico_mcd->TOC.Tracks[i].ftype == TYPE_WAV)
+  if (Pico_mcd->TOC.Tracks[i].ftype == CT_WAV)
   {
     // skip headers, assume it's 44kHz stereo uncompressed
     pm_seek(cdda_stream, 44, SEEK_CUR);
@@ -358,7 +359,7 @@ static int PsndRender(int offset, int length)
     // note: only 44, 22 and 11 kHz supported, with forced stereo
     int index = Pico_mcd->scd.Cur_Track - 1;
 
-    if (Pico_mcd->TOC.Tracks[index].ftype == TYPE_MP3)
+    if (Pico_mcd->TOC.Tracks[index].ftype == CT_MP3)
       mp3_update(buf32, length, stereo);
     else
       cdda_raw_update(buf32, length);