mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 15:27:46 -04:00
core, groundwork for chd support
still needs some scrutiny, and build integration is missing
This commit is contained in:
parent
4da84f9454
commit
15ca715228
18 changed files with 411 additions and 100 deletions
200
pico/cart.c
200
pico/cart.c
|
@ -16,6 +16,11 @@
|
|||
#include "file_stream_transforms.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIBCHDR)
|
||||
#include "libchdr/chd.h"
|
||||
#include "libchdr/cdrom.h"
|
||||
#endif
|
||||
|
||||
static int rom_alloc_size;
|
||||
static const char *rom_exts[] = { "bin", "gen", "smd", "iso", "sms", "gg", "sg" };
|
||||
|
||||
|
@ -102,6 +107,19 @@ struct zip_file {
|
|||
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 *file = NULL;
|
||||
|
@ -228,6 +246,50 @@ cso_failed:
|
|||
if (f != NULL) fclose(f);
|
||||
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 */
|
||||
f = fopen(path, "rb");
|
||||
|
@ -255,6 +317,88 @@ cso_failed:
|
|||
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)
|
||||
{
|
||||
int ret;
|
||||
|
@ -355,12 +499,46 @@ size_t pm_read(void *ptr, size_t bytes, pm_file *stream)
|
|||
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
|
||||
ret = 0;
|
||||
|
||||
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)
|
||||
{
|
||||
if (stream->type == PMT_UNCOMPRESSED)
|
||||
|
@ -421,6 +599,19 @@ int pm_seek(pm_file *stream, long offset, int whence)
|
|||
}
|
||||
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
|
||||
return -1;
|
||||
}
|
||||
|
@ -446,6 +637,15 @@ int pm_close(pm_file *fp)
|
|||
free(fp->param);
|
||||
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
|
||||
ret = EOF;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
5
pico/cd/cd_parse.h
Normal file
5
pico/cd/cd_parse.h
Normal 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);
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
/* CD track */
|
||||
typedef struct
|
||||
{
|
||||
char *fname;
|
||||
void *fd;
|
||||
#ifdef USE_LIBTREMOR
|
||||
OggVorbis_File vf;
|
||||
|
|
|
@ -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);
|
||||
|
39
pico/media.c
39
pico/media.c
|
@ -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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (cue_data != NULL)
|
||||
cue_destroy(cue_data);
|
||||
|
||||
if (cd_f == NULL) return 0; // let the upper level handle this
|
||||
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();
|
||||
|
|
35
pico/pico.h
35
pico/pico.h
|
@ -161,7 +161,8 @@ typedef enum
|
|||
{
|
||||
PMT_UNCOMPRESSED = 0,
|
||||
PMT_ZIP,
|
||||
PMT_CSO
|
||||
PMT_CSO,
|
||||
PMT_CHD
|
||||
} pm_type;
|
||||
typedef struct
|
||||
{
|
||||
|
@ -172,7 +173,9 @@ typedef struct
|
|||
char ext[4];
|
||||
} pm_file;
|
||||
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_audio(void *ptr, size_t bytes, pm_file *stream);
|
||||
int pm_seek(pm_file *stream, long offset, int whence);
|
||||
int pm_close(pm_file *fp);
|
||||
int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize,int is_sms);
|
||||
|
@ -255,14 +258,34 @@ enum media_type_e {
|
|||
PM_CD,
|
||||
};
|
||||
|
||||
enum cd_img_type
|
||||
enum cd_track_type
|
||||
{
|
||||
CIT_NOT_CD = 0,
|
||||
CIT_ISO,
|
||||
CIT_BIN,
|
||||
CIT_CUE
|
||||
CT_UNKNOWN = 0,
|
||||
// data tracks
|
||||
CT_ISO = 1, /* 2048 B/sector */
|
||||
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,
|
||||
const char *carthw_cfg_fname,
|
||||
const char *(*get_bios_filename)(int *region, const char *cd_fname),
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "ym2612.h"
|
||||
#include "sn76496.h"
|
||||
#include "../pico_int.h"
|
||||
#include "../cd/cue.h"
|
||||
#include "mix.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;
|
||||
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) {
|
||||
memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret);
|
||||
Pico_mcd->cdda_stream = NULL;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue