mirror of
https://github.com/dborth/fceugx.git
synced 2025-01-07 14:28:18 +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_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();
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
@ -11,4 +11,4 @@
|
|||||||
|
|
||||||
void InitialiseSound();
|
void InitialiseSound();
|
||||||
void StopAudio();
|
void StopAudio();
|
||||||
void PlaySound( void *Buf, int samples );
|
void PlaySound( int *Buffer, int samples );
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
Loading…
Reference in New Issue
Block a user