improve cue handling a bit

This commit is contained in:
notaz 2013-09-08 00:35:09 +03:00
parent c7fd7bb8b7
commit e71fae1f13
7 changed files with 156 additions and 62 deletions

View file

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

View file

@ -59,7 +59,7 @@ static int audio_track_mp3(const char *fname, int index)
Tracks[index].F = tmp_file; Tracks[index].F = tmp_file;
// MP3 File // MP3 File
Tracks[index].ftype = TYPE_MP3; Tracks[index].ftype = CT_MP3;
fs *= 75; fs *= 75;
fs /= Tracks[index].KBtps * 1000; fs /= Tracks[index].KBtps * 1000;
Tracks[index].Length = fs; 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) 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; _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; cue_data_t *cue_data = NULL;
pm_file *pmf; pm_file *pmf;
static const char *exts[] = { 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(); Unload_ISO();
/* is this .cue? */ /* is this a .cue? */
ret = strlen(cd_img_name); cue_data = cue_parse(cd_img_name);
if (ret >= 3 && strcasecmp(cd_img_name + ret - 3, "cue") == 0) if (cue_data != NULL) {
cue_data = cue_parse(cd_img_name);
if (cue_data != NULL)
cd_img_name = cue_data->tracks[1].fname; cd_img_name = cue_data->tracks[1].fname;
Tracks[0].ftype = cue_data->tracks[1].type;
Tracks[0].ftype = type == CIT_BIN ? TYPE_BIN : TYPE_ISO; }
else
Tracks[0].ftype = type == CIT_BIN ? CT_BIN : CT_ISO;
Tracks[0].F = pmf = pm_open(cd_img_name); Tracks[0].F = pmf = pm_open(cd_img_name);
if (Tracks[0].F == NULL) 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; return -1;
} }
if (Tracks[0].ftype == TYPE_ISO) if (Tracks[0].ftype == CT_ISO)
cd_img_sectors = pmf->size >>= 11; // size in sectors cd_img_sectors = pmf->size >>= 11; // size in sectors
else cd_img_sectors = pmf->size /= 2352; else cd_img_sectors = pmf->size /= 2352;
Tracks[0].Offset = 0; 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.S = 2; // seconds
Tracks[0].MSF.F = 0; // frames Tracks[0].MSF.F = 0; // frames
elprintf(EL_STATUS, "Track 1: %02d:%02d:%02d %9i DATA", 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); 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; 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); LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
Cur_LBA += Tracks[index].Length; 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, Tracks[index].MSF.S, Tracks[index].MSF.F, Tracks[index].Length,
cue_data->tracks[num_track].fname); 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].F != NULL)
{ {
if (Pico_mcd->TOC.Tracks[i].ftype == TYPE_MP3) if (Pico_mcd->TOC.Tracks[i].ftype == CT_MP3)
#ifdef _PSP_FW_VERSION #ifdef _PSP_FW_VERSION
free(Pico_mcd->TOC.Tracks[i].F); free(Pico_mcd->TOC.Tracks[i].F);
#else #else

View file

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

View file

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

View file

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

View file

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

View file

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