added GX_Flush(), documented sound rendering core

This commit is contained in:
ekeeke31 2008-12-19 15:38:26 +00:00
parent 840a370418
commit f6a242a031
3 changed files with 76 additions and 43 deletions

View File

@ -79,7 +79,7 @@ static void load_bios()
static void init_machine (void) static void init_machine (void)
{ {
/* Allocate cart_rom here */ /* Allocate cart_rom here ( 10 MBytes ) */
cart_rom = memalign(32, 10 * 1024 * 1024); cart_rom = memalign(32, 10 * 1024 * 1024);
/* BIOS support */ /* BIOS support */
@ -194,16 +194,16 @@ int main (int argc, char *argv[])
if (frameticker > 1) if (frameticker > 1)
{ {
/* Frame skipping */ /* frameskipping */
frameticker--; frameticker--;
system_frame (1); system_frame (1);
} }
else else
{ {
/* Delay */ /* frame sync */
while (!frameticker) usleep(10); while (!frameticker) usleep(10);
/* Render Frame */ /* frame rendering */
system_frame (0); system_frame (0);
RenderedFrameCount++; RenderedFrameCount++;
} }
@ -214,7 +214,7 @@ int main (int argc, char *argv[])
ogc_audio__update(); ogc_audio__update();
ogc_video__update(); ogc_video__update();
/* Check rendered frames (FPS) */ /* check rendered frames (FPS) */
FrameCount++; FrameCount++;
if (FrameCount == vdp_rate) if (FrameCount == vdp_rate)
{ {
@ -226,14 +226,14 @@ int main (int argc, char *argv[])
/* Check for Menu request */ /* Check for Menu request */
if (ConfigRequested) if (ConfigRequested)
{ {
/* stop AUDIO */ /* stop Audio */
ogc_audio__stop(); ogc_audio__stop();
/* go to menu */ /* go to menu */
MainMenu (); MainMenu ();
ConfigRequested = 0; ConfigRequested = 0;
/* reset frame timings */ /* reset frame sync */
frameticker = 0; frameticker = 0;
FrameCount = 0; FrameCount = 0;
RenderedFrameCount = 0; RenderedFrameCount = 0;

View File

@ -23,71 +23,102 @@
#include "shared.h" #include "shared.h"
/* global datas */ /* DMA soundbuffers (required to be 32-bytes aligned)
unsigned char soundbuffer[2][3840] ATTRIBUTE_ALIGN(32); Length is dimensionned for one frame of emulation (see below)
u8 mixbuffer = 0; To prevent audio clashes, we use double buffering technique:
one buffer is the active DMA buffer
the other one is the current work buffer (updated during frame emulation)
We do not need more since frame emulation is synchronized with DMA execution
*/
u8 soundbuffer[2][3840] ATTRIBUTE_ALIGN(32);
/* Current work soundbuffer */
u8 mixbuffer = 1;
/* Current DMA status (1: DMA in progress, 0: DMA stopped) */
static int IsPlaying = 0; static int IsPlaying = 0;
/* Current DMA length (required to be a factor of 32-bytes)
length is calculated regarding current emulation timings:
PAL timings : 50 frames/sec, 48000 samples/sec = 960 samples per frame = 3840 bytes (16 bits stereo samples)
NTSC timings: 60 frames/sec, 48000 samples/sec = 800 samples per frame = 3200 bytes (16 bits stereo samples)
*/
static int dma_len = 3200; static int dma_len = 3200;
/*** AudioDmaCallback /***
AudioDmaCallback
Genesis Plus only provides sound data on completion of each frame. Genesis Plus only provides sound data on completion of each frame.
To try to make the audio less choppy, we synchronize emulation with audio DMA To try to make the audio less choppy, we synchronize frame emulation with audio DMA
This ensure we only update audio framebuffer when DMA is finished This ensure we don't access current active audiobuffer until a new DMA has been started
This also makes frame emulation sync completely independent from video sync
***/ ***/
static void AudioDmaCallback() static void AudioDmaCallback()
{ {
frameticker++; frameticker++;
} }
/***
ogc_audio__init
This function initializes the Audio Interface and DMA callback
Default samplerate is set to 48khZ
***/
void ogc_audio__init(void) void ogc_audio__init(void)
{ {
AUDIO_Init (NULL); AUDIO_Init (NULL);
AUDIO_SetDSPSampleRate (AI_SAMPLERATE_48KHZ); AUDIO_SetDSPSampleRate (AI_SAMPLERATE_48KHZ);
AUDIO_RegisterDMACallback (AudioDmaCallback); AUDIO_RegisterDMACallback (AudioDmaCallback);
mixbuffer = 0;
memset(soundbuffer, 0, 2 * 3840); memset(soundbuffer, 0, 2 * 3840);
} }
/***
ogc_audio__update
This function is called at the end of each frame, once the current soundbuffer has been updated
DMA sync and switching ensure we never access the active DMA buffer
This function set the next DMA buffer
Parameters will be taken in account ONLY when current DMA has finished
***/
void ogc_audio__update(void) void ogc_audio__update(void)
{ {
/* buffer size */
uint32 dma_len = vdp_pal ? 3840 : 3200;
/* update DMA settings (this will only be taken in account when current DMA finishes) */
AUDIO_InitDMA((u32) soundbuffer[mixbuffer], dma_len); AUDIO_InitDMA((u32) soundbuffer[mixbuffer], dma_len);
/* flush data from CPU cache */
DCFlushRange(soundbuffer[mixbuffer], dma_len); DCFlushRange(soundbuffer[mixbuffer], dma_len);
/* switch buffer */
mixbuffer ^= 1; mixbuffer ^= 1;
} }
void ogc_audio__stop(void) /***
{ ogc_audio__start
/* stop audio DMA */
AUDIO_StopDMA ();
IsPlaying = 0;
/* reset audio buffers */
mixbuffer = 0;
memset(soundbuffer, 0, 2 * 3840);
}
This function restarts Audio DMA processing
This is called only ONCE, when emulation loop starts or when coming back from Main Menu
DMA length is used for frame emulation synchronization (PAL & NTSC timings)
DMA is *automatically* restarted once the configured audio length has been output
When DMA parameters are not updated, same soundbuffer is played again
DMA parameters can be updated using successive calls to AUDIO_InitDMA (see above)
***/
void ogc_audio__start(void) void ogc_audio__start(void)
{ {
if (!IsPlaying) if (!IsPlaying)
{ {
/* buffer size */
dma_len = vdp_pal ? 3840 : 3200; dma_len = vdp_pal ? 3840 : 3200;
AUDIO_InitDMA((u32) soundbuffer[0], dma_len);
/* set first DMA parameters */
AUDIO_InitDMA((u32) soundbuffer[1], dma_len);
/* start audio DMA */
AUDIO_StartDMA(); AUDIO_StartDMA();
IsPlaying = 1; IsPlaying = 1;
} }
} }
/***
ogc_audio__stop
This function reset current Audio DMA process and clear soundbuffers
This is called when going back to Main Menu
DMA need to be restarted when going back to the game (see above)
***/
void ogc_audio__stop(void)
{
AUDIO_StopDMA ();
IsPlaying = 0;
mixbuffer = 1;
memset(soundbuffer, 0, 2 * 3840);
}

View File

@ -377,10 +377,11 @@ static void gxStart(void)
/*** Reset XFB ***/ /*** Reset XFB ***/
GX_CopyDisp (xfb[whichfb ^ 1], GX_TRUE); GX_CopyDisp (xfb[whichfb ^ 1], GX_TRUE);
GX_Flush ();
/*** Initialize texture data ***/ /*** Initialize texture data ***/
texturemem = memalign(32, TEX_WIDTH * TEX_HEIGHT * 2); texturemem = memalign(32, TEX_SIZE);
memset (texturemem, 0, TEX_WIDTH * TEX_HEIGHT * 2); memset (texturemem, 0, TEX_SIZE);
/*** Initialize renderer */ /*** Initialize renderer */
draw_init(); draw_init();
@ -545,6 +546,7 @@ void ogc_video__reset()
GX_SetPixelFmt (rmode->aa ? GX_PF_RGB565_Z16 : GX_PF_RGB8_Z24, GX_ZC_LINEAR); GX_SetPixelFmt (rmode->aa ? GX_PF_RGB565_Z16 : GX_PF_RGB8_Z24, GX_ZC_LINEAR);
guOrtho(p, rmode->efbHeight/2, -(rmode->efbHeight/2), -(rmode->fbWidth/2), rmode->fbWidth/2, 100, 1000); guOrtho(p, rmode->efbHeight/2, -(rmode->efbHeight/2), -(rmode->fbWidth/2), rmode->fbWidth/2, 100, 1000);
GX_LoadProjectionMtx (p, GX_ORTHOGRAPHIC); GX_LoadProjectionMtx (p, GX_ORTHOGRAPHIC);
GX_Flush ();
/* Software NTSC filter */ /* Software NTSC filter */
if (config.ntsc == 1) if (config.ntsc == 1)