mirror of
https://github.com/dborth/fceugx.git
synced 2025-01-05 21:38:17 +01:00
new audio system by eke-eke, add video threading
This commit is contained in:
parent
16e97e0da1
commit
6ae2648d39
@ -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();
|
||||
|
||||
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
@ -11,4 +11,4 @@
|
||||
|
||||
void InitialiseSound();
|
||||
void StopAudio();
|
||||
void PlaySound( void *Buf, int samples );
|
||||
void PlaySound( int *Buffer, int samples );
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
Loading…
Reference in New Issue
Block a user