PicoDrive: CD Audio support. GPGX and PicoDrive both share the same MCD emulation core, which has significant accuracy difficulties with CD audio...
This commit is contained in:
parent
24cd317a1c
commit
bc55597e90
|
@ -147,7 +147,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
|
|||
if (audio)
|
||||
{
|
||||
byte[] data = new byte[2352];
|
||||
if (lba < _cd.Session1.LeadoutLBA)
|
||||
if (lba < _cd.Session1.LeadoutLBA && lba >= _cd.Session1.Tracks[2].LBA)
|
||||
{
|
||||
_cdReader.ReadLBA_2352(lba, data, 0);
|
||||
}
|
||||
|
|
|
@ -122,10 +122,6 @@ void emu_32x_startup(void)
|
|||
{
|
||||
}
|
||||
|
||||
int mp3_get_bitrate(void *f, int size) { return 0; }
|
||||
void mp3_start_play(void *f, int pos) {}
|
||||
void mp3_update(int *buffer, int length, int stereo) {}
|
||||
|
||||
static const uint8_t *TryLoadBios(const char *name)
|
||||
{
|
||||
FILE *f = fopen(name, "rb");
|
||||
|
|
|
@ -125,6 +125,12 @@ void cdd_reset(void)
|
|||
/* reset logical block address */
|
||||
cdd.lba = 0;
|
||||
|
||||
// reset audio subblock position
|
||||
cdd.sampleOffset = 0;
|
||||
|
||||
// reset audio read position
|
||||
cdd.sampleLba = 0;
|
||||
|
||||
/* reset status */
|
||||
cdd.status = NO_DISC;
|
||||
|
||||
|
@ -198,164 +204,108 @@ void cdd_read_data(uint8 *dst)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void cdd_read_audio(unsigned int samples)
|
||||
void cdd_read_audio(short *buffer, unsigned int samples)
|
||||
{
|
||||
/* previous audio outputs */
|
||||
int16 l = cdd.audio[0];
|
||||
int16 r = cdd.audio[1];
|
||||
printf("cdd_read_audio %u\n", samples);
|
||||
short *outptr = buffer;
|
||||
/* audio track playing ? */
|
||||
if (!Pico_mcd->s68k_regs[0x36 + 0])
|
||||
{
|
||||
int i, mul;
|
||||
|
||||
/* get number of internal clocks (samples) needed */
|
||||
samples = blip_clocks_needed(blip[0], samples);
|
||||
/* current CD-DA fader volume */
|
||||
int curVol = cdd.volume;
|
||||
|
||||
/* audio track playing ? */
|
||||
if (!Pico_mcd->s68k_regs[0x36+0] && cdd.toc.tracks[cdd.index].fd)
|
||||
{
|
||||
int i, mul, delta;
|
||||
/* CD-DA fader volume setup (0-1024) */
|
||||
int endVol = Pico_mcd->s68k_regs[0x34] << 4 | Pico_mcd->s68k_regs[0x35] >> 4;
|
||||
|
||||
/* current CD-DA fader volume */
|
||||
int curVol = cdd.volume;
|
||||
|
||||
/* CD-DA fader volume setup (0-1024) */
|
||||
int endVol = Pico_mcd->regs[0x34>>1].w >> 4;
|
||||
|
||||
/* read samples from current block */
|
||||
#ifdef USE_LIBTREMOR
|
||||
if (cdd.toc.tracks[cdd.index].vf.datasource)
|
||||
{
|
||||
int len, done = 0;
|
||||
int16 *ptr = (int16 *) (cdc.ram);
|
||||
samples = samples * 4;
|
||||
while (done < samples)
|
||||
{
|
||||
len = ov_read(&cdd.toc.tracks[cdd.index].vf, (char *)(cdc.ram + done), samples - done, 0);
|
||||
if (len <= 0)
|
||||
{
|
||||
done = samples;
|
||||
break;
|
||||
}
|
||||
done += len;
|
||||
}
|
||||
samples = done / 4;
|
||||
|
||||
/* process 16-bit (host-endian) stereo samples */
|
||||
for (i=0; i<samples; i++)
|
||||
{
|
||||
/* CD-DA fader multiplier (cf. LC7883 datasheet) */
|
||||
/* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
|
||||
mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
|
||||
|
||||
/* left channel */
|
||||
delta = ((ptr[0] * mul) / 1024) - l;
|
||||
ptr++;
|
||||
l += delta;
|
||||
blip_add_delta_fast(blip[0], i, delta);
|
||||
|
||||
/* right channel */
|
||||
delta = ((ptr[0] * mul) / 1024) - r;
|
||||
ptr++;
|
||||
r += delta;
|
||||
blip_add_delta_fast(blip[1], i, delta);
|
||||
|
||||
/* update CD-DA fader volume (one step/sample) */
|
||||
if (curVol < endVol)
|
||||
{
|
||||
/* fade-in */
|
||||
curVol++;
|
||||
}
|
||||
else if (curVol > endVol)
|
||||
{
|
||||
/* fade-out */
|
||||
curVol--;
|
||||
}
|
||||
else if (!curVol)
|
||||
{
|
||||
/* audio will remain muted until next setup */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* read samples from current block */
|
||||
{
|
||||
uint8_t audio_scratch[4096];
|
||||
#ifdef LSB_FIRST
|
||||
int16 *ptr = (int16 *) (cdc.ram);
|
||||
int16 *ptr = (int16 *)audio_scratch;
|
||||
#else
|
||||
uint8 *ptr = cdc.ram;
|
||||
uint8 *ptr = audio_scratch;
|
||||
#endif
|
||||
fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd);
|
||||
{
|
||||
char scratch[2352];
|
||||
int nsampreq = samples;
|
||||
unsigned char *dest = audio_scratch;
|
||||
while (nsampreq > 0)
|
||||
{
|
||||
int tocopy = 588 - cdd.sampleOffset;
|
||||
if (tocopy > nsampreq)
|
||||
tocopy = nsampreq;
|
||||
CDReadSector(cdd.sampleLba, scratch, 1);
|
||||
memcpy(dest, scratch + cdd.sampleOffset * 4, tocopy * 4);
|
||||
nsampreq -= tocopy;
|
||||
dest += tocopy * 4;
|
||||
cdd.sampleOffset += tocopy;
|
||||
if (cdd.sampleOffset == 588)
|
||||
{
|
||||
cdd.sampleOffset = 0;
|
||||
cdd.sampleLba++;
|
||||
}
|
||||
}
|
||||
|
||||
/* process 16-bit (little-endian) stereo samples */
|
||||
for (i=0; i<samples; i++)
|
||||
{
|
||||
/* CD-DA fader multiplier (cf. LC7883 datasheet) */
|
||||
/* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
|
||||
mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
|
||||
//printf("samples: %i\n", samples);
|
||||
//memset(cdc.ram, 0, samples * 4);
|
||||
//fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd);
|
||||
}
|
||||
|
||||
/* left channel */
|
||||
/* process 16-bit (little-endian) stereo samples */
|
||||
for (i = 0; i < samples; i++)
|
||||
{
|
||||
/* CD-DA fader multiplier (cf. LC7883 datasheet) */
|
||||
/* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
|
||||
mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
|
||||
|
||||
/* left channel */
|
||||
#ifdef LSB_FIRST
|
||||
delta = ((ptr[0] * mul) / 1024) - l;
|
||||
ptr++;
|
||||
*outptr++ = ((ptr[0] * mul) / 1024);
|
||||
ptr++;
|
||||
#else
|
||||
delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
|
||||
ptr += 2;
|
||||
*outptr++ = (((int16)((ptr[0] + ptr[1] * 256)) * mul) / 1024);
|
||||
ptr += 2;
|
||||
#endif
|
||||
l += delta;
|
||||
blip_add_delta_fast(blip[0], i, delta);
|
||||
|
||||
/* right channel */
|
||||
/* right channel */
|
||||
#ifdef LSB_FIRST
|
||||
delta = ((ptr[0] * mul) / 1024) - r;
|
||||
ptr++;
|
||||
*outptr++ = ((ptr[0] * mul) / 1024);
|
||||
ptr++;
|
||||
#else
|
||||
delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r;
|
||||
ptr += 2;
|
||||
*outptr++ = (((int16)((ptr[0] + ptr[1] * 256)) * mul) / 1024);
|
||||
ptr += 2;
|
||||
#endif
|
||||
r += delta;
|
||||
blip_add_delta_fast(blip[1], i, delta);
|
||||
|
||||
/* update CD-DA fader volume (one step/sample) */
|
||||
if (curVol < endVol)
|
||||
{
|
||||
/* fade-in */
|
||||
curVol++;
|
||||
}
|
||||
else if (curVol > endVol)
|
||||
{
|
||||
/* fade-out */
|
||||
curVol--;
|
||||
}
|
||||
else if (!curVol)
|
||||
{
|
||||
/* audio will remain muted until next setup */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* update CD-DA fader volume (one step/sample) */
|
||||
if (curVol < endVol)
|
||||
{
|
||||
/* fade-in */
|
||||
curVol++;
|
||||
}
|
||||
else if (curVol > endVol)
|
||||
{
|
||||
/* fade-out */
|
||||
curVol--;
|
||||
}
|
||||
else if (!curVol)
|
||||
{
|
||||
/* audio will remain muted until next setup */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* save current CD-DA fader volume */
|
||||
cdd.volume = curVol;
|
||||
|
||||
/* save last audio output for next frame */
|
||||
cdd.audio[0] = l;
|
||||
cdd.audio[1] = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no audio output */
|
||||
if (l) blip_add_delta_fast(blip[0], 0, -l);
|
||||
if (r) blip_add_delta_fast(blip[1], 0, -r);
|
||||
|
||||
/* save audio output for next frame */
|
||||
cdd.audio[0] = 0;
|
||||
cdd.audio[1] = 0;
|
||||
}
|
||||
|
||||
/* end of Blip Buffer timeframe */
|
||||
blip_end_frame(blip[0], samples);
|
||||
blip_end_frame(blip[1], samples);
|
||||
/* save current CD-DA fader volume */
|
||||
cdd.volume = curVol;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no audio output */
|
||||
memset(buffer, 0, samples * 4);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void cdd_update(void)
|
||||
{
|
||||
|
@ -411,6 +361,12 @@ void cdd_update(void)
|
|||
if (cdd.lba >= cdd.toc.tracks[cdd.index].start)
|
||||
{
|
||||
/* audio track playing */
|
||||
// if it wasn't before, set the audio start position
|
||||
if (Pico_mcd->s68k_regs[0x36 + 0])
|
||||
{
|
||||
cdd.sampleLba = cdd.lba + 1;
|
||||
cdd.sampleOffset = 0;
|
||||
}
|
||||
Pico_mcd->s68k_regs[0x36 + 0] = 0x00;
|
||||
}
|
||||
|
||||
|
@ -455,6 +411,7 @@ void cdd_update(void)
|
|||
{
|
||||
/* fast-forward or fast-rewind */
|
||||
cdd.lba += cdd.scanOffset;
|
||||
cdd.sampleLba += cdd.scanOffset;
|
||||
|
||||
/* check current track limits */
|
||||
if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
|
||||
|
@ -469,6 +426,9 @@ void cdd_update(void)
|
|||
if (cdd.status == CD_PLAY)
|
||||
{
|
||||
Pico_mcd->s68k_regs[0x36 + 0] = 0x00;
|
||||
// set audio start point
|
||||
cdd.sampleLba = cdd.lba;
|
||||
cdd.sampleOffset = 0;
|
||||
}
|
||||
}
|
||||
else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
|
||||
|
|
|
@ -80,6 +80,8 @@ typedef struct
|
|||
int lba;
|
||||
int scanOffset;
|
||||
int volume;
|
||||
int sampleOffset;
|
||||
int sampleLba;
|
||||
uint8_t status;
|
||||
toc_t toc;
|
||||
int16_t audio[2];
|
||||
|
|
|
@ -19,11 +19,6 @@ extern "C" {
|
|||
// message log
|
||||
extern void lprintf(const char *fmt, ...);
|
||||
|
||||
// external funcs for Sega/Mega CD
|
||||
extern int mp3_get_bitrate(void *f, int size);
|
||||
extern void mp3_start_play(void *f, int pos);
|
||||
extern void mp3_update(int *buffer, int length, int stereo);
|
||||
|
||||
// this one should handle display mode changes
|
||||
extern void emu_video_mode_change(int start_line, int line_count, int is_32cols);
|
||||
|
||||
|
|
|
@ -438,8 +438,6 @@ typedef struct
|
|||
unsigned char bram[0x2000]; // 110200: 8K
|
||||
struct mcd_misc m; // 112200: misc
|
||||
struct mcd_pcm pcm; // 112240:
|
||||
void *cdda_stream;
|
||||
int cdda_type;
|
||||
int pcm_mixbuf[PCM_MIXBUF_LEN * 2];
|
||||
int pcm_mixpos;
|
||||
char pcm_mixbuf_dirty;
|
||||
|
@ -605,7 +603,7 @@ unsigned short cdc_host_r(void);
|
|||
// cd/cdd.c
|
||||
void cdd_reset(void);
|
||||
void cdd_read_data(unsigned char *dst);
|
||||
void cdd_read_audio(unsigned int samples);
|
||||
void cdd_read_audio(short *buffer, unsigned int samples);
|
||||
void cdd_update(void);
|
||||
void cdd_process(void);
|
||||
|
||||
|
@ -709,7 +707,6 @@ PICO_INTERNAL int SekInterruptS68k(int irq);
|
|||
void SekInterruptClearS68k(int irq);
|
||||
|
||||
// sound/sound.c
|
||||
extern short cdda_out_buffer[2*1152];
|
||||
extern int PsndLen_exc_cnt;
|
||||
extern int PsndLen_exc_add;
|
||||
extern int timer_a_next_oflow, timer_a_step; // in z80 cycles
|
||||
|
|
|
@ -24,7 +24,7 @@ static int PsndBuffer[2*(44100+100)/50];
|
|||
static unsigned short dac_info[312+4]; // pppppppp ppppllll, p - pos in buff, l - length to write for this sample
|
||||
|
||||
// cdda output buffer
|
||||
short cdda_out_buffer[2*1152];
|
||||
static short cdda_out_buffer[2*1152];
|
||||
|
||||
// for Pico
|
||||
int PsndRate=0;
|
||||
|
@ -190,50 +190,30 @@ PICO_INTERNAL void PsndDoDAC(int line_to)
|
|||
// cdda
|
||||
static void cdda_raw_update(int *buffer, int length)
|
||||
{
|
||||
/*int ret, cdda_bytes, mult = 1;
|
||||
cdd_read_audio(cdda_out_buffer, length);
|
||||
|
||||
cdda_bytes = length*4;
|
||||
if (PsndRate <= 22050 + 100) mult = 2;
|
||||
if (PsndRate < 22050 - 100) mult = 4;
|
||||
cdda_bytes *= mult;
|
||||
int mult = 1;
|
||||
|
||||
ret = pm_read(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;
|
||||
return;
|
||||
}
|
||||
if (PsndRate <= 22050 + 100)
|
||||
mult = 2;
|
||||
if (PsndRate < 22050 - 100)
|
||||
mult = 4;
|
||||
|
||||
// now mix
|
||||
switch (mult) {
|
||||
case 1: mix_16h_to_32(buffer, cdda_out_buffer, length*2); break;
|
||||
case 2: mix_16h_to_32_s1(buffer, cdda_out_buffer, length*2); break;
|
||||
case 4: mix_16h_to_32_s2(buffer, cdda_out_buffer, length*2); break;
|
||||
}*/
|
||||
// now mix
|
||||
switch (mult)
|
||||
{
|
||||
case 1:
|
||||
mix_16h_to_32(buffer, cdda_out_buffer, length * 2);
|
||||
break;
|
||||
case 2:
|
||||
mix_16h_to_32_s1(buffer, cdda_out_buffer, length * 2);
|
||||
break;
|
||||
case 4:
|
||||
mix_16h_to_32_s2(buffer, cdda_out_buffer, length * 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cdda_start_play(int lba_base, int lba_offset, int lb_len)
|
||||
{
|
||||
/*if (Pico_mcd->cdda_type == CT_MP3)
|
||||
{
|
||||
int pos1024 = 0;
|
||||
|
||||
if (lba_offset)
|
||||
pos1024 = lba_offset * 1024 / lb_len;
|
||||
|
||||
mp3_start_play(Pico_mcd->cdda_stream, pos1024);
|
||||
return;
|
||||
}
|
||||
|
||||
pm_seek(Pico_mcd->cdda_stream, (lba_base + lba_offset) * 2352, SEEK_SET);
|
||||
if (Pico_mcd->cdda_type == CT_WAV)
|
||||
{
|
||||
// skip headers, assume it's 44kHz stereo uncompressed
|
||||
pm_seek(Pico_mcd->cdda_stream, 44, SEEK_CUR);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL void PsndClear(void)
|
||||
{
|
||||
int len = PsndLen;
|
||||
|
@ -297,7 +277,6 @@ static int PsndRender(int offset, int length)
|
|||
// CD: CDDA audio
|
||||
// CD mode, cdda enabled, not data track, CDC is reading
|
||||
if ((PicoAHW & PAHW_MCD) && (PicoOpt & POPT_EN_MCD_CDDA)
|
||||
&& Pico_mcd->cdda_stream != NULL
|
||||
&& !(Pico_mcd->s68k_regs[0x36] & 1))
|
||||
{
|
||||
// note: only 44, 22 and 11 kHz supported, with forced stereo
|
||||
|
|
Loading…
Reference in New Issue