The previous sector delay thing breaks rhythm games.
Also much easier to deal with timing in SPU code.
static void CALLBACK GPUdisplayText(char *_) { return; }
/* SPU */
-extern long CALLBACK SPUopen(void);
-extern long CALLBACK SPUinit(void);
-extern long CALLBACK SPUshutdown(void);
-extern long CALLBACK SPUclose(void);
-extern void CALLBACK SPUwriteRegister(unsigned long, unsigned short, unsigned int);
-extern unsigned short CALLBACK SPUreadRegister(unsigned long, unsigned int);
-extern void CALLBACK SPUwriteDMAMem(unsigned short *, int, unsigned int);
-extern void CALLBACK SPUreadDMAMem(unsigned short *, int, unsigned int);
-extern void CALLBACK SPUplayADPCMchannel(void *, unsigned int, int);
-extern void CALLBACK SPUregisterCallback(void (*cb)(int));
-extern void CALLBACK SPUregisterScheduleCb(void (*cb)(unsigned int));
-extern long CALLBACK SPUfreeze(unsigned int, void *, unsigned int);
-extern void CALLBACK SPUasync(unsigned int, unsigned int);
-extern int CALLBACK SPUplayCDDAchannel(short *, int, unsigned int, int);
+#include "../plugins/dfsound/spu.h"
/* PAD */
static long CALLBACK PADinit(long _) { return 0; }
DIRECT_SPU(SPUregisterScheduleCb),
DIRECT_SPU(SPUasync),
DIRECT_SPU(SPUplayCDDAchannel),
+ DIRECT_SPU(SPUsetCDvol),
/* PAD */
DIRECT_PAD(PADinit),
DIRECT_PAD(PADshutdown),
static void cdrUpdateTransferBuf(const u8 *buf);
static void cdrReadInterrupt(void);
static void cdrPrepCdda(s16 *buf, int samples);
-static void cdrAttenuate(s16 *buf, int samples, int stereo);
static void msfiAdd(u8 *msfi, u32 count)
{
if (!cdr.IrqStat && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)))
cdrPlayInterrupt_Autopause();
- if (!cdr.Muted && cdr.Play && !Config.Cdda) {
+ if (cdr.Play && !Config.Cdda) {
cdrPrepCdda(read_buf, CD_FRAMESIZE_RAW / 4);
- cdrAttenuate(read_buf, CD_FRAMESIZE_RAW / 4, 1);
SPU_playCDDAchannel(read_buf, CD_FRAMESIZE_RAW, psxRegs.cycle, 0);
}
break;
case CdlPause:
+ if (cdr.AdpcmActive) {
+ cdr.AdpcmActive = 0;
+ cdr.Xa.nsamples = 0;
+ SPU_playADPCMchannel(&cdr.Xa, psxRegs.cycle, 1); // flush adpcm
+ }
StopCdda();
StopReading();
StopReading();
SetPlaySeekRead(cdr.StatP, 0);
cdr.LocL[0] = LOCL_INVALID;
- cdr.Muted = FALSE;
cdr.Mode = MODE_SIZE_2340; /* This fixes This is Football 2, Pooh's Party lockups */
cdr.DriveState = DRIVESTATE_PAUSED;
+ cdr.Muted = FALSE;
+ SPU_setCDvol(cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight,
+ cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight, psxRegs.cycle);
second_resp_time = not_ready ? 70000 : 4100000;
start_rotating = 1;
break;
case CdlMute:
cdr.Muted = TRUE;
+ SPU_setCDvol(0, 0, 0, 0, psxRegs.cycle);
break;
case CdlDemute:
cdr.Muted = FALSE;
+ SPU_setCDvol(cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight,
+ cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight, psxRegs.cycle);
break;
case CdlSetfilter:
#endif
}
-static void cdrAttenuate(s16 *buf, int samples, int stereo)
-{
- int i, l, r;
- int ll = cdr.AttenuatorLeftToLeft;
- int lr = cdr.AttenuatorLeftToRight;
- int rl = cdr.AttenuatorRightToLeft;
- int rr = cdr.AttenuatorRightToRight;
-
- if (lr == 0 && rl == 0 && 0x78 <= ll && ll <= 0x88 && 0x78 <= rr && rr <= 0x88)
- return;
-
- if (!stereo && ll == 0x40 && lr == 0x40 && rl == 0x40 && rr == 0x40)
- return;
-
- if (stereo) {
- for (i = 0; i < samples; i++) {
- l = buf[i * 2];
- r = buf[i * 2 + 1];
- l = (l * ll + r * rl) >> 7;
- r = (r * rr + l * lr) >> 7;
- ssat32_to_16(l);
- ssat32_to_16(r);
- buf[i * 2] = l;
- buf[i * 2 + 1] = r;
- }
- }
- else {
- for (i = 0; i < samples; i++) {
- l = buf[i];
- l = l * (ll + rl) >> 7;
- //r = r * (rr + lr) >> 7;
- ssat32_to_16(l);
- //ssat32_to_16(r);
- buf[i] = l;
- }
- }
-}
-
static void cdrReadInterruptSetResult(unsigned char result)
{
if (cdr.IrqStat) {
int deliver_data = 1;
u8 subqPos[3];
int read_ok;
+ int is_start;
memcpy(subqPos, cdr.SetSectorPlay, sizeof(subqPos));
msfiAdd(subqPos, cdr.SubqForwardSectors);
if (Config.Xa)
break;
- if (!cdr.Muted && cdr.AdpcmActive) {
- cdrAttenuate(cdr.Xa.pcm, cdr.Xa.nsamples, cdr.Xa.stereo);
- SPU_playADPCMchannel(&cdr.Xa, psxRegs.cycle, 0);
- }
- // decode next
- cdr.AdpcmActive = !xa_decode_sector(&cdr.Xa, buf + 4, !cdr.AdpcmActive);
+ is_start = !cdr.AdpcmActive;
+ cdr.AdpcmActive = !xa_decode_sector(&cdr.Xa, buf + 4, is_start);
+ if (cdr.AdpcmActive)
+ SPU_playADPCMchannel(&cdr.Xa, psxRegs.cycle, is_start);
} while (0);
if ((cdr.Mode & MODE_SF) && (subhdr->mode & 0x44) == 0x44) // according to nocash
void cdrWrite3(unsigned char rt) {
const char *rnames[] = { "req", "ifl", "alr", "ava" }; (void)rnames;
+ u8 ll, lr, rl, rr;
CDR_LOG_IO("cdr w3.%s: %02x\n", rnames[cdr.Ctrl & 3], rt);
switch (cdr.Ctrl & 3) {
cdr.AttenuatorLeftToRightT = rt;
return;
case 3:
+ if (rt & 0x01)
+ log_unhandled("Mute ADPCM?\n");
if (rt & 0x20) {
- memcpy(&cdr.AttenuatorLeftToLeft, &cdr.AttenuatorLeftToLeftT, 4);
- CDR_LOG("CD-XA Volume: %02x %02x | %02x %02x\n",
- cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight,
- cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight);
+ ll = cdr.AttenuatorLeftToLeftT; lr = cdr.AttenuatorLeftToRightT;
+ rl = cdr.AttenuatorRightToLeftT; rr = cdr.AttenuatorRightToRightT;
+ if (ll == cdr.AttenuatorLeftToLeft &&
+ lr == cdr.AttenuatorLeftToRight &&
+ rl == cdr.AttenuatorRightToLeft &&
+ rr == cdr.AttenuatorRightToRight)
+ return;
+ cdr.AttenuatorLeftToLeftT = ll; cdr.AttenuatorLeftToRightT = lr;
+ cdr.AttenuatorRightToLeftT = rl; cdr.AttenuatorRightToRightT = rr;
+ CDR_LOG_I("CD-XA Volume: %02x %02x | %02x %02x\n", ll, lr, rl, rr);
+ SPU_setCDvol(ll, lr, rl, rr, psxRegs.cycle);
}
return;
}
cdr.AttenuatorLeftToRight = 0x00;
cdr.AttenuatorRightToLeft = 0x00;
cdr.AttenuatorRightToRight = 0x80;
+ SPU_setCDvol(cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight,
+ cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight, psxRegs.cycle);
getCdInfo();
}
gzfreeze(&tmp, sizeof(tmp));
if (Mode == 0) {
+ u8 ll = 0, lr = 0, rl = 0, rr = 0;
getCdInfo();
cdr.FifoOffset = tmp < DATA_SIZE ? tmp : DATA_SIZE;
if (!Config.Cdda)
CDR_play(cdr.SetSectorPlay);
}
+ if (!cdr.Muted)
+ ll = cdr.AttenuatorLeftToLeft, lr = cdr.AttenuatorLeftToLeft,
+ rl = cdr.AttenuatorRightToLeft, rr = cdr.AttenuatorRightToRight;
+ SPU_setCDvol(ll, lr, rl, rr, psxRegs.cycle);
}
return 0;
s32 y0, y1;
} ADPCM_Decode_t;
-typedef struct {
+typedef struct xa_decode {
int freq;
int nbits;
int stereo;
SPUregisterScheduleCb SPU_registerScheduleCb;
SPUasync SPU_async;
SPUplayCDDAchannel SPU_playCDDAchannel;
+SPUsetCDvol SPU_setCDvol;
PADconfigure PAD1_configure;
PADabout PAD1_about;
#define LoadSym(dest, src, name, checkerr) { \
dest = (src)SysLoadSym(drv, name); \
- if (checkerr) { CheckErr(name); } else SysLibError(); \
+ if (checkerr) { CheckErr(name); } \
}
void *hGPUDriver = NULL;
static void *hSPUDriver = NULL;\r
static void CALLBACK SPU__registerScheduleCb(void (CALLBACK *cb)(unsigned int)) {}\r
+static void CALLBACK SPU__setCDvol(unsigned char ll, unsigned char lr,
+ unsigned char rl, unsigned char rr, unsigned int cycle) {}
#define LoadSpuSym1(dest, name) \
LoadSym(SPU_##dest, SPU##dest, name, TRUE);
#define LoadSpuSym0(dest, name) \
LoadSym(SPU_##dest, SPU##dest, name, FALSE); \
- if (SPU_##dest == NULL) SPU_##dest = (SPU##dest) SPU__##dest;
+ if (SPU_##dest == NULL) SPU_##dest = SPU__##dest;
#define LoadSpuSymN(dest, name) \
LoadSym(SPU_##dest, SPU##dest, name, FALSE);
LoadSpuSym0(registerScheduleCb, "SPUregisterScheduleCb");
LoadSpuSymN(async, "SPUasync");
LoadSpuSymN(playCDDAchannel, "SPUplayCDDAchannel");
+ LoadSpuSym0(setCDvol, "SPUsetCDvol");
return 0;
}
uint32_t PluginVersion;\r
uint32_t Size;\r
} SPUFreezeHdr_t;\r
-typedef struct {\r
+typedef struct SPUFreeze {\r
unsigned char PluginName[8];\r
uint32_t PluginVersion;\r
uint32_t Size;\r
xa_decode_t xa;\r
unsigned char *unused;\r
} SPUFreeze_t;\r
-typedef long (CALLBACK* SPUfreeze)(uint32_t, SPUFreeze_t *, uint32_t);\r
-typedef void (CALLBACK* SPUasync)(uint32_t, uint32_t);\r
+typedef long (CALLBACK* SPUfreeze)(unsigned int, struct SPUFreeze *, unsigned int);\r
+typedef void (CALLBACK* SPUasync)(unsigned int, unsigned int);\r
typedef int (CALLBACK* SPUplayCDDAchannel)(short *, int, unsigned int, int);\r
+typedef void (CALLBACK* SPUsetCDvol)(unsigned char, unsigned char, unsigned char, unsigned char, unsigned int);\r
\r
// SPU function pointers\r
extern SPUinit SPU_init;\r
extern SPUregisterScheduleCb SPU_registerScheduleCb;\r
extern SPUasync SPU_async;\r
extern SPUplayCDDAchannel SPU_playCDDAchannel;\r
+extern SPUsetCDvol SPU_setCDvol;\r
\r
// PAD Functions\r
typedef long (CALLBACK* PADconfigure)(void);\r
+++ /dev/null
-/***************************************************************************\r
- dma.h - description\r
- -------------------\r
- begin : Wed May 15 2002\r
- copyright : (C) 2002 by Pete Bernert\r
- email : BlackDove@addcom.de\r
- ***************************************************************************/\r
-\r
-/***************************************************************************\r
- * *\r
- * This program is free software; you can redistribute it and/or modify *\r
- * it under the terms of the GNU General Public License as published by *\r
- * the Free Software Foundation; either version 2 of the License, or *\r
- * (at your option) any later version. See also the license.txt file for *\r
- * additional informations. *\r
- * *\r
- ***************************************************************************/\r
-\r
-//*************************************************************************//\r
-// History of changes:\r
-//\r
-// 2002/05/15 - Pete\r
-// - generic cleanup for the Peops release\r
-//\r
-//*************************************************************************//\r
-\r
-#ifndef __P_DMA_H__\r
-#define __P_DMA_H__\r
-\r
-unsigned short CALLBACK SPUreadDMA(void);\r
-void CALLBACK SPUreadDMAMem(unsigned short * pusPSXMem,int iSize);\r
-void CALLBACK SPUwriteDMA(unsigned short val);\r
-void CALLBACK SPUwriteDMAMem(unsigned short * pusPSXMem,int iSize);\r
-\r
-#endif /* __P_DMA_H__ */\r
\r
///////////////////////////////////////////////////////////\r
\r
-// Tmp Flags\r
-\r
-// used for debug channel muting\r
-#define FLAG_MUTE 1\r
-\r
-// used for simple interpolation\r
-#define FLAG_IPOL0 2\r
-#define FLAG_IPOL1 4\r
-\r
-///////////////////////////////////////////////////////////\r
-\r
// MAIN CHANNEL STRUCT\r
typedef struct\r
{\r
int iLeftXAVol;\r
int iRightXAVol;\r
\r
+ struct { // channel volume in the cd controller\r
+ unsigned char ll, lr, rl, rr; // see cdr.Attenuator* in cdrom.c\r
+ } cdv; // applied on spu side for easier emulation\r
+\r
unsigned int last_keyon_cycles;\r
\r
union {\r
\r
#endif\r
\r
+void FeedXA(const xa_decode_t *xap);\r
+void FeedCDDA(unsigned char *pcm, int nBytes);\r
+\r
#endif /* __P_SOUND_EXTERNALS_H__ */\r
ADSRInfoEx_orig ADSRX; // next ADSR settings (will be moved to active on sample start)\r
} SPUCHAN_orig;\r
\r
-typedef struct\r
+typedef struct SPUFreeze\r
{\r
char szSPUName[8];\r
uint32_t ulFreezeVersion;\r
// SPUFREEZE: called by main emu on savestate load/save\r
////////////////////////////////////////////////////////////////////////\r
\r
-long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,\r
- uint32_t cycles)\r
+long CALLBACK SPUfreeze(unsigned int ulFreezeMode, SPUFreeze_t * pF,\r
+ unsigned int cycles)\r
{\r
SPUOSSFreeze_t * pFO = NULL;\r
int i;\r
int y0, y1;\r
} ADPCM_Decode_t;\r
\r
-typedef struct\r
+typedef struct xa_decode\r
{ \r
int freq;\r
int nbits;\r
#include "registers.h"
#include "out.h"
#include "spu_config.h"
+#include "spu.h"
#ifdef __arm__
#include "arm_features.h"
mix_chan(spu.SSumLR, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume);
}
- MixXA(spu.SSumLR, RVB, ns_to, spu.decode_pos);
+ MixCD(spu.SSumLR, RVB, ns_to, spu.decode_pos);
if (spu.rvb->StartAddr) {
if (do_rvb)
work = &worker->i[worker->i_reaped & WORK_I_MASK];
thread_work_wait_sync(work, force);
- MixXA(work->SSumLR, RVB, work->ns_to, work->decode_pos);
+ MixCD(work->SSumLR, RVB, work->ns_to, work->decode_pos);
do_samples_finish(work->SSumLR, work->ns_to,
work->channels_silent, work->decode_pos);
// XA AUDIO
-void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int unused)
+void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int is_start)
{
if(!xap) return;
if(!xap->freq) return; // no xa freq ? bye
+ if (is_start)
+ spu.XAPlay = spu.XAFeed = spu.XAStart;
if (spu.XAPlay == spu.XAFeed)
do_samples(cycle, 1); // catch up to prevent source underflows later
return 0;
}
+void CALLBACK SPUsetCDvol(unsigned char ll, unsigned char lr,
+ unsigned char rl, unsigned char rr, unsigned int cycle)
+{
+ if (spu.XAPlay != spu.XAFeed || spu.CDDAPlay != spu.CDDAFeed)
+ do_samples(cycle, 1);
+ spu.cdv.ll = ll;
+ spu.cdv.lr = lr;
+ spu.cdv.rl = rl;
+ spu.cdv.rr = rr;
+}
+
// to be called after state load
void ClearWorkingState(void)
{
#ifndef __P_SPU_H__\r
#define __P_SPU_H__\r
\r
-#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\r
-#define HTOLE16(x) __builtin_bswap16(x)\r
-#define LE16TOH(x) __builtin_bswap16(x)\r
-#else\r
-#define HTOLE16(x) (x)\r
-#define LE16TOH(x) (x)\r
-#endif\r
+struct SPUFreeze;\r
+struct xa_decode;\r
\r
-void ClearWorkingState(void);\r
-void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int is_start);\r
+long CALLBACK SPUopen(void);\r
+long CALLBACK SPUinit(void);\r
+long CALLBACK SPUshutdown(void);\r
+long CALLBACK SPUclose(void);\r
+void CALLBACK SPUwriteRegister(unsigned long, unsigned short, unsigned int);\r
+unsigned short CALLBACK SPUreadRegister(unsigned long, unsigned int);\r
+void CALLBACK SPUregisterCallback(void (*cb)(int));\r
+void CALLBACK SPUregisterScheduleCb(void (*cb)(unsigned int));\r
+long CALLBACK SPUfreeze(unsigned int, struct SPUFreeze *, unsigned int);\r
+void CALLBACK SPUasync(unsigned int, unsigned int);\r
+\r
+void CALLBACK SPUreadDMAMem(unsigned short * pusPSXMem,int iSize,unsigned int cycles);\r
+void CALLBACK SPUwriteDMAMem(unsigned short * pusPSXMem,int iSize,unsigned int cycles);\r
+\r
+void CALLBACK SPUplayADPCMchannel(struct xa_decode *xap, unsigned int cycle, int is_start);\r
int CALLBACK SPUplayCDDAchannel(short *pcm, int bytes, unsigned int cycle, int is_start);\r
-void FeedXA(const xa_decode_t *xap);\r
-void FeedCDDA(unsigned char *pcm, int nBytes);\r
+void CALLBACK SPUsetCDvol(unsigned char ll, unsigned char lr,\r
+ unsigned char rl, unsigned char rr, unsigned int cycle);\r
+\r
+// internal\r
+void ClearWorkingState(void);\r
\r
#endif /* __P_SPU_H__ */\r
#define INLINE static inline
#endif
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define HTOLE16(x) __builtin_bswap16(x)
+#define LE16TOH(x) __builtin_bswap16(x)
+#else
+#define HTOLE16(x) (x)
+#define LE16TOH(x) (x)
+#endif
+
#include "psemuxa.h"
#endif /* __P_STDAFX_H__ */
// MIX XA & CDDA
////////////////////////////////////////////////////////////////////////
-INLINE void MixXA(int *SSumLR, int *RVB, int ns_to, int decode_pos)
+INLINE void SkipCD(int ns_to, int decode_pos)
{
int cursor = decode_pos;
int ns;
- short l, r;
+
+ if(spu.XAPlay != spu.XAFeed)
+ {
+ for(ns = 0; ns < ns_to*2; ns += 2)
+ {
+ if(spu.XAPlay != spu.XAFeed) spu.XAPlay++;
+ if(spu.XAPlay == spu.XAEnd) spu.XAPlay=spu.XAStart;
+
+ spu.spuMem[cursor] = 0;
+ spu.spuMem[cursor + 0x400/2] = 0;
+ cursor = (cursor + 1) & 0x1ff;
+ }
+ }
+ else if(spu.CDDAPlay != spu.CDDAFeed)
+ {
+ for(ns = 0; ns < ns_to*2; ns += 2)
+ {
+ if(spu.CDDAPlay != spu.CDDAFeed) spu.CDDAPlay++;
+ if(spu.CDDAPlay == spu.CDDAEnd) spu.CDDAPlay=spu.CDDAStart;
+
+ spu.spuMem[cursor] = 0;
+ spu.spuMem[cursor + 0x400/2] = 0;
+ cursor = (cursor + 1) & 0x1ff;
+ }
+ }
+ spu.XALastVal = 0;
+}
+
+INLINE void MixCD(int *SSumLR, int *RVB, int ns_to, int decode_pos)
+{
+ int vll = spu.iLeftXAVol * spu.cdv.ll >> 7;
+ int vrl = spu.iLeftXAVol * spu.cdv.rl >> 7;
+ int vlr = spu.iRightXAVol * spu.cdv.lr >> 7;
+ int vrr = spu.iRightXAVol * spu.cdv.rr >> 7;
+ int cursor = decode_pos;
+ int l1, r1, l, r;
+ int ns;
uint32_t v = spu.XALastVal;
+ if ((vll | vlr | vrl | vrr) == 0)
+ {
+ SkipCD(ns_to, decode_pos);
+ return;
+ }
+
if(spu.XAPlay != spu.XAFeed || spu.XARepeat > 0)
{
if(spu.XAPlay == spu.XAFeed)
if(spu.XAPlay != spu.XAFeed) v=*spu.XAPlay++;
if(spu.XAPlay == spu.XAEnd) spu.XAPlay=spu.XAStart;
- l = ((int)(short)v * spu.iLeftXAVol) >> 15;
- r = ((int)(short)(v >> 16) * spu.iLeftXAVol) >> 15;
+ l1 = (short)v, r1 = (short)(v >> 16);
+ l = (l1 * vll + r1 * vrl) >> 15;
+ r = (r1 * vrr + l1 * vlr) >> 15;
+ ssat32_to_16(l);
+ ssat32_to_16(r);
if (spu.spuCtrl & CTRL_CD)
{
SSumLR[ns+0] += l;
if(spu.CDDAPlay != spu.CDDAFeed) v=*spu.CDDAPlay++;
if(spu.CDDAPlay == spu.CDDAEnd) spu.CDDAPlay=spu.CDDAStart;
- l = ((int)(short)v * spu.iLeftXAVol) >> 15;
- r = ((int)(short)(v >> 16) * spu.iLeftXAVol) >> 15;
+ l1 = (short)v, r1 = (short)(v >> 16);
+ l = (l1 * vll + r1 * vrl) >> 15;
+ r = (r1 * vrr + l1 * vlr) >> 15;
+ ssat32_to_16(l);
+ ssat32_to_16(r);
if (spu.spuCtrl & CTRL_CD)
{
SSumLR[ns+0] += l;
{
}
+void CALLBACK SPUsetCDvol(unsigned char ll, unsigned char lr,
+ unsigned char rl, unsigned char rr, unsigned int cycle)
+{
+}
+
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////