fixed audio/video synchronization in interlaced & progressive modes

This commit is contained in:
ekeeke31 2010-08-08 18:09:37 +00:00
parent cd14774e03
commit 54f1b14aa9
7 changed files with 147 additions and 67 deletions

View File

@ -988,7 +988,7 @@ static void systemmenu ()
switch (ret) switch (ret)
{ {
case 0: /*** Region Force ***/ case 0: /*** Force Region ***/
config.region_detect = (config.region_detect + 1) % 4; config.region_detect = (config.region_detect + 1) % 4;
if (config.region_detect == 0) if (config.region_detect == 0)
sprintf (items[0].text, "Console Region: AUTO"); sprintf (items[0].text, "Console Region: AUTO");
@ -1004,18 +1004,13 @@ static void systemmenu ()
/* reset console region */ /* reset console region */
region_autodetect(); region_autodetect();
/* update framerate */
if (vdp_pal)
framerate = 50.0;
else
framerate = ((config.tv_mode == 0) || (config.tv_mode == 2)) ? (1000000.0/16715.0) : 60.0;
/* save YM2612 context */ /* save YM2612 context */
temp = memalign(32,YM2612GetContextSize()); temp = memalign(32,YM2612GetContextSize());
if (temp) if (temp)
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
/* reinitialize all timings */ /* reinitialize all timings */
framerate = vdp_pal ? 50.0 : ((config.tv_mode == 1) ? 60.0 : ((config.render || interlaced) ? 59.94 : (1000000.0/16715.0)));
audio_init(snd.sample_rate, framerate); audio_init(snd.sample_rate, framerate);
system_init(); system_init();
@ -1212,6 +1207,27 @@ static void videomenu ()
config.render = 0; config.render = 0;
} }
} }
if (!vdp_pal && cart.romsize)
{
/* save YM2612 context */
temp = memalign(32,YM2612GetContextSize());
if (temp)
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
/* reinitialize audio timings */
framerate = (config.tv_mode == 1) ? 60.0 : ((config.render || interlaced) ? 59.94 : (1000000.0/16715.0));
audio_init(snd.sample_rate, framerate);
sound_init();
/* restore YM2612 context */
if (temp)
{
YM2612Restore(temp);
free(temp);
}
}
if (config.render == 1) if (config.render == 1)
sprintf (items[0].text,"Display: INTERLACED"); sprintf (items[0].text,"Display: INTERLACED");
else if (config.render == 2) else if (config.render == 2)
@ -1225,26 +1241,24 @@ static void videomenu ()
{ {
config.tv_mode = (config.tv_mode + 1) % 3; config.tv_mode = (config.tv_mode + 1) % 3;
/* update framerate */ if (!vdp_pal && cart.romsize)
if (vdp_pal)
framerate = 50.0;
else
framerate = ((config.tv_mode == 0) || (config.tv_mode == 2)) ? (1000000.0/16715.0) : 60.0;
/* save YM2612 context */
temp = memalign(32,YM2612GetContextSize());
if (temp)
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
/* reinitialize audio timings */
audio_init(snd.sample_rate, framerate);
sound_init();
/* restore YM2612 context */
if (temp)
{ {
YM2612Restore(temp); /* save YM2612 context */
free(temp); temp = memalign(32,YM2612GetContextSize());
if (temp)
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
/* reinitialize audio timings */
framerate = (config.tv_mode == 1) ? 60.0 : ((config.render || interlaced) ? 59.94 : (1000000.0/16715.0));
audio_init(snd.sample_rate, framerate);
sound_init();
/* restore YM2612 context */
if (temp)
{
YM2612Restore(temp);
free(temp);
}
} }
if (config.tv_mode == 0) if (config.tv_mode == 0)

View File

@ -71,7 +71,10 @@ void gx_audio_Init(void)
stat(fname, &filestat); stat(fname, &filestat);
Bg_music_ogg_size = filestat.st_size; Bg_music_ogg_size = filestat.st_size;
Bg_music_ogg = memalign(32,Bg_music_ogg_size); Bg_music_ogg = memalign(32,Bg_music_ogg_size);
if (Bg_music_ogg) fread(Bg_music_ogg,1,Bg_music_ogg_size,f); if (Bg_music_ogg)
{
fread(Bg_music_ogg,1,Bg_music_ogg_size,f);
}
fclose(f); fclose(f);
} }
} }
@ -84,7 +87,9 @@ void gx_audio_Shutdown(void)
ASND_Pause(1); ASND_Pause(1);
ASND_End(); ASND_End();
if (Bg_music_ogg) if (Bg_music_ogg)
{
free(Bg_music_ogg); free(Bg_music_ogg);
}
} }
/*** /***
@ -111,24 +116,19 @@ void gx_audio_Update(void)
/* Therefore we need to make sure frame emulation is completed before current DMA is */ /* Therefore we need to make sure frame emulation is completed before current DMA is */
/* completed, either by synchronizing frame emulation with DMA start or by syncing it */ /* completed, either by synchronizing frame emulation with DMA start or by syncing it */
/* with Vertical Interrupt and outputing a suitable number of samples per frame. */ /* with Vertical Interrupt and outputing a suitable number of samples per frame. */
/* In 60hz mode, VSYNC period is actually 16715 ms which is 802.32 samples at 48kHz. */
/* */ /* */
/* In both cases, audio DMA need to be synchronized with VSYNC and therefore need to */ /* In both cases, audio DMA need to be synchronized with VSYNC and therefore need to */
/* be resynchronized (restarted) every time video settings are changed (hopefully, */ /* be resynchronized (restarted) every time video settings are changed (hopefully, */
/* this generally happens while no music is played. */ /* this generally happens while no music is played. */
if (!audioStarted) if (!audioStarted)
{ {
audioStarted = 1;
/* when not using 60hz mode, frame emulation is synchronized with Audio Interface DMA */
if (gc_pal | vdp_pal)
AUDIO_RegisterDMACallback(ai_callback);
/* restart audio DMA */ /* restart audio DMA */
AUDIO_StopDMA(); AUDIO_StopDMA();
AUDIO_StartDMA(); AUDIO_StartDMA();
if (frameticker > 1) audioStarted = 1;
frameticker = 1;
/* resynchronize emulation */
frameticker = 1;
} }
} }
@ -150,6 +150,12 @@ void gx_audio_Start(void)
AUDIO_RegisterDMACallback(NULL); AUDIO_RegisterDMACallback(NULL);
DSP_Halt(); DSP_Halt();
/* when not using 60hz mode, frame emulation is synchronized with Audio Interface DMA */
if (gc_pal | vdp_pal)
{
AUDIO_RegisterDMACallback(ai_callback);
}
/* reset emulation audio processing */ /* reset emulation audio processing */
memset(soundbuffer, 0, 2 * 3840); memset(soundbuffer, 0, 2 * 3840);
audioStarted = 0; audioStarted = 0;

View File

@ -1306,9 +1306,13 @@ void gx_video_Start(void)
{ {
/* 50Hz/60Hz mode */ /* 50Hz/60Hz mode */
if ((config.tv_mode == 1) || ((config.tv_mode == 2) && vdp_pal)) if ((config.tv_mode == 1) || ((config.tv_mode == 2) && vdp_pal))
{
gc_pal = 1; gc_pal = 1;
}
else else
{
gc_pal = 0; gc_pal = 0;
}
#ifdef HW_RVL #ifdef HW_RVL
VIDEO_SetTrapFilter(config.trap); VIDEO_SetTrapFilter(config.trap);
@ -1318,7 +1322,9 @@ void gx_video_Start(void)
/* VSYNC callbacks */ /* VSYNC callbacks */
/* in 60hz mode, frame emulation is synchronized with Video Interrupt */ /* in 60hz mode, frame emulation is synchronized with Video Interrupt */
if (!gc_pal && !vdp_pal) if (!gc_pal && !vdp_pal)
{
VIDEO_SetPreRetraceCallback(vi_callback); VIDEO_SetPreRetraceCallback(vi_callback);
}
VIDEO_SetPostRetraceCallback(NULL); VIDEO_SetPostRetraceCallback(NULL);
VIDEO_Flush(); VIDEO_Flush();
@ -1342,9 +1348,13 @@ void gx_video_Start(void)
{ {
/* allocate filters */ /* allocate filters */
if (!sms_ntsc) if (!sms_ntsc)
{
sms_ntsc = (sms_ntsc_t *)memalign(32,sizeof(sms_ntsc_t)); sms_ntsc = (sms_ntsc_t *)memalign(32,sizeof(sms_ntsc_t));
}
if (!md_ntsc) if (!md_ntsc)
{
md_ntsc = (md_ntsc_t *)memalign(32,sizeof(md_ntsc_t)); md_ntsc = (md_ntsc_t *)memalign(32,sizeof(md_ntsc_t));
}
/* setup filters default configuration */ /* setup filters default configuration */
switch (config.ntsc) switch (config.ntsc)
@ -1366,9 +1376,13 @@ void gx_video_Start(void)
/* lightgun textures */ /* lightgun textures */
if (config.gun_cursor[0] && (input.dev[4] == DEVICE_LIGHTGUN)) if (config.gun_cursor[0] && (input.dev[4] == DEVICE_LIGHTGUN))
{
crosshair[0] = gxTextureOpenPNG(Crosshair_p1_png,0); crosshair[0] = gxTextureOpenPNG(Crosshair_p1_png,0);
}
if (config.gun_cursor[1] && (input.dev[5] == DEVICE_LIGHTGUN)) if (config.gun_cursor[1] && (input.dev[5] == DEVICE_LIGHTGUN))
{
crosshair[1] = gxTextureOpenPNG(Crosshair_p2_png,0); crosshair[1] = gxTextureOpenPNG(Crosshair_p2_png,0);
}
/* GX emulation rendering */ /* GX emulation rendering */
gxResetRendering(0); gxResetRendering(0);
@ -1382,7 +1396,7 @@ void gx_video_Update(void)
{ {
int update = bitmap.viewport.changed & 1; int update = bitmap.viewport.changed & 1;
/* check if display has changed */ /* check if display has changed during frame */
if (update) if (update)
{ {
/* update texture size */ /* update texture size */
@ -1391,11 +1405,15 @@ void gx_video_Update(void)
/* interlaced mode */ /* interlaced mode */
if (config.render && interlaced) if (config.render && interlaced)
{
vheight = vheight << 1; vheight = vheight << 1;
}
/* ntsc filter */ /* ntsc filter */
if (config.ntsc) if (config.ntsc)
{
vwidth = (reg[12] & 1) ? MD_NTSC_OUT_WIDTH(vwidth) : SMS_NTSC_OUT_WIDTH(vwidth); vwidth = (reg[12] & 1) ? MD_NTSC_OUT_WIDTH(vwidth) : SMS_NTSC_OUT_WIDTH(vwidth);
}
/* texels size must be multiple of 4 */ /* texels size must be multiple of 4 */
vwidth = (vwidth >> 2) << 2; vwidth = (vwidth >> 2) << 2;
@ -1407,16 +1425,22 @@ void gx_video_Update(void)
/* configure texture filtering */ /* configure texture filtering */
if (!config.bilinear) if (!config.bilinear)
{
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,0.0,10.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,0.0,10.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1);
}
/* load texture object */ /* load texture object */
GX_LoadTexObj(&texobj, GX_TEXMAP0); GX_LoadTexObj(&texobj, GX_TEXMAP0);
/* update TV mode */ /* update rendering mode */
if (config.render) if (config.render)
{
rmode = tvmodes[gc_pal*3 + 2]; rmode = tvmodes[gc_pal*3 + 2];
}
else else
{
rmode = tvmodes[gc_pal*3 + interlaced]; rmode = tvmodes[gc_pal*3 + interlaced];
}
/* update aspect ratio */ /* update aspect ratio */
gxResetScaler(vwidth); gxResetScaler(vwidth);
@ -1426,7 +1450,6 @@ void gx_video_Update(void)
/* update VI mode */ /* update VI mode */
VIDEO_Configure(rmode); VIDEO_Configure(rmode);
VIDEO_Flush();
} }
/* texture is now directly mapped by the line renderer */ /* texture is now directly mapped by the line renderer */
@ -1438,11 +1461,15 @@ void gx_video_Update(void)
/* render textured quad */ /* render textured quad */
draw_square(); draw_square();
/* LightGun marks */ /* Lightgun marks */
if (crosshair[0]) if (crosshair[0])
{
gxDrawCrosshair(crosshair[0], input.analog[0][0],input.analog[0][1]); gxDrawCrosshair(crosshair[0], input.analog[0][0],input.analog[0][1]);
}
if (crosshair[1]) if (crosshair[1])
{
gxDrawCrosshair(crosshair[1], input.analog[1][0],input.analog[1][1]); gxDrawCrosshair(crosshair[1], input.analog[1][0],input.analog[1][1]);
}
/* swap XFB */ /* swap XFB */
whichfb ^= 1; whichfb ^= 1;
@ -1451,24 +1478,29 @@ void gx_video_Update(void)
GX_DrawDone(); GX_DrawDone();
GX_CopyDisp(xfb[whichfb], GX_TRUE); GX_CopyDisp(xfb[whichfb], GX_TRUE);
GX_Flush(); GX_Flush();
/* XFB is ready to be displayed */
VIDEO_SetNextFramebuffer(xfb[whichfb]); VIDEO_SetNextFramebuffer(xfb[whichfb]);
VIDEO_Flush(); VIDEO_Flush();
if (update) if (update)
{ {
/* Clear update flags */
bitmap.viewport.changed &= ~1;
/* field synchronization */ /* field synchronization */
VIDEO_WaitVSync(); VIDEO_WaitVSync();
if (rmode->viTVMode & VI_NON_INTERLACE) if (rmode->viTVMode & VI_NON_INTERLACE)
{
VIDEO_WaitVSync(); VIDEO_WaitVSync();
}
else while (VIDEO_GetNextField() != odd_frame) else while (VIDEO_GetNextField() != odd_frame)
{
VIDEO_WaitVSync(); VIDEO_WaitVSync();
if (frameticker > 1) }
frameticker = 1;
/* force audio DMA resynchronization */ /* audio & video resynchronization */
audioStarted = 0; audioStarted = 0;
bitmap.viewport.changed &= ~1;
} }
} }

View File

@ -105,7 +105,7 @@ static bool FindIOS(u32 ios)
***************************************************************************/ ***************************************************************************/
static void load_bios(void) static void load_bios(void)
{ {
/* reset BIOS flag */ /* clear BIOS detection flag */
config.tmss &= ~2; config.tmss &= ~2;
/* open BIOS file */ /* open BIOS file */
@ -116,8 +116,12 @@ static void load_bios(void)
fread(bios_rom, 1, 0x800, fp); fread(bios_rom, 1, 0x800, fp);
fclose(fp); fclose(fp);
/* update BIOS flags */ /* check ROM file */
config.tmss |= 2; if (!strncmp((char *)(bios_rom + 0x120),"GENESIS OS", 10))
{
/* valid BIOS detected */
config.tmss |= 2;
}
} }
static void init_machine(void) static void init_machine(void)
@ -173,8 +177,8 @@ static void run_emulation(void)
ConfigRequested = 0; ConfigRequested = 0;
/* start video & audio */ /* start video & audio */
gx_audio_Start();
gx_video_Start(); gx_video_Start();
gx_audio_Start();
frameticker = 1; frameticker = 1;
} }
@ -182,8 +186,8 @@ static void run_emulation(void)
if (frameticker > 1) if (frameticker > 1)
{ {
/* skip frame */ /* skip frame */
frameticker = 0;
system_frame(1); system_frame(1);
frameticker = 1;
} }
else else
{ {
@ -198,6 +202,32 @@ static void run_emulation(void)
/* update audio */ /* update audio */
gx_audio_Update(); gx_audio_Update();
/* check interlaced mode change */
if (bitmap.viewport.changed & 4)
{
/* in original 60hz modes, audio is synced with framerate */
if (!config.render && !vdp_pal && (config.tv_mode != 1))
{
u8 *temp = memalign(32,YM2612GetContextSize());
if (temp)
{
/* save YM2612 context */
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
/* framerate has changed, reinitialize audio timings */
audio_init(48000, interlaced ? 59.94 : (1000000.0/16715.0));
sound_init();
/* restore YM2612 context */
YM2612Restore(temp);
free(temp);
}
}
/* clear flag */
bitmap.viewport.changed &= ~4;
}
/* wait for next frame */ /* wait for next frame */
while (frameticker < 1) while (frameticker < 1)
usleep(1); usleep(1);
@ -227,12 +257,8 @@ void reloadrom (int size, char *name)
{ {
/* initialize audio back-end */ /* initialize audio back-end */
/* 60hz video mode requires synchronization with Video Interrupt. */ /* 60hz video mode requires synchronization with Video Interrupt. */
/* VSYNC period is 16715 us on Wii/Gamecube (approx. 802.32 samples per frame) */ /* Framerate is 59.94 fps in interlaced/progressive modes, ~59.825 fps in non-interlaced mode */
float framerate; float framerate = vdp_pal ? 50.0 : ((config.tv_mode == 1) ? 60.0 : (config.render ? 59.94 : (1000000.0/16715.0)));
if (vdp_pal)
framerate = 50.0;
else
framerate = ((config.tv_mode == 0) || (config.tv_mode == 2)) ? (1000000.0/16715.0) : 60.0;
audio_init(48000, framerate); audio_init(48000, framerate);
/* System Power ON */ /* System Power ON */

View File

@ -114,7 +114,6 @@ void SN76489_Init(float PSGClockValue, int SamplingRate)
SN76489_Context *p = &SN76489; SN76489_Context *p = &SN76489;
p->dClock=PSGClockValue/16.0/SamplingRate; p->dClock=PSGClockValue/16.0/SamplingRate;
SN76489_Config(MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, config.psgBoostNoise); SN76489_Config(MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, config.psgBoostNoise);
SN76489_Reset();
} }
void SN76489_Reset(void) void SN76489_Reset(void)

View File

@ -178,18 +178,21 @@ int sound_update(unsigned int cycles)
int avail = Fir_Resampler_avail(); int avail = Fir_Resampler_avail();
/* resynchronize FM & PSG chips */ /* resynchronize FM & PSG chips */
if (avail < size) if (avail > size)
{
/* FM chip is late for one sample */
YM2612Update(Fir_Resampler_buffer(), 1);
Fir_Resampler_write(2);
fm_cycles_count += fm_cycles_ratio;
}
else
{ {
/* FM chip is ahead */ /* FM chip is ahead */
fm_cycles_count += (avail - size) * psg_cycles_ratio; fm_cycles_count += (avail - size) * psg_cycles_ratio;
} }
else
{
while (avail < size)
{
/* FM chip is late for one sample */
YM2612Update(Fir_Resampler_buffer(), 1);
Fir_Resampler_write(2);
avail = Fir_Resampler_avail();
}
}
} }
#ifdef LOGSOUND #ifdef LOGSOUND

View File

@ -334,7 +334,7 @@ void system_frame (int do_skip)
{ {
im2_flag = ((reg[12] & 6) == 6); im2_flag = ((reg[12] & 6) == 6);
odd_frame = 1; odd_frame = 1;
bitmap.viewport.changed = 1; bitmap.viewport.changed = 5;
} }
/* active screen height */ /* active screen height */