From d5bc5099d150ae3b974a7e350e12cc2836dff7a4 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Wed, 11 Feb 2009 07:20:14 +0000 Subject: [PATCH] SPU2ghz: Significant overhaul of the volume system! Volumes for most games should be much more accurate now, and distortion greatly reduced. This is still a work-in-progress, and I intend to follow up with another commit soon that should improve performance in a few areas, improve overall audio quality and (hopefully!) fix up the Special Effects system as well. Pcsx2: This time the Pg icon really has been replaced/reverted to the original (dunno why my last attempt didn't commit, oh well). Also improved the syntax of the SourceLogs; fixing if/else statement scoping problems. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@470 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/DebugTools/Debug.h | 116 +++---- pcsx2/Sio.cpp | 1 + pcsx2/SourceLog.cpp | 3 +- pcsx2/windows/Cdrom02.ico | Bin 12862 -> 12862 bytes plugins/spu2ghz/src/debug.h | 39 ++- plugins/spu2ghz/src/interface.cpp | 23 +- plugins/spu2ghz/src/mixer.cpp | 452 ++++++++++++++------------- plugins/spu2ghz/src/savestate.cpp | 2 +- plugins/spu2ghz/src/sndout.cpp | 9 +- plugins/spu2ghz/src/sndout.h | 2 +- plugins/spu2ghz/src/spu2.cpp | 156 +++++---- plugins/spu2ghz/src/spu2.h | 2 +- plugins/spu2ghz/src/wavedump_wav.cpp | 230 +++++--------- 13 files changed, 508 insertions(+), 527 deletions(-) diff --git a/pcsx2/DebugTools/Debug.h b/pcsx2/DebugTools/Debug.h index 188e2f017c..919b7f60c5 100644 --- a/pcsx2/DebugTools/Debug.h +++ b/pcsx2/DebugTools/Debug.h @@ -78,72 +78,72 @@ extern u32 varLog; void SourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fmt, ...); void __Log( const char* fmt, ... ); -extern void SrcLog_CPU( const char* fmt, ... ); -extern void SrcLog_COP0( const char* fmt, ... ); -extern void SrcLog_FPU( const char* fmt, ... ); -extern void SrcLog_MMI( const char* fmt, ... ); +extern bool SrcLog_CPU( const char* fmt, ... ); +extern bool SrcLog_COP0( const char* fmt, ... ); +extern bool SrcLog_FPU( const char* fmt, ... ); +extern bool SrcLog_MMI( const char* fmt, ... ); -extern void SrcLog_MEM( const char* fmt, ... ); -extern void SrcLog_HW( const char* fmt, ... ); -extern void SrcLog_DMA( const char* fmt, ... ); -extern void SrcLog_BIOS( const char* fmt, ... ); -extern void SrcLog_ELF( const char* fmt, ... ); -extern void SrcLog_VU0( const char* fmt, ... ); +extern bool SrcLog_MEM( const char* fmt, ... ); +extern bool SrcLog_HW( const char* fmt, ... ); +extern bool SrcLog_DMA( const char* fmt, ... ); +extern bool SrcLog_BIOS( const char* fmt, ... ); +extern bool SrcLog_ELF( const char* fmt, ... ); +extern bool SrcLog_VU0( const char* fmt, ... ); -extern void SrcLog_VIF( const char* fmt, ... ); -extern void SrcLog_SPR( const char* fmt, ... ); -extern void SrcLog_GIF( const char* fmt, ... ); -extern void SrcLog_SIF( const char* fmt, ... ); -extern void SrcLog_IPU( const char* fmt, ... ); -extern void SrcLog_VUM( const char* fmt, ... ); -extern void SrcLog_RPC( const char* fmt, ... ); -extern void SrcLog_EECNT( const char* fmt, ... ); +extern bool SrcLog_VIF( const char* fmt, ... ); +extern bool SrcLog_SPR( const char* fmt, ... ); +extern bool SrcLog_GIF( const char* fmt, ... ); +extern bool SrcLog_SIF( const char* fmt, ... ); +extern bool SrcLog_IPU( const char* fmt, ... ); +extern bool SrcLog_VUM( const char* fmt, ... ); +extern bool SrcLog_RPC( const char* fmt, ... ); +extern bool SrcLog_EECNT( const char* fmt, ... ); -extern void SrcLog_PSXCPU( const char* fmt, ... ); -extern void SrcLog_PSXMEM( const char* fmt, ... ); -extern void SrcLog_PSXHW( const char* fmt, ... ); -extern void SrcLog_PSXBIOS( const char* fmt, ... ); -extern void SrcLog_PSXDMA( const char* fmt, ... ); -extern void SrcLog_PSXCNT( const char* fmt, ... ); +extern bool SrcLog_PSXCPU( const char* fmt, ... ); +extern bool SrcLog_PSXMEM( const char* fmt, ... ); +extern bool SrcLog_PSXHW( const char* fmt, ... ); +extern bool SrcLog_PSXBIOS( const char* fmt, ... ); +extern bool SrcLog_PSXDMA( const char* fmt, ... ); +extern bool SrcLog_PSXCNT( const char* fmt, ... ); -extern void SrcLog_MEMCARDS( const char* fmt, ... ); -extern void SrcLog_PAD( const char* fmt, ... ); -extern void SrcLog_GTE( const char* fmt, ... ); -extern void SrcLog_CDR( const char* fmt, ... ); -extern void SrcLog_GPU( const char* fmt, ... ); +extern bool SrcLog_MEMCARDS( const char* fmt, ... ); +extern bool SrcLog_PAD( const char* fmt, ... ); +extern bool SrcLog_GTE( const char* fmt, ... ); +extern bool SrcLog_CDR( const char* fmt, ... ); +extern bool SrcLog_GPU( const char* fmt, ... ); -#define CPU_LOG if (varLog & 0x00000001) SrcLog_CPU -#define MEM_LOG if (varLog & 0x00000002) SrcLog_MEM -#define HW_LOG if (varLog & 0x00000004) SrcLog_HW -#define DMA_LOG if (varLog & 0x00000008) SrcLog_DMA -#define BIOS_LOG if (varLog & 0x00000010) SrcLog_BIOS -#define ELF_LOG if (varLog & 0x00000020) SrcLog_ELF -#define FPU_LOG if (varLog & 0x00000040) SrcLog_FPU -#define MMI_LOG if (varLog & 0x00000080) SrcLog_MMI -#define VU0_LOG if (varLog & 0x00000100) SrcLog_VU0 -#define COP0_LOG if (varLog & 0x00000200) SrcLog_COP0 -#define VIF_LOG if (varLog & 0x00000400) SrcLog_VIF -#define SPR_LOG if (varLog & 0x00000800) SrcLog_SPR -#define GIF_LOG if (varLog & 0x00001000) SrcLog_GIF -#define SIF_LOG if (varLog & 0x00002000) SrcLog_SIF -#define IPU_LOG if (varLog & 0x00004000) SrcLog_IPU -#define VUM_LOG if (varLog & 0x00008000) SrcLog_VUM -#define RPC_LOG if (varLog & 0x00010000) SrcLog_RPC -#define EECNT_LOG if (varLog & 0x40000000) SrcLog_EECNT +#define CPU_LOG (varLog & 0x00000001) && SrcLog_CPU +#define MEM_LOG (varLog & 0x00000002) && SrcLog_MEM +#define HW_LOG (varLog & 0x00000004) && SrcLog_HW +#define DMA_LOG (varLog & 0x00000008) && SrcLog_DMA +#define BIOS_LOG (varLog & 0x00000010) && SrcLog_BIOS +#define ELF_LOG (varLog & 0x00000020) && SrcLog_ELF +#define FPU_LOG (varLog & 0x00000040) && SrcLog_FPU +#define MMI_LOG (varLog & 0x00000080) && SrcLog_MMI +#define VU0_LOG (varLog & 0x00000100) && SrcLog_VU0 +#define COP0_LOG (varLog & 0x00000200) && SrcLog_COP0 +#define VIF_LOG (varLog & 0x00000400) && SrcLog_VIF +#define SPR_LOG (varLog & 0x00000800) && SrcLog_SPR +#define GIF_LOG (varLog & 0x00001000) && SrcLog_GIF +#define SIF_LOG (varLog & 0x00002000) && SrcLog_SIF +#define IPU_LOG (varLog & 0x00004000) && SrcLog_IPU +#define VUM_LOG (varLog & 0x00008000) && SrcLog_VUM +#define RPC_LOG (varLog & 0x00010000) && SrcLog_RPC +#define EECNT_LOG (varLog & 0x40000000) && SrcLog_EECNT -#define PSXCPU_LOG if (varLog & 0x00100000) SrcLog_PSXCPU -#define PSXMEM_LOG if (varLog & 0x00200000) SrcLog_PSXMEM -#define PSXHW_LOG if (varLog & 0x00400000) SrcLog_PSXHW -#define PSXBIOS_LOG if (varLog & 0x00800000) SrcLog_PSXBIOS -#define PSXDMA_LOG if (varLog & 0x01000000) SrcLog_PSXDMA -#define PSXCNT_LOG if (varLog & 0x20000000) SrcLog_PSXCNT +#define PSXCPU_LOG (varLog & 0x00100000) && SrcLog_PSXCPU +#define PSXMEM_LOG (varLog & 0x00200000) && SrcLog_PSXMEM +#define PSXHW_LOG (varLog & 0x00400000) && SrcLog_PSXHW +#define PSXBIOS_LOG (varLog & 0x00800000) && SrcLog_PSXBIOS +#define PSXDMA_LOG (varLog & 0x01000000) && SrcLog_PSXDMA +#define PSXCNT_LOG (varLog & 0x20000000) && SrcLog_PSXCNT //memcard has the same number as PAD_LOG for now -#define MEMCARDS_LOG if (varLog & 0x02000000) SrcLog_MEMCARDS -#define PAD_LOG if (varLog & 0x02000000) SrcLog_PAD -#define GTE_LOG if (varLog & 0x04000000) SrcLog_GTE -#define CDR_LOG if (varLog & 0x08000000) SrcLog_CDR -#define GPU_LOG if (varLog & 0x10000000) SrcLog_GPU +#define MEMCARDS_LOG (varLog & 0x02000000) && SrcLog_MEMCARDS +#define PAD_LOG (varLog & 0x02000000) && SrcLog_PAD +#define GTE_LOG (varLog & 0x04000000) && SrcLog_GTE +#define CDR_LOG (varLog & 0x08000000) && SrcLog_CDR +#define GPU_LOG (varLog & 0x10000000) && SrcLog_GPU // fixme - currently we don't log cache #define CACHE_LOG 0&& diff --git a/pcsx2/Sio.cpp b/pcsx2/Sio.cpp index 9c8527d57e..35f3c9ae30 100644 --- a/pcsx2/Sio.cpp +++ b/pcsx2/Sio.cpp @@ -67,6 +67,7 @@ u8 sio_xor(u8 *buf, uint length){ void sioInit() { memzero_obj(sio); + memzero_obj(m_PostSavestateCards); // Transfer(?) Ready and the Buffer is Empty sio.StatReg = TX_RDY | TX_EMPTY; diff --git a/pcsx2/SourceLog.cpp b/pcsx2/SourceLog.cpp index c008e9f0f6..d9d1cd649a 100644 --- a/pcsx2/SourceLog.cpp +++ b/pcsx2/SourceLog.cpp @@ -129,7 +129,7 @@ void SourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fm // Functions with variable argument lists can't be inlined. #define IMPLEMENT_SOURCE_LOG( unit, source, protocol ) \ - void SrcLog_##unit( const char* fmt, ... ) \ + bool SrcLog_##unit( const char* fmt, ... ) \ { \ va_list list; \ va_start( list, fmt ); \ @@ -137,6 +137,7 @@ void SourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fm (source == 'E') ? cpuRegs.pc : psxRegs.pc, \ (source == 'E') ? cpuRegs.cycle : psxRegs.cycle, fmt, list ); \ va_end( list ); \ + return false; \ } \ IMPLEMENT_SOURCE_LOG( EECNT, 'E', 0 ) diff --git a/pcsx2/windows/Cdrom02.ico b/pcsx2/windows/Cdrom02.ico index 0fa4d2be80454316c894473ddb00499949a2f8cc..07588baeaa79ee6acf726e73fb70937a1dadb53e 100644 GIT binary patch literal 12862 zcmeHO>(f_d75()kE6fWRf~lFNF^(DOq=`*Kw`shE;~15usFWItiKUlh5G4rAsI13nq&$ zn@r|UCX+?@0X6v}e#pl+Z_Z@GpZM&fNB+m_Vf!fR*u$m*15oqCk91@z8&FR0H|bl| zGOhS`>uYo?WsSjTl)mm*9sL9ASabl@Ael04Q_M%>@V@}*mLN@zp2+#=?`^t{4Us7; z+lSgi@Y9E4*rBgaD%@O2+>rI_S{1<>I|3{31P^gM5+kw5H4z{*$^&HymP&VnVe$ol z30pEQDCf#hy~}MlD35M&SjK$rK~MXj%>+0i0MD9f$Tc=2!L$a93If+qDY1H*pfTXMX2}`~d1=YTogYDW=>WM?bI)WwDBp?>0|YOe@Y9e)8c1*41j8dBA2? zlS#m>^PSAMASpxd>+3_{_A318nYIGy<5#?OMh;4qFY*-^d~mS7AHiYsj!<={!JNuMNXg%|ax_u3h-1fyX5lJ`S$}?Am^yg?B52ct&9imH+&&l&{ zJM-1295POulfRL(t)eH+B$fbsmdxeHpX{wCBrC5305)S z58P=7Rd?6{uY>4d?qHRz<1ylUj4B=@MMx&R(+=Ej`%x zJQ09k;p5yXS;#Ya9Bn;{CnDAzM z`)2kmjY$&xjG9qCrt;SjAR}c|fVXa9z3n{##%X3Se|@f#Jj_+{04l9g0MM+OlSWye zzj>p*xy;_Wkwpx!tN@K;XdfV@hdT!9(~WHw zAd63!)6=WdD?ln8C|D7@ZR)k!dyTz*jqSbG0En;UNJgWtG!EuZB^>gQCT^Hpt=J`V zL8p&bq}Q#&$d))t!L$YW+D}-odl#PW+79NQ{WfiDka+gn=@^6hSAT4%SG>RaBSRG| z9!#tT^MBGLUsnbMi);XeMDicl9@Gz6uS8FP6|oCG>8OMLy=(~MNfb%_uirP;Qq~?- zjP(lJQ9fkY6A2NoLugvWxJQy?yKx2^d)5kiIIh^YRM?^{dG^GkV>dj>MwrBUcAzFU&%gujq(e0k&x4) zmL6$e__nE@50K2q%Qv>oh}Q?d7p`DDWy^#KxVqeSUC#deWvmW6zsnhQZ41U$VqD1q zW8yF*6MQ~|Cu$Qu?GA(axm5M^fs z^J&AfT|5|{k#xd%`IbnJ{oFV0xl6qgXso+d=qjv2yfXkyc21v&$*bzHJgO@<8T z7pv!#;n_=U$0hdcH@pJuzzD2SpfBUetOY?pKkQuOF(hJi%6Ok?pEB{OKOPv&pKix9-@eFD+q|}aJwPzx(V-dT+oniE!4&(Mi|m;TjlC{0 z6~FDGQR0_WcpdT7ducDUr!TOlzZP9U3~;|j`30H`z0q?%b-q3IRo0W|v&tw?b*x7D zn5V9Y%FNDh{fa$_I?uMAR{$^=junG(lrOW@d4S6ZaIS4RxAZON*jAOubGYKx!6^9| zDFS3pG7;>FvyJuTD2->^7BJ$0eHgf$7clr(6>YoME7Jv4Z8fUgXNRkIl2XHqEn5bIAZ?7vL(y1Lml1ldWZ%SEk1~wr-9e;ubjidgn0`fb;@R zzKFGQ4PTcGUFWWEPh=Q^V&05$2*WN|-YVD}Tl)ppI&@(OG&&Em9*Oe=pxMTXo?3aA zzYa^!=lm_k%aaIGzpIcXVJP*)+Rs~4k4`ZVh|E=j!P{nA-vT#VITRAvre3elbDJiQ ze$G&9y$cUADOh_F^{fC~1)jdm!*X?^hf+3p*pL|ibP@{znoj<+Wh)Iv$;ybUis7$N n`PAcpb11c{#lWfW9typ-^%X;YTBH31;@<&$`v3pWzreo$+!n*^ literal 12862 zcmeHO+mcn)747^)DsOx3H=pwbep*oEB7}>82pUa{5)kAnAP4~z1VqSp(5L&H)A!T7 zm~okF?X`hjCDqkcR3$K3HP)D8jycw*d1P+x5BUA=yK^}IH22P*=jQ%6H#heV{(zeM z3;vKF`t|%jE$dl&{tPE@0p{bJr^bTn#FY8y@;XnMc#wtnZ0+!@rKk0l6+HoC(8{fP zQOF?h_8j0-bH? zK4#Yfj#&0M#mM7S2E$N;*-%}ZLy1?!cq=Qt0_F%%oC8={jbpafIP)XsiFl9N(W5kv zLN;J61;BMaU+b0z=|8f7)9caR--?s3JTa<17VM#)UB+dDqnfzyzk~j~q3LICr zOj@6rBB)1bMZ|`87D+B;tOI950<>7dxuWj?{zP{|u=3HTt z=G+42Zo7yR&UcB)7#Bc+_EMY{sgYqP)6`v)#U%HTjB#>?2C{+?l&1^f=c9wFxTS|2SqQ^Q?e zh-;r3FG4AS#AV7R8n=nvZuh=JjBvci*Zwuuu96BMucJ9lU^xCEp&03hb`gLl ztM;ieS{hMQ>+xg)`0(v=3oyRb%SmU7dDfmo7&5wHBjRP}*v=T*ax*R7NMoEgTL9zn z%|U;(pd8=8i78@U$?%F(R~o8%KHfsvuz&p)uDAg)troR0cF{qBDUjy-H2%I_#0kA{ z?NeiRJrZZ=Jp~gNt%P4c%dU2n?F1r=e*i1(ma;9yi{5ozt?TU=;CegZ$*T9(7_CW& zskgX0>1jS%FU?AcR&=$_*IGEm`8~f8DI++SwNCWzDrSP0cWPpTw^+L zgs;wGn8+tuX*d!Jm1B<=SzZbOTlS}{v(iXj+uI!A}SQKY&fjQq!&!?sH04gN8Fr5E<8%oH^2!XGKgbDHQ$vLE< z1HX(*xZ4PG)wgNtI+vEdZGo3`9rA<*f~9kqqIim_b7XK8U%Ip zY+p91Jwx9ug7}+$ooUSs=0B5`vnFQGWCs9taSfABpcbzMW~4>zFJE6<*|ipLr)*BxfMN2_)9T-JR$%4xw=O?IB9+swl)zvV|TVwu}6>y+t z=x5KK%o$cP#Pvj4J<+V5FaTzege;TNXs{wJLvk8Qxptxn<*Qdb$If~hM>rLG39`vh zevOB}Rtsb5lTr=vy06EHUth=58oD?`P^K!9f}X>=ubNu#&OAa-tv){d{Xeld+a7On z)U^I_T8nCE{xKMegExSlK*1memQrGmR3>sOwj6XqIgrP5Vxwl&rPXl$Sce#SFqmV_ zIxDRmYu1h>0AXBvIA5u(^z}9Ll|wj7Z*!iq@EIN{y=jhemHF$ZZ-}l0iU?Kc+Eu( z_@dVp3~QY{TR3$!>Dge|I%K_-zy%cjV19>;kwe|Cjf1j1luuj_rj0{`K11JUyLrC7 zt7aWf;8kf4B);NcGc(Y+-Fe>Be};qzc0eb-u!~HZ{gt)BYIO4YrvBTlXSM^4bC$F- zko%k2{-gpX5YudTo;UR`A!qxUlOY{`Uz+V}X8Y0x3&8dEegDYGs49bIb8nh`*v$4e zvk%iIfNSqtmml$vO$ilPSEk*QHW41Lz_~|Pop1X0yWRT8xd%BDb278i?oOL1CnrcV zGR=19c~gIcob6^{K4f>Jz&e55B4}p2n$2Aep5RviQ!EX;eykZO`F31)=_3FWNWUx1 zgt1g6nP=A{g~yck(w|)qmQ;}>1}T<92H4^xAEZrGxe}=LfflhPz_VbDKwu5{aInDF zGL-?v5R?*MNV;KAo`H46-XOC%8MSr_?95X;n-?#Sr%iMr3yqao4>9?g^fkTcCE=DA z-qqtFbCT@fEuqXIdyzUl4WnevoQ~SO*l9-bq$y&w;yHLMWkuPEZHtlI4O{TVC$BbR zpJG)fDIpC)!x-U7HfTenAm}mv;G3!f>X|ROR+_}3eI|McZ_`I zmX~G|grq>F)rzg;Zuu2#`9+m;kPKW^o-Kng4{QgC`F#vLs~9i)6tWuZX*`=9cBG;I M7w~`nf8z`M7kSCVjsO4v diff --git a/plugins/spu2ghz/src/debug.h b/plugins/spu2ghz/src/debug.h index 724a4e94c0..b6d29e837a 100644 --- a/plugins/spu2ghz/src/debug.h +++ b/plugins/spu2ghz/src/debug.h @@ -26,11 +26,42 @@ void ConLog(const char *fmt, ...); void DoFullDump(); -extern int wavedump_ok; +namespace WaveDump +{ + enum CoreSourceType + { + // Core's input stream, usually pulled from ADMA streams. + CoreSrc_Input = 0 -int wavedump_open(); -void wavedump_close(); -void wavedump_write(s16 left,s16 right); + // Output of the actual 24 input voices which have dry output enabled. + , CoreSrc_DryVoiceMix + // Output of the actual 24 input voices that have wet output enabled. + , CoreSrc_WetVoiceMix + + // Wet mix including inputs and externals, prior to the application of reverb. + , CoreSrc_PreReverb + + // Wet mix after reverb has turned it into a pile of garbly gook. + , CoreSrc_PostReverb + + // Final output of the core. For core 0, it's the feed into Core1. + // For Core1, it's the feed into SndOut. + , CoreSrc_External + + , CoreSrc_Count + }; + + void Open(); + void Close(); + void WriteCore( uint coreidx, CoreSourceType src, s16 left, s16 right ); +} + +using WaveDump::CoreSrc_Input; +using WaveDump::CoreSrc_DryVoiceMix; +using WaveDump::CoreSrc_WetVoiceMix; +using WaveDump::CoreSrc_PreReverb; +using WaveDump::CoreSrc_PostReverb; +using WaveDump::CoreSrc_External; #endif // DEBUG_H_INCLUDED // diff --git a/plugins/spu2ghz/src/interface.cpp b/plugins/spu2ghz/src/interface.cpp index 7378fb21fb..b1b0f15ba3 100644 --- a/plugins/spu2ghz/src/interface.cpp +++ b/plugins/spu2ghz/src/interface.cpp @@ -180,14 +180,6 @@ EXPORT_C_(s32) SPU2init() DMALogOpen(); - if(WaveLog()) - { - if(!wavedump_open()) - { - SysMessage("Can't open '%s'.\nWave Log disabled.",WaveLogFileName); - } - } - for(v=0;v<16384;v++) { logvolume[v]=(s32)(s32)floor(log((double)(v+1))*3376.7); @@ -236,6 +228,8 @@ EXPORT_C_(s32) SPU2open(void *pDsp) spdif_init(); DspLoadLibrary(dspPlugin,dspPluginModule); + + WaveDump::Open(); return 0; } @@ -280,7 +274,7 @@ EXPORT_C_(void) SPU2shutdown() fclose(el0); fclose(el1); #endif - if(WaveLog() && wavedump_ok) wavedump_close(); + WaveDump::Close(); DMALogClose(); @@ -452,18 +446,9 @@ EXPORT_C_(int) SPU2setupRecording(int start, void* pData) if( disableFreezes ) return 0; if(start==0) - { - //stop recording RecordStop(); - if(recording==0) - return 1; - } else if(start==1) - { - //start recording RecordStart(); - if(recording!=0) - return 1; - } + return 0; } diff --git a/plugins/spu2ghz/src/mixer.cpp b/plugins/spu2ghz/src/mixer.cpp index 76fa7ec287..4a90da9299 100644 --- a/plugins/spu2ghz/src/mixer.cpp +++ b/plugins/spu2ghz/src/mixer.cpp @@ -25,11 +25,17 @@ // #include "spu2.h" -#include -#include #include #include "lowpass.h" +#undef min +#undef max + +#include + +using std::min; +using std::max; + extern void spdif_update(); void ADMAOutLogWrite(void *lpData, u32 ulSize); @@ -39,19 +45,54 @@ extern void VoiceStop(int core,int vc); double pow_2_31 = pow(2.0,31.0); LPF_data L,R; - extern u32 core; - u32 core, voice; - extern u8 callirq; - double srate_pv=1.0; -extern u32 PsxRates[160]; - static const s32 ADSR_MAX_VOL = 0x7fffffff; +static const s32 f[5][2] = +{ + { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 } +}; + +static const int InvExpOffsets[] = { 0,4,6,8,9,10,11,12 }; + +static u32 PsxRates[160]; +/*= +{ + + //for +Lin: PsxRates[value+8] + //for -Lin: PsxRates[value+7] + + 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, + 0xD744FCCB,0xB504F334,0x9837F052,0x80000000,0x6BA27E65,0x5A82799A,0x4C1BF829,0x40000000, + 0x35D13F33,0x2D413CCD,0x260DFC14,0x20000000,0x1AE89F99,0x16A09E66,0x1306FE0A,0x10000000, + 0x0D744FCD,0x0B504F33,0x09837F05,0x08000000,0x06BA27E6,0x05A8279A,0x04C1BF83,0x04000000, + 0x035D13F3,0x02D413CD,0x0260DFC1,0x02000000,0x01AE89FA,0x016A09E6,0x01306FE1,0x01000000, + 0x00D744FD,0x00B504F3,0x009837F0,0x00800000,0x006BA27E,0x005A827A,0x004C1BF8,0x00400000, + 0x0035D13F,0x002D413D,0x00260DFC,0x00200000,0x001AE8A0,0x0016A09E,0x001306FE,0x00100000, + 0x000D7450,0x000B504F,0x0009837F,0x00080000,0x0006BA28,0x0005A828,0x0004C1C0,0x00040000, + 0x00035D14,0x0002D414,0x000260E0,0x00020000,0x0001AE8A,0x00016A0A,0x00013070,0x00010000, + 0x0000D745,0x0000B505,0x00009838,0x00008000,0x00006BA2,0x00005A82,0x00004C1C,0x00004000, + 0x000035D1,0x00002D41,0x0000260E,0x00002000,0x00001AE9,0x000016A1,0x00001307,0x00001000, + 0x00000D74,0x00000B50,0x00000983,0x00000800,0x000006BA,0x000005A8,0x000004C2,0x00000400, + 0x0000035D,0x000002D4,0x00000261,0x00000200,0x000001AF,0x0000016A,0x00000130,0x00000100, + 0x000000D7,0x000000B5,0x00000098,0x00000080,0x0000006C,0x0000005B,0x0000004C,0x00000040, + 0x00000036,0x0000002D,0x00000026,0x00000020,0x0000001B,0x00000017,0x00000013,0x00000010, + 0x0000000D,0x0000000B,0x0000000A,0x00000008,0x00000007,0x00000006,0x00000005,0x00000004, + 0x00000003,0x00000003,0x00000002,0x00000002,0x00000002,0x00000001,0x00000001,0x00000000, + + //128+8 + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, +};*/ + + // Performs a 64-bit multiplication between two values and returns the // high 32 bits as a result (discarding the fractional 32 bits). // The combined fracional bits of both inputs must be 32 bits for this @@ -89,26 +130,16 @@ void InitADSR() // INIT ADSR int shift=(i-32)>>2; s64 rate=(i&3)+4; if (shift<0) - rate>>=-shift; + rate >>= -shift; else - rate<<=shift; + rate <<= shift; - PsxRates[i]=(int)min(rate,0x3fffffff); + PsxRates[i] = (int)min( rate, 0x3fffffffLL ); } } #define VOL(x) (((s32)x)) //24.8 volume -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // - -const s32 f[5][2] ={{ 0, 0 }, - { 60, 0 }, - { 115, -52 }, - { 98, -55 }, - { 122, -60 }}; - static void __forceinline XA_decode_block(s16* buffer, const s16* block, s32& prev1, s32& prev2) { const s32 header = *block; @@ -306,11 +337,16 @@ _skipIncrement: Data = vc.SBuffer[vc.SCurrent++]; } -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // +// Returns the linear slide value for AR and SR inputs. +static int GetLinearSrAr( uint SrAr ) +{ + // The Sr/Ar settings work in quarter steps, which means + // the bottom 2 bits go on the left side of the shift, and + // the right side of the shift gets divided by 4: -const int InvExpOffsets[] = { 0,4,6,8,9,10,11,12 }; + const uint newSr = 0x127 - SrAr; + return (1+(newSr&3)) << (30UL-(newSr>>2)); +} static void __forceinline CalculateADSR( V_Voice& vc ) { @@ -318,17 +354,8 @@ static void __forceinline CalculateADSR( V_Voice& vc ) jASSUME( env.Phase != 0 ); - s32 SLevel = ((s32)env.Sl)<<27; - - jASSUME( SLevel >= 0 ); - - if(env.Releasing) - { - if( env.Phase < 5) - { - env.Phase=5; - } - } + if(env.Releasing && (env.Phase < 5)) + env.Phase = 5; switch (env.Phase) { @@ -340,21 +367,14 @@ static void __forceinline CalculateADSR( V_Voice& vc ) break; } - if (env.Am) // pseudo exponential - { - if (env.Value<0x60000000) // below 75% - { - env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32]; - } - else // above 75% - { - env.Value+=PsxRates[(env.Ar^0x7f)-0x18+32]; - } - } - else // linear - { - env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32]; - } + // Case 1 below is for pseudo exponential below 75%. + // Pseudo Exp > 75% and Linear are the same. + + if (env.Am && (env.Value>=0x60000000)) + env.Value += PsxRates[(env.Ar^0x7f)-0x18+32]; + else if( env.Ar < 0x7f ) + //env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32]; + env.Value += GetLinearSrAr( env.Ar ); if( env.Value < 0 ) { @@ -362,29 +382,37 @@ static void __forceinline CalculateADSR( V_Voice& vc ) env.Phase++; env.Value = ADSR_MAX_VOL; } - - break; + break; case 2: // decay { u32 off = InvExpOffsets[(env.Value>>28)&7]; - env.Value-=PsxRates[((env.Dr^0x1f)<<2)-0x18+off+32]; + env.Value-=PsxRates[((env.Dr^0x1f)*4)-0x18+off+32]; - if(env.Value <= SLevel) + // Clamp decay to SLevel or Zero + if (env.Value < 0) + env.Value = 0; + else { - // Clamp decay to SLevel or Zero - if (env.Value < 0) - env.Value = 0; - else - env.Value = SLevel; + // calculate sustain level by mirroring the bits + // of the sustain var into the lower bits as we shift up + // (total shift, 27 bits) + + u32 suslev = (env.Sl << 4) | env.Sl; + suslev = (suslev << 8) | suslev; // brings us to 12 bits! + suslev = (suslev << 12) | suslev; // 24 bits! - env.Phase++; - } - - break; + if( env.Value <= (suslev<<3) ) + env.Phase++; + } } + break; case 3: // sustain + { + // 0x7f disables sustain (infinite sustain) + if( env.Sr == 0x7f ) return; + if (env.Sm&2) // decreasing { if (env.Sm&4) // exponential @@ -394,8 +422,10 @@ static void __forceinline CalculateADSR( V_Voice& vc ) } else // linear { - env.Value-=PsxRates[(env.Sr^0x7f)-0xf+32]; + //env.Value-=PsxRates[(env.Sr^0x7f)-0xf+32]; + env.Value -= GetLinearSrAr( env.Sr ); } + if( env.Value <= 0 ) { env.Value = 0; @@ -404,22 +434,15 @@ static void __forceinline CalculateADSR( V_Voice& vc ) } else // increasing { - if (env.Sm&4) // pseudo exponential - { - if (env.Value<0x60000000) // below 75% - { - env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32]; - } - else // above 75% - { - env.Value+=PsxRates[(env.Sr^0x7f)-0x18+32]; - } - } + if( (env.Sm&4) && (env.Value>=0x60000000) ) + env.Value+=PsxRates[(env.Sr^0x7f)-0x18+32]; else { - // linear + // linear / Pseudo below 75% (they're the same) + //env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32]; - env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32]; + int newSr = 0x7f-env.Sr; + env.Value += GetLinearSrAr( env.Sr ); } if( env.Value < 0 ) @@ -428,8 +451,8 @@ static void __forceinline CalculateADSR( V_Voice& vc ) env.Phase++; } } - - break; + } + break; case 4: // sustain end env.Value = (env.Sm&2) ? 0 : ADSR_MAX_VOL; @@ -442,11 +465,13 @@ static void __forceinline CalculateADSR( V_Voice& vc ) if (env.Rm) // exponential { u32 off=InvExpOffsets[(env.Value>>28)&7]; - env.Value-=PsxRates[((env.Rr^0x1f)<<2)-0x18+off+32]; + env.Value-=PsxRates[((env.Rr^0x1f)*4)-0x18+off+32]; } else // linear { - env.Value-=PsxRates[((env.Rr^0x1f)<<2)-0xc+32]; + //env.Value-=PsxRates[((env.Rr^0x1f)*4)-0xc+32]; + if( env.Rr != 0x1f ) + env.Value -= 1 << (30UL-env.Rr); } if( env.Value <= 0 ) @@ -454,12 +479,11 @@ static void __forceinline CalculateADSR( V_Voice& vc ) env.Value=0; env.Phase++; } - - break; + break; case 6: // release end env.Value=0; - break; + break; jNO_DEFAULT } @@ -482,7 +506,7 @@ static void __forceinline GetNoiseValues(s32& VD) { static s32 Seed = 0x41595321; - if(Seed&0x100) VD =(s32)((Seed&0xff)<<8); + if(Seed&0x100) VD = (s32)((Seed&0xff)<<8); else if(!(Seed&0xffff)) VD = (s32)0x8000; else VD = (s32)0x7fff; @@ -515,12 +539,11 @@ void LowPass(s32& VL, s32& VR) VR = (s32)(LPF(&R,(VR)/pow_2_31)*pow_2_31); } -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // +// Data is expected to be 16 bit signed (typical stuff!). +// Volume is the SPU2 register value, usually ranged from 0 to 0x7fff. static __forceinline s32 ApplyVolume(s32 data, s32 volume) { - return (volume * data) >> 7; // >> 6 is more correct, but causes a few overflows + return (volume * data) >> 15; } static void __forceinline UpdatePitch( V_Voice& vc ) @@ -532,13 +555,14 @@ static void __forceinline UpdatePitch( V_Voice& vc ) // most of the time. Now it'll just check Modulated and short-circuit past the voice // check (not that it amounts to much, but eh every little bit helps). if( (vc.Modulated==0) || (voice==0) ) - pitch=vc.Pitch; + pitch = vc.Pitch; else - pitch=(vc.Pitch*(32768 + abs(Cores[core].Voices[voice-1].OutX)))>>15; + pitch = (vc.Pitch*(32768 + abs(Cores[core].Voices[voice-1].OutX)))>>15; vc.SP+=pitch; } +// Returns a 16 bit result in Value. static void __forceinline GetVoiceValues_Linear(V_Core& thiscore, V_Voice& vc, s32& Value) { while( vc.SP > 0 ) @@ -560,19 +584,22 @@ static void __forceinline GetVoiceValues_Linear(V_Core& thiscore, V_Voice& vc, s jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative... + // Note! It's very important that ADSR stay as accurate as possible. By the way + // it is used, various sound effects can end prematurely if we truncate more than + // one or two bits. + if(Interpolation==0) { - Value = MulShr32( vc.PV1, vc.ADSR.Value ); + Value = MulShr32( vc.PV1<<1, vc.ADSR.Value ); } else //if(Interpolation==1) //must be linear { s32 t0 = vc.PV2 - vc.PV1; - s32 t1 = vc.PV1; - Value = MulShr32( t1 - ((t0*vc.SP)>>12), vc.ADSR.Value ); + Value = MulShr32( (vc.PV1<<1) - ((t0*vc.SP)>>11), vc.ADSR.Value ); } } - +// Returns a 16 bit result in Value. static void __forceinline GetVoiceValues_Cubic(V_Core& thiscore, V_Voice& vc, s32& Value) { while( vc.SP > 0 ) @@ -582,7 +609,7 @@ static void __forceinline GetVoiceValues_Cubic(V_Core& thiscore, V_Voice& vc, s3 vc.PV2=vc.PV1; GetNextDataBuffered( thiscore, vc, vc.PV1 ); - vc.PV1<<=3; + vc.PV1<<=2; vc.SPc = vc.SP&4095; // just the fractional part, please! vc.SP-=4096; } @@ -608,11 +635,15 @@ static void __forceinline GetVoiceValues_Cubic(V_Core& thiscore, V_Voice& vc, s3 val = ((val + z2) * mu) >> 12; val += vc.PV2; - Value = MulShr32( val, vc.ADSR.Value>>3 ); + // Note! It's very important that ADSR stay as accurate as possible. By the way + // it is used, various sound effects can end prematurely if we truncate more than + // one or two bits. + Value = MulShr32( val, vc.ADSR.Value>>1 ); } -// [Air]: Noise values need to be mixed without going through interpolation, since it -// can wreak havoc on the noise (causing muffling or popping). +// Noise values need to be mixed without going through interpolation, since it +// can wreak havoc on the noise (causing muffling or popping). Not that this noise +// generator is accurate in its own right.. but eh, ah well :) static void __forceinline __fastcall GetNoiseValues(V_Core& thiscore, V_Voice& vc, s32& Data) { while(vc.SP>=4096) @@ -622,10 +653,13 @@ static void __forceinline __fastcall GetNoiseValues(V_Core& thiscore, V_Voice& v } // GetNoiseValues can't set the phase zero on us unexpectedly - // like GetVoiceValues can. Better asster just in case though.. + // like GetVoiceValues can. Better assert just in case though.. jASSUME( vc.ADSR.Phase != 0 ); CalculateADSR( vc ); + + // Yup, ADSR applies even to noise sources... + Data = MulShr32( Data, vc.ADSR.Value ); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -642,7 +676,11 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR) { thiscore.InputPos&=~1; - //CDDA mode + // CDDA mode + // Source audio data is 32 bits. + // We don't yet have the capability to handle this high res input data + // so we just downgrade it to 16 bits for now. + #ifdef PCM24_S1_INTERLEAVE *PDataL=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)))); *PDataR=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)+2))); @@ -653,8 +691,8 @@ void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR) PDataR=*pr; #endif - PDataL>>=4; //give 16.8 data - PDataR>>=4; + PDataL>>=1; //give 31 bit data (SndOut downsamples the rest of the way) + PDataR>>=1; thiscore.InputPos+=2; if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) { @@ -821,11 +859,6 @@ static void __forceinline __fastcall ReadInputPV(V_Core& thiscore, s32& ValL,s32 // Apply volumes: ValL = ApplyVolume( ValL, thiscore.InpL ); ValR = ApplyVolume( ValR, thiscore.InpR ); - - // These make XS2 intro too quiet. - //ValL >>= 1; - //ValR >>= 1; - } ///////////////////////////////////////////////////////////////////////////////////////// @@ -839,72 +872,46 @@ static void __forceinline __fastcall ReadInputPV(V_Core& thiscore, s32& ValL,s32 static void __fastcall UpdateVolume(V_Volume& Vol) { - // TIMINGS ARE FAKE!!! Need to investigate. - - // [Air]: Cleaned up this code... may have broken it. Can't really - // test it here since none of my games seem to use it. If anything's - // not sounding right, we should revert the code in this method first. - - // [Air] Reverse phasing? - // Invert our value so that exponential mathematics are applied - // as if the volume were sliding the other direction. This makes - // a lot more sense than the old method's likeliness to chop off - // sound volumes to zero abruptly. - - if(Vol.Mode & VOLFLAG_REVERSE_PHASE) - { - ConLog( " *** SPU2 > Reverse Phase in progress!\n" ); - Vol.Value = 0x7fff - Vol.Value; - } + // TODO : Vol.Value should be a 32 bit internal value, same as ADSR. + // Volume slides use the same basic logic as ADSR, but simplified (single-stage + // instead of multi-stage) + if (Vol.Mode & VOLFLAG_DECREMENT) { // Decrement if(Vol.Mode & VOLFLAG_EXPONENTIAL) { - ConLog( " *** SPU2 > Exponential Volume Slide Down!\n" ); - Vol.Value *= Vol.Increment >> 7; - Vol.Value-=((32768*5)>>(Vol.Increment)); + u32 off = InvExpOffsets[(Vol.Value>>12)&7]; + Vol.Value -= PsxRates[(Vol.Increment^0x7f)-0x1b+off+32] >> 16; } else - { - Vol.Value-=Vol.Increment; - } + Vol.Value -= Vol.Increment; - if (Vol.Value<0) + if (Vol.Value < 0) { Vol.Value = 0; - Vol.Mode=0; // disable slide + Vol.Mode = 0; // disable slide } } else { - //ConLog( " *** SPU2 > Volflag > Increment!\n" ); // Increment - if(Vol.Mode & VOLFLAG_EXPONENTIAL) - { - ConLog( " *** SPU2 > Exponential Volume Slide Up!\n" ); - int T = Vol.Increment>>(Vol.Value>>12); - Vol.Value+=T; - } - else - { - Vol.Value+=Vol.Increment; - } + // Pseudo-exponential increments, as done by the SPU2 (really!) + // Above 75% slides slow, below 75% slides fast. It's exponential, pseudoly speaking. - if( Vol.Value > 0x7fff ) + if( (Vol.Mode & VOLFLAG_EXPONENTIAL) && (Vol.Value>=0x6000)) + Vol.Value += PsxRates[(Vol.Increment^0x7f)-0x18+32] >> 16; + else + Vol.Value += Vol.Increment; + + if( Vol.Value < 0 ) // wrapped around the "top"? { Vol.Value = 0x7fff; - Vol.Mode=0; // disable slide + Vol.Mode = 0; // disable slide } } - - // Reverse phasing - // Invert the value back into output form: - if(Vol.Mode & VOLFLAG_REVERSE_PHASE) Vol.Value = 0x7fff-Vol.Value; - - //Vol.Value=NVal; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1022,17 +1029,16 @@ static __forceinline void MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s { s32 Value=0; - VValL=0; - VValR=0; + VValL = 0; + VValR = 0; - // [Air] : Most games don't use much volume slide effects. So only - // call the UpdateVolume methods when needed by checking the flag - // outside the method here... + // Most games don't use much volume slide effects. So only call the UpdateVolume + // methods when needed by checking the flag outside the method here... if( vc.VolumeL.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume( vc.VolumeL ); if( vc.VolumeR.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume( vc.VolumeR ); - if (vc.ADSR.Phase>0) + if( vc.ADSR.Phase > 0 ) { UpdatePitch( vc ); @@ -1053,12 +1059,17 @@ static __forceinline void MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s DebugCores[core].Voices[voice].displayPeak = max(DebugCores[core].Voices[voice].displayPeak,abs(Value)); #endif - VValL=ApplyVolume(Value,(vc.VolumeL.Value)); - VValR=ApplyVolume(Value,(vc.VolumeR.Value)); + // TODO : Implement this using high-def MulShr32. + // vc.VolumeL/R are 15 bits. Value should be 32 bits (but is currently 16) + + VValL = ApplyVolume(Value,vc.VolumeL.Value); + VValR = ApplyVolume(Value,vc.VolumeR.Value); } - if (voice==1) spu2M_WriteFast( 0x400 + (core<<12) + OutPos, (s16)Value ); - else if (voice==3) spu2M_WriteFast( 0x600 + (core<<12) + OutPos, (s16)Value ); + // Write-back of raw voice data (post ADSR applied) + + if (voice==1) spu2M_WriteFast( 0x400 + (core<<12) + OutPos, (s16)Value>>3 ); + else if (voice==3) spu2M_WriteFast( 0x600 + (core<<12) + OutPos, (s16)Value>>3 ); } @@ -1071,29 +1082,42 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR) V_Core& thiscore( Cores[core] ); - for (voice=0;voice<24;voice++) + for (voice=0;voice<24;voice++) { s32 VValL,VValR; V_Voice& vc( thiscore.Voices[voice] ); MixVoice( thiscore, vc, VValL, VValR ); + + // Note: Results from MixVoice are ranged at 16 bits. + // Following muls are toggles only (0 or 1) SDL += VValL * vc.DryL; SDR += VValR * vc.DryR; SWL += VValL * vc.WetL; SWR += VValR * vc.WetR; } - - //Write To Output Area - spu2M_WriteFast( 0x1000 + (core<<12) + OutPos, (s16)(SDL>>16) ); - spu2M_WriteFast( 0x1200 + (core<<12) + OutPos, (s16)(SDR>>16) ); - spu2M_WriteFast( 0x1400 + (core<<12) + OutPos, (s16)(SWL>>16) ); - spu2M_WriteFast( 0x1600 + (core<<12) + OutPos, (s16)(SWR>>16) ); + + // Saturate final result to standard 16 bit range. + SDL = min( max( SDL, -0x8000 ), 0x7fff ); + SDR = min( max( SDR, -0x8000 ), 0x7fff ); + SWL = min( max( SWL, -0x8000 ), 0x7fff ); + SWR = min( max( SWR, -0x8000 ), 0x7fff ); + + // Write Mixed results To Output Area + spu2M_WriteFast( 0x1000 + (core<<12) + OutPos, (s16)SDL ); + spu2M_WriteFast( 0x1200 + (core<<12) + OutPos, (s16)SDR ); + spu2M_WriteFast( 0x1400 + (core<<12) + OutPos, (s16)SWL ); + spu2M_WriteFast( 0x1600 + (core<<12) + OutPos, (s16)SWR ); + + // Write mixed results to logfile (if enabled) + + WaveDump::WriteCore( core, CoreSrc_DryVoiceMix, SDL, SDR ); + WaveDump::WriteCore( core, CoreSrc_WetVoiceMix, SWL, SWR ); s32 TDL,TDR; // Mix in the Input data - // divide by 3 fixes some volume problems. TDL = OutL * thiscore.InpDryL; TDR = OutR * thiscore.InpDryR; @@ -1107,7 +1131,7 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR) if(EffectsEnabled) { - s32 TWL=0,TWR=0; + s32 TWL,TWR; // Mix Input, Voice, and External data: TWL = OutL * thiscore.InpWetL; @@ -1117,15 +1141,19 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR) TWL += ExtL * thiscore.ExtWetL; TWR += ExtR * thiscore.ExtWetR; - //Apply Effects - DoReverb( thiscore, RVL,RVR,TWL>>16,TWR>>16); + WaveDump::WriteCore( core, CoreSrc_PreReverb, TWL, TWR ); - TWL=ApplyVolume(RVL,VOL(thiscore.FxL)); - TWR=ApplyVolume(RVR,VOL(thiscore.FxR)); + //Apply Effects + DoReverb( thiscore, RVL, RVR, TWL, TWR ); + + TWL = ApplyVolume(RVL,VOL(thiscore.FxL)); + TWR = ApplyVolume(RVR,VOL(thiscore.FxR)); + + WaveDump::WriteCore( core, CoreSrc_PostReverb, TWL, TWR ); //Mix Wet,Dry - OutL=(TDL + TWL); - OutR=(TDR + TWR); + OutL = (TDL + TWL); + OutR = (TDR + TWR); } else { @@ -1139,8 +1167,11 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR) if (thiscore.Mute==0) { - OutL = MulShr32( OutL, ((s32)thiscore.MasterL.Value)<<16 ); - OutR = MulShr32( OutR, ((s32)thiscore.MasterR.Value)<<16 ); + // Final output value -- We don't use ApplyVolume sot hat we can leave the 15 bits of + // fixed point accuracy in place for SoundTouch and other post processing. + + OutL = OutL * thiscore.MasterL.Value; + OutR = OutR * thiscore.MasterR.Value; } else { @@ -1159,10 +1190,11 @@ void __fastcall Mix() // **** CORE ZERO **** core=0; - if( (PlayMode&4) != 4 ) + if( (PlayMode&4) == 0 ) { // get input data from input buffers ReadInputPV(Cores[0], ExtL, ExtR); + WaveDump::WriteCore( 0, CoreSrc_Input, ExtL, ExtR ); } MixCore( ExtL, ExtR, 0, 0 ); @@ -1174,10 +1206,16 @@ void __fastcall Mix() } // Commit Core 0 output to ram before mixing Core 1: - ExtL>>=14; - ExtR>>=14; - spu2M_WriteFast( 0x800 + OutPos, ExtL>>3 ); - spu2M_WriteFast( 0xA00 + OutPos, ExtR>>3 ); + ExtL>>=15; + ExtR>>=15; + + ExtL = min( max( ExtL, -0x8000 ), 0x7fff ); + ExtR = min( max( ExtR, -0x8000 ), 0x7fff ); + + spu2M_WriteFast( 0x800 + OutPos, ExtL ); + spu2M_WriteFast( 0xA00 + OutPos, ExtR ); + + WaveDump::WriteCore( 0, CoreSrc_External, ExtL, ExtR ); // **** CORE ONE **** @@ -1185,15 +1223,20 @@ void __fastcall Mix() if( (PlayMode&8) != 8 ) { ReadInputPV(Cores[1], OutL, OutR); // get input data from input buffers + WaveDump::WriteCore( 1, CoreSrc_Input, OutL, OutR ); } // Apply volume to the external (Core 0) input data. - MixCore( OutL, OutR, ExtL*Cores[1].ExtL, ExtR*Cores[1].ExtR ); + MixCore( OutL, OutR, ApplyVolume( ExtL, Cores[1].ExtL), ApplyVolume( ExtR, Cores[1].ExtR) ); if( PlayMode & 8 ) { + // Experimental CDDA support + // The CDDA overrides all other mixer output. It's a direct feed! + ReadInput(Cores[1], OutL, OutR); + //WaveLog::WriteCore( 1, "CDDA-32", OutL, OutR ); } #ifndef PUBLIC @@ -1206,12 +1249,13 @@ void __fastcall Mix() // Update spdif (called each sample) if(PlayMode&4) - { spdif_update(); - } + + OutL >>= 6; + OutR >>= 6; // AddToBuffer - SndWrite(OutL, OutR); //ExtL,ExtR); + SndWrite(OutL, OutR); OutPos++; if (OutPos>=0x200) OutPos=0; @@ -1233,36 +1277,6 @@ void __fastcall Mix() #endif } -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // -u32 PsxRates[160]={ - - //for +Lin: PsxRates[value+8] - //for -Lin: PsxRates[value+7] - - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xD744FCCB,0xB504F334,0x9837F052,0x80000000,0x6BA27E65,0x5A82799A,0x4C1BF829,0x40000000, - 0x35D13F33,0x2D413CCD,0x260DFC14,0x20000000,0x1AE89F99,0x16A09E66,0x1306FE0A,0x10000000, - 0x0D744FCD,0x0B504F33,0x09837F05,0x08000000,0x06BA27E6,0x05A8279A,0x04C1BF83,0x04000000, - 0x035D13F3,0x02D413CD,0x0260DFC1,0x02000000,0x01AE89FA,0x016A09E6,0x01306FE1,0x01000000, - 0x00D744FD,0x00B504F3,0x009837F0,0x00800000,0x006BA27E,0x005A827A,0x004C1BF8,0x00400000, - 0x0035D13F,0x002D413D,0x00260DFC,0x00200000,0x001AE8A0,0x0016A09E,0x001306FE,0x00100000, - 0x000D7450,0x000B504F,0x0009837F,0x00080000,0x0006BA28,0x0005A828,0x0004C1C0,0x00040000, - 0x00035D14,0x0002D414,0x000260E0,0x00020000,0x0001AE8A,0x00016A0A,0x00013070,0x00010000, - 0x0000D745,0x0000B505,0x00009838,0x00008000,0x00006BA2,0x00005A82,0x00004C1C,0x00004000, - 0x000035D1,0x00002D41,0x0000260E,0x00002000,0x00001AE9,0x000016A1,0x00001307,0x00001000, - 0x00000D74,0x00000B50,0x00000983,0x00000800,0x000006BA,0x000005A8,0x000004C2,0x00000400, - 0x0000035D,0x000002D4,0x00000261,0x00000200,0x000001AF,0x0000016A,0x00000130,0x00000100, - 0x000000D7,0x000000B5,0x00000098,0x00000080,0x0000006C,0x0000005B,0x0000004C,0x00000040, - 0x00000036,0x0000002D,0x00000026,0x00000020,0x0000001B,0x00000017,0x00000013,0x00000010, - 0x0000000D,0x0000000B,0x0000000A,0x00000008,0x00000007,0x00000006,0x00000005,0x00000004, - 0x00000003,0x00000003,0x00000002,0x00000002,0x00000002,0x00000001,0x00000001,0x00000000, - - //128+8 - 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, -}; - ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // // diff --git a/plugins/spu2ghz/src/savestate.cpp b/plugins/spu2ghz/src/savestate.cpp index 756b2199c1..b96614ac78 100644 --- a/plugins/spu2ghz/src/savestate.cpp +++ b/plugins/spu2ghz/src/savestate.cpp @@ -131,7 +131,7 @@ EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data) { printf("\n*** SPU2Ghz Warning:\n"); printf("\tSavestate version is from an older version of this plugin.\n"); - printf("\tAudio may not recover correctly."); + printf("\tAudio may not recover correctly.\n\n"); const PcmCacheEntry* pcmSrc = &spud->cacheData; int blksLoaded=0; diff --git a/plugins/spu2ghz/src/sndout.cpp b/plugins/spu2ghz/src/sndout.cpp index d4f6d32cfd..9317ea2e85 100644 --- a/plugins/spu2ghz/src/sndout.cpp +++ b/plugins/spu2ghz/src/sndout.cpp @@ -693,15 +693,12 @@ void SndUpdateLimitMode() s32 SndWrite(s32 ValL, s32 ValR) { + // Log final output to wavefile. #ifndef PUBLIC - if(WaveLog() && wavedump_ok) - { - wavedump_write(SndScaleVol(ValL),SndScaleVol(ValR)); - } + WaveDump::WriteCore( 1, CoreSrc_External, SndScaleVol(ValL), SndScaleVol(ValR) ); #endif - if(recording!=0) - RecordWrite(SndScaleVol(ValL),SndScaleVol(ValR)); + RecordWrite(SndScaleVol(ValL),SndScaleVol(ValR)); if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p return 0; diff --git a/plugins/spu2ghz/src/sndout.h b/plugins/spu2ghz/src/sndout.h index f0fe394b15..38a2952075 100644 --- a/plugins/spu2ghz/src/sndout.h +++ b/plugins/spu2ghz/src/sndout.h @@ -23,7 +23,7 @@ // SndOut. static const int SndOutPacketSize = 1024; -static const int SndOutVolumeShiftBase = 8; +static const int SndOutVolumeShiftBase = 10; extern int SndOutVolumeShift; #define pcmlog diff --git a/plugins/spu2ghz/src/spu2.cpp b/plugins/spu2ghz/src/spu2.cpp index 98837e7069..072222f436 100644 --- a/plugins/spu2ghz/src/spu2.cpp +++ b/plugins/spu2ghz/src/spu2.cpp @@ -155,11 +155,8 @@ void AssignVolume(V_Volume& vol, s16 value) else { vol.Mode=0; vol.Increment=0; - - value<<=1; - vol.Value=value; - - } + vol.Value=value<<1; + } } void CoreReset(int c) @@ -173,10 +170,10 @@ void CoreReset(int c) Cores[c].Regs.STATX=0; Cores[c].Regs.ATTR=0; - Cores[c].ExtL=0x3FFF; - Cores[c].ExtR=0x3FFF; - Cores[c].InpL=0x3FFF; - Cores[c].InpR=0x3FFF; + Cores[c].ExtL=0x7FFF; + Cores[c].ExtR=0x7FFF; + Cores[c].InpL=0x7FFF; + Cores[c].InpR=0x7FFF; Cores[c].FxL=0x7FFF; Cores[c].FxR=0x7FFF; Cores[c].MasterL.Reg_VOL=0x3FFF; @@ -519,7 +516,8 @@ void UpdateSpdifMode() } if(OPM!=PlayMode) { - ConLog(" * SPU2: Play Mode Set to %s (%d).\n",(PlayMode==0)?"Normal":((PlayMode==1)?"PCM Clone":((PlayMode==2)?"PCM Bypass":"BitStream Bypass")),PlayMode); + ConLog(" * SPU2: Play Mode Set to %s (%d).\n", + (PlayMode==0) ? "Normal" : ((PlayMode==1) ? "PCM Clone" : ((PlayMode==2) ? "PCM Bypass" : "BitStream Bypass")),PlayMode); } } @@ -748,19 +746,24 @@ void SPU2writeLog(u32 rmem, u16 value) omem=mem=rmem & 0x7FF; //FFFF; if (mem & 0x400) { omem^=0x400; core=1; } - /* - if ((omem >= 0x0000) && (omem < 0x0180)) { // Voice Params - u32 voice=(omem & 0x1F0) >> 4; - u32 param=(omem & 0xF)>>1; - FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Param %s) value %x\n",Cycles,rmem,core,voice,ParamNames[param],value); + if( omem < 0x0180 ) // Voice Params (VP) + { + const u32 voice = (omem & 0x1F0) >> 4; + const u32 param = (omem & 0xF) >> 1; + char dest[192]; + sprintf( dest, "Voice %d %s", voice,ParamNames[param] ); + RegLog( 2, dest, rmem, core, value ); } - else if ((omem >= 0x01C0) && (omem < 0x02DE)) { - u32 voice =((omem-0x01C0) / 12); - u32 address =((omem-0x01C0) % 12)>>1; - FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Address %s) value %x\n",Cycles,rmem,core,voice,AddressNames[address],value); + else if ((omem >= 0x01C0) && (omem < 0x02DE)) // Voice Addressing Params (VA) + { + const u32 voice = ((omem-0x01C0) / 12); + const u32 address = ((omem-0x01C0) % 12)>>1; + + char dest[192]; + sprintf( dest, "Voice %d %s", voice, AddressNames[address] ); + RegLog( 2, dest, rmem, core, value ); } - */ - if ((mem >= 0x0760) && (mem < 0x07b0)) + else if ((mem >= 0x0760) && (mem < 0x07b0)) { omem=mem; core=0; if (mem >= 0x0788) {omem-=0x28; core=1;} @@ -869,16 +872,16 @@ void SPU2writeLog(u32 rmem, u16 value) RegLog(2,"IRQAL",rmem,core,value); break; case (REG_S_KON + 2): - RegLog(2,"KON1",rmem,core,value); + RegLog(1,"KON1",rmem,core,value); break; case REG_S_KON: - RegLog(2,"KON0",rmem,core,value); + RegLog(1,"KON0",rmem,core,value); break; case (REG_S_KOFF + 2): - RegLog(2,"KOFF1",rmem,core,value); + RegLog(1,"KOFF1",rmem,core,value); break; case REG_S_KOFF: - RegLog(2,"KOFF0",rmem,core,value); + RegLog(1,"KOFF0",rmem,core,value); break; case REG_A_TSA: RegLog(2,"TSAH",rmem,core,value); @@ -973,35 +976,31 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value ) switch (param) { case 0: //VOLL (Volume L) + case 1: //VOLR (Volume R) + { + V_Volume& thisvol = (param==0) ? Cores[core].Voices[voice].VolumeL : Cores[core].Voices[voice].VolumeR; if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp { - Cores[core].Voices[voice].VolumeL.Mode=(value & 0xF000)>>12; - Cores[core].Voices[voice].VolumeL.Increment=(value & 0x3F); + thisvol.Mode=(value & 0xF000)>>12; + thisvol.Increment=(value & 0x3F); } else { - Cores[core].Voices[voice].VolumeL.Mode=0; - Cores[core].Voices[voice].VolumeL.Increment=0; - if(value&0x4000) - value=0x3fff - (value&0x3fff); - Cores[core].Voices[voice].VolumeL.Value=value<<1; + // Constant Volume mode (no slides or envelopes) + // Volumes range from 0x3fff to -0x4000. Values below zero invert the waveform (unimplemented) + + thisvol.Mode=0; + thisvol.Increment=0; + + s16 newval = value & 0x3fff; + if( value & 0x4000 ) + newval = 0x3fff - newval; + thisvol.Value = newval<<1; } - Cores[core].Voices[voice].VolumeL.Reg_VOL = value; + thisvol.Reg_VOL = value; + } break; - case 1: //VOLR (Volume R) - if (value & 0x8000) - { - Cores[core].Voices[voice].VolumeR.Mode=(value & 0xF000)>>12; - Cores[core].Voices[voice].VolumeR.Increment=(value & 0x3F); - } - else - { - Cores[core].Voices[voice].VolumeR.Mode=0; - Cores[core].Voices[voice].VolumeR.Increment=0; - Cores[core].Voices[voice].VolumeR.Value=value<<1; - } - Cores[core].Voices[voice].VolumeR.Reg_VOL = value; break; case 2: Cores[core].Voices[voice].Pitch=value; break; case 3: // ADSR1 (Envelope) Cores[core].Voices[voice].ADSR.Am=(value & 0x8000)>>15; @@ -1021,6 +1020,7 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value ) Cores[core].Voices[voice].ADSR.Value = value << 15; ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); break; + case 6: Cores[core].Voices[voice].VolumeL.Value=value; break; case 7: Cores[core].Voices[voice].VolumeR.Value=value; break; @@ -1214,29 +1214,55 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value ) return; case REG_P_MVOLL: - if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp - Cores[core].MasterL.Mode=(value & 0xE000)/0x2000; - Cores[core].MasterL.Increment=(value & 0x3F) | ((value & 0x800)/0x10); + case REG_P_MVOLR: + { + V_Volume& thisvol = (omem==REG_P_MVOLL) ? Cores[core].MasterL : Cores[core].MasterR; + + if( value & 0x8000 ) // +Lin/-Lin/+Exp/-Exp + { + thisvol.Mode = (value & 0xE000) / 0x2000; + thisvol.Increment = (value & 0x7F); // | ((value & 0x800)/0x10); } - else { - Cores[core].MasterL.Mode=0; - Cores[core].MasterL.Increment=0; - Cores[core].MasterL.Value=value; + else + { + thisvol.Mode = 0; + thisvol.Increment = 0; + + // Constant Volume mode (no slides or envelopes) + // Volumes range from 0x3fff to -0x4000. Values below zero invert the waveform (unimplemented) + + s16 newval = value & 0x3fff; + if( value & 0x4000 ) + newval = 0x3fff - newval; + + thisvol.Value = newval<<1; } - Cores[core].MasterL.Reg_VOL=value; + thisvol.Reg_VOL = value; + } return; - case REG_P_MVOLR: - if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp - Cores[core].MasterR.Mode=(value & 0xE000)/0x2000; - Cores[core].MasterR.Increment=(value & 0x3F) | ((value & 0x800)/0x10); - } - else { - Cores[core].MasterR.Mode=0; - Cores[core].MasterR.Increment=0; - Cores[core].MasterR.Value=value; - } - Cores[core].MasterR.Reg_VOL=value; + case REG_P_EVOLL: + Cores[core].FxL = ( value & 0x8000 ) ? -value : value; + return; + + case REG_P_EVOLR: + Cores[core].FxR = ( value & 0x8000 ) ? -value : value; + return; + + case REG_P_AVOLL: + Cores[core].ExtL = ( value & 0x8000 ) ? -value : value; + return; + + case REG_P_AVOLR: + Cores[core].ExtR = ( value & 0x8000 ) ? -value : value; + return; + + case REG_P_BVOLL: + Cores[core].InpL = ( value & 0x8000 ) ? -value : value; + return; + + case REG_P_BVOLR: + Cores[core].InpR = ( value & 0x8000 ) ? -value : value; return; case REG_S_ADMAS: diff --git a/plugins/spu2ghz/src/spu2.h b/plugins/spu2ghz/src/spu2.h index 619b9be2dc..7b2fc13ca9 100644 --- a/plugins/spu2ghz/src/spu2.h +++ b/plugins/spu2ghz/src/spu2.h @@ -135,7 +135,7 @@ default: \ #ifndef SAFE_DELETE_ARRAY # define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } #endif -#ifndef SAFE_DELETE +#ifndef SAFE_DELETE_OBJ # define SAFE_DELETE_OBJ(p) { if(p) { delete (p); (p)=NULL; } } #endif #ifndef SAFE_RELEASE diff --git a/plugins/spu2ghz/src/wavedump_wav.cpp b/plugins/spu2ghz/src/wavedump_wav.cpp index 4971c559f2..59e8680bc2 100644 --- a/plugins/spu2ghz/src/wavedump_wav.cpp +++ b/plugins/spu2ghz/src/wavedump_wav.cpp @@ -16,181 +16,107 @@ //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // +#include +#include + #include "spu2.h" -#include -#define WAVONLY +#include "SoundTouch/WavFile.h" -typedef struct { - //Main Header - char riffID[4]; - long riffSize; - char riffTYPE[4]; - //Format Tag - char chunkID[4]; - long chunkSize; - short wFormatTag; - unsigned short wChannels; - unsigned long dwSamplesPerSec; - unsigned long dwAvgBytesPerSec; - unsigned short wBlockAlign; - unsigned short wBitsPerSample; - //Data Tag - char dataID[4]; - long dataSize; -} WAVEHeader; - -int wavedump_ok=0; -int datasize; -FILE *fdump; - -#ifndef WAVONLY -int flacdump_open(); -void flacdump_close(); -void flacdump_write(s16 left,s16 right); -int oggvdump_open(); -void oggvdump_close(); -void oggvdump_write(s16 left,s16 right); -#endif - -int wavedump_open() +static WavOutFile* _new_WavOutFile( const char* destfile ) { -#ifndef WAVONLY - if(WaveDumpFormat==1) return flacdump_open(); - if(WaveDumpFormat==2) return oggvdump_open(); -#endif - - fdump=fopen(WaveLogFileName,"wb"); - if(fdump==NULL) return 0; - - fseek(fdump,sizeof(WAVEHeader),SEEK_SET); - - datasize=0; - wavedump_ok=1; - return 1; + return new WavOutFile( destfile, 48000, 16, 2 ); } -void wavedump_flush() +namespace WaveDump { - WAVEHeader w; + static WavOutFile* m_CoreWav[2][CoreSrc_Count] = { NULL }; - memcpy(w.riffID,"RIFF",4); - w.riffSize=datasize+36; - memcpy(w.riffTYPE,"WAVE",4); - memcpy(w.chunkID,"fmt ",4); - w.chunkSize=0x10; - w.wFormatTag=1; - w.wChannels=2; - w.dwSamplesPerSec=48000; - w.dwAvgBytesPerSec=48000*4; - w.wBlockAlign=4; - w.wBitsPerSample=16; - memcpy(w.dataID,"data",4); - w.dataSize=datasize; + static const char* m_tbl_CoreOutputTypeNames[CoreSrc_Count] = + { + "Input", + "DryVoiceMix", + "WetVoiceMix", + "PreReverb", + "PostReverb", + "External" + }; - fseek(fdump,0,SEEK_SET); - fwrite(&w,sizeof(w),1,fdump); + void Open() + { + if( !WaveLog() ) return; + + char wavfilename[256]; - fseek(fdump,datasize+sizeof(w),SEEK_SET); + for( uint cidx=0; cidx<2; cidx++ ) + { + for( int srcidx=0; srcidx %s.\n\tWave Log for this core source disabled.", ex.what() ); + m_CoreWav[cidx][srcidx] = NULL; + } + } + } + } + + void Close() + { + for( uint cidx=0; cidx<2; cidx++ ) + { + for( int srcidx=0; srcidxwrite( buffer, 2 ); + } + } } -void wavedump_close() -{ - if(!wavedump_ok) return; - - wavedump_flush(); -#ifndef WAVONLY - if(WaveDumpFormat==1) { flacdump_close(); return;} - if(WaveDumpFormat==2) { oggvdump_close(); return;} -#endif - - - fclose(fdump); - wavedump_ok=0; -} - -void wavedump_write(s16 left,s16 right) -{ - s16 buffer[2]={left,right}; - - if(!wavedump_ok) return; - -#ifndef WAVONLY - if(WaveDumpFormat==1) return flacdump_write(left,right); - if(WaveDumpFormat==2) return oggvdump_write(left,right); -#endif - datasize+=4; - - fwrite(buffer,4,1,fdump); - - if((datasize&1023)==0) - wavedump_flush(); -} - -FILE *recordFile; -int recordSize; -int recording; +WavOutFile* m_wavrecord = NULL; void RecordStart() { - if(recording&&recordFile) - fclose(recordFile); + SAFE_DELETE_OBJ( m_wavrecord ); - recordFile=fopen("recording.wav","wb"); - if(recordFile==NULL) return; - - fseek(recordFile,sizeof(WAVEHeader),SEEK_SET); - - recordSize=0; - recording=1; -} - -void RecordFlush() -{ - WAVEHeader w; - - memcpy(w.riffID,"RIFF",4); - w.riffSize=recordSize+36; - memcpy(w.riffTYPE,"WAVE",4); - memcpy(w.chunkID,"fmt ",4); - w.chunkSize=0x10; - w.wFormatTag=1; - w.wChannels=2; - w.dwSamplesPerSec=48000; - w.dwAvgBytesPerSec=48000*4; - w.wBlockAlign=4; - w.wBitsPerSample=16; - memcpy(w.dataID,"data",4); - w.dataSize=recordSize; - - fseek(recordFile,0,SEEK_SET); - fwrite(&w,sizeof(w),1,recordFile); - fseek(recordFile,recordSize+sizeof(w),SEEK_SET); + try + { + m_wavrecord = new WavOutFile( "recording.wav", 48000, 16, 2 ); + } + catch( std::runtime_error& ) + { + SysMessage("SPU2ghz couldn't open file for recording: %s.\nRecording to wavfile disabled.", "recording.wav"); + m_wavrecord = NULL; + } } void RecordStop() { - if(!recording) - return; - recording=0; - - RecordFlush(); - - fclose(recordFile); + SAFE_DELETE_OBJ( m_wavrecord ); } void RecordWrite(s16 left, s16 right) { - if(!recording) - return; - - s16 buffer[2]={left,right}; - - recordSize+=4; - - fwrite(buffer,4,1,recordFile); - - if((recordSize&1023)==0) - RecordFlush(); + if( m_wavrecord == NULL ) return; + s16 buffer[2] = { left, right }; + m_wavrecord->write( buffer, 2 ); }