From e71fae1f13fa9cb16b435c18edb5e1505b18e592 Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 8 Sep 2013 00:35:09 +0300 Subject: [PATCH] improve cue handling a bit --- pico/cd/buffering.c | 3 +- pico/cd/cd_file.c | 32 +++++----- pico/cd/cd_file.h | 5 -- pico/cd/cd_sys.h | 4 +- pico/cd/cue.c | 152 ++++++++++++++++++++++++++++++++++++-------- pico/media.c | 17 ++--- pico/sound/sound.c | 7 +- 7 files changed, 157 insertions(+), 63 deletions(-) diff --git a/pico/cd/buffering.c b/pico/cd/buffering.c index 25f54ff..8420336 100644 --- a/pico/cd/buffering.c +++ b/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) { diff --git a/pico/cd/cd_file.c b/pico/cd/cd_file.c index 4e2446c..0f19b71 100644 --- a/pico/cd/cd_file.c +++ b/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 diff --git a/pico/cd/cd_file.h b/pico/cd/cd_file.h index f8fbb39..f9bb8ea 100644 --- a/pico/cd/cd_file.h +++ b/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, diff --git a/pico/cd/cd_sys.h b/pico/cd/cd_sys.h index fcac1d8..6291c2c 100644 --- a/pico/cd/cd_sys.h +++ b/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 diff --git a/pico/cd/cue.c b/pico/cd/cue.c index 2b92bee..a038ccf 100644 --- a/pico/cd/cue.c +++ b/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; } diff --git a/pico/media.c b/pico/media.c index c03846d..597a43c 100644 --- a/pico/media.c +++ b/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; } diff --git a/pico/sound/sound.c b/pico/sound/sound.c index ede33f1..236a483 100644 --- a/pico/sound/sound.c +++ b/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); -- 2.39.2