new audio system by eke-eke, add video threading

This commit is contained in:
dborth 2008-10-18 15:58:54 +00:00
parent 16e97e0da1
commit 6ae2648d39
4 changed files with 145 additions and 88 deletions

View File

@ -95,7 +95,7 @@ int GCMemROM(int method, int size)
FCEUI_Sound(SAMPLERATE); FCEUI_Sound(SAMPLERATE);
FCEUI_SetSoundVolume(100); // 0-100 FCEUI_SetSoundVolume(100); // 0-100
FCEUI_SetSoundQuality(0); // 0 - low, 1 - high FCEUI_SetSoundQuality(0); // 0 - low, 1 - high
FCEUI_SetLowPass(0); FCEUI_SetLowPass(1);
InitialisePads(); InitialisePads();

View File

@ -13,31 +13,56 @@
#include <string.h> #include <string.h>
#define SAMPLERATE 48000 #define SAMPLERATE 48000
unsigned char audiobuffer[2][64 * 1024] ATTRIBUTE_ALIGN(32);
/*** Allow for up to 1 full second ***/ static u8 ConfigRequested = 0;
static u8 soundbuffer[2][3840] ATTRIBUTE_ALIGN(32);
static u8 mixbuffer[16000];
static int mixhead = 0;
static int mixtail = 0;
static int whichab = 0;
int IsPlaying = 0;
static int mixercollect( u8 *outbuffer, int len )
{
u32 *dst = (u32 *)outbuffer;
u32 *src = (u32 *)mixbuffer;
int done = 0;
/*** Always clear output buffer ***/
memset(outbuffer, 0, len);
while ( ( mixtail != mixhead ) && ( done < len ) )
{
*dst++ = src[mixtail++];
if (mixtail == 4000) mixtail = 0;
done += 4;
}
/*** Realign to 32 bytes for DMA ***/
mixtail -= ((done&0x1f) >> 2);
if (mixtail < 0) mixtail += 4000;
done &= ~0x1f;
if (!done) return len >> 1;
return done;
}
/**************************************************************************** /****************************************************************************
* AudioSwitchBuffers * AudioSwitchBuffers
* *
* Manages which buffer is played next * Manages which buffer is played next
****************************************************************************/ ****************************************************************************/
static int isWriting = 0; /*** Bool for buffer writes ***/ void AudioSwitchBuffers()
static int buffSize[2]; /*** Hold size of current buffer ***/
static int whichab = 0; /*** Which Audio Buffer is in use ***/
static int isPlaying; /*** Is Playing ***/
static void AudioSwitchBuffers()
{ {
if ( buffSize[whichab] ) if ( !ConfigRequested )
{ {
AUDIO_StopDMA(); int len = mixercollect( soundbuffer[whichab], 3840 );
AUDIO_InitDMA((u32)audiobuffer[whichab], buffSize[whichab]); DCFlushRange(soundbuffer[whichab], len);
DCFlushRange(audiobuffer[whichab], buffSize[whichab]); AUDIO_InitDMA((u32)soundbuffer[whichab], len);
AUDIO_StartDMA(); AUDIO_StartDMA();
isPlaying = 0; whichab ^= 1;
} IsPlaying = 1;
}
whichab ^= 1; else IsPlaying = 0;
buffSize[whichab] = 0;
} }
void InitialiseSound() void InitialiseSound()
@ -45,29 +70,15 @@ void InitialiseSound()
AUDIO_Init(NULL); /*** Start audio subsystem ***/ AUDIO_Init(NULL); /*** Start audio subsystem ***/
AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ); AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
AUDIO_RegisterDMACallback( AudioSwitchBuffers ); AUDIO_RegisterDMACallback( AudioSwitchBuffers );
memset(audiobuffer, 0, (64 * 1024 * 2)); memset(soundbuffer, 0, 3840*2);
buffSize[0] = buffSize[1] = 0; memset(mixbuffer, 0, 16000);
}
void StartAudio()
{
AUDIO_StartDMA();
} }
void StopAudio() void StopAudio()
{ {
AUDIO_StopDMA(); AUDIO_StopDMA();
buffSize[0] = buffSize[1] = 0; ConfigRequested = 1;
} IsPlaying = 0;
static inline unsigned short FLIP16(unsigned short b)
{
return((b<<8)|((b>>8)&0xFF));
}
static inline u32 FLIP32(u32 b)
{
return( (b<<24) | ((b>>8)&0xFF00) | ((b<<8)&0xFF0000) | ((b>>24)&0xFF) );
} }
/**************************************************************************** /****************************************************************************
@ -75,43 +86,24 @@ static inline u32 FLIP32(u32 b)
* *
* PlaySound will simply mix to get it right * PlaySound will simply mix to get it right
****************************************************************************/ ****************************************************************************/
#define AUDIOBUFFER ((50 * SAMPLERATE) / 1000 ) << 4 void PlaySound( int *Buffer, int count )
static int isPlaying = 0;
static short MBuffer[ 8 * 96000 / 50 ];
void PlaySound( unsigned int *Buffer, int count )
{ {
int P; int i;
unsigned short *s = (unsigned short *)&MBuffer[0]; s16 sample;
unsigned int *d = (unsigned int *)&audiobuffer[whichab][buffSize[whichab]]; u32 *dst = (u32 *)mixbuffer;
unsigned int c;
int ms;
isWriting = 1; for( i = 0; i < count; i++ )
{
sample = Buffer[i] & 0xffff;
dst[mixhead++] = sample | ( sample << 16);
if (mixhead == 4000) mixhead = 0;
}
for ( P = 0; P < count; P++ ) /* Restart Sound Processing if stopped */
{ //return;
MBuffer[P] = Buffer[P]; if (IsPlaying == 0)
} {
ConfigRequested = 0;
/*** Now do Mono - Stereo Conversion ***/ AudioSwitchBuffers ();
ms = count; }
do
{
c = 0xffff & *s++;
*d++ = (c | (c<<16));
} while(--ms);
buffSize[whichab] += ( count << 2 );
/*** This is the kicker for the entire audio loop ***/
if ( isPlaying == 0 )
{
if ( buffSize[whichab] > AUDIOBUFFER )
{
isPlaying = 1;
AudioSwitchBuffers();
}
}
isWriting = 0;
} }

View File

@ -11,4 +11,4 @@
void InitialiseSound(); void InitialiseSound();
void StopAudio(); void StopAudio();
void PlaySound( void *Buf, int samples ); void PlaySound( int *Buffer, int samples );

View File

@ -10,6 +10,7 @@
****************************************************************************/ ****************************************************************************/
#include <gccore.h> #include <gccore.h>
#include <unistd.h>
#include <ogcsys.h> #include <ogcsys.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -52,11 +53,57 @@ void CheesyScale(unsigned char *XBuf);
int whichfb = 0; int whichfb = 0;
int copynow = GX_FALSE; int copynow = GX_FALSE;
/****************************************************************************
* VideoThreading
***************************************************************************/
#define TSTACK 16384
lwpq_t videoblankqueue;
lwp_t vbthread;
static unsigned char vbstack[TSTACK];
/****************************************************************************
* vbgetback
*
* This callback enables the emulator to keep running while waiting for a
* vertical blank.
*
* Putting LWP to good use :)
***************************************************************************/
static void *
vbgetback (void *arg)
{
while (1)
{
VIDEO_WaitVSync (); /**< Wait for video vertical blank */
LWP_SuspendThread (vbthread);
}
return NULL;
}
/****************************************************************************
* InitVideoThread
*
* libOGC provides a nice wrapper for LWP access.
* This function sets up a new local queue and attaches the thread to it.
***************************************************************************/
void
InitVideoThread ()
{
/*** Initialise a new queue ***/
LWP_InitQueue (&videoblankqueue);
/*** Create the thread on this queue ***/
LWP_CreateThread (&vbthread, vbgetback, NULL, vbstack, TSTACK, 80);
}
/**************************************************************************** /****************************************************************************
* GX Chip Copy to XFB * GX Chip Copy to XFB
****************************************************************************/ ****************************************************************************/
static void copy_to_xfb() { static void copy_to_xfb()
if (copynow == GX_TRUE) { {
if (copynow == GX_TRUE)
{
GX_CopyDisp(xfb[whichfb],GX_TRUE); GX_CopyDisp(xfb[whichfb],GX_TRUE);
GX_Flush(); GX_Flush();
copynow = GX_FALSE; copynow = GX_FALSE;
@ -90,7 +137,8 @@ static void copy_to_xfb() {
/**************************************************************************** /****************************************************************************
* Initialise the GX * Initialise the GX
****************************************************************************/ ****************************************************************************/
void StartGX() { void StartGX()
{
/*** Clear out FIFO area ***/ /*** Clear out FIFO area ***/
memset(&gp_fifo, 0, DEFAULT_FIFO_SIZE); memset(&gp_fifo, 0, DEFAULT_FIFO_SIZE);
@ -149,7 +197,8 @@ void StartGX() {
* *
* Using the texture map draw with quads * Using the texture map draw with quads
****************************************************************************/ ****************************************************************************/
void GXDraw(unsigned char *XBuf) { void GXDraw(unsigned char *XBuf)
{
float gs = 1.0; float gs = 1.0;
float gt = 1.0; float gt = 1.0;
int width, height,t,xb; int width, height,t,xb;
@ -236,7 +285,8 @@ UpdatePadsCB ()
* *
* Helps keep the rendering at 2x sweet * Helps keep the rendering at 2x sweet
****************************************************************************/ ****************************************************************************/
void initDisplay() { void initDisplay()
{
/*** Start VIDEO Subsystem ***/ /*** Start VIDEO Subsystem ***/
VIDEO_Init(); VIDEO_Init();
@ -258,18 +308,24 @@ void initDisplay() {
xfb[1] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode)); xfb[1] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode));
VIDEO_SetNextFramebuffer(xfb[0]); VIDEO_SetNextFramebuffer(xfb[0]);
VIDEO_ClearFrameBuffer (vmode, xfb[0], COLOR_BLACK);
VIDEO_ClearFrameBuffer (vmode, xfb[1], COLOR_BLACK);
VIDEO_SetNextFramebuffer (xfb[0]);
VIDEO_SetBlack(FALSE); VIDEO_SetBlack(FALSE);
VIDEO_Flush(); VIDEO_Flush();
VIDEO_WaitVSync(); VIDEO_WaitVSync();
if(vmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); if(vmode->viTVMode&VI_NON_INTERLACE)
VIDEO_WaitVSync();
VIDEO_SetPostRetraceCallback((VIRetraceCallback)UpdatePadsCB); VIDEO_SetPostRetraceCallback((VIRetraceCallback)UpdatePadsCB);
/*** Setup a console - guard against spurious printf ***/
VIDEO_SetPreRetraceCallback((VIRetraceCallback)copy_to_xfb); VIDEO_SetPreRetraceCallback((VIRetraceCallback)copy_to_xfb);
VIDEO_SetNextFramebuffer(xfb[0]);
PAD_Init(); PAD_Init();
StartGX(); StartGX();
InitVideoThread ();
} }
/**************************************************************************** /****************************************************************************
@ -279,12 +335,19 @@ void initDisplay() {
****************************************************************************/ ****************************************************************************/
#define NESWIDTH 256 #define NESWIDTH 256
#define NESHEIGHT 240 #define NESHEIGHT 240
void RenderFrame(char *XBuf, int style) {
void RenderFrame(char *XBuf, int style)
{
int gcdispOffset = 32; /*** Offset to centre on screen ***/ int gcdispOffset = 32; /*** Offset to centre on screen ***/
int w,h; int w,h;
int c,i; int c,i;
// Ensure previous vb has complete
while ((LWP_ThreadIsSuspended (vbthread) == 0) || (copynow == GX_TRUE))
usleep (50);
whichfb ^= 1; whichfb ^= 1;
switch(style) { switch(style) {
case 0 : case 0 :
VIDEO_ClearFrameBuffer(vmode, xfb[whichfb], COLOR_BLACK); VIDEO_ClearFrameBuffer(vmode, xfb[whichfb], COLOR_BLACK);
@ -313,10 +376,12 @@ void RenderFrame(char *XBuf, int style) {
break; break;
} }
/*** Now resync with VSync ***/ VIDEO_SetNextFramebuffer(xfb[whichfb]);
VIDEO_SetNextFramebuffer(xfb[whichfb]); VIDEO_Flush();
VIDEO_Flush(); copynow = GX_TRUE;
VIDEO_WaitVSync();
// Return to caller, don't waste time waiting for vb
LWP_ResumeThread (vbthread);
} }
/**************************************************************************** /****************************************************************************