[Core/CD] improved CD audio savestate and CD file seeking (in preparation for MegaSD support)

This commit is contained in:
ekeeke 2021-09-09 00:54:45 +02:00
parent 76a08ebe6a
commit e87891fcca
6 changed files with 207 additions and 250 deletions

View file

@ -216,6 +216,7 @@ void cdd_reset(void)
int cdd_context_save(uint8 *state)
{
int bufferptr = 0;
unsigned int offset = 0;
save_param(&cdd.cycles, sizeof(cdd.cycles));
save_param(&cdd.latency, sizeof(cdd.latency));
@ -225,37 +226,121 @@ int cdd_context_save(uint8 *state)
save_param(&cdd.fader, sizeof(cdd.fader));
save_param(&cdd.status, sizeof(cdd.status));
/* current track is an audio track ? */
if (cdd.toc.tracks[cdd.index].type == TYPE_AUDIO)
{
/* get file read offset */
#if defined(USE_LIBCHDR)
if (cdd.chd.file)
{
/* CHD file offset */
offset = cdd.chd.hunkofs;
}
else
#endif
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
if (cdd.toc.tracks[cdd.index].vf.seekable)
{
/* VORBIS file sample offset */
offset = ov_pcm_tell(&cdd.toc.tracks[cdd.index].vf);
}
else
#endif
if (cdd.toc.tracks[cdd.index].fd)
{
/* PCM file offset */
offset = cdStreamTell(cdd.toc.tracks[cdd.index].fd);
}
}
save_param(&offset, sizeof(offset));
save_param(&cdd.audio, sizeof(cdd.audio));
return bufferptr;
}
int cdd_context_load(uint8 *state)
int cdd_context_load(uint8 *state, char *version)
{
int lba;
unsigned int offset, lba, index;
int bufferptr = 0;
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
#endif
#endif
load_param(&cdd.cycles, sizeof(cdd.cycles));
load_param(&cdd.latency, sizeof(cdd.latency));
load_param(&cdd.index, sizeof(cdd.index));
load_param(&cdd.lba, sizeof(cdd.lba));
load_param(&index, sizeof(cdd.index));
load_param(&lba, sizeof(cdd.lba));
load_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
load_param(&cdd.fader, sizeof(cdd.fader));
load_param(&cdd.status, sizeof(cdd.status));
/* adjust current LBA within track limit */
lba = cdd.lba;
if (lba < cdd.toc.tracks[cdd.index].start)
/* update current sector */
cdd.lba = lba;
/* support for previous state version (1.7.5) */
if ((version[11] == 0x31) && (version[13] == 0x37) && (version[15] == 0x35))
{
lba = cdd.toc.tracks[cdd.index].start;
/* current track is an audio track ? */
if (cdd.toc.tracks[index].type == TYPE_AUDIO)
{
/* stay within track limits when seeking files */
if (lba < cdd.toc.tracks[index].start)
{
lba = cdd.toc.tracks[index].start;
}
/* seek to current track sector */
cdd_seek_audio(index, lba);
}
}
else
{
load_param(&offset, sizeof(offset));
load_param(&cdd.audio, sizeof(cdd.audio));
/* current track is an audio track ? */
if (cdd.toc.tracks[index].type == TYPE_AUDIO)
{
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* check if track index has changed */
if (index != cdd.index)
{
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
/* open current track VORBIS file */
if (cdd.toc.tracks[index].vf.seekable)
{
ov_open_callbacks(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0,cb);
}
}
#endif
#endif
/* seek to current file read offset */
#if defined(USE_LIBCHDR)
if (cdd.chd.file)
{
/* CHD file offset */
cdd.chd.hunkofs = offset;
}
else
#endif
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
if (cdd.toc.tracks[index].vf.seekable)
{
/* VORBIS file sample offset */
ov_pcm_seek(&cdd.toc.tracks[index].vf, offset);
}
else
#endif
if (cdd.toc.tracks[index].fd)
{
/* PCM file offset */
cdStreamSeek(cdd.toc.tracks[index].fd, offset, SEEK_SET);
}
}
}
/* seek to current subcode position */
@ -265,36 +350,8 @@ int cdd_context_load(uint8 *state)
cdStreamSeek(cdd.toc.sub, lba * 96, SEEK_SET);
}
/* seek to current track position */
#if defined(USE_LIBCHDR)
if (cdd.chd.file)
{
/* CHD file offset */
cdd.chd.hunkofs = cdd.toc.tracks[cdd.index].offset + (lba * CD_FRAME_SIZE);
}
else
#endif
if (cdd.toc.tracks[cdd.index].type)
{
/* DATA track */
cdStreamSeek(cdd.toc.tracks[cdd.index].fd, lba * cdd.sectorSize, SEEK_SET);
}
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
else if (cdd.toc.tracks[cdd.index].vf.seekable)
{
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* VORBIS file need to be opened first */
ov_open_callbacks(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0,cb);
#endif
/* VORBIS AUDIO track */
ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba * 588) - cdd.toc.tracks[cdd.index].offset);
}
#endif
else if (cdd.toc.tracks[cdd.index].fd)
{
/* PCM AUDIO track */
cdStreamSeek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
}
/* update current track index */
cdd.index = index;
return bufferptr;
}
@ -1305,6 +1362,52 @@ void cdd_read_data(uint8 *dst, uint8 *subheader)
}
}
void cdd_seek_audio(int index, int lba)
{
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* check if track index has changed */
if (index != cdd.index)
{
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
/* open current track VORBIS file */
if (cdd.toc.tracks[index].vf.seekable)
{
ov_open_callbacks(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0,cb);
}
}
#endif
#endif
/* seek to track position */
#if defined(USE_LIBCHDR)
if (cdd.chd.file)
{
/* CHD file offset */
cdd.chd.hunkofs = cdd.toc.tracks[index].offset + (lba * CD_FRAME_SIZE);
}
else
#endif
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
if (cdd.toc.tracks[index].vf.seekable)
{
/* VORBIS AUDIO track */
ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba * 588) - cdd.toc.tracks[index].offset);
}
else
#endif
if (cdd.toc.tracks[index].fd)
{
/* PCM AUDIO track */
cdStreamSeek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
}
}
void cdd_read_audio(unsigned int samples)
{
/* previous audio outputs */
@ -1637,107 +1740,60 @@ void cdd_update(void)
/* check end of current track */
if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
{
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
#endif
#endif
/* play next track */
/* seek to next track start (assuming it can only be an audio track) */
cdd_seek_audio(cdd.index + 1, cdd.toc.tracks[cdd.index + 1].start);
/* increment current track index */
cdd.index++;
/* PAUSE between tracks */
scd.regs[0x36>>1].byte.h = 0x01;
/* seek to next audio track start */
#if defined(USE_LIBCHDR)
if (cdd.chd.file)
{
/* CHD file offset */
cdd.chd.hunkofs = cdd.toc.tracks[cdd.index].offset + (cdd.toc.tracks[cdd.index].start * CD_FRAME_SIZE);
}
else
#endif
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
if (cdd.toc.tracks[cdd.index].vf.seekable)
{
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* VORBIS file need to be opened first */
ov_open_callbacks(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0,cb);
#endif
ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (cdd.toc.tracks[cdd.index].start * 588) - cdd.toc.tracks[cdd.index].offset);
}
else
#endif
if (cdd.toc.tracks[cdd.index].fd)
{
cdStreamSeek(cdd.toc.tracks[cdd.index].fd, (cdd.toc.tracks[cdd.index].start * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
}
}
}
/* scanning disc */
else if (cdd.status == CD_SCAN)
{
/* current track index */
int index = cdd.index;
/* fast-forward or fast-rewind */
cdd.lba += cdd.scanOffset;
/* check current track limits */
if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
if (cdd.lba >= cdd.toc.tracks[index].end)
{
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
#endif
#endif
/* next track */
cdd.index++;
index++;
/* check disc limits */
if (cdd.index < cdd.toc.last)
if (index < cdd.toc.last)
{
/* skip directly to next track start position */
cdd.lba = cdd.toc.tracks[cdd.index].start;
cdd.lba = cdd.toc.tracks[index].start;
}
else
{
/* end of disc */
cdd.lba = cdd.toc.end;
cdd.index = cdd.toc.last;
cdd.status = CD_END;
/* no AUDIO track playing */
/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
return;
}
}
else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
else if (cdd.lba < cdd.toc.tracks[index].start)
{
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
#endif
#endif
/* check disc limits */
if (cdd.index > 0)
if (index > 0)
{
/* previous track */
cdd.index--;
index--;
/* skip directly to previous track end position */
cdd.lba = cdd.toc.tracks[cdd.index].end;
cdd.lba = cdd.toc.tracks[index].end;
}
else
{
@ -1746,49 +1802,29 @@ void cdd_update(void)
}
}
/* AUDIO track playing ? */
scd.regs[0x36>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x01 : 0x00;
/* seek to current subcode position */
if (cdd.toc.sub)
{
cdStreamSeek(cdd.toc.sub, cdd.lba * 96, SEEK_SET);
}
/* seek to current track position */
#if defined(USE_LIBCHDR)
if (cdd.chd.file)
/* current track is an audio track ? */
if (cdd.toc.tracks[index].type == TYPE_AUDIO)
{
/* CHD file offset */
cdd.chd.hunkofs = cdd.toc.tracks[cdd.index].offset + (cdd.lba * CD_FRAME_SIZE);
/* seek to current track sector */
cdd_seek_audio(index, cdd.lba);
/* audio track playing */
scd.regs[0x36>>1].byte.h = 0x00;
}
else
#endif
if (cdd.toc.tracks[cdd.index].type)
{
/* DATA track */
cdStreamSeek(cdd.toc.tracks[0].fd, cdd.lba * cdd.sectorSize, SEEK_SET);
}
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
else if (cdd.toc.tracks[cdd.index].vf.seekable)
{
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* check if a new track is being played */
if (!cdd.toc.tracks[cdd.index].vf.datasource)
{
/* VORBIS file need to be opened first */
ov_open_callbacks(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0,cb);
}
#endif
/* VORBIS AUDIO track */
ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (cdd.lba * 588) - cdd.toc.tracks[cdd.index].offset);
}
#endif
else if (cdd.toc.tracks[cdd.index].fd)
{
/* PCM AUDIO track */
cdStreamSeek(cdd.toc.tracks[cdd.index].fd, (cdd.lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
}
/* udpate current track index */
cdd.index = index;
}
}
@ -1996,62 +2032,22 @@ void cdd_process(void)
/* get track index */
while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* check if track index has changed */
if (index != cdd.index)
/* audio track ? */
if (cdd.toc.tracks[index].type == TYPE_AUDIO)
{
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
/* stay within track limits when seeking files */
if (lba < cdd.toc.tracks[index].start)
{
ogg_free(cdd.index);
lba = cdd.toc.tracks[index].start;
}
/* open current track VORBIS file */
if (cdd.toc.tracks[index].vf.seekable)
{
ov_open_callbacks(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0,cb);
}
/* seek to current track sector */
cdd_seek_audio(index, lba);
}
#endif
#endif
/* update current track index */
cdd.index = index;
/* stay within track limits when seeking files */
if (lba < cdd.toc.tracks[index].start)
{
lba = cdd.toc.tracks[index].start;
}
/* seek to current track position */
#if defined(USE_LIBCHDR)
if (cdd.chd.file)
{
/* CHD file offset */
cdd.chd.hunkofs = cdd.toc.tracks[index].offset + (lba * CD_FRAME_SIZE);
}
else
#endif
if (cdd.toc.tracks[index].type)
{
/* DATA track */
cdStreamSeek(cdd.toc.tracks[index].fd, lba * cdd.sectorSize, SEEK_SET);
}
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
else if (cdd.toc.tracks[index].vf.seekable)
{
/* VORBIS AUDIO track */
ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba * 588) - cdd.toc.tracks[index].offset);
}
#endif
else if (cdd.toc.tracks[index].fd)
{
/* PCM AUDIO track */
cdStreamSeek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
}
/* seek to current subcode position */
if (cdd.toc.sub)
{
@ -2103,62 +2099,22 @@ void cdd_process(void)
/* get current track index */
while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* check if track index has changed */
if (index != cdd.index)
/* audio track ? */
if (cdd.toc.tracks[index].type == TYPE_AUDIO)
{
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
/* stay within track limits when seeking files */
if (lba < cdd.toc.tracks[index].start)
{
ogg_free(cdd.index);
lba = cdd.toc.tracks[index].start;
}
/* open current track VORBIS file */
if (cdd.toc.tracks[index].vf.seekable)
{
ov_open_callbacks(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0,cb);
}
/* seek to current track sector */
cdd_seek_audio(index, lba);
}
#endif
#endif
/* update current track index */
cdd.index = index;
/* stay within track limits */
if (lba < cdd.toc.tracks[index].start)
{
lba = cdd.toc.tracks[index].start;
}
/* seek to current track position */
#if defined(USE_LIBCHDR)
if (cdd.chd.file)
{
/* CHD file offset */
cdd.chd.hunkofs = cdd.toc.tracks[index].offset + (lba * CD_FRAME_SIZE);
}
else
#endif
if (cdd.toc.tracks[index].type)
{
/* DATA track */
cdStreamSeek(cdd.toc.tracks[index].fd, lba * cdd.sectorSize, SEEK_SET);
}
#if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS)
else if (cdd.toc.tracks[index].vf.seekable)
{
/* VORBIS AUDIO track */
ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba * 588) - cdd.toc.tracks[index].offset);
}
#endif
else if (cdd.toc.tracks[index].fd)
{
/* PCM AUDIO track */
cdStreamSeek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
}
/* seek to current subcode position */
if (cdd.toc.sub)
{

View file

@ -2,7 +2,7 @@
* Genesis Plus
* CD drive processor & CD-DA fader
*
* Copyright (C) 2012-2020 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -133,10 +133,11 @@ typedef struct
extern void cdd_init(int samplerate);
extern void cdd_reset(void);
extern int cdd_context_save(uint8 *state);
extern int cdd_context_load(uint8 *state);
extern int cdd_context_load(uint8 *state, char *version);
extern int cdd_load(char *filename, char *header);
extern void cdd_unload(void);
extern void cdd_read_data(uint8 *dst, uint8 *subheader);
extern void cdd_seek_audio(int index, int lba);
extern void cdd_read_audio(unsigned int samples);
extern void cdd_update(void);
extern void cdd_process(void);

View file

@ -2,7 +2,7 @@
* Genesis Plus
* Mega CD / Sega CD hardware
*
* Copyright (C) 2012-2020 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -1851,7 +1851,7 @@ int scd_context_save(uint8 *state)
return bufferptr;
}
int scd_context_load(uint8 *state)
int scd_context_load(uint8 *state, char *version)
{
int i;
uint16 tmp16;
@ -1873,7 +1873,7 @@ int scd_context_load(uint8 *state)
bufferptr += cdc_context_load(&state[bufferptr]);
/* CD Drive processor */
bufferptr += cdd_context_load(&state[bufferptr]);
bufferptr += cdd_context_load(&state[bufferptr], version);
/* PCM chip */
bufferptr += pcm_context_load(&state[bufferptr]);

View file

@ -2,7 +2,7 @@
* Genesis Plus
* Mega CD / Sega CD hardware
*
* Copyright (C) 2012-2020 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -87,7 +87,7 @@ extern void scd_init(void);
extern void scd_reset(int hard);
extern void scd_update(unsigned int cycles);
extern void scd_end_frame(unsigned int cycles);
extern int scd_context_load(uint8 *state);
extern int scd_context_load(uint8 *state, char *version);
extern int scd_context_save(uint8 *state);
extern int scd_68k_irq_ack(int level);
extern void prg_ram_dma_w(unsigned int words);

View file

@ -2,7 +2,7 @@
* Genesis Plus
* Savestate support
*
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -149,7 +149,7 @@ int state_load(unsigned char *state)
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_USP,tmp32);
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_ISP,tmp32);
load_param(&m68k.cycles, sizeof(m68k.cycles));
load_param(&m68k.cycles, sizeof(m68k.cycles));
load_param(&m68k.int_level, sizeof(m68k.int_level));
load_param(&m68k.stopped, sizeof(m68k.stopped));
}
@ -173,7 +173,7 @@ int state_load(unsigned char *state)
}
/* CD hardware */
bufferptr += scd_context_load(&state[bufferptr]);
bufferptr += scd_context_load(&state[bufferptr], version);
}
else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{

View file

@ -2,7 +2,7 @@
* Genesis Plus
* Savestate support
*
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -40,7 +40,7 @@
#define _STATE_H_
#define STATE_SIZE 0xfd000
#define STATE_VERSION "GENPLUS-GX 1.7.5"
#define STATE_VERSION "GENPLUS-GX 1.7.6"
#define load_param(param, size) \
memcpy(param, &state[bufferptr], size); \