[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); u8 soundbuffer[2][3840] ATTRIBUTE_ALIGN(32);
/* Current work soundbuffer */ /* Current work soundbuffer */
u8 mixbuffer; u32 mixbuffer;
/* audio DMA status */ /* audio DMA status */
static u8 audioStarted = 0; static u32 audioStarted = 0;
/* Background music */ /* Background music */
static u8 *Bg_music_ogg = NULL; static u8 *Bg_music_ogg = NULL;
@ -56,9 +56,9 @@ static void ai_callback(void)
/* AUDIO engine initialization */ /* AUDIO engine initialization */
void gx_audio_Init(void) void gx_audio_Init(void)
{ {
/* Initialize AUDIO hardware */ /* Initialize AUDIO processing library (ASNDLIB) */
/* Default samplerate is 48kHZ */ /* AUDIO & DSP hardware are initialized */
/* Default DMA callback is programmed */ /* Default samplerate is set to 48kHz */
ASND_Init(); ASND_Init();
/* Load background music from FAT device */ /* Load background music from FAT device */
@ -83,7 +83,8 @@ void gx_audio_Shutdown(void)
StopOgg(); StopOgg();
ASND_Pause(1); ASND_Pause(1);
ASND_End(); 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 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 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 */ /* set next DMA soundbuffer */
s16 *sb = (s16 *)(soundbuffer[mixbuffer]); s16 *sb = (s16 *)(soundbuffer[mixbuffer]);
mixbuffer ^= 1; mixbuffer ^= 1;
@ -101,11 +105,21 @@ void gx_audio_Update(int size)
AUDIO_InitDMA((u32) sb, size); AUDIO_InitDMA((u32) sb, size);
/* Start Audio DMA */ /* Start Audio DMA */
/* this is only called once, DMA being automatically restarted when previous one is over */ /* this is only called once to kick-off DMA from external memory to audio interface */
/* If DMA settings are not updated at that time, the same soundbuffer will be played again */ /* 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) if (!audioStarted)
{ {
audioStarted = 1; 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(); AUDIO_StartDMA();
if (frameticker > 1) if (frameticker > 1)
frameticker = 1; frameticker = 1;
@ -120,20 +134,20 @@ void gx_audio_Update(int size)
***/ ***/
void gx_audio_Start(void) void gx_audio_Start(void)
{ {
/* shutdown menu audio */ /* shutdown background music */
PauseOgg(1); PauseOgg(1);
StopOgg(); StopOgg();
/* shutdown menu audio processing */
ASND_Pause(1); ASND_Pause(1);
ASND_End(); AUDIO_StopDMA();
AUDIO_RegisterDMACallback(NULL);
DSP_Halt();
/* reset emulation audio processing */
memset(soundbuffer, 0, 2 * 3840);
audioStarted = 0; audioStarted = 0;
mixbuffer = 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) void gx_audio_Stop(void)
{ {
/* restart menu audio (this will automatically stops current audio DMA) */ /* restart menu audio processing */
DSP_Unhalt();
ASND_Init(); ASND_Init();
ASND_Pause(0); ASND_Pause(0);
/* play background music */
if (Bg_music_ogg && !Shutdown) if (Bg_music_ogg && !Shutdown)
{ {
PauseOgg(0); PauseOgg(0);

View File

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

View File

@ -37,7 +37,7 @@
#define HELD_SPEED 4 #define HELD_SPEED 4
/* Menu request flag */ /* Menu request flag */
u8 ConfigRequested = 0; u32 ConfigRequested = 0;
/* Configurable Genesis keys */ /* Configurable Genesis keys */
#define KEY_BUTTONA 0 #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_UpdateEmu(void);
extern void gx_input_UpdateMenu(u32 cnt); extern void gx_input_UpdateMenu(u32 cnt);
extern u8 ConfigRequested; extern u32 ConfigRequested;
#endif #endif

View File

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

View File

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

View File

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

View File

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