#define N_(x) (x)
#endif
+/*
#if defined (USEMACOSX)
static char * libraryName = N_("Mac OS X Sound");
#elif defined (USEALSA)
#endif
static char * libraryInfo = N_("P.E.Op.S. Sound Driver V1.7\nCoded by Pete Bernert and the P.E.Op.S. team\n");
+*/
// globals
int iRecordMode=0;
int iUseReverb=2;
int iUseInterpolation=2;
-int iDisStereo=0;
// MAIN infos struct for each channel
static pthread_t thread = (pthread_t)-1; // thread id (linux)
unsigned long dwNewChannel=0; // flags for faster testing, if new channel starts
+unsigned long dwChannelOn=0;
void (CALLBACK *irqCallback)(void)=0; // func of main emu, called on spu irq
void (CALLBACK *cddavCallback)(unsigned short,unsigned short)=0;
// certain globals (were local before, but with the new timeproc I need em global)
-static const int f[5][2] = { { 0, 0 },
+static const int f[8][2] = { { 0, 0 },
{ 60, 0 },
{ 115, -52 },
{ 98, -55 },
{ 122, -60 } };
-int SSumR[NSSIZE];
-int SSumL[NSSIZE];
+int SSumLR[NSSIZE*2];
int iFMod[NSSIZE];
int iCycle = 0;
short * pS;
StartADSR(ch);
StartREVERB(ch);
- s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start
+ // fussy timing issues - do in VoiceOn
+ //s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start
+ //s_chan[ch].bStop=0;
+ //s_chan[ch].bOn=1;
s_chan[ch].s_1=0; // init mixing vars
s_chan[ch].s_2=0;
s_chan[ch].iSBPos=28;
- s_chan[ch].bNew=0; // init channel flags
- s_chan[ch].bStop=0;
- s_chan[ch].bOn=1;
-
s_chan[ch].SB[29]=0; // init our interpolation helpers
s_chan[ch].SB[30]=0;
static void *MAINThread(void *arg)
{
- int s_1,s_2,fa,ns;
-#ifndef _MACOSX
+ int s_1,s_2,fa,ns,ns_from,ns_to;
+#if !defined(_MACOSX) && !defined(__arm__)
int voldiv = iVolume;
#else
const int voldiv = 2;
//--------------------------------------------------// continue from irq handling in timer mode?
+ ns_from=0;
+ ns_to=NSSIZE;
+ ch=0;
if(lastch>=0) // will be -1 if no continue is pending
{
- ch=lastch; ns=lastns; lastch=-1; // -> setup all kind of vars to continue
- goto GOON; // -> directly jump to the continue point
+ ch=lastch; ns_from=lastns+1; lastch=-1; // -> setup all kind of vars to continue
}
//--------------------------------------------------//
//- main channel loop -//
//--------------------------------------------------//
{
- for(ch=0;ch<MAXCHAN;ch++) // loop em all... we will collect 1 ms of sound of each playing channel
+ for(;ch<MAXCHAN;ch++) // loop em all... we will collect 1 ms of sound of each playing channel
{
- if(s_chan[ch].bNew) StartSound(ch); // start new sound
- if(!s_chan[ch].bOn) continue; // channel not playing? next
+ if(dwNewChannel&(1<<ch)) StartSound(ch); // start new sound
+ if(!(dwChannelOn&(1<<ch))) continue; // channel not playing? next
if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq) // new psx frequency?
VoiceChangeFrequency(ch);
- ns=0;
- while(ns<NSSIZE) // loop until 1 ms of data is reached
+ for(ns=ns_from;ns<ns_to;ns++) // loop until 1 ms of data is reached
{
+ int sval;
+
if(s_chan[ch].bFMod==1 && iFMod[ns]) // fmod freq channel
FModChangeFrequency(ch,ns);
if (start == (unsigned char*)-1) // special "stop" sign
{
- s_chan[ch].bOn=0; // -> turn everything off
- s_chan[ch].ADSRX.lVolume=0;
+ dwChannelOn&=~(1<<ch); // -> turn everything off
s_chan[ch].ADSRX.EnvelopeVol=0;
goto ENDX; // -> and done for this channel
}
(pSpuIrq > s_chan[ch].pLoop-16 &&
pSpuIrq <= s_chan[ch].pLoop)))
{
- s_chan[ch].iIrqDone=1; // -> debug flag
irqCallback(); // -> call main emu
if(iSPUIRQWait) // -> option: wait after irq for main emu
{
iSpuAsyncWait=1;
bIRQReturn=1;
+ lastch=ch;
+ lastns=ns;
+ ns_to=ns+1;
}
}
}
{
// We play this block out first...
//if(!(flags&2)) // 1+2: do loop... otherwise: stop
- if(flags!=3 || s_chan[ch].pLoop==NULL) // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example)
- { // and checking if pLoop is set avoids crashes, yeah
+ if((flags!=3 && flags!=7) // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example)
+ || s_chan[ch].pLoop==NULL) // and checking if pLoop is set avoids crashes, yeah
+ {
start = (unsigned char*)-1;
+ // Actua Soccer 2, Jungle Book, other games that check for this condition
+ s_chan[ch].ADSRX.EnvelopeVol = 0;
}
else
{
}
}
+ if (start - spuMemC >= 0x80000)
+ start = (unsigned char*)-1;
+
s_chan[ch].pCurr=start; // store values for next cycle
s_chan[ch].s_1=s_1;
s_chan[ch].s_2=s_2;
-
- if(bIRQReturn) // special return for "spu irq - wait for cpu action"
- {
- bIRQReturn=0;
- if(iUseTimer!=2)
- {
- DWORD dwWatchTime=timeGetTime_spu()+2500;
-
- while(iSpuAsyncWait && !bEndThread &&
- timeGetTime_spu()<dwWatchTime)
- usleep(1000L);
- }
- else
- {
- lastch=ch;
- lastns=ns;
-
- return 0;
- }
- }
-
-GOON: ;
}
fa=s_chan[ch].SB[s_chan[ch].iSBPos++]; // get sample data
fa=iGetNoiseVal(ch); // get noise val
else fa=iGetInterpolationVal(ch); // get sample val
- s_chan[ch].sval = (MixADSR(ch) * fa) / 1023; // mix adsr
+ sval = (MixADSR(ch) * fa) / 1023; // mix adsr
if(s_chan[ch].bFMod==2) // fmod freq channel
- iFMod[ns]=s_chan[ch].sval; // -> store 1T sample data, use that to do fmod on next channel
+ iFMod[ns]=sval; // -> store 1T sample data, use that to do fmod on next channel
else // no fmod freq channel
{
//////////////////////////////////////////////
// ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
- if(s_chan[ch].iMute)
- s_chan[ch].sval=0; // debug mute
- else
- {
- SSumL[ns]+=(s_chan[ch].sval*s_chan[ch].iLeftVolume)/0x4000L;
- SSumR[ns]+=(s_chan[ch].sval*s_chan[ch].iRightVolume)/0x4000L;
- }
+ SSumLR[ns*2] +=(sval*s_chan[ch].iLeftVolume)/0x4000L;
+ SSumLR[ns*2+1]+=(sval*s_chan[ch].iRightVolume)/0x4000L;
//////////////////////////////////////////////
// now let us store sound data for reverb
- if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns);
+ if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns,sval);
}
////////////////////////////////////////////////
// ok, go on until 1 ms data of this channel is collected
- ns++;
s_chan[ch].spos += s_chan[ch].sinc;
-
}
ENDX: ;
}
}
+ if(bIRQReturn) // special return for "spu irq - wait for cpu action"
+ {
+ bIRQReturn=0;
+ if(iUseTimer!=2)
+ {
+ DWORD dwWatchTime=timeGetTime_spu()+2500;
+
+ while(iSpuAsyncWait && !bEndThread &&
+ timeGetTime_spu()<dwWatchTime)
+ usleep(1000L);
+ continue;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+
//---------------------------------------------------//
//- here we have another 1 ms of sound data
//---------------------------------------------------//
///////////////////////////////////////////////////////
// mix all channels (including reverb) into one buffer
- if(iDisStereo) // no stereo?
- {
- int dl, dr;
- for (ns = 0; ns < NSSIZE; ns++)
- {
- SSumL[ns] += MixREVERBLeft(ns);
-
- dl = SSumL[ns] / voldiv; SSumL[ns] = 0;
- if (dl < -32767) dl = -32767; if (dl > 32767) dl = 32767;
-
- SSumR[ns] += MixREVERBRight();
-
- dr = SSumR[ns] / voldiv; SSumR[ns] = 0;
- if (dr < -32767) dr = -32767; if (dr > 32767) dr = 32767;
- *pS++ = (dl + dr) / 2;
- }
- }
- else // stereo:
- for (ns = 0; ns < NSSIZE; ns++)
+ for (ns = 0; ns < NSSIZE*2; )
{
- SSumL[ns] += MixREVERBLeft(ns);
+ SSumLR[ns] += MixREVERBLeft(ns/2);
- d = SSumL[ns] / voldiv; SSumL[ns] = 0;
+ d = SSumLR[ns] / voldiv; SSumLR[ns] = 0;
if (d < -32767) d = -32767; if (d > 32767) d = 32767;
*pS++ = d;
+ ns++;
- SSumR[ns] += MixREVERBRight();
+ SSumLR[ns] += MixREVERBRight();
- d = SSumR[ns] / voldiv; SSumR[ns] = 0;
+ d = SSumLR[ns] / voldiv; SSumLR[ns] = 0;
if(d < -32767) d = -32767; if(d > 32767) d = 32767;
*pS++ = d;
+ ns++;
}
//////////////////////////////////////////////////////
for(ch=0;ch<4;ch++)
{
if(pSpuIrq>=pMixIrq+(ch*0x400) && pSpuIrq<pMixIrq+(ch*0x400)+2)
- {irqCallback();s_chan[ch].iIrqDone=1;}
+ irqCallback();
}
}
pMixIrq+=2;if(pMixIrq>spuMemC+0x3ff) pMixIrq=spuMemC;
if(iSpuAsyncWait)
{
iSpuAsyncWait++;
- if(iSpuAsyncWait<=64) return;
+ if(iSpuAsyncWait<=16) return;
iSpuAsyncWait=0;
}
if(!bSpuInit) return; // -> no init, no call
MAINThread(0); // -> linux high-compat mode
+
+ // abuse iSpuAsyncWait mechanism to reduce calls to above function
+ // to make it do larger chunks
+ // note: doing it less often than once per frame causes skips
+ iSpuAsyncWait=1;
}
}
// SETUPTIMER: init of certain buffers and threads/timers
void SetupTimer(void)
{
- memset(SSumR,0,NSSIZE*sizeof(int)); // init some mixing buffers
- memset(SSumL,0,NSSIZE*sizeof(int));
+ memset(SSumLR,0,sizeof(SSumLR)); // init some mixing buffers
memset(iFMod,0,NSSIZE*sizeof(int));
pS=(short *)pSpuBuffer; // setup soundbuffer pointer
(uint32_t *)malloc(16384 * sizeof(uint32_t));
CDDAEnd = CDDAStart + 16384;
CDDAPlay = CDDAStart;
- CDDAFeed = CDDAStart + 1;
+ CDDAFeed = CDDAStart;
for(i=0;i<MAXCHAN;i++) // loop sound channels
{
// we don't use mutex sync... not needed, would only
// slow us down:
// s_chan[i].hMutex=CreateMutex(NULL,FALSE,NULL);
- s_chan[i].ADSRX.SustainLevel = 1024; // -> init sustain
- s_chan[i].iMute=0;
- s_chan[i].iIrqDone=0;
+ s_chan[i].ADSRX.SustainLevel = 0xf; // -> init sustain
s_chan[i].pLoop=spuMemC;
s_chan[i].pStart=spuMemC;
s_chan[i].pCurr=spuMemC;
pMixIrq = 0;
memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN));
pSpuIrq = 0;
- iSPUIRQWait = 1;
+ //iSPUIRQWait = 0;
lastch = -1;
- ReadConfig(); // read user stuff
+ //ReadConfigSPU(); // read user stuff
SetupStreams(); // prepare streaming
return 0;
#ifdef _MACOSX
DoConfiguration();
#else
- StartCfgTool("CFG");
+// StartCfgTool("CFG");
#endif
return 0;
}
#ifdef _MACOSX
DoAbout();
#else
- StartCfgTool("ABOUT");
+// StartCfgTool("ABOUT");
#endif
}
}
// COMMON PLUGIN INFO FUNCS
+/*
char * CALLBACK PSEgetLibName(void)
{
return _(libraryName);
{
return _(libraryInfo);
}
+*/
+
+// vim:shiftwidth=1:expandtab