mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-26 03:01:50 +01:00
added GX_Flush(), documented sound rendering core
This commit is contained in:
parent
840a370418
commit
f6a242a031
@ -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;
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user