[GCN/Wii]

*fixed audio/video desync that could occur after loading a new game 
*improved general synchronization of frame execution
*modified ASNDLIB shutdown to prevent potential memory leak with DSP tasks
*changed some global variables to use int type by default for optimization
*some code cleanup
This commit is contained in:
ekeeke31 2010-01-27 13:12:06 +00:00
parent f44d38b537
commit bad0696190
8 changed files with 107 additions and 76 deletions

View File

@ -34,10 +34,10 @@
u8 soundbuffer[2][3840] ATTRIBUTE_ALIGN(32);
/* Current work soundbuffer */
u8 mixbuffer;
u32 mixbuffer;
/* audio DMA status */
static u8 audioStarted = 0;
static u32 audioStarted = 0;
/* Background music */
static u8 *Bg_music_ogg = NULL;
@ -56,9 +56,9 @@ static void ai_callback(void)
/* AUDIO engine initialization */
void gx_audio_Init(void)
{
/* Initialize AUDIO hardware */
/* Default samplerate is 48kHZ */
/* Default DMA callback is programmed */
/* Initialize AUDIO processing library (ASNDLIB) */
/* AUDIO & DSP hardware are initialized */
/* Default samplerate is set to 48kHz */
ASND_Init();
/* Load background music from FAT device */
@ -83,7 +83,8 @@ void gx_audio_Shutdown(void)
StopOgg();
ASND_Pause(1);
ASND_End();
if (Bg_music_ogg) free(Bg_music_ogg);
if (Bg_music_ogg)
free(Bg_music_ogg);
}
/***
@ -92,8 +93,11 @@ void gx_audio_Shutdown(void)
This function retrieves samples for the frame then set the next DMA parameters
Parameters will be taken in account only when current DMA operation is over
***/
void gx_audio_Update(int size)
void gx_audio_Update(void)
{
/* retrieve audio samples */
int size = audio_update() * 4;
/* set next DMA soundbuffer */
s16 *sb = (s16 *)(soundbuffer[mixbuffer]);
mixbuffer ^= 1;
@ -101,11 +105,21 @@ void gx_audio_Update(int size)
AUDIO_InitDMA((u32) sb, size);
/* Start Audio DMA */
/* this is only called once, DMA being automatically restarted when previous one is over */
/* If DMA settings are not updated at that time, the same soundbuffer will be played again */
/* this is only called once to kick-off DMA from external memory to audio interface */
/* DMA operation is automatically restarted when all samples have been sent. */
/* If DMA settings are not updated at that time, previous sound buffer will be used. */
/* 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 */
/* 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. */
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);
AUDIO_StartDMA();
if (frameticker > 1)
frameticker = 1;
@ -120,20 +134,20 @@ void gx_audio_Update(int size)
***/
void gx_audio_Start(void)
{
/* shutdown menu audio */
/* shutdown background music */
PauseOgg(1);
StopOgg();
/* shutdown menu audio processing */
ASND_Pause(1);
ASND_End();
AUDIO_StopDMA();
AUDIO_RegisterDMACallback(NULL);
DSP_Halt();
/* reset emulation audio processing */
memset(soundbuffer, 0, 2 * 3840);
audioStarted = 0;
mixbuffer = 0;
/* reset sound buffers */
memset(soundbuffer, 0, 2 * 3840);
/* By default, use audio DMA to synchronize frame emulation */
if (gc_pal | vdp_pal)
AUDIO_RegisterDMACallback(ai_callback);
}
/***
@ -145,9 +159,12 @@ void gx_audio_Start(void)
***/
void gx_audio_Stop(void)
{
/* restart menu audio (this will automatically stops current audio DMA) */
/* restart menu audio processing */
DSP_Unhalt();
ASND_Init();
ASND_Pause(0);
/* play background music */
if (Bg_music_ogg && !Shutdown)
{
PauseOgg(0);

View File

@ -26,12 +26,12 @@
#define _GC_AUDIO_H_
extern u8 soundbuffer[2][3840];
extern u8 mixbuffer;
extern u32 mixbuffer;
extern void gx_audio_Init(void);
extern void gx_audio_Shutdown(void);
extern void gx_audio_Start(void);
extern void gx_audio_Stop(void);
extern void gx_audio_Update(int size);
extern void gx_audio_Update(void);
#endif

View File

@ -37,7 +37,7 @@
#define HELD_SPEED 4
/* Menu request flag */
u8 ConfigRequested = 0;
u32 ConfigRequested = 0;
/* Configurable Genesis keys */
#define KEY_BUTTONA 0

View File

@ -49,6 +49,6 @@ extern void gx_input_Config(u8 num, u8 type, u8 max_keys);
extern void gx_input_UpdateEmu(void);
extern void gx_input_UpdateMenu(u32 cnt);
extern u8 ConfigRequested;
extern u32 ConfigRequested;
#endif

View File

@ -48,14 +48,14 @@ extern const u8 Crosshair_p1_png[];
extern const u8 Crosshair_p2_png[];
/*** VI ***/
unsigned int *xfb[2]; /* External Framebuffers */
int whichfb = 0; /* Current Framebuffer */
u32 *xfb[2]; /* External Framebuffers */
u32 whichfb = 0; /* Current Framebuffer */
GXRModeObj *vmode; /* Default Video Mode */
u8 *texturemem; /* Texture Data */
u8 *screenshot; /* Texture Data */
/* 50/60hz flag */
u8 gc_pal = 0;
/*** 50/60hz flag ***/
u32 gc_pal = 0;
/*** NTSC Filters ***/
sms_ntsc_t sms_ntsc;
@ -1282,14 +1282,13 @@ void gx_video_Start(void)
gc_pal = 0;
/* VSYNC callbacks */
/* in 60hz mode we use VSYNC to synchronize frame emulation */
/* in 60hz mode, frame emulation is synchronized with Video Interrupt */
if (!gc_pal && !vdp_pal)
VIDEO_SetPreRetraceCallback(vi_callback);
VIDEO_SetPostRetraceCallback(NULL);
VIDEO_Flush();
VIDEO_WaitVSync();
/* interlaced/progressive mode */
/* interlaced/progressive Video mode */
if (config.render == 2)
{
tvmodes[2]->viTVMode = VI_TVMODE_NTSC_PROG;
@ -1306,7 +1305,8 @@ void gx_video_Start(void)
{
bitmap.viewport.x = (reg[12] & 1) ? 16 : 12;
bitmap.viewport.y = (reg[1] & 8) ? 0 : 8;
if (vdp_pal) bitmap.viewport.y += 24;
if (vdp_pal)
bitmap.viewport.y += 24;
}
else
{
@ -1314,6 +1314,10 @@ void gx_video_Start(void)
bitmap.viewport.y = 0;
}
/* reinitialize video size */
vwidth = bitmap.viewport.w + (2 * bitmap.viewport.x);
vheight = bitmap.viewport.h + (2 * bitmap.viewport.y);
/* software NTSC filters */
if (config.ntsc == 1)
{
@ -1348,6 +1352,9 @@ void gx_video_Start(void)
/* reset GX rendering */
gxResetRendering(0);
/* resynchronize emulation with VSYNC*/
VIDEO_WaitVSync();
}
/* GX render update */
@ -1365,11 +1372,14 @@ void gx_video_Update(void)
/* if width has been changed, do no render this frame */
/* this fixes texture glitches when changing width middle-frame */
if (vwidth != old_vwidth) return;
if (vwidth != old_vwidth)
return;
/* special cases */
if (config.render && interlaced) vheight = vheight << 1;
if (config.ntsc) vwidth = (reg[12]&1) ? MD_NTSC_OUT_WIDTH(vwidth) : SMS_NTSC_OUT_WIDTH(vwidth);
if (config.render && interlaced)
vheight = vheight << 1;
if (config.ntsc)
vwidth = (reg[12]&1) ? MD_NTSC_OUT_WIDTH(vwidth) : SMS_NTSC_OUT_WIDTH(vwidth);
/* texels size must be multiple of 4 */
vwidth = (vwidth >> 2) << 2;
@ -1380,14 +1390,17 @@ void gx_video_Update(void)
GX_InitTexObj(&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
/* configure texture filtering */
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);
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);
/* load texture object */
GX_LoadTexObj(&texobj, GX_TEXMAP0);
/* reset TV mode */
if (config.render) rmode = tvmodes[gc_pal*3 + 2];
else rmode = tvmodes[gc_pal*3 + interlaced];
if (config.render)
rmode = tvmodes[gc_pal*3 + 2];
else
rmode = tvmodes[gc_pal*3 + interlaced];
/* reset aspect ratio */
gxResetScaler(vwidth,vheight);
@ -1410,8 +1423,10 @@ void gx_video_Update(void)
draw_square();
/* LightGun marks */
if (crosshair[0]) gxDrawCrosshair(crosshair[0], input.analog[0][0],input.analog[0][1]);
if (crosshair[1]) gxDrawCrosshair(crosshair[1], input.analog[1][0],input.analog[1][1]);
if (crosshair[0])
gxDrawCrosshair(crosshair[0], input.analog[0][0],input.analog[0][1]);
if (crosshair[1])
gxDrawCrosshair(crosshair[1], input.analog[1][0],input.analog[1][1]);
/* swap XFB */
whichfb ^= 1;
@ -1427,9 +1442,12 @@ void gx_video_Update(void)
{
/* field synchronizations */
VIDEO_WaitVSync();
if (rmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
else while (VIDEO_GetNextField() != odd_frame) VIDEO_WaitVSync();
if (frameticker > 1) frameticker = 1;
if (rmode->viTVMode & VI_NON_INTERLACE)
VIDEO_WaitVSync();
else while (VIDEO_GetNextField() != odd_frame)
VIDEO_WaitVSync();
if (frameticker > 1)
frameticker = 1;
bitmap.viewport.changed = 0;
}
}

View File

@ -40,11 +40,11 @@ typedef struct
} gx_texture;
/* Global variables */
extern unsigned int *xfb[2];
extern int whichfb;
extern u32 *xfb[2];
extern u32 whichfb;
extern GXRModeObj *vmode;
extern u8 *texturemem;
extern u8 gc_pal;
extern u32 gc_pal;
/* GX rendering */

View File

@ -30,12 +30,13 @@
#include "dvd.h"
#include <fat.h>
#include <ogc/cast.h>
#ifdef HW_RVL
#include <wiiuse/wpad.h>
#endif
u8 Shutdown = 0;
u32 Shutdown = 0;
#ifdef HW_RVL
@ -163,19 +164,18 @@ void shutdown(void)
* M A I N
*
***************************************************************************/
u8 fat_enabled = 0;
u32 fat_enabled = 0;
u32 frameticker = 0;
int main (int argc, char *argv[])
{
CAST_Init();
#ifdef HW_RVL
/* initialize DVDX */
DI_Close();
DI_Init();
#endif
int size;
/* initialize hardware */
gx_video_Init();
gx_input_Init();
@ -255,44 +255,40 @@ int main (int argc, char *argv[])
if (ConfigRequested)
{
/* stop video & audio */
gx_video_Stop();
gx_audio_Stop();
gx_video_Stop();
/* show menu */
MainMenu ();
ConfigRequested = 0;
/* start video & audio */
/* always restart video first because it setup gc_pal */
gx_video_Start();
gx_audio_Start();
/* reset framesync */
gx_video_Start();
frameticker = 1;
}
if (frameticker > 1)
{
/* skip frame */
frameticker-=2;
system_frame (1);
system_frame(1);
--frameticker;
}
else
{
/* framesync */
while (frameticker < 1) usleep(1);
frameticker--;
while (frameticker < 1)
usleep(10);
/* render frame */
system_frame (0);
system_frame(0);
--frameticker;
/* update video */
gx_video_Update();
}
/* retrieve audio samples */
size = audio_update();
/* update video & audio */
gx_video_Update();
gx_audio_Update(size * 4);
/* update audio */
gx_audio_Update();
}
return 0;

View File

@ -49,6 +49,6 @@ extern void legal();
extern void reloadrom (int size, char *name);
extern void shutdown();
extern u32 frameticker;
extern u8 Shutdown;
extern u32 Shutdown;
#endif /* _OSD_H_ */