core, groundwork for chd support
authorkub <derkub@gmail.com>
Thu, 4 Mar 2021 19:48:02 +0000 (20:48 +0100)
committerkub <derkub@gmail.com>
Thu, 4 Mar 2021 19:54:10 +0000 (20:54 +0100)
still needs some scrutiny, and build integration is missing

18 files changed:
Makefile
Makefile.libretro
pico/cart.c
pico/cd/cd_image.c
pico/cd/cd_parse.c [moved from pico/cd/cue.c with 73% similarity]
pico/cd/cd_parse.h [new file with mode: 0644]
pico/cd/cdd.c
pico/cd/cdd.h
pico/cd/cue.h [deleted file]
pico/media.c
pico/pico.h
pico/sound/sound.c
platform/common/common.mak
platform/common/emu.c
platform/common/menu_pico.c
platform/gizmondo/menu.c
platform/libretro/libretro.c
platform/psp/emu.c

index 7955305..99bfc6a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -236,6 +236,11 @@ OBJS += platform/common/mp3_minimp3.o
 endif
 endif
 
+ifneq (,$(HAVE_LIBCHDR))
+CFLAGS += -DUSE_LIBCHDR -Iplatform/common/libchdr/include
+LDFLAGS += -Lplatform/common/libchdr -lchdr
+endif
+
 ifeq "$(PLATFORM_ZLIB)" "1"
 # zlib
 OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
index e1d4414..a7ef008 100644 (file)
@@ -564,6 +564,8 @@ asm_32xdraw = 0
 asm_32xmemory = 0
 endif
 
+#HAVE_LIBCHDR = 1
+
 CFLAGS += $(fpic)
 
 ifeq ($(findstring Haiku,$(shell uname -a)),)
index 9d35c04..702947c 100644 (file)
 #include "file_stream_transforms.h"\r
 #endif\r
 \r
+#if defined(USE_LIBCHDR)\r
+#include "libchdr/chd.h"\r
+#include "libchdr/cdrom.h"\r
+#endif\r
+\r
 static int rom_alloc_size;\r
 static const char *rom_exts[] = { "bin", "gen", "smd", "iso", "sms", "gg", "sg" };\r
 \r
@@ -102,6 +107,19 @@ struct zip_file {
   unsigned int pos;\r
 };\r
 \r
+#if defined(USE_LIBCHDR)\r
+struct chd_struct {\r
+  pm_file file;\r
+  int fpos;\r
+  int sectorsize;\r
+  chd_file *chd;\r
+  int unitbytes;\r
+  int hunkunits;\r
+  u8 *hunk;\r
+  int hunknum;\r
+};\r
+#endif\r
+\r
 pm_file *pm_open(const char *path)\r
 {\r
   pm_file *file = NULL;\r
@@ -228,6 +246,50 @@ cso_failed:
     if (f != NULL) fclose(f);\r
     return NULL;\r
   }\r
+#if defined(USE_LIBCHDR)\r
+  else if (strcasecmp(ext, "chd") == 0)\r
+  {\r
+    struct chd_struct *chd = NULL;\r
+    chd_file *cf = NULL;\r
+    const chd_header *head;\r
+\r
+    if (chd_open(path, CHD_OPEN_READ, NULL, &cf) != CHDERR_NONE)\r
+      goto chd_failed;\r
+\r
+    // sanity check\r
+    head = chd_get_header(cf);\r
+    if ((head->hunkbytes == 0) || (head->hunkbytes % CD_FRAME_SIZE))\r
+      goto chd_failed;\r
+\r
+    chd = calloc(1, sizeof(*chd));\r
+    if (chd == NULL)\r
+      goto chd_failed;\r
+    chd->hunk = (u8 *)malloc(head->hunkbytes);\r
+    if (!chd->hunk)\r
+      goto chd_failed;\r
+\r
+    chd->chd = cf;\r
+    chd->unitbytes = head->unitbytes;\r
+    chd->hunkunits = head->hunkbytes / head->unitbytes;\r
+    chd->sectorsize = CD_MAX_SECTOR_DATA; // default to RAW mode\r
+\r
+    chd->fpos = 0;\r
+    chd->hunknum = -1;\r
+\r
+    chd->file.file = chd;\r
+    chd->file.type = PMT_CHD;\r
+    // subchannel data is skipped, remove it from total size\r
+    chd->file.size = chd_get_header(cf)->logicalbytes / CD_FRAME_SIZE * CD_MAX_SECTOR_DATA;\r
+    strncpy(chd->file.ext, ext, sizeof(chd->file.ext) - 1);\r
+    return &chd->file;\r
+\r
+chd_failed:\r
+    /* invalid CHD file */\r
+    if (chd != NULL) free(chd);\r
+    if (cf != NULL) chd_close(cf);\r
+    return NULL;\r
+  }\r
+#endif\r
 \r
   /* not a zip, treat as uncompressed file */\r
   f = fopen(path, "rb");\r
@@ -255,6 +317,88 @@ cso_failed:
   return file;\r
 }\r
 \r
+void pm_sectorsize(int length, pm_file *stream)\r
+{\r
+  // CHD reading needs to know how much binary data is in one data sector(=unit)\r
+#if defined(USE_LIBCHDR)\r
+  if (stream->type == PMT_CHD) {\r
+    struct chd_struct *chd = stream->file;\r
+    chd->sectorsize = length;\r
+    if (chd->sectorsize > chd->unitbytes)\r
+      elprintf(EL_STATUS|EL_ANOMALY, "cd: sector size %d too large for unit %d", chd->sectorsize, chd->unitbytes);\r
+  }\r
+#endif\r
+}\r
+\r
+#if defined(USE_LIBCHDR)\r
+static size_t _pm_read_chd(void *ptr, size_t bytes, pm_file *stream, int is_audio)\r
+{\r
+  int ret = 0;\r
+\r
+  if (stream->type == PMT_CHD) {\r
+    struct chd_struct *chd = stream->file;\r
+    // calculate sector and offset in sector\r
+    int sectsz = is_audio ? CD_MAX_SECTOR_DATA : chd->sectorsize;\r
+    int sector = chd->fpos / sectsz;\r
+    int offset = chd->fpos - (sector * sectsz);\r
+    // calculate hunk and sector offset in hunk\r
+    int hunknum = sector / chd->hunkunits;\r
+    int hunksec = sector - (hunknum * chd->hunkunits);\r
+    int hunkofs = hunksec * chd->unitbytes;\r
+\r
+    while (bytes != 0) {\r
+      // data left in current sector\r
+      int len = sectsz - offset;\r
+\r
+      // update hunk cache if needed\r
+      if (hunknum != chd->hunknum) {\r
+        chd_read(chd->chd, hunknum, chd->hunk);\r
+        chd->hunknum = hunknum;\r
+      }\r
+      if (len > bytes)\r
+        len = bytes;\r
+\r
+#ifdef CPU_IS_LE\r
+      if (is_audio) {\r
+        // convert big endian audio samples\r
+        u16 *dst = ptr, v;\r
+        u8 *src = chd->hunk + hunkofs + offset;\r
+        int i;\r
+\r
+        for (i = 0; i < len; i += 4) {\r
+          v = *src++ << 8; *dst++ = v | *src++;\r
+          v = *src++ << 8; *dst++ = v | *src++;\r
+        }\r
+      } else\r
+#endif\r
+        memcpy(ptr, chd->hunk + hunkofs + offset, len);\r
+\r
+      // house keeping\r
+      ret += len;\r
+      chd->fpos += len;\r
+      bytes -= len;\r
+\r
+      // no need to advance internals if there's no more data to read\r
+      if (bytes) {\r
+        ptr += len;\r
+        offset = 0;\r
+\r
+        sector ++;\r
+        hunksec ++;\r
+        hunkofs += chd->unitbytes;\r
+        if (hunksec >= chd->hunkunits) {\r
+          hunksec = 0;\r
+          hunkofs = 0;\r
+          hunknum ++;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return ret;\r
+}\r
+#endif\r
+\r
 size_t pm_read(void *ptr, size_t bytes, pm_file *stream)\r
 {\r
   int ret;\r
@@ -355,12 +499,46 @@ size_t pm_read(void *ptr, size_t bytes, pm_file *stream)
       index_end = cso->index[block+1];\r
     }\r
   }\r
+#if defined(USE_LIBCHDR)\r
+  else if (stream->type == PMT_CHD)\r
+  {\r
+    ret = _pm_read_chd(ptr, bytes, stream, 0);\r
+  }\r
+#endif\r
   else\r
     ret = 0;\r
 \r
   return ret;\r
 }\r
 \r
+size_t pm_read_audio(void *ptr, size_t bytes, pm_file *stream)\r
+{\r
+#if !(CPU_IS_LE)\r
+  if (stream->type == PMT_UNCOMPRESSED)\r
+  {\r
+    // convert little endian audio samples from WAV file\r
+    int ret = pm_read(ptr, bytes, stream);\r
+    u16 *dst = ptr, v;\r
+    u8 *src = ptr;\r
+    int i;\r
+\r
+    for (i = 0; i < ret; i += 4) {\r
+      v = *src++; *dst++ = v | (*src++ << 8);\r
+      v = *src++; *dst++ = v | (*src++ << 8);\r
+    }\r
+    return ret;\r
+  }\r
+  else\r
+#endif\r
+#if defined(USE_LIBCHDR)\r
+  if (stream->type == PMT_CHD)\r
+  {\r
+    return _pm_read_chd(ptr, bytes, stream, 1);\r
+  }\r
+#endif\r
+  return pm_read(ptr, bytes, stream);\r
+}\r
+\r
 int pm_seek(pm_file *stream, long offset, int whence)\r
 {\r
   if (stream->type == PMT_UNCOMPRESSED)\r
@@ -421,6 +599,19 @@ int pm_seek(pm_file *stream, long offset, int whence)
     }\r
     return cso->fpos_out;\r
   }\r
+#if defined(USE_LIBCHDR)\r
+  else if (stream->type == PMT_CHD)\r
+  {\r
+    struct chd_struct *chd = stream->file;\r
+    switch (whence)\r
+    {\r
+      case SEEK_CUR: chd->fpos += offset; break;\r
+      case SEEK_SET: chd->fpos  = offset; break;\r
+      case SEEK_END: chd->fpos  = stream->size - offset; break;\r
+    }\r
+    return chd->fpos;\r
+  }\r
+#endif\r
   else\r
     return -1;\r
 }\r
@@ -446,6 +637,15 @@ int pm_close(pm_file *fp)
     free(fp->param);\r
     fclose(fp->file);\r
   }\r
+#if defined(USE_LIBCHDR)\r
+  else if (fp->type == PMT_CHD)\r
+  {\r
+    struct chd_struct *chd = fp->file;\r
+    chd_close(chd->chd);\r
+    if (chd->hunk)\r
+      free(chd->hunk);\r
+  }\r
+#endif\r
   else\r
     ret = EOF;\r
 \r
index f328be0..530071a 100644 (file)
@@ -9,7 +9,7 @@
 #include "../pico_int.h"
 #include "genplus_macros.h"
 #include "cdd.h"
-#include "cue.h"
+#include "cd_parse.h"
 
 #ifdef USE_LIBRETRO_VFS
 #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;
   char tmp_name[256], tmp_ext[10], tmp_ext_u[10];
   track_t *tracks = cdd.toc.tracks;
-  cue_data_t *cue_data = NULL;
+  cd_data_t *cue_data = NULL;
   pm_file *pmf;
 
   if (PicoCDLoadProgressCB != NULL)
@@ -103,16 +103,21 @@ int load_cd_image(const char *cd_img_name, int *type)
   if (cue_data != NULL) {
     cd_img_name = cue_data->tracks[1].fname;
     *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);
   if (pmf == NULL)
   {
     if (cue_data != NULL)
-      cue_destroy(cue_data);
+      cdparse_destroy(cue_data);
     return -1;
   }
   tracks[0].fd = pmf;
+  tracks[0].fname = strdup(cd_img_name);
 
   if (*type == CT_ISO)
        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->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
       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..
           tracks[index].fd = f;
+          tracks[index].fname = strdup(cue_data->tracks[n].fname);
           tracks[index].offset = cue_data->tracks[n].sector_offset;
           length = f->size / 2352;
         }
@@ -189,8 +195,8 @@ int load_cd_image(const char *cd_img_name, int *type)
       tracks[index].end = lba;
 
       sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
-      elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s",
-        n, tmp_ext, length, cue_data->tracks[n].fname);
+      elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s", n, tmp_ext, length,
+          cue_data->tracks[n].fname ? cue_data->tracks[n].fname : "");
     }
     goto finish;
   }
@@ -269,7 +275,7 @@ finish:
     PicoCDLoadProgressCB(cd_img_name, 100);
 
   if (cue_data != NULL)
-    cue_destroy(cue_data);
+    cdparse_destroy(cue_data);
 
   return 0;
 }
similarity index 73%
rename from pico/cd/cue.c
rename to pico/cd/cd_parse.c
index e8174ce..6ed6335 100644 (file)
@@ -8,15 +8,20 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include "cue.h"
 
 #include "../pico_int.h"
+#include "cd_parse.h"
 // #define elprintf(w,f,...) printf(f "\n",##__VA_ARGS__);
 
 #ifdef USE_LIBRETRO_VFS
 #include "file_stream_transforms.h"
 #endif
 
+#if defined(USE_LIBCHDR)
+#include "libchdr/chd.h"
+#include "libchdr/cdrom.h"
+#endif
+
 #ifdef _MSC_VER
 #define snprintf _snprintf
 #endif
@@ -75,7 +80,8 @@ static int get_ext(const char *fname, char ext[4],
        if (len > 0)
                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 (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)
 
 /* 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 buff[256], buff2[32], ext[4], *p;
        int ret, count = 0, count_alloc = 2, pending_pregap = 0;
        size_t current_filep_size, fname_len;
-       cue_data_t *data = NULL;
+       cd_data_t *data = NULL, *tmp;
        FILE *f = NULL;
-       void *tmp;
 
        if (fname == NULL || (fname_len = strlen(fname)) == 0)
                return NULL;
@@ -156,14 +257,13 @@ cue_data_t *cue_parse(const char *fname)
        p = strrchr(cue_base, '.');
        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)
                goto out;
 
        while (!feof(f))
        {
-               tmp = fgets(buff, sizeof(buff), f);
-               if (tmp == NULL)
+               if (fgets(buff, sizeof(buff), f) == NULL)
                        break;
 
                mystrip(buff);
@@ -180,7 +280,7 @@ cue_data_t *cue_parse(const char *fname)
                        count++;
                        if (count >= count_alloc) {
                                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) {
                                        count--;
                                        break;
@@ -344,7 +444,7 @@ out:
 }
 
 
-void cue_destroy(cue_data_t *data)
+void cdparse_destroy(cd_data_t *data)
 {
        int c;
 
@@ -360,7 +460,7 @@ void cue_destroy(cue_data_t *data)
 #if 0
 int main(int argc, char *argv[])
 {
-       cue_data_t *data = cue_parse(argv[1]);
+       cd_data_t *data = cue_parse(argv[1]);
        int c;
 
        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, data->tracks[c].pregap, data->tracks[c].fname);
 
-       cue_destroy(data);
+       cdparse_destroy(data);
 
        return 0;
 }
diff --git a/pico/cd/cd_parse.h b/pico/cd/cd_parse.h
new file mode 100644 (file)
index 0000000..0e1f59e
--- /dev/null
@@ -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);
+
index 81bc23b..8fa16e1 100644 (file)
@@ -38,7 +38,7 @@
 
 #include "../pico_int.h"
 #include "genplus_macros.h"
-#include "cue.h"
+#include "cd_parse.h"
 #include "cdd.h"
 
 #ifdef USE_LIBTREMOR
@@ -321,6 +321,7 @@ int cdd_load(const char *filename, int type)
   ret = (type == CT_BIN) ? 2352 : 2048;
   if (ret != cdd.sectorSize)
     elprintf(EL_STATUS|EL_ANOMALY, "cd: type detection mismatch");
+  pm_sectorsize(cdd.sectorSize, cdd.toc.tracks[0].fd);
 
   /* read CD image header + security code */
   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);
       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++)
@@ -466,7 +470,11 @@ int cdd_unload(void)
         if (Pico_mcd->cdda_type == CT_MP3)
           fclose(cdd.toc.tracks[i].fd);
         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 */
         if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)
index 4789cdb..da5b510 100644 (file)
@@ -60,6 +60,7 @@
 /* CD track */
 typedef struct
 {
+  char *fname;
   void *fd;
 #ifdef USE_LIBTREMOR
   OggVorbis_File vf;
diff --git a/pico/cd/cue.h b/pico/cd/cue.h
deleted file mode 100644 (file)
index 70ade53..0000000
+++ /dev/null
@@ -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);
-
index f9b053b..1294243 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <string.h>
 #include "pico_int.h"
-#include "cd/cue.h"
+#include "cd/cd_parse.h"
 
 unsigned char media_id_header[0x100];
 
@@ -49,7 +49,7 @@ static int detect_media(const char *fname)
     return PM_BAD_DETECT;
 
   /* don't believe in extensions, except .cue */
-  if (strcasecmp(ext, ".cue") == 0)
+  if (strcasecmp(ext, ".cue") == 0 || strcasecmp(ext, ".chd") == 0)
     return PM_CD;
 
   pmf = pm_open(fname);
@@ -129,26 +129,31 @@ int PicoCdCheck(const char *fname_in, int *pregion)
   pm_file *cd_f;
   int region = 4; // 1: Japan, 4: US, 8: Europe
   char ext[5];
-  cue_track_type type = CT_UNKNOWN;
-  cue_data_t *cue_data = NULL;
+  enum cd_track_type type = CT_UNKNOWN;
+  cd_data_t *cd_data = NULL;
 
   // 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 {
+  if (!cd_data && (cd_data = cue_parse(fname_in)) == NULL) {
     get_ext(fname_in, ext);
     if (strcasecmp(ext, ".cue") == 0)
       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;
+  }
 
-  cd_f = pm_open(fname);
-  if (cue_data != NULL)
-    cue_destroy(cue_data);
+  if (cd_data != NULL) {
+    // 1st track contains the code
+    fname = cd_data->tracks[1].fname;
+    type  = cd_data->tracks[1].type;
+  }
 
-  if (cd_f == NULL) return 0; // let the upper level handle this
+  cd_f = pm_open(fname);
+  cdparse_destroy(cd_data);
+  if (cd_f == NULL) return CT_UNKNOWN; // let the upper level handle this
 
   if (pm_read(buf, 32, cd_f) != 32) {
     pm_close(cd_f);
@@ -198,7 +203,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
 {
   const char *rom_fname = filename;
   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 int rom_size = 0;
   pm_file *rom = NULL;
@@ -219,7 +224,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
   {
     // check for MegaCD image
     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..
       rom_fname = NULL;
@@ -290,7 +295,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
   Pico.m.ncart_in = 0;
 
   // 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);
     if (ret != 0) {
       PicoCartUnload();
index b75a014..5ec67d4 100644 (file)
@@ -161,7 +161,8 @@ typedef enum
 {\r
        PMT_UNCOMPRESSED = 0,\r
        PMT_ZIP,\r
-       PMT_CSO\r
+       PMT_CSO,\r
+       PMT_CHD\r
 } pm_type;\r
 typedef struct\r
 {\r
@@ -172,7 +173,9 @@ typedef struct
        char ext[4];\r
 } pm_file;\r
 pm_file *pm_open(const char *path);\r
+void     pm_sectorsize(int length, pm_file *stream);\r
 size_t   pm_read(void *ptr, size_t bytes, pm_file *stream);\r
+size_t   pm_read_audio(void *ptr, size_t bytes, pm_file *stream);\r
 int      pm_seek(pm_file *stream, long offset, int whence);\r
 int      pm_close(pm_file *fp);\r
 int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize,int is_sms);\r
@@ -255,14 +258,34 @@ enum media_type_e {
   PM_CD,\r
 };\r
 \r
-enum cd_img_type\r
+enum cd_track_type\r
 {\r
-  CIT_NOT_CD = 0,\r
-  CIT_ISO,\r
-  CIT_BIN,\r
-  CIT_CUE\r
+  CT_UNKNOWN = 0,\r
+  // data tracks\r
+  CT_ISO = 1,  /* 2048 B/sector */\r
+  CT_BIN = 2,  /* 2352 B/sector */\r
+  // audio tracks\r
+  CT_MP3 = 3,\r
+  CT_WAV = 4,\r
+  CT_CHD = 5,\r
 };\r
 \r
+typedef struct\r
+{\r
+       char *fname;\r
+       int pregap;             /* pregap for current track */\r
+       int sector_offset;      /* in current file */\r
+       int sector_xlength;\r
+       enum cd_track_type type;\r
+} cd_track_t;\r
+\r
+typedef struct\r
+{\r
+       int track_count;\r
+       cd_track_t tracks[0];\r
+} cd_data_t;\r
+\r
+\r
 enum media_type_e PicoLoadMedia(const char *filename,\r
   const char *carthw_cfg_fname,\r
   const char *(*get_bios_filename)(int *region, const char *cd_fname),\r
index ad74868..0807c03 100644 (file)
@@ -11,7 +11,6 @@
 #include "ym2612.h"\r
 #include "sn76496.h"\r
 #include "../pico_int.h"\r
-#include "../cd/cue.h"\r
 #include "mix.h"\r
 #include "emu2413/emu2413.h"\r
 \r
@@ -266,7 +265,7 @@ static void cdda_raw_update(int *buffer, int length)
   if (PicoIn.sndRate <  22050 - 100) mult = 4;\r
   cdda_bytes *= mult;\r
 \r
-  ret = pm_read(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream);\r
+  ret = pm_read_audio(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream);\r
   if (ret < cdda_bytes) {\r
     memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret);\r
     Pico_mcd->cdda_stream = NULL;\r
index de1c3d7..0aabeab 100644 (file)
@@ -99,7 +99,7 @@ endif
 # CD
 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/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
 # 32X
 ifneq "$(no_32x)" "1"
index 089189d..151fb53 100644 (file)
@@ -539,11 +539,11 @@ out:
 \r
 int emu_swap_cd(const char *fname)\r
 {\r
-       enum cd_img_type cd_type;\r
+       enum cd_track_type cd_type;\r
        int ret = -1;\r
 \r
        cd_type = PicoCdCheck(fname, NULL);\r
-       if (cd_type != CIT_NOT_CD)\r
+       if (cd_type != CT_UNKNOWN)\r
                ret = cdd_load(fname, cd_type);\r
        if (ret != 0) {\r
                menu_update_msg("Load failed, invalid CD image?");\r
index 38adcc2..fc238c3 100644 (file)
@@ -40,7 +40,7 @@
 static const char *rom_exts[] = {
        "zip",
        "bin", "smd", "gen", "md",
-       "iso", "cso", "cue",
+       "iso", "cso", "cue", "chd",
        "32x",
        "sms",
        NULL
index 07a2ce7..cf1f5b4 100644 (file)
@@ -1577,9 +1577,9 @@ int menu_loop_tray(void)
                                        selfname = romsel_loop(curr_path);\r
                                        if (selfname) {\r
                                                int ret = -1;\r
-                                               cd_img_type cd_type;\r
+                                               cd_track_type cd_type;\r
                                                cd_type = emu_cdCheck(NULL, romFileName);\r
-                                               if (cd_type != CIT_NOT_CD)\r
+                                               if (cd_type >= 0 && cd_type != CT_UNKNOWN)\r
                                                        ret = Insert_CD(romFileName, cd_type);\r
                                                if (ret != 0) {\r
                                                        sprintf(menuErrorMsg, "Load failed, invalid CD image?");\r
index d889fb2..a6fce3e 100644 (file)
@@ -749,7 +749,7 @@ void retro_get_system_info(struct retro_system_info *info)
 #define _GIT_VERSION "-" GIT_VERSION
 #endif
    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;
 }
 
@@ -1002,7 +1002,7 @@ static unsigned int disk_get_image_index(void)
 
 static bool disk_set_image_index(unsigned int index)
 {
-   enum cd_img_type cd_type;
+   enum cd_track_type cd_type;
    int ret;
 
    if (index >= sizeof(disks) / sizeof(disks[0]))
@@ -1024,7 +1024,7 @@ static bool disk_set_image_index(unsigned int index)
 
    ret = -1;
    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);
    if (ret != 0) {
       if (log_cb)
index 080784d..016c44d 100644 (file)
@@ -30,7 +30,6 @@
 #include <pico/pico_int.h>
 #include <pico/cd/genplus_macros.h>
 #include <pico/cd/cdd.h>
-#include <pico/cd/cue.h>
 
 #define OSD_FPS_X 432
 
@@ -744,23 +743,10 @@ void emu_handle_resume(void)
        // reopen first CD track
        if (cdd.toc.tracks[0].fd != NULL)
        {
-               const char *fname = rom_fname_reload;
-               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);
+               lprintf("emu_HandleResume: reopen %s\n", cdd.toc.tracks[0].fname);
                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");
-
-               if (cue_data != NULL) cue_destroy(cue_data);
        }
 
        mp3_reopen_file();