improve cue handling a bit
authornotaz <notasas@gmail.com>
Sat, 7 Sep 2013 21:35:09 +0000 (00:35 +0300)
committernotaz <notasas@gmail.com>
Sun, 8 Sep 2013 17:27:41 +0000 (20:27 +0300)
pico/cd/buffering.c
pico/cd/cd_file.c
pico/cd/cd_file.h
pico/cd/cd_sys.h
pico/cd/cue.c
pico/media.c
pico/sound/sound.c

index 25f54ff..8420336 100644 (file)
@@ -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)
        {
index 4e2446c..0f19b71 100644 (file)
@@ -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
index f8fbb39..f9bb8ea 100644 (file)
@@ -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,
index fcac1d8..6291c2c 100644 (file)
@@ -39,11 +39,9 @@ typedef struct
 \r
 typedef struct\r
 {\r
-//     unsigned char Type; // always 1 (data) for 1st track, 0 (audio) for others\r
-//     unsigned char Num; // unused\r
        _msf MSF;\r
        //\r
-       char ftype; // TYPE_ISO, TYPE_BIN, TYPE_MP3\r
+       char ftype; // cue_track_type\r
        void *F;\r
        int Length;\r
        int Offset;  // sector offset, when single file is used for multiple virtual tracks\r
index 2b92bee..a038ccf 100644 (file)
@@ -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;
 }
 
index c03846d..597a43c 100644 (file)
@@ -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;
   }
 
index ede33f1..236a483 100644 (file)
@@ -12,6 +12,7 @@
 #include "sn76496.h"\r
 #include "../pico_int.h"\r
 #include "../cd/pcm.h"\r
+#include "../cd/cue.h"\r
 #include "mix.h"\r
 \r
 #define SIMPLE_WRITE_SOUND 0\r
@@ -260,7 +261,7 @@ PICO_INTERNAL void cdda_start_play(void)
     return;\r
   }\r
 \r
-  if (Pico_mcd->TOC.Tracks[i].ftype == TYPE_MP3)\r
+  if (Pico_mcd->TOC.Tracks[i].ftype == CT_MP3)\r
   {\r
     int pos1024 = 0;\r
 \r
@@ -280,7 +281,7 @@ PICO_INTERNAL void cdda_start_play(void)
   cdda_stream = Pico_mcd->TOC.Tracks[i].F;\r
   PicoCDBufferFlush(); // buffering relies on fp not being touched\r
   pm_seek(cdda_stream, lba_offset * 2352, SEEK_SET);\r
-  if (Pico_mcd->TOC.Tracks[i].ftype == TYPE_WAV)\r
+  if (Pico_mcd->TOC.Tracks[i].ftype == CT_WAV)\r
   {\r
     // skip headers, assume it's 44kHz stereo uncompressed\r
     pm_seek(cdda_stream, 44, SEEK_CUR);\r
@@ -358,7 +359,7 @@ static int PsndRender(int offset, int length)
     // note: only 44, 22 and 11 kHz supported, with forced stereo\r
     int index = Pico_mcd->scd.Cur_Track - 1;\r
 \r
-    if (Pico_mcd->TOC.Tracks[index].ftype == TYPE_MP3)\r
+    if (Pico_mcd->TOC.Tracks[index].ftype == CT_MP3)\r
       mp3_update(buf32, length, stereo);\r
     else\r
       cdda_raw_update(buf32, length);\r