core, groundwork for chd support

still needs some scrutiny, and build integration is missing
This commit is contained in:
kub 2021-03-04 20:48:02 +01:00
parent 4da84f9454
commit 15ca715228
18 changed files with 411 additions and 100 deletions

View file

@ -236,6 +236,11 @@ OBJS += platform/common/mp3_minimp3.o
endif endif
endif endif
ifneq (,$(HAVE_LIBCHDR))
CFLAGS += -DUSE_LIBCHDR -Iplatform/common/libchdr/include
LDFLAGS += -Lplatform/common/libchdr -lchdr
endif
ifeq "$(PLATFORM_ZLIB)" "1" ifeq "$(PLATFORM_ZLIB)" "1"
# zlib # zlib
OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \ OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \

View file

@ -564,6 +564,8 @@ asm_32xdraw = 0
asm_32xmemory = 0 asm_32xmemory = 0
endif endif
#HAVE_LIBCHDR = 1
CFLAGS += $(fpic) CFLAGS += $(fpic)
ifeq ($(findstring Haiku,$(shell uname -a)),) ifeq ($(findstring Haiku,$(shell uname -a)),)

View file

@ -16,6 +16,11 @@
#include "file_stream_transforms.h" #include "file_stream_transforms.h"
#endif #endif
#if defined(USE_LIBCHDR)
#include "libchdr/chd.h"
#include "libchdr/cdrom.h"
#endif
static int rom_alloc_size; static int rom_alloc_size;
static const char *rom_exts[] = { "bin", "gen", "smd", "iso", "sms", "gg", "sg" }; static const char *rom_exts[] = { "bin", "gen", "smd", "iso", "sms", "gg", "sg" };
@ -102,6 +107,19 @@ struct zip_file {
unsigned int pos; unsigned int pos;
}; };
#if defined(USE_LIBCHDR)
struct chd_struct {
pm_file file;
int fpos;
int sectorsize;
chd_file *chd;
int unitbytes;
int hunkunits;
u8 *hunk;
int hunknum;
};
#endif
pm_file *pm_open(const char *path) pm_file *pm_open(const char *path)
{ {
pm_file *file = NULL; pm_file *file = NULL;
@ -228,6 +246,50 @@ cso_failed:
if (f != NULL) fclose(f); if (f != NULL) fclose(f);
return NULL; return NULL;
} }
#if defined(USE_LIBCHDR)
else if (strcasecmp(ext, "chd") == 0)
{
struct chd_struct *chd = NULL;
chd_file *cf = NULL;
const chd_header *head;
if (chd_open(path, CHD_OPEN_READ, NULL, &cf) != CHDERR_NONE)
goto chd_failed;
// sanity check
head = chd_get_header(cf);
if ((head->hunkbytes == 0) || (head->hunkbytes % CD_FRAME_SIZE))
goto chd_failed;
chd = calloc(1, sizeof(*chd));
if (chd == NULL)
goto chd_failed;
chd->hunk = (u8 *)malloc(head->hunkbytes);
if (!chd->hunk)
goto chd_failed;
chd->chd = cf;
chd->unitbytes = head->unitbytes;
chd->hunkunits = head->hunkbytes / head->unitbytes;
chd->sectorsize = CD_MAX_SECTOR_DATA; // default to RAW mode
chd->fpos = 0;
chd->hunknum = -1;
chd->file.file = chd;
chd->file.type = PMT_CHD;
// subchannel data is skipped, remove it from total size
chd->file.size = chd_get_header(cf)->logicalbytes / CD_FRAME_SIZE * CD_MAX_SECTOR_DATA;
strncpy(chd->file.ext, ext, sizeof(chd->file.ext) - 1);
return &chd->file;
chd_failed:
/* invalid CHD file */
if (chd != NULL) free(chd);
if (cf != NULL) chd_close(cf);
return NULL;
}
#endif
/* not a zip, treat as uncompressed file */ /* not a zip, treat as uncompressed file */
f = fopen(path, "rb"); f = fopen(path, "rb");
@ -255,6 +317,88 @@ cso_failed:
return file; return file;
} }
void pm_sectorsize(int length, pm_file *stream)
{
// CHD reading needs to know how much binary data is in one data sector(=unit)
#if defined(USE_LIBCHDR)
if (stream->type == PMT_CHD) {
struct chd_struct *chd = stream->file;
chd->sectorsize = length;
if (chd->sectorsize > chd->unitbytes)
elprintf(EL_STATUS|EL_ANOMALY, "cd: sector size %d too large for unit %d", chd->sectorsize, chd->unitbytes);
}
#endif
}
#if defined(USE_LIBCHDR)
static size_t _pm_read_chd(void *ptr, size_t bytes, pm_file *stream, int is_audio)
{
int ret = 0;
if (stream->type == PMT_CHD) {
struct chd_struct *chd = stream->file;
// calculate sector and offset in sector
int sectsz = is_audio ? CD_MAX_SECTOR_DATA : chd->sectorsize;
int sector = chd->fpos / sectsz;
int offset = chd->fpos - (sector * sectsz);
// calculate hunk and sector offset in hunk
int hunknum = sector / chd->hunkunits;
int hunksec = sector - (hunknum * chd->hunkunits);
int hunkofs = hunksec * chd->unitbytes;
while (bytes != 0) {
// data left in current sector
int len = sectsz - offset;
// update hunk cache if needed
if (hunknum != chd->hunknum) {
chd_read(chd->chd, hunknum, chd->hunk);
chd->hunknum = hunknum;
}
if (len > bytes)
len = bytes;
#ifdef CPU_IS_LE
if (is_audio) {
// convert big endian audio samples
u16 *dst = ptr, v;
u8 *src = chd->hunk + hunkofs + offset;
int i;
for (i = 0; i < len; i += 4) {
v = *src++ << 8; *dst++ = v | *src++;
v = *src++ << 8; *dst++ = v | *src++;
}
} else
#endif
memcpy(ptr, chd->hunk + hunkofs + offset, len);
// house keeping
ret += len;
chd->fpos += len;
bytes -= len;
// no need to advance internals if there's no more data to read
if (bytes) {
ptr += len;
offset = 0;
sector ++;
hunksec ++;
hunkofs += chd->unitbytes;
if (hunksec >= chd->hunkunits) {
hunksec = 0;
hunkofs = 0;
hunknum ++;
}
}
}
}
return ret;
}
#endif
size_t pm_read(void *ptr, size_t bytes, pm_file *stream) size_t pm_read(void *ptr, size_t bytes, pm_file *stream)
{ {
int ret; int ret;
@ -355,12 +499,46 @@ size_t pm_read(void *ptr, size_t bytes, pm_file *stream)
index_end = cso->index[block+1]; index_end = cso->index[block+1];
} }
} }
#if defined(USE_LIBCHDR)
else if (stream->type == PMT_CHD)
{
ret = _pm_read_chd(ptr, bytes, stream, 0);
}
#endif
else else
ret = 0; ret = 0;
return ret; return ret;
} }
size_t pm_read_audio(void *ptr, size_t bytes, pm_file *stream)
{
#if !(CPU_IS_LE)
if (stream->type == PMT_UNCOMPRESSED)
{
// convert little endian audio samples from WAV file
int ret = pm_read(ptr, bytes, stream);
u16 *dst = ptr, v;
u8 *src = ptr;
int i;
for (i = 0; i < ret; i += 4) {
v = *src++; *dst++ = v | (*src++ << 8);
v = *src++; *dst++ = v | (*src++ << 8);
}
return ret;
}
else
#endif
#if defined(USE_LIBCHDR)
if (stream->type == PMT_CHD)
{
return _pm_read_chd(ptr, bytes, stream, 1);
}
#endif
return pm_read(ptr, bytes, stream);
}
int pm_seek(pm_file *stream, long offset, int whence) int pm_seek(pm_file *stream, long offset, int whence)
{ {
if (stream->type == PMT_UNCOMPRESSED) if (stream->type == PMT_UNCOMPRESSED)
@ -421,6 +599,19 @@ int pm_seek(pm_file *stream, long offset, int whence)
} }
return cso->fpos_out; return cso->fpos_out;
} }
#if defined(USE_LIBCHDR)
else if (stream->type == PMT_CHD)
{
struct chd_struct *chd = stream->file;
switch (whence)
{
case SEEK_CUR: chd->fpos += offset; break;
case SEEK_SET: chd->fpos = offset; break;
case SEEK_END: chd->fpos = stream->size - offset; break;
}
return chd->fpos;
}
#endif
else else
return -1; return -1;
} }
@ -446,6 +637,15 @@ int pm_close(pm_file *fp)
free(fp->param); free(fp->param);
fclose(fp->file); fclose(fp->file);
} }
#if defined(USE_LIBCHDR)
else if (fp->type == PMT_CHD)
{
struct chd_struct *chd = fp->file;
chd_close(chd->chd);
if (chd->hunk)
free(chd->hunk);
}
#endif
else else
ret = EOF; ret = EOF;

View file

@ -9,7 +9,7 @@
#include "../pico_int.h" #include "../pico_int.h"
#include "genplus_macros.h" #include "genplus_macros.h"
#include "cdd.h" #include "cdd.h"
#include "cue.h" #include "cd_parse.h"
#ifdef USE_LIBRETRO_VFS #ifdef USE_LIBRETRO_VFS
#include "file_stream_transforms.h" #include "file_stream_transforms.h"
@ -90,7 +90,7 @@ int load_cd_image(const char *cd_img_name, int *type)
int iso_name_len, missed, cd_img_sectors; int iso_name_len, missed, cd_img_sectors;
char tmp_name[256], tmp_ext[10], tmp_ext_u[10]; char tmp_name[256], tmp_ext[10], tmp_ext_u[10];
track_t *tracks = cdd.toc.tracks; track_t *tracks = cdd.toc.tracks;
cue_data_t *cue_data = NULL; cd_data_t *cue_data = NULL;
pm_file *pmf; pm_file *pmf;
if (PicoCDLoadProgressCB != NULL) if (PicoCDLoadProgressCB != NULL)
@ -103,16 +103,21 @@ int load_cd_image(const char *cd_img_name, int *type)
if (cue_data != NULL) { if (cue_data != NULL) {
cd_img_name = cue_data->tracks[1].fname; cd_img_name = cue_data->tracks[1].fname;
*type = cue_data->tracks[1].type; *type = cue_data->tracks[1].type;
} else {
cue_data = chd_parse(cd_img_name);
if (cue_data != NULL)
*type = cue_data->tracks[1].type;
} }
pmf = pm_open(cd_img_name); pmf = pm_open(cd_img_name);
if (pmf == NULL) if (pmf == NULL)
{ {
if (cue_data != NULL) if (cue_data != NULL)
cue_destroy(cue_data); cdparse_destroy(cue_data);
return -1; return -1;
} }
tracks[0].fd = pmf; tracks[0].fd = pmf;
tracks[0].fname = strdup(cd_img_name);
if (*type == CT_ISO) if (*type == CT_ISO)
cd_img_sectors = pmf->size >>= 11; // size in sectors cd_img_sectors = pmf->size >>= 11; // size in sectors
@ -131,7 +136,7 @@ int load_cd_image(const char *cd_img_name, int *type)
if (cue_data != NULL) if (cue_data != NULL)
{ {
if (cue_data->tracks[2].fname == NULL) { if (cue_data->track_count > 1 && cue_data->tracks[2].fname == NULL) {
// NULL fname means track2 is in same file as track1 // NULL fname means track2 is in same file as track1
lba = tracks[0].end = cue_data->tracks[2].sector_offset; lba = tracks[0].end = cue_data->tracks[2].sector_offset;
} }
@ -157,6 +162,7 @@ int load_cd_image(const char *cd_img_name, int *type)
{ {
// assume raw, ignore header for wav.. // assume raw, ignore header for wav..
tracks[index].fd = f; tracks[index].fd = f;
tracks[index].fname = strdup(cue_data->tracks[n].fname);
tracks[index].offset = cue_data->tracks[n].sector_offset; tracks[index].offset = cue_data->tracks[n].sector_offset;
length = f->size / 2352; length = f->size / 2352;
} }
@ -189,8 +195,8 @@ int load_cd_image(const char *cd_img_name, int *type)
tracks[index].end = lba; tracks[index].end = lba;
sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start); sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s", elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s", n, tmp_ext, length,
n, tmp_ext, length, cue_data->tracks[n].fname); cue_data->tracks[n].fname ? cue_data->tracks[n].fname : "");
} }
goto finish; goto finish;
} }
@ -269,7 +275,7 @@ finish:
PicoCDLoadProgressCB(cd_img_name, 100); PicoCDLoadProgressCB(cd_img_name, 100);
if (cue_data != NULL) if (cue_data != NULL)
cue_destroy(cue_data); cdparse_destroy(cue_data);
return 0; return 0;
} }

View file

@ -8,15 +8,20 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "cue.h"
#include "../pico_int.h" #include "../pico_int.h"
#include "cd_parse.h"
// #define elprintf(w,f,...) printf(f "\n",##__VA_ARGS__); // #define elprintf(w,f,...) printf(f "\n",##__VA_ARGS__);
#ifdef USE_LIBRETRO_VFS #ifdef USE_LIBRETRO_VFS
#include "file_stream_transforms.h" #include "file_stream_transforms.h"
#endif #endif
#if defined(USE_LIBCHDR)
#include "libchdr/chd.h"
#include "libchdr/cdrom.h"
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
@ -75,7 +80,8 @@ static int get_ext(const char *fname, char ext[4],
if (len > 0) if (len > 0)
pos = len; pos = len;
strcpy(ext, fname + pos + 1); strncpy(ext, fname + pos + 1, 4/*sizeof(ext)*/-1);
ext[4/*sizeof(ext)*/-1] = '\0';
if (base != NULL) { if (base != NULL) {
if (pos + 1 < base_size) if (pos + 1 < base_size)
@ -111,15 +117,110 @@ static int file_openable(const char *fname)
#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) cd_data_t *chd_parse(const char *fname)
{
cd_data_t *data = NULL;
#if defined(USE_LIBCHDR)
cd_data_t *tmp;
int count = 0, count_alloc = 2;
int sectors = 0;
char metadata[256];
chd_file *cf = NULL;
if (fname == NULL || *fname == '\0')
return NULL;
if (chd_open(fname, CHD_OPEN_READ, NULL, &cf) != CHDERR_NONE)
goto out;
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (data == NULL)
goto out;
// get track info
while (count < CD_MAX_TRACKS) {
int track = 0, frames = 0, pregap = 0, postgap = 0;
char type[16], subtype[16], pgtype[16], pgsub[16];
type[0] = subtype[0] = pgtype[0] = pgsub[0] = 0;
// get metadata for track
if (chd_get_metadata(cf, CDROM_TRACK_METADATA2_TAG, count,
metadata, sizeof(metadata), 0, 0, 0) == CHDERR_NONE) {
if (sscanf(metadata, CDROM_TRACK_METADATA2_FORMAT,
&track, &type[0], &subtype[0], &frames,
&pregap, &pgtype[0], &pgsub[0], &postgap) != 8)
break;
}
else if (chd_get_metadata(cf, CDROM_TRACK_METADATA_TAG, count,
metadata, sizeof(metadata), 0, 0, 0) == CHDERR_NONE) {
if (sscanf(metadata, CDROM_TRACK_METADATA_FORMAT,
&track, &type[0], &subtype[0], &frames) != 4)
break;
}
else break; // all tracks completed
// metadata sanity check
if (track != count + 1 || frames < 0 || pregap < 0)
break;
// allocate track structure
count ++;
if (count >= count_alloc) {
count_alloc *= 2;
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (tmp == NULL) {
count--;
break;
}
data = tmp;
}
memset(&data->tracks[count], 0, sizeof(data->tracks[0]));
if (count == 1) { // binary code
data->tracks[count].fname = strdup(fname);
if (!strcmp(type, "MODE1_RAW") || !strcmp(type, "MODE2_RAW")) {
data->tracks[count].type = CT_BIN;
} else if (!strcmp(type, "MODE1") || !strcmp(type, "MODE2_FORM1")) {
data->tracks[count].type = CT_ISO;
} else
break;
} else { // audio
if (strcmp(type, "AUDIO"))
break;
data->tracks[count].type = CT_CHD;
}
data->tracks[count].pregap = pregap;
if (pgtype[0] != 'V') // VAUDIO includes pregap in file
pregap = 0;
data->tracks[count].sector_offset = sectors + pregap;
data->tracks[count].sector_xlength = frames - pregap;
sectors += (((frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING) * CD_TRACK_PADDING);
}
// check if image id OK, i.e. there are tracks, and length <= 80 min
if (count && sectors < (80*60*75)) {
data->track_count = count;
} else {
free(data);
data = NULL;
}
out:
if (cf)
chd_close(cf);
#endif
return data;
}
cd_data_t *cue_parse(const char *fname)
{ {
char current_file[256], *current_filep, cue_base[256]; char current_file[256], *current_filep, cue_base[256];
char buff[256], buff2[32], ext[4], *p; 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;
size_t current_filep_size, fname_len; size_t current_filep_size, fname_len;
cue_data_t *data = NULL; cd_data_t *data = NULL, *tmp;
FILE *f = NULL; FILE *f = NULL;
void *tmp;
if (fname == NULL || (fname_len = strlen(fname)) == 0) if (fname == NULL || (fname_len = strlen(fname)) == 0)
return NULL; return NULL;
@ -156,14 +257,13 @@ cue_data_t *cue_parse(const char *fname)
p = strrchr(cue_base, '.'); p = strrchr(cue_base, '.');
if (p) p[1] = '\0'; if (p) p[1] = '\0';
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cue_track)); data = calloc(1, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (data == NULL) if (data == NULL)
goto out; goto out;
while (!feof(f)) while (!feof(f))
{ {
tmp = fgets(buff, sizeof(buff), f); if (fgets(buff, sizeof(buff), f) == NULL)
if (tmp == NULL)
break; break;
mystrip(buff); mystrip(buff);
@ -180,7 +280,7 @@ cue_data_t *cue_parse(const char *fname)
count++; count++;
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(cd_track_t));
if (tmp == NULL) { if (tmp == NULL) {
count--; count--;
break; break;
@ -344,7 +444,7 @@ out:
} }
void cue_destroy(cue_data_t *data) void cdparse_destroy(cd_data_t *data)
{ {
int c; int c;
@ -360,7 +460,7 @@ void cue_destroy(cue_data_t *data)
#if 0 #if 0
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
cue_data_t *data = cue_parse(argv[1]); cd_data_t *data = cue_parse(argv[1]);
int c; int c;
if (data == NULL) return 1; if (data == NULL) return 1;
@ -370,7 +470,7 @@ int main(int argc, char *argv[])
data->tracks[c].sector_offset / (75*60), data->tracks[c].sector_offset / 75 % 60, data->tracks[c].sector_offset / (75*60), data->tracks[c].sector_offset / 75 % 60,
data->tracks[c].sector_offset % 75, data->tracks[c].pregap, data->tracks[c].fname); data->tracks[c].sector_offset % 75, data->tracks[c].pregap, data->tracks[c].fname);
cue_destroy(data); cdparse_destroy(data);
return 0; return 0;
} }

5
pico/cd/cd_parse.h Normal file
View file

@ -0,0 +1,5 @@
cd_data_t *chd_parse(const char *fname);
cd_data_t *cue_parse(const char *fname);
void cdparse_destroy(cd_data_t *data);

View file

@ -38,7 +38,7 @@
#include "../pico_int.h" #include "../pico_int.h"
#include "genplus_macros.h" #include "genplus_macros.h"
#include "cue.h" #include "cd_parse.h"
#include "cdd.h" #include "cdd.h"
#ifdef USE_LIBTREMOR #ifdef USE_LIBTREMOR
@ -321,6 +321,7 @@ int cdd_load(const char *filename, int type)
ret = (type == CT_BIN) ? 2352 : 2048; ret = (type == CT_BIN) ? 2352 : 2048;
if (ret != cdd.sectorSize) if (ret != cdd.sectorSize)
elprintf(EL_STATUS|EL_ANOMALY, "cd: type detection mismatch"); elprintf(EL_STATUS|EL_ANOMALY, "cd: type detection mismatch");
pm_sectorsize(cdd.sectorSize, cdd.toc.tracks[0].fd);
/* read CD image header + security code */ /* read CD image header + security code */
pm_read(header + 0x10, 0x200, cdd.toc.tracks[0].fd); pm_read(header + 0x10, 0x200, cdd.toc.tracks[0].fd);
@ -448,6 +449,9 @@ int cdd_unload(void)
{ {
pm_close(cdd.toc.tracks[0].fd); pm_close(cdd.toc.tracks[0].fd);
cdd.toc.tracks[0].fd = NULL; cdd.toc.tracks[0].fd = NULL;
if (cdd.toc.tracks[0].fname)
free(cdd.toc.tracks[0].fd);
cdd.toc.tracks[0].fname = NULL;
} }
for (i = 1; i < cdd.toc.last; i++) for (i = 1; i < cdd.toc.last; i++)
@ -466,7 +470,11 @@ int cdd_unload(void)
if (Pico_mcd->cdda_type == CT_MP3) if (Pico_mcd->cdda_type == CT_MP3)
fclose(cdd.toc.tracks[i].fd); fclose(cdd.toc.tracks[i].fd);
else else
pm_close(cdd.toc.tracks[0].fd); pm_close(cdd.toc.tracks[i].fd);
cdd.toc.tracks[i].fd = NULL;
if (cdd.toc.tracks[i].fname)
free(cdd.toc.tracks[i].fd);
cdd.toc.tracks[i].fname = NULL;
/* detect single file images */ /* detect single file images */
if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd) if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)

View file

@ -60,6 +60,7 @@
/* CD track */ /* CD track */
typedef struct typedef struct
{ {
char *fname;
void *fd; void *fd;
#ifdef USE_LIBTREMOR #ifdef USE_LIBTREMOR
OggVorbis_File vf; OggVorbis_File vf;

View file

@ -1,29 +0,0 @@
typedef enum
{
CT_UNKNOWN = 0,
CT_ISO = 1, /* 2048 B/sector */
CT_BIN = 2, /* 2352 B/sector */
CT_MP3 = 3,
CT_WAV = 4
} cue_track_type;
typedef struct
{
char *fname;
int pregap; /* pregap for current track */
int sector_offset; /* in current file */
int sector_xlength;
cue_track_type type;
} cue_track;
typedef struct
{
int track_count;
cue_track tracks[0];
} cue_data_t;
cue_data_t *cue_parse(const char *fname);
void cue_destroy(cue_data_t *data);

View file

@ -8,7 +8,7 @@
#include <string.h> #include <string.h>
#include "pico_int.h" #include "pico_int.h"
#include "cd/cue.h" #include "cd/cd_parse.h"
unsigned char media_id_header[0x100]; unsigned char media_id_header[0x100];
@ -49,7 +49,7 @@ static int detect_media(const char *fname)
return PM_BAD_DETECT; return PM_BAD_DETECT;
/* don't believe in extensions, except .cue */ /* don't believe in extensions, except .cue */
if (strcasecmp(ext, ".cue") == 0) if (strcasecmp(ext, ".cue") == 0 || strcasecmp(ext, ".chd") == 0)
return PM_CD; return PM_CD;
pmf = pm_open(fname); pmf = pm_open(fname);
@ -129,26 +129,31 @@ int PicoCdCheck(const char *fname_in, int *pregion)
pm_file *cd_f; pm_file *cd_f;
int region = 4; // 1: Japan, 4: US, 8: Europe int region = 4; // 1: Japan, 4: US, 8: Europe
char ext[5]; char ext[5];
cue_track_type type = CT_UNKNOWN; enum cd_track_type type = CT_UNKNOWN;
cue_data_t *cue_data = NULL; cd_data_t *cd_data = NULL;
// opens a cue, or searches for one // opens a cue, or searches for one
cue_data = cue_parse(fname_in); if (!cd_data && (cd_data = cue_parse(fname_in)) == NULL) {
if (cue_data != NULL) {
fname = cue_data->tracks[1].fname;
type = cue_data->tracks[1].type;
}
else {
get_ext(fname_in, ext); get_ext(fname_in, ext);
if (strcasecmp(ext, ".cue") == 0) if (strcasecmp(ext, ".cue") == 0)
return -1; return -1;
} }
// opens a chd
if (!cd_data && (cd_data = chd_parse(fname_in)) == NULL) {
get_ext(fname_in, ext);
if (strcasecmp(ext, ".chd") == 0)
return -1;
}
if (cd_data != NULL) {
// 1st track contains the code
fname = cd_data->tracks[1].fname;
type = cd_data->tracks[1].type;
}
cd_f = pm_open(fname); cd_f = pm_open(fname);
if (cue_data != NULL) cdparse_destroy(cd_data);
cue_destroy(cue_data); if (cd_f == NULL) return CT_UNKNOWN; // let the upper level handle this
if (cd_f == NULL) return 0; // let the upper level handle this
if (pm_read(buf, 32, cd_f) != 32) { if (pm_read(buf, 32, cd_f) != 32) {
pm_close(cd_f); pm_close(cd_f);
@ -198,7 +203,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
{ {
const char *rom_fname = filename; const char *rom_fname = filename;
enum media_type_e media_type; enum media_type_e media_type;
enum cd_img_type cd_img_type = CIT_NOT_CD; enum cd_track_type cd_img_type = CT_UNKNOWN;
unsigned char *rom_data = NULL; unsigned char *rom_data = NULL;
unsigned int rom_size = 0; unsigned int rom_size = 0;
pm_file *rom = NULL; pm_file *rom = NULL;
@ -219,7 +224,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
{ {
// check for MegaCD image // check for MegaCD image
cd_img_type = PicoCdCheck(filename, &cd_region); cd_img_type = PicoCdCheck(filename, &cd_region);
if ((int)cd_img_type >= 0 && cd_img_type != CIT_NOT_CD) if ((int)cd_img_type >= 0 && cd_img_type != CT_UNKNOWN)
{ {
// valid CD image, ask frontend for BIOS.. // valid CD image, ask frontend for BIOS..
rom_fname = NULL; rom_fname = NULL;
@ -290,7 +295,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
Pico.m.ncart_in = 0; Pico.m.ncart_in = 0;
// insert CD if it was detected // insert CD if it was detected
if (cd_img_type != CIT_NOT_CD) { if (cd_img_type != CT_UNKNOWN) {
ret = cdd_load(filename, cd_img_type); ret = cdd_load(filename, cd_img_type);
if (ret != 0) { if (ret != 0) {
PicoCartUnload(); PicoCartUnload();

View file

@ -161,7 +161,8 @@ typedef enum
{ {
PMT_UNCOMPRESSED = 0, PMT_UNCOMPRESSED = 0,
PMT_ZIP, PMT_ZIP,
PMT_CSO PMT_CSO,
PMT_CHD
} pm_type; } pm_type;
typedef struct typedef struct
{ {
@ -172,7 +173,9 @@ typedef struct
char ext[4]; char ext[4];
} pm_file; } pm_file;
pm_file *pm_open(const char *path); pm_file *pm_open(const char *path);
void pm_sectorsize(int length, pm_file *stream);
size_t pm_read(void *ptr, size_t bytes, pm_file *stream); size_t pm_read(void *ptr, size_t bytes, pm_file *stream);
size_t pm_read_audio(void *ptr, size_t bytes, pm_file *stream);
int pm_seek(pm_file *stream, long offset, int whence); int pm_seek(pm_file *stream, long offset, int whence);
int pm_close(pm_file *fp); int pm_close(pm_file *fp);
int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize,int is_sms); int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize,int is_sms);
@ -255,14 +258,34 @@ enum media_type_e {
PM_CD, PM_CD,
}; };
enum cd_img_type enum cd_track_type
{ {
CIT_NOT_CD = 0, CT_UNKNOWN = 0,
CIT_ISO, // data tracks
CIT_BIN, CT_ISO = 1, /* 2048 B/sector */
CIT_CUE CT_BIN = 2, /* 2352 B/sector */
// audio tracks
CT_MP3 = 3,
CT_WAV = 4,
CT_CHD = 5,
}; };
typedef struct
{
char *fname;
int pregap; /* pregap for current track */
int sector_offset; /* in current file */
int sector_xlength;
enum cd_track_type type;
} cd_track_t;
typedef struct
{
int track_count;
cd_track_t tracks[0];
} cd_data_t;
enum media_type_e PicoLoadMedia(const char *filename, enum media_type_e PicoLoadMedia(const char *filename,
const char *carthw_cfg_fname, const char *carthw_cfg_fname,
const char *(*get_bios_filename)(int *region, const char *cd_fname), const char *(*get_bios_filename)(int *region, const char *cd_fname),

View file

@ -11,7 +11,6 @@
#include "ym2612.h" #include "ym2612.h"
#include "sn76496.h" #include "sn76496.h"
#include "../pico_int.h" #include "../pico_int.h"
#include "../cd/cue.h"
#include "mix.h" #include "mix.h"
#include "emu2413/emu2413.h" #include "emu2413/emu2413.h"
@ -266,7 +265,7 @@ static void cdda_raw_update(int *buffer, int length)
if (PicoIn.sndRate < 22050 - 100) mult = 4; if (PicoIn.sndRate < 22050 - 100) mult = 4;
cdda_bytes *= mult; cdda_bytes *= mult;
ret = pm_read(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream); ret = pm_read_audio(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream);
if (ret < cdda_bytes) { if (ret < cdda_bytes) {
memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret); memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret);
Pico_mcd->cdda_stream = NULL; Pico_mcd->cdda_stream = NULL;

View file

@ -99,7 +99,7 @@ endif
# CD # CD
SRCS_COMMON += $(R)pico/cd/mcd.c $(R)pico/cd/memory.c $(R)pico/cd/sek.c \ SRCS_COMMON += $(R)pico/cd/mcd.c $(R)pico/cd/memory.c $(R)pico/cd/sek.c \
$(R)pico/cd/cdc.c $(R)pico/cd/cdd.c $(R)pico/cd/cd_image.c \ $(R)pico/cd/cdc.c $(R)pico/cd/cdd.c $(R)pico/cd/cd_image.c \
$(R)pico/cd/cue.c $(R)pico/cd/gfx.c $(R)pico/cd/gfx_dma.c \ $(R)pico/cd/cd_parse.c $(R)pico/cd/gfx.c $(R)pico/cd/gfx_dma.c \
$(R)pico/cd/misc.c $(R)pico/cd/pcm.c $(R)pico/cd/misc.c $(R)pico/cd/pcm.c
# 32X # 32X
ifneq "$(no_32x)" "1" ifneq "$(no_32x)" "1"

View file

@ -539,11 +539,11 @@ out:
int emu_swap_cd(const char *fname) int emu_swap_cd(const char *fname)
{ {
enum cd_img_type cd_type; enum cd_track_type cd_type;
int ret = -1; int ret = -1;
cd_type = PicoCdCheck(fname, NULL); cd_type = PicoCdCheck(fname, NULL);
if (cd_type != CIT_NOT_CD) if (cd_type != CT_UNKNOWN)
ret = cdd_load(fname, cd_type); ret = cdd_load(fname, cd_type);
if (ret != 0) { if (ret != 0) {
menu_update_msg("Load failed, invalid CD image?"); menu_update_msg("Load failed, invalid CD image?");

View file

@ -40,7 +40,7 @@
static const char *rom_exts[] = { static const char *rom_exts[] = {
"zip", "zip",
"bin", "smd", "gen", "md", "bin", "smd", "gen", "md",
"iso", "cso", "cue", "iso", "cso", "cue", "chd",
"32x", "32x",
"sms", "sms",
NULL NULL

View file

@ -1577,9 +1577,9 @@ int menu_loop_tray(void)
selfname = romsel_loop(curr_path); selfname = romsel_loop(curr_path);
if (selfname) { if (selfname) {
int ret = -1; int ret = -1;
cd_img_type cd_type; cd_track_type cd_type;
cd_type = emu_cdCheck(NULL, romFileName); cd_type = emu_cdCheck(NULL, romFileName);
if (cd_type != CIT_NOT_CD) if (cd_type >= 0 && cd_type != CT_UNKNOWN)
ret = Insert_CD(romFileName, cd_type); ret = Insert_CD(romFileName, cd_type);
if (ret != 0) { if (ret != 0) {
sprintf(menuErrorMsg, "Load failed, invalid CD image?"); sprintf(menuErrorMsg, "Load failed, invalid CD image?");

View file

@ -749,7 +749,7 @@ void retro_get_system_info(struct retro_system_info *info)
#define _GIT_VERSION "-" GIT_VERSION #define _GIT_VERSION "-" GIT_VERSION
#endif #endif
info->library_version = VERSION _GIT_VERSION; info->library_version = VERSION _GIT_VERSION;
info->valid_extensions = "bin|gen|smd|md|32x|cue|iso|sms"; info->valid_extensions = "bin|gen|smd|md|32x|cue|iso|chd|sms";
info->need_fullpath = true; info->need_fullpath = true;
} }
@ -1002,7 +1002,7 @@ static unsigned int disk_get_image_index(void)
static bool disk_set_image_index(unsigned int index) static bool disk_set_image_index(unsigned int index)
{ {
enum cd_img_type cd_type; enum cd_track_type cd_type;
int ret; int ret;
if (index >= sizeof(disks) / sizeof(disks[0])) if (index >= sizeof(disks) / sizeof(disks[0]))
@ -1024,7 +1024,7 @@ static bool disk_set_image_index(unsigned int index)
ret = -1; ret = -1;
cd_type = PicoCdCheck(disks[index].fname, NULL); cd_type = PicoCdCheck(disks[index].fname, NULL);
if (cd_type != CIT_NOT_CD) if (cd_type >= 0 && cd_type != CT_UNKNOWN)
ret = cdd_load(disks[index].fname, cd_type); ret = cdd_load(disks[index].fname, cd_type);
if (ret != 0) { if (ret != 0) {
if (log_cb) if (log_cb)

View file

@ -30,7 +30,6 @@
#include <pico/pico_int.h> #include <pico/pico_int.h>
#include <pico/cd/genplus_macros.h> #include <pico/cd/genplus_macros.h>
#include <pico/cd/cdd.h> #include <pico/cd/cdd.h>
#include <pico/cd/cue.h>
#define OSD_FPS_X 432 #define OSD_FPS_X 432
@ -744,23 +743,10 @@ void emu_handle_resume(void)
// reopen first CD track // reopen first CD track
if (cdd.toc.tracks[0].fd != NULL) if (cdd.toc.tracks[0].fd != NULL)
{ {
const char *fname = rom_fname_reload; lprintf("emu_HandleResume: reopen %s\n", cdd.toc.tracks[0].fname);
int len = strlen(rom_fname_reload);
cue_data_t *cue_data = NULL;
if (len > 4 && strcasecmp(fname + len - 4, ".cue") == 0)
{
cue_data = cue_parse(rom_fname_reload);
if (cue_data != NULL)
fname = cue_data->tracks[1].fname;
}
lprintf("emu_HandleResume: reopen %s\n", fname);
pm_close(cdd.toc.tracks[0].fd); pm_close(cdd.toc.tracks[0].fd);
cdd.toc.tracks[0].fd = pm_open(fname); cdd.toc.tracks[0].fd = pm_open(cdd.toc.tracks[0].fname);
lprintf("reopen %s\n", cdd.toc.tracks[0].fd != NULL ? "ok" : "failed"); lprintf("reopen %s\n", cdd.toc.tracks[0].fd != NULL ? "ok" : "failed");
if (cue_data != NULL) cue_destroy(cue_data);
} }
mp3_reopen_file(); mp3_reopen_file();