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_SetSoundVolume(100); // 0-100
FCEUI_SetSoundQuality(0); // 0 - low, 1 - high
FCEUI_SetLowPass(0);
FCEUI_SetLowPass(1);
InitialisePads();

View File

@ -13,31 +13,56 @@
#include <string.h>
#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
*
* Manages which buffer is played next
****************************************************************************/
static int isWriting = 0; /*** Bool for buffer writes ***/
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()
void AudioSwitchBuffers()
{
if ( buffSize[whichab] )
{
AUDIO_StopDMA();
AUDIO_InitDMA((u32)audiobuffer[whichab], buffSize[whichab]);
DCFlushRange(audiobuffer[whichab], buffSize[whichab]);
AUDIO_StartDMA();
isPlaying = 0;
}
whichab ^= 1;
buffSize[whichab] = 0;
if ( !ConfigRequested )
{
int len = mixercollect( soundbuffer[whichab], 3840 );
DCFlushRange(soundbuffer[whichab], len);
AUDIO_InitDMA((u32)soundbuffer[whichab], len);
AUDIO_StartDMA();
whichab ^= 1;
IsPlaying = 1;
}
else IsPlaying = 0;
}
void InitialiseSound()
@ -45,29 +70,15 @@ void InitialiseSound()
AUDIO_Init(NULL); /*** Start audio subsystem ***/
AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
AUDIO_RegisterDMACallback( AudioSwitchBuffers );
memset(audiobuffer, 0, (64 * 1024 * 2));
buffSize[0] = buffSize[1] = 0;
}
void StartAudio()
{
AUDIO_StartDMA();
memset(soundbuffer, 0, 3840*2);
memset(mixbuffer, 0, 16000);
}
void StopAudio()
{
AUDIO_StopDMA();
buffSize[0] = buffSize[1] = 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) );
AUDIO_StopDMA();
ConfigRequested = 1;
IsPlaying = 0;
}
/****************************************************************************
@ -75,43 +86,24 @@ static inline u32 FLIP32(u32 b)
*
* PlaySound will simply mix to get it right
****************************************************************************/
#define AUDIOBUFFER ((50 * SAMPLERATE) / 1000 ) << 4
static int isPlaying = 0;
static short MBuffer[ 8 * 96000 / 50 ];
void PlaySound( unsigned int *Buffer, int count )
void PlaySound( int *Buffer, int count )
{
int P;
unsigned short *s = (unsigned short *)&MBuffer[0];
unsigned int *d = (unsigned int *)&audiobuffer[whichab][buffSize[whichab]];
unsigned int c;
int ms;
int i;
s16 sample;
u32 *dst = (u32 *)mixbuffer;
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++ )
{
MBuffer[P] = Buffer[P];
}
/*** Now do Mono - Stereo Conversion ***/
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;
/* Restart Sound Processing if stopped */
//return;
if (IsPlaying == 0)
{
ConfigRequested = 0;
AudioSwitchBuffers ();
}
}

View File

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

View File

@ -10,6 +10,7 @@
****************************************************************************/
#include <gccore.h>
#include <unistd.h>
#include <ogcsys.h>
#include <stdio.h>
#include <stdlib.h>
@ -52,11 +53,57 @@ void CheesyScale(unsigned char *XBuf);
int whichfb = 0;
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
****************************************************************************/
static void copy_to_xfb() {
if (copynow == GX_TRUE) {
static void copy_to_xfb()
{
if (copynow == GX_TRUE)
{
GX_CopyDisp(xfb[whichfb],GX_TRUE);
GX_Flush();
copynow = GX_FALSE;
@ -90,7 +137,8 @@ static void copy_to_xfb() {
/****************************************************************************
* Initialise the GX
****************************************************************************/
void StartGX() {
void StartGX()
{
/*** Clear out FIFO area ***/
memset(&gp_fifo, 0, DEFAULT_FIFO_SIZE);
@ -149,7 +197,8 @@ void StartGX() {
*
* Using the texture map draw with quads
****************************************************************************/
void GXDraw(unsigned char *XBuf) {
void GXDraw(unsigned char *XBuf)
{
float gs = 1.0;
float gt = 1.0;
int width, height,t,xb;
@ -236,7 +285,8 @@ UpdatePadsCB ()
*
* Helps keep the rendering at 2x sweet
****************************************************************************/
void initDisplay() {
void initDisplay()
{
/*** Start VIDEO Subsystem ***/
VIDEO_Init();
@ -258,18 +308,24 @@ void initDisplay() {
xfb[1] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode));
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_Flush();
VIDEO_WaitVSync();
if(vmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
if(vmode->viTVMode&VI_NON_INTERLACE)
VIDEO_WaitVSync();
VIDEO_SetPostRetraceCallback((VIRetraceCallback)UpdatePadsCB);
/*** Setup a console - guard against spurious printf ***/
VIDEO_SetPreRetraceCallback((VIRetraceCallback)copy_to_xfb);
VIDEO_SetNextFramebuffer(xfb[0]);
PAD_Init();
StartGX();
InitVideoThread ();
}
/****************************************************************************
@ -279,12 +335,19 @@ void initDisplay() {
****************************************************************************/
#define NESWIDTH 256
#define NESHEIGHT 240
void RenderFrame(char *XBuf, int style) {
void RenderFrame(char *XBuf, int style)
{
int gcdispOffset = 32; /*** Offset to centre on screen ***/
int w,h;
int c,i;
// Ensure previous vb has complete
while ((LWP_ThreadIsSuspended (vbthread) == 0) || (copynow == GX_TRUE))
usleep (50);
whichfb ^= 1;
switch(style) {
case 0 :
VIDEO_ClearFrameBuffer(vmode, xfb[whichfb], COLOR_BLACK);
@ -313,10 +376,12 @@ void RenderFrame(char *XBuf, int style) {
break;
}
/*** Now resync with VSync ***/
VIDEO_SetNextFramebuffer(xfb[whichfb]);
VIDEO_Flush();
VIDEO_WaitVSync();
VIDEO_SetNextFramebuffer(xfb[whichfb]);
VIDEO_Flush();
copynow = GX_TRUE;
// Return to caller, don't waste time waiting for vb
LWP_ResumeThread (vbthread);
}
/****************************************************************************