diff --git a/source/gx/gx_audio.c b/source/gx/gx_audio.c index fd21d94..10dcd78 100644 --- a/source/gx/gx_audio.c +++ b/source/gx/gx_audio.c @@ -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 */ - PauseOgg(1); - StopOgg(); + /* 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,13 +159,16 @@ 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); - PlayOgg((char *)Bg_music_ogg, Bg_music_ogg_size, 0, OGG_INFINITE_TIME); - SetVolumeOgg(((int)config.bgm_volume * 255) / 100); + PauseOgg(0); + PlayOgg((char *)Bg_music_ogg, Bg_music_ogg_size, 0, OGG_INFINITE_TIME); + SetVolumeOgg(((int)config.bgm_volume * 255) / 100); } } diff --git a/source/gx/gx_audio.h b/source/gx/gx_audio.h index 1186d83..ef0ae1d 100644 --- a/source/gx/gx_audio.h +++ b/source/gx/gx_audio.h @@ -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 diff --git a/source/gx/gx_input.c b/source/gx/gx_input.c index 787a2ae..39a043c 100644 --- a/source/gx/gx_input.c +++ b/source/gx/gx_input.c @@ -37,7 +37,7 @@ #define HELD_SPEED 4 /* Menu request flag */ -u8 ConfigRequested = 0; +u32 ConfigRequested = 0; /* Configurable Genesis keys */ #define KEY_BUTTONA 0 diff --git a/source/gx/gx_input.h b/source/gx/gx_input.h index d342491..9dd5db9 100644 --- a/source/gx/gx_input.h +++ b/source/gx/gx_input.h @@ -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 diff --git a/source/gx/gx_video.c b/source/gx/gx_video.c index cb8d912..85cddba 100644 --- a/source/gx/gx_video.c +++ b/source/gx/gx_video.c @@ -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 */ -GXRModeObj *vmode; /* Default Video Mode */ -u8 *texturemem; /* Texture Data */ -u8 *screenshot; /* Texture Data */ +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; } } diff --git a/source/gx/gx_video.h b/source/gx/gx_video.h index 3e3a214..586e83a 100644 --- a/source/gx/gx_video.h +++ b/source/gx/gx_video.h @@ -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 */ diff --git a/source/gx/main.c b/source/gx/main.c index 1c2f9e2..97ca7b9 100644 --- a/source/gx/main.c +++ b/source/gx/main.c @@ -30,12 +30,13 @@ #include "dvd.h" #include +#include #ifdef HW_RVL #include #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; diff --git a/source/gx/osd.h b/source/gx/osd.h index e5a8425..9e2254a 100644 --- a/source/gx/osd.h +++ b/source/gx/osd.h @@ -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_ */