changeset 854:61e7332e0652 trunk

[svn] - PSF2 support (everything is BORKED right now)
author nenolod
date Sun, 19 Mar 2006 12:51:03 -0800
parents 74576869a506
children 89df4358d522
files Plugins/Input/sexypsf/Makefile.in Plugins/Input/sexypsf/Misc.c Plugins/Input/sexypsf/PsxCounters.c Plugins/Input/sexypsf/PsxDma.c Plugins/Input/sexypsf/PsxHw.c Plugins/Input/sexypsf/R3000A.c Plugins/Input/sexypsf/Spu.c Plugins/Input/sexypsf/Spu.h Plugins/Input/sexypsf/psemuxa.h Plugins/Input/sexypsf/spu.c Plugins/Input/sexypsf/spu/adsr.c Plugins/Input/sexypsf/spu/adsr.h Plugins/Input/sexypsf/spu/alsa.c Plugins/Input/sexypsf/spu/alsa.h Plugins/Input/sexypsf/spu/cfg.c Plugins/Input/sexypsf/spu/cfg.h Plugins/Input/sexypsf/spu/debug.c Plugins/Input/sexypsf/spu/debug.h Plugins/Input/sexypsf/spu/dma.c Plugins/Input/sexypsf/spu/dma.h Plugins/Input/sexypsf/spu/dsound.c Plugins/Input/sexypsf/spu/dsoundoss.h Plugins/Input/sexypsf/spu/externals.h Plugins/Input/sexypsf/spu/freeze.c Plugins/Input/sexypsf/spu/gauss_i.h Plugins/Input/sexypsf/spu/oss.c Plugins/Input/sexypsf/spu/oss.h Plugins/Input/sexypsf/spu/psemu.c Plugins/Input/sexypsf/spu/psemuxa.h Plugins/Input/sexypsf/spu/record.c Plugins/Input/sexypsf/spu/record.h Plugins/Input/sexypsf/spu/registers.c Plugins/Input/sexypsf/spu/registers.h Plugins/Input/sexypsf/spu/regs.h Plugins/Input/sexypsf/spu/resource.h Plugins/Input/sexypsf/spu/reverb.c Plugins/Input/sexypsf/spu/reverb.h Plugins/Input/sexypsf/spu/spu.c Plugins/Input/sexypsf/spu/spu.h Plugins/Input/sexypsf/spu/stdafx.c Plugins/Input/sexypsf/spu/stdafx.h Plugins/Input/sexypsf/spu/xa.c Plugins/Input/sexypsf/spu/xa.h
diffstat 42 files changed, 8064 insertions(+), 2637 deletions(-) [+]
line wrap: on
line diff
--- a/Plugins/Input/sexypsf/Makefile.in	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/Makefile.in	Sun Mar 19 12:51:03 2006 -0800
@@ -17,6 +17,8 @@
 	PsxInterpreter.c \
 	PsxHLE.c \
 	spu/spu.c \
+	spu/dma.c \
+	spu/registers.c \
 	xmms.c
 
 LIBADD = -lz
--- a/Plugins/Input/sexypsf/Misc.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/Misc.c	Sun Mar 19 12:51:03 2006 -0800
@@ -447,8 +447,8 @@
         psxInit();
         psxReset();
 
-        SPUinit();
-        SPUopen();
+        SPU2init();
+        SPU2open();
 
 	if(!(ret=LoadPSF(path,0,0)))
 	{
--- a/Plugins/Input/sexypsf/PsxCounters.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/PsxCounters.c	Sun Mar 19 12:51:03 2006 -0800
@@ -103,7 +103,7 @@
 
  if(cycles>=16)
  {
-  if(!SPUasync(cycles)) return(0);
+  if(!SPU2async(cycles)) return(0);
   last=psxRegs.cycle;
  }
  return(1);
--- a/Plugins/Input/sexypsf/PsxDma.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/PsxDma.c	Sun Mar 19 12:51:03 2006 -0800
@@ -25,13 +25,13 @@
 		 bcr= (bcr>>16) * (bcr&0xffff) * 2;
 
 		 //printf("%08x, %08x\n",madr,bcr);
-		 SPUwriteDMAMem(madr, bcr);		
+		 SPU2writeDMA4Mem(madr, bcr);		
 		}
 		break;
 		case 0x01000200: //spu to cpu transfer
 		{
 		 //printf("%08x\n",madr);
-	  	 SPUreadDMAMem (madr, (bcr >> 16) * (bcr & 0xffff) * 2);
+	  	 SPU2readDMA4Mem (madr, (bcr >> 16) * (bcr & 0xffff) * 2);
 		}
 		break;
 	}
--- a/Plugins/Input/sexypsf/PsxHw.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/PsxHw.c	Sun Mar 19 12:51:03 2006 -0800
@@ -78,7 +78,7 @@
 	
 		default:
 			if (add>=0x1f801c00 && add<0x1f801e00) {
-            		  hard = SPUreadRegister(add);
+            		  hard = SPU2read(add);
 			} else {
 				hard = BFLIP16(psxHu16(add)); 
 			}
@@ -165,7 +165,7 @@
 
 		default:
 			if (add>=0x1f801c00 && add<0x1f801e00) {
-            			SPUwriteRegister(add, value);
+            			SPU2write(add, value);
 				return;
 			}
 
--- a/Plugins/Input/sexypsf/R3000A.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/R3000A.c	Sun Mar 19 12:51:03 2006 -0800
@@ -50,7 +50,7 @@
 	psxBiosShutdown();
 
 	psxCpu->Shutdown();
-	SPUclose();
+	SPU2close();
 }
 
 void psxException(u32 code, u32 bd) {
--- a/Plugins/Input/sexypsf/Spu.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/Spu.c	Sun Mar 19 12:51:03 2006 -0800
@@ -21,3 +21,4 @@
 void SPUirq(void) {
 	psxHu32(0x1070)|=BFLIP32(0x200);
 }
+
--- a/Plugins/Input/sexypsf/Spu.h	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/Spu.h	Sun Mar 19 12:51:03 2006 -0800
@@ -31,8 +31,8 @@
 
 
 void SPUirq(void);
-u16 SPUreadRegister(u32 reg);
-void SPUwriteRegister(u32 reg, u16 val);
+unsigned short SPUreadRegister(unsigned long reg);
+void SPUwriteRegister(unsigned long reg, unsigned short val);
 int SPUasync(u32 cycle);
 void SPUwriteDMAMem(u32 usPSXMem,int iSize);
 void SPUreadDMAMem(u32 usPSXMem,int iSize);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/psemuxa.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,28 @@
+//============================================
+//=== Audio XA decoding
+//=== Kazzuya
+//============================================
+
+#ifndef DECODEXA_H
+#define DECODEXA_H
+
+typedef struct
+{
+	long	y0, y1;
+} ADPCM_Decode_t;
+
+typedef struct
+{                                                                   
+	int				freq;
+	int				nbits;
+	int				stereo;
+	int				nsamples;
+	ADPCM_Decode_t	left, right;
+	short			pcm[16384];
+} xa_decode_t;
+
+long xa_decode_sector( xa_decode_t *xdp,
+					   unsigned char *sectorp,
+					   int is_first_sector );
+
+#endif
--- a/Plugins/Input/sexypsf/spu.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu.c	Sun Mar 19 12:51:03 2006 -0800
@@ -171,6 +171,18 @@
  s_chan[ch].spos=0x40000L;s_chan[ch].SB[28]=0;  // -> start with more decoding
 }
 
+static unsigned long long SexyTime64(void)
+{
+ struct timeval tv;
+ unsigned long long ret;
+
+ gettimeofday(&tv,0);
+ ret=tv.tv_sec;
+ ret*=1000000;
+ ret+=tv.tv_usec;
+ return(ret);
+}
+
 ////////////////////////////////////////////////////////////////////////
 // MAIN SPU FUNCTION
 // here is the main job handler... thread, timer or direct func call
--- a/Plugins/Input/sexypsf/spu/adsr.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/adsr.c	Sun Mar 19 12:51:03 2006 -0800
@@ -1,618 +1,656 @@
-/***************************************************************************
-                          adsr.c  -  description
-                             -------------------
-    begin                : Wed May 15 2002
-    copyright            : (C) 2002 by Pete Bernert
-    email                : BlackDove@addcom.de
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version. See also the license.txt file for *
- *   additional informations.                                              *
- *                                                                         *
- ***************************************************************************/
-
-//*************************************************************************//
-// History of changes:
-//
-// 2003/01/06 - Pete
-// - added Neill's ADSR timings
-//
-// 2002/05/15 - Pete
-// - generic cleanup for the Peops release
-//
-//*************************************************************************//
-
-#define _IN_ADSR
-
-// will be included from spu.c
-#ifdef _IN_SPU
-
-////////////////////////////////////////////////////////////////////////
-// ADSR func
-////////////////////////////////////////////////////////////////////////
-
-static u32 RateTable[160];
-
-static void InitADSR(void)                                    // INIT ADSR
-{
- u32 r,rs,rd;int i;
-
- memset(RateTable,0,sizeof(u32)*160);        // build the rate table according to Neill's rules (see at bottom of file)
-
- r=3;rs=1;rd=0;
-
- for(i=32;i<160;i++)                                   // we start at pos 32 with the real values... everything before is 0
-  {
-   if(r<0x3FFFFFFF)
-    {
-     r+=rs;
-     rd++;if(rd==5) {rd=1;rs*=2;}
-    }
-   if(r>0x3FFFFFFF) r=0x3FFFFFFF;
-
-   RateTable[i]=r;
-  }
-}
-
-////////////////////////////////////////////////////////////////////////
-
-static INLINE void StartADSR(int ch)                          // MIX ADSR
-{
- s_chan[ch].ADSRX.lVolume=1;                           // and init some adsr vars
- s_chan[ch].ADSRX.State=0;
- s_chan[ch].ADSRX.EnvelopeVol=0;
-}
-
-////////////////////////////////////////////////////////////////////////
-
-static INLINE int MixADSR(int ch)                             // MIX ADSR
-{    
- static const int sexytable[8]=
-	{0,4,6,8,9,10,11,12};
-
- if(s_chan[ch].bStop)                                  // should be stopped:
-  {                                                    // do release
-   if(s_chan[ch].ADSRX.ReleaseModeExp)
-    {
-     s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18+32+sexytable[(s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7]];
-    }
-   else
-    {
-     s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x0C + 32];
-    }
-
-   if(s_chan[ch].ADSRX.EnvelopeVol<0) 
-    {
-     s_chan[ch].ADSRX.EnvelopeVol=0;
-     s_chan[ch].bOn=0;
-     s_chan[ch].bNoise=0;
-    }
-
-   s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
-   return s_chan[ch].ADSRX.lVolume;
-  }
- else                                                  // not stopped yet?
-  {
-   if(s_chan[ch].ADSRX.State==0)                       // -> attack
-    {
-     if(s_chan[ch].ADSRX.AttackModeExp)
-      {
-       if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) 
-        s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32];
-       else
-        s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + 32];
-      }
-     else
-      {
-       s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32];
-      }
-
-     if(s_chan[ch].ADSRX.EnvelopeVol<0) 
-      {
-       s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF;
-       s_chan[ch].ADSRX.State=1;
-      }
-
-     s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
-     return s_chan[ch].ADSRX.lVolume;
-    }
-   //--------------------------------------------------//
-   if(s_chan[ch].ADSRX.State==1)                       // -> decay
-    {
-     s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+32+sexytable[(s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7]];
-
-     if(s_chan[ch].ADSRX.EnvelopeVol<0) s_chan[ch].ADSRX.EnvelopeVol=0;
-     if(((s_chan[ch].ADSRX.EnvelopeVol>>27)&0xF) <= s_chan[ch].ADSRX.SustainLevel)
-      {
-       s_chan[ch].ADSRX.State=2;
-      }
-
-     s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
-     return s_chan[ch].ADSRX.lVolume;
-    }
-   //--------------------------------------------------//
-   if(s_chan[ch].ADSRX.State==2)                       // -> sustain
-    {
-     if(s_chan[ch].ADSRX.SustainIncrease)
-      {
-       if(s_chan[ch].ADSRX.SustainModeExp)
-        {
-         if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) 
-          s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32];
-         else
-          s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x18 + 32];
-        }
-       else
-        {
-         s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32];
-        }
-
-       if(s_chan[ch].ADSRX.EnvelopeVol<0) 
-        {
-         s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF;
-        }
-      }
-     else
-      {
-       if(s_chan[ch].ADSRX.SustainModeExp)
-        s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B+32+sexytable[(s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7]];
-       else
-        s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x0F + 32];
-
-       if(s_chan[ch].ADSRX.EnvelopeVol<0) 
-        {
-         s_chan[ch].ADSRX.EnvelopeVol=0;
-        }
-      }
-     s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
-     return s_chan[ch].ADSRX.lVolume;
-    }
-  }
- return 0;
-}
-
-#endif
-
-/*
-James Higgs ADSR investigations:
-
-PSX SPU Envelope Timings
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-First, here is an extract from doomed's SPU doc, which explains the basics
-of the SPU "volume envelope": 
-
-*** doomed doc extract start ***
-
---------------------------------------------------------------------------
-Voices.
---------------------------------------------------------------------------
-The SPU has 24 hardware voices. These voices can be used to reproduce sample
-data, noise or can be used as frequency modulator on the next voice.
-Each voice has it's own programmable ADSR envelope filter. The main volume
-can be programmed independently for left and right output.
-
-The ADSR envelope filter works as follows:
-Ar = Attack rate, which specifies the speed at which the volume increases
-     from zero to it's maximum value, as soon as the note on is given. The
-     slope can be set to lineair or exponential.
-Dr = Decay rate specifies the speed at which the volume decreases to the
-     sustain level. Decay is always decreasing exponentially.
-Sl = Sustain level, base level from which sustain starts.
-Sr = Sustain rate is the rate at which the volume of the sustained note
-     increases or decreases. This can be either lineair or exponential.
-Rr = Release rate is the rate at which the volume of the note decreases
-     as soon as the note off is given.
-
-     lvl |
-       ^ |     /\Dr     __
-     Sl _| _  / _ \__---  \
-         |   /       ---__ \ Rr
-         |  /Ar       Sr  \ \
-         | /                \\
-         |/___________________\________
-                                  ->time
-
-The overal volume can also be set to sweep up or down lineairly or
-exponentially from it's current value. This can be done seperately
-for left and right.
-
-Relevant SPU registers:
--------------------------------------------------------------
-$1f801xx8         Attack/Decay/Sustain level
-bit  |0f|0e 0d 0c 0b 0a 09 08|07 06 05 04|03 02 01 00|
-desc.|Am|         Ar         |Dr         |Sl         |
-
-Am       0        Attack mode Linear
-         1                    Exponential
-
-Ar       0-7f     attack rate
-Dr       0-f      decay rate
-Sl       0-f      sustain level
--------------------------------------------------------------
-$1f801xxa         Sustain rate, Release Rate.
-bit  |0f|0e|0d|0c 0b 0a 09 08 07 06|05|04 03 02 01 00|
-desc.|Sm|Sd| 0|   Sr               |Rm|Rr            |
-
-Sm       0        sustain rate mode linear
-         1                          exponential
-Sd       0        sustain rate mode increase
-         1                          decrease
-Sr       0-7f     Sustain Rate
-Rm       0        Linear decrease
-         1        Exponential decrease
-Rr       0-1f     Release Rate
-
-Note: decay mode is always Expontial decrease, and thus cannot
-be set.
--------------------------------------------------------------
-$1f801xxc         Current ADSR volume
-bit  |0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00|
-desc.|ADSRvol                                        |
-
-ADSRvol           Returns the current envelope volume when
-                  read.
--- James' Note: return range: 0 -> 32767
-
-*** doomed doc extract end *** 
-
-By using a small PSX proggie to visualise the envelope as it was played,
-the following results for envelope timing were obtained:
-
-1. Attack rate value (linear mode)
-
-   Attack value range: 0 -> 127
-
-   Value  | 48 | 52 | 56 | 60 | 64 | 68 | 72 |    | 80 |
-   -----------------------------------------------------------------
-   Frames | 11 | 21 | 42 | 84 | 169| 338| 676|    |2890|
-
-   Note: frames is no. of PAL frames to reach full volume (100%
-   amplitude)
-
-   Hmm, noticing that the time taken to reach full volume doubles
-   every time we add 4 to our attack value, we know the equation is
-   of form:
-             frames = k * 2 ^ (value / 4)
-
-   (You may ponder about envelope generator hardware at this point,
-   or maybe not... :)
-
-   By substituting some stuff and running some checks, we get:
-
-       k = 0.00257              (close enuf)
-
-   therefore,
-             frames = 0.00257 * 2 ^ (value / 4)
-   If you just happen to be writing an emulator, then you can probably
-   use an equation like:
-
-       %volume_increase_per_tick = 1 / frames
-
-
-   ------------------------------------
-   Pete:
-   ms=((1<<(value>>2))*514)/10000
-   ------------------------------------
-
-2. Decay rate value (only has log mode)
-
-   Decay value range: 0 -> 15
-
-   Value  |  8 |  9 | 10 | 11 | 12 | 13 | 14 | 15 |
-   ------------------------------------------------
-   frames |    |    |    |    |  6 | 12 | 24 | 47 |
-
-   Note: frames here is no. of PAL frames to decay to 50% volume.
-
-   formula: frames = k * 2 ^ (value)
-
-   Substituting, we get: k = 0.00146
-
-   Further info on logarithmic nature:
-   frames to decay to sustain level 3  =  3 * frames to decay to 
-   sustain level 9
-
-   Also no. of frames to 25% volume = roughly 1.85 * no. of frames to
-   50% volume.
-
-   Frag it - just use linear approx.
-
-   ------------------------------------
-   Pete:
-   ms=((1<<value)*292)/10000
-   ------------------------------------
-
-
-3. Sustain rate value (linear mode)
-
-   Sustain rate range: 0 -> 127
-
-   Value  | 48 | 52 | 56 | 60 | 64 | 68 | 72 |
-   -------------------------------------------
-   frames |  9 | 19 | 37 | 74 | 147| 293| 587|
-
-   Here, frames = no. of PAL frames for volume amplitude to go from 100%
-   to 0% (or vice-versa).
-
-   Same formula as for attack value, just a different value for k:
-
-   k = 0.00225
-
-   ie: frames = 0.00225 * 2 ^ (value / 4)
-
-   For emulation purposes:
-
-   %volume_increase_or_decrease_per_tick = 1 / frames
-
-   ------------------------------------
-   Pete:
-   ms=((1<<(value>>2))*450)/10000
-   ------------------------------------
-
-
-4. Release rate (linear mode)
-
-   Release rate range: 0 -> 31
-
-   Value  | 13 | 14 | 15 | 16 | 17 |
-   ---------------------------------------------------------------
-   frames | 18 | 36 | 73 | 146| 292|
-
-   Here, frames = no. of PAL frames to decay from 100% vol to 0% vol
-   after "note-off" is triggered.
-
-   Formula: frames = k * 2 ^ (value)
-
-   And so: k = 0.00223
-
-   ------------------------------------
-   Pete:
-   ms=((1<<value)*446)/10000
-   ------------------------------------
-
-
-Other notes:   
-
-Log stuff not figured out. You may get some clues from the "Decay rate"
-stuff above. For emu purposes it may not be important - use linear
-approx.
-
-To get timings in millisecs, multiply frames by 20.
-
-
-
-- James Higgs 17/6/2000
-james7780@yahoo.com
-
-//---------------------------------------------------------------
-
-OLD adsr mixing according to james' rules... has to be called
-every one millisecond
-
-
- i32 v,v2,lT,l1,l2,l3;
-
- if(s_chan[ch].bStop)                                  // psx wants to stop? -> release phase
-  {
-   if(s_chan[ch].ADSR.ReleaseVal!=0)                   // -> release not 0: do release (if 0: stop right now)
-    {
-     if(!s_chan[ch].ADSR.ReleaseVol)                   // --> release just started? set up the release stuff
-      {
-       s_chan[ch].ADSR.ReleaseStartTime=s_chan[ch].ADSR.lTime;
-       s_chan[ch].ADSR.ReleaseVol=s_chan[ch].ADSR.lVolume;
-       s_chan[ch].ADSR.ReleaseTime =                   // --> calc how long does it take to reach the wanted sus level
-         (s_chan[ch].ADSR.ReleaseTime*
-          s_chan[ch].ADSR.ReleaseVol)/1024;
-      }
-                                                       // -> NO release exp mode used (yet)
-     v=s_chan[ch].ADSR.ReleaseVol;                     // -> get last volume
-     lT=s_chan[ch].ADSR.lTime-                         // -> how much time is past?
-        s_chan[ch].ADSR.ReleaseStartTime;
-     l1=s_chan[ch].ADSR.ReleaseTime;
-                                                       
-     if(lT<l1)                                         // -> we still have to release
-      {
-       v=v-((v*lT)/l1);                                // --> calc new volume
-      }
-     else                                              // -> release is over: now really stop that sample
-      {v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;}
-    }
-   else                                                // -> release IS 0: release at once
-    {
-     v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;
-    }
-  }
- else                                               
-  {//--------------------------------------------------// not in release phase:
-   v=1024;
-   lT=s_chan[ch].ADSR.lTime;
-   l1=s_chan[ch].ADSR.AttackTime;
-                                                       
-   if(lT<l1)                                           // attack
-    {                                                  // no exp mode used (yet)
-//     if(s_chan[ch].ADSR.AttackModeExp)
-//      {
-//       v=(v*lT)/l1;
-//      }
-//     else
-      {
-       v=(v*lT)/l1;
-      }
-     if(v==0) v=1;
-    }
-   else                                                // decay
-    {                                                  // should be exp, but who cares? ;)
-     l2=s_chan[ch].ADSR.DecayTime;
-     v2=s_chan[ch].ADSR.SustainLevel;
-
-     lT-=l1;
-     if(lT<l2)
-      {
-       v-=(((v-v2)*lT)/l2);
-      }
-     else                                              // sustain
-      {                                                // no exp mode used (yet)
-       l3=s_chan[ch].ADSR.SustainTime;
-       lT-=l2;
-       if(s_chan[ch].ADSR.SustainModeDec>0)
-        {
-         if(l3!=0) v2+=((v-v2)*lT)/l3;
-         else      v2=v;
-        }
-       else
-        {
-         if(l3!=0) v2-=(v2*lT)/l3;
-         else      v2=v;
-        }
-
-       if(v2>v)  v2=v;
-       if(v2<=0) {v2=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;}
-
-       v=v2;
-      }
-    }
-  }
-
- //----------------------------------------------------// 
- // ok, done for this channel, so increase time
-
- s_chan[ch].ADSR.lTime+=1;                             // 1 = 1.020408f ms;      
-
- if(v>1024)     v=1024;                                // adjust volume
- if(v<0)        v=0;                                  
- s_chan[ch].ADSR.lVolume=v;                            // store act volume
-
- return v;                                             // return the volume factor
-*/
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-
-/*
------------------------------------------------------------------------------
-Neill Corlett
-Playstation SPU envelope timing notes
------------------------------------------------------------------------------
-
-This is preliminary.  This may be wrong.  But the model described herein fits
-all of my experimental data, and it's just simple enough to sound right.
-
-ADSR envelope level ranges from 0x00000000 to 0x7FFFFFFF internally.
-The value returned by channel reg 0xC is (envelope_level>>16).
-
-Each sample, an increment or decrement value will be added to or
-subtracted from this envelope level.
-
-Create the rate log table.  The values double every 4 entries.
-   entry #0 = 4
-
-    4, 5, 6, 7,
-    8,10,12,14,
-   16,20,24,28, ...
-
-   entry #40 = 4096...
-   entry #44 = 8192...
-   entry #48 = 16384...
-   entry #52 = 32768...
-   entry #56 = 65536...
-
-increments and decrements are in terms of ratelogtable[n]
-n may exceed the table bounds (plan on n being between -32 and 127).
-table values are all clipped between 0x00000000 and 0x3FFFFFFF
-
-when you "voice on", the envelope is always fully reset.
-(yes, it may click. the real thing does this too.)
-
-envelope level begins at zero.
-
-each state happens for at least 1 cycle
-(transitions are not instantaneous)
-this may result in some oddness: if the decay rate is uberfast, it will cut
-the envelope from full down to half in one sample, potentially skipping over
-the sustain level
-
-ATTACK
-------
-- if the envelope level has overflowed past the max, clip to 0x7FFFFFFF and
-  proceed to DECAY.
-
-Linear attack mode:
-- line extends upward to 0x7FFFFFFF
-- increment per sample is ratelogtable[(Ar^0x7F)-0x10]
-
-Logarithmic attack mode:
-if envelope_level < 0x60000000:
-  - line extends upward to 0x60000000
-  - increment per sample is ratelogtable[(Ar^0x7F)-0x10]
-else:
-  - line extends upward to 0x7FFFFFFF
-  - increment per sample is ratelogtable[(Ar^0x7F)-0x18]
-
-DECAY
------
-- if ((envelope_level>>27)&0xF) <= Sl, proceed to SUSTAIN.
-  Do not clip to the sustain level.
-- current line ends at (envelope_level & 0x07FFFFFF)
-- decrement per sample depends on (envelope_level>>28)&0x7
-  0: ratelogtable[(4*(Dr^0x1F))-0x18+0]
-  1: ratelogtable[(4*(Dr^0x1F))-0x18+4]
-  2: ratelogtable[(4*(Dr^0x1F))-0x18+6]
-  3: ratelogtable[(4*(Dr^0x1F))-0x18+8]
-  4: ratelogtable[(4*(Dr^0x1F))-0x18+9]
-  5: ratelogtable[(4*(Dr^0x1F))-0x18+10]
-  6: ratelogtable[(4*(Dr^0x1F))-0x18+11]
-  7: ratelogtable[(4*(Dr^0x1F))-0x18+12]
-  (note that this is the same as the release rate formula, except that
-   decay rates 10-1F aren't possible... those would be slower in theory)
-
-SUSTAIN
--------
-- no terminating condition except for voice off
-- Sd=0 (increase) behavior is identical to ATTACK for both log and linear.
-- Sd=1 (decrease) behavior:
-Linear sustain decrease:
-- line extends to 0x00000000
-- decrement per sample is ratelogtable[(Sr^0x7F)-0x0F]
-Logarithmic sustain decrease:
-- current line ends at (envelope_level & 0x07FFFFFF)
-- decrement per sample depends on (envelope_level>>28)&0x7
-  0: ratelogtable[(Sr^0x7F)-0x1B+0]
-  1: ratelogtable[(Sr^0x7F)-0x1B+4]
-  2: ratelogtable[(Sr^0x7F)-0x1B+6]
-  3: ratelogtable[(Sr^0x7F)-0x1B+8]
-  4: ratelogtable[(Sr^0x7F)-0x1B+9]
-  5: ratelogtable[(Sr^0x7F)-0x1B+10]
-  6: ratelogtable[(Sr^0x7F)-0x1B+11]
-  7: ratelogtable[(Sr^0x7F)-0x1B+12]
-
-RELEASE
--------
-- if the envelope level has overflowed to negative, clip to 0 and QUIT.
-
-Linear release mode:
-- line extends to 0x00000000
-- decrement per sample is ratelogtable[(4*(Rr^0x1F))-0x0C]
-
-Logarithmic release mode:
-- line extends to (envelope_level & 0x0FFFFFFF)
-- decrement per sample depends on (envelope_level>>28)&0x7
-  0: ratelogtable[(4*(Rr^0x1F))-0x18+0]
-  1: ratelogtable[(4*(Rr^0x1F))-0x18+4]
-  2: ratelogtable[(4*(Rr^0x1F))-0x18+6]
-  3: ratelogtable[(4*(Rr^0x1F))-0x18+8]
-  4: ratelogtable[(4*(Rr^0x1F))-0x18+9]
-  5: ratelogtable[(4*(Rr^0x1F))-0x18+10]
-  6: ratelogtable[(4*(Rr^0x1F))-0x18+11]
-  7: ratelogtable[(4*(Rr^0x1F))-0x18+12]
-
------------------------------------------------------------------------------
-*/
+/***************************************************************************
+                          adsr.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2003/05/14 - xodnizel
+// - removed stopping of reverb on sample end
+//
+// 2003/01/06 - Pete
+// - added Neill's ADSR timings
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_ADSR
+
+// will be included from spu.c
+#ifdef _IN_SPU
+
+////////////////////////////////////////////////////////////////////////
+// ADSR func
+////////////////////////////////////////////////////////////////////////
+
+unsigned long RateTable[160];
+
+void InitADSR(void)                                    // INIT ADSR
+{
+ unsigned long r,rs,rd;int i;
+
+ memset(RateTable,0,sizeof(unsigned long)*160);        // build the rate table according to Neill's rules (see at bottom of file)
+
+ r=3;rs=1;rd=0;
+
+ for(i=32;i<160;i++)                                   // we start at pos 32 with the real values... everything before is 0
+  {
+   if(r<0x3FFFFFFF)
+    {
+     r+=rs;
+     rd++;if(rd==5) {rd=1;rs*=2;}
+    }
+   if(r>0x3FFFFFFF) r=0x3FFFFFFF;
+
+   RateTable[i]=r;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE void StartADSR(int ch)                          // MIX ADSR
+{
+ s_chan[ch].ADSRX.lVolume=1;                           // and init some adsr vars
+ s_chan[ch].ADSRX.State=0;
+ s_chan[ch].ADSRX.EnvelopeVol=0;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE int MixADSR(int ch)                             // MIX ADSR
+{    
+ if(s_chan[ch].bStop)                                  // should be stopped:
+  {                                                    // do release
+   if(s_chan[ch].ADSRX.ReleaseModeExp)
+    {
+     switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7)
+      {
+       case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +0 + 32]; break;
+       case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +4 + 32]; break;
+       case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +6 + 32]; break;
+       case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +8 + 32]; break;
+       case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +9 + 32]; break;
+       case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +10+ 32]; break;
+       case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +11+ 32]; break;
+       case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +12+ 32]; break;
+      }
+    }
+   else
+    {
+     s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x0C + 32];
+    }
+
+   if(s_chan[ch].ADSRX.EnvelopeVol<0) 
+    {
+     s_chan[ch].ADSRX.EnvelopeVol=0;
+     s_chan[ch].bOn=0;
+     //s_chan[ch].bReverb=0;
+     //s_chan[ch].bNoise=0;
+    }
+
+   s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
+   return s_chan[ch].ADSRX.lVolume;
+  }
+ else                                                  // not stopped yet?
+  {
+   if(s_chan[ch].ADSRX.State==0)                       // -> attack
+    {
+     if(s_chan[ch].ADSRX.AttackModeExp)
+      {
+       if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) 
+        s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32];
+       else
+        s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + 32];
+      }
+     else
+      {
+       s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32];
+      }
+
+     if(s_chan[ch].ADSRX.EnvelopeVol<0) 
+      {
+       s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF;
+       s_chan[ch].ADSRX.State=1;
+      }
+
+     s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
+     return s_chan[ch].ADSRX.lVolume;
+    }
+   //--------------------------------------------------//
+   if(s_chan[ch].ADSRX.State==1)                       // -> decay
+    {
+     switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7)
+      {
+       case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+0 + 32]; break;
+       case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+4 + 32]; break;
+       case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+6 + 32]; break;
+       case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+8 + 32]; break;
+       case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+9 + 32]; break;
+       case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+10+ 32]; break;
+       case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+11+ 32]; break;
+       case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+12+ 32]; break;
+      }
+
+     if(s_chan[ch].ADSRX.EnvelopeVol<0) s_chan[ch].ADSRX.EnvelopeVol=0;
+     if(((s_chan[ch].ADSRX.EnvelopeVol>>27)&0xF) <= s_chan[ch].ADSRX.SustainLevel)
+      {
+       s_chan[ch].ADSRX.State=2;
+      }
+
+     s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
+     return s_chan[ch].ADSRX.lVolume;
+    }
+   //--------------------------------------------------//
+   if(s_chan[ch].ADSRX.State==2)                       // -> sustain
+    {
+     if(s_chan[ch].ADSRX.SustainIncrease)
+      {
+       if(s_chan[ch].ADSRX.SustainModeExp)
+        {
+         if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) 
+          s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32];
+         else
+          s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x18 + 32];
+        }
+       else
+        {
+         s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32];
+        }
+
+       if(s_chan[ch].ADSRX.EnvelopeVol<0) 
+        {
+         s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF;
+        }
+      }
+     else
+      {
+       if(s_chan[ch].ADSRX.SustainModeExp)
+        {
+         switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7)
+          {
+           case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +0 + 32];break;
+           case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +4 + 32];break;
+           case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +6 + 32];break;
+           case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +8 + 32];break;
+           case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +9 + 32];break;
+           case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +10+ 32];break;
+           case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +11+ 32];break;
+           case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +12+ 32];break;
+          }
+        }
+       else
+        {
+         s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x0F + 32];
+        }
+
+       if(s_chan[ch].ADSRX.EnvelopeVol<0) 
+        {
+         s_chan[ch].ADSRX.EnvelopeVol=0;
+        }
+      }
+     s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
+     return s_chan[ch].ADSRX.lVolume;
+    }
+  }
+ return 0;
+}
+
+#endif
+
+/*
+James Higgs ADSR investigations:
+
+PSX SPU Envelope Timings
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+First, here is an extract from doomed's SPU doc, which explains the basics
+of the SPU "volume envelope": 
+
+*** doomed doc extract start ***
+
+--------------------------------------------------------------------------
+Voices.
+--------------------------------------------------------------------------
+The SPU has 24 hardware voices. These voices can be used to reproduce sample
+data, noise or can be used as frequency modulator on the next voice.
+Each voice has it's own programmable ADSR envelope filter. The main volume
+can be programmed independently for left and right output.
+
+The ADSR envelope filter works as follows:
+Ar = Attack rate, which specifies the speed at which the volume increases
+     from zero to it's maximum value, as soon as the note on is given. The
+     slope can be set to lineair or exponential.
+Dr = Decay rate specifies the speed at which the volume decreases to the
+     sustain level. Decay is always decreasing exponentially.
+Sl = Sustain level, base level from which sustain starts.
+Sr = Sustain rate is the rate at which the volume of the sustained note
+     increases or decreases. This can be either lineair or exponential.
+Rr = Release rate is the rate at which the volume of the note decreases
+     as soon as the note off is given.
+
+     lvl |
+       ^ |     /\Dr     __
+     Sl _| _  / _ \__---  \
+         |   /       ---__ \ Rr
+         |  /Ar       Sr  \ \
+         | /                \\
+         |/___________________\________
+                                  ->time
+
+The overal volume can also be set to sweep up or down lineairly or
+exponentially from it's current value. This can be done seperately
+for left and right.
+
+Relevant SPU registers:
+-------------------------------------------------------------
+$1f801xx8         Attack/Decay/Sustain level
+bit  |0f|0e 0d 0c 0b 0a 09 08|07 06 05 04|03 02 01 00|
+desc.|Am|         Ar         |Dr         |Sl         |
+
+Am       0        Attack mode Linear
+         1                    Exponential
+
+Ar       0-7f     attack rate
+Dr       0-f      decay rate
+Sl       0-f      sustain level
+-------------------------------------------------------------
+$1f801xxa         Sustain rate, Release Rate.
+bit  |0f|0e|0d|0c 0b 0a 09 08 07 06|05|04 03 02 01 00|
+desc.|Sm|Sd| 0|   Sr               |Rm|Rr            |
+
+Sm       0        sustain rate mode linear
+         1                          exponential
+Sd       0        sustain rate mode increase
+         1                          decrease
+Sr       0-7f     Sustain Rate
+Rm       0        Linear decrease
+         1        Exponential decrease
+Rr       0-1f     Release Rate
+
+Note: decay mode is always Expontial decrease, and thus cannot
+be set.
+-------------------------------------------------------------
+$1f801xxc         Current ADSR volume
+bit  |0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00|
+desc.|ADSRvol                                        |
+
+ADSRvol           Returns the current envelope volume when
+                  read.
+-- James' Note: return range: 0 -> 32767
+
+*** doomed doc extract end *** 
+
+By using a small PSX proggie to visualise the envelope as it was played,
+the following results for envelope timing were obtained:
+
+1. Attack rate value (linear mode)
+
+   Attack value range: 0 -> 127
+
+   Value  | 48 | 52 | 56 | 60 | 64 | 68 | 72 |    | 80 |
+   -----------------------------------------------------------------
+   Frames | 11 | 21 | 42 | 84 | 169| 338| 676|    |2890|
+
+   Note: frames is no. of PAL frames to reach full volume (100%
+   amplitude)
+
+   Hmm, noticing that the time taken to reach full volume doubles
+   every time we add 4 to our attack value, we know the equation is
+   of form:
+             frames = k * 2 ^ (value / 4)
+
+   (You may ponder about envelope generator hardware at this point,
+   or maybe not... :)
+
+   By substituting some stuff and running some checks, we get:
+
+       k = 0.00257              (close enuf)
+
+   therefore,
+             frames = 0.00257 * 2 ^ (value / 4)
+   If you just happen to be writing an emulator, then you can probably
+   use an equation like:
+
+       %volume_increase_per_tick = 1 / frames
+
+
+   ------------------------------------
+   Pete:
+   ms=((1<<(value>>2))*514)/10000
+   ------------------------------------
+
+2. Decay rate value (only has log mode)
+
+   Decay value range: 0 -> 15
+
+   Value  |  8 |  9 | 10 | 11 | 12 | 13 | 14 | 15 |
+   ------------------------------------------------
+   frames |    |    |    |    |  6 | 12 | 24 | 47 |
+
+   Note: frames here is no. of PAL frames to decay to 50% volume.
+
+   formula: frames = k * 2 ^ (value)
+
+   Substituting, we get: k = 0.00146
+
+   Further info on logarithmic nature:
+   frames to decay to sustain level 3  =  3 * frames to decay to 
+   sustain level 9
+
+   Also no. of frames to 25% volume = roughly 1.85 * no. of frames to
+   50% volume.
+
+   Frag it - just use linear approx.
+
+   ------------------------------------
+   Pete:
+   ms=((1<<value)*292)/10000
+   ------------------------------------
+
+
+3. Sustain rate value (linear mode)
+
+   Sustain rate range: 0 -> 127
+
+   Value  | 48 | 52 | 56 | 60 | 64 | 68 | 72 |
+   -------------------------------------------
+   frames |  9 | 19 | 37 | 74 | 147| 293| 587|
+
+   Here, frames = no. of PAL frames for volume amplitude to go from 100%
+   to 0% (or vice-versa).
+
+   Same formula as for attack value, just a different value for k:
+
+   k = 0.00225
+
+   ie: frames = 0.00225 * 2 ^ (value / 4)
+
+   For emulation purposes:
+
+   %volume_increase_or_decrease_per_tick = 1 / frames
+
+   ------------------------------------
+   Pete:
+   ms=((1<<(value>>2))*450)/10000
+   ------------------------------------
+
+
+4. Release rate (linear mode)
+
+   Release rate range: 0 -> 31
+
+   Value  | 13 | 14 | 15 | 16 | 17 |
+   ---------------------------------------------------------------
+   frames | 18 | 36 | 73 | 146| 292|
+
+   Here, frames = no. of PAL frames to decay from 100% vol to 0% vol
+   after "note-off" is triggered.
+
+   Formula: frames = k * 2 ^ (value)
+
+   And so: k = 0.00223
+
+   ------------------------------------
+   Pete:
+   ms=((1<<value)*446)/10000
+   ------------------------------------
+
+
+Other notes:   
+
+Log stuff not figured out. You may get some clues from the "Decay rate"
+stuff above. For emu purposes it may not be important - use linear
+approx.
+
+To get timings in millisecs, multiply frames by 20.
+
+
+
+- James Higgs 17/6/2000
+james7780@yahoo.com
+
+//---------------------------------------------------------------
+
+OLD adsr mixing according to james' rules... has to be called
+every one millisecond
+
+
+ long v,v2,lT,l1,l2,l3;
+
+ if(s_chan[ch].bStop)                                  // psx wants to stop? -> release phase
+  {
+   if(s_chan[ch].ADSR.ReleaseVal!=0)                   // -> release not 0: do release (if 0: stop right now)
+    {
+     if(!s_chan[ch].ADSR.ReleaseVol)                   // --> release just started? set up the release stuff
+      {
+       s_chan[ch].ADSR.ReleaseStartTime=s_chan[ch].ADSR.lTime;
+       s_chan[ch].ADSR.ReleaseVol=s_chan[ch].ADSR.lVolume;
+       s_chan[ch].ADSR.ReleaseTime =                   // --> calc how long does it take to reach the wanted sus level
+         (s_chan[ch].ADSR.ReleaseTime*
+          s_chan[ch].ADSR.ReleaseVol)/1024;
+      }
+                                                       // -> NO release exp mode used (yet)
+     v=s_chan[ch].ADSR.ReleaseVol;                     // -> get last volume
+     lT=s_chan[ch].ADSR.lTime-                         // -> how much time is past?
+        s_chan[ch].ADSR.ReleaseStartTime;
+     l1=s_chan[ch].ADSR.ReleaseTime;
+                                                       
+     if(lT<l1)                                         // -> we still have to release
+      {
+       v=v-((v*lT)/l1);                                // --> calc new volume
+      }
+     else                                              // -> release is over: now really stop that sample
+      {v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;}
+    }
+   else                                                // -> release IS 0: release at once
+    {
+     v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;
+    }
+  }
+ else                                               
+  {//--------------------------------------------------// not in release phase:
+   v=1024;
+   lT=s_chan[ch].ADSR.lTime;
+   l1=s_chan[ch].ADSR.AttackTime;
+                                                       
+   if(lT<l1)                                           // attack
+    {                                                  // no exp mode used (yet)
+//     if(s_chan[ch].ADSR.AttackModeExp)
+//      {
+//       v=(v*lT)/l1;
+//      }
+//     else
+      {
+       v=(v*lT)/l1;
+      }
+     if(v==0) v=1;
+    }
+   else                                                // decay
+    {                                                  // should be exp, but who cares? ;)
+     l2=s_chan[ch].ADSR.DecayTime;
+     v2=s_chan[ch].ADSR.SustainLevel;
+
+     lT-=l1;
+     if(lT<l2)
+      {
+       v-=(((v-v2)*lT)/l2);
+      }
+     else                                              // sustain
+      {                                                // no exp mode used (yet)
+       l3=s_chan[ch].ADSR.SustainTime;
+       lT-=l2;
+       if(s_chan[ch].ADSR.SustainModeDec>0)
+        {
+         if(l3!=0) v2+=((v-v2)*lT)/l3;
+         else      v2=v;
+        }
+       else
+        {
+         if(l3!=0) v2-=(v2*lT)/l3;
+         else      v2=v;
+        }
+
+       if(v2>v)  v2=v;
+       if(v2<=0) {v2=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;}
+
+       v=v2;
+      }
+    }
+  }
+
+ //----------------------------------------------------// 
+ // ok, done for this channel, so increase time
+
+ s_chan[ch].ADSR.lTime+=1;                             // 1 = 1.020408f ms;      
+
+ if(v>1024)     v=1024;                                // adjust volume
+ if(v<0)        v=0;                                  
+ s_chan[ch].ADSR.lVolume=v;                            // store act volume
+
+ return v;                                             // return the volume factor
+*/
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+
+/*
+-----------------------------------------------------------------------------
+Neill Corlett
+Playstation SPU envelope timing notes
+-----------------------------------------------------------------------------
+
+This is preliminary.  This may be wrong.  But the model described herein fits
+all of my experimental data, and it's just simple enough to sound right.
+
+ADSR envelope level ranges from 0x00000000 to 0x7FFFFFFF internally.
+The value returned by channel reg 0xC is (envelope_level>>16).
+
+Each sample, an increment or decrement value will be added to or
+subtracted from this envelope level.
+
+Create the rate log table.  The values double every 4 entries.
+   entry #0 = 4
+
+    4, 5, 6, 7,
+    8,10,12,14,
+   16,20,24,28, ...
+
+   entry #40 = 4096...
+   entry #44 = 8192...
+   entry #48 = 16384...
+   entry #52 = 32768...
+   entry #56 = 65536...
+
+increments and decrements are in terms of ratelogtable[n]
+n may exceed the table bounds (plan on n being between -32 and 127).
+table values are all clipped between 0x00000000 and 0x3FFFFFFF
+
+when you "voice on", the envelope is always fully reset.
+(yes, it may click. the real thing does this too.)
+
+envelope level begins at zero.
+
+each state happens for at least 1 cycle
+(transitions are not instantaneous)
+this may result in some oddness: if the decay rate is uberfast, it will cut
+the envelope from full down to half in one sample, potentially skipping over
+the sustain level
+
+ATTACK
+------
+- if the envelope level has overflowed past the max, clip to 0x7FFFFFFF and
+  proceed to DECAY.
+
+Linear attack mode:
+- line extends upward to 0x7FFFFFFF
+- increment per sample is ratelogtable[(Ar^0x7F)-0x10]
+
+Logarithmic attack mode:
+if envelope_level < 0x60000000:
+  - line extends upward to 0x60000000
+  - increment per sample is ratelogtable[(Ar^0x7F)-0x10]
+else:
+  - line extends upward to 0x7FFFFFFF
+  - increment per sample is ratelogtable[(Ar^0x7F)-0x18]
+
+DECAY
+-----
+- if ((envelope_level>>27)&0xF) <= Sl, proceed to SUSTAIN.
+  Do not clip to the sustain level.
+- current line ends at (envelope_level & 0x07FFFFFF)
+- decrement per sample depends on (envelope_level>>28)&0x7
+  0: ratelogtable[(4*(Dr^0x1F))-0x18+0]
+  1: ratelogtable[(4*(Dr^0x1F))-0x18+4]
+  2: ratelogtable[(4*(Dr^0x1F))-0x18+6]
+  3: ratelogtable[(4*(Dr^0x1F))-0x18+8]
+  4: ratelogtable[(4*(Dr^0x1F))-0x18+9]
+  5: ratelogtable[(4*(Dr^0x1F))-0x18+10]
+  6: ratelogtable[(4*(Dr^0x1F))-0x18+11]
+  7: ratelogtable[(4*(Dr^0x1F))-0x18+12]
+  (note that this is the same as the release rate formula, except that
+   decay rates 10-1F aren't possible... those would be slower in theory)
+
+SUSTAIN
+-------
+- no terminating condition except for voice off
+- Sd=0 (increase) behavior is identical to ATTACK for both log and linear.
+- Sd=1 (decrease) behavior:
+Linear sustain decrease:
+- line extends to 0x00000000
+- decrement per sample is ratelogtable[(Sr^0x7F)-0x0F]
+Logarithmic sustain decrease:
+- current line ends at (envelope_level & 0x07FFFFFF)
+- decrement per sample depends on (envelope_level>>28)&0x7
+  0: ratelogtable[(Sr^0x7F)-0x1B+0]
+  1: ratelogtable[(Sr^0x7F)-0x1B+4]
+  2: ratelogtable[(Sr^0x7F)-0x1B+6]
+  3: ratelogtable[(Sr^0x7F)-0x1B+8]
+  4: ratelogtable[(Sr^0x7F)-0x1B+9]
+  5: ratelogtable[(Sr^0x7F)-0x1B+10]
+  6: ratelogtable[(Sr^0x7F)-0x1B+11]
+  7: ratelogtable[(Sr^0x7F)-0x1B+12]
+
+RELEASE
+-------
+- if the envelope level has overflowed to negative, clip to 0 and QUIT.
+
+Linear release mode:
+- line extends to 0x00000000
+- decrement per sample is ratelogtable[(4*(Rr^0x1F))-0x0C]
+
+Logarithmic release mode:
+- line extends to (envelope_level & 0x0FFFFFFF)
+- decrement per sample depends on (envelope_level>>28)&0x7
+  0: ratelogtable[(4*(Rr^0x1F))-0x18+0]
+  1: ratelogtable[(4*(Rr^0x1F))-0x18+4]
+  2: ratelogtable[(4*(Rr^0x1F))-0x18+6]
+  3: ratelogtable[(4*(Rr^0x1F))-0x18+8]
+  4: ratelogtable[(4*(Rr^0x1F))-0x18+9]
+  5: ratelogtable[(4*(Rr^0x1F))-0x18+10]
+  6: ratelogtable[(4*(Rr^0x1F))-0x18+11]
+  7: ratelogtable[(4*(Rr^0x1F))-0x18+12]
+
+-----------------------------------------------------------------------------
+*/
+
--- a/Plugins/Input/sexypsf/spu/adsr.h	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/adsr.h	Sun Mar 19 12:51:03 2006 -0800
@@ -1,28 +1,28 @@
-/***************************************************************************
-                           adsr.h  -  description
-                             -------------------
-    begin                : Wed May 15 2002
-    copyright            : (C) 2002 by Pete Bernert
-    email                : BlackDove@addcom.de
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version. See also the license.txt file for *
- *   additional informations.                                              *
- *                                                                         *
- ***************************************************************************/
-
-//*************************************************************************//
-// History of changes:
-//
-// 2002/05/15 - Pete
-// - generic cleanup for the Peops release
-//
-//*************************************************************************//
-
-static INLINE void StartADSR(int ch);
-static INLINE int  MixADSR(int ch);
+/***************************************************************************
+                           adsr.h  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+INLINE void StartADSR(int ch);
+INLINE int  MixADSR(int ch);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/alsa.c	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,206 @@
+/***************************************************************************
+                            alsa.c  -  description
+                             -------------------
+    begin                : Sat Mar 01 2003
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2003/03/02 - linuzappz
+// - fixed XRUN behavior
+//
+// 2003/03/01 - linuzappz
+// - created
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_OSS
+
+#include "externals.h"
+
+#ifndef _WINDOWS
+
+#define ALSA_PCM_NEW_HW_PARAMS_API
+#define ALSA_PCM_NEW_SW_PARAMS_API
+#include <alsa/asoundlib.h>
+
+////////////////////////////////////////////////////////////////////////
+// small linux time helper... only used for watchdog
+////////////////////////////////////////////////////////////////////////
+
+unsigned long timeGetTime()
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);                                 // well, maybe there are better ways
+ return tv.tv_sec * 1000 + tv.tv_usec/1000;            // to do that, but at least it works
+}
+
+////////////////////////////////////////////////////////////////////////
+// oss globals
+////////////////////////////////////////////////////////////////////////
+
+#define ALSA_MEM_DEF
+#include "alsa.h"
+static snd_pcm_t *handle = NULL;
+static snd_pcm_uframes_t buffer_size;
+
+////////////////////////////////////////////////////////////////////////
+// SETUP SOUND
+////////////////////////////////////////////////////////////////////////
+
+void SetupSound(void)
+{
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_status_t *status;
+ int pspeed;
+ int pchannels;
+ int format;
+ int buffer_time;
+ int period_time;
+ int err;
+
+ if(iDisStereo) pchannels=1;
+ else pchannels=2;
+
+ pspeed=44100;
+ format=SND_PCM_FORMAT_S16_LE;
+ buffer_time=500000;
+ period_time=buffer_time/4;
+
+ if((err=snd_pcm_open(&handle, "default", 
+                      SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))<0)
+  {
+   printf("Audio open error: %s\n", snd_strerror(err));
+   return;
+  }
+
+ if((err=snd_pcm_nonblock(handle, 0))<0)
+  {
+   printf("Can't set blocking moded: %s\n", snd_strerror(err));
+   return;
+  }
+
+ snd_pcm_hw_params_alloca(&hwparams);
+ snd_pcm_sw_params_alloca(&swparams);
+ if((err=snd_pcm_hw_params_any(handle, hwparams))<0)
+  {
+   printf("Broken configuration for this PCM: %s\n", snd_strerror(err));
+   return;
+  }
+
+ if((err=snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED))<0)
+  {
+   printf("Access type not available: %s\n", snd_strerror(err));
+   return;
+  }
+
+ if((err=snd_pcm_hw_params_set_format(handle, hwparams, format))<0)
+  {
+   printf("Sample format not available: %s\n", snd_strerror(err));
+   return;
+  }
+
+ if((err=snd_pcm_hw_params_set_channels(handle, hwparams, pchannels))<0)
+  {
+   printf("Channels count not available: %s\n", snd_strerror(err));
+   return;
+  }
+
+ if((err=snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0))<0)
+  {
+   printf("Rate not available: %s\n", snd_strerror(err));
+   return;
+  }
+
+ if((err=snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0))<0)
+  {
+   printf("Buffer time error: %s\n", snd_strerror(err));
+   return;
+  }
+
+ if((err=snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0))<0)
+  {
+   printf("Period time error: %s\n", snd_strerror(err));
+   return;
+  }
+
+ if((err=snd_pcm_hw_params(handle, hwparams))<0)
+  {
+   printf("Unable to install hw params: %s\n", snd_strerror(err));
+   return;
+  }
+
+ snd_pcm_status_alloca(&status);
+ if((err=snd_pcm_status(handle, status))<0)
+  {
+   printf("Unable to get status: %s\n", snd_strerror(err));
+   return;
+  }
+
+ buffer_size=snd_pcm_status_get_avail(status);
+}
+
+////////////////////////////////////////////////////////////////////////
+// REMOVE SOUND
+////////////////////////////////////////////////////////////////////////
+
+void RemoveSound(void)
+{
+ if(handle != NULL)
+  {
+   snd_pcm_drop(handle);
+   snd_pcm_close(handle);
+   handle = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// GET BYTES BUFFERED
+////////////////////////////////////////////////////////////////////////
+
+unsigned long SoundGetBytesBuffered(void)
+{
+ unsigned long l;
+
+ if(handle == NULL)                                 // failed to open?
+  return SOUNDSIZE;
+ l = snd_pcm_avail_update(handle);
+ if(l<0) return 0;
+ if(l<buffer_size/2)                                 // can we write in at least the half of fragments?
+      l=SOUNDSIZE;                                   // -> no? wait
+ else l=0;                                           // -> else go on
+
+ return l;
+}
+
+////////////////////////////////////////////////////////////////////////
+// FEED SOUND DATA
+////////////////////////////////////////////////////////////////////////
+
+void SoundFeedStreamData(unsigned char* pSound,long lBytes)
+{
+ if(handle == NULL) return;
+
+ if(snd_pcm_state(handle) == SND_PCM_STATE_XRUN)
+  snd_pcm_prepare(handle);
+ snd_pcm_writei(handle,pSound,
+                iDisStereo == 1 ? lBytes/2 : lBytes/4);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/alsa.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,30 @@
+/***************************************************************************
+                          alsa.h  -  description
+                             -------------------
+    begin                : Sat Mar 01 2003
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+
+#ifndef _ALSA_SOUND_H
+#define _ALSA_SOUND_H
+
+#ifdef ALSA_MEM_DEF
+#define ALSA_MEM_EXTERN
+#else
+#define ALSA_MEM_EXTERN extern
+#endif
+
+ALSA_MEM_EXTERN int sound_buffer_size;
+
+#endif // _ALSA_SOUND_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/cfg.c	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,478 @@
+/***************************************************************************
+                            cfg.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2003/06/07 - Pete
+// - added Linux NOTHREADLIB define
+//
+// 2003/02/28 - Pete
+// - added option for kode54's interpolation and linuzappz's mono mode
+//
+// 2003/01/19 - Pete
+// - added Neill's reverb
+//
+// 2002/08/04 - Pete
+// - small linux bug fix: now the cfg file can be in the main emu directory as well
+//
+// 2002/06/08 - linuzappz
+// - Added combo str for SPUasync, and MAXMODE is now defined as 2
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_CFG
+
+#include "externals.h"
+
+////////////////////////////////////////////////////////////////////////
+// WINDOWS CONFIG/ABOUT HANDLING
+////////////////////////////////////////////////////////////////////////
+
+#ifdef _WINDOWS
+
+#include "resource.h"
+
+////////////////////////////////////////////////////////////////////////
+// simple about dlg handler
+////////////////////////////////////////////////////////////////////////
+
+BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+  {
+   case WM_COMMAND:
+    {
+     switch(LOWORD(wParam))
+      {case IDOK:  EndDialog(hW,TRUE);return TRUE;}
+    }
+  }
+ return FALSE;
+}
+
+////////////////////////////////////////////////////////////////////////
+// READ CONFIG: from win registry
+////////////////////////////////////////////////////////////////////////
+
+// timer mode 2 (spuupdate sync mode) can be enabled for windows
+// by setting MAXMODE to 2. 
+// Attention: that mode is not much tested, maybe the dsound buffers 
+// need to get adjusted to use that mode safely. Also please note:
+// sync sound updates will _always_ cause glitches, if the system is
+// busy by, for example, long lasting cdrom accesses. OK, you have
+// be warned :)
+
+#define MAXMODE 2
+//#define MAXMODE 1
+
+void ReadConfig(void)
+{
+ HKEY myKey;
+ DWORD temp;
+ DWORD type;
+ DWORD size;
+
+ iUseXA=1;                                             // init vars
+ iVolume=3;
+ iXAPitch=1;
+ iUseTimer=1;
+ iSPUIRQWait=0;
+ iDebugMode=0;
+ iRecordMode=0;
+ iUseReverb=0;
+ iUseInterpolation=2;
+ iDisStereo=0;
+
+ if(RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\SPU2\\PeopsSound",0,KEY_ALL_ACCESS,&myKey)==ERROR_SUCCESS)
+  {
+   size = 4;
+   if(RegQueryValueEx(myKey,"UseXA",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS)
+    iUseXA=(int)temp;
+   size = 4;
+   if(RegQueryValueEx(myKey,"Volume",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS)
+    iVolume=(int)temp;
+   size = 4;
+   if(RegQueryValueEx(myKey,"XAPitch",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS)
+    iXAPitch=(int)temp;
+   size = 4;
+   if(RegQueryValueEx(myKey,"UseTimer",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS)
+    iUseTimer=(int)temp;
+   size = 4;
+   if(RegQueryValueEx(myKey,"SPUIRQWait",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS)
+    iSPUIRQWait=(int)temp;
+   size = 4;
+   if(RegQueryValueEx(myKey,"DebugMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS)
+    iDebugMode=(int)temp;
+   size = 4;
+   if(RegQueryValueEx(myKey,"RecordMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS)
+    iRecordMode=(int)temp;
+   size = 4;
+   if(RegQueryValueEx(myKey,"UseReverb",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS)
+    iUseReverb=(int)temp;
+   size = 4;
+   if(RegQueryValueEx(myKey,"UseInterpolation",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS)
+    iUseInterpolation=(int)temp;
+   size = 4;
+   if(RegQueryValueEx(myKey,"DisStereo",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS)
+    iDisStereo=(int)temp;
+
+   RegCloseKey(myKey);
+  }
+
+ if(iUseTimer>MAXMODE) iUseTimer=MAXMODE;              // some checks
+ if(iVolume<1) iVolume=1;
+ if(iVolume>4) iVolume=4;
+}
+
+////////////////////////////////////////////////////////////////////////
+// WRITE CONFIG: in win registry
+////////////////////////////////////////////////////////////////////////
+
+void WriteConfig(void)
+{
+ HKEY myKey;
+ DWORD myDisp;
+ DWORD temp;
+
+ RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\SPU2\\PeopsSound",0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&myKey,&myDisp);
+ temp=iUseXA;
+ RegSetValueEx(myKey,"UseXA",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp));
+ temp=iVolume;
+ RegSetValueEx(myKey,"Volume",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp));
+ temp=iXAPitch;
+ RegSetValueEx(myKey,"XAPitch",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp));
+ temp=iUseTimer;
+ RegSetValueEx(myKey,"UseTimer",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp));
+ temp=iSPUIRQWait;
+ RegSetValueEx(myKey,"SPUIRQWait",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp));
+ temp=iDebugMode;
+ RegSetValueEx(myKey,"DebugMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp));
+ temp=iRecordMode;
+ RegSetValueEx(myKey,"RecordMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp));
+ temp=iUseReverb;
+ RegSetValueEx(myKey,"UseReverb",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp));
+ temp=iUseInterpolation;
+ RegSetValueEx(myKey,"UseInterpolation",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp));
+ temp=iDisStereo;
+ RegSetValueEx(myKey,"DisStereo",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp));
+
+ RegCloseKey(myKey);
+}
+
+////////////////////////////////////////////////////////////////////////
+// INIT WIN CFG DIALOG
+////////////////////////////////////////////////////////////////////////
+
+BOOL OnInitDSoundDialog(HWND hW) 
+{
+ HWND hWC;
+
+ ReadConfig();
+                
+ if(iUseXA)      CheckDlgButton(hW,IDC_ENABXA,TRUE);
+
+ if(iXAPitch)    CheckDlgButton(hW,IDC_XAPITCH,TRUE);
+
+ hWC=GetDlgItem(hW,IDC_VOLUME);
+ ComboBox_AddString(hWC, "0: low");
+ ComboBox_AddString(hWC, "1: medium");
+ ComboBox_AddString(hWC, "2: loud");
+ ComboBox_AddString(hWC, "3: loudest");
+ ComboBox_SetCurSel(hWC,4-iVolume);
+
+ if(iSPUIRQWait) CheckDlgButton(hW,IDC_IRQWAIT,TRUE);
+ if(iDebugMode)  CheckDlgButton(hW,IDC_DEBUGMODE,TRUE);
+ if(iRecordMode) CheckDlgButton(hW,IDC_RECORDMODE,TRUE);
+ if(iDisStereo)  CheckDlgButton(hW,IDC_DISSTEREO,TRUE);
+
+ hWC=GetDlgItem(hW,IDC_USETIMER);
+ ComboBox_AddString(hWC, "0: Fast mode (thread, less compatible spu timing)");
+ ComboBox_AddString(hWC, "1: High compatibility mode (timer event, slower)");
+#if MAXMODE == 2
+ //ComboBox_AddString(hWC, "2: Use spu update calls (TESTMODE!)");
+ ComboBox_AddString(hWC, "2: Use SPUasync (must be supported by the emu)");
+#endif
+ ComboBox_SetCurSel(hWC,iUseTimer);
+
+ hWC=GetDlgItem(hW,IDC_USEREVERB);
+ ComboBox_AddString(hWC, "0: No reverb (fastest)");
+ ComboBox_AddString(hWC, "1: SPU2 reverb (may be buggy, not tested yet)");
+ ComboBox_SetCurSel(hWC,iUseReverb);
+
+ hWC=GetDlgItem(hW,IDC_INTERPOL);
+ ComboBox_AddString(hWC, "0: None (fastest)");
+ ComboBox_AddString(hWC, "1: Simple interpolation");
+ ComboBox_AddString(hWC, "2: Gaussian interpolation (good quality)");
+ ComboBox_AddString(hWC, "3: Cubic interpolation (better treble)");
+ ComboBox_SetCurSel(hWC,iUseInterpolation);
+
+ return TRUE;	                
+}
+
+////////////////////////////////////////////////////////////////////////
+// WIN CFG DLG OK
+////////////////////////////////////////////////////////////////////////
+
+void OnDSoundOK(HWND hW) 
+{
+ HWND hWC;
+
+ if(IsDlgButtonChecked(hW,IDC_ENABXA))
+  iUseXA=1; else iUseXA=0;
+
+ if(IsDlgButtonChecked(hW,IDC_XAPITCH))
+  iXAPitch=1; else iXAPitch=0;
+
+ hWC=GetDlgItem(hW,IDC_VOLUME);
+ iVolume=4-ComboBox_GetCurSel(hWC);
+
+ hWC=GetDlgItem(hW,IDC_USETIMER);
+ iUseTimer=ComboBox_GetCurSel(hWC);
+
+ hWC=GetDlgItem(hW,IDC_USEREVERB);
+ iUseReverb=ComboBox_GetCurSel(hWC);
+
+ hWC=GetDlgItem(hW,IDC_INTERPOL);
+ iUseInterpolation=ComboBox_GetCurSel(hWC);
+
+ if(IsDlgButtonChecked(hW,IDC_IRQWAIT))
+  iSPUIRQWait=1; else iSPUIRQWait=0;
+
+ if(IsDlgButtonChecked(hW,IDC_DEBUGMODE))
+  iDebugMode=1; else iDebugMode=0;
+
+ if(IsDlgButtonChecked(hW,IDC_RECORDMODE))
+  iRecordMode=1; else iRecordMode=0;
+
+ if(IsDlgButtonChecked(hW,IDC_DISSTEREO))
+  iDisStereo=1; else iDisStereo=0;
+
+ WriteConfig();                                        // write registry
+
+ EndDialog(hW,TRUE);
+}
+
+////////////////////////////////////////////////////////////////////////
+// WIN CFG DLG CANCEL
+////////////////////////////////////////////////////////////////////////
+
+void OnDSoundCancel(HWND hW) 
+{
+ EndDialog(hW,FALSE);
+}
+
+////////////////////////////////////////////////////////////////////////
+// WIN CFG PROC
+////////////////////////////////////////////////////////////////////////
+
+BOOL CALLBACK DSoundDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+  {
+   case WM_INITDIALOG:
+     return OnInitDSoundDialog(hW);
+
+   case WM_COMMAND:
+    {
+     switch(LOWORD(wParam))
+      {
+       case IDCANCEL:     OnDSoundCancel(hW);return TRUE;
+       case IDOK:         OnDSoundOK(hW);   return TRUE;
+      }
+    }
+  }
+ return FALSE;
+}
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+// LINUX CONFIG/ABOUT HANDLING
+////////////////////////////////////////////////////////////////////////
+
+#else
+            
+char * pConfigFile=NULL;
+
+#include <unistd.h>
+
+////////////////////////////////////////////////////////////////////////
+// START EXTERNAL CFG TOOL
+////////////////////////////////////////////////////////////////////////
+
+void StartCfgTool(char * pCmdLine)
+{
+ FILE * cf;char filename[255],t[255];
+
+ strcpy(filename,"cfg/cfgPeopsOSS2");
+ cf=fopen(filename,"rb");
+ if(cf!=NULL)
+  {
+   fclose(cf);
+   getcwd(t,255);
+   chdir("cfg");
+   sprintf(filename,"./cfgPeopsOSS2 %s",pCmdLine);
+   system(filename);
+   chdir(t);
+  }
+ else
+  {
+   strcpy(filename,"cfgPeopsOSS2");
+   cf=fopen(filename,"rb");
+   if(cf!=NULL)
+    {
+     fclose(cf);
+     sprintf(filename,"./cfgPeopsOSS2 %s",pCmdLine);
+     system(filename);
+    }
+   else
+    {
+     sprintf(filename,"%s/cfgPeopsOSS2",getenv("HOME"));
+     cf=fopen(filename,"rb");
+     if(cf!=NULL)
+      {
+       fclose(cf);
+       getcwd(t,255);
+       chdir(getenv("HOME"));
+       sprintf(filename,"./cfgPeopsOSS2 %s",pCmdLine);
+       system(filename);
+       chdir(t);
+      }
+     else printf("cfgPeopsOSS2 not found!\n");
+    }
+  }
+}
+
+/////////////////////////////////////////////////////////
+// READ LINUX CONFIG FILE
+/////////////////////////////////////////////////////////
+
+void ReadConfigFile(void)
+{
+ FILE *in;char t[256];int len;
+ char * pB, * p;
+
+ if(pConfigFile)  
+  {
+   strcpy(t,pConfigFile); 
+   in = fopen(t,"rb"); 
+   if(!in) return;
+  }
+ else 
+  {
+   strcpy(t,"cfg/spuPeopsOSS2.cfg");
+   in = fopen(t,"rb"); 
+   if(!in) 
+    {
+     strcpy(t,"spuPeopsOSS2.cfg");
+     in = fopen(t,"rb"); 
+     if(!in) 
+      {
+       sprintf(t,"%s/spuPeopsOSS2.cfg",getenv("HOME")); 
+       in = fopen(t,"rb"); 
+       if(!in) return;
+      }
+    }
+  } 
+
+ pB=(char *)malloc(32767);
+ memset(pB,0,32767);
+
+ len = fread(pB, 1, 32767, in);
+ fclose(in);
+
+ strcpy(t,"\nVolume");p=strstr(pB,t);if(p) {p=strstr(p,"=");len=1;}
+ if(p) iVolume=atoi(p+len);
+ if(iVolume<1) iVolume=1;
+ if(iVolume>4) iVolume=4;
+
+ strcpy(t,"\nUseXA");p=strstr(pB,t);if(p) {p=strstr(p,"=");len=1;}
+ if(p) iUseXA=atoi(p+len);
+ if(iUseXA<0) iUseXA=0;
+ if(iUseXA>1) iUseXA=1;
+
+ strcpy(t,"\nXAPitch");p=strstr(pB,t);if(p) {p=strstr(p,"=");len=1;}
+ if(p) iXAPitch=atoi(p+len);
+ if(iXAPitch<0) iXAPitch=0;
+ if(iXAPitch>1) iXAPitch=1;
+
+ strcpy(t,"\nHighCompMode");p=strstr(pB,t);if(p) {p=strstr(p,"=");len=1;} 
+ if(p)  iUseTimer=atoi(p+len); 
+ if(iUseTimer<0) iUseTimer=0; 
+ // note: timer mode 1 (win time events) is not supported
+ // in linux. But timer mode 2 (spuupdate) is safe to use.
+ if(iUseTimer)   iUseTimer=2; 
+
+#ifdef NOTHREADLIB
+ iUseTimer=2; 
+#endif
+
+ strcpy(t,"\nSPUIRQWait");p=strstr(pB,t);if(p) {p=strstr(p,"=");len=1;} 
+ if(p)  iSPUIRQWait=atoi(p+len); 
+ if(iSPUIRQWait<0) iSPUIRQWait=0; 
+ if(iSPUIRQWait>1) iSPUIRQWait=1; 
+
+ strcpy(t,"\nUseReverb");p=strstr(pB,t);if(p) {p=strstr(p,"=");len=1;} 
+ if(p)  iUseReverb=atoi(p+len); 
+ if(iUseReverb<0) iUseReverb=0; 
+ if(iUseReverb>1) iUseReverb=1; 
+
+ strcpy(t,"\nUseInterpolation");p=strstr(pB,t);if(p) {p=strstr(p,"=");len=1;} 
+ if(p)  iUseInterpolation=atoi(p+len); 
+ if(iUseInterpolation<0) iUseInterpolation=0; 
+ if(iUseInterpolation>3) iUseInterpolation=3; 
+
+ strcpy(t,"\nDisStereo");p=strstr(pB,t);if(p) {p=strstr(p,"=");len=1;} 
+ if(p)  iDisStereo=atoi(p+len); 
+ if(iDisStereo<0) iDisStereo=0; 
+ if(iDisStereo>1) iDisStereo=1; 
+
+ free(pB);
+}
+
+/////////////////////////////////////////////////////////
+// READ CONFIG called by spu funcs
+/////////////////////////////////////////////////////////
+
+void ReadConfig(void)             
+{
+ iVolume=3; 
+ iUseXA=1; 
+ iXAPitch=0;
+ iSPUIRQWait=1;  
+ iUseTimer=2;
+ iUseReverb=0;
+ iUseInterpolation=2;
+ iDisStereo=0;
+
+ ReadConfigFile();
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/cfg.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,36 @@
+/***************************************************************************
+                            cfg.h  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+
+void ReadConfig(void);
+
+
+#ifdef _WINDOWS
+BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK DSoundDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
+#else
+void StartCfgTool(char * pCmdLine);
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/debug.c	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,521 @@
+/***************************************************************************
+                           debug.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/12/25 - Pete
+// - update mute checkboxes if core selection changes
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2003/01/06 - Pete
+// - added Neil's ADSR timings
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_DEBUG
+
+#include "externals.h"
+
+////////////////////////////////////////////////////////////////////////
+// WINDOWS DEBUG DIALOG HANDLING
+////////////////////////////////////////////////////////////////////////
+
+#ifdef _WINDOWS
+
+#include "resource.h"
+
+//#define SMALLDEBUG
+//#include <dbgout.h>
+
+////////////////////////////////////////////////////////////////////////
+// display debug infos
+
+const COLORREF crStreamCol[]={
+                              RGB(  0,  0,  0),
+                              RGB(255,255,255),
+                              RGB(128,  0,128),
+                              RGB(  0,128,  0),
+                              RGB(  0,  0,255),
+                              RGB(255,  0,  0)
+                             };
+
+const COLORREF crAdsrCol[]  ={
+                              RGB(  0,  0,  0),
+                              RGB(255,  0,  0),
+                              RGB(  0,255,  0),
+                              RGB(255,  0,255),
+                              RGB(  0,  0,255),
+                              RGB(  0,  0,  0),
+                             };
+
+HBRUSH hBStream[6];                                    // brushes for stream lines
+HPEN   hPAdsr[6];                                      // pens for adsr lines
+int    iSelChannel=0;                                  // user selected channel
+int    iCoreOffset=0;
+
+////////////////////////////////////////////////////////////////////////
+// display the sound data waves: no subclassing used, so the
+// area will not be redrawn... but faster that way, and good enuff
+// for debugging purposes 
+
+void DisplayStreamInfos(HWND hW)
+{
+ HWND hWS=GetDlgItem(hW,IDC_SAREA);
+ HDC hdc;RECT r;HBRUSH hBO;int ch,dy,i,j,id;
+
+ //----------------------------------------------------//
+                                                      
+ GetClientRect(hWS,&r);                                // get size of stream display
+ hdc=GetDC(hWS);                                       // device context
+ r.right--;                                            // leave the right border intact
+ ScrollDC(hdc,-1,0,&r,&r,NULL,NULL);                   // scroll one pixel to the left
+
+ //----------------------------------------------------//
+
+ hBO=SelectObject(hdc,hBStream[0]);                    // clean the right border
+ PatBlt(hdc,r.right-1,0,1,r.bottom,PATCOPY);
+
+ //----------------------------------------------------//
+
+ dy=r.bottom/HLFCHAN;                                  // size of one channel area
+
+ for(ch=0;ch<HLFCHAN;ch++)                             // loop the channels
+  {
+   if(s_chan[ch+iCoreOffset].bOn)                      // channel is on?
+    {
+     if(s_chan[ch+iCoreOffset].iIrqDone)
+      {
+       s_chan[ch+iCoreOffset].iIrqDone=0;
+       PatBlt(hdc,r.right-1,ch*r.bottom/HLFCHAN,
+              1,dy,BLACKNESS);
+       continue;
+      }
+
+     j=s_chan[ch+iCoreOffset].sval;if(j<0)  j=-j;      // -> get one channel data (-32k ... 32k)
+     j=(dy*j)/32768;   if(j==0) j=1;                   // -> adjust to display coords
+     i=(dy/2)+(ch*r.bottom/HLFCHAN)-j/2;               // -> position where to paint it
+
+
+
+     if     (s_chan[ch+iCoreOffset].iMute)    id=1;    // -> get color id
+     else if(s_chan[ch+iCoreOffset].bNoise)   id=2;
+     else if(s_chan[ch+iCoreOffset].bFMod==2) id=3;
+     else if(s_chan[ch+iCoreOffset].bFMod==1) id=4;
+     else                                     id=5;
+
+     SelectObject(hdc,hBStream[id]);                   // -> select the brush
+     PatBlt(hdc,r.right-1,i,1,j,PATCOPY);              // -> paint the value line
+    }
+
+   if(ch) SetPixel(hdc,r.right-1,                      // -> not first line?
+                   ch*r.bottom/HLFCHAN,RGB(0,0,0));    // --> draw the line (one dot scrolled to the left)
+  }
+
+ //----------------------------------------------------//
+
+ SelectObject(hdc,hBO);                                // repair brush
+
+ ReleaseDC(hWS,hdc);                                   // release context
+}
+
+////////////////////////////////////////////////////////////////////////
+// display adsr lines: also no subclassing for repainting used
+
+void DisplayADSRInfos(HWND hW)
+{
+ HWND hWS=GetDlgItem(hW,IDC_ADSR);
+ HDC hdc;RECT r;HBRUSH hBO;char szB[16];
+ int ch=iSelChannel+iCoreOffset,dx,dy,dm,dn,ia,id,is,ir;
+
+ //----------------------------------------------------// get display size
+
+ GetClientRect(hWS,&r);
+ hdc=GetDC(hWS);
+
+ //----------------------------------------------------// clean the area
+
+ hBO=SelectObject(hdc,hBStream[0]);
+ PatBlt(hdc,0,0,r.right,r.bottom,PATCOPY);
+ r.left++;r.right-=2;r.top++;r.bottom-=2;              // shrink the display rect for better optics
+
+ //----------------------------------------------------// 
+
+ ia=min(s_chan[ch].ADSR.AttackTime,10000);             // get adsr, but limit it for drawing 
+ id=min(s_chan[ch].ADSR.DecayTime,10000);
+ is=min(s_chan[ch].ADSR.SustainTime,10000);
+ ir=min(s_chan[ch].ADSR.ReleaseTime,10000);
+
+ dx=ia+id+is+ir;                                       // get the dx in (limited) adsr units
+
+                                                       // set the real values to the info statics
+ SetDlgItemInt(hW,IDC_SADSR1,s_chan[ch].ADSRX.AttackRate,FALSE);
+ SetDlgItemInt(hW,IDC_SADSR2,s_chan[ch].ADSRX.DecayRate,FALSE);
+ SetDlgItemInt(hW,IDC_SADSR3,s_chan[ch].ADSRX.SustainRate,FALSE);
+ SetDlgItemInt(hW,IDC_SADSR4,s_chan[ch].ADSRX.ReleaseRate,FALSE);
+ SetDlgItemInt(hW,IDC_SADSR5,s_chan[ch].ADSRX.SustainLevel,FALSE);
+ SetDlgItemInt(hW,IDC_SADSR6,s_chan[ch].ADSRX.SustainIncrease,TRUE);
+ SetDlgItemInt(hW,IDC_SADSR7,s_chan[ch].ADSRX.lVolume,TRUE);
+ wsprintf(szB,"%08lX",s_chan[ch].ADSRX.EnvelopeVol);
+ SetDlgItemText(hW,IDC_SADSR8,szB);
+
+ if(dx)                                                // something to draw?
+  {
+   HPEN hPO=SelectObject(hdc,hPAdsr[1]);               // sel A pen
+   dn=r.left;
+   MoveToEx(hdc,dn,r.bottom,NULL);                     // move to bottom left corner
+
+   dn+=(ia*r.right)/dx;                                // calc A x line pos
+   LineTo(hdc,dn,r.top);                               // line to AxPos,top
+
+   SelectObject(hdc,hPAdsr[2]);                        // sel D pen
+   dn+=(id*r.right)/dx;                                // calc D x line pos
+   dy=r.top+((1024-s_chan[ch].ADSR.SustainLevel)*      // calc the D y pos
+             r.bottom)/1024;                           // (our S level is ranged from 0 to 1024)
+   LineTo(hdc,dn,dy);                                  // line to DxPos,SLevel
+
+   SelectObject(hdc,hPAdsr[3]);                        // sel S pen
+   if(s_chan[ch].ADSR.SustainTime>10000) 
+    dm=1;                                              // we have to fake the S values... S will
+   else                                                // inc/decrease until channel stop...
+   if(s_chan[ch].ADSR.SustainTime==0)    
+    dm=0;                                              // we dunno here when this will happen,
+   else 
+    dm=21-(((s_chan[ch].ADSR.SustainTime/500)));       // so we do some more or less angled line,
+   dy=dy-(s_chan[ch].ADSR.SustainModeDec*dm);          // roughly depending on the S time
+   if(dy>r.bottom) dy=r.bottom; 
+   if(dy<r.top)    dy=r.top;
+   dn+=(is*r.right)/dx;
+   LineTo(hdc,dn,dy);                                  // line to SxPos, fake end volume level
+
+   SelectObject(hdc,hPAdsr[4]);                        // sel R pen
+   dn+=(ir*r.right)/dx;                                // calc R x line pos
+   LineTo(hdc,dn,r.bottom);                            // line to RxPos, bottom right y
+
+   SelectObject(hdc,hPO);                              // repair pen
+  }
+
+ SelectObject(hdc,hBO);                                // repair brush
+ ReleaseDC(hWS,hdc);                                   // release context
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void DisplayChannelInfos(HWND hW)
+{
+ int ch=iSelChannel+iCoreOffset;char szB[16];
+
+ // channel infos
+ SetDlgItemInt(hW,IDC_CI1,s_chan[ch].bOn,TRUE);
+ SetDlgItemInt(hW,IDC_CI2,s_chan[ch].bStop,TRUE);
+ SetDlgItemInt(hW,IDC_CI3,s_chan[ch].bNoise,TRUE);
+ SetDlgItemInt(hW,IDC_CI4,s_chan[ch].bFMod,TRUE);
+ wsprintf(szB,"L%d R%d",s_chan[ch].bReverbL,s_chan[ch].bReverbR);
+ SetDlgItemText(hW,IDC_CI5,szB);
+ SetDlgItemInt(hW,IDC_CI6,s_chan[ch].bRVBActive,TRUE);
+ wsprintf(szB,"%08lX",rvb[iCoreOffset/24].StartAddr);
+ SetDlgItemText(hW,IDC_CI7,szB);
+ wsprintf(szB,"%08lX",rvb[iCoreOffset/24].EndAddr);
+ SetDlgItemText(hW,IDC_CI8,szB);
+ wsprintf(szB,"%08lX",rvb[iCoreOffset/24].CurrAddr);
+ SetDlgItemText(hW,IDC_CI9,szB);
+ 
+ wsprintf(szB,"%08lX",((unsigned long)s_chan[ch].pStart-(unsigned long)spuMemC)>>1);
+ SetDlgItemText(hW,IDC_CI10,szB);
+ if(s_chan[ch].pCurr==(unsigned char *)-1)
+  SetDlgItemText(hW,IDC_CI11,"FFFFFFFF");
+ else 
+  {
+   wsprintf(szB,"%08lX",((unsigned long)s_chan[ch].pCurr-(unsigned long)spuMemC)>>1);
+   SetDlgItemText(hW,IDC_CI11,szB);
+  }
+
+ wsprintf(szB,"%08lX",((unsigned long)s_chan[ch].pLoop-(unsigned long)spuMemC)>>1);
+ SetDlgItemText(hW,IDC_CI12,szB);
+ SetDlgItemInt(hW,IDC_CI13,s_chan[ch].iRightVolume,TRUE);
+ SetDlgItemInt(hW,IDC_CI14,s_chan[ch].iLeftVolume,TRUE);
+ SetDlgItemInt(hW,IDC_CI15,s_chan[ch].iActFreq,TRUE);
+ SetDlgItemInt(hW,IDC_CI16,s_chan[ch].iUsedFreq,TRUE);
+
+// wsprintf(szB,"%04x",s_chan[ch].iRightVolRaw);
+ wsprintf(szB,"R%d",s_chan[ch].bVolumeR);
+ SetDlgItemText(hW,IDC_CI17,szB);
+// wsprintf(szB,"%04x",s_chan[ch].iLeftVolRaw);
+ wsprintf(szB,"L%d",s_chan[ch].bVolumeL);
+ SetDlgItemText(hW,IDC_CI18,szB);
+
+ wsprintf(szB,"%08lX",s_chan[ch].iNextAdr);
+ SetDlgItemText(hW,IDC_CI19,szB);
+
+ // generic infos
+ if(pSpuIrq[ch/24]==0) 
+      SetDlgItemText(hW,IDC_STA1,"FFFFFFFF");
+ else
+  {
+   wsprintf(szB,"%08lX",((unsigned long)pSpuIrq[ch/24]-(unsigned long)spuMemC)>>1);
+   SetDlgItemText(hW,IDC_STA1,szB);
+  }
+  
+ wsprintf(szB,"%04X",spuCtrl2[ch/24]);
+ SetDlgItemText(hW,IDC_STA2,szB);
+ wsprintf(szB,"%04X",spuStat2[ch/24]);
+ SetDlgItemText(hW,IDC_STA3,szB);
+ 
+ wsprintf(szB,"%08lX",spuAddr2[ch/24]);
+ SetDlgItemText(hW,IDC_STA4,szB);
+
+ // xa infos
+ if(XAPlay<=XAFeed) ch=XAFeed-XAPlay;
+ else               ch=(XAFeed-XAStart)+(XAEnd-XAPlay);
+ SetDlgItemInt(hW,IDC_XA4,ch,FALSE);
+ SetDlgItemInt(hW,IDC_XA5,iLeftXAVol,TRUE);
+ SetDlgItemInt(hW,IDC_XA6,iRightXAVol,TRUE);
+ if(!xapGlobal) return;
+ SetDlgItemInt(hW,IDC_XA1,xapGlobal->freq,TRUE);
+ SetDlgItemInt(hW,IDC_XA2,xapGlobal->stereo,TRUE);
+ SetDlgItemInt(hW,IDC_XA3,xapGlobal->nsamples,TRUE);
+}
+ 
+////////////////////////////////////////////////////////////////////////
+// display everything (called in dialog timer for value refreshing)
+
+void DisplayDebugInfos(HWND hW)
+{
+ DisplayStreamInfos(hW);
+ DisplayADSRInfos(hW);
+ DisplayChannelInfos(hW);
+}
+
+EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val);
+EXPORT_GCC unsigned short CALLBACK SPU2read(unsigned long reg);
+
+////////////////////////////////////////////////////////////////////////
+// main debug dlg handler
+
+char old_buffer[128];
+int  iBuffRepeats=0;
+
+BOOL CALLBACK DebugDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+  {
+   //--------------------------------------------------// init
+   case WM_INITDIALOG:
+    {
+     int i;
+     ShowCursor(TRUE);                                 // mmm... who is hiding it? main emu? tsts
+     iSelChannel=0;                                    // sel first channel
+     iCoreOffset=0;
+     CheckRadioButton(hW,IDC_CHAN1,IDC_CHAN24,IDC_CHAN1);
+     CheckRadioButton(hW,IDC_CORE1,IDC_CORE2,IDC_CORE1);
+     if(iUseXA) CheckDlgButton(hW,IDC_XA,TRUE);
+
+     memset(old_buffer,0,128);
+                                                       // create brushes/pens
+     hBStream[0]=CreateSolidBrush(GetSysColor(COLOR_3DFACE));
+     hPAdsr[0]=CreatePen(PS_SOLID,0,GetSysColor(COLOR_3DFACE));
+     for(i=1;i<6;i++) 
+      {
+       hBStream[i]=CreateSolidBrush(crStreamCol[i]);
+       hPAdsr[i]=CreatePen(PS_SOLID,0,crAdsrCol[i]);
+      }
+     SetTimer(hW,999,50,NULL);                         // now create update timer
+     return TRUE;
+    }
+   //--------------------------------------------------// destroy
+   case WM_DESTROY:
+    {
+     int i;
+     KillTimer(hW,999);                                // first kill timer
+     for(i=0;i<6;i++)                                  // then kill brushes/pens
+      {
+       DeleteObject(hBStream[i]);
+       DeleteObject(hPAdsr[i]);
+      }
+    }break;
+   //--------------------------------------------------// timer
+   case WM_TIMER:
+    {
+     if(wParam==999) DisplayDebugInfos(hW);            // update all values
+    }break;
+   //--------------------------------------------------// command
+   case WM_COMMAND:
+    {
+     if(wParam==IDCANCEL) iDebugMode=2;                // cancel? raise flag for destroying the dialog
+
+     if(wParam==IDC_REGWRITE)
+      {
+       char szB[8];unsigned long l;
+       GetDlgItemText(hW,IDC_REGEDIT,szB,8);
+       l=strtoul(szB,NULL,16);
+       GetDlgItemText(hW,IDC_VALEDIT,szB,8);
+       SPU2write(l,(unsigned short)strtoul(szB,NULL,16));
+      }
+
+     if(wParam==IDC_CLEAR)
+      {
+       SetDlgItemText(hW,IDC_LOG,"");
+      }
+
+     if(wParam==IDC_COPY)
+      {
+       SendMessage(GetDlgItem(hW,IDC_LOG),EM_SETSEL,0,-1);
+       SendMessage(GetDlgItem(hW,IDC_LOG),WM_COPY,0,0);
+       MessageBeep(0xFFFFFFFF);
+      }
+      
+     if(wParam==IDC_REGREAD)
+      {
+       char szB[8];unsigned long l;
+       GetDlgItemText(hW,IDC_REGEDIT,szB,8);
+       l=strtoul(szB,NULL,16);
+       wsprintf(szB,"%04x",SPU2read(l));
+       SetDlgItemText(hW,IDC_VALEDIT,szB);
+      }
+
+     if(wParam==IDC_XA)
+      {
+       if(IsDlgButtonChecked(hW,wParam))               // -> mute/unmute it
+            iUseXA=1;
+       else iUseXA=0;
+      }
+
+     if(wParam>=IDC_CORE1 && wParam<=IDC_CORE2)        // core clicked?
+      {
+       int i;
+
+       if(IsDlgButtonChecked(hW,IDC_CORE1))            // -> sel correct half of channels
+            iCoreOffset=0;
+       else iCoreOffset=24;
+       
+       for(i=IDC_MUTE1;i<=IDC_MUTE24;i++)
+        {
+         if(s_chan[i-IDC_MUTE1+iCoreOffset].iMute)
+              CheckDlgButton(hW,i,TRUE);
+         else CheckDlgButton(hW,i,FALSE);
+        }
+
+       InvalidateRect(hW,NULL,TRUE);
+       UpdateWindow(hW);
+      }
+
+     if(wParam>=IDC_MUTE1 && wParam<=IDC_MUTE24)       // mute clicked?
+      {
+       if(IsDlgButtonChecked(hW,wParam))               // -> mute/unmute it
+        s_chan[wParam-IDC_MUTE1+iCoreOffset].iMute=1;
+       else 
+        s_chan[wParam-IDC_MUTE1+iCoreOffset].iMute=0;
+      }
+                                                       // all mute/unmute
+     if(wParam==IDC_MUTEOFF) SendMessage(hW,WM_MUTE,0,0); 
+     if(wParam==IDC_MUTEON)  SendMessage(hW,WM_MUTE,1,0);
+
+     if(wParam>=IDC_CHAN1 && wParam<=IDC_CHAN24)       // sel channel
+      {
+       if(IsDlgButtonChecked(hW,wParam)) 
+        {
+         iSelChannel=wParam-IDC_CHAN1;
+         SetDlgItemInt(hW,IDC_CHANNUM,iSelChannel+1,FALSE);
+        }
+      }
+    }break;
+   //--------------------------------------------------// mute
+   case WM_MUTE:
+    {                                                  // will be called by the mute/unmute all button and on savestate load
+     int i;
+     for(i=IDC_MUTE1;i<=IDC_MUTE24;i++)
+      {
+       CheckDlgButton(hW,i,wParam);
+       if(wParam) 
+        s_chan[i-IDC_MUTE1+iCoreOffset].iMute=1;
+       else
+        s_chan[i-IDC_MUTE1+iCoreOffset].iMute=0;
+      }
+    }break;
+   //--------------------------------------------------// size
+   case WM_SIZE:
+    if(wParam==SIZE_MINIMIZED) SetFocus(hWMain);       // if we get minimized, set the foxus to the main window
+    break;
+   //--------------------------------------------------// setcursor
+   case WM_SETCURSOR:
+    {
+     SetCursor(LoadCursor(NULL,IDC_ARROW));            // force the arrow 
+     return TRUE;
+    }
+   //--------------------------------------------------//
+  }
+ return FALSE;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void logprintf(LPCTSTR pFormat, ...)
+{
+ if(iDebugMode!=1) return;
+ if(!IsWindow(hWDebug)) return;
+ else
+ if(IsDlgButtonChecked(hWDebug,IDC_NOLOG)) return;
+ else
+  {
+   char buffer [128];
+   va_list args;
+
+   va_start(args, pFormat);
+   wvsprintf(buffer, pFormat, args);
+   va_end(args);
+
+   if(strcmp(old_buffer,buffer)==0) 
+    {
+     iBuffRepeats++;
+     if(iBuffRepeats>=100)
+      {
+       SendMessage(GetDlgItem(hWDebug,IDC_LOG),EM_SETSEL,0,0);
+       SendMessage(GetDlgItem(hWDebug,IDC_LOG),EM_REPLACESEL,0,(long)old_buffer);
+       SendMessage(GetDlgItem(hWDebug,IDC_LOG),EM_REPLACESEL,0,(long)"->[100]\r\n");
+       iBuffRepeats=0;
+       return;
+      }
+     return;
+    }
+
+   if(iBuffRepeats)
+    {
+     SendMessage(GetDlgItem(hWDebug,IDC_LOG),EM_SETSEL,0,0);
+     SendMessage(GetDlgItem(hWDebug,IDC_LOG),EM_REPLACESEL,0,(long)old_buffer);
+     wsprintf(old_buffer,"->[%d]\r\n",iBuffRepeats);
+     SendMessage(GetDlgItem(hWDebug,IDC_LOG),EM_REPLACESEL,0,(long)old_buffer);
+     iBuffRepeats=0;
+    }
+
+   SendMessage(GetDlgItem(hWDebug,IDC_LOG),EM_SETSEL,0,0);
+   SendMessage(GetDlgItem(hWDebug,IDC_LOG),EM_REPLACESEL,0,(long)buffer);
+
+   lstrcpy(old_buffer,buffer);
+
+  }
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/debug.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,30 @@
+/***************************************************************************
+                           debug.h  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#ifdef _WINDOWS
+BOOL CALLBACK DebugDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
+void logprintf(LPCTSTR pFormat, ...);
+#endif
--- a/Plugins/Input/sexypsf/spu/dma.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/dma.c	Sun Mar 19 12:51:03 2006 -0800
@@ -1,75 +1,214 @@
-/***************************************************************************
-                            dma.c  -  description
-                             -------------------
-    begin                : Wed May 15 2002
-    copyright            : (C) 2002 by Pete Bernert
-    email                : BlackDove@addcom.de
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version. See also the license.txt file for *
- *   additional informations.                                              *
- *                                                                         *
- ***************************************************************************/
-
-//*************************************************************************//
-// History of changes:
-//
-// 2002/05/15 - Pete
-// - generic cleanup for the Peops release
-//
-//*************************************************************************//
-
-#include "stdafx.h"
-
-#define _IN_DMA
-
-//#include "externals.h"
-////////////////////////////////////////////////////////////////////////
-// READ DMA (many values)
-////////////////////////////////////////////////////////////////////////
-
-void SPUreadDMAMem(u32 usPSXMem,int iSize)
-{
- int i;
-
- for(i=0;i<iSize;i++)
-  {
-   *(u16 *)PSXM(usPSXMem)=spuMem[spuAddr>>1];		// spu addr got by writeregister
-   usPSXMem+=2;
-   spuAddr+=2;                                         // inc spu addr
-   if(spuAddr>0x7ffff) spuAddr=0;                      // wrap
-  }
-}
-
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-
-// to investigate: do sound data updates by writedma affect spu
-// irqs? Will an irq be triggered, if new data is written to
-// the memory irq address?
-
-////////////////////////////////////////////////////////////////////////
-// WRITE DMA (many values)
-////////////////////////////////////////////////////////////////////////
-
-void SPUwriteDMAMem(u32 usPSXMem,int iSize)
-{
- int i;
-
- for(i=0;i<iSize;i++)
-  {
-   spuMem[spuAddr>>1] = *(u16 *)PSXM(usPSXMem);
-   usPSXMem+=2;                  			// spu addr got by writeregister
-   spuAddr+=2;                                         // inc spu addr
-   if(spuAddr>0x7ffff) spuAddr=0;                      // wrap
-  }
-}
-
-////////////////////////////////////////////////////////////////////////
-
+/***************************************************************************
+                            dma.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_DMA
+
+#include "externals.h"
+#include "registers.h"
+#include "debug.h"
+
+////////////////////////////////////////////////////////////////////////
+// READ DMA (many values)
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2readDMA4Mem(unsigned short * pusPSXMem,int iSize)
+{
+ int i;
+
+#ifdef _WINDOWS
+ if(iDebugMode==1) 
+  {
+   logprintf("READDMA4 %X - %X\r\n",spuAddr2[0],iSize);
+   
+   if(spuAddr2[0]<=0x1fff)
+    logprintf("# OUTPUT AREA ACCESS #############\r\n");
+  }
+
+#endif
+
+ for(i=0;i<iSize;i++)
+  {
+   *pusPSXMem++=spuMem[spuAddr2[0]];                  // spu addr 0 got by writeregister
+   spuAddr2[0]++;                                     // inc spu addr
+   if(spuAddr2[0]>0xfffff) spuAddr2[0]=0;             // wrap
+  }
+
+ spuAddr2[0]+=0x20; //?????
+ 
+
+ iSpuAsyncWait=0;
+
+ // got from J.F. and Kanodin... is it needed?
+ regArea[(PS2_C0_ADMAS)>>1]=0;                         // Auto DMA complete
+ spuStat2[0]=0x80;                                     // DMA complete
+}
+
+EXPORT_GCC void CALLBACK SPU2readDMA7Mem(unsigned short * pusPSXMem,int iSize)
+{
+ int i;
+
+#ifdef _WINDOWS
+ if(iDebugMode==1) 
+  { 
+   logprintf("READDMA7 %X - %X\r\n",spuAddr2[1],iSize);
+   
+   if(spuAddr2[1]<=0x1fff)
+    logprintf("# OUTPUT AREA ACCESS #############\r\n");
+  }
+#endif
+
+ for(i=0;i<iSize;i++)
+  {
+   *pusPSXMem++=spuMem[spuAddr2[1]];                   // spu addr 1 got by writeregister
+   spuAddr2[1]++;                                      // inc spu addr
+   if(spuAddr2[1]>0xfffff) spuAddr2[1]=0;              // wrap
+  }
+
+ spuAddr2[1]+=0x20; //?????
+
+ iSpuAsyncWait=0;
+
+ // got from J.F. and Kanodin... is it needed?
+ regArea[(PS2_C1_ADMAS)>>1]=0;                         // Auto DMA complete
+ spuStat2[1]=0x80;                                     // DMA complete
+}
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+// to investigate: do sound data updates by writedma affect spu
+// irqs? Will an irq be triggered, if new data is written to
+// the memory irq address?
+
+////////////////////////////////////////////////////////////////////////
+// WRITE DMA (many values)
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2writeDMA4Mem(unsigned short * pusPSXMem,int iSize)
+{
+ int i;
+
+#ifdef _WINDOWS
+ if(iDebugMode==1) 
+  {
+   logprintf("WRITEDMA4 %X - %X\r\n",spuAddr2[0],iSize);
+   
+   if(spuAddr2[0]>=0x2000 && spuAddr2[0]<=0x27ff)
+    logprintf("# RAW INPUT ###############\r\n");
+  } 
+#endif
+
+ for(i=0;i<iSize;i++)
+  {
+   spuMem[spuAddr2[0]] = *pusPSXMem++;                 // spu addr 0 got by writeregister
+   spuAddr2[0]++;                                      // inc spu addr
+   if(spuAddr2[0]>0xfffff) spuAddr2[0]=0;              // wrap
+  }
+ 
+ iSpuAsyncWait=0;
+
+ // got from J.F. and Kanodin... is it needed?
+ spuStat2[0]=0x80;                                     // DMA complete
+}
+
+EXPORT_GCC void CALLBACK SPU2writeDMA7Mem(unsigned short * pusPSXMem,int iSize)
+{
+ int i;
+
+#ifdef _WINDOWS
+ if(iDebugMode==1) 
+  {
+   logprintf("WRITEDMA7 %X - %X\r\n",spuAddr2[1],iSize);
+   if(spuAddr2[1]>=0x2000 && spuAddr2[1]<=0x27ff)
+    logprintf("# RAW INPUT ###############\r\n");
+  } 
+#endif
+
+ for(i=0;i<iSize;i++)
+  {
+   spuMem[spuAddr2[1]] = *pusPSXMem++;                 // spu addr 1 got by writeregister
+   spuAddr2[1]++;                                      // inc spu addr
+   if(spuAddr2[1]>0xfffff) spuAddr2[1]=0;              // wrap
+  }
+ 
+ iSpuAsyncWait=0;
+
+ // got from J.F. and Kanodin... is it needed?
+ spuStat2[1]=0x80;                                     // DMA complete
+}
+
+////////////////////////////////////////////////////////////////////////
+// INTERRUPTS
+////////////////////////////////////////////////////////////////////////
+
+void InterruptDMA4(void) 
+{
+// taken from linuzappz NULL spu2
+//	spu2Rs16(CORE0_ATTR)&= ~0x30;
+//	spu2Rs16(REG__1B0) = 0;
+//	spu2Rs16(SPU2_STATX_WRDY_M)|= 0x80;
+
+#ifdef _WINDOWS
+ if(iDebugMode==1) logprintf("IRQDMA4\r\n");
+#endif
+
+ spuCtrl2[0]&=~0x30;
+ regArea[(PS2_C0_ADMAS)>>1]=0;
+ spuStat2[0]|=0x80;
+}
+                       
+EXPORT_GCC void CALLBACK SPU2interruptDMA4(void) 
+{
+ InterruptDMA4();
+}
+
+void InterruptDMA7(void) 
+{
+// taken from linuzappz NULL spu2
+//	spu2Rs16(CORE1_ATTR)&= ~0x30;
+//	spu2Rs16(REG__5B0) = 0;
+//	spu2Rs16(SPU2_STATX_DREQ)|= 0x80;
+
+#ifdef _WINDOWS
+ if(iDebugMode==1) logprintf("IRQDMA7\r\n");
+#endif
+
+ spuCtrl2[1]&=~0x30;
+ regArea[(PS2_C1_ADMAS)>>1]=0;
+ spuStat2[1]|=0x80;
+}
+
+EXPORT_GCC void CALLBACK SPU2interruptDMA7(void) 
+{
+ InterruptDMA7();
+}
+
--- a/Plugins/Input/sexypsf/spu/dma.h	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/dma.h	Sun Mar 19 12:51:03 2006 -0800
@@ -24,8 +24,6 @@
 //
 //*************************************************************************//
 
-
-u16 CALLBACK SPUreadDMA(void);
-void CALLBACK SPUreadDMAMem(u16 * pusPSXMem,int iSize);
-void CALLBACK SPUwriteDMA(u16 val);
-void CALLBACK SPUwriteDMAMem(u16 * pusPSXMem,int iSize);
+void InterruptDMA4(void);
+void InterruptDMA7(void); 
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/dsound.c	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,280 @@
+/***************************************************************************
+                          dsound.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2005/08/29 - Pete
+// - changed to 48Khz output
+//
+// 2003/01/12 - Pete
+// - added recording funcs
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_DSOUND
+
+#include "externals.h"
+
+#ifdef _WINDOWS
+#define _LPCWAVEFORMATEX_DEFINED
+#include <dsound.h>
+                                
+#include "record.h"
+                   
+////////////////////////////////////////////////////////////////////////
+// dsound globals
+////////////////////////////////////////////////////////////////////////
+
+LPDIRECTSOUND lpDS;
+LPDIRECTSOUNDBUFFER lpDSBP = NULL;
+LPDIRECTSOUNDBUFFER lpDSB = NULL;
+DSBUFFERDESC        dsbd;
+DSBUFFERDESC        dsbdesc;
+DSCAPS              dscaps;
+DSBCAPS             dsbcaps;
+
+unsigned long LastWrite=0xffffffff;
+unsigned long LastPlay=0;
+
+////////////////////////////////////////////////////////////////////////
+// SETUP SOUND
+////////////////////////////////////////////////////////////////////////
+
+void SetupSound(void)
+{
+ HRESULT dsval;WAVEFORMATEX pcmwf;
+
+ dsval = DirectSoundCreate(NULL,&lpDS,NULL);
+ if(dsval!=DS_OK) 
+  {
+   MessageBox(hWMain,"DirectSoundCreate!","Error",MB_OK);
+   return;
+  }
+
+ if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_PRIORITY))
+  {
+   if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_NORMAL))
+    {
+     MessageBox(hWMain,"SetCooperativeLevel!","Error",MB_OK);
+     return;
+    }
+  }
+
+ memset(&dsbd,0,sizeof(DSBUFFERDESC));
+ dsbd.dwSize = 20;                                     // NT4 hack! sizeof(dsbd);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;                 
+ dsbd.dwBufferBytes = 0; 
+ dsbd.lpwfxFormat = NULL;
+
+ dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbd,&lpDSBP,NULL);
+ if(dsval!=DS_OK) 
+  {
+   MessageBox(hWMain, "CreateSoundBuffer (Primary)", "Error",MB_OK);
+   return;
+  }
+
+ memset(&pcmwf, 0, sizeof(WAVEFORMATEX));
+ pcmwf.wFormatTag = WAVE_FORMAT_PCM;
+
+ if(iDisStereo) {pcmwf.nChannels = 1; pcmwf.nBlockAlign = 2;}
+ else           {pcmwf.nChannels = 2; pcmwf.nBlockAlign = 4;}
+
+ pcmwf.nSamplesPerSec = 48000;
+ 
+ pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign;
+ pcmwf.wBitsPerSample = 16;
+
+ dsval=IDirectSoundBuffer_SetFormat(lpDSBP,&pcmwf);
+ if(dsval!=DS_OK) 
+  {
+   MessageBox(hWMain, "SetFormat!", "Error",MB_OK);
+   return;
+  }
+
+ dscaps.dwSize = sizeof(DSCAPS);
+ dsbcaps.dwSize = sizeof(DSBCAPS);
+ IDirectSound_GetCaps(lpDS,&dscaps);
+ IDirectSoundBuffer_GetCaps(lpDSBP,&dsbcaps);
+
+ memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
+ dsbdesc.dwSize = 20;                                  // NT4 hack! sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
+ dsbdesc.dwBufferBytes = SOUNDSIZE;
+ dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
+
+ dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSB,NULL);
+ if(dsval!=DS_OK) 
+  {
+   MessageBox(hWMain,"CreateSoundBuffer (Secondary)", "Error",MB_OK);
+   return;
+  }
+
+ dsval=IDirectSoundBuffer_Play(lpDSBP,0,0,DSBPLAY_LOOPING);
+ if(dsval!=DS_OK) 
+  {
+   MessageBox(hWMain,"Play (Primary)","Error",MB_OK);
+   return;
+  }
+
+ dsval=IDirectSoundBuffer_Play(lpDSB,0,0,DSBPLAY_LOOPING);
+ if(dsval!=DS_OK) 
+  {
+   MessageBox(hWMain,"Play (Secondary)","Error",MB_OK);
+   return;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// REMOVE SOUND
+////////////////////////////////////////////////////////////////////////
+
+void RemoveSound(void)
+{ 
+ int iRes;
+
+ if(iDoRecord) RecordStop();
+
+ if(lpDSB!=NULL) 
+  {
+   IDirectSoundBuffer_Stop(lpDSB);
+   iRes=IDirectSoundBuffer_Release(lpDSB);
+   // FF says such a loop is bad... Demo says it's good... Pete doesn't care
+   while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSB);
+   lpDSB=NULL;
+  }
+
+ if(lpDSBP!=NULL) 
+  {
+   IDirectSoundBuffer_Stop(lpDSBP);
+   iRes=IDirectSoundBuffer_Release(lpDSBP);
+   // FF says such a loop is bad... Demo says it's good... Pete doesn't care
+   while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBP);
+   lpDSBP=NULL;
+  }
+
+ if(lpDS!=NULL) 
+  {
+   iRes=IDirectSound_Release(lpDS);
+   // FF says such a loop is bad... Demo says it's good... Pete doesn't care
+   while(iRes!=0) iRes=IDirectSound_Release(lpDS);
+   lpDS=NULL;
+  }
+
+}
+
+////////////////////////////////////////////////////////////////////////
+// GET BYTES BUFFERED
+////////////////////////////////////////////////////////////////////////
+
+unsigned long SoundGetBytesBuffered(void)
+{
+ unsigned long cplay,cwrite;
+
+ if(LastWrite==0xffffffff) return 0;
+
+ IDirectSoundBuffer_GetCurrentPosition(lpDSB,&cplay,&cwrite);
+
+ if(cplay>SOUNDSIZE) return SOUNDSIZE;
+
+ if(cplay<LastWrite) return LastWrite-cplay;
+ return (SOUNDSIZE-cplay)+LastWrite;
+}
+
+////////////////////////////////////////////////////////////////////////
+// FEED SOUND DATA
+////////////////////////////////////////////////////////////////////////
+
+void SoundFeedStreamData(unsigned char* pSound,long lBytes)
+{
+ LPVOID lpvPtr1, lpvPtr2;
+ unsigned long dwBytes1,dwBytes2; 
+ unsigned long *lpSS, *lpSD;
+ unsigned long dw,cplay,cwrite;
+ HRESULT hr;
+ unsigned long status;
+
+ if(iDoRecord) RecordBuffer(pSound,lBytes);
+
+ IDirectSoundBuffer_GetStatus(lpDSB,&status);
+ if(status&DSBSTATUS_BUFFERLOST)
+  {
+   if(IDirectSoundBuffer_Restore(lpDSB)!=DS_OK) return;
+   IDirectSoundBuffer_Play(lpDSB,0,0,DSBPLAY_LOOPING);
+  }
+
+ IDirectSoundBuffer_GetCurrentPosition(lpDSB,&cplay,&cwrite);
+
+ if(LastWrite==0xffffffff) LastWrite=cwrite;
+
+/*
+// mmm... security... not needed, I think
+ if(LastWrite<cplay)
+  {
+   if((cplay-LastWrite)<=(unsigned long)lBytes)
+    {
+     LastWrite=0xffffffff;
+     return;
+    }
+  }
+ else
+  {
+   if(LastWrite<cwrite)
+    {
+     LastWrite=0xffffffff;
+     return;
+    }
+  }
+*/
+
+ hr=IDirectSoundBuffer_Lock(lpDSB,LastWrite,lBytes,
+                &lpvPtr1, &dwBytes1, 
+                &lpvPtr2, &dwBytes2,
+                0);
+
+ if(hr!=DS_OK) {LastWrite=0xffffffff;return;}
+
+ lpSD=(unsigned long *)lpvPtr1;
+ dw=dwBytes1>>2;
+
+ lpSS=(unsigned long *)pSound;
+ while(dw) {*lpSD++=*lpSS++;dw--;}
+
+ if(lpvPtr2)
+  {
+   lpSD=(unsigned long *)lpvPtr2;
+   dw=dwBytes2>>2;
+   while(dw) {*lpSD++=*lpSS++;dw--;}
+  }
+
+ IDirectSoundBuffer_Unlock(lpDSB,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2);
+
+ LastWrite+=lBytes;
+ if(LastWrite>=SOUNDSIZE) LastWrite-=SOUNDSIZE;
+ LastPlay=cplay;
+}
+
+#endif
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/dsoundoss.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,36 @@
+/***************************************************************************
+                         dsoundoss.h  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+
+void SetupSound(void);
+void RemoveSound(void);
+unsigned long SoundGetBytesBuffered(void);
+void SoundFeedStreamData(unsigned char* pSound,long lBytes);
+
+#ifndef _WINDOWS
+unsigned long timeGetTime();
+#endif
+
--- a/Plugins/Input/sexypsf/spu/externals.h	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/externals.h	Sun Mar 19 12:51:03 2006 -0800
@@ -1,177 +1,357 @@
-/***************************************************************************
-                         externals.h  -  description
-                             -------------------
-    begin                : Wed May 15 2002
-    copyright            : (C) 2002 by Pete Bernert
-    email                : BlackDove@addcom.de
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version. See also the license.txt file for *
- *   additional informations.                                              *
- *                                                                         *
- ***************************************************************************/
-
-#include "types.h"
-#include "PsxMem.h"
-
-//*************************************************************************//
-// History of changes:
-//
-// 2002/05/15 - Pete
-// - generic cleanup for the Peops release
-//
-//*************************************************************************//
-
-#define max(a,b)            (((a) > (b)) ? (a) : (b))
-#define min(a,b)            (((a) < (b)) ? (a) : (b))
-
-////////////////////////////////////////////////////////////////////////
-// spu defines
-////////////////////////////////////////////////////////////////////////
-
-// num of channels
-#define MAXCHAN     24
-
-///////////////////////////////////////////////////////////
-// struct defines
-///////////////////////////////////////////////////////////
-
-// ADSR INFOS PER CHANNEL
-typedef struct
-{
- int            AttackModeExp;
- s32           AttackTime;
- s32           DecayTime;
- s32           SustainLevel;
- int            SustainModeExp;
- s32           SustainModeDec;
- s32           SustainTime;
- int            ReleaseModeExp;
- u32  ReleaseVal;
- s32           ReleaseTime;
- s32           ReleaseStartTime; 
- s32           ReleaseVol; 
- s32           lTime;
- s32           lVolume;
-} ADSRInfo;
-
-typedef struct
-{
- int            State;
- int            AttackModeExp;
- int            AttackRate;
- int            DecayRate;
- int            SustainLevel;
- int            SustainModeExp;
- int            SustainIncrease;
- int            SustainRate;
- int            ReleaseModeExp;
- int            ReleaseRate;
- int            EnvelopeVol;
- s32           lVolume;
- s32           lDummy1;
- s32           lDummy2;
-} ADSRInfoEx;
-              
-///////////////////////////////////////////////////////////
-
-// Tmp Flags
-
-// used for debug channel muting
-#define FLAG_MUTE  1
-
-///////////////////////////////////////////////////////////
-
-// MAIN CHANNEL STRUCT
-typedef struct
-{
- int               bNew;                               // start flag
-
- int               iSBPos;                             // mixing stuff
- int               spos;
- int               sinc;
- int               SB[32+1];
- int               sval;
-
- u8 *   pStart;                             // start ptr into sound mem
- u8 *   pCurr;                              // current pos in sound mem
- u8 *   pLoop;                              // loop ptr in sound mem
-
- int               bOn;                                // is channel active (sample playing?)
- int               bStop;                              // is channel stopped (sample _can_ still be playing, ADSR Release phase)
- int               iActFreq;                           // current psx pitch
- int               iUsedFreq;                          // current pc pitch
- int               iLeftVolume;                        // left volume
- int               iLeftVolRaw;                        // left psx volume value
- int               bIgnoreLoop;                        // ignore loop bit, if an external loop address is used
- int               iRightVolume;                       // right volume
- int               iRightVolRaw;                       // right psx volume value
- int               iRawPitch;                          // raw pitch (0...3fff)
- int               iIrqDone;                           // debug irq done flag
- int               s_1;                                // last decoding infos
- int               s_2;
- int               bRVBActive;                         // reverb active flag
- int               iRVBOffset;                         // reverb offset
- int               iRVBRepeat;                         // reverb repeat
- int               bNoise;                             // noise active flag
- int               bFMod;                              // freq mod (0=off, 1=sound channel, 2=freq channel)
- int               iOldNoise;                          // old noise val for this channel   
- ADSRInfo          ADSR;                               // active ADSR settings
- ADSRInfoEx        ADSRX;                              // next ADSR settings (will be moved to active on sample start)
-
-} SPUCHAN;
-
-///////////////////////////////////////////////////////////
-
-typedef struct
-{
- int StartAddr;      // reverb area start addr in samples
- int CurrAddr;       // reverb area curr addr in samples
-
- int Enabled;
- int VolLeft;
- int VolRight;
- int iLastRVBLeft;
- int iLastRVBRight;
- int iRVBLeft;
- int iRVBRight;
-
-
- int FB_SRC_A;       // (offset)
- int FB_SRC_B;       // (offset)
- int IIR_ALPHA;      // (coef.)
- int ACC_COEF_A;     // (coef.)
- int ACC_COEF_B;     // (coef.)
- int ACC_COEF_C;     // (coef.)
- int ACC_COEF_D;     // (coef.)
- int IIR_COEF;       // (coef.)
- int FB_ALPHA;       // (coef.)
- int FB_X;           // (coef.)
- int IIR_DEST_A0;    // (offset)
- int IIR_DEST_A1;    // (offset)
- int ACC_SRC_A0;     // (offset)
- int ACC_SRC_A1;     // (offset)
- int ACC_SRC_B0;     // (offset)
- int ACC_SRC_B1;     // (offset)
- int IIR_SRC_A0;     // (offset)
- int IIR_SRC_A1;     // (offset)
- int IIR_DEST_B0;    // (offset)
- int IIR_DEST_B1;    // (offset)
- int ACC_SRC_C0;     // (offset)
- int ACC_SRC_C1;     // (offset)
- int ACC_SRC_D0;     // (offset)
- int ACC_SRC_D1;     // (offset)
- int IIR_SRC_B1;     // (offset)
- int IIR_SRC_B0;     // (offset)
- int MIX_DEST_A0;    // (offset)
- int MIX_DEST_A1;    // (offset)
- int MIX_DEST_B0;    // (offset)
- int MIX_DEST_B1;    // (offset)
- int IN_COEF_L;      // (coef.)
- int IN_COEF_R;      // (coef.)
-} REVERBInfo;
+/***************************************************************************
+                         externals.h  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2002/04/04 - Pete
+// - increased channel struct for interpolation
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+
+/////////////////////////////////////////////////////////
+// generic defines
+/////////////////////////////////////////////////////////
+
+//#define PSE_LT_SPU                  4
+//#define PSE_SPU_ERR_SUCCESS         0
+//#define PSE_SPU_ERR                 -60
+//#define PSE_SPU_ERR_NOTCONFIGURED   PSE_SPU_ERR - 1
+//#define PSE_SPU_ERR_INIT            PSE_SPU_ERR - 2
+
+#ifndef max
+#define max(a,b)            (((a) > (b)) ? (a) : (b))
+#define min(a,b)            (((a) < (b)) ? (a) : (b))
+#endif
+
+////////////////////////////////////////////////////////////////////////
+// spu defines
+////////////////////////////////////////////////////////////////////////
+
+// sound buffer sizes
+// 400 ms complete sound buffer
+#define SOUNDSIZE   76800
+                    
+// 137 ms test buffer... if less than that is buffered, a new upload will happen
+#define TESTSIZE    26304
+                    
+// num of channels
+#define MAXCHAN     48
+#define HLFCHAN     24
+
+// ~ 1 ms of data
+#define NSSIZE 48
+
+///////////////////////////////////////////////////////////
+// struct defines
+///////////////////////////////////////////////////////////
+
+// ADSR INFOS PER CHANNEL
+typedef struct
+{
+ int            AttackModeExp;
+ long           AttackTime;
+ long           DecayTime;
+ long           SustainLevel;
+ int            SustainModeExp;
+ long           SustainModeDec;
+ long           SustainTime;
+ int            ReleaseModeExp;
+ unsigned long  ReleaseVal;
+ long           ReleaseTime;
+ long           ReleaseStartTime; 
+ long           ReleaseVol; 
+ long           lTime;
+ long           lVolume;
+} ADSRInfo;
+
+typedef struct
+{
+ int            State;
+ int            AttackModeExp;
+ int            AttackRate;
+ int            DecayRate;
+ int            SustainLevel;
+ int            SustainModeExp;
+ int            SustainIncrease;
+ int            SustainRate;
+ int            ReleaseModeExp;
+ int            ReleaseRate;
+ int            EnvelopeVol;
+ long           lVolume;
+ long           lDummy1;
+ long           lDummy2;
+} ADSRInfoEx;
+              
+///////////////////////////////////////////////////////////
+
+// Tmp Flags
+
+// used for debug channel muting
+#define FLAG_MUTE  1
+
+// used for simple interpolation
+#define FLAG_IPOL0 2
+#define FLAG_IPOL1 4
+
+///////////////////////////////////////////////////////////
+
+// MAIN CHANNEL STRUCT
+typedef struct
+{
+ // no mutexes used anymore... don't need them to sync access
+ //HANDLE            hMutex;
+
+ int               bNew;                               // start flag
+
+ int               iSBPos;                             // mixing stuff
+ int               spos;
+ int               sinc;
+ int               SB[32+32];                          // Pete added another 32 dwords in 1.6 ... prevents overflow issues with gaussian/cubic interpolation (thanx xodnizel!), and can be used for even better interpolations, eh? :)
+ int               sval;
+
+ unsigned char *   pStart;                             // start ptr into sound mem
+ unsigned char *   pCurr;                              // current pos in sound mem
+ unsigned char *   pLoop;                              // loop ptr in sound mem
+
+ int               iStartAdr;
+ int               iLoopAdr; 
+ int               iNextAdr; 
+
+ int               bOn;                                // is channel active (sample playing?)
+ int               bStop;                              // is channel stopped (sample _can_ still be playing, ADSR Release phase)
+ int               bEndPoint;                          // end point reached
+ int               bReverbL;                           // can we do reverb on this channel? must have ctrl register bit, to get active
+ int               bReverbR; 
+ 
+ int               bVolumeL;                           // Volume on/off
+ int               bVolumeR;
+ 
+ int               iActFreq;                           // current psx pitch
+ int               iUsedFreq;                          // current pc pitch
+ int               iLeftVolume;                        // left volume
+ int               iLeftVolRaw;                        // left psx volume value
+ int               bIgnoreLoop;                        // ignore loop bit, if an external loop address is used
+ int               iMute;                              // mute mode
+ int               iRightVolume;                       // right volume
+ int               iRightVolRaw;                       // right psx volume value
+ int               iRawPitch;                          // raw pitch (0...3fff)
+ int               iIrqDone;                           // debug irq done flag
+ int               s_1;                                // last decoding infos
+ int               s_2;
+ int               bRVBActive;                         // reverb active flag
+ int               bNoise;                             // noise active flag
+ int               bFMod;                              // freq mod (0=off, 1=sound channel, 2=freq channel)
+ int               iOldNoise;                          // old noise val for this channel   
+ ADSRInfo          ADSR;                               // active ADSR settings
+ ADSRInfoEx        ADSRX;                              // next ADSR settings (will be moved to active on sample start)
+
+} SPUCHAN;
+
+///////////////////////////////////////////////////////////
+
+typedef struct
+{
+ int StartAddr;      // reverb area start addr in samples
+ int EndAddr;        // reverb area end addr in samples
+ int CurrAddr;       // reverb area curr addr in samples
+
+ int VolLeft;
+ int VolRight;
+ int iLastRVBLeft;
+ int iLastRVBRight;
+ int iRVBLeft;
+ int iRVBRight;
+ int iCnt;
+
+ int FB_SRC_A;       // (offset)
+ int FB_SRC_B;       // (offset)
+ int IIR_ALPHA;      // (coef.)
+ int ACC_COEF_A;     // (coef.)
+ int ACC_COEF_B;     // (coef.)
+ int ACC_COEF_C;     // (coef.)
+ int ACC_COEF_D;     // (coef.)
+ int IIR_COEF;       // (coef.)
+ int FB_ALPHA;       // (coef.)
+ int FB_X;           // (coef.)
+ int IIR_DEST_A0;    // (offset)
+ int IIR_DEST_A1;    // (offset)
+ int ACC_SRC_A0;     // (offset)
+ int ACC_SRC_A1;     // (offset)
+ int ACC_SRC_B0;     // (offset)
+ int ACC_SRC_B1;     // (offset)
+ int IIR_SRC_A0;     // (offset)
+ int IIR_SRC_A1;     // (offset)
+ int IIR_DEST_B0;    // (offset)
+ int IIR_DEST_B1;    // (offset)
+ int ACC_SRC_C0;     // (offset)
+ int ACC_SRC_C1;     // (offset)
+ int ACC_SRC_D0;     // (offset)
+ int ACC_SRC_D1;     // (offset)
+ int IIR_SRC_B1;     // (offset)
+ int IIR_SRC_B0;     // (offset)
+ int MIX_DEST_A0;    // (offset)
+ int MIX_DEST_A1;    // (offset)
+ int MIX_DEST_B0;    // (offset)
+ int MIX_DEST_B1;    // (offset)
+ int IN_COEF_L;      // (coef.)
+ int IN_COEF_R;      // (coef.)
+} REVERBInfo;
+
+#ifdef _WINDOWS
+extern HINSTANCE hInst;
+#define WM_MUTE (WM_USER+543)
+#endif
+
+///////////////////////////////////////////////////////////
+// SPU.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_SPU
+
+// psx buffers / addresses
+
+extern unsigned short  regArea[];                        
+extern unsigned short  spuMem[];
+extern unsigned char * spuMemC;
+extern unsigned char * pSpuIrq[];
+extern unsigned char * pSpuBuffer;
+
+// user settings
+
+extern int        iUseXA;
+extern int        iVolume;
+extern int        iXAPitch;
+extern int        iUseTimer;
+extern int        iSPUIRQWait;
+extern int        iDebugMode;
+extern int        iRecordMode;
+extern int        iUseReverb;
+extern int        iUseInterpolation;
+extern int        iDisStereo;
+// MISC
+
+extern SPUCHAN s_chan[];
+extern REVERBInfo rvb[];
+
+extern unsigned long dwNoiseVal;
+extern unsigned short spuCtrl2[];
+extern unsigned short spuStat2[];
+extern unsigned long  spuIrq2[];
+extern unsigned long  spuAddr2[];
+extern unsigned long   spuRvbAddr2[];
+extern unsigned long   spuRvbAEnd2[];
+
+extern int      bEndThread; 
+extern int      bThreadEnded;
+extern int      bSpuInit;
+
+extern int      SSumR[];
+extern int      SSumL[];
+extern int      iCycle;
+extern short *  pS;
+extern unsigned long dwNewChannel2[];
+extern unsigned long dwEndChannel2[];
+
+extern int iSpuAsyncWait;
+
+#ifdef _WINDOWS
+extern HWND    hWMain;                               // window handle
+extern HWND    hWDebug;
+#endif
+
+extern void (CALLBACK *cddavCallback)(unsigned short,unsigned short);
+
+#endif
+
+///////////////////////////////////////////////////////////
+// CFG.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_CFG
+
+#ifndef _WINDOWS
+extern char * pConfigFile;
+#endif
+
+#endif
+
+///////////////////////////////////////////////////////////
+// DSOUND.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_DSOUND
+
+#ifdef _WINDOWS
+extern unsigned long LastWrite;
+extern unsigned long LastPlay;
+#endif
+
+#endif
+
+///////////////////////////////////////////////////////////
+// RECORD.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_RECORD
+
+#ifdef _WINDOWS
+extern int iDoRecord;
+#endif
+
+#endif
+
+///////////////////////////////////////////////////////////
+// XA.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_XA
+
+extern xa_decode_t   * xapGlobal;
+
+extern unsigned long * XAFeed;
+extern unsigned long * XAPlay;
+extern unsigned long * XAStart;
+extern unsigned long * XAEnd;
+
+extern unsigned long   XARepeat;
+extern unsigned long   XALastVal;
+
+extern int           iLeftXAVol;
+extern int           iRightXAVol;
+
+#endif
+
+///////////////////////////////////////////////////////////
+// REVERB.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_REVERB
+
+extern int *          sRVBPlay[];
+extern int *          sRVBEnd[];
+extern int *          sRVBStart[];
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/freeze.c	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,260 @@
+/***************************************************************************
+                          freeze.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/12/24 - Pete
+// - freeze functions adapted to pcsx2-0.7
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2003/03/20 - Pete
+// - fix to prevent the new interpolations from crashing when loading a save state
+//
+// 2003/01/06 - Pete
+// - small changes for version 1.3 adsr save state loading      
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_FREEZE
+
+#include "externals.h"
+#include "registers.h"
+#include "spu.h"
+#include "regs.h"
+#include "debug.h"
+#include "resource.h"
+
+////////////////////////////////////////////////////////////////////////
+// freeze structs
+////////////////////////////////////////////////////////////////////////
+
+typedef struct {
+	int size;
+	char *data;
+} SPUFreeze_t;
+
+typedef struct
+{
+ char          szSPUName[8];
+ unsigned long ulFreezeVersion;
+ unsigned long ulFreezeSize;
+ unsigned char cSPUPort[64*1024];
+ unsigned char cSPURam[2*1024*1024];
+ xa_decode_t   xaS;     
+} SPUFreeze_Ex_t;
+
+typedef struct
+{
+ unsigned long   spuIrq0;
+ unsigned long   spuIrq1;
+ unsigned long   pSpuIrq0;
+ unsigned long   pSpuIrq1;
+ unsigned long   dummy0;
+ unsigned long   dummy1;
+ unsigned long   dummy2;
+ unsigned long   dummy3;
+
+ SPUCHAN  s_chan[MAXCHAN];   
+
+} SPUOSSFreeze_t;
+
+////////////////////////////////////////////////////////////////////////
+
+void LoadStateV1(SPUFreeze_Ex_t * pF);                    // newest version
+void LoadStateUnknown(SPUFreeze_Ex_t * pF);               // unknown format
+
+////////////////////////////////////////////////////////////////////////
+// SPUFREEZE: called by main emu on savestate load/save
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC long CALLBACK SPU2freeze(unsigned long ulFreezeMode,SPUFreeze_t * pFt)
+{
+ int i;SPUOSSFreeze_t * pFO;SPUFreeze_Ex_t * pF;
+
+ if(!pFt) return 0;                                    // first check
+
+ if(ulFreezeMode)                                      // save?
+  {//--------------------------------------------------//
+   pFt->size=sizeof(SPUFreeze_Ex_t)+sizeof(SPUOSSFreeze_t);
+
+   if(ulFreezeMode==2) return 0;                       // emu just asking for size? bye
+
+   if(!pFt->data) return 0;
+   
+   pF=(SPUFreeze_Ex_t *)pFt->data;
+  
+   memset(pF,0,pFt->size);
+
+   strcpy(pF->szSPUName,"PBOSS2");
+   pF->ulFreezeVersion=1;
+   pF->ulFreezeSize=pFt->size;
+                                                       // save mode:
+   RemoveTimer();                                      // stop timer
+
+   memcpy(pF->cSPURam,spuMem,2*1024*1024);             // copy common infos
+   memcpy(pF->cSPUPort,regArea,64*1024);
+
+   if(xapGlobal && XAPlay!=XAFeed)                     // some xa
+    {
+     pF->xaS=*xapGlobal;     
+    }
+   else 
+   memset(&pF->xaS,0,sizeof(xa_decode_t));             // or clean xa
+
+   pFO=(SPUOSSFreeze_t *)(pF+1);                       // store special stuff
+
+   pFO->spuIrq0=spuIrq2[0];
+   if(pSpuIrq[0])  pFO->pSpuIrq0 = (unsigned long)pSpuIrq[0]-(unsigned long)spuMemC;
+   pFO->spuIrq1=spuIrq2[1];
+   if(pSpuIrq[1])  pFO->pSpuIrq1 = (unsigned long)pSpuIrq[1]-(unsigned long)spuMemC;
+
+   for(i=0;i<MAXCHAN;i++)
+    {
+     memcpy((void *)&pFO->s_chan[i],(void *)&s_chan[i],sizeof(SPUCHAN));
+     if(pFO->s_chan[i].pStart)
+      pFO->s_chan[i].pStart-=(unsigned long)spuMemC;
+     if(pFO->s_chan[i].pCurr)
+      pFO->s_chan[i].pCurr-=(unsigned long)spuMemC;
+     if(pFO->s_chan[i].pLoop)
+      pFO->s_chan[i].pLoop-=(unsigned long)spuMemC;
+    }
+
+   SetupTimer();                                       // sound processing on again
+
+   return 1;
+   //--------------------------------------------------//
+  }
+
+                                                       // load state:
+#ifdef _WINDOWS
+ if(iDebugMode==1 && IsWindow(hWDebug))                // we have to disbale the debug window, if active
+  DestroyWindow(hWDebug);
+ hWDebug=0;
+
+ if(IsBadReadPtr(pFt,sizeof(SPUFreeze_t)))             // check bad emu stuff
+  return 0;
+#endif
+
+ if(pFt->size!=sizeof(SPUFreeze_Ex_t)+                 // not our stuff? bye
+               sizeof(SPUOSSFreeze_t)) return 0;
+ if(!pFt->data) return 0;
+
+ pF=(SPUFreeze_Ex_t *)pFt->data;
+
+ RemoveTimer();                                        // we stop processing while doing the save!
+
+ memcpy(spuMem,pF->cSPURam,2*1024*1024);               // get ram
+ memcpy(regArea,pF->cSPUPort,64*1024);
+
+ if(pF->xaS.nsamples<=4032)                            // start xa again
+  SPU2playADPCMchannel(&pF->xaS);
+
+ xapGlobal=0;
+
+ if(!strcmp(pF->szSPUName,"PBOSS2") &&                  
+    pF->ulFreezeVersion==1)
+      LoadStateV1(pF);
+ else LoadStateUnknown(pF);
+
+ // repair some globals
+ for(i=0xFFFE;i>=0x0000;i-=2)
+  {
+   SPU2write(i,regArea[i>>1]);
+  }
+
+ // fix to prevent new interpolations from crashing
+ for(i=0;i<MAXCHAN;i++) s_chan[i].SB[28]=0;
+
+ SetupTimer();                                         // start sound processing again
+
+#ifdef _WINDOWS
+ if(iDebugMode)                                        // re-activate windows debug dialog
+  {
+   hWDebug=CreateDialog(hInst,MAKEINTRESOURCE(IDD_DEBUG),
+                        NULL,(DLGPROC)DebugDlgProc);
+   SetWindowPos(hWDebug,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE);
+   UpdateWindow(hWDebug);
+   SetFocus(hWMain);
+  }
+#endif
+
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void LoadStateV1(SPUFreeze_Ex_t * pF)
+{
+ int i;SPUOSSFreeze_t * pFO;
+
+ pFO=(SPUOSSFreeze_t *)(pF+1);
+
+ spuIrq2[0]   = pFO->spuIrq0;
+ if(pFO->pSpuIrq0)  pSpuIrq[0]  = pFO->pSpuIrq0+spuMemC;  else pSpuIrq[0]=0;
+ spuIrq2[1]   = pFO->spuIrq1;
+ if(pFO->pSpuIrq1)  pSpuIrq[1]  = pFO->pSpuIrq1+spuMemC;  else pSpuIrq[1]=0;
+
+ for(i=0;i<MAXCHAN;i++)
+  {
+   memcpy((void *)&s_chan[i],(void *)&pFO->s_chan[i],sizeof(SPUCHAN));
+
+   s_chan[i].pStart+=(unsigned long)spuMemC;
+   s_chan[i].pCurr+=(unsigned long)spuMemC;
+   s_chan[i].pLoop+=(unsigned long)spuMemC;
+   s_chan[i].iMute=0;
+   s_chan[i].iIrqDone=0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void LoadStateUnknown(SPUFreeze_Ex_t * pF)
+{
+ int i;
+
+ for(i=0;i<MAXCHAN;i++)
+  {
+   s_chan[i].bOn=0;
+   s_chan[i].bNew=0;
+   s_chan[i].bStop=0;
+   s_chan[i].ADSR.lVolume=0;
+   s_chan[i].pLoop=spuMemC;
+   s_chan[i].pStart=spuMemC;
+   s_chan[i].pLoop=spuMemC;
+   s_chan[i].iMute=0;
+   s_chan[i].iIrqDone=0;
+  }
+
+ dwNewChannel2[0]=0;
+ dwNewChannel2[1]=0;
+ dwEndChannel2[0]=0;
+ dwEndChannel2[1]=0;
+ 
+ pSpuIrq[0]=0;
+ pSpuIrq[1]=0;
+}
+
+////////////////////////////////////////////////////////////////////////
--- a/Plugins/Input/sexypsf/spu/gauss_i.h	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/gauss_i.h	Sun Mar 19 12:51:03 2006 -0800
@@ -1,163 +1,162 @@
-/***************************************************************************
-                          gauss_i.h  -  description
-                           -----------------------
-    begin                : Sun Feb 08 2003
-    copyright            : (C) 2003 by Chris Moeller, eh, whatever
-    email                : chris@kode54.tk
- ***************************************************************************/
-                       
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version. See also the license.txt file for *
- *   additional informations.                                              *
- *                                                                         *
- ***************************************************************************/
-                           
-//*************************************************************************//
-// History of changes:
-//
-// 2003/02/08 - kode54
-// - generated by interleaving table from gauss.h from the libopenspc
-//   project; a gaussian bell curve table logged from the SPC-700,
-//   though Neill says he logged the same curve from a PSX SPU. Also
-//   says that interleaving the coefficients together runs faster. Meh.
-//
-//*************************************************************************//
-
-#ifndef GAUSS_H
-#define GAUSS_H
-
-// 1024 entries
-const int gauss[]={
-	0x172, 0x519, 0x176, 0x000, 0x16E, 0x519, 0x17A, 0x000, 
-	0x16A, 0x518, 0x17D, 0x000, 0x166, 0x518, 0x181, 0x000, 
-	0x162, 0x518, 0x185, 0x000, 0x15F, 0x518, 0x189, 0x000, 
-	0x15B, 0x518, 0x18D, 0x000, 0x157, 0x517, 0x191, 0x000, 
-	0x153, 0x517, 0x195, 0x000, 0x150, 0x517, 0x19A, 0x000, 
-	0x14C, 0x516, 0x19E, 0x000, 0x148, 0x516, 0x1A2, 0x000, 
-	0x145, 0x515, 0x1A6, 0x000, 0x141, 0x514, 0x1AA, 0x000, 
-	0x13E, 0x514, 0x1AE, 0x000, 0x13A, 0x513, 0x1B2, 0x000, 
-	0x137, 0x512, 0x1B7, 0x001, 0x133, 0x511, 0x1BB, 0x001, 
-	0x130, 0x511, 0x1BF, 0x001, 0x12C, 0x510, 0x1C3, 0x001, 
-	0x129, 0x50F, 0x1C8, 0x001, 0x125, 0x50E, 0x1CC, 0x001, 
-	0x122, 0x50D, 0x1D0, 0x001, 0x11E, 0x50C, 0x1D5, 0x001, 
-	0x11B, 0x50B, 0x1D9, 0x001, 0x118, 0x50A, 0x1DD, 0x001, 
-	0x114, 0x508, 0x1E2, 0x001, 0x111, 0x507, 0x1E6, 0x002, 
-	0x10E, 0x506, 0x1EB, 0x002, 0x10B, 0x504, 0x1EF, 0x002, 
-	0x107, 0x503, 0x1F3, 0x002, 0x104, 0x502, 0x1F8, 0x002, 
-	0x101, 0x500, 0x1FC, 0x002, 0x0FE, 0x4FF, 0x201, 0x002, 
-	0x0FB, 0x4FD, 0x205, 0x003, 0x0F8, 0x4FB, 0x20A, 0x003, 
-	0x0F5, 0x4FA, 0x20F, 0x003, 0x0F2, 0x4F8, 0x213, 0x003, 
-	0x0EF, 0x4F6, 0x218, 0x003, 0x0EC, 0x4F5, 0x21C, 0x004, 
-	0x0E9, 0x4F3, 0x221, 0x004, 0x0E6, 0x4F1, 0x226, 0x004, 
-	0x0E3, 0x4EF, 0x22A, 0x004, 0x0E0, 0x4ED, 0x22F, 0x004, 
-	0x0DD, 0x4EB, 0x233, 0x005, 0x0DA, 0x4E9, 0x238, 0x005, 
-	0x0D7, 0x4E7, 0x23D, 0x005, 0x0D4, 0x4E5, 0x241, 0x005, 
-	0x0D2, 0x4E3, 0x246, 0x006, 0x0CF, 0x4E0, 0x24B, 0x006, 
-	0x0CC, 0x4DE, 0x250, 0x006, 0x0C9, 0x4DC, 0x254, 0x006, 
-	0x0C7, 0x4D9, 0x259, 0x007, 0x0C4, 0x4D7, 0x25E, 0x007, 
-	0x0C1, 0x4D5, 0x263, 0x007, 0x0BF, 0x4D2, 0x267, 0x008, 
-	0x0BC, 0x4D0, 0x26C, 0x008, 0x0BA, 0x4CD, 0x271, 0x008, 
-	0x0B7, 0x4CB, 0x276, 0x009, 0x0B4, 0x4C8, 0x27B, 0x009, 
-	0x0B2, 0x4C5, 0x280, 0x009, 0x0AF, 0x4C3, 0x284, 0x00A, 
-	0x0AD, 0x4C0, 0x289, 0x00A, 0x0AB, 0x4BD, 0x28E, 0x00A, 
-	0x0A8, 0x4BA, 0x293, 0x00B, 0x0A6, 0x4B7, 0x298, 0x00B, 
-	0x0A3, 0x4B5, 0x29D, 0x00B, 0x0A1, 0x4B2, 0x2A2, 0x00C, 
-	0x09F, 0x4AF, 0x2A6, 0x00C, 0x09C, 0x4AC, 0x2AB, 0x00D, 
-	0x09A, 0x4A9, 0x2B0, 0x00D, 0x098, 0x4A6, 0x2B5, 0x00E, 
-	0x096, 0x4A2, 0x2BA, 0x00E, 0x093, 0x49F, 0x2BF, 0x00F, 
-	0x091, 0x49C, 0x2C4, 0x00F, 0x08F, 0x499, 0x2C9, 0x00F, 
-	0x08D, 0x496, 0x2CE, 0x010, 0x08B, 0x492, 0x2D3, 0x010, 
-	0x089, 0x48F, 0x2D8, 0x011, 0x086, 0x48C, 0x2DC, 0x011, 
-	0x084, 0x488, 0x2E1, 0x012, 0x082, 0x485, 0x2E6, 0x013, 
-	0x080, 0x481, 0x2EB, 0x013, 0x07E, 0x47E, 0x2F0, 0x014, 
-	0x07C, 0x47A, 0x2F5, 0x014, 0x07A, 0x477, 0x2FA, 0x015, 
-	0x078, 0x473, 0x2FF, 0x015, 0x076, 0x470, 0x304, 0x016, 
-	0x075, 0x46C, 0x309, 0x017, 0x073, 0x468, 0x30E, 0x017, 
-	0x071, 0x465, 0x313, 0x018, 0x06F, 0x461, 0x318, 0x018, 
-	0x06D, 0x45D, 0x31D, 0x019, 0x06B, 0x459, 0x322, 0x01A, 
-	0x06A, 0x455, 0x326, 0x01B, 0x068, 0x452, 0x32B, 0x01B, 
-	0x066, 0x44E, 0x330, 0x01C, 0x064, 0x44A, 0x335, 0x01D, 
-	0x063, 0x446, 0x33A, 0x01D, 0x061, 0x442, 0x33F, 0x01E, 
-	0x05F, 0x43E, 0x344, 0x01F, 0x05E, 0x43A, 0x349, 0x020, 
-	0x05C, 0x436, 0x34E, 0x020, 0x05A, 0x432, 0x353, 0x021, 
-	0x059, 0x42E, 0x357, 0x022, 0x057, 0x42A, 0x35C, 0x023, 
-	0x056, 0x425, 0x361, 0x024, 0x054, 0x421, 0x366, 0x024, 
-	0x053, 0x41D, 0x36B, 0x025, 0x051, 0x419, 0x370, 0x026, 
-	0x050, 0x415, 0x374, 0x027, 0x04E, 0x410, 0x379, 0x028, 
-	0x04D, 0x40C, 0x37E, 0x029, 0x04C, 0x408, 0x383, 0x02A, 
-	0x04A, 0x403, 0x388, 0x02B, 0x049, 0x3FF, 0x38C, 0x02C, 
-	0x047, 0x3FB, 0x391, 0x02D, 0x046, 0x3F6, 0x396, 0x02E, 
-	0x045, 0x3F2, 0x39B, 0x02F, 0x043, 0x3ED, 0x39F, 0x030, 
-	0x042, 0x3E9, 0x3A4, 0x031, 0x041, 0x3E5, 0x3A9, 0x032, 
-	0x040, 0x3E0, 0x3AD, 0x033, 0x03E, 0x3DC, 0x3B2, 0x034, 
-	0x03D, 0x3D7, 0x3B7, 0x035, 0x03C, 0x3D2, 0x3BB, 0x036, 
-	0x03B, 0x3CE, 0x3C0, 0x037, 0x03A, 0x3C9, 0x3C5, 0x038, 
-	0x038, 0x3C5, 0x3C9, 0x03A, 0x037, 0x3C0, 0x3CE, 0x03B, 
-	0x036, 0x3BB, 0x3D2, 0x03C, 0x035, 0x3B7, 0x3D7, 0x03D, 
-	0x034, 0x3B2, 0x3DC, 0x03E, 0x033, 0x3AD, 0x3E0, 0x040, 
-	0x032, 0x3A9, 0x3E5, 0x041, 0x031, 0x3A4, 0x3E9, 0x042, 
-	0x030, 0x39F, 0x3ED, 0x043, 0x02F, 0x39B, 0x3F2, 0x045, 
-	0x02E, 0x396, 0x3F6, 0x046, 0x02D, 0x391, 0x3FB, 0x047, 
-	0x02C, 0x38C, 0x3FF, 0x049, 0x02B, 0x388, 0x403, 0x04A, 
-	0x02A, 0x383, 0x408, 0x04C, 0x029, 0x37E, 0x40C, 0x04D, 
-	0x028, 0x379, 0x410, 0x04E, 0x027, 0x374, 0x415, 0x050, 
-	0x026, 0x370, 0x419, 0x051, 0x025, 0x36B, 0x41D, 0x053, 
-	0x024, 0x366, 0x421, 0x054, 0x024, 0x361, 0x425, 0x056, 
-	0x023, 0x35C, 0x42A, 0x057, 0x022, 0x357, 0x42E, 0x059, 
-	0x021, 0x353, 0x432, 0x05A, 0x020, 0x34E, 0x436, 0x05C, 
-	0x020, 0x349, 0x43A, 0x05E, 0x01F, 0x344, 0x43E, 0x05F, 
-	0x01E, 0x33F, 0x442, 0x061, 0x01D, 0x33A, 0x446, 0x063, 
-	0x01D, 0x335, 0x44A, 0x064, 0x01C, 0x330, 0x44E, 0x066, 
-	0x01B, 0x32B, 0x452, 0x068, 0x01B, 0x326, 0x455, 0x06A, 
-	0x01A, 0x322, 0x459, 0x06B, 0x019, 0x31D, 0x45D, 0x06D, 
-	0x018, 0x318, 0x461, 0x06F, 0x018, 0x313, 0x465, 0x071, 
-	0x017, 0x30E, 0x468, 0x073, 0x017, 0x309, 0x46C, 0x075, 
-	0x016, 0x304, 0x470, 0x076, 0x015, 0x2FF, 0x473, 0x078, 
-	0x015, 0x2FA, 0x477, 0x07A, 0x014, 0x2F5, 0x47A, 0x07C, 
-	0x014, 0x2F0, 0x47E, 0x07E, 0x013, 0x2EB, 0x481, 0x080, 
-	0x013, 0x2E6, 0x485, 0x082, 0x012, 0x2E1, 0x488, 0x084, 
-	0x011, 0x2DC, 0x48C, 0x086, 0x011, 0x2D8, 0x48F, 0x089, 
-	0x010, 0x2D3, 0x492, 0x08B, 0x010, 0x2CE, 0x496, 0x08D, 
-	0x00F, 0x2C9, 0x499, 0x08F, 0x00F, 0x2C4, 0x49C, 0x091, 
-	0x00F, 0x2BF, 0x49F, 0x093, 0x00E, 0x2BA, 0x4A2, 0x096, 
-	0x00E, 0x2B5, 0x4A6, 0x098, 0x00D, 0x2B0, 0x4A9, 0x09A, 
-	0x00D, 0x2AB, 0x4AC, 0x09C, 0x00C, 0x2A6, 0x4AF, 0x09F, 
-	0x00C, 0x2A2, 0x4B2, 0x0A1, 0x00B, 0x29D, 0x4B5, 0x0A3, 
-	0x00B, 0x298, 0x4B7, 0x0A6, 0x00B, 0x293, 0x4BA, 0x0A8, 
-	0x00A, 0x28E, 0x4BD, 0x0AB, 0x00A, 0x289, 0x4C0, 0x0AD, 
-	0x00A, 0x284, 0x4C3, 0x0AF, 0x009, 0x280, 0x4C5, 0x0B2, 
-	0x009, 0x27B, 0x4C8, 0x0B4, 0x009, 0x276, 0x4CB, 0x0B7, 
-	0x008, 0x271, 0x4CD, 0x0BA, 0x008, 0x26C, 0x4D0, 0x0BC, 
-	0x008, 0x267, 0x4D2, 0x0BF, 0x007, 0x263, 0x4D5, 0x0C1, 
-	0x007, 0x25E, 0x4D7, 0x0C4, 0x007, 0x259, 0x4D9, 0x0C7, 
-	0x006, 0x254, 0x4DC, 0x0C9, 0x006, 0x250, 0x4DE, 0x0CC, 
-	0x006, 0x24B, 0x4E0, 0x0CF, 0x006, 0x246, 0x4E3, 0x0D2, 
-	0x005, 0x241, 0x4E5, 0x0D4, 0x005, 0x23D, 0x4E7, 0x0D7, 
-	0x005, 0x238, 0x4E9, 0x0DA, 0x005, 0x233, 0x4EB, 0x0DD, 
-	0x004, 0x22F, 0x4ED, 0x0E0, 0x004, 0x22A, 0x4EF, 0x0E3, 
-	0x004, 0x226, 0x4F1, 0x0E6, 0x004, 0x221, 0x4F3, 0x0E9, 
-	0x004, 0x21C, 0x4F5, 0x0EC, 0x003, 0x218, 0x4F6, 0x0EF, 
-	0x003, 0x213, 0x4F8, 0x0F2, 0x003, 0x20F, 0x4FA, 0x0F5, 
-	0x003, 0x20A, 0x4FB, 0x0F8, 0x003, 0x205, 0x4FD, 0x0FB, 
-	0x002, 0x201, 0x4FF, 0x0FE, 0x002, 0x1FC, 0x500, 0x101, 
-	0x002, 0x1F8, 0x502, 0x104, 0x002, 0x1F3, 0x503, 0x107, 
-	0x002, 0x1EF, 0x504, 0x10B, 0x002, 0x1EB, 0x506, 0x10E, 
-	0x002, 0x1E6, 0x507, 0x111, 0x001, 0x1E2, 0x508, 0x114, 
-	0x001, 0x1DD, 0x50A, 0x118, 0x001, 0x1D9, 0x50B, 0x11B, 
-	0x001, 0x1D5, 0x50C, 0x11E, 0x001, 0x1D0, 0x50D, 0x122, 
-	0x001, 0x1CC, 0x50E, 0x125, 0x001, 0x1C8, 0x50F, 0x129, 
-	0x001, 0x1C3, 0x510, 0x12C, 0x001, 0x1BF, 0x511, 0x130, 
-	0x001, 0x1BB, 0x511, 0x133, 0x001, 0x1B7, 0x512, 0x137, 
-	0x000, 0x1B2, 0x513, 0x13A, 0x000, 0x1AE, 0x514, 0x13E, 
-	0x000, 0x1AA, 0x514, 0x141, 0x000, 0x1A6, 0x515, 0x145, 
-	0x000, 0x1A2, 0x516, 0x148, 0x000, 0x19E, 0x516, 0x14C, 
-	0x000, 0x19A, 0x517, 0x150, 0x000, 0x195, 0x517, 0x153, 
-	0x000, 0x191, 0x517, 0x157, 0x000, 0x18D, 0x518, 0x15B, 
-	0x000, 0x189, 0x518, 0x15F, 0x000, 0x185, 0x518, 0x162, 
-	0x000, 0x181, 0x518, 0x166, 0x000, 0x17D, 0x518, 0x16A, 
-	0x000, 0x17A, 0x519, 0x16E, 0x000, 0x176, 0x519, 0x172};
-#endif
+/***************************************************************************
+                          gauss_i.h  -  description
+                           -----------------------
+    begin                : Sun Feb 08 2003
+    copyright            : (C) 2003 by Chris Moeller, eh, whatever
+    email                : chris@kode54.tk
+ ***************************************************************************/
+                       
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+                           
+//*************************************************************************//
+// History of changes:
+//
+// 2003/02/08 - kode54
+// - generated by interleaving table from gauss.h from the libopenspc
+//   project; a gaussian bell curve table logged from the SPC-700,
+//   though Neill says he logged the same curve from a PSX SPU. Also
+//   says that interleaving the coefficients together runs faster. Meh.
+//
+//*************************************************************************//
+
+#ifndef GAUSS_H
+#define GAUSS_H
+
+const int gauss[]={
+	0x172, 0x519, 0x176, 0x000, 0x16E, 0x519, 0x17A, 0x000, 
+	0x16A, 0x518, 0x17D, 0x000, 0x166, 0x518, 0x181, 0x000, 
+	0x162, 0x518, 0x185, 0x000, 0x15F, 0x518, 0x189, 0x000, 
+	0x15B, 0x518, 0x18D, 0x000, 0x157, 0x517, 0x191, 0x000, 
+	0x153, 0x517, 0x195, 0x000, 0x150, 0x517, 0x19A, 0x000, 
+	0x14C, 0x516, 0x19E, 0x000, 0x148, 0x516, 0x1A2, 0x000, 
+	0x145, 0x515, 0x1A6, 0x000, 0x141, 0x514, 0x1AA, 0x000, 
+	0x13E, 0x514, 0x1AE, 0x000, 0x13A, 0x513, 0x1B2, 0x000, 
+	0x137, 0x512, 0x1B7, 0x001, 0x133, 0x511, 0x1BB, 0x001, 
+	0x130, 0x511, 0x1BF, 0x001, 0x12C, 0x510, 0x1C3, 0x001, 
+	0x129, 0x50F, 0x1C8, 0x001, 0x125, 0x50E, 0x1CC, 0x001, 
+	0x122, 0x50D, 0x1D0, 0x001, 0x11E, 0x50C, 0x1D5, 0x001, 
+	0x11B, 0x50B, 0x1D9, 0x001, 0x118, 0x50A, 0x1DD, 0x001, 
+	0x114, 0x508, 0x1E2, 0x001, 0x111, 0x507, 0x1E6, 0x002, 
+	0x10E, 0x506, 0x1EB, 0x002, 0x10B, 0x504, 0x1EF, 0x002, 
+	0x107, 0x503, 0x1F3, 0x002, 0x104, 0x502, 0x1F8, 0x002, 
+	0x101, 0x500, 0x1FC, 0x002, 0x0FE, 0x4FF, 0x201, 0x002, 
+	0x0FB, 0x4FD, 0x205, 0x003, 0x0F8, 0x4FB, 0x20A, 0x003, 
+	0x0F5, 0x4FA, 0x20F, 0x003, 0x0F2, 0x4F8, 0x213, 0x003, 
+	0x0EF, 0x4F6, 0x218, 0x003, 0x0EC, 0x4F5, 0x21C, 0x004, 
+	0x0E9, 0x4F3, 0x221, 0x004, 0x0E6, 0x4F1, 0x226, 0x004, 
+	0x0E3, 0x4EF, 0x22A, 0x004, 0x0E0, 0x4ED, 0x22F, 0x004, 
+	0x0DD, 0x4EB, 0x233, 0x005, 0x0DA, 0x4E9, 0x238, 0x005, 
+	0x0D7, 0x4E7, 0x23D, 0x005, 0x0D4, 0x4E5, 0x241, 0x005, 
+	0x0D2, 0x4E3, 0x246, 0x006, 0x0CF, 0x4E0, 0x24B, 0x006, 
+	0x0CC, 0x4DE, 0x250, 0x006, 0x0C9, 0x4DC, 0x254, 0x006, 
+	0x0C7, 0x4D9, 0x259, 0x007, 0x0C4, 0x4D7, 0x25E, 0x007, 
+	0x0C1, 0x4D5, 0x263, 0x007, 0x0BF, 0x4D2, 0x267, 0x008, 
+	0x0BC, 0x4D0, 0x26C, 0x008, 0x0BA, 0x4CD, 0x271, 0x008, 
+	0x0B7, 0x4CB, 0x276, 0x009, 0x0B4, 0x4C8, 0x27B, 0x009, 
+	0x0B2, 0x4C5, 0x280, 0x009, 0x0AF, 0x4C3, 0x284, 0x00A, 
+	0x0AD, 0x4C0, 0x289, 0x00A, 0x0AB, 0x4BD, 0x28E, 0x00A, 
+	0x0A8, 0x4BA, 0x293, 0x00B, 0x0A6, 0x4B7, 0x298, 0x00B, 
+	0x0A3, 0x4B5, 0x29D, 0x00B, 0x0A1, 0x4B2, 0x2A2, 0x00C, 
+	0x09F, 0x4AF, 0x2A6, 0x00C, 0x09C, 0x4AC, 0x2AB, 0x00D, 
+	0x09A, 0x4A9, 0x2B0, 0x00D, 0x098, 0x4A6, 0x2B5, 0x00E, 
+	0x096, 0x4A2, 0x2BA, 0x00E, 0x093, 0x49F, 0x2BF, 0x00F, 
+	0x091, 0x49C, 0x2C4, 0x00F, 0x08F, 0x499, 0x2C9, 0x00F, 
+	0x08D, 0x496, 0x2CE, 0x010, 0x08B, 0x492, 0x2D3, 0x010, 
+	0x089, 0x48F, 0x2D8, 0x011, 0x086, 0x48C, 0x2DC, 0x011, 
+	0x084, 0x488, 0x2E1, 0x012, 0x082, 0x485, 0x2E6, 0x013, 
+	0x080, 0x481, 0x2EB, 0x013, 0x07E, 0x47E, 0x2F0, 0x014, 
+	0x07C, 0x47A, 0x2F5, 0x014, 0x07A, 0x477, 0x2FA, 0x015, 
+	0x078, 0x473, 0x2FF, 0x015, 0x076, 0x470, 0x304, 0x016, 
+	0x075, 0x46C, 0x309, 0x017, 0x073, 0x468, 0x30E, 0x017, 
+	0x071, 0x465, 0x313, 0x018, 0x06F, 0x461, 0x318, 0x018, 
+	0x06D, 0x45D, 0x31D, 0x019, 0x06B, 0x459, 0x322, 0x01A, 
+	0x06A, 0x455, 0x326, 0x01B, 0x068, 0x452, 0x32B, 0x01B, 
+	0x066, 0x44E, 0x330, 0x01C, 0x064, 0x44A, 0x335, 0x01D, 
+	0x063, 0x446, 0x33A, 0x01D, 0x061, 0x442, 0x33F, 0x01E, 
+	0x05F, 0x43E, 0x344, 0x01F, 0x05E, 0x43A, 0x349, 0x020, 
+	0x05C, 0x436, 0x34E, 0x020, 0x05A, 0x432, 0x353, 0x021, 
+	0x059, 0x42E, 0x357, 0x022, 0x057, 0x42A, 0x35C, 0x023, 
+	0x056, 0x425, 0x361, 0x024, 0x054, 0x421, 0x366, 0x024, 
+	0x053, 0x41D, 0x36B, 0x025, 0x051, 0x419, 0x370, 0x026, 
+	0x050, 0x415, 0x374, 0x027, 0x04E, 0x410, 0x379, 0x028, 
+	0x04D, 0x40C, 0x37E, 0x029, 0x04C, 0x408, 0x383, 0x02A, 
+	0x04A, 0x403, 0x388, 0x02B, 0x049, 0x3FF, 0x38C, 0x02C, 
+	0x047, 0x3FB, 0x391, 0x02D, 0x046, 0x3F6, 0x396, 0x02E, 
+	0x045, 0x3F2, 0x39B, 0x02F, 0x043, 0x3ED, 0x39F, 0x030, 
+	0x042, 0x3E9, 0x3A4, 0x031, 0x041, 0x3E5, 0x3A9, 0x032, 
+	0x040, 0x3E0, 0x3AD, 0x033, 0x03E, 0x3DC, 0x3B2, 0x034, 
+	0x03D, 0x3D7, 0x3B7, 0x035, 0x03C, 0x3D2, 0x3BB, 0x036, 
+	0x03B, 0x3CE, 0x3C0, 0x037, 0x03A, 0x3C9, 0x3C5, 0x038, 
+	0x038, 0x3C5, 0x3C9, 0x03A, 0x037, 0x3C0, 0x3CE, 0x03B, 
+	0x036, 0x3BB, 0x3D2, 0x03C, 0x035, 0x3B7, 0x3D7, 0x03D, 
+	0x034, 0x3B2, 0x3DC, 0x03E, 0x033, 0x3AD, 0x3E0, 0x040, 
+	0x032, 0x3A9, 0x3E5, 0x041, 0x031, 0x3A4, 0x3E9, 0x042, 
+	0x030, 0x39F, 0x3ED, 0x043, 0x02F, 0x39B, 0x3F2, 0x045, 
+	0x02E, 0x396, 0x3F6, 0x046, 0x02D, 0x391, 0x3FB, 0x047, 
+	0x02C, 0x38C, 0x3FF, 0x049, 0x02B, 0x388, 0x403, 0x04A, 
+	0x02A, 0x383, 0x408, 0x04C, 0x029, 0x37E, 0x40C, 0x04D, 
+	0x028, 0x379, 0x410, 0x04E, 0x027, 0x374, 0x415, 0x050, 
+	0x026, 0x370, 0x419, 0x051, 0x025, 0x36B, 0x41D, 0x053, 
+	0x024, 0x366, 0x421, 0x054, 0x024, 0x361, 0x425, 0x056, 
+	0x023, 0x35C, 0x42A, 0x057, 0x022, 0x357, 0x42E, 0x059, 
+	0x021, 0x353, 0x432, 0x05A, 0x020, 0x34E, 0x436, 0x05C, 
+	0x020, 0x349, 0x43A, 0x05E, 0x01F, 0x344, 0x43E, 0x05F, 
+	0x01E, 0x33F, 0x442, 0x061, 0x01D, 0x33A, 0x446, 0x063, 
+	0x01D, 0x335, 0x44A, 0x064, 0x01C, 0x330, 0x44E, 0x066, 
+	0x01B, 0x32B, 0x452, 0x068, 0x01B, 0x326, 0x455, 0x06A, 
+	0x01A, 0x322, 0x459, 0x06B, 0x019, 0x31D, 0x45D, 0x06D, 
+	0x018, 0x318, 0x461, 0x06F, 0x018, 0x313, 0x465, 0x071, 
+	0x017, 0x30E, 0x468, 0x073, 0x017, 0x309, 0x46C, 0x075, 
+	0x016, 0x304, 0x470, 0x076, 0x015, 0x2FF, 0x473, 0x078, 
+	0x015, 0x2FA, 0x477, 0x07A, 0x014, 0x2F5, 0x47A, 0x07C, 
+	0x014, 0x2F0, 0x47E, 0x07E, 0x013, 0x2EB, 0x481, 0x080, 
+	0x013, 0x2E6, 0x485, 0x082, 0x012, 0x2E1, 0x488, 0x084, 
+	0x011, 0x2DC, 0x48C, 0x086, 0x011, 0x2D8, 0x48F, 0x089, 
+	0x010, 0x2D3, 0x492, 0x08B, 0x010, 0x2CE, 0x496, 0x08D, 
+	0x00F, 0x2C9, 0x499, 0x08F, 0x00F, 0x2C4, 0x49C, 0x091, 
+	0x00F, 0x2BF, 0x49F, 0x093, 0x00E, 0x2BA, 0x4A2, 0x096, 
+	0x00E, 0x2B5, 0x4A6, 0x098, 0x00D, 0x2B0, 0x4A9, 0x09A, 
+	0x00D, 0x2AB, 0x4AC, 0x09C, 0x00C, 0x2A6, 0x4AF, 0x09F, 
+	0x00C, 0x2A2, 0x4B2, 0x0A1, 0x00B, 0x29D, 0x4B5, 0x0A3, 
+	0x00B, 0x298, 0x4B7, 0x0A6, 0x00B, 0x293, 0x4BA, 0x0A8, 
+	0x00A, 0x28E, 0x4BD, 0x0AB, 0x00A, 0x289, 0x4C0, 0x0AD, 
+	0x00A, 0x284, 0x4C3, 0x0AF, 0x009, 0x280, 0x4C5, 0x0B2, 
+	0x009, 0x27B, 0x4C8, 0x0B4, 0x009, 0x276, 0x4CB, 0x0B7, 
+	0x008, 0x271, 0x4CD, 0x0BA, 0x008, 0x26C, 0x4D0, 0x0BC, 
+	0x008, 0x267, 0x4D2, 0x0BF, 0x007, 0x263, 0x4D5, 0x0C1, 
+	0x007, 0x25E, 0x4D7, 0x0C4, 0x007, 0x259, 0x4D9, 0x0C7, 
+	0x006, 0x254, 0x4DC, 0x0C9, 0x006, 0x250, 0x4DE, 0x0CC, 
+	0x006, 0x24B, 0x4E0, 0x0CF, 0x006, 0x246, 0x4E3, 0x0D2, 
+	0x005, 0x241, 0x4E5, 0x0D4, 0x005, 0x23D, 0x4E7, 0x0D7, 
+	0x005, 0x238, 0x4E9, 0x0DA, 0x005, 0x233, 0x4EB, 0x0DD, 
+	0x004, 0x22F, 0x4ED, 0x0E0, 0x004, 0x22A, 0x4EF, 0x0E3, 
+	0x004, 0x226, 0x4F1, 0x0E6, 0x004, 0x221, 0x4F3, 0x0E9, 
+	0x004, 0x21C, 0x4F5, 0x0EC, 0x003, 0x218, 0x4F6, 0x0EF, 
+	0x003, 0x213, 0x4F8, 0x0F2, 0x003, 0x20F, 0x4FA, 0x0F5, 
+	0x003, 0x20A, 0x4FB, 0x0F8, 0x003, 0x205, 0x4FD, 0x0FB, 
+	0x002, 0x201, 0x4FF, 0x0FE, 0x002, 0x1FC, 0x500, 0x101, 
+	0x002, 0x1F8, 0x502, 0x104, 0x002, 0x1F3, 0x503, 0x107, 
+	0x002, 0x1EF, 0x504, 0x10B, 0x002, 0x1EB, 0x506, 0x10E, 
+	0x002, 0x1E6, 0x507, 0x111, 0x001, 0x1E2, 0x508, 0x114, 
+	0x001, 0x1DD, 0x50A, 0x118, 0x001, 0x1D9, 0x50B, 0x11B, 
+	0x001, 0x1D5, 0x50C, 0x11E, 0x001, 0x1D0, 0x50D, 0x122, 
+	0x001, 0x1CC, 0x50E, 0x125, 0x001, 0x1C8, 0x50F, 0x129, 
+	0x001, 0x1C3, 0x510, 0x12C, 0x001, 0x1BF, 0x511, 0x130, 
+	0x001, 0x1BB, 0x511, 0x133, 0x001, 0x1B7, 0x512, 0x137, 
+	0x000, 0x1B2, 0x513, 0x13A, 0x000, 0x1AE, 0x514, 0x13E, 
+	0x000, 0x1AA, 0x514, 0x141, 0x000, 0x1A6, 0x515, 0x145, 
+	0x000, 0x1A2, 0x516, 0x148, 0x000, 0x19E, 0x516, 0x14C, 
+	0x000, 0x19A, 0x517, 0x150, 0x000, 0x195, 0x517, 0x153, 
+	0x000, 0x191, 0x517, 0x157, 0x000, 0x18D, 0x518, 0x15B, 
+	0x000, 0x189, 0x518, 0x15F, 0x000, 0x185, 0x518, 0x162, 
+	0x000, 0x181, 0x518, 0x166, 0x000, 0x17D, 0x518, 0x16A, 
+	0x000, 0x17A, 0x519, 0x16E, 0x000, 0x176, 0x519, 0x172};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/oss.c	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,189 @@
+/***************************************************************************
+                            oss.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2005/08/29 - Pete
+// - changed to 48Khz output
+//
+// 2003/03/01 - linuzappz
+// - added checkings for oss_audio_fd == -1
+//
+// 2003/02/08 - linuzappz
+// - added iDisStereo stuff
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_OSS
+
+#include "externals.h"
+
+#ifndef _WINDOWS
+
+////////////////////////////////////////////////////////////////////////
+// small linux time helper... only used for watchdog
+////////////////////////////////////////////////////////////////////////
+
+unsigned long timeGetTime()
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);                                 // well, maybe there are better ways
+ return tv.tv_sec * 1000 + tv.tv_usec/1000;            // to do that, but at least it works
+}
+
+////////////////////////////////////////////////////////////////////////
+// oss globals
+////////////////////////////////////////////////////////////////////////
+
+#define OSS_MEM_DEF
+#include "oss.h"
+static int oss_audio_fd = -1;
+extern int errno;
+
+////////////////////////////////////////////////////////////////////////
+// SETUP SOUND
+////////////////////////////////////////////////////////////////////////
+
+void SetupSound(void)
+{
+ int pspeed=48000;
+ int pstereo;
+ int format;
+ int fragsize = 0;
+ int myfrag;
+ int oss_speed, oss_stereo;
+
+ if(iDisStereo) pstereo=OSS_MODE_MONO;
+ else           pstereo=OSS_MODE_STEREO;
+
+ oss_speed = pspeed;
+ oss_stereo = pstereo;
+
+ if((oss_audio_fd=open("/dev/dsp",O_WRONLY,0))==-1)
+  {
+   printf("Sound device not available!\n");
+   return;
+  }
+
+ if(ioctl(oss_audio_fd,SNDCTL_DSP_RESET,0)==-1)
+  {
+   printf("Sound reset failed\n");
+   return;
+  }
+
+ // we use 64 fragments with 1024 bytes each
+
+ fragsize=10;
+ myfrag=(63<<16)|fragsize;
+
+ if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFRAGMENT,&myfrag)==-1)
+  {
+   printf("Sound set fragment failed!\n");
+   return;        
+  }
+
+ format = AFMT_S16_LE;
+
+ if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFMT,&format) == -1)
+  {
+   printf("Sound format not supported!\n");
+   return;
+  }
+
+ if(format!=AFMT_S16_LE)
+  {
+   printf("Sound format not supported!\n");
+   return;
+  }
+
+ if(ioctl(oss_audio_fd,SNDCTL_DSP_STEREO,&oss_stereo)==-1)
+  {
+   printf("Stereo mode not supported!\n");
+   return;
+  }
+
+ if(oss_stereo!=1)
+  {
+   iDisStereo=1;
+  }
+
+ if(ioctl(oss_audio_fd,SNDCTL_DSP_SPEED,&oss_speed)==-1)
+  {
+   printf("Sound frequency not supported\n");
+   return;
+  }
+
+ if(oss_speed!=pspeed)
+  {
+   printf("Sound frequency not supported\n");
+   return;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// REMOVE SOUND
+////////////////////////////////////////////////////////////////////////
+
+void RemoveSound(void)
+{
+ if(oss_audio_fd != -1 )
+  {
+   close(oss_audio_fd);
+   oss_audio_fd = -1;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// GET BYTES BUFFERED
+////////////////////////////////////////////////////////////////////////
+
+unsigned long SoundGetBytesBuffered(void)
+{
+ audio_buf_info info;
+ unsigned long l;
+
+ if(oss_audio_fd == -1) return SOUNDSIZE;
+ if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==-1)
+  l=0;
+ else
+  {
+   if(info.fragments<(info.fragstotal>>1))             // can we write in at least the half of fragments?
+        l=SOUNDSIZE;                                   // -> no? wait
+   else l=0;                                           // -> else go on
+  }
+
+ return l;
+}
+
+////////////////////////////////////////////////////////////////////////
+// FEED SOUND DATA
+////////////////////////////////////////////////////////////////////////
+
+void SoundFeedStreamData(unsigned char* pSound,long lBytes)
+{
+ if(oss_audio_fd == -1) return;
+ write(oss_audio_fd,pSound,lBytes);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/oss.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,35 @@
+/***************************************************************************
+                          oss_sound.h  -  description
+                             -------------------
+    begin                : Wed Dec 8 1999
+    copyright            : (C) 1999 by Marcin "Duddie" Dudar
+    email                : duddie@psemu.com
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+
+#ifndef _OSS_SOUND_H
+#define _OSS_SOUND_H
+
+#ifdef OSS_MEM_DEF
+#define OSS_MEM_EXTERN
+#else
+#define OSS_MEM_EXTERN extern
+#endif
+
+OSS_MEM_EXTERN int sound_buffer_size;
+
+#define OSS_MODE_STEREO	1
+#define OSS_MODE_MONO		0
+
+#define OSS_SPEED_44100	44100
+
+#endif // _OSS_SOUND_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/psemuxa.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,28 @@
+//============================================
+//=== Audio XA decoding
+//=== Kazzuya
+//============================================
+
+#ifndef DECODEXA_H
+#define DECODEXA_H
+
+typedef struct
+{
+	long	y0, y1;
+} ADPCM_Decode_t;
+
+typedef struct
+{                                                                   
+	int				freq;
+	int				nbits;
+	int				stereo;
+	int				nsamples;
+	ADPCM_Decode_t	left, right;
+	short			pcm[16384];
+} xa_decode_t;
+
+long xa_decode_sector( xa_decode_t *xdp,
+					   unsigned char *sectorp,
+					   int is_first_sector );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/record.c	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,191 @@
+/***************************************************************************
+                            spu.c  -  description
+                             -------------------
+    begin                : Sun Jan 12 2003
+    copyright            : (C) 2003 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+              
+//*************************************************************************//
+// History of changes:
+//
+// 2005/08/29 - Pete
+// - changed to 48Khz output
+//
+// 2003/03/01 - Pete
+// - added mono mode
+//
+// 2003/01/12 - Pete
+// - added recording funcs (win version only)
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#ifdef _WINDOWS
+
+#include <mmsystem.h>
+#include "resource.h"
+#include "externals.h"
+
+#define _IN_RECORD
+
+#include "record.h"
+
+////////////////////////////////////////////////////////////////////////
+
+int      iDoRecord=0;
+HMMIO    hWaveFile=NULL;
+MMCKINFO mmckMain;
+MMCKINFO mmckData;
+char     szFileName[256];
+
+////////////////////////////////////////////////////////////////////////
+
+void RecordStart()
+{
+ WAVEFORMATEX pcmwf;
+
+ // setup header in the same format as our directsound stream
+ memset(&pcmwf,0,sizeof(WAVEFORMATEX));
+ pcmwf.wFormatTag      = WAVE_FORMAT_PCM;
+
+ if(iDisStereo)
+  {
+   pcmwf.nChannels       = 1;
+   pcmwf.nBlockAlign     = 2;
+  }
+ else
+  {
+   pcmwf.nChannels       = 2;
+   pcmwf.nBlockAlign     = 4;
+  }
+
+ pcmwf.nSamplesPerSec  = 48000;
+ pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign;
+ pcmwf.wBitsPerSample  = 16;
+
+ // create file
+ hWaveFile=mmioOpen(szFileName,NULL,MMIO_CREATE|MMIO_WRITE|MMIO_EXCLUSIVE | MMIO_ALLOCBUF);
+ if(!hWaveFile) return;
+ 
+ // setup WAVE, fmt and data chunks
+ memset(&mmckMain,0,sizeof(MMCKINFO));
+ mmckMain.fccType = mmioFOURCC('W','A','V','E');
+
+ mmioCreateChunk(hWaveFile,&mmckMain,MMIO_CREATERIFF);
+
+ memset(&mmckData,0,sizeof(MMCKINFO));
+ mmckData.ckid    = mmioFOURCC('f','m','t',' ');
+ mmckData.cksize  = sizeof(WAVEFORMATEX);
+
+ mmioCreateChunk(hWaveFile,&mmckData,0);
+ mmioWrite(hWaveFile,(char*)&pcmwf,sizeof(WAVEFORMATEX)); 
+ mmioAscend(hWaveFile,&mmckData,0);
+
+ mmckData.ckid = mmioFOURCC('d','a','t','a');
+ mmioCreateChunk(hWaveFile,&mmckData,0);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void RecordStop()
+{
+ // first some check, if recording is running
+ iDoRecord=0;
+ if(!hWaveFile) return;
+
+ // now finish writing & close the wave file
+ mmioAscend(hWaveFile,&mmckData,0);
+ mmioAscend(hWaveFile,&mmckMain,0);
+ mmioClose(hWaveFile,0);
+
+ // init var
+ hWaveFile=NULL;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void RecordBuffer(unsigned char* pSound,long lBytes)
+{
+ // write the samples
+ if(hWaveFile) mmioWrite(hWaveFile,pSound,lBytes);
+}
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+BOOL CALLBACK RecordDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+  {
+   //--------------------------------------------------// init
+   case WM_INITDIALOG:
+    {
+     SetDlgItemText(hW,IDC_WAVFILE,"C:\\PEOPS.WAV");   // init filename edit
+     ShowCursor(TRUE);                                 // mmm... who is hiding it? main emu? tsts
+     return TRUE;
+    }
+   //--------------------------------------------------// destroy
+   case WM_DESTROY:
+    {
+     RecordStop();
+    }break;
+   //--------------------------------------------------// command
+   case WM_COMMAND:
+    {
+     if(wParam==IDCANCEL) iRecordMode=2;               // cancel? raise flag for destroying the dialog
+
+     if(wParam==IDC_RECORD)                            // record start/stop?
+      {
+       if(IsWindowEnabled(GetDlgItem(hW,IDC_WAVFILE))) // not started yet (edit is not disabled):
+        {
+         GetDlgItemText(hW,IDC_WAVFILE,szFileName,255);// get filename
+
+         RecordStart();                                // start recording
+
+         if(hWaveFile)                                 // start was ok?
+          {                                            // -> disable filename edit, change text, raise flag
+           EnableWindow(GetDlgItem(hW,IDC_WAVFILE),FALSE);
+           SetDlgItemText(hW,IDC_RECORD,"Stop recording");
+           iDoRecord=1;
+          }
+         else MessageBeep(0xFFFFFFFF);                 // error starting recording? BEEP
+        }
+       else                                            // stop recording?
+        {
+         RecordStop();                                 // -> just do it
+         EnableWindow(GetDlgItem(hW,IDC_WAVFILE),TRUE);// -> enable filename edit again
+         SetDlgItemText(hW,IDC_RECORD,"Start recording");
+        }
+       SetFocus(hWMain);
+      }
+    }break;
+   //--------------------------------------------------// size
+   case WM_SIZE:
+    if(wParam==SIZE_MINIMIZED) SetFocus(hWMain);       // if we get minimized, set the foxus to the main window
+    break;
+   //--------------------------------------------------// setcursor
+   case WM_SETCURSOR:
+    {
+     SetCursor(LoadCursor(NULL,IDC_ARROW));            // force the arrow 
+     return TRUE;
+    }
+   //--------------------------------------------------//
+  }
+ return FALSE;
+}
+
+////////////////////////////////////////////////////////////////////////
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/record.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,12 @@
+#ifndef _RECORD_H_
+#define _RECORD_H_
+
+#ifdef _WINDOWS
+void RecordStart();
+void RecordBuffer(unsigned char* pSound,long lBytes);
+void RecordStop();
+BOOL CALLBACK RecordDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
+#endif
+
+#endif
+
--- a/Plugins/Input/sexypsf/spu/registers.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/registers.c	Sun Mar 19 12:51:03 2006 -0800
@@ -1,490 +1,1130 @@
-/***************************************************************************
-                         registers.c  -  description
-                             -------------------
-    begin                : Wed May 15 2002
-    copyright            : (C) 2002 by Pete Bernert
-    email                : BlackDove@addcom.de
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version. See also the license.txt file for *
- *   additional informations.                                              *
- *                                                                         *
- ***************************************************************************/
-
-/* ChangeLog 
-
- February 8, 2004	-	xodnizel
- - Fixed setting of reverb volume.  Just typecast val("u16") to s16.
-   Also adjusted the normal channel volume to be one less than what it was before when the 
-   "phase invert" bit is set.  I'm assuming it's just in two's complement.
-
- 2003/02/09 - kode54
- - removed &0x3fff from reverb volume registers, fixes a few games,
-   hopefully won't be breaking anything
-
- 2003/01/19 - Pete
- - added Neill's reverb
-
- 2003/01/06 - Pete
- - added Neill's ADSR timings
-
- 2002/05/15 - Pete
- - generic cleanup for the Peops release
-
-*/
-
-//#include "stdafx.h"
-
-#define _IN_REGISTERS
-
-//#include "externals.h"
-//#include "registers.h"
-//#include "regs.h"
-
-////////////////////////////////////////////////////////////////////////
-// WRITE REGISTERS: called by main emu
-////////////////////////////////////////////////////////////////////////
-
-void SPUwriteRegister(u32 reg, u16 val)
-{
- const u32 r=reg&0xfff;
- regArea[(r-0xc00)>>1] = val;
-
- if(r>=0x0c00 && r<0x0d80)                             // some channel info?
-  {
-   int ch=(r>>4)-0xc0;                                 // calc channel
-
-   //if(ch==20) printf("%08x: %04x\n",reg,val);
-
-   switch(r&0x0f)
-    {
-     //------------------------------------------------// r volume
-     case 0:                                           
-       SetVolumeLR(0,(u8)ch,val);
-       break;
-     //------------------------------------------------// l volume
-     case 2:                                           
-       SetVolumeLR(1,(u8)ch,val);
-       break;
-     //------------------------------------------------// pitch
-     case 4:                                           
-       SetPitch(ch,val);
-       break;
-     //------------------------------------------------// start
-     case 6:      
-       s_chan[ch].pStart=spuMemC+((u32) val<<3);
-       break;
-     //------------------------------------------------// level with pre-calcs
-     case 8:
-       {
-        const u32 lval=val; // DEBUG CHECK
-        //---------------------------------------------//
-        s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; 
-        s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;
-        s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;
-        s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;
-        //---------------------------------------------//
-      }
-      break;
-     //------------------------------------------------// adsr times with pre-calcs
-     case 10:
-      {
-       const u32 lval=val; // DEBUG CHECK
-
-       //----------------------------------------------//
-       s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;
-       s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;
-       s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;
-       s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;
-       s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;
-       //----------------------------------------------//
-      }
-     break;
-     //------------------------------------------------// adsr volume... mmm have to investigate this
-     //case 0xC:
-     //  break;
-     //------------------------------------------------//
-     case 0xE:                                          // loop?
-       s_chan[ch].pLoop=spuMemC+((u32) val<<3);
-       s_chan[ch].bIgnoreLoop=1;
-       break;
-     //------------------------------------------------//
-    }
-   return;
-  }
-
- switch(r)
-   {
-    //-------------------------------------------------//
-    case H_SPUaddr:
-      spuAddr = (u32) val<<3;
-      break;
-    //-------------------------------------------------//
-    case H_SPUdata:
-      spuMem[spuAddr>>1] = BFLIP16(val);
-      spuAddr+=2;
-      if(spuAddr>0x7ffff) spuAddr=0;
-      break;
-    //-------------------------------------------------//
-    case H_SPUctrl:
-      spuCtrl=val;
-      break;
-    //-------------------------------------------------//
-    case H_SPUstat:
-      spuStat=val & 0xf800;
-      break;
-    //-------------------------------------------------//
-    case H_SPUReverbAddr:
-      if(val==0xFFFF || val<=0x200)
-       {rvb.StartAddr=rvb.CurrAddr=0;}
-      else
-       {
-        const s32 iv=(u32)val<<2;
-        if(rvb.StartAddr!=iv)
-         {
-          rvb.StartAddr=(u32)val<<2;
-          rvb.CurrAddr=rvb.StartAddr;
-         }
-       }
-      break;
-    //-------------------------------------------------//
-    case H_SPUirqAddr:
-      spuIrq = val;
-      pSpuIrq=spuMemC+((u32) val<<3);
-      break;
-    //-------------------------------------------------//
-    /* Volume settings appear to be at least 15-bit unsigned in this case.  
-       Definitely NOT 15-bit signed.  Probably 16-bit signed, so s16 type cast.
-       Check out "Chrono Cross:  Shadow's End Forest"
-    */
-    case H_SPUrvolL:
-      rvb.VolLeft=(s16)val;
-      //printf("%d\n",val);
-      break;
-    //-------------------------------------------------//
-    case H_SPUrvolR:
-      rvb.VolRight=(s16)val;
-      //printf("%d\n",val);
-      break;
-    //-------------------------------------------------//
-
-/*
-    case H_ExtLeft:
-     //auxprintf("EL %d\n",val);
-      break;
-    //-------------------------------------------------//
-    case H_ExtRight:
-     //auxprintf("ER %d\n",val);
-      break;
-    //-------------------------------------------------//
-    case H_SPUmvolL:
-     //auxprintf("ML %d\n",val);
-      break;
-    //-------------------------------------------------//
-    case H_SPUmvolR:
-     //auxprintf("MR %d\n",val);
-      break;
-    //-------------------------------------------------//
-    case H_SPUMute1:
-     //printf("M0 %04x\n",val);
-      break;
-    //-------------------------------------------------//
-    case H_SPUMute2:
-    // printf("M1 %04x\n",val);
-      break;
-*/
-    //-------------------------------------------------//
-    case H_SPUon1:
-      SoundOn(0,16,val);
-      break;
-    //-------------------------------------------------//
-     case H_SPUon2:
-	// printf("Boop: %08x: %04x\n",reg,val);
-      SoundOn(16,24,val);
-      break;
-    //-------------------------------------------------//
-    case H_SPUoff1:
-      SoundOff(0,16,val);
-      break;
-    //-------------------------------------------------//
-    case H_SPUoff2:
-      SoundOff(16,24,val);
-	// printf("Boop: %08x: %04x\n",reg,val);
-      break;
-    //-------------------------------------------------//
-    case H_FMod1:
-      FModOn(0,16,val);
-      break;
-    //-------------------------------------------------//
-    case H_FMod2:
-      FModOn(16,24,val);
-      break;
-    //-------------------------------------------------//
-    case H_Noise1:
-      NoiseOn(0,16,val);
-      break;
-    //-------------------------------------------------//
-    case H_Noise2:
-      NoiseOn(16,24,val);
-      break;
-    //-------------------------------------------------//
-    case H_RVBon1:
-      rvb.Enabled&=~0xFFFF;
-      rvb.Enabled|=val;
-      break;
-
-    //-------------------------------------------------//
-    case H_RVBon2:
-      rvb.Enabled&=0xFFFF;
-      rvb.Enabled|=val<<16;
-      break;
-
-    //-------------------------------------------------//
-    case H_Reverb+0:
-      rvb.FB_SRC_A=val;
-      break;
-
-    case H_Reverb+2   : rvb.FB_SRC_B=(s16)val;       break;
-    case H_Reverb+4   : rvb.IIR_ALPHA=(s16)val;      break;
-    case H_Reverb+6   : rvb.ACC_COEF_A=(s16)val;     break;
-    case H_Reverb+8   : rvb.ACC_COEF_B=(s16)val;     break;
-    case H_Reverb+10  : rvb.ACC_COEF_C=(s16)val;     break;
-    case H_Reverb+12  : rvb.ACC_COEF_D=(s16)val;     break;
-    case H_Reverb+14  : rvb.IIR_COEF=(s16)val;       break;
-    case H_Reverb+16  : rvb.FB_ALPHA=(s16)val;       break;
-    case H_Reverb+18  : rvb.FB_X=(s16)val;           break;
-    case H_Reverb+20  : rvb.IIR_DEST_A0=(s16)val;    break;
-    case H_Reverb+22  : rvb.IIR_DEST_A1=(s16)val;    break;
-    case H_Reverb+24  : rvb.ACC_SRC_A0=(s16)val;     break;
-    case H_Reverb+26  : rvb.ACC_SRC_A1=(s16)val;     break;
-    case H_Reverb+28  : rvb.ACC_SRC_B0=(s16)val;     break;
-    case H_Reverb+30  : rvb.ACC_SRC_B1=(s16)val;     break;
-    case H_Reverb+32  : rvb.IIR_SRC_A0=(s16)val;     break;
-    case H_Reverb+34  : rvb.IIR_SRC_A1=(s16)val;     break;
-    case H_Reverb+36  : rvb.IIR_DEST_B0=(s16)val;    break;
-    case H_Reverb+38  : rvb.IIR_DEST_B1=(s16)val;    break;
-    case H_Reverb+40  : rvb.ACC_SRC_C0=(s16)val;     break;
-    case H_Reverb+42  : rvb.ACC_SRC_C1=(s16)val;     break;
-    case H_Reverb+44  : rvb.ACC_SRC_D0=(s16)val;     break;
-    case H_Reverb+46  : rvb.ACC_SRC_D1=(s16)val;     break;
-    case H_Reverb+48  : rvb.IIR_SRC_B1=(s16)val;     break;
-    case H_Reverb+50  : rvb.IIR_SRC_B0=(s16)val;     break;
-    case H_Reverb+52  : rvb.MIX_DEST_A0=(s16)val;    break;
-    case H_Reverb+54  : rvb.MIX_DEST_A1=(s16)val;    break;
-    case H_Reverb+56  : rvb.MIX_DEST_B0=(s16)val;    break;
-    case H_Reverb+58  : rvb.MIX_DEST_B1=(s16)val;    break;
-    case H_Reverb+60  : rvb.IN_COEF_L=(s16)val;      break;
-    case H_Reverb+62  : rvb.IN_COEF_R=(s16)val;      break;
-   }
-
-}
-
-////////////////////////////////////////////////////////////////////////
-// READ REGISTER: called by main emu
-////////////////////////////////////////////////////////////////////////
-
-u16 SPUreadRegister(u32 reg)
-{
- const u32 r=reg&0xfff;
-
- if(r>=0x0c00 && r<0x0d80)
-  {
-   switch(r&0x0f)
-    {
-     case 0xC:                                          // get adsr vol
-      {
-       const int ch=(r>>4)-0xc0;
-       if(s_chan[ch].bNew) return 1;                   // we are started, but not processed? return 1
-       if(s_chan[ch].ADSRX.lVolume &&                  // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well
-          !s_chan[ch].ADSRX.EnvelopeVol)                   
-        return 1;
-       return (u16)(s_chan[ch].ADSRX.EnvelopeVol>>16);
-      }
-
-     case 0xE:                                          // get loop address
-      {
-       const int ch=(r>>4)-0xc0;
-       if(s_chan[ch].pLoop==NULL) return 0;
-       return (u16)((s_chan[ch].pLoop-spuMemC)>>3);
-      }
-    }
-  }
-
- switch(r)
-  {
-    case H_SPUctrl:
-     return spuCtrl;
-
-    case H_SPUstat:
-     return spuStat;
-        
-    case H_SPUaddr:
-     return (u16)(spuAddr>>3);
-
-    case H_SPUdata:
-     {
-      u16 s=BFLIP16(spuMem[spuAddr>>1]);
-      spuAddr+=2;
-      if(spuAddr>0x7ffff) spuAddr=0;
-      return s;
-     }
-
-    case H_SPUirqAddr:
-     return spuIrq;
-
-    //case H_SPUIsOn1:
-    // return IsSoundOn(0,16);
-
-    //case H_SPUIsOn2:
-    // return IsSoundOn(16,24);
- 
-  }
-
- return regArea[(r-0xc00)>>1];
-}
- 
-////////////////////////////////////////////////////////////////////////
-// SOUND ON register write
-////////////////////////////////////////////////////////////////////////
-
-static void SoundOn(int start,int end,u16 val)     // SOUND ON PSX COMAND
-{
- int ch;
-
- for(ch=start;ch<end;ch++,val>>=1)                     // loop channels
-  {
-   if((val&1) && s_chan[ch].pStart)                    // mmm... start has to be set before key on !?!
-    {
-     s_chan[ch].bIgnoreLoop=0;
-     s_chan[ch].bNew=1;
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////////
-// SOUND OFF register write
-////////////////////////////////////////////////////////////////////////
-
-static void SoundOff(int start,int end,u16 val)    // SOUND OFF PSX COMMAND
-{
- int ch;
- for(ch=start;ch<end;ch++,val>>=1)                     // loop channels
-  {
-   if(val&1)                                           // && s_chan[i].bOn)  mmm...
-    {
-     s_chan[ch].bStop=1;
-    }                                                  
-  }
-}
-
-////////////////////////////////////////////////////////////////////////
-// FMOD register write
-////////////////////////////////////////////////////////////////////////
-
-static void FModOn(int start,int end,u16 val)      // FMOD ON PSX COMMAND
-{
- int ch;
-
- for(ch=start;ch<end;ch++,val>>=1)                     // loop channels
-  {
-   if(val&1)                                           // -> fmod on/off
-    {
-     if(ch>0) 
-      {
-       s_chan[ch].bFMod=1;                             // --> sound channel
-       s_chan[ch-1].bFMod=2;                           // --> freq channel
-      }
-    }
-   else
-    {
-     s_chan[ch].bFMod=0;                               // --> turn off fmod
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////////
-// NOISE register write
-////////////////////////////////////////////////////////////////////////
-
-static void NoiseOn(int start,int end,u16 val)     // NOISE ON PSX COMMAND
-{
- int ch;
-
- for(ch=start;ch<end;ch++,val>>=1)                     // loop channels
-  {
-   if(val&1)                                           // -> noise on/off
-    {
-     s_chan[ch].bNoise=1;
-    }
-   else 
-    {
-     s_chan[ch].bNoise=0;
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////////
-// LEFT VOLUME register write
-////////////////////////////////////////////////////////////////////////
-
-// please note: sweep is wrong.
-
-static void SetVolumeLR(int right, u8 ch,s16 vol)            // LEFT VOLUME
-{
- //if(vol&0xc000)
- //printf("%d %08x\n",right,vol);
- if(right)
-  s_chan[ch].iRightVolRaw=vol;
- else
-  s_chan[ch].iLeftVolRaw=vol;
-
- if(vol&0x8000)                                        // sweep?
-  {
-   s16 sInc=1;                                       // -> sweep up?
-   if(vol&0x2000) sInc=-1;                             // -> or down?
-   if(vol&0x1000) vol^=0xffff;                         // -> mmm... phase inverted? have to investigate this
-   vol=((vol&0x7f)+1)/2;                               // -> sweep: 0..127 -> 0..64
-   vol+=vol/(2*sInc);                                  // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half!
-   vol*=128;
-   vol&=0x3fff;
-   //puts("Sweep");
-  }
- else                                                  // no sweep:
-  {
-   if(vol&0x4000)
-    vol=(vol&0x3FFF)-0x4000;
-   else
-    vol&=0x3FFF;
-
-   //if(vol&0x4000)                                      // -> mmm... phase inverted? have to investigate this
-   // vol=0-(0x3fff-(vol&0x3fff));
-   //else
-   // vol&=0x3fff;
-  }
- if(right)
-  s_chan[ch].iRightVolume=vol;
- else
-  s_chan[ch].iLeftVolume=vol;                           // store volume
-}
-
-////////////////////////////////////////////////////////////////////////
-// PITCH register write
-////////////////////////////////////////////////////////////////////////
-
-static void SetPitch(int ch,u16 val)               // SET PITCH
-{
- int NP;
- if(val>0x3fff) NP=0x3fff;                             // get pitch val
- else           NP=val;
-
- s_chan[ch].iRawPitch=NP;
-
- NP=(44100L*NP)/4096L;                                 // calc frequency
- if(NP<1) NP=1;                                        // some security
- s_chan[ch].iActFreq=NP;                               // store frequency
-}
+/***************************************************************************
+                         registers.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2003/02/09 - kode54
+// - removed &0x3fff from reverb volume registers, fixes a few games,
+//   hopefully won't be breaking anything
+//
+// 2003/01/19 - Pete
+// - added Neill's reverb
+//
+// 2003/01/06 - Pete
+// - added Neill's ADSR timings
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_REGISTERS
+
+#include "externals.h"
+#include "registers.h"
+#include "regs.h"
+#include "reverb.h"
+#include "debug.h"
+
+/*
+// adsr time values (in ms) by James Higgs ... see the end of
+// the adsr.c source for details
+
+#define ATTACK_MS     514L
+#define DECAYHALF_MS  292L
+#define DECAY_MS      584L
+#define SUSTAIN_MS    450L
+#define RELEASE_MS    446L
+*/
+
+// we have a timebase of 1.020408f ms, not 1 ms... so adjust adsr defines
+#define ATTACK_MS      494L
+#define DECAYHALF_MS   286L
+#define DECAY_MS       572L
+#define SUSTAIN_MS     441L
+#define RELEASE_MS     437L
+
+////////////////////////////////////////////////////////////////////////
+// WRITE REGISTERS: called by main emu
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val)
+{
+ long r=reg&0xffff;
+
+#ifdef _WINDOWS
+ if(iDebugMode==1) logprintf("W_REG %X - %X\r\n",reg&0xFFFF,val);
+#endif
+
+ regArea[r>>1] = val;
+
+ if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580))  // some channel info?
+  {
+   int ch=(r>>4)&0x1f;
+   if(r>=0x400) ch+=24;
+   
+   switch(r&0x0f)
+    {
+     //------------------------------------------------// r volume
+     case 0:                                           
+       SetVolumeL((unsigned char)ch,val);
+       break;
+     //------------------------------------------------// l volume
+     case 2:                                           
+       SetVolumeR((unsigned char)ch,val);
+       break;
+     //------------------------------------------------// pitch
+     case 4:                                           
+       SetPitch(ch,val);
+       break;
+     //------------------------------------------------// level with pre-calcs
+     case 6:
+       {
+        const unsigned long lval=val;unsigned long lx;
+        //---------------------------------------------//
+        s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; 
+        s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;
+        s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;
+        s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;
+        //---------------------------------------------//
+        if(!iDebugMode) break;
+        //---------------------------------------------// stuff below is only for debug mode
+
+        s_chan[ch].ADSR.AttackModeExp=(lval&0x8000)?1:0;        //0x007f
+
+        lx=(((lval>>8) & 0x007f)>>2);                  // attack time to run from 0 to 100% volume
+        lx=min(31,lx);                                 // no overflow on shift!
+        if(lx) 
+         { 
+          lx = (1<<lx);
+          if(lx<2147483) lx=(lx*ATTACK_MS)/10000L;     // another overflow check
+          else           lx=(lx/10000L)*ATTACK_MS;
+          if(!lx) lx=1;
+         }
+        s_chan[ch].ADSR.AttackTime=lx;                
+
+        s_chan[ch].ADSR.SustainLevel=                 // our adsr vol runs from 0 to 1024, so scale the sustain level
+         (1024*((lval) & 0x000f))/15;
+
+        lx=(lval>>4) & 0x000f;                         // decay:
+        if(lx)                                         // our const decay value is time it takes from 100% to 0% of volume
+         {
+          lx = ((1<<(lx))*DECAY_MS)/10000L;
+          if(!lx) lx=1;
+         }
+        s_chan[ch].ADSR.DecayTime =                   // so calc how long does it take to run from 100% to the wanted sus level
+         (lx*(1024-s_chan[ch].ADSR.SustainLevel))/1024;
+       }
+      break;
+     //------------------------------------------------// adsr times with pre-calcs
+     case 8:
+      {
+       const unsigned long lval=val;unsigned long lx;
+
+       //----------------------------------------------//
+       s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;
+       s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;
+       s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;
+       s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;
+       s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;
+       //----------------------------------------------//
+       if(!iDebugMode) break;
+       //----------------------------------------------// stuff below is only for debug mode
+
+       s_chan[ch].ADSR.SustainModeExp = (lval&0x8000)?1:0;
+       s_chan[ch].ADSR.ReleaseModeExp = (lval&0x0020)?1:0;
+                   
+       lx=((((lval>>6) & 0x007f)>>2));                 // sustain time... often very high
+       lx=min(31,lx);                                  // values are used to hold the volume
+       if(lx)                                          // until a sound stop occurs
+        {                                              // the highest value we reach (due to 
+         lx = (1<<lx);                                 // overflow checking) is: 
+         if(lx<2147483) lx=(lx*SUSTAIN_MS)/10000L;     // 94704 seconds = 1578 minutes = 26 hours... 
+         else           lx=(lx/10000L)*SUSTAIN_MS;     // should be enuff... if the stop doesn't 
+         if(!lx) lx=1;                                 // come in this time span, I don't care :)
+        }
+       s_chan[ch].ADSR.SustainTime = lx;
+
+       lx=(lval & 0x001f);
+       s_chan[ch].ADSR.ReleaseVal     =lx;
+       if(lx)                                          // release time from 100% to 0%
+        {                                              // note: the release time will be
+         lx = (1<<lx);                                 // adjusted when a stop is coming,
+         if(lx<2147483) lx=(lx*RELEASE_MS)/10000L;     // so at this time the adsr vol will 
+         else           lx=(lx/10000L)*RELEASE_MS;     // run from (current volume) to 0%
+         if(!lx) lx=1;
+        }
+       s_chan[ch].ADSR.ReleaseTime=lx;
+
+       if(lval & 0x4000)                               // add/dec flag
+            s_chan[ch].ADSR.SustainModeDec=-1;
+       else s_chan[ch].ADSR.SustainModeDec=1;
+      }
+     break;
+     //------------------------------------------------//
+    }
+
+   iSpuAsyncWait=0;
+
+   return;
+  }
+
+ if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0))  // some channel info?
+  {
+   int ch=0;
+   if(r>=0x400) {ch=24;r-=0x400;}
+
+   ch+=(r-0x1c0)/12;
+   r-=(ch%24)*12;
+   switch(r)
+    {
+     //------------------------------------------------//
+     case 0x1C0:
+      s_chan[ch].iStartAdr=(((unsigned long)val&0xf)<<16)|(s_chan[ch].iStartAdr&0xFFFF);
+      s_chan[ch].pStart=spuMemC+(s_chan[ch].iStartAdr<<1);
+      break;
+     case 0x1C2:
+      s_chan[ch].iStartAdr=(s_chan[ch].iStartAdr & 0xF0000) | (val & 0xFFFF);
+      s_chan[ch].pStart=spuMemC+(s_chan[ch].iStartAdr<<1);
+      break;
+     //------------------------------------------------//
+     case 0x1C4:
+      s_chan[ch].iLoopAdr=(((unsigned long)val&0xf)<<16)|(s_chan[ch].iLoopAdr&0xFFFF);
+      s_chan[ch].pLoop=spuMemC+(s_chan[ch].iLoopAdr<<1);
+      s_chan[ch].bIgnoreLoop=1;
+      break;
+     case 0x1C6:
+      s_chan[ch].iLoopAdr=(s_chan[ch].iLoopAdr & 0xF0000) | (val & 0xFFFF);
+      s_chan[ch].pLoop=spuMemC+(s_chan[ch].iLoopAdr<<1);
+      s_chan[ch].bIgnoreLoop=1;
+      break;
+     //------------------------------------------------//
+     case 0x1C8:
+      // unused... check if it gets written as well
+      s_chan[ch].iNextAdr=(((unsigned long)val&0xf)<<16)|(s_chan[ch].iNextAdr&0xFFFF);
+      break;
+     case 0x1CA:
+      // unused... check if it gets written as well
+      s_chan[ch].iNextAdr=(s_chan[ch].iNextAdr & 0xF0000) | (val & 0xFFFF);
+      break;
+     //------------------------------------------------//
+    }
+
+   iSpuAsyncWait=0;
+
+   return;
+  } 
+
+ switch(r)
+   {
+    //-------------------------------------------------//
+    case PS2_C0_SPUaddr_Hi:
+      spuAddr2[0] = (((unsigned long)val&0xf)<<16)|(spuAddr2[0]&0xFFFF);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUaddr_Lo:
+      spuAddr2[0] = (spuAddr2[0] & 0xF0000) | (val & 0xFFFF);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUaddr_Hi:
+      spuAddr2[1] = (((unsigned long)val&0xf)<<16)|(spuAddr2[1]&0xFFFF);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUaddr_Lo:
+      spuAddr2[1] = (spuAddr2[1] & 0xF0000) | (val & 0xFFFF);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUdata:
+      spuMem[spuAddr2[0]] = val;
+      spuAddr2[0]++;
+      if(spuAddr2[0]>0xfffff) spuAddr2[0]=0;
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUdata:
+      spuMem[spuAddr2[1]] = val;
+      spuAddr2[1]++;
+      if(spuAddr2[1]>0xfffff) spuAddr2[1]=0;
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_ATTR:
+      spuCtrl2[0]=val;
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_ATTR:
+      spuCtrl2[1]=val;
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUstat:
+      spuStat2[0]=val;
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUstat:
+      spuStat2[1]=val;
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_ReverbAddr_Hi:
+      spuRvbAddr2[0] = (((unsigned long)val&0xf)<<16)|(spuRvbAddr2[0]&0xFFFF);
+      SetReverbAddr(0);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_ReverbAddr_Lo:
+      spuRvbAddr2[0] = (spuRvbAddr2[0] & 0xF0000) | (val & 0xFFFF);
+      SetReverbAddr(0);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_ReverbAEnd_Hi:
+      spuRvbAEnd2[0] = (((unsigned long)val&0xf)<<16)|(/*spuRvbAEnd2[0]&*/0xFFFF);
+      rvb[0].EndAddr=spuRvbAEnd2[0];
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_ReverbAEnd_Hi:
+      spuRvbAEnd2[1] = (((unsigned long)val&0xf)<<16)|(/*spuRvbAEnd2[1]&*/0xFFFF);
+      rvb[1].EndAddr=spuRvbAEnd2[1];
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_ReverbAddr_Hi:
+      spuRvbAddr2[1] = (((unsigned long)val&0xf)<<16)|(spuRvbAddr2[1]&0xFFFF);
+      SetReverbAddr(1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_ReverbAddr_Lo:
+      spuRvbAddr2[1] = (spuRvbAddr2[1] & 0xF0000) | (val & 0xFFFF);
+      SetReverbAddr(1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUirqAddr_Hi:
+      spuIrq2[0] = (((unsigned long)val&0xf)<<16)|(spuIrq2[0]&0xFFFF);
+      pSpuIrq[0]=spuMemC+(spuIrq2[0]<<1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUirqAddr_Lo:
+      spuIrq2[0] = (spuIrq2[0] & 0xF0000) | (val & 0xFFFF);
+      pSpuIrq[0]=spuMemC+(spuIrq2[0]<<1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUirqAddr_Hi:
+      spuIrq2[1] = (((unsigned long)val&0xf)<<16)|(spuIrq2[1]&0xFFFF);
+      pSpuIrq[1]=spuMemC+(spuIrq2[1]<<1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUirqAddr_Lo:
+      spuIrq2[1] = (spuIrq2[1] & 0xF0000) | (val & 0xFFFF);
+      pSpuIrq[1]=spuMemC+(spuIrq2[1]<<1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUrvolL:
+      rvb[0].VolLeft=val;
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUrvolR:
+      rvb[0].VolRight=val;
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUrvolL:
+      rvb[1].VolLeft=val;
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUrvolR:
+      rvb[1].VolRight=val;
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUon1:
+      SoundOn(0,16,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUon2:
+      SoundOn(16,24,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUon1:
+      SoundOn(24,40,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUon2:
+      SoundOn(40,48,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUoff1:
+      SoundOff(0,16,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUoff2:
+      SoundOff(16,24,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUoff1:
+      SoundOff(24,40,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUoff2:
+      SoundOff(40,48,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_SPUend1:
+    case PS2_C0_SPUend2:
+      if(val) dwEndChannel2[0]=0;
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_SPUend1:
+    case PS2_C1_SPUend2:
+      if(val) dwEndChannel2[1]=0;
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_FMod1:
+      FModOn(0,16,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_FMod2:
+      FModOn(16,24,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_FMod1:
+      FModOn(24,40,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_FMod2:
+      FModOn(40,48,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_Noise1:
+      NoiseOn(0,16,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_Noise2:
+      NoiseOn(16,24,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_Noise1:
+      NoiseOn(24,40,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_Noise2:
+      NoiseOn(40,48,val);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_DryL1:
+      VolumeOn(0,16,val,0);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_DryL2:
+      VolumeOn(16,24,val,0);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_DryL1:
+      VolumeOn(24,40,val,0);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_DryL2:
+      VolumeOn(40,48,val,0);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_DryR1:
+      VolumeOn(0,16,val,1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_DryR2:
+      VolumeOn(16,24,val,1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_DryR1:
+      VolumeOn(24,40,val,1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_DryR2:
+      VolumeOn(40,48,val,1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_RVBon1_L:
+      ReverbOn(0,16,val,0);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_RVBon2_L:
+      ReverbOn(16,24,val,0);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_RVBon1_L:
+      ReverbOn(24,40,val,0);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_RVBon2_L:
+      ReverbOn(40,48,val,0);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_RVBon1_R:
+      ReverbOn(0,16,val,1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_RVBon2_R:
+      ReverbOn(16,24,val,1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_RVBon1_R:
+      ReverbOn(24,40,val,1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C1_RVBon2_R:
+      ReverbOn(40,48,val,1);
+      break;
+    //-------------------------------------------------//
+    case PS2_C0_Reverb+0:
+      rvb[0].FB_SRC_A=(((unsigned long)val&0xf)<<16)|(rvb[0].FB_SRC_A&0xFFFF);
+      break;
+    case PS2_C0_Reverb+2:
+      rvb[0].FB_SRC_A=(rvb[0].FB_SRC_A & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+4:
+      rvb[0].FB_SRC_B=(((unsigned long)val&0xf)<<16)|(rvb[0].FB_SRC_B&0xFFFF);
+      break;
+    case PS2_C0_Reverb+6:
+      rvb[0].FB_SRC_B=(rvb[0].FB_SRC_B & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+8:
+      rvb[0].IIR_DEST_A0=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_DEST_A0&0xFFFF);
+      break;
+    case PS2_C0_Reverb+10:
+      rvb[0].IIR_DEST_A0=(rvb[0].IIR_DEST_A0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+12:
+      rvb[0].IIR_DEST_A1=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_DEST_A1&0xFFFF);
+      break;
+    case PS2_C0_Reverb+14:
+      rvb[0].IIR_DEST_A1=(rvb[0].IIR_DEST_A1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+16:
+      rvb[0].ACC_SRC_A0=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_A0&0xFFFF);
+      break;
+    case PS2_C0_Reverb+18:
+      rvb[0].ACC_SRC_A0=(rvb[0].ACC_SRC_A0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+20:
+      rvb[0].ACC_SRC_A1=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_A1&0xFFFF);
+      break;
+    case PS2_C0_Reverb+22:
+      rvb[0].ACC_SRC_A1=(rvb[0].ACC_SRC_A1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+24:
+      rvb[0].ACC_SRC_B0=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_B0&0xFFFF);
+      break;
+    case PS2_C0_Reverb+26:
+      rvb[0].ACC_SRC_B0=(rvb[0].ACC_SRC_B0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+28:
+      rvb[0].ACC_SRC_B1=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_B1&0xFFFF);
+      break;
+    case PS2_C0_Reverb+30:
+      rvb[0].ACC_SRC_B1=(rvb[0].ACC_SRC_B1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+32:
+      rvb[0].IIR_SRC_A0=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_SRC_A0&0xFFFF);
+      break;
+    case PS2_C0_Reverb+34:
+      rvb[0].IIR_SRC_A0=(rvb[0].IIR_SRC_A0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+36:
+      rvb[0].IIR_SRC_A1=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_SRC_A1&0xFFFF);
+      break;
+    case PS2_C0_Reverb+38:
+      rvb[0].IIR_SRC_A1=(rvb[0].IIR_SRC_A1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+40:
+      rvb[0].IIR_DEST_B0=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_DEST_B0&0xFFFF);
+      break;
+    case PS2_C0_Reverb+42:
+      rvb[0].IIR_DEST_B0=(rvb[0].IIR_DEST_B0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+44:
+      rvb[0].IIR_DEST_B1=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_DEST_B1&0xFFFF);
+      break;
+    case PS2_C0_Reverb+46:
+      rvb[0].IIR_DEST_B1=(rvb[0].IIR_DEST_B1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+48:
+      rvb[0].ACC_SRC_C0=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_C0&0xFFFF);
+      break;
+    case PS2_C0_Reverb+50:
+      rvb[0].ACC_SRC_C0=(rvb[0].ACC_SRC_C0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+52:
+      rvb[0].ACC_SRC_C1=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_C1&0xFFFF);
+      break;
+    case PS2_C0_Reverb+54:
+      rvb[0].ACC_SRC_C1=(rvb[0].ACC_SRC_C1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+56:
+      rvb[0].ACC_SRC_D0=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_D0&0xFFFF);
+      break;
+    case PS2_C0_Reverb+58:
+      rvb[0].ACC_SRC_D0=(rvb[0].ACC_SRC_D0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+60:
+      rvb[0].ACC_SRC_D1=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_D1&0xFFFF);
+      break;
+    case PS2_C0_Reverb+62:
+      rvb[0].ACC_SRC_D1=(rvb[0].ACC_SRC_D1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+64:
+      rvb[0].IIR_SRC_B1=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_SRC_B1&0xFFFF);
+      break;
+    case PS2_C0_Reverb+66:
+      rvb[0].IIR_SRC_B1=(rvb[0].IIR_SRC_B1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+68:
+      rvb[0].IIR_SRC_B0=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_SRC_B0&0xFFFF);
+      break;
+    case PS2_C0_Reverb+70:
+      rvb[0].IIR_SRC_B0=(rvb[0].IIR_SRC_B0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+72:
+      rvb[0].MIX_DEST_A0=(((unsigned long)val&0xf)<<16)|(rvb[0].MIX_DEST_A0&0xFFFF);
+      break;
+    case PS2_C0_Reverb+74:
+      rvb[0].MIX_DEST_A0=(rvb[0].MIX_DEST_A0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+76:
+      rvb[0].MIX_DEST_A1=(((unsigned long)val&0xf)<<16)|(rvb[0].MIX_DEST_A1&0xFFFF);
+      break;
+    case PS2_C0_Reverb+78:
+      rvb[0].MIX_DEST_A1=(rvb[0].MIX_DEST_A1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+80:
+      rvb[0].MIX_DEST_B0=(((unsigned long)val&0xf)<<16)|(rvb[0].MIX_DEST_B0&0xFFFF);
+      break;
+    case PS2_C0_Reverb+82:
+      rvb[0].MIX_DEST_B0=(rvb[0].MIX_DEST_B0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_Reverb+84:
+      rvb[0].MIX_DEST_B1=(((unsigned long)val&0xf)<<16)|(rvb[0].MIX_DEST_B1&0xFFFF);
+      break;
+    case PS2_C0_Reverb+86:
+      rvb[0].MIX_DEST_B1=(rvb[0].MIX_DEST_B1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C0_ReverbX+0:  rvb[0].IIR_ALPHA=(short)val;      break;
+    case PS2_C0_ReverbX+2:  rvb[0].ACC_COEF_A=(short)val;     break;
+    case PS2_C0_ReverbX+4:  rvb[0].ACC_COEF_B=(short)val;     break;
+    case PS2_C0_ReverbX+6:  rvb[0].ACC_COEF_C=(short)val;     break;
+    case PS2_C0_ReverbX+8:  rvb[0].ACC_COEF_D=(short)val;     break;
+    case PS2_C0_ReverbX+10: rvb[0].IIR_COEF=(short)val;       break;
+    case PS2_C0_ReverbX+12: rvb[0].FB_ALPHA=(short)val;       break;
+    case PS2_C0_ReverbX+14: rvb[0].FB_X=(short)val;           break;
+    case PS2_C0_ReverbX+16: rvb[0].IN_COEF_L=(short)val;      break;
+    case PS2_C0_ReverbX+18: rvb[0].IN_COEF_R=(short)val;      break;
+    //-------------------------------------------------//
+    case PS2_C1_Reverb+0:
+      rvb[1].FB_SRC_A=(((unsigned long)val&0xf)<<16)|(rvb[1].FB_SRC_A&0xFFFF);
+      break;
+    case PS2_C1_Reverb+2:
+      rvb[1].FB_SRC_A=(rvb[1].FB_SRC_A & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+4:
+      rvb[1].FB_SRC_B=(((unsigned long)val&0xf)<<16)|(rvb[1].FB_SRC_B&0xFFFF);
+      break;
+    case PS2_C1_Reverb+6:
+      rvb[1].FB_SRC_B=(rvb[1].FB_SRC_B & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+8:
+      rvb[1].IIR_DEST_A0=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_DEST_A0&0xFFFF);
+      break;
+    case PS2_C1_Reverb+10:
+      rvb[1].IIR_DEST_A0=(rvb[1].IIR_DEST_A0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+12:
+      rvb[1].IIR_DEST_A1=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_DEST_A1&0xFFFF);
+      break;
+    case PS2_C1_Reverb+14:
+      rvb[1].IIR_DEST_A1=(rvb[1].IIR_DEST_A1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+16:
+      rvb[1].ACC_SRC_A0=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_A0&0xFFFF);
+      break;
+    case PS2_C1_Reverb+18:
+      rvb[1].ACC_SRC_A0=(rvb[1].ACC_SRC_A0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+20:
+      rvb[1].ACC_SRC_A1=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_A1&0xFFFF);
+      break;
+    case PS2_C1_Reverb+22:
+      rvb[1].ACC_SRC_A1=(rvb[1].ACC_SRC_A1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+24:
+      rvb[1].ACC_SRC_B0=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_B0&0xFFFF);
+      break;
+    case PS2_C1_Reverb+26:
+      rvb[1].ACC_SRC_B0=(rvb[1].ACC_SRC_B0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+28:
+      rvb[1].ACC_SRC_B1=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_B1&0xFFFF);
+      break;
+    case PS2_C1_Reverb+30:
+      rvb[1].ACC_SRC_B1=(rvb[1].ACC_SRC_B1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+32:
+      rvb[1].IIR_SRC_A0=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_SRC_A0&0xFFFF);
+      break;
+    case PS2_C1_Reverb+34:
+      rvb[1].IIR_SRC_A0=(rvb[1].IIR_SRC_A0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+36:
+      rvb[1].IIR_SRC_A1=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_SRC_A1&0xFFFF);
+      break;
+    case PS2_C1_Reverb+38:
+      rvb[1].IIR_SRC_A1=(rvb[1].IIR_SRC_A1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+40:
+      rvb[1].IIR_DEST_B0=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_DEST_B0&0xFFFF);
+      break;
+    case PS2_C1_Reverb+42:
+      rvb[1].IIR_DEST_B0=(rvb[1].IIR_DEST_B0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+44:
+      rvb[1].IIR_DEST_B1=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_DEST_B1&0xFFFF);
+      break;
+    case PS2_C1_Reverb+46:
+      rvb[1].IIR_DEST_B1=(rvb[1].IIR_DEST_B1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+48:
+      rvb[1].ACC_SRC_C0=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_C0&0xFFFF);
+      break;
+    case PS2_C1_Reverb+50:
+      rvb[1].ACC_SRC_C0=(rvb[1].ACC_SRC_C0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+52:
+      rvb[1].ACC_SRC_C1=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_C1&0xFFFF);
+      break;
+    case PS2_C1_Reverb+54:
+      rvb[1].ACC_SRC_C1=(rvb[1].ACC_SRC_C1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+56:
+      rvb[1].ACC_SRC_D0=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_D0&0xFFFF);
+      break;
+    case PS2_C1_Reverb+58:
+      rvb[1].ACC_SRC_D0=(rvb[1].ACC_SRC_D0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+60:
+      rvb[1].ACC_SRC_D1=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_D1&0xFFFF);
+      break;
+    case PS2_C1_Reverb+62:
+      rvb[1].ACC_SRC_D1=(rvb[1].ACC_SRC_D1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+64:
+      rvb[1].IIR_SRC_B1=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_SRC_B1&0xFFFF);
+      break;
+    case PS2_C1_Reverb+66:
+      rvb[1].IIR_SRC_B1=(rvb[1].IIR_SRC_B1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+68:
+      rvb[1].IIR_SRC_B0=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_SRC_B0&0xFFFF);
+      break;
+    case PS2_C1_Reverb+70:
+      rvb[1].IIR_SRC_B0=(rvb[1].IIR_SRC_B0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+72:
+      rvb[1].MIX_DEST_A0=(((unsigned long)val&0xf)<<16)|(rvb[1].MIX_DEST_A0&0xFFFF);
+      break;
+    case PS2_C1_Reverb+74:
+      rvb[1].MIX_DEST_A0=(rvb[1].MIX_DEST_A0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+76:
+      rvb[1].MIX_DEST_A1=(((unsigned long)val&0xf)<<16)|(rvb[1].MIX_DEST_A1&0xFFFF);
+      break;
+    case PS2_C1_Reverb+78:
+      rvb[1].MIX_DEST_A1=(rvb[1].MIX_DEST_A1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+80:
+      rvb[1].MIX_DEST_B0=(((unsigned long)val&0xf)<<16)|(rvb[1].MIX_DEST_B0&0xFFFF);
+      break;
+    case PS2_C1_Reverb+82:
+      rvb[1].MIX_DEST_B0=(rvb[1].MIX_DEST_B0 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_Reverb+84:
+      rvb[1].MIX_DEST_B1=(((unsigned long)val&0xf)<<16)|(rvb[1].MIX_DEST_B1&0xFFFF);
+      break;
+    case PS2_C1_Reverb+86:
+      rvb[1].MIX_DEST_B1=(rvb[1].MIX_DEST_B1 & 0xF0000) | ((val) & 0xFFFF);
+      break;
+    case PS2_C1_ReverbX+0:  rvb[1].IIR_ALPHA=(short)val;      break;
+    case PS2_C1_ReverbX+2:  rvb[1].ACC_COEF_A=(short)val;     break;
+    case PS2_C1_ReverbX+4:  rvb[1].ACC_COEF_B=(short)val;     break;
+    case PS2_C1_ReverbX+6:  rvb[1].ACC_COEF_C=(short)val;     break;
+    case PS2_C1_ReverbX+8:  rvb[1].ACC_COEF_D=(short)val;     break;
+    case PS2_C1_ReverbX+10: rvb[1].IIR_COEF=(short)val;       break;
+    case PS2_C1_ReverbX+12: rvb[1].FB_ALPHA=(short)val;       break;
+    case PS2_C1_ReverbX+14: rvb[1].FB_X=(short)val;           break;
+    case PS2_C1_ReverbX+16: rvb[1].IN_COEF_L=(short)val;      break;
+    case PS2_C1_ReverbX+18: rvb[1].IN_COEF_R=(short)val;      break;
+   }
+
+ iSpuAsyncWait=0;
+
+}
+
+////////////////////////////////////////////////////////////////////////
+// READ REGISTER: called by main emu
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC unsigned short CALLBACK SPU2read(unsigned long reg)
+{
+ long r=reg&0xffff;
+
+#ifdef _WINDOWS
+ if(iDebugMode==1) logprintf("R_REG %X\r\n",reg&0xFFFF);
+#endif
+
+ iSpuAsyncWait=0;
+
+ if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580))  // some channel info?
+  {
+   switch(r&0x0f)
+    {
+     //------------------------------------------------// env value
+     case 10:                                           
+      {
+       int ch=(r>>4)&0x1f;
+       if(r>=0x400) ch+=24;
+       if(s_chan[ch].bNew) return 1;                   // we are started, but not processed? return 1
+       if(s_chan[ch].ADSRX.lVolume &&                  // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well
+          !s_chan[ch].ADSRX.EnvelopeVol)                   
+        return 1;
+       return (unsigned short)(s_chan[ch].ADSRX.EnvelopeVol>>16);
+      }break;
+    }
+  }
+
+ if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0))  // some channel info?
+  {
+   int ch=0;unsigned long rx=r;
+   if(rx>=0x400) {ch=24;rx-=0x400;}
+        
+   ch+=(rx-0x1c0)/12;
+   rx-=(ch%24)*12;
+   
+   switch(rx)
+    {
+     //------------------------------------------------//
+     case 0x1C4:
+      return (((s_chan[ch].pLoop-spuMemC)>>17)&0xF);
+      break;
+     case 0x1C6:
+      return (((s_chan[ch].pLoop-spuMemC)>>1)&0xFFFF);
+      break;
+     //------------------------------------------------//
+     case 0x1C8:
+      return (((s_chan[ch].pCurr-spuMemC)>>17)&0xF);
+      break;
+     case 0x1CA:
+      return (((s_chan[ch].pCurr-spuMemC)>>1)&0xFFFF);
+      break;
+     //------------------------------------------------//
+    }
+  }
+
+ switch(r)
+  {
+   //--------------------------------------------------//
+   case PS2_C0_SPUend1:
+     return (unsigned short)((dwEndChannel2[0]&0xFFFF));
+   case PS2_C0_SPUend2:
+     return (unsigned short)((dwEndChannel2[0]>>16));
+   //--------------------------------------------------//
+   case PS2_C1_SPUend1:
+     return (unsigned short)((dwEndChannel2[1]&0xFFFF));
+   case PS2_C1_SPUend2:
+     return (unsigned short)((dwEndChannel2[1]>>16));
+   //--------------------------------------------------//
+   case PS2_C0_ATTR:
+     return spuCtrl2[0];
+     break;
+   //--------------------------------------------------//
+   case PS2_C1_ATTR:
+     return spuCtrl2[1];
+     break;
+   //--------------------------------------------------//
+   case PS2_C0_SPUstat:
+     return spuStat2[0];
+     break;
+   //--------------------------------------------------//
+   case PS2_C1_SPUstat:
+     return spuStat2[1];
+     break;
+   //--------------------------------------------------//
+   case PS2_C0_SPUdata:
+     {
+      unsigned short s=spuMem[spuAddr2[0]];
+      spuAddr2[0]++;
+      if(spuAddr2[0]>0xfffff) spuAddr2[0]=0;
+      return s;
+     }
+   //--------------------------------------------------//
+   case PS2_C1_SPUdata:
+     {
+      unsigned short s=spuMem[spuAddr2[1]];
+      spuAddr2[1]++;
+      if(spuAddr2[1]>0xfffff) spuAddr2[1]=0;
+      return s;
+     }
+   //--------------------------------------------------//
+   case PS2_C0_SPUaddr_Hi:
+     return (unsigned short)((spuAddr2[0]>>16)&0xF);
+     break;
+   case PS2_C0_SPUaddr_Lo:
+     return (unsigned short)((spuAddr2[0]&0xFFFF));
+     break;
+   //--------------------------------------------------//
+   case PS2_C1_SPUaddr_Hi:
+     return (unsigned short)((spuAddr2[1]>>16)&0xF);
+     break;
+   case PS2_C1_SPUaddr_Lo:
+     return (unsigned short)((spuAddr2[1]&0xFFFF));
+     break;
+   //--------------------------------------------------//
+  }
+
+ return regArea[r>>1];
+}
+ 
+////////////////////////////////////////////////////////////////////////
+// SOUND ON register write
+////////////////////////////////////////////////////////////////////////
+
+void SoundOn(int start,int end,unsigned short val)     // SOUND ON PSX COMAND
+{
+ int ch;
+
+ for(ch=start;ch<end;ch++,val>>=1)                     // loop channels
+  {
+   if((val&1) && s_chan[ch].pStart)                    // mmm... start has to be set before key on !?!
+    {
+     s_chan[ch].bIgnoreLoop=0;
+     s_chan[ch].bNew=1;
+     dwNewChannel2[ch/24]|=(1<<(ch%24));               // bitfield for faster testing
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// SOUND OFF register write
+////////////////////////////////////////////////////////////////////////
+
+void SoundOff(int start,int end,unsigned short val)    // SOUND OFF PSX COMMAND
+{
+ int ch;
+ for(ch=start;ch<end;ch++,val>>=1)                     // loop channels
+  {
+   if(val&1)                                           // && s_chan[i].bOn)  mmm...
+    {
+     s_chan[ch].bStop=1;
+    }                                                  
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// FMOD register write
+////////////////////////////////////////////////////////////////////////
+
+void FModOn(int start,int end,unsigned short val)      // FMOD ON PSX COMMAND
+{
+ int ch;
+
+ for(ch=start;ch<end;ch++,val>>=1)                     // loop channels
+  {
+   if(val&1)                                           // -> fmod on/off
+    {
+     if(ch>0) 
+      {
+       s_chan[ch].bFMod=1;                             // --> sound channel
+       s_chan[ch-1].bFMod=2;                           // --> freq channel
+      }
+    }
+   else
+    {
+     s_chan[ch].bFMod=0;                               // --> turn off fmod
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// NOISE register write
+////////////////////////////////////////////////////////////////////////
+
+void NoiseOn(int start,int end,unsigned short val)     // NOISE ON PSX COMMAND
+{
+ int ch;
+
+ for(ch=start;ch<end;ch++,val>>=1)                     // loop channels
+  {
+   if(val&1)                                           // -> noise on/off
+    {
+     s_chan[ch].bNoise=1;
+    }
+   else 
+    {
+     s_chan[ch].bNoise=0;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// LEFT VOLUME register write
+////////////////////////////////////////////////////////////////////////
+
+// please note: sweep and phase invert are wrong... but I've never seen
+// them used
+
+void SetVolumeL(unsigned char ch,short vol)            // LEFT VOLUME
+{
+ s_chan[ch].iLeftVolRaw=vol;
+
+ if(vol&0x8000)                                        // sweep?
+  {
+   short sInc=1;                                       // -> sweep up?
+   if(vol&0x2000) sInc=-1;                             // -> or down?
+   if(vol&0x1000) vol^=0xffff;                         // -> mmm... phase inverted? have to investigate this
+   vol=((vol&0x7f)+1)/2;                               // -> sweep: 0..127 -> 0..64
+   vol+=vol/(2*sInc);                                  // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half!
+   vol*=128;
+  }
+ else                                                  // no sweep:
+  {
+   if(vol&0x4000)                                      // -> mmm... phase inverted? have to investigate this
+    //vol^=0xffff;
+    vol=0x3fff-(vol&0x3fff);
+  }
+
+ vol&=0x3fff;
+ s_chan[ch].iLeftVolume=vol;                           // store volume
+}
+
+////////////////////////////////////////////////////////////////////////
+// RIGHT VOLUME register write
+////////////////////////////////////////////////////////////////////////
+
+void SetVolumeR(unsigned char ch,short vol)            // RIGHT VOLUME
+{
+ s_chan[ch].iRightVolRaw=vol;
+
+ if(vol&0x8000)                                        // comments... see above :)
+  {
+   short sInc=1;
+   if(vol&0x2000) sInc=-1;
+   if(vol&0x1000) vol^=0xffff;
+   vol=((vol&0x7f)+1)/2;        
+   vol+=vol/(2*sInc);
+   vol*=128;
+  }
+ else            
+  {
+   if(vol&0x4000) //vol=vol^=0xffff;
+    vol=0x3fff-(vol&0x3fff);
+  }
+
+ vol&=0x3fff;
+
+ s_chan[ch].iRightVolume=vol;
+}
+
+////////////////////////////////////////////////////////////////////////
+// PITCH register write
+////////////////////////////////////////////////////////////////////////
+
+void SetPitch(int ch,unsigned short val)               // SET PITCH
+{
+ int NP;
+ if(val>0x3fff) NP=0x3fff;                             // get pitch val
+ else           NP=val;
+
+ s_chan[ch].iRawPitch=NP;
+
+ NP=(44100L*NP)/4096L;                                 // calc frequency
+ if(NP<1) NP=1;                                        // some security
+ s_chan[ch].iActFreq=NP;                               // store frequency
+}
+
+////////////////////////////////////////////////////////////////////////
+// REVERB register write
+////////////////////////////////////////////////////////////////////////
+
+void ReverbOn(int start,int end,unsigned short val,int iRight)  // REVERB ON PSX COMMAND
+{
+ int ch;
+
+ for(ch=start;ch<end;ch++,val>>=1)                     // loop channels
+  {
+   if(val&1)                                           // -> reverb on/off
+    {
+     if(iRight) s_chan[ch].bReverbR=1;
+     else       s_chan[ch].bReverbL=1;
+    }
+   else 
+    {
+     if(iRight) s_chan[ch].bReverbR=0;
+     else       s_chan[ch].bReverbL=0;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// REVERB START register write
+////////////////////////////////////////////////////////////////////////
+
+void SetReverbAddr(int core)
+{
+ long val=spuRvbAddr2[core];
+ 
+ if(rvb[core].StartAddr!=val)
+  {
+   if(val<=0x27ff)
+    {
+     rvb[core].StartAddr=rvb[core].CurrAddr=0;
+    }
+   else
+    {
+     rvb[core].StartAddr=val;
+     rvb[core].CurrAddr=rvb[core].StartAddr;
+    } 
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// DRY LEFT/RIGHT per voice switches
+////////////////////////////////////////////////////////////////////////
+
+void VolumeOn(int start,int end,unsigned short val,int iRight)  // VOLUME ON PSX COMMAND
+{
+ int ch;
+
+ for(ch=start;ch<end;ch++,val>>=1)                     // loop channels
+  {
+   if(val&1)                                           // -> reverb on/off
+    {
+     if(iRight) s_chan[ch].bVolumeR=1;
+     else       s_chan[ch].bVolumeL=1;
+    }
+   else 
+    {
+     if(iRight) s_chan[ch].bVolumeR=0;
+     else       s_chan[ch].bVolumeL=0;
+    }
+  }
+}
+
+
--- a/Plugins/Input/sexypsf/spu/registers.h	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/registers.h	Sun Mar 19 12:51:03 2006 -0800
@@ -1,9 +1,5 @@
 /***************************************************************************
                          registers.h  -  description
-                             -------------------
-    begin                : Wed May 15 2002
-    copyright            : (C) 2002 by Pete Bernert
-    email                : BlackDove@addcom.de
  ***************************************************************************/
 
 /***************************************************************************
@@ -19,11 +15,661 @@
 //*************************************************************************//
 // History of changes:
 //
-// 2002/05/15 - Pete
-// - generic cleanup for the Peops release
+// 2004/04/04 - Pete
+// - generic cleanup for the Peops release... register values by Kanodin &
+//   his team
 //
 //*************************************************************************//
 
+//###########################################################################
+
+#define PS2_C0_SPUaddr_Hi    (0x000 + 0x1A8)
+#define PS2_C0_SPUaddr_Lo    (0x000 + 0x1AA)
+#define PS2_C1_SPUaddr_Hi    (0x400 + 0x1A8)
+#define PS2_C1_SPUaddr_Lo    (0x400 + 0x1AA)
+#define PS2_C0_SPUdata       (0x000 + 0x1AC)
+#define PS2_C1_SPUdata       (0x400 + 0x1AC)
+
+#define PS2_C0_SPUDMActrl    (0x000 + 0x1AE)
+#define PS2_C1_SPUDMActrl    (0x400 + 0x1AE)
+
+#define PS2_C0_SPUstat       (0x000 + 0x344)
+#define PS2_C1_SPUstat       (0x400 + 0x344)
+#define PS2_C0_ReverbAddr_Hi (0x000 + 0x2E0)
+#define PS2_C0_ReverbAddr_Lo (0x000 + 0x2E2)
+#define PS2_C1_ReverbAddr_Hi (0x400 + 0x2E0)
+#define PS2_C1_ReverbAddr_Lo (0x400 + 0x2E2)
+
+#define PS2_C0_ReverbAEnd_Hi (0x000 + 0x33C)
+#define PS2_C0_ReverbAEnd_Lo (0x000 + 0x33E)
+#define PS2_C1_ReverbAEnd_Hi (0x400 + 0x33C)
+#define PS2_C1_ReverbAEnd_Lo (0x400 + 0x33E)
+
+#define PS2_C0_DryL1         (0x000 + 0x188)
+#define PS2_C1_DryL1         (0x400 + 0x188)
+#define PS2_C0_DryL2         (0x000 + 0x18A)
+#define PS2_C1_DryL2         (0x400 + 0x18A)
+
+#define PS2_C0_DryR1         (0x000 + 0x190)
+#define PS2_C1_DryR1         (0x400 + 0x190)
+#define PS2_C0_DryR2         (0x000 + 0x192)
+#define PS2_C1_DryR2         (0x400 + 0x192)
+
+#define PS2_C0_ATTR          (0x000 + 0x19A)
+#define PS2_C1_ATTR          (0x400 + 0x19A)
+#define PS2_C0_ADMAS         (0x000 + 0x1B0)
+#define PS2_C1_ADMAS         (0x400 + 0x1B0)
+
+#define PS2_C0_SPUirqAddr_Hi (0x000 + 0x19C)
+#define PS2_C0_SPUirqAddr_Lo (0x000 + 0x19D)
+#define PS2_C1_SPUirqAddr_Hi (0x400 + 0x19C)
+#define PS2_C1_SPUirqAddr_Lo (0x400 + 0x19D)
+#define PS2_C0_SPUrvolL      (0x000 + 0x764)
+#define PS2_C0_SPUrvolR      (0x000 + 0x766)
+#define PS2_C1_SPUrvolL      (0x028 + 0x764)
+#define PS2_C1_SPUrvolR      (0x028 + 0x766)
+#define PS2_C0_SPUon1        (0x000 + 0x1A0)
+#define PS2_C0_SPUon2        (0x000 + 0x1A2)
+#define PS2_C1_SPUon1        (0x400 + 0x1A0)
+#define PS2_C1_SPUon2        (0x400 + 0x1A2)
+#define PS2_C0_SPUoff1       (0x000 + 0x1A4)
+#define PS2_C0_SPUoff2       (0x000 + 0x1A6)
+#define PS2_C1_SPUoff1       (0x400 + 0x1A4)
+#define PS2_C1_SPUoff2       (0x400 + 0x1A6)
+#define PS2_C0_FMod1         (0x000 + 0x180)
+#define PS2_C0_FMod2         (0x000 + 0x182)
+#define PS2_C1_FMod1         (0x400 + 0x180)
+#define PS2_C1_FMod2         (0x400 + 0x182)
+#define PS2_C0_Noise1        (0x000 + 0x184)
+#define PS2_C0_Noise2        (0x000 + 0x186)
+#define PS2_C1_Noise1        (0x400 + 0x184)
+#define PS2_C1_Noise2        (0x400 + 0x186)
+
+#define PS2_C0_RVBon1_L      (0x000 + 0x18C)
+#define PS2_C0_RVBon2_L      (0x000 + 0x18E)
+#define PS2_C0_RVBon1_R      (0x000 + 0x194)
+#define PS2_C0_RVBon2_R      (0x000 + 0x196)
+
+#define PS2_C1_RVBon1_L      (0x400 + 0x18C)
+#define PS2_C1_RVBon2_L      (0x400 + 0x18E)
+#define PS2_C1_RVBon1_R      (0x400 + 0x194)
+#define PS2_C1_RVBon2_R      (0x400 + 0x196)
+#define PS2_C0_Reverb        (0x000 + 0x2E4)
+#define PS2_C1_Reverb        (0x400 + 0x2E4)
+#define PS2_C0_ReverbX       (0x000 + 0x774)
+#define PS2_C1_ReverbX       (0x028 + 0x774)
+#define PS2_C0_SPUend1       (0x000 + 0x340)
+#define PS2_C0_SPUend2       (0x000 + 0x342)
+#define PS2_C1_SPUend1       (0x400 + 0x340)
+#define PS2_C1_SPUend2       (0x400 + 0x342)
+
+
+
+//###########################################################################
+
+/*
+ Included the info received in Regs.txt list by Neill Corlett - Kanodin
+
+ Voice parameters:
+ SD_VP_VOLL, SD_VP_VOLR   - Volume left/right per voice.  Assuming identical to PS1.
+ SD_VP_PITCH              - Pitch scaler 0000-3FFF. Assuming identical to PS1.
+ SD_VP_ADSR1, SD_VP_ADSR1 - Envelope data. Bitfields are documented as identical to PS1.
+ SD_VP_ENVX               - Current envelope value. Assuming identical to PS1.
+ SD_VP_VOLXL, SD_VP_VOLXR - Current voice volume left/right. Does not exist on the PS1.
+                            Guessing that this is handy for the increase/decrease modes.
+
+ Voice addresses:
+
+ SD_VA_SSA                - Sample start address; assuming identical to PS1
+ SD_VA_LSAX               - Loop start address; assuming identical to PS1
+ SD_VA_NAX                - Seems to be documented as the current playing address.
+                            Does not exist on PS1.
+
+ Switches:
+
+ SD_S_PMON                - Pitch mod; assuming identical to PS1
+ SD_S_NON                 - Noise; assuming identical to PS1
+ SD_S_VMIXL, SD_S_VMIXR   - Voice mix L/R. Guessing this is just a separate L/R version 
+                            of the "voice enable" bits on the PS1.
+ SD_S_VMIXEL, SD_S_VMIXER - Voice effect mix L/R. Guessing this is just a separate L/R
+                            version of the "voice reverb enable" bits on the PS1.
+ SD_S_KON, SD_S_KOFF      - Key on/off; assuming identical to PS1
+
+
+ Addresses:
+
+ SD_A_TSA                 - Transfer start address; assuming identical to PS1
+ SD_A_ESA                 - Effect start address - this is probably analogous to the
+                            PS1's reverb work area start address
+ SD_A_EEA                 - Effect end address - this would've been fixed to 0x7FFFF on
+                            the PS1; settable in 128K increments on the PS2.
+ SD_A_IRQA                - IRQ address; assuming identical to PS1
+
+ Volume parameters:
+
+ SD_P_MVOLL, SD_P_MVOLR   - Master volume L/R; assuming identical to PS1
+ SD_P_EVOLL, SD_P_EVOLR   - Effect volume L/R; assuming analogous to RVOL on the PS1
+ SD_P_AVOLL, SD_P_AVOLR   - External input volume L/R
+                            This is probably where CORE0 connects to CORE1
+ SD_P_BVOLL, SD_P_BVOLR   - Sound data input volume - perhaps this is the volume of
+                            the raw PCM auto-DMA input? analogous to CD input volume?
+ SD_P_MVOLXL, SD_P_MVOLXR - Current master volume L/R; seems self-explanatory
+
+ SD_P_MMIX                - Mixer / effect enable bits.
+                             bit 11 = MSNDL  = voice output dry L
+                                 10 = MSNDR  = voice output dry R
+                                  9 = MSNDEL = voice output wet L
+                                  8 = MSNDER = voice output wet R
+                                  7 = MINL   = sound data input dry L
+                                  6 = MINR   = sound data input dry R
+                                  5 = MINEL  = sound data input wet L
+                                  4 = MINER  = sound data input wet R
+                                  3 = SINL   = core external input dry L
+                                  2 = SINR   = core external input dry R
+                                  1 = SINEL  = core external input wet L
+                                  0 = SINER  = core external input wet R
+
+Core attributes (SD_C)
+
+    bit 4..5      - DMA related
+    bit 6         - IRQ enable
+    bit 7         - effect enable (reverb enable)
+    bit 13..8     - noise clock
+    bit 14        - mute
+
+ - if you READ the two DMA related bits, if either are set, the channel is
+   considered "busy" by sceSdVoiceTrans
+
+
+
+Reverb parameters:
+
+  Same as PS1 reverb (I used the names from my reverb doc).
+
+
+Other PS2 IOP notes
+
+ There's two DMA controllers:
+ The original one at 1F801080-1F8010FF (channels 0-6)
+ A new one at        1F801500-1F80157F (channels 7-13)
+
+ They appear to function the same way - 7 channels each.
+
+ SPU CORE0's DMA channel is 4 as per usual
+ SPU CORE1's DMA channel is 7
+
+DMA channel 10 is SIF
+ 
+ Original INTR controller at 1F801000-1F80107F
+
+ All interrupt handling seems to be done using the old INTR, but
+ with some new bits defined:
+
+
+
+ Reading from 1F801078 masks interrupts and returns 1 if they weren't
+ masked before.  Writing 1 to 1F801078 re-enables interrupts.
+ Writing 0 doesn't.  Maybe it was like that on the original PS1 too.
+
+Six root counters:
+
+ RTC#   address      sources           size     prescale     interrupt#
+0      0x1F801100   sysclock,pixel    16 bit   1 only       4
+1      0x1F801110   sysclock,hline    16 bit   1 only       5
+2      0x1F801120   sysclock          16 bit   1,8          6
+3      0x1F801480   sysclock,hline    32 bit   1 only       14
+4      0x1F801490   sysclock          32 bit   1,8,16,256   15
+5      0x1F8014A0   sysclock          32 bit   1,8,16,256   16
+
+Count (0x0) and Compare (0x8) registers work as before, only with more bits
+in the new counters.
+
+Mode (0x4) works like this when written:
+
+  bits 0..2    gate
+  bit  3       reset on target
+  bit  4       target interrupt enable
+  bit  5       overflow interrupt enable
+  bit  6       master enable (?)
+  bit  7       ?
+  bit  8       clock select
+  bit  9       prescale (OLD)
+  bit  10..12  ?
+  bit  13..14  prescale (NEW)
+  bit  15      ? always set to 1
+
+Gate:
+   TM_NO_GATE                   000
+   TM_GATE_ON_Count             001
+   TM_GATE_ON_ClearStart        011
+   TM_GATE_ON_Clear_OFF_Start   101
+   TM_GATE_ON_Start             111
+
+   V-blank  ----+    +----------------------------+    +------
+                |    |                            |    |
+                |    |                            |    |
+                +----+                            +----+
+ TM_NO_GATE:
+
+                0================================>============
+
+ TM_GATE_ON_Count:
+
+                <---->0==========================><---->0=====
+
+ TM_GATE_ON_ClearStart:
+
+                0====>0================================>0=====
+
+ TM_GATE_ON_Clear_OFF_Start:
+
+                0====><-------------------------->0====><-----
+
+ TM_GATE_ON_Start:
+
+                <---->0==========================>============
+
+  reset on target: if set, counter resets to 0 when Compare value is reached
+
+  target interrupt enable: if set, interrupt when Compare value is reached
+  overflow interrupt enable: if set, interrupt when counter overflows
+
+  master enable: if this bit is clear, the timer should do nothing.
+
+  clock select: for counters 0, 1, and 3, setting this will select the alternate
+  counter (pixel or hline)
+
+  prescale (OLD): for counter 2 only. set this to prescale (divide) by 8.
+
+  prescale (NEW): for counters 4 and 5 only:
+
+  00 = prescale by 1
+  01 = prescale by 8
+  10 = prescale by 16
+  11 = prescale by 256
+
+Writing 0x4 also clears the counter. (I think.)
+
+When 0x4 is read, it becomes Status:
+
+  bit  0..10   ?
+  bit  11      compare value was reached
+  bit  12      count overflowed
+  bit  13..15  ?
+
+Reading probably clears these bits.
+
+
+
+ 1F8014B0 (word) - timer-related but otherwise unknown
+ 1F8014C0 (word) - timer-related but otherwise unknown
+
+
+ don't currently know how the interrupts work for DMA ch7 yet
+
+ 1F801060 (word) - address of some kind.
+
+ 1F801450 (word) -
+    if bit 3 is SET, we're in PS1 mode.
+    if bit 3 is CLEAR, we're in PS2 IOP mode.
+
+ 1F802070 (byte) - unknown. status byte of some kind? visible to EE?
+
+ 1D000000-1D00007F (?) - SIF related
+
+ 1D000020 (word) - read counter of some sort?
+                   sceSifInit waits for bit 0x10000 of this to be set.
+ 1D000030 (word) - read counter of some sort?
+ 1D000040 (word) - read bits 0x20, 0x40 mean something
+ 1D000060 (word) - used to detect whether the SIF interface exists
+                   read must be 0x1D000060, or the top 20 bits must be zero 
+*/
+
+/*
+
+// DirectX Audio SPU2 Driver for PCSX2
+// audio.c by J.F. and Kanodin (hooper1@cox.net)
+//
+// Copyright 2003 J.F. and Kanodin, and distributed under the
+// terms of the GNU General Public License, v2 or later.
+// http://www.gnu.org/copyleft/gpl.html.
+
+Included these just in case you need them J.F. - Kanodin
+
+// Core Start Addresses
+#define CORE0 0x1f900000
+#define CORE1 0x1f900400
+
+
+   #define IOP_INT_VBLANK  (1<<0)
+   #define IOP_INT_GM      (1<<1)
+   #define IOP_INT_CDROM   (1<<2)
+   #define IOP_INT_DMA     (1<<3)
+   #define IOP_INT_RTC0    (1<<4)
+   #define IOP_INT_RTC1    (1<<5)
+   #define IOP_INT_RTC2    (1<<6)
+   #define IOP_INT_SIO0    (1<<7)
+   #define IOP_INT_SIO1    (1<<8)
+   #define IOP_INT_SPU     (1<<9)
+   #define IOP_INT_PIO     (1<<10)
+   #define IOP_INT_EVBLANK (1<<11)
+   #define IOP_INT_DVD     (1<<12)
+   #define IOP_INT_PCMCIA  (1<<13)
+   #define IOP_INT_RTC3    (1<<14)
+   #define IOP_INT_RTC4    (1<<15)
+   #define IOP_INT_RTC5    (1<<16)
+   #define IOP_INT_SIO2    (1<<17)
+   #define IOP_INT_HTR0    (1<<18)
+   #define IOP_INT_HTR1    (1<<19)
+   #define IOP_INT_HTR2    (1<<20)
+   #define IOP_INT_HTR3    (1<<21)
+   #define IOP_INT_USB     (1<<22)
+   #define IOP_INT_EXTR    (1<<23)
+   #define IOP_INT_FWRE    (1<<24)
+   #define IOP_INT_FDMA    (1<<25)    
+
+// CORE0 => +0x000, CORE1 => +0x400
+
+// individual voice parameter regs
+
+#define VP_VOLL(cr, vc)  (0x400 * cr + 0x000 + (vc << 4))    // voice volume (left)
+#define VP_VOLR(cr, vc)  (0x400 * cr + 0x002 + (vc << 4))    // voice volume (right)
+#define VP_PITCH(cr, vc) (0x400 * cr + 0x004 + (vc << 4))    // voice pitch
+#define VP_ADSR1(cr, vc) (0x400 * cr + 0x006 + (vc << 4))    // voice envelope (AR, DR, SL)
+#define VP_ADSR2(cr, vc) (0x400 * cr + 0x008 + (vc << 4))    // voice envelope (SR, RR)
+#define VP_ENVX(cr, vc)  (0x400 * cr + 0x00A + (vc << 4))    // voice envelope (current value)
+#define VP_VOLXL(cr, vc) (0x400 * cr + 0x00C + (vc << 4))    // voice volume (current value left)
+#define VP_VOLXR(cr, vc) (0x400 * cr + 0x00E + (vc << 4))    // voice volume (current value right)
+
+#define VA_SSA(cr, vc)   (0x400 * cr + 0x1C0 + (vc * 12))    // voice waveform data start address
+#define VA_LSAX(cr, vc)  (0x400 * cr + 0x1C4 + (vc * 12))    // voice waveform data loop address
+#define VA_NAX(cr, vc)   (0x400 * cr + 0x1C8 + (vc * 12))    // voice waveform data next address
+
+// common settings
+
+#define S_PMON(cr)       (0x400 * cr + 0x180)                // pitch modulation on
+#define S_NON(cr)        (0x400 * cr + 0x184)                // noise generator on
+#define S_VMIXL(cr)      (0x400 * cr + 0x188)                // voice output mixing (dry left)
+#define S_VMIXEL(cr)     (0x400 * cr + 0x18C)                // voice output mixing (wet left)
+#define S_VMIXR(cr)      (0x400 * cr + 0x190)                // voice output mixing (dry right)
+#define S_VMIXER(cr)     (0x400 * cr + 0x194)                // voice output mixing (wet right)
+#define P_MMIX(cr)       (0x400 * cr + 0x198)                // output type after voice mixing (See paragraph below)
+#define P_ATTR(cr)       (0x400 * cr + 0x19A)                // core attributes (See paragraph below)
+#define A_IRQA(cr)       (0x400 * cr + 0x19C)                // IRQ address 
+#define S_KON(cr)        (0x400 * cr + 0x1A0)                // key on (start voice sound generation)
+#define S_KOFF(cr)       (0x400 * cr + 0x1A4)                // key off (end voice sound generation)
+#define A_TSA(cr)        (0x400 * cr + 0x1A8)                // DMA transfer start address
+#define P_DATA(cr)       (0x400 * cr + 0x1AC)                // DMA data register
+#define P_CTRL(cr)       (0x400 * cr + 0x1AE)                // DMA control register
+#define P_ADMAS(cr)      (0x400 * cr + 0x1B0)                // AutoDMA status
+
+#define A_ESA(cr)        (0x400 * cr + 0x2E0)                // effects work area start address
+
+#define FB_SRC_A(cr)     (0x400 * cr + 0x2E4)      
+#define FB_SRC_B(cr)     (0x400 * cr + 0x2E8)      
+#define IIR_DEST_A0(cr)  (0x400 * cr + 0x2EC)      
+#define IIR_DEST_A1(cr)  (0x400 * cr + 0x2F0)      
+#define ACC_SRC_A0(cr)   (0x400 * cr + 0x2F4)     
+#define ACC_SRC_A1(cr)   (0x400 * cr + 0x2F8)
+#define ACC_SRC_B0(cr)   (0x400 * cr + 0x2FC)  
+
+#define ACC_SRC_B1(cr)   (0x400 * cr + 0x300)      
+#define IIR_SRC_A0(cr)   (0x400 * cr + 0x304)      
+#define IIR_SRC_A1(cr)   (0x400 * cr + 0x308)      
+#define IIR_DEST_B0(cr)  (0x400 * cr + 0x30C)      
+#define IIR_DEST_B1(cr)  (0x400 * cr + 0x310)      
+#define ACC_SRC_C0(cr)   (0x400 * cr + 0x314)      
+#define ACC_SRC_C1(cr)   (0x400 * cr + 0x318)  
+
+#define ACC_SRC_D0(cr)   (0x400 * cr + 0x31C)      
+#define ACC_SRC_D1(cr)   (0x400 * cr + 0x320)      
+#define IIR_SRC_B1(cr)   (0x400 * cr + 0x324)      
+#define IIR_SRC_B0(cr)   (0x400 * cr + 0x328)      
+#define MIX_DEST_A0(cr)  (0x400 * cr + 0x32C)      
+#define MIX_DEST_A1(cr)  (0x400 * cr + 0x330)      
+#define MIX_DEST_B0(cr)  (0x400 * cr + 0x334)      
+#define MIX_DEST_B1(cr)  (0x400 * cr + 0x338)      
+
+#define A_EEA(cr)        (0x400 * cr + 0x33C)                // effects work area end address
+
+#define P_ENDX(cr)       (0x400 * cr + 0x340)                // voice loop end status
+#define P_STAT(cr)       (0x400 * cr + 0x344)                // DMA status register
+#define P_ENDS(cr)       (0x400 * cr + 0x346)                // ?
+
+// CORE0 => +0x400, CORE1 => +0x428
+
+#define P_MVOLL(cr)      (0x28 * cr + 0x760)                 // master volume (left)
+#define P_MVOLR(cr)      (0x28 * cr + 0x762)                 // master volume (right)
+#define P_EVOLL(cr)      (0x28 * cr + 0x764)                 // effect return volume (left)
+#define P_EVOLR(cr)      (0x28 * cr + 0x766)                 // effect return volume (right)
+#define P_AVOLL(cr)      (0x28 * cr + 0x768)                 // core external input volume (left)
+#define P_AVOLR(cr)      (0x28 * cr + 0x76A)                 // core external input volume (right)
+#define P_BVOLL(cr)      (0x28 * cr + 0x76C)                 // sound data input volume (left)
+#define P_BVOLR(cr)      (0x28 * cr + 0x76E)                 // sound data input volume (right)
+#define P_MVOLXL(cr)     (0x28 * cr + 0x770)                 // current master volume (left)
+#define P_MVOLXR(cr)     (0x28 * cr + 0x772)                 // current master volume (right)
+
+#define IIR_ALPHA(cr)    (0x28 * cr + 0x774)      
+#define ACC_COEF_A(cr)   (0x28 * cr + 0x776)      
+#define ACC_COEF_B(cr)   (0x28 * cr + 0x778)      
+#define ACC_COEF_C(cr)   (0x28 * cr + 0x77A)      
+#define ACC_COEF_D(cr)   (0x28 * cr + 0x77C)      
+#define IIR_COEF(cr)     (0x28 * cr + 0x77E)      
+#define FB_ALPHA(cr)     (0x28 * cr + 0x780)      
+#define FB_X(cr)         (0x28 * cr + 0x782)      
+#define IN_COEF_L(cr)    (0x28 * cr + 0x784)      
+#define IN_COEF_R(cr)    (0x28 * cr + 0x786)      
+
+// CORE1 only => +0x400
+
+#define SPDIF_OUT        0x7C0                               // SPDIF Out: OFF/'PCM'/Bitstream/Bypass 
+#define SPDIF_MODE       0x7C6
+#define SPDIF_MEDIA      0x7C8                               // SPDIF Media: 'CD'/DVD	
+#define SPDIF_COPY       0x7CA                               // SPDIF Copy Protection
+
+// PS1 SPU CORE
+
+// individual voice settings
+
+#define SPU_VP_PITCH(vc) (0xC04 + (vc << 4))                 // voice pitch
+#define SPU_VA_SSA(vc)   (0xC06 + (vc << 4))                 // voice waveform data start address
+#define SPU_VP_ADSR(vc)  (0xC08 + (vc << 4))                 // voice envelope
+#define SPU_VA_SSA(vc)   (0xC0E + (vc << 4))                 // voice waveform data loop address
+
+// common settings
+
+#define SPU_P_MVOLL      0xD80                               // master volume (left)
+#define SPU_P_MVOLR      0xD82                               // master volume (right)
+#define SPU_P_RVOLL      0xD84                               // effect return volume (left)
+#define SPU_P_RVOLR      0xD86                               // effect return volume (right)
+#define SPU_S_KON1       0xD88                               // key on
+#define SPU_S_KON2       0xD8A                               // 
+#define SPU_S_KOFF1      0xD8C                               // key off
+#define SPU_S_KOFF2      0xD8E                               // 
+#define SPU_S_PMON1      0xD90                               // pitch modulation on
+#define SPU_S_PMON2      0xD92                               // 
+#define SPU_S_NON1       0xD94                               // noise generator on
+#define SPU_S_NON2       0xD96                               // 
+#define SPU_S_RVBON1     0xD98                               // effects on
+#define SPU_S_RVBON2     0xD9A                               // 
+#define SPU_S_MUTE1      0xD9C                               // voice mute
+#define SPU_S_MUTE2      0xD9E                               // 
+
+#define SPU_A_ESA        0xDA2                               // effects work area start
+#define SPU_A_IRQA       0xDA4                               // IRQ address
+#define SPU_A_TSA        0xDA6                               // DMA transfer start address
+#define SPU_P_DATA       0xDA8                               // DMA data register
+#define SPU_P_CTRL       0xDAA                               // DMA control register
+#define SPU_P_STAT       0xDAE                               // DMA status register
+
+#define SPU_P_CDL        0xDB0                               // sound data input volume (left)
+#define SPU_P_CDR        0xDB2                               // sound data input volume (right)
+#define SPU_P_EXTL       0xDB4                               // external input volume (left)
+#define SPU_P_EXTR       0xDB6                               // external input volume (right)
+
+#define SPU_P_REVERB     0xDC0                               // effects control
+
+
+// Individual voice parameter regs CORE 0
+// Only
+
+
+#define VP_VOLL(cr, vc)  (0x400 * cr + 0x000 + (vc << 4))    // voice volume (left)
+#define VP_VOLR(cr, vc)  (0x400 * cr + 0x002 + (vc << 4))    // voice volume (right)
+#define VP_PITCH(cr, vc) (0x400 * cr + 0x004 + (vc << 4))    // voice pitch
+#define VP_ADSR1(cr, vc) (0x400 * cr + 0x006 + (vc << 4))    // voice envelope (AR, DR, SL)
+#define VP_ADSR2(cr, vc) (0x400 * cr + 0x008 + (vc << 4))    // voice envelope (SR, RR)
+#define VP_ENVX(cr, vc)  (0x400 * cr + 0x00A + (vc << 4))    // voice envelope (current value)
+#define VP_VOLXL(cr, vc) (0x400 * cr + 0x00C + (vc << 4))    // voice volume (current value left)
+#define VP_VOLXR(cr, vc) (0x400 * cr + 0x00E + (vc << 4))    // voice volume (current value right)
+
+#define VA_SSA(cr, vc)   (0x400 * cr + 0x1C0 + (vc * 12))    // voice waveform data start address
+#define VA_LSAX(cr, vc)  (0x400 * cr + 0x1C4 + (vc * 12))    // voice waveform data loop address
+#define VA_NAX(cr, vc)   (0x400 * cr + 0x1C8 + (vc * 12))    // voice waveform data next address
+
+
+// CORE 0 Common Settings
+
+
+#define S_PMON(cr)       (0x400 * cr + 0x180)                // pitch modulation on
+#define S_NON(cr)        (0x400 * cr + 0x184)                // noise generator on
+#define S_VMIXL(cr)      (0x400 * cr + 0x188)                // voice output mixing (dry left)
+#define S_VMIXEL(cr)     (0x400 * cr + 0x18C)                // voice output mixing (wet left)
+#define S_VMIXR(cr)      (0x400 * cr + 0x190)                // voice output mixing (dry right)
+#define S_VMIXER(cr)     (0x400 * cr + 0x194)                // voice output mixing (wet right)
+#define P_MMIX(cr)       (0x400 * cr + 0x198)                // output type after voice mixing (See paragraph below)
+#define P_ATTR(cr)       (0x400 * cr + 0x19A)                // core attributes (See paragraph below)
+#define A_IRQA(cr)       (0x400 * cr + 0x19C)                // IRQ address 
+#define S_KON(cr)        (0x400 * cr + 0x1A0)                // key on (start voice sound generation)
+#define S_KOFF(cr)       (0x400 * cr + 0x1A4)                // key off (end voice sound generation)
+#define A_TSA(cr)        (0x400 * cr + 0x1A8)                // DMA transfer start address
+#define P_DATA(cr)       (0x400 * cr + 0x1AC)                // DMA data register
+#define P_CTRL(cr)       (0x400 * cr + 0x1AE)                // DMA control register
+#define P_ADMAS(cr)      (0x400 * cr + 0x1B0)                // AutoDMA status
+
+#define A_ESA(cr)        (0x400 * cr + 0x2E0)                // effects work area start address
+
+
+// Core 0 Reverb Addresses
+
+
+#define FB_SRC_A(cr)     (0x400 * cr + 0x2E4)      
+#define FB_SRC_B(cr)     (0x400 * cr + 0x2E8)      
+#define IIR_DEST_A0(cr)  (0x400 * cr + 0x2EC)      
+#define IIR_DEST_A1(cr)  (0x400 * cr + 0x2F0)      
+#define ACC_SRC_A0(cr)   (0x400 * cr + 0x2F4)     
+#define ACC_SRC_A1(cr)   (0x400 * cr + 0x2F8)
+#define ACC_SRC_B0(cr)   (0x400 * cr + 0x2FC)  
+
+#define ACC_SRC_B1(cr)   (0x400 * cr + 0x300)      
+#define IIR_SRC_A0(cr)   (0x400 * cr + 0x304)      
+#define IIR_SRC_A1(cr)   (0x400 * cr + 0x308)      
+#define IIR_DEST_B0(cr)  (0x400 * cr + 0x30C)      
+#define IIR_DEST_B1(cr)  (0x400 * cr + 0x310)      
+#define ACC_SRC_C0(cr)   (0x400 * cr + 0x314)      
+#define ACC_SRC_C1(cr)   (0x400 * cr + 0x318)  
+
+#define ACC_SRC_D0(cr)   (0x400 * cr + 0x31C)      
+#define ACC_SRC_D1(cr)   (0x400 * cr + 0x320)      
+#define IIR_SRC_B1(cr)   (0x400 * cr + 0x324)      
+#define IIR_SRC_B0(cr)   (0x400 * cr + 0x328)      
+#define MIX_DEST_A0(cr)  (0x400 * cr + 0x32C)      
+#define MIX_DEST_A1(cr)  (0x400 * cr + 0x330)      
+#define MIX_DEST_B0(cr)  (0x400 * cr + 0x334)      
+#define MIX_DEST_B1(cr)  (0x400 * cr + 0x338)      
+
+#define A_EEA(cr)        (0x400 * cr + 0x33C)                // effects work area end address
+
+#define P_ENDX(cr)       (0x400 * cr + 0x340)                // voice loop end status
+#define P_STAT(cr)       (0x400 * cr + 0x344)                // DMA status register
+#define P_ENDS(cr)       (0x400 * cr + 0x346)                // ?
+
+
+// CORE 0 Specific
+
+
+#define P_MVOLL(cr)      (0x28 * cr + 0x760)                 // master volume (left)
+#define P_MVOLR(cr)      (0x28 * cr + 0x762)                 // master volume (right)
+#define P_EVOLL(cr)      (0x28 * cr + 0x764)                 // effect return volume (left)
+#define P_EVOLR(cr)      (0x28 * cr + 0x766)                 // effect return volume (right)
+#define P_AVOLL(cr)      (0x28 * cr + 0x768)                 // core external input volume (left)
+#define P_AVOLR(cr)      (0x28 * cr + 0x76A)                 // core external input volume (right)
+#define P_BVOLL(cr)      (0x28 * cr + 0x76C)                 // sound data input volume (left)
+#define P_BVOLR(cr)      (0x28 * cr + 0x76E)                 // sound data input volume (right)
+#define P_MVOLXL(cr)     (0x28 * cr + 0x770)                 // current master volume (left)
+#define P_MVOLXR(cr)     (0x28 * cr + 0x772)                 // current master volume (right)
+
+
+// More CORE 0 Reverb
+
+
+#define IIR_ALPHA(cr)    (0x28 * cr + 0x774)      
+#define ACC_COEF_A(cr)   (0x28 * cr + 0x776)      
+#define ACC_COEF_B(cr)   (0x28 * cr + 0x778)      
+#define ACC_COEF_C(cr)   (0x28 * cr + 0x77A)      
+#define ACC_COEF_D(cr)   (0x28 * cr + 0x77C)      
+#define IIR_COEF(cr)     (0x28 * cr + 0x77E)      
+#define FB_ALPHA(cr)     (0x28 * cr + 0x780)      
+#define FB_X(cr)         (0x28 * cr + 0x782)      
+#define IN_COEF_L(cr)    (0x28 * cr + 0x784)      
+#define IN_COEF_R(cr)    (0x28 * cr + 0x786) 
+
+
+// CORE 1 only
+
+#define SPDIF_OUT        0x7C0                                // SPDIF Out: OFF/'PCM'/Bitstream/Bypass 
+#define SPDIF_MODE       0x7C6 
+#define SPDIF_MEDIA      0x7C8                                // SPDIF Media: 'CD'/DVD	
+#define SPDIF_COPY       0x7CA                                // SPDIF Copy Protection
+*/
+
+/* PS1 SPU CORE
+
+*** The below really isn't needed, only if you ***
+*** want to add SPU support to the plugin      ***
+*** which I see no need to add at this time.   ***
+*** individual voice settings                  ***
+
+#define SPU_VP_PITCH(vc) (0xC04 + (vc << 4))                 // voice pitch
+#define SPU_VA_SSA(vc)   (0xC06 + (vc << 4))                 // voice waveform data start address
+#define SPU_VP_ADSR(vc)  (0xC08 + (vc << 4))                 // voice envelope
+#define SPU_VA_SSA(vc)   (0xC0E + (vc << 4))                 // voice waveform data loop address
+
+// common settings
+
+#define SPU_P_MVOLL      0xD80                               // master volume (left)
+#define SPU_P_MVOLR      0xD82                               // master volume (right)
+#define SPU_P_RVOLL      0xD84                               // effect return volume (left)
+#define SPU_P_RVOLR      0xD86                               // effect return volume (right)
+#define SPU_S_KON1       0xD88                               // key on
+#define SPU_S_KON2       0xD8A                               // 
+#define SPU_S_KOFF1      0xD8C                               // key off
+#define SPU_S_KOFF2      0xD8E                               // 
+#define SPU_S_PMON1      0xD90                               // pitch modulation on
+#define SPU_S_PMON2      0xD92                               // 
+#define SPU_S_NON1       0xD94                               // noise generator on
+#define SPU_S_NON2       0xD96                               // 
+#define SPU_S_RVBON1     0xD98                               // effects on
+#define SPU_S_RVBON2     0xD9A                               // 
+#define SPU_S_MUTE1      0xD9C                               // voice mute
+#define SPU_S_MUTE2      0xD9E                               // 
+
+#define SPU_A_ESA        0xDA2                               // effects work area start
+#define SPU_A_IRQA       0xDA4                               // IRQ address
+#define SPU_A_TSA        0xDA6                               // DMA transfer start address
+#define SPU_P_DATA       0xDA8                               // DMA data register
+#define SPU_P_CTRL       0xDAA                               // DMA control register
+#define SPU_P_STAT       0xDAE                               // DMA status register
+
+#define SPU_P_CDL        0xDB0                               // sound data input volume (left)
+#define SPU_P_CDR        0xDB2                               // sound data input volume (right)
+#define SPU_P_EXTL       0xDB4                               // external input volume (left)
+#define SPU_P_EXTR       0xDB6                               // external input volume (right)
+
+#define SPU_P_REVERB     0xDC0                               // effects control
+*/
+
+/*
 #define H_SPUReverbAddr  0x0da2
 #define H_SPUirqAddr     0x0da4
 #define H_SPUaddr        0x0da6
@@ -150,4 +796,4 @@
 #define H_SPU_ADSRLevel21  0x0d58
 #define H_SPU_ADSRLevel22  0x0d68
 #define H_SPU_ADSRLevel23  0x0d78
-
+*/
--- a/Plugins/Input/sexypsf/spu/regs.h	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/regs.h	Sun Mar 19 12:51:03 2006 -0800
@@ -1,34 +1,43 @@
-/***************************************************************************
-                           regs.h  -  description
-                             -------------------
-    begin                : Wed May 15 2002
-    copyright            : (C) 2002 by Pete Bernert
-    email                : BlackDove@addcom.de
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version. See also the license.txt file for *
- *   additional informations.                                              *
- *                                                                         *
- ***************************************************************************/
-
-//*************************************************************************//
-// History of changes:
-//
-// 2002/05/15 - Pete
-// - generic cleanup for the Peops release
-//
-//*************************************************************************//
-
-
-static void SoundOn(int start,int end,u16 val);
-static void SoundOff(int start,int end,u16 val);
-static void FModOn(int start,int end,u16 val);
-static void NoiseOn(int start,int end,u16 val);
-static void SetVolumeLR(int right, u8 ch,s16 vol);
-static void SetPitch(int ch,u16 val);
-void SPUwriteRegister(u32 reg, u16 val);
+/***************************************************************************
+                           regs.h  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+
+void SoundOn(int start,int end,unsigned short val);
+void SoundOff(int start,int end,unsigned short val);
+void VolumeOn(int start,int end,unsigned short val,int iRight);
+void FModOn(int start,int end,unsigned short val);
+void NoiseOn(int start,int end,unsigned short val);
+void SetVolumeL(unsigned char ch,short vol);
+void SetVolumeR(unsigned char ch,short vol);
+void SetPitch(int ch,unsigned short val);
+void ReverbOn(int start,int end,unsigned short val,int iRight);
+void SetReverbAddr(int core);
+
+EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/resource.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,158 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by spu2PeopsSound.rc
+//
+#define IDC_SETS1                       3
+#define IDC_SETS2                       4
+#define IDOK2                           5
+#define IDD_DIALOG1                     130
+#define IDD_ABOUT                       130
+#define IDD_CFGDLG                      131
+#define IDD_DEBUG                       135
+#define IDB_BITMAP1                     136
+#define IDB_BITMAP2                     137
+#define IDB_BITMAP3                     138
+#define IDB_BITMAP4                     139
+#define IDB_BITMAP5                     140
+#define IDD_RECORD                      141
+#define IDC_XAVOLUME                    1004
+#define IDC_ENABXA                      1005
+#define IDC_XAPITCH                     1006
+#define IDC_XABLOCK                     1007
+#define IDC_USETIMER                    1007
+#define IDC_CMIXRATE                    1008
+#define IDC_USEIRQ                      1008
+#define IDC_USEREVERB                   1008
+#define IDC_CMODE                       1009
+#define IDC_VOLUME                      1009
+#define IDC_CFILTER                     1010
+#define IDC_IRQWAIT                     1010
+#define IDC_CQUALITY                    1011
+#define IDC_DEBUGMODE                   1011
+#define IDC_CDSOUND                     1012
+#define IDC_INTERPOL                    1012
+#define IDC_PLAYALWAYS                  1013
+#define IDC_RECORDMODE                  1013
+#define IDC_IGNOREPITCH                 1014
+#define IDC_DISSTEREO                   1014
+#define IDC_AMPLIF                      1015
+#define IDC_VENVELOPE                   1016
+#define IDC_VOL1                        1016
+#define IDC_REVERB                      1017
+#define IDC_VOL2                        1017
+#define IDC_VOL3                        1018
+#define IDC_VOL4                        1019
+#define IDC_SAREA                       1022
+#define IDC_ADSR                        1023
+#define IDC_MUTE1                       1047
+#define IDC_MUTE2                       1048
+#define IDC_MUTE3                       1049
+#define IDC_MUTE4                       1050
+#define IDC_MUTE5                       1051
+#define IDC_MUTE6                       1052
+#define IDC_MUTE7                       1053
+#define IDC_MUTE8                       1054
+#define IDC_MUTE9                       1055
+#define IDC_MUTE10                      1056
+#define IDC_MUTE11                      1057
+#define IDC_MUTE12                      1058
+#define IDC_MUTE13                      1059
+#define IDC_MUTE14                      1060
+#define IDC_MUTE15                      1061
+#define IDC_MUTE16                      1062
+#define IDC_MUTE17                      1063
+#define IDC_MUTE18                      1064
+#define IDC_MUTE19                      1065
+#define IDC_MUTE20                      1066
+#define IDC_MUTE21                      1067
+#define IDC_MUTE22                      1068
+#define IDC_MUTE23                      1069
+#define IDC_MUTE24                      1070
+#define IDC_CHAN1                       1071
+#define IDC_CHAN2                       1072
+#define IDC_CHAN3                       1073
+#define IDC_CHAN4                       1074
+#define IDC_CHAN5                       1075
+#define IDC_CHAN6                       1076
+#define IDC_CHAN7                       1077
+#define IDC_CHAN8                       1078
+#define IDC_CHAN9                       1079
+#define IDC_CHAN10                      1080
+#define IDC_CHAN11                      1081
+#define IDC_CHAN12                      1082
+#define IDC_CHAN13                      1083
+#define IDC_CHAN14                      1084
+#define IDC_CHAN15                      1085
+#define IDC_CHAN16                      1086
+#define IDC_CHAN17                      1087
+#define IDC_CHAN18                      1088
+#define IDC_CHAN19                      1089
+#define IDC_CHAN20                      1090
+#define IDC_CHAN21                      1091
+#define IDC_CHAN22                      1092
+#define IDC_CHAN23                      1093
+#define IDC_CHAN24                      1094
+#define IDC_SADSR1                      1096
+#define IDC_SADSR2                      1097
+#define IDC_SADSR3                      1098
+#define IDC_SADSR4                      1099
+#define IDC_SADSR5                      1100
+#define IDC_SADSR6                      1101
+#define IDC_CHANNUM                     1102
+#define IDC_MUTEOFF                     1103
+#define IDC_MUTEON                      1104
+#define IDC_SADSR7                      1105
+#define IDC_CI1                         1106
+#define IDC_CI2                         1107
+#define IDC_CI3                         1108
+#define IDC_CI4                         1109
+#define IDC_CI5                         1110
+#define IDC_CI6                         1111
+#define IDC_CI7                         1112
+#define IDC_CI8                         1113
+#define IDC_CI9                         1114
+#define IDC_CI10                        1115
+#define IDC_CI11                        1116
+#define IDC_CI12                        1117
+#define IDC_CI13                        1118
+#define IDC_CI14                        1119
+#define IDC_CI15                        1120
+#define IDC_CI16                        1121
+#define IDC_STA1                        1122
+#define IDC_SADSR8                      1123
+#define IDC_STA2                        1124
+#define IDC_STA3                        1125
+#define IDC_STA4                        1126
+#define IDC_XA1                         1127
+#define IDC_XA2                         1128
+#define IDC_XA3                         1129
+#define IDC_XA4                         1130
+#define IDC_CI17                        1131
+#define IDC_CI18                        1132
+#define IDC_XA                          1133
+#define IDC_WAVFILE                     1134
+#define IDC_CI19                        1134
+#define IDC_XA5                         1135
+#define IDC_RECORD                      1135
+#define IDC_XA6                         1136
+#define IDC_CORE1                       1137
+#define IDC_CORE2                       1138
+#define IDC_REGWRITE                    1139
+#define IDC_REGREAD                     1140
+#define IDC_CLEAR                       1141
+#define IDC_LOG                         1142
+#define IDC_NOLOG                       1143
+#define IDC_REGEDIT                     1144
+#define IDC_VALEDIT                     1145
+#define IDC_COPY                        1146
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        142
+#define _APS_NEXT_COMMAND_VALUE         32771
+#define _APS_NEXT_CONTROL_VALUE         1145
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
--- a/Plugins/Input/sexypsf/spu/reverb.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/reverb.c	Sun Mar 19 12:51:03 2006 -0800
@@ -1,383 +1,420 @@
-/***************************************************************************
-                          reverb.c  -  description
-                             -------------------
-    begin                : Wed May 15 2002
-    copyright            : (C) 2002 by Pete Bernert
-    email                : BlackDove@addcom.de
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version. See also the license.txt file for *
- *   additional informations.                                              *
- *                                                                         *
- ***************************************************************************/
-
-//*************************************************************************//
-// History of changes:
-//
-// 2003/03/17 - xodnizel
-// - Implemented Neill's 44.1Khz-22050Hz downsampling data
-//   I also need to check if the ~4 sample delay doesn't screw any sounds
-//   up by making things too out of phase.  It could be fixed easily(elsewhere).
-//
-// 2003/01/19 - Pete
-// - added Neill's reverb (see at the end of file)
-//
-// 2002/12/26 - Pete
-// - adjusted reverb handling
-//
-// 2002/08/14 - Pete
-// - added extra reverb
-//
-// 2002/05/15 - Pete
-// - generic cleanup for the Peops release
-//
-//*************************************************************************//
-
-#define _IN_REVERB
-
-// will be included from spu.c
-#ifdef _IN_SPU
-
-////////////////////////////////////////////////////////////////////////
-// globals
-////////////////////////////////////////////////////////////////////////
-
-// REVERB info and timing vars...
-
-////////////////////////////////////////////////////////////////////////
-
-static INLINE s64 g_buffer(int iOff)                          // get_buffer content helper: takes care about wraps
-{
- s16 * p=(s16 *)spuMem;
- iOff=(iOff*4)+rvb.CurrAddr;
- while(iOff>0x3FFFF)       iOff=rvb.StartAddr+(iOff-0x40000);
- while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);
- return (int)(s16)BFLIP16(*(p+iOff));
-}
-
-////////////////////////////////////////////////////////////////////////
-
-static INLINE void s_buffer(int iOff,int iVal)                // set_buffer content helper: takes care about wraps and clipping
-{
- s16 * p=(s16 *)spuMem;
- iOff=(iOff*4)+rvb.CurrAddr;
- while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000);
- while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);
- if(iVal<-32768L) iVal=-32768L;
- if(iVal>32767L) iVal=32767L;
- *(p+iOff)=(s16)BFLIP16((s16)iVal);
-}
-
-////////////////////////////////////////////////////////////////////////
-
-static INLINE void s_buffer1(int iOff,int iVal)                // set_buffer (+1 sample) content helper: takes care about wraps and clipping
-{
- s16 * p=(s16 *)spuMem;
- iOff=(iOff*4)+rvb.CurrAddr+1;
- while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000);
- while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);
- if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;
- *(p+iOff)=(s16)BFLIP16((s16)iVal);
-}
-
-static INLINE void MixREVERBLeftRight(s32 *oleft, s32 *oright, s32 inleft, s32 inright)
-{
-   static s32 downbuf[2][8];
-   static s32 upbuf[2][8];
-   static int dbpos=0,ubpos=0;
-   static s32 downcoeffs[8]={ /* Symmetry is sexy. */
-				1283,5344,10895,15243,
-				15243,10895,5344,1283
-			       };
-   int x;
-
-   if(!rvb.StartAddr)                                  // reverb is off
-    {
-     rvb.iRVBLeft=rvb.iRVBRight=0;
-     return;
-    }
-
-   //if(inleft<-32767 || inleft>32767) printf("%d\n",inleft);
-   //if(inright<-32767 || inright>32767) printf("%d\n",inright);
-   downbuf[0][dbpos]=inleft;
-   downbuf[1][dbpos]=inright;
-   dbpos=(dbpos+1)&7;
-
-   if(dbpos&1)                                          // we work on every second left value: downsample to 22 khz
-    {
-     if(spuCtrl&0x80)                                  // -> reverb on? oki
-      {
-       int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1;
-       s32 INPUT_SAMPLE_L=0;                         
-       s32 INPUT_SAMPLE_R=0;
-
-       for(x=0;x<8;x++)
-       {
-        INPUT_SAMPLE_L+=(downbuf[0][(dbpos+x)&7]*downcoeffs[x])>>8; /* Lose insignificant
-							    digits to prevent
-							    overflow(check this) */
-        INPUT_SAMPLE_R+=(downbuf[1][(dbpos+x)&7]*downcoeffs[x])>>8;
-       }
-
-       INPUT_SAMPLE_L>>=(16-8);
-       INPUT_SAMPLE_R>>=(16-8);
-       {
-        const s64 IIR_INPUT_A0 = ((g_buffer(rvb.IIR_SRC_A0) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_L * rvb.IN_COEF_L)>>15);
-        const s64 IIR_INPUT_A1 = ((g_buffer(rvb.IIR_SRC_A1) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_R * rvb.IN_COEF_R)>>15);
-        const s64 IIR_INPUT_B0 = ((g_buffer(rvb.IIR_SRC_B0) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_L * rvb.IN_COEF_L)>>15);
-        const s64 IIR_INPUT_B1 = ((g_buffer(rvb.IIR_SRC_B1) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_R * rvb.IN_COEF_R)>>15);
-        const s64 IIR_A0 = ((IIR_INPUT_A0 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_A0) * (32768L - rvb.IIR_ALPHA))>>15);
-        const s64 IIR_A1 = ((IIR_INPUT_A1 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_A1) * (32768L - rvb.IIR_ALPHA))>>15);
-        const s64 IIR_B0 = ((IIR_INPUT_B0 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_B0) * (32768L - rvb.IIR_ALPHA))>>15);
-        const s64 IIR_B1 = ((IIR_INPUT_B1 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_B1) * (32768L - rvb.IIR_ALPHA))>>15);
-
-       s_buffer1(rvb.IIR_DEST_A0, IIR_A0);
-       s_buffer1(rvb.IIR_DEST_A1, IIR_A1);
-       s_buffer1(rvb.IIR_DEST_B0, IIR_B0);
-       s_buffer1(rvb.IIR_DEST_B1, IIR_B1);
- 
-       ACC0 = ((g_buffer(rvb.ACC_SRC_A0) * rvb.ACC_COEF_A)>>15) +
-              ((g_buffer(rvb.ACC_SRC_B0) * rvb.ACC_COEF_B)>>15) +
-              ((g_buffer(rvb.ACC_SRC_C0) * rvb.ACC_COEF_C)>>15) +
-              ((g_buffer(rvb.ACC_SRC_D0) * rvb.ACC_COEF_D)>>15);
-       ACC1 = ((g_buffer(rvb.ACC_SRC_A1) * rvb.ACC_COEF_A)>>15) +
-              ((g_buffer(rvb.ACC_SRC_B1) * rvb.ACC_COEF_B)>>15) +
-              ((g_buffer(rvb.ACC_SRC_C1) * rvb.ACC_COEF_C)>>15) +
-              ((g_buffer(rvb.ACC_SRC_D1) * rvb.ACC_COEF_D)>>15);
-
-       FB_A0 = g_buffer(rvb.MIX_DEST_A0 - rvb.FB_SRC_A);
-       FB_A1 = g_buffer(rvb.MIX_DEST_A1 - rvb.FB_SRC_A);
-       FB_B0 = g_buffer(rvb.MIX_DEST_B0 - rvb.FB_SRC_B);
-       FB_B1 = g_buffer(rvb.MIX_DEST_B1 - rvb.FB_SRC_B);
-
-       s_buffer(rvb.MIX_DEST_A0, ACC0 - ((FB_A0 * rvb.FB_ALPHA)>>15));
-       s_buffer(rvb.MIX_DEST_A1, ACC1 - ((FB_A1 * rvb.FB_ALPHA)>>15));
-       
-       s_buffer(rvb.MIX_DEST_B0, ((rvb.FB_ALPHA * ACC0)>>15) - ((FB_A0 * (int)(rvb.FB_ALPHA^0xFFFF8000))>>15) - ((FB_B0 * rvb.FB_X)>>15));
-       s_buffer(rvb.MIX_DEST_B1, ((rvb.FB_ALPHA * ACC1)>>15) - ((FB_A1 * (int)(rvb.FB_ALPHA^0xFFFF8000))>>15) - ((FB_B1 * rvb.FB_X)>>15));
- 
-       rvb.iRVBLeft  = (g_buffer(rvb.MIX_DEST_A0)+g_buffer(rvb.MIX_DEST_B0))/3;
-       rvb.iRVBRight = (g_buffer(rvb.MIX_DEST_A1)+g_buffer(rvb.MIX_DEST_B1))/3;
-
-       rvb.iRVBLeft  = ((s64)rvb.iRVBLeft * rvb.VolLeft)  >> 14;
-       rvb.iRVBRight = ((s64)rvb.iRVBRight * rvb.VolRight) >> 14;
-
-       upbuf[0][ubpos]=rvb.iRVBLeft;
-       upbuf[1][ubpos]=rvb.iRVBRight;
-       ubpos=(ubpos+1)&7;
-       } // Bracket hack(et).
-      }
-     else                                              // -> reverb off
-      {
-       rvb.iRVBLeft=rvb.iRVBRight=0;
-       return;
-      }
-     rvb.CurrAddr++;
-     if(rvb.CurrAddr>0x3ffff) rvb.CurrAddr=rvb.StartAddr;
-    }
-    else
-    {
-     upbuf[0][ubpos]=0;
-     upbuf[1][ubpos]=0;
-     ubpos=(ubpos+1)&7;
-    }
-   {
-    s32 retl=0,retr=0;
-    for(x=0;x<8;x++)
-    {
-     retl+=(upbuf[0][(ubpos+x)&7]*downcoeffs[x])>>8;
-     retr+=(upbuf[1][(ubpos+x)&7]*downcoeffs[x])>>8;
-    }
-    retl>>=(16-8-1); /* -1 To adjust for the null padding. */
-    retr>>=(16-8-1);
-
-    *oleft+=retl;
-    *oright+=retr;
-   }
-}
-
-////////////////////////////////////////////////////////////////////////
-
-#endif
-
-/*
------------------------------------------------------------------------------
-PSX reverb hardware notes
-by Neill Corlett
------------------------------------------------------------------------------
-
-Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway
-yadda yadda.
-
------------------------------------------------------------------------------
-
-Basics
-------
-
-- The reverb buffer is 22khz 16-bit mono PCM.
-- It starts at the reverb address given by 1DA2, extends to
-  the end of sound RAM, and wraps back to the 1DA2 address.
-
-Setting the address at 1DA2 resets the current reverb work address.
-
-This work address ALWAYS increments every 1/22050 sec., regardless of
-whether reverb is enabled (bit 7 of 1DAA set).
-
-And the contents of the reverb buffer ALWAYS play, scaled by the
-"reverberation depth left/right" volumes (1D84/1D86).
-(which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0)
-
------------------------------------------------------------------------------
-
-Register names
---------------
-
-These are probably not their real names.
-These are probably not even correct names.
-We will use them anyway, because we can.
-
-1DC0: FB_SRC_A       (offset)
-1DC2: FB_SRC_B       (offset)
-1DC4: IIR_ALPHA      (coef.)
-1DC6: ACC_COEF_A     (coef.)
-1DC8: ACC_COEF_B     (coef.)
-1DCA: ACC_COEF_C     (coef.)
-1DCC: ACC_COEF_D     (coef.)
-1DCE: IIR_COEF       (coef.)
-1DD0: FB_ALPHA       (coef.)
-1DD2: FB_X           (coef.)
-1DD4: IIR_DEST_A0    (offset)
-1DD6: IIR_DEST_A1    (offset)
-1DD8: ACC_SRC_A0     (offset)
-1DDA: ACC_SRC_A1     (offset)
-1DDC: ACC_SRC_B0     (offset)
-1DDE: ACC_SRC_B1     (offset)
-1DE0: IIR_SRC_A0     (offset)
-1DE2: IIR_SRC_A1     (offset)
-1DE4: IIR_DEST_B0    (offset)
-1DE6: IIR_DEST_B1    (offset)
-1DE8: ACC_SRC_C0     (offset)
-1DEA: ACC_SRC_C1     (offset)
-1DEC: ACC_SRC_D0     (offset)
-1DEE: ACC_SRC_D1     (offset)
-1DF0: IIR_SRC_B1     (offset)
-1DF2: IIR_SRC_B0     (offset)
-1DF4: MIX_DEST_A0    (offset)
-1DF6: MIX_DEST_A1    (offset)
-1DF8: MIX_DEST_B0    (offset)
-1DFA: MIX_DEST_B1    (offset)
-1DFC: IN_COEF_L      (coef.)
-1DFE: IN_COEF_R      (coef.)
-
-The coefficients are signed fractional values.
--32768 would be -1.0
- 32768 would be  1.0 (if it were possible... the highest is of course 32767)
-
-The offsets are (byte/8) offsets into the reverb buffer.
-i.e. you multiply them by 8, you get byte offsets.
-You can also think of them as (samples/4) offsets.
-They appear to be signed.  They can be negative.
-None of the documented presets make them negative, though.
-
-Yes, 1DF0 and 1DF2 appear to be backwards.  Not a typo.
-
------------------------------------------------------------------------------
-
-What it does
-------------
-
-We take all reverb sources:
-- regular channels that have the reverb bit on
-- cd and external sources, if their reverb bits are on
-and mix them into one stereo 44100hz signal.
-
-Lowpass/downsample that to 22050hz.  The PSX uses a proper bandlimiting
-algorithm here, but I haven't figured out the hysterically exact specifics.
-I use an 8-tap filter with these coefficients, which are nice but probably
-not the real ones:
-
-0.037828187894
-0.157538631280
-0.321159685278
-0.449322115345
-0.449322115345
-0.321159685278
-0.157538631280
-0.037828187894
-
-So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz.
-
-* IN MY EMULATION, I divide these by 2 to make it clip less.
-  (and of course the L/R output coefficients are adjusted to compensate)
-  The real thing appears to not do this.
-
-At every 22050hz tick:
-- If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb
-  steady-state algorithm described below
-- AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer
-  (This part may not be exactly right and I guessed at the coefs. TODO: check later.)
-  L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0])
-  R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1])
-- Advance the current buffer position by 1 sample
-
-The wet out L and R are then upsampled to 44100hz and played at the
-"reverberation depth left/right" (1D84/1D86) volume, independent of the main
-volume.
-
------------------------------------------------------------------------------
-
-Reverb steady-state
--------------------
-
-The reverb steady-state algorithm is fairly clever, and of course by
-"clever" I mean "batshit insane".
-
-buffer[x] is relative to the current buffer position, not the beginning of
-the buffer.  Note that all buffer offsets must wrap around so they're
-contained within the reverb work area.
-
-Clipping is performed at the end... maybe also sooner, but definitely at
-the end.
-
-IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
-IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
-IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
-IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
-
-IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA);
-IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA);
-IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA);
-IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA);
-
-buffer[IIR_DEST_A0 + 1sample] = IIR_A0;
-buffer[IIR_DEST_A1 + 1sample] = IIR_A1;
-buffer[IIR_DEST_B0 + 1sample] = IIR_B0;
-buffer[IIR_DEST_B1 + 1sample] = IIR_B1;
-
-ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A +
-       buffer[ACC_SRC_B0] * ACC_COEF_B +
-       buffer[ACC_SRC_C0] * ACC_COEF_C +
-       buffer[ACC_SRC_D0] * ACC_COEF_D;
-ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A +
-       buffer[ACC_SRC_B1] * ACC_COEF_B +
-       buffer[ACC_SRC_C1] * ACC_COEF_C +
-       buffer[ACC_SRC_D1] * ACC_COEF_D;
-
-FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A];
-FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A];
-FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B];
-FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B];
-
-buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA;
-buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA;
-buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X;
-buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X;
-
------------------------------------------------------------------------------
-*/
-
+/***************************************************************************
+                          reverb.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed to SPU2 functionality
+//
+// 2003/01/19 - Pete
+// - added Neill's reverb (see at the end of file)
+//
+// 2002/12/26 - Pete
+// - adjusted reverb handling
+//
+// 2002/08/14 - Pete
+// - added extra reverb
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_REVERB
+
+// will be included from spu.c
+#ifdef _IN_SPU
+
+////////////////////////////////////////////////////////////////////////
+// globals
+////////////////////////////////////////////////////////////////////////
+
+// REVERB info and timing vars...
+
+int *          sRVBPlay[2];
+int *          sRVBEnd[2];
+int *          sRVBStart[2];
+
+////////////////////////////////////////////////////////////////////////
+// START REVERB
+////////////////////////////////////////////////////////////////////////
+
+INLINE void StartREVERB(int ch)
+{
+ int core=ch/24;
+ 
+ if((s_chan[ch].bReverbL || s_chan[ch].bReverbR) && (spuCtrl2[core]&0x80))       // reverb possible?
+  {
+   if(iUseReverb==1) s_chan[ch].bRVBActive=1;
+  }
+ else s_chan[ch].bRVBActive=0;                         // else -> no reverb
+}
+
+////////////////////////////////////////////////////////////////////////
+// HELPER FOR NEILL'S REVERB: re-inits our reverb mixing buf
+////////////////////////////////////////////////////////////////////////
+
+INLINE void InitREVERB(void)
+{
+ if(iUseReverb==1)
+  {
+   memset(sRVBStart[0],0,NSSIZE*2*4);
+   memset(sRVBStart[1],0,NSSIZE*2*4);
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// STORE REVERB
+////////////////////////////////////////////////////////////////////////
+
+INLINE void StoreREVERB(int ch,int ns)
+{
+ int core=ch/24;
+ 
+ if(iUseReverb==0) return;
+ else
+ if(iUseReverb==1) // -------------------------------- // Neil's reverb
+  {
+   const int iRxl=(s_chan[ch].sval*s_chan[ch].iLeftVolume*s_chan[ch].bReverbL)/0x4000;
+   const int iRxr=(s_chan[ch].sval*s_chan[ch].iRightVolume*s_chan[ch].bReverbR)/0x4000;
+
+   ns<<=1;
+
+   *(sRVBStart[core]+ns)  +=iRxl;                      // -> we mix all active reverb channels into an extra buffer
+   *(sRVBStart[core]+ns+1)+=iRxr;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE int g_buffer(int iOff,int core)                   // get_buffer content helper: takes care about wraps
+{
+ short * p=(short *)spuMem;
+ iOff=(iOff)+rvb[core].CurrAddr;
+ while(iOff>rvb[core].EndAddr)   iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1));
+ while(iOff<rvb[core].StartAddr) iOff=rvb[core].EndAddr-(rvb[core].StartAddr-iOff);
+ return (int)*(p+iOff);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE void s_buffer(int iOff,int iVal,int core)        // set_buffer content helper: takes care about wraps and clipping
+{
+ short * p=(short *)spuMem;
+ iOff=(iOff)+rvb[core].CurrAddr;
+ while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1));
+ while(iOff<rvb[core].StartAddr) iOff=rvb[core].EndAddr-(rvb[core].StartAddr-iOff);
+ if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;
+ *(p+iOff)=(short)iVal;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE void s_buffer1(int iOff,int iVal,int core)      // set_buffer (+1 sample) content helper: takes care about wraps and clipping
+{
+ short * p=(short *)spuMem;
+ iOff=(iOff)+rvb[core].CurrAddr+1;
+ while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1));
+ while(iOff<rvb[core].StartAddr) iOff=rvb[core].EndAddr-(rvb[core].StartAddr-iOff);
+ if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;
+ *(p+iOff)=(short)iVal;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE int MixREVERBLeft(int ns,int core)
+{
+ if(iUseReverb==1)
+  {
+   if(!rvb[core].StartAddr || !rvb[core].EndAddr || 
+      rvb[core].StartAddr>=rvb[core].EndAddr)          // reverb is off
+    {
+     rvb[core].iLastRVBLeft=rvb[core].iLastRVBRight=rvb[core].iRVBLeft=rvb[core].iRVBRight=0;
+     return 0;
+    }
+
+   rvb[core].iCnt++;                                    
+
+   if(rvb[core].iCnt&1)                                // we work on every second left value: downsample to 22 khz
+    {
+     if((spuCtrl2[core]&0x80))                         // -> reverb on? oki
+      {
+       int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1;
+
+       const int INPUT_SAMPLE_L=*(sRVBStart[core]+(ns<<1));                         
+       const int INPUT_SAMPLE_R=*(sRVBStart[core]+(ns<<1)+1);                     
+
+       const int IIR_INPUT_A0 = (g_buffer(rvb[core].IIR_SRC_A0,core) * rvb[core].IIR_COEF)/32768L + (INPUT_SAMPLE_L * rvb[core].IN_COEF_L)/32768L;
+       const int IIR_INPUT_A1 = (g_buffer(rvb[core].IIR_SRC_A1,core) * rvb[core].IIR_COEF)/32768L + (INPUT_SAMPLE_R * rvb[core].IN_COEF_R)/32768L;
+       const int IIR_INPUT_B0 = (g_buffer(rvb[core].IIR_SRC_B0,core) * rvb[core].IIR_COEF)/32768L + (INPUT_SAMPLE_L * rvb[core].IN_COEF_L)/32768L;
+       const int IIR_INPUT_B1 = (g_buffer(rvb[core].IIR_SRC_B1,core) * rvb[core].IIR_COEF)/32768L + (INPUT_SAMPLE_R * rvb[core].IN_COEF_R)/32768L;
+
+       const int IIR_A0 = (IIR_INPUT_A0 * rvb[core].IIR_ALPHA)/32768L + (g_buffer(rvb[core].IIR_DEST_A0,core) * (32768L - rvb[core].IIR_ALPHA))/32768L;
+       const int IIR_A1 = (IIR_INPUT_A1 * rvb[core].IIR_ALPHA)/32768L + (g_buffer(rvb[core].IIR_DEST_A1,core) * (32768L - rvb[core].IIR_ALPHA))/32768L;
+       const int IIR_B0 = (IIR_INPUT_B0 * rvb[core].IIR_ALPHA)/32768L + (g_buffer(rvb[core].IIR_DEST_B0,core) * (32768L - rvb[core].IIR_ALPHA))/32768L;
+       const int IIR_B1 = (IIR_INPUT_B1 * rvb[core].IIR_ALPHA)/32768L + (g_buffer(rvb[core].IIR_DEST_B1,core) * (32768L - rvb[core].IIR_ALPHA))/32768L;
+
+       s_buffer1(rvb[core].IIR_DEST_A0, IIR_A0,core);
+       s_buffer1(rvb[core].IIR_DEST_A1, IIR_A1,core);
+       s_buffer1(rvb[core].IIR_DEST_B0, IIR_B0,core);
+       s_buffer1(rvb[core].IIR_DEST_B1, IIR_B1,core);
+ 
+       ACC0 = (g_buffer(rvb[core].ACC_SRC_A0,core) * rvb[core].ACC_COEF_A)/32768L +
+              (g_buffer(rvb[core].ACC_SRC_B0,core) * rvb[core].ACC_COEF_B)/32768L +
+              (g_buffer(rvb[core].ACC_SRC_C0,core) * rvb[core].ACC_COEF_C)/32768L +
+              (g_buffer(rvb[core].ACC_SRC_D0,core) * rvb[core].ACC_COEF_D)/32768L;
+       ACC1 = (g_buffer(rvb[core].ACC_SRC_A1,core) * rvb[core].ACC_COEF_A)/32768L +
+              (g_buffer(rvb[core].ACC_SRC_B1,core) * rvb[core].ACC_COEF_B)/32768L +
+              (g_buffer(rvb[core].ACC_SRC_C1,core) * rvb[core].ACC_COEF_C)/32768L +
+              (g_buffer(rvb[core].ACC_SRC_D1,core) * rvb[core].ACC_COEF_D)/32768L;
+
+       FB_A0 = g_buffer(rvb[core].MIX_DEST_A0 - rvb[core].FB_SRC_A,core);
+       FB_A1 = g_buffer(rvb[core].MIX_DEST_A1 - rvb[core].FB_SRC_A,core);
+       FB_B0 = g_buffer(rvb[core].MIX_DEST_B0 - rvb[core].FB_SRC_B,core);
+       FB_B1 = g_buffer(rvb[core].MIX_DEST_B1 - rvb[core].FB_SRC_B,core);
+
+       s_buffer(rvb[core].MIX_DEST_A0, ACC0 - (FB_A0 * rvb[core].FB_ALPHA)/32768L,core);
+       s_buffer(rvb[core].MIX_DEST_A1, ACC1 - (FB_A1 * rvb[core].FB_ALPHA)/32768L,core);
+       
+       s_buffer(rvb[core].MIX_DEST_B0, (rvb[core].FB_ALPHA * ACC0)/32768L - (FB_A0 * (int)(rvb[core].FB_ALPHA^0xFFFF8000))/32768L - (FB_B0 * rvb[core].FB_X)/32768L,core);
+       s_buffer(rvb[core].MIX_DEST_B1, (rvb[core].FB_ALPHA * ACC1)/32768L - (FB_A1 * (int)(rvb[core].FB_ALPHA^0xFFFF8000))/32768L - (FB_B1 * rvb[core].FB_X)/32768L,core);
+ 
+       rvb[core].iLastRVBLeft  = rvb[core].iRVBLeft;
+       rvb[core].iLastRVBRight = rvb[core].iRVBRight;
+
+       rvb[core].iRVBLeft  = (g_buffer(rvb[core].MIX_DEST_A0,core)+g_buffer(rvb[core].MIX_DEST_B0,core))/3;
+       rvb[core].iRVBRight = (g_buffer(rvb[core].MIX_DEST_A1,core)+g_buffer(rvb[core].MIX_DEST_B1,core))/3;
+
+       rvb[core].iRVBLeft  = (rvb[core].iRVBLeft  * rvb[core].VolLeft)  / 0x4000;
+       rvb[core].iRVBRight = (rvb[core].iRVBRight * rvb[core].VolRight) / 0x4000;
+
+       rvb[core].CurrAddr++;
+       if(rvb[core].CurrAddr>rvb[core].EndAddr) rvb[core].CurrAddr=rvb[core].StartAddr;
+
+       return rvb[core].iLastRVBLeft+(rvb[core].iRVBLeft-rvb[core].iLastRVBLeft)/2;
+      }
+     else                                              // -> reverb off
+      {
+       rvb[core].iLastRVBLeft=rvb[core].iLastRVBRight=rvb[core].iRVBLeft=rvb[core].iRVBRight=0;
+      }
+
+     rvb[core].CurrAddr++;
+     if(rvb[core].CurrAddr>rvb[core].EndAddr) rvb[core].CurrAddr=rvb[core].StartAddr;
+    }
+
+   return rvb[core].iLastRVBLeft;
+  }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE int MixREVERBRight(int core)
+{
+ if(iUseReverb==1)                                     // Neill's reverb:
+  {
+   int i=rvb[core].iLastRVBRight+(rvb[core].iRVBRight-rvb[core].iLastRVBRight)/2;
+   rvb[core].iLastRVBRight=rvb[core].iRVBRight;
+   return i;                                           // -> just return the last right reverb val (little bit scaled by the previous right val)
+  }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
+/*
+-----------------------------------------------------------------------------
+PSX reverb hardware notes
+by Neill Corlett
+-----------------------------------------------------------------------------
+
+Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway
+yadda yadda.
+
+-----------------------------------------------------------------------------
+
+Basics
+------
+
+- The reverb buffer is 22khz 16-bit mono PCM.
+- It starts at the reverb address given by 1DA2, extends to
+  the end of sound RAM, and wraps back to the 1DA2 address.
+
+Setting the address at 1DA2 resets the current reverb work address.
+
+This work address ALWAYS increments every 1/22050 sec., regardless of
+whether reverb is enabled (bit 7 of 1DAA set).
+
+And the contents of the reverb buffer ALWAYS play, scaled by the
+"reverberation depth left/right" volumes (1D84/1D86).
+(which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0)
+
+-----------------------------------------------------------------------------
+
+Register names
+--------------
+
+These are probably not their real names.
+These are probably not even correct names.
+We will use them anyway, because we can.
+
+1DC0: FB_SRC_A       (offset)
+1DC2: FB_SRC_B       (offset)
+1DC4: IIR_ALPHA      (coef.)
+1DC6: ACC_COEF_A     (coef.)
+1DC8: ACC_COEF_B     (coef.)
+1DCA: ACC_COEF_C     (coef.)
+1DCC: ACC_COEF_D     (coef.)
+1DCE: IIR_COEF       (coef.)
+1DD0: FB_ALPHA       (coef.)
+1DD2: FB_X           (coef.)
+1DD4: IIR_DEST_A0    (offset)
+1DD6: IIR_DEST_A1    (offset)
+1DD8: ACC_SRC_A0     (offset)
+1DDA: ACC_SRC_A1     (offset)
+1DDC: ACC_SRC_B0     (offset)
+1DDE: ACC_SRC_B1     (offset)
+1DE0: IIR_SRC_A0     (offset)
+1DE2: IIR_SRC_A1     (offset)
+1DE4: IIR_DEST_B0    (offset)
+1DE6: IIR_DEST_B1    (offset)
+1DE8: ACC_SRC_C0     (offset)
+1DEA: ACC_SRC_C1     (offset)
+1DEC: ACC_SRC_D0     (offset)
+1DEE: ACC_SRC_D1     (offset)
+1DF0: IIR_SRC_B1     (offset)
+1DF2: IIR_SRC_B0     (offset)
+1DF4: MIX_DEST_A0    (offset)
+1DF6: MIX_DEST_A1    (offset)
+1DF8: MIX_DEST_B0    (offset)
+1DFA: MIX_DEST_B1    (offset)
+1DFC: IN_COEF_L      (coef.)
+1DFE: IN_COEF_R      (coef.)
+
+The coefficients are signed fractional values.
+-32768 would be -1.0
+ 32768 would be  1.0 (if it were possible... the highest is of course 32767)
+
+The offsets are (byte/8) offsets into the reverb buffer.
+i.e. you multiply them by 8, you get byte offsets.
+You can also think of them as (samples/4) offsets.
+They appear to be signed.  They can be negative.
+None of the documented presets make them negative, though.
+
+Yes, 1DF0 and 1DF2 appear to be backwards.  Not a typo.
+
+-----------------------------------------------------------------------------
+
+What it does
+------------
+
+We take all reverb sources:
+- regular channels that have the reverb bit on
+- cd and external sources, if their reverb bits are on
+and mix them into one stereo 44100hz signal.
+
+Lowpass/downsample that to 22050hz.  The PSX uses a proper bandlimiting
+algorithm here, but I haven't figured out the hysterically exact specifics.
+I use an 8-tap filter with these coefficients, which are nice but probably
+not the real ones:
+
+0.037828187894
+0.157538631280
+0.321159685278
+0.449322115345
+0.449322115345
+0.321159685278
+0.157538631280
+0.037828187894
+
+So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz.
+
+* IN MY EMULATION, I divide these by 2 to make it clip less.
+  (and of course the L/R output coefficients are adjusted to compensate)
+  The real thing appears to not do this.
+
+At every 22050hz tick:
+- If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb
+  steady-state algorithm described below
+- AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer
+  (This part may not be exactly right and I guessed at the coefs. TODO: check later.)
+  L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0])
+  R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1])
+- Advance the current buffer position by 1 sample
+
+The wet out L and R are then upsampled to 44100hz and played at the
+"reverberation depth left/right" (1D84/1D86) volume, independent of the main
+volume.
+
+-----------------------------------------------------------------------------
+
+Reverb steady-state
+-------------------
+
+The reverb steady-state algorithm is fairly clever, and of course by
+"clever" I mean "batshit insane".
+
+buffer[x] is relative to the current buffer position, not the beginning of
+the buffer.  Note that all buffer offsets must wrap around so they're
+contained within the reverb work area.
+
+Clipping is performed at the end... maybe also sooner, but definitely at
+the end.
+
+IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
+IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
+IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
+IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
+
+IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA);
+IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA);
+IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA);
+IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA);
+
+buffer[IIR_DEST_A0 + 1sample] = IIR_A0;
+buffer[IIR_DEST_A1 + 1sample] = IIR_A1;
+buffer[IIR_DEST_B0 + 1sample] = IIR_B0;
+buffer[IIR_DEST_B1 + 1sample] = IIR_B1;
+
+ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A +
+       buffer[ACC_SRC_B0] * ACC_COEF_B +
+       buffer[ACC_SRC_C0] * ACC_COEF_C +
+       buffer[ACC_SRC_D0] * ACC_COEF_D;
+ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A +
+       buffer[ACC_SRC_B1] * ACC_COEF_B +
+       buffer[ACC_SRC_C1] * ACC_COEF_C +
+       buffer[ACC_SRC_D1] * ACC_COEF_D;
+
+FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A];
+FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A];
+FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B];
+FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B];
+
+buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA;
+buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA;
+buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X;
+buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X;
+
+-----------------------------------------------------------------------------
+*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/reverb.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,33 @@
+/***************************************************************************
+                          reverb.h  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+
+INLINE void StartREVERB(int ch);
+INLINE void StoreREVERB(int ch,int ns);
+
--- a/Plugins/Input/sexypsf/spu/spu.c	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/spu.c	Sun Mar 19 12:51:03 2006 -0800
@@ -1,637 +1,1331 @@
-/***************************************************************************
-                            spu.c  -  description
-                             -------------------
-    begin                : Wed May 15 2002
-    copyright            : (C) 2002 by Pete Bernert
-    email                : BlackDove@addcom.de
- ***************************************************************************/
-                       
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version. See also the license.txt file for *
- *   additional informations.                                              *
- *                                                                         *
- ***************************************************************************/
-                           
-//*************************************************************************//
-// History of changes:
-//
-// 2003/03/01 - linuzappz
-// - libraryName changes using ALSA
-//
-// 2003/02/28 - Pete
-// - added option for type of interpolation
-// - adjusted spu irqs again (Thousant Arms, Valkyrie Profile)
-// - added MONO support for MSWindows DirectSound
-//
-// 2003/02/20 - kode54
-// - amended interpolation code, goto GOON could skip initialization of gpos and cause segfault
-//
-// 2003/02/19 - kode54
-// - moved SPU IRQ handler and changed sample flag processing
-//
-// 2003/02/18 - kode54
-// - moved ADSR calculation outside of the sample decode loop, somehow I doubt that
-//   ADSR timing is relative to the frequency at which a sample is played... I guess
-//   this remains to be seen, and I don't know whether ADSR is applied to noise channels...
-//
-// 2003/02/09 - kode54
-// - one-shot samples now process the end block before stopping
-// - in light of removing fmod hack, now processing ADSR on frequency channel as well
-//
-// 2003/02/08 - kode54
-// - replaced easy interpolation with gaussian
-// - removed fmod averaging hack
-// - changed .sinc to be updated from .iRawPitch, no idea why it wasn't done this way already (<- Pete: because I sometimes fail to see the obvious, haharhar :)
-//
-// 2003/02/08 - linuzappz
-// - small bugfix for one usleep that was 1 instead of 1000
-// - added iDisStereo for no stereo (Linux)
-//
-// 2003/01/22 - Pete
-// - added easy interpolation & small noise adjustments
-//
-// 2003/01/19 - Pete
-// - added Neill's reverb
-//
-// 2003/01/12 - Pete
-// - added recording window handlers
-//
-// 2003/01/06 - Pete
-// - added Neill's ADSR timings
-//
-// 2002/12/28 - Pete
-// - adjusted spu irq handling, fmod handling and loop handling
-//
-// 2002/08/14 - Pete
-// - added extra reverb
-//
-// 2002/06/08 - linuzappz
-// - SPUupdate changed for SPUasync
-//
-// 2002/05/15 - Pete
-// - generic cleanup for the Peops release
-//
-//*************************************************************************//
-
-#define _IN_SPU
-
-#include "stdafx.h"
-#include "externals.h"
-#include "spu.h"
-#include "regs.h"
-#include "registers.h"
-
-#include "PsxMem.h"
-#include "driver.h"
-
-////////////////////////////////////////////////////////////////////////
-// globals
-////////////////////////////////////////////////////////////////////////
-
-// psx buffer / addresses
-
-static u16  regArea[0x200];
-static u16  spuMem[256*1024];
-static u8 * spuMemC;
-static u8 * pSpuIrq=0;
-static u8 * pSpuBuffer;
-
-// user settings          
-static int             iVolume;
-                               
-// MAIN infos struct for each channel
-
-static SPUCHAN         s_chan[MAXCHAN+1];                     // channel + 1 infos (1 is security for fmod handling)
-static REVERBInfo      rvb;
-
-static u32   dwNoiseVal=1;                          // global noise generator
-
-static u16  spuCtrl=0;                             // some vars to store psx reg infos
-static u16  spuStat=0;
-static u16  spuIrq=0;             
-static u32  spuAddr=0xffffffff;                    // address into spu mem
-static int  bSPUIsOpen=0;
-
-static const int f[5][2] = {   
-			{    0,  0  },
-                        {   60,  0  },
-                        {  115, -52 },
-                        {   98, -55 },
-                        {  122, -60 } };
-s16 * pS;
-
-////////////////////////////////////////////////////////////////////////
-// CODE AREA
-////////////////////////////////////////////////////////////////////////
-
-// dirty inline func includes
-
-#include "reverb.c"        
-#include "adsr.c"
-
-// Try this to increase speed.
-#include "registers.c"
-#include "dma.c"
-
-////////////////////////////////////////////////////////////////////////
-// helpers for so-called "gauss interpolation"
-
-#define gval0 (((int *)(&s_chan[ch].SB[29]))[gpos])
-#define gval(x) (((int *)(&s_chan[ch].SB[29]))[(gpos+x)&3])
-
-#include "gauss_i.h"
-
-////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////////
-// START SOUND... called by main thread to setup a new sound on a channel
-////////////////////////////////////////////////////////////////////////
-
-static INLINE void StartSound(int ch)
-{
- StartADSR(ch);
-                          
- s_chan[ch].pCurr=s_chan[ch].pStart;                   // set sample start
-                         
- 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;
-
- s_chan[ch].spos=0x40000L;s_chan[ch].SB[28]=0;  // -> start with more decoding
-}
-
-////////////////////////////////////////////////////////////////////////
-// MAIN SPU FUNCTION
-// here is the main job handler... thread, timer or direct func call
-// basically the whole sound processing is done in this fat func!
-////////////////////////////////////////////////////////////////////////
-
-static u32 sampcount;
-static u32 decaybegin;
-static u32 decayend;
-
-// Counting to 65536 results in full volume offage.
-void SPUsetlength(s32 stop, s32 fade)
-{
- if(stop==~0)
- {
-  decaybegin=~0;
- }
- else
- {
-  stop=(stop*441)/10;
-  fade=(fade*441)/10;
-
-  decaybegin=stop;
-  decayend=stop+fade;
- }
-}
-
-static u32 seektime;
-static s32 poo;
-int sexypsf_seek(u32 t)
-{
- seektime=t*441/10;
- if(seektime>sampcount) return(1);
- return(0);
-}
-
-#define CLIP(_x) {if(_x>32767) _x=32767; if(_x<-32767) _x=-32767;}
-int SPUasync(u32 cycles)
-{
- int volmul=iVolume;
- static s32 dosampies;
- s32 temp;
-
- poo+=cycles;
- dosampies=poo/384;
- if(!dosampies) return(1);
- poo-=dosampies*384;
- temp=dosampies;
-
- while(temp)
- {
-   s32 revLeft=0, revRight=0;
-   s32 sl=0, sr=0;
-   int ch,fa;
-
-   temp--;
-   //--------------------------------------------------//
-   //- main channel loop                              -// 
-   //--------------------------------------------------//
-    {
-     for(ch=0;ch<MAXCHAN;ch++)                         // loop em all.
-      {
-       if(s_chan[ch].bNew) StartSound(ch);             // start new sound
-       if(!s_chan[ch].bOn) continue;                   // channel not playing? next
-
-
-       if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq)   // new psx frequency?
-        {
-         s_chan[ch].iUsedFreq=s_chan[ch].iActFreq;     // -> take it and calc steps
-         s_chan[ch].sinc=s_chan[ch].iRawPitch<<4;
-         if(!s_chan[ch].sinc) s_chan[ch].sinc=1;
-        }
-
-         while(s_chan[ch].spos>=0x10000L)
-          {
-           if(s_chan[ch].iSBPos==28)                   // 28 reached?
-            {
-	     int predict_nr,shift_factor,flags,d,s;
-	     u8* start;unsigned int nSample;
-	     int s_1,s_2;
-
-             start=s_chan[ch].pCurr;                   // set up the current pos
-
-             if (start == (u8*)-1)          // special "stop" sign
-              {
-               s_chan[ch].bOn=0;                       // -> turn everything off
-               s_chan[ch].ADSRX.lVolume=0;
-               s_chan[ch].ADSRX.EnvelopeVol=0;
-               goto ENDX;                              // -> and done for this channel
-              }
-
-             s_chan[ch].iSBPos=0;	// Reset buffer play index.
-
-             //////////////////////////////////////////// spu irq handler here? mmm... do it later
-
-             s_1=s_chan[ch].s_1;
-             s_2=s_chan[ch].s_2;
-
-             predict_nr=(int)*start;start++;           
-             shift_factor=predict_nr&0xf;
-             predict_nr >>= 4;
-             flags=(int)*start;start++;
-
-             // -------------------------------------- // 
-	     // Decode new samples into s_chan[ch].SB[0 through 27]
-             for (nSample=0;nSample<28;start++)      
-              {
-               d=(int)*start;
-               s=((d&0xf)<<12);
-               if(s&0x8000) s|=0xffff0000;
-
-               fa=(s >> shift_factor);
-               fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
-               s_2=s_1;s_1=fa;
-               s=((d & 0xf0) << 8);
-
-               s_chan[ch].SB[nSample++]=fa;
-
-               if(s&0x8000) s|=0xffff0000;
-               fa=(s>>shift_factor);              
-               fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
-               s_2=s_1;s_1=fa;
-
-               s_chan[ch].SB[nSample++]=fa;
-              }     
-
-             //////////////////////////////////////////// irq check
-
-             if(spuCtrl&0x40)         			// irq active?
-              {
-               if((pSpuIrq >  start-16 &&              // irq address reached?
-                   pSpuIrq <= start) ||
-                  ((flags&1) &&                        // special: irq on looping addr, when stop/loop flag is set 
-                   (pSpuIrq >  s_chan[ch].pLoop-16 && 
-                    pSpuIrq <= s_chan[ch].pLoop)))
-               {
-		 //extern s32 spuirqvoodoo;
-                 s_chan[ch].iIrqDone=1;                // -> debug flag
-		 SPUirq();
-		//puts("IRQ");
-		 //if(spuirqvoodoo!=-1)
-		 //{
-		 // spuirqvoodoo=temp*384;
-		 // temp=0;
-		 //}
-                }
-              }
-      
-             //////////////////////////////////////////// flag handler
-
-             if((flags&4) && (!s_chan[ch].bIgnoreLoop))
-              s_chan[ch].pLoop=start-16;               // loop adress
-
-             if(flags&1)                               // 1: stop/loop
-              {
-               // 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
-                 start = (u8*)-1;
-                }
-               else
-                {
-                 start = s_chan[ch].pLoop;
-                }
-              }
-
-             s_chan[ch].pCurr=start;                   // store values for next cycle
-             s_chan[ch].s_1=s_1;
-             s_chan[ch].s_2=s_2;      
-
-             ////////////////////////////////////////////
-            }
-
-           fa=s_chan[ch].SB[s_chan[ch].iSBPos++];      // get sample data
-
-           if((spuCtrl&0x4000)==0) fa=0;               // muted?
-	   else CLIP(fa);
-
-	    {
-	     int gpos;
-             gpos = s_chan[ch].SB[28];
-             gval0 = fa;
-             gpos = (gpos+1) & 3;
-             s_chan[ch].SB[28] = gpos;
-	    }
-           s_chan[ch].spos -= 0x10000L;
-          }
-
-         ////////////////////////////////////////////////
-         // noise handler... just produces some noise data
-         // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used...
-         // and sometimes the noise will be used as fmod modulation... pfff
-
-         if(s_chan[ch].bNoise)
-          {
-	   //puts("Noise");
-           if((dwNoiseVal<<=1)&0x80000000L)
-            {
-             dwNoiseVal^=0x0040001L;
-             fa=((dwNoiseVal>>2)&0x7fff);
-             fa=-fa;
-            }
-           else fa=(dwNoiseVal>>2)&0x7fff;
-
-           // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val
-           fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl&0x3f00)>>9))+1));
-           if(fa>32767L)  fa=32767L;
-           if(fa<-32767L) fa=-32767L;              
-           s_chan[ch].iOldNoise=fa;
-
-          }                                            //----------------------------------------
-         else                                         // NO NOISE (NORMAL SAMPLE DATA) HERE 
-          {
-             int vl, vr, gpos;
-             vl = (s_chan[ch].spos >> 6) & ~3;
-             gpos = s_chan[ch].SB[28];
-             vr=(gauss[vl]*gval0)>>9;
-             vr+=(gauss[vl+1]*gval(1))>>9;
-             vr+=(gauss[vl+2]*gval(2))>>9;
-             vr+=(gauss[vl+3]*gval(3))>>9;
-             fa = vr>>2;
-          }
-
-         s_chan[ch].sval = (MixADSR(ch) * fa)>>10;     // / 1023;  // add adsr
-         if(s_chan[ch].bFMod==2)                       // fmod freq channel
-         {
-           int NP=s_chan[ch+1].iRawPitch;
-           NP=((32768L+s_chan[ch].sval)*NP)>>15; ///32768L;
-
-           if(NP>0x3fff) NP=0x3fff;
-           if(NP<0x1)    NP=0x1;
-                                                        
-	   // mmmm... if I do this, all is screwed              
-	  //           s_chan[ch+1].iRawPitch=NP;
-
-           NP=(44100L*NP)/(4096L);                     // calc frequency
-
-           s_chan[ch+1].iActFreq=NP;
-           s_chan[ch+1].iUsedFreq=NP;
-           s_chan[ch+1].sinc=(((NP/10)<<16)/4410);
-           if(!s_chan[ch+1].sinc) s_chan[ch+1].sinc=1;
-
-		// mmmm... set up freq decoding positions?
-		//           s_chan[ch+1].iSBPos=28;
-		//           s_chan[ch+1].spos=0x10000L;
-          }                    
-         else
-          {                                          
-           //////////////////////////////////////////////
-           // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
-	   int tmpl,tmpr;
-
-	   tmpl=(s_chan[ch].sval*s_chan[ch].iLeftVolume)>>14;
-	   tmpr=(s_chan[ch].sval*s_chan[ch].iRightVolume)>>14;
-
-	   sl+=tmpl;
-	   sr+=tmpr;
-
-	   if(((rvb.Enabled>>ch)&1) && (spuCtrl&0x80))
-	   {
-	    revLeft+=tmpl;
-	    revRight+=tmpr;
-	   }
-          }
-
-         s_chan[ch].spos += s_chan[ch].sinc;             
- ENDX:   ;                                                      
-      }
-    }                                                         
-                                                           
-  ///////////////////////////////////////////////////////
-  // mix all channels (including reverb) into one buffer
-  MixREVERBLeftRight(&sl,&sr,revLeft,revRight);
-  if(sampcount>=decaybegin)
-  {
-   s32 dmul;
-   if(decaybegin!=(u32)~0) // Is anyone REALLY going to be playing a song
-		      // for 13 hours?
-   {
-    if(sampcount>=decayend) return(0);
-    dmul=256-(256*(sampcount-decaybegin)/(decayend-decaybegin));
-    sl=(sl*dmul)>>8;
-    sr=(sr*dmul)>>8;
-   }
-  }
-  sampcount++;
-  sl=(sl*volmul)>>8;
-  sr=(sr*volmul)>>8;
-
-  //{
-  // static double asl=0;
-  // static double asr=0;
-   
-  // asl+=(sl-asl)/5;
-  // asr+=(sl-asr)/5;
-
-   //sl-=asl;
-   //sr-=asr;
-
-  // if(sl>32767 || sl < -32767) printf("Left: %d, %f\n",sl,asl);
-  // if(sr>32767 || sr < -32767) printf("Right: %d, %f\n",sl,asl);
-  //}
-
-  if(sl>32767) sl=32767; if(sl<-32767) sl=-32767;
-  if(sr>32767) sr=32767; if(sr<-32767) sr=-32767;
-  *pS++=sl;
-  *pS++=sr;
- }
-
- return(1);
-}
-
-void sexypsf_stop(void)
-{
- decaybegin=decayend=0;
-}
-
-void SPUendflush(void)
-{
-   if((seektime!=(u32)~0) && seektime>sampcount)
-   {
-    pS=(s16 *)pSpuBuffer;
-    sexypsf_update(0,0);
-   }
-   else if((u8*)pS>((u8*)pSpuBuffer+1024))
-   {
-    sexypsf_update((u8*)pSpuBuffer,(u8*)pS-(u8*)pSpuBuffer);
-    pS=(s16 *)pSpuBuffer;
-   }
-}   
-
-#ifdef TIMEO
-static u64 begintime;
-static u64 SexyTime64(void)
-{
- struct timeval tv;
- u64 ret;
-
- gettimeofday(&tv,0);
- ret=tv.tv_sec;
- ret*=1000000;
- ret+=tv.tv_usec;
- return(ret);
-}
-#endif
-////////////////////////////////////////////////////////////////////////
-// INIT/EXIT STUFF
-////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////////
-// SPUINIT: this func will be called first by the main emu
-////////////////////////////////////////////////////////////////////////
-              
-int SPUinit(void)
-{
- spuMemC=(u8*)spuMem;                      // just small setup
- memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN));
- memset((void *)&rvb,0,sizeof(REVERBInfo));
- memset(regArea,0,sizeof(regArea));
- memset(spuMem,0,sizeof(spuMem));
- InitADSR();
- sampcount=poo=0;
- seektime=(u32)~0;
- #ifdef TIMEO
- begintime=SexyTime64();
- #endif
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////
-// SETUPSTREAMS: init most of the spu buffers
-////////////////////////////////////////////////////////////////////////
-
-void SetupStreams(void)
-{ 
- int i;
-
- pSpuBuffer=(u8*)malloc(32768);            // alloc mixing buffer
- pS=(s16 *)pSpuBuffer;
-
- for(i=0;i<MAXCHAN;i++)                                // loop sound channels
-  {
-   s_chan[i].ADSRX.SustainLevel = 1024;                // -> init sustain
-   s_chan[i].iIrqDone=0;
-   s_chan[i].pLoop=spuMemC;
-   s_chan[i].pStart=spuMemC;
-   s_chan[i].pCurr=spuMemC;
-  }
-}
-
-////////////////////////////////////////////////////////////////////////
-// REMOVESTREAMS: free most buffer
-////////////////////////////////////////////////////////////////////////
-
-void RemoveStreams(void)
-{ 
- free(pSpuBuffer);                                     // free mixing buffer
- pSpuBuffer=NULL;
-
- #ifdef TIMEO
- {
-  u64 tmp;
-  tmp=SexyTime64();
-  tmp-=begintime;
-  if(tmp)
-   tmp=(u64)sampcount*1000000/tmp;
-  printf("%lld samples per second\n",tmp);
- }
- #endif
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// SPUOPEN: called by main emu after init
-////////////////////////////////////////////////////////////////////////
-   
-int SPUopen(void)
-{
- if(bSPUIsOpen) return 0;                              // security for some stupid main emus
- spuIrq=0;                       
-
- spuStat=spuCtrl=0;
- spuAddr=0xffffffff;
- dwNoiseVal=1;
-
- spuMemC=(u8*)spuMem;      
- memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN));
- pSpuIrq=0;
-
- iVolume=128; //85;
- SetupStreams();                                       // prepare streaming
-
- bSPUIsOpen=1;
-
- return 1;
-}
-
-////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////////
-// SPUCLOSE: called before shutdown
-////////////////////////////////////////////////////////////////////////
-
-int SPUclose(void)
-{
- if(!bSPUIsOpen) return 0;                             // some security
-
- bSPUIsOpen=0;                                         // no more open
-
- RemoveStreams();                                      // no more streaming
-
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////
-// SPUSHUTDOWN: called by main emu on final exit
-////////////////////////////////////////////////////////////////////////
-
-int SPUshutdown(void)
-{
- return 0;
-}
-
+/***************************************************************************
+                            spu.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+                       
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+                           
+//*************************************************************************//
+// History of changes:
+//
+// 2005/08/29 - Pete
+// - changed to 48Khz output
+//
+// 2004/12/25 - Pete
+// - inc'd version for pcsx2-0.7
+//
+// 2004/04/18 - Pete
+// - changed all kind of things in the plugin
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2003/04/07 - Eric
+// - adjusted cubic interpolation algorithm
+//
+// 2003/03/16 - Eric
+// - added cubic interpolation
+//
+// 2003/03/01 - linuzappz
+// - libraryName changes using ALSA
+//
+// 2003/02/28 - Pete
+// - added option for type of interpolation
+// - adjusted spu irqs again (Thousant Arms, Valkyrie Profile)
+// - added MONO support for MSWindows DirectSound
+//
+// 2003/02/20 - kode54
+// - amended interpolation code, goto GOON could skip initialization of gpos and cause segfault
+//
+// 2003/02/19 - kode54
+// - moved SPU IRQ handler and changed sample flag processing
+//
+// 2003/02/18 - kode54
+// - moved ADSR calculation outside of the sample decode loop, somehow I doubt that
+//   ADSR timing is relative to the frequency at which a sample is played... I guess
+//   this remains to be seen, and I don't know whether ADSR is applied to noise channels...
+//
+// 2003/02/09 - kode54
+// - one-shot samples now process the end block before stopping
+// - in light of removing fmod hack, now processing ADSR on frequency channel as well
+//
+// 2003/02/08 - kode54
+// - replaced easy interpolation with gaussian
+// - removed fmod averaging hack
+// - changed .sinc to be updated from .iRawPitch, no idea why it wasn't done this way already (<- Pete: because I sometimes fail to see the obvious, haharhar :)
+//
+// 2003/02/08 - linuzappz
+// - small bugfix for one usleep that was 1 instead of 1000
+// - added iDisStereo for no stereo (Linux)
+//
+// 2003/01/22 - Pete
+// - added easy interpolation & small noise adjustments
+//
+// 2003/01/19 - Pete
+// - added Neill's reverb
+//
+// 2003/01/12 - Pete
+// - added recording window handlers
+//
+// 2003/01/06 - Pete
+// - added Neill's ADSR timings
+//
+// 2002/12/28 - Pete
+// - adjusted spu irq handling, fmod handling and loop handling
+//
+// 2002/08/14 - Pete
+// - added extra reverb
+//
+// 2002/06/08 - linuzappz
+// - SPUupdate changed for SPUasync
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_SPU
+
+#include "externals.h"
+#include "cfg.h"
+#include "dsoundoss.h"
+#include "regs.h"
+#include "debug.h"
+#include "record.h"
+#include "resource.h"
+#include "dma.h"
+ 
+////////////////////////////////////////////////////////////////////////
+// spu version infos/name
+////////////////////////////////////////////////////////////////////////
+
+const unsigned char version  = 4;    
+const unsigned char revision = 1;  
+const unsigned char build    = 3;  
+#ifdef _WINDOWS
+static char * libraryName     = "P.E.Op.S. SPU2 DSound Driver";
+#else
+#ifndef USEALSA
+static char * libraryName     = "P.E.Op.S. SPU2 OSS Driver";
+#else
+static char * libraryName     = "P.E.Op.S. SPU2 ALSA Driver";
+#endif
+#endif
+static char * libraryInfo     = "P.E.Op.S. SPU2 Driver V1.3\nCoded by Pete Bernert and the P.E.Op.S. team\n";
+
+////////////////////////////////////////////////////////////////////////
+// globals
+////////////////////////////////////////////////////////////////////////
+
+// psx buffer / addresses
+
+unsigned short  regArea[32*1024];                        
+unsigned short  spuMem[1*1024*1024];
+unsigned char * spuMemC;
+unsigned char * pSpuIrq[2];
+unsigned char * pSpuBuffer;
+
+// sexypsf tracking stuff
+
+static unsigned long seektime;
+static unsigned long sampcount;
+static unsigned long decaybegin;
+static unsigned long decayend;
+
+void SPUsetlength(long stop, long fade)
+{
+ if(stop==~0)
+ {
+  decaybegin=~0;
+ }
+ else
+ {
+  stop=(stop*441)/10;
+  fade=(fade*441)/10;
+
+  decaybegin=stop;
+  decayend=stop+fade;
+ }
+}
+
+// user settings          
+
+int             iUseXA=1;
+int             iVolume=3;
+int             iXAPitch=1;
+int             iUseTimer=2;
+int             iSPUIRQWait=1;
+int             iDebugMode=0;
+int             iRecordMode=0;
+int             iUseReverb=0;
+int             iUseInterpolation=2;
+int             iDisStereo=0;
+                             
+// MAIN infos struct for each channel
+
+SPUCHAN         s_chan[MAXCHAN+1];                     // channel + 1 infos (1 is security for fmod handling)
+REVERBInfo      rvb[2];
+
+unsigned long   dwNoiseVal=1;                          // global noise generator
+
+unsigned short  spuCtrl2[2];                           // some vars to store psx reg infos
+unsigned short  spuStat2[2];
+unsigned long   spuIrq2[2];             
+unsigned long   spuAddr2[2];                           // address into spu mem
+unsigned long   spuRvbAddr2[2];
+unsigned long   spuRvbAEnd2[2];
+int             bEndThread=0;                          // thread handlers
+int             bThreadEnded=0;
+int             bSpuInit=0;
+int             bSPUIsOpen=0;
+
+#ifdef _WINDOWS
+HWND    hWMain=0;                                      // window handle
+HWND    hWDebug=0;
+HWND    hWRecord=0;
+static HANDLE   hMainThread;                           
+#else
+// 2003/06/07 - Pete
+#ifndef NOTHREADLIB
+static pthread_t thread = -1;                          // thread id (linux)
+#endif
+#endif
+
+unsigned long dwNewChannel2[2];                        // flags for faster testing, if new channel starts
+unsigned long dwEndChannel2[2];
+
+// UNUSED IN PS2 YET
+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)
+
+const int f[5][2] = {   {    0,  0  },
+                        {   60,  0  },
+                        {  115, -52 },
+                        {   98, -55 },
+                        {  122, -60 } };
+int SSumR[NSSIZE];
+int SSumL[NSSIZE];
+int iCycle=0;
+short * pS;
+
+static int lastch=-1;      // last channel processed on spu irq in timer mode
+static int lastns=0;       // last ns pos
+static int iSecureStart=0; // secure start counter
+
+////////////////////////////////////////////////////////////////////////
+// CODE AREA
+////////////////////////////////////////////////////////////////////////
+
+// dirty inline func includes
+
+#include "reverb.c"        
+#include "adsr.c"
+
+////////////////////////////////////////////////////////////////////////
+// helpers for simple interpolation
+
+//
+// easy interpolation on upsampling, no special filter, just "Pete's common sense" tm
+//
+// instead of having n equal sample values in a row like:
+//       ____
+//           |____
+//
+// we compare the current delta change with the next delta change.
+//
+// if curr_delta is positive,
+//
+//  - and next delta is smaller (or changing direction):
+//         \.
+//          -__
+//
+//  - and next delta significant (at least twice) bigger:
+//         --_
+//            \.
+//
+//  - and next delta is nearly same:
+//          \.
+//           \.
+//
+//
+// if curr_delta is negative,
+//
+//  - and next delta is smaller (or changing direction):
+//          _--
+//         /
+//
+//  - and next delta significant (at least twice) bigger:
+//            /
+//         __- 
+//         
+//  - and next delta is nearly same:
+//           /
+//          /
+//     
+
+static unsigned long long SexyTime64(void)
+{
+ struct timeval tv;
+ unsigned long long ret;
+
+ gettimeofday(&tv,0);
+ ret=tv.tv_sec;
+ ret*=1000000;
+ ret+=tv.tv_usec;
+ return(ret);
+}
+
+INLINE void InterpolateUp(int ch)
+{
+ if(s_chan[ch].SB[32]==1)                              // flag == 1? calc step and set flag... and don't change the value in this pass
+  {
+   const int id1=s_chan[ch].SB[30]-s_chan[ch].SB[29];  // curr delta to next val
+   const int id2=s_chan[ch].SB[31]-s_chan[ch].SB[30];  // and next delta to next-next val :)
+
+   s_chan[ch].SB[32]=0;
+
+   if(id1>0)                                           // curr delta positive
+    {
+     if(id2<id1)
+      {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
+     else
+     if(id2<(id1<<1))
+      s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
+     else
+      s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; 
+    }
+   else                                                // curr delta negative
+    {
+     if(id2>id1)
+      {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
+     else
+     if(id2>(id1<<1))
+      s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
+     else
+      s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; 
+    }
+  }
+ else
+ if(s_chan[ch].SB[32]==2)                              // flag 1: calc step and set flag... and don't change the value in this pass
+  {
+   s_chan[ch].SB[32]=0;
+
+   s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L;
+   if(s_chan[ch].sinc<=0x8000)
+        s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1));
+   else s_chan[ch].SB[29]+=s_chan[ch].SB[28];
+  }
+ else                                                  // no flags? add bigger val (if possible), calc smaller step, set flag1
+  s_chan[ch].SB[29]+=s_chan[ch].SB[28];
+}
+
+//
+// even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm
+//
+
+INLINE void InterpolateDown(int ch)
+{
+ if(s_chan[ch].sinc>=0x20000L)                                 // we would skip at least one val?
+  {
+   s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight
+   if(s_chan[ch].sinc>=0x30000L)                               // we would skip even more vals?
+    s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// helpers for gauss interpolation
+
+#define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos])
+#define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3])
+
+#include "gauss_i.h"
+
+////////////////////////////////////////////////////////////////////////
+
+#include "xa.c"
+
+////////////////////////////////////////////////////////////////////////
+// START SOUND... called by main thread to setup a new sound on a channel
+////////////////////////////////////////////////////////////////////////
+
+INLINE void StartSound(int ch)
+{
+ dwNewChannel2[ch/24]&=~(1<<(ch%24));                  // clear new channel bit
+ dwEndChannel2[ch/24]&=~(1<<(ch%24));                  // clear end channel bit
+ 
+ StartADSR(ch);
+ StartREVERB(ch);      
+                          
+ s_chan[ch].pCurr=s_chan[ch].pStart;                   // set sample start
+                         
+ 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;
+
+ if(iUseInterpolation>=2)                              // gauss interpolation?
+      {s_chan[ch].spos=0x30000L;s_chan[ch].SB[28]=0;}  // -> start with more decoding
+ else {s_chan[ch].spos=0x10000L;s_chan[ch].SB[31]=0;}  // -> no/simple interpolation starts with one 44100 decoding
+}
+
+////////////////////////////////////////////////////////////////////////
+// MAIN SPU FUNCTION
+// here is the main job handler... thread, timer or direct func call
+// basically the whole sound processing is done in this fat func!
+////////////////////////////////////////////////////////////////////////
+
+// 5 ms waiting phase, if buffer is full and no new sound has to get started
+// .. can be made smaller (smallest val: 1 ms), but bigger waits give
+// better performance
+
+#define PAUSE_W 5
+#define PAUSE_L 5000
+
+////////////////////////////////////////////////////////////////////////
+
+int iSpuAsyncWait=0;
+
+#ifdef _WINDOWS
+static VOID CALLBACK MAINProc(UINT nTimerId,UINT msg,DWORD dwUser,DWORD dwParam1, DWORD dwParam2)
+#else
+static void *MAINThread(void *arg)
+#endif
+{
+ int s_1,s_2,fa,ns,voldiv=iVolume;
+ unsigned char * start;unsigned int nSample;
+ int ch,predict_nr,shift_factor,flags,d,s;
+ int gpos,bIRQReturn=0;
+
+ while(!bEndThread)                                    // until we are shutting down
+  {
+   //--------------------------------------------------//
+   // ok, at the beginning we are looking if there is
+   // enuff free place in the dsound/oss buffer to
+   // fill in new data, or if there is a new channel to start.
+   // if not, we wait (thread) or return (timer/spuasync)
+   // until enuff free place is available/a new channel gets
+   // started
+
+   if(dwNewChannel2[0] || dwNewChannel2[1])            // new channel should start immedately?
+    {                                                  // (at least one bit 0 ... MAXCHANNEL is set?)
+     iSecureStart++;                                   // -> set iSecure
+     if(iSecureStart>5) iSecureStart=0;                //    (if it is set 5 times - that means on 5 tries a new samples has been started - in a row, we will reset it, to give the sound update a chance)
+    }
+   else iSecureStart=0;                                // 0: no new channel should start
+
+   while(!iSecureStart && !bEndThread               // no new start? no thread end?
+#if 0
+        && (SoundGetBytesBuffered()>TESTSIZE)
+#endif
+	)           // and still enuff data in sound buffer?
+    {
+     iSecureStart=0;                                   // reset secure
+
+#ifdef _WINDOWS
+     if(iUseTimer)                                     // no-thread mode?
+      {
+       if(iUseTimer==1)                                // -> ok, timer mode 1: setup a oneshot timer of x ms to wait
+        timeSetEvent(PAUSE_W,1,MAINProc,0,TIME_ONESHOT);
+       return;                                         // -> and done this time (timer mode 1 or 2)
+      }
+                                                       // win thread mode:
+     Sleep(PAUSE_W);                                   // sleep for x ms (win)
+#else
+     if(iUseTimer) return 0;                           // linux no-thread mode? bye
+     usleep(PAUSE_L);                                  // else sleep for x ms (linux)
+#endif
+
+     if(dwNewChannel2[0] || dwNewChannel2[1]) 
+      iSecureStart=1;                                  // if a new channel kicks in (or, of course, sound buffer runs low), we will leave the loop
+    }
+
+   //--------------------------------------------------// continue from irq handling in timer mode? 
+
+   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
+    }
+
+   //--------------------------------------------------//
+   //- main channel loop                              -// 
+   //--------------------------------------------------//
+    {
+     for(ch=0;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(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq)   // new psx frequency?
+        {
+         s_chan[ch].iUsedFreq=s_chan[ch].iActFreq;     // -> take it and calc steps
+         s_chan[ch].sinc=s_chan[ch].iRawPitch<<4;
+         if(!s_chan[ch].sinc) s_chan[ch].sinc=1;
+         if(iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simle imterpolation mode: set flag
+        }
+
+       ns=0;
+       while(ns<NSSIZE)                                // loop until 1 ms of data is reached
+        {
+         while(s_chan[ch].spos>=0x10000L)
+          {
+           if(s_chan[ch].iSBPos==28)                   // 28 reached?
+            {
+             start=s_chan[ch].pCurr;                   // set up the current pos
+
+             if (start == (unsigned char*)-1)          // special "stop" sign
+              {
+               s_chan[ch].bOn=0;                       // -> turn everything off
+               s_chan[ch].ADSRX.lVolume=0;
+               s_chan[ch].ADSRX.EnvelopeVol=0;
+               goto ENDX;                              // -> and done for this channel
+              }
+
+             s_chan[ch].iSBPos=0;
+
+             //////////////////////////////////////////// spu irq handler here? mmm... do it later
+
+             s_1=s_chan[ch].s_1;
+             s_2=s_chan[ch].s_2;
+
+             predict_nr=(int)*start;start++;
+             shift_factor=predict_nr&0xf;
+             predict_nr >>= 4;
+             flags=(int)*start;start++;
+
+             // -------------------------------------- // 
+
+             for (nSample=0;nSample<28;start++)      
+              {
+               d=(int)*start;
+               s=((d&0xf)<<12);
+               if(s&0x8000) s|=0xffff0000;
+
+               fa=(s >> shift_factor);
+               fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
+               s_2=s_1;s_1=fa;
+               s=((d & 0xf0) << 8);
+
+               s_chan[ch].SB[nSample++]=fa;
+
+               if(s&0x8000) s|=0xffff0000;
+               fa=(s>>shift_factor);              
+               fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
+               s_2=s_1;s_1=fa;
+
+               s_chan[ch].SB[nSample++]=fa;
+              }     
+
+             //////////////////////////////////////////// irq check
+
+             if(spuCtrl2[ch/24]&0x40)                  // some irq active?
+              {
+               if((pSpuIrq[ch/24] >  start-16 &&       // irq address reached?
+                   pSpuIrq[ch/24] <= start) ||
+                  ((flags&1) &&                        // special: irq on looping addr, when stop/loop flag is set 
+                   (pSpuIrq[ch/24] >  s_chan[ch].pLoop-16 &&
+                    pSpuIrq[ch/24] <= s_chan[ch].pLoop)))
+                {
+                 s_chan[ch].iIrqDone=1;                // -> debug flag
+
+                 if(irqCallback) irqCallback();        // -> call main emu (not supported in SPU2 right now)
+                 else
+                  {
+                   if(ch<24) InterruptDMA4();            // -> let's see what is happening if we call our irqs instead ;)
+                   else      InterruptDMA7();
+                  }
+                  
+                 if(iSPUIRQWait)                       // -> option: wait after irq for main emu
+                  {
+                   iSpuAsyncWait=1;
+                   bIRQReturn=1;
+                  }
+                }
+              }
+      
+             //////////////////////////////////////////// flag handler
+
+             if((flags&4) && (!s_chan[ch].bIgnoreLoop))
+              s_chan[ch].pLoop=start-16;               // loop adress
+
+             if(flags&1)                               // 1: stop/loop
+              {
+               dwEndChannel2[ch/24]|=(1<<(ch%24));
+              
+               // We play this block out first...
+               //if(!(flags&2)|| s_chan[ch].pLoop==NULL)   
+                                                       // 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
+                 start = (unsigned char*)-1;
+                }
+               else
+                {
+                 start = s_chan[ch].pLoop;
+                }
+              }
+
+             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=SexyTime64()+2500;
+
+                 while(iSpuAsyncWait && !bEndThread && 
+                       SexyTime64()<dwWatchTime)
+#ifdef _WINDOWS
+                     Sleep(1);
+#else
+                     usleep(1000L);
+#endif
+                       
+                }
+               else
+                {
+                 lastch=ch; 
+                 lastns=ns;
+
+#ifdef _WINDOWS
+                 return;
+#else
+                 return 0;
+#endif
+                }
+              }
+
+             ////////////////////////////////////////////
+
+GOON: ;
+
+            }
+
+           fa=s_chan[ch].SB[s_chan[ch].iSBPos++];      // get sample data
+
+           if((spuCtrl2[ch/24]&0x4000)==0) fa=0;       // muted?
+           else                                        // else adjust
+            {
+             if(fa>32767L)  fa=32767L;
+             if(fa<-32767L) fa=-32767L;              
+            }
+
+           if(iUseInterpolation>=2)                    // gauss/cubic interpolation
+            {
+             gpos = s_chan[ch].SB[28];
+             gval0 = fa;          
+             gpos = (gpos+1) & 3;
+             s_chan[ch].SB[28] = gpos;
+            }
+           else
+           if(iUseInterpolation==1)                    // simple interpolation
+            {
+             s_chan[ch].SB[28] = 0;                    
+             s_chan[ch].SB[29] = s_chan[ch].SB[30];    // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour'
+             s_chan[ch].SB[30] = s_chan[ch].SB[31];
+             s_chan[ch].SB[31] = fa;
+             s_chan[ch].SB[32] = 1;                    // -> flag: calc new interolation
+            }
+           else s_chan[ch].SB[29]=fa;                  // no interpolation
+
+           s_chan[ch].spos -= 0x10000L;
+          }
+
+         ////////////////////////////////////////////////
+         // noise handler... just produces some noise data
+         // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used...
+         // and sometimes the noise will be used as fmod modulation... pfff
+
+         if(s_chan[ch].bNoise)
+          {
+           if((dwNoiseVal<<=1)&0x80000000L)
+            {
+             dwNoiseVal^=0x0040001L;
+             fa=((dwNoiseVal>>2)&0x7fff);
+             fa=-fa;
+            }
+           else fa=(dwNoiseVal>>2)&0x7fff;
+
+           // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val
+           fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl2[ch/24]&0x3f00)>>9))+1));
+           if(fa>32767L)  fa=32767L;
+           if(fa<-32767L) fa=-32767L;              
+           s_chan[ch].iOldNoise=fa;
+
+           if(iUseInterpolation<2)                     // no gauss/cubic interpolation?
+            s_chan[ch].SB[29] = fa;                    // -> store noise val in "current sample" slot
+          }                                            //----------------------------------------
+         else                                          // NO NOISE (NORMAL SAMPLE DATA) HERE 
+          {//------------------------------------------//
+           if(iUseInterpolation==3)                    // cubic interpolation
+            {
+             long xd;  
+             xd = ((s_chan[ch].spos) >> 1)+1;
+             gpos = s_chan[ch].SB[28];
+
+             fa  = gval(3) - 3*gval(2) + 3*gval(1) - gval0;
+             fa *= (xd - (2<<15)) / 6;
+             fa >>= 15;
+             fa += gval(2) - gval(1) - gval(1) + gval0;
+             fa *= (xd - (1<<15)) >> 1;
+             fa >>= 15;
+             fa += gval(1) - gval0;
+             fa *= xd;
+             fa >>= 15;
+             fa = fa + gval0;
+            }
+           //------------------------------------------//
+           else
+           if(iUseInterpolation==2)                    // gauss interpolation
+            {
+             int vl, vr;
+             vl = (s_chan[ch].spos >> 6) & ~3;
+             gpos = s_chan[ch].SB[28];
+             vr=(gauss[vl]*gval0)&~2047;
+             vr+=(gauss[vl+1]*gval(1))&~2047;
+             vr+=(gauss[vl+2]*gval(2))&~2047;
+             vr+=(gauss[vl+3]*gval(3))&~2047;
+             fa = vr>>11;
+/*
+             vr=(gauss[vl]*gval0)>>9;
+             vr+=(gauss[vl+1]*gval(1))>>9;
+             vr+=(gauss[vl+2]*gval(2))>>9;
+             vr+=(gauss[vl+3]*gval(3))>>9;
+             fa = vr>>2;
+*/
+            }
+           //------------------------------------------//
+           else
+           if(iUseInterpolation==1)                    // simple interpolation
+            {
+             if(s_chan[ch].sinc<0x10000L)              // -> upsampling?
+                  InterpolateUp(ch);                   // --> interpolate up
+             else InterpolateDown(ch);                 // --> else down
+             fa=s_chan[ch].SB[29];
+            }
+           //------------------------------------------//
+           else fa=s_chan[ch].SB[29];                  // no interpolation
+          }
+
+         s_chan[ch].sval = (MixADSR(ch) * fa) / 1023;  // add adsr
+
+         if(s_chan[ch].bFMod==2)                       // fmod freq channel
+          {
+           int NP=s_chan[ch+1].iRawPitch;
+
+           NP=((32768L+s_chan[ch].sval)*NP)/32768L;    // mmm... I still need to adjust that to 1/48 khz... we will wait for the first game/demo using it to decide how to do it :)
+
+           if(NP>0x3fff) NP=0x3fff;
+           if(NP<0x1)    NP=0x1;
+                                                        
+           NP=(44100L*NP)/(4096L);                     // calc frequency
+
+           s_chan[ch+1].iActFreq=NP;
+           s_chan[ch+1].iUsedFreq=NP;
+           s_chan[ch+1].sinc=(((NP/10)<<16)/4410);
+           if(!s_chan[ch+1].sinc) s_chan[ch+1].sinc=1;
+           if(iUseInterpolation==1)                    // freq change in sipmle interpolation mode
+            s_chan[ch+1].SB[32]=1;
+
+// mmmm... set up freq decoding positions?
+//           s_chan[ch+1].iSBPos=28;
+//           s_chan[ch+1].spos=0x10000L;
+          }                    
+         else                   
+          {                                          
+           //////////////////////////////////////////////
+           // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
+
+           if(s_chan[ch].iMute) 
+            s_chan[ch].sval=0;                         // debug mute
+           else
+            {
+             if(s_chan[ch].bVolumeL)
+              SSumL[ns]+=(s_chan[ch].sval*s_chan[ch].iLeftVolume)/0x4000L;
+             if(s_chan[ch].bVolumeR)
+              SSumR[ns]+=(s_chan[ch].sval*s_chan[ch].iRightVolume)/0x4000L;
+            }
+        
+           //////////////////////////////////////////////
+           // now let us store sound data for reverb    
+                                                          
+           if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns);
+          }
+
+         ////////////////////////////////////////////////
+         // ok, go on until 1 ms data of this channel is collected
+                                                       
+         ns++;                                          
+         s_chan[ch].spos += s_chan[ch].sinc;             
+                                                              
+        }        
+ENDX:   ;                                                      
+      }
+    }                                                         
+   
+  //---------------------------------------------------//
+  //- here we have another 1 ms of sound data
+  //---------------------------------------------------//
+  // mix XA infos (if any)
+  sampcount++;
+
+
+  if(XAPlay!=XAFeed || XARepeat) MixXA();
+  
+  ///////////////////////////////////////////////////////
+  // 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,0);
+      SSumL[ns]+=MixREVERBLeft(ns,1);
+                                              
+      dl=SSumL[ns]/voldiv;SSumL[ns]=0;
+      if(dl<-32767) dl=-32767;if(dl>32767) dl=32767;
+        
+      SSumR[ns]+=MixREVERBRight(0);
+      SSumR[ns]+=MixREVERBRight(1);
+
+      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++)
+   {            
+    SSumL[ns]+=MixREVERBLeft(ns,0);
+    SSumL[ns]+=MixREVERBLeft(ns,1);
+                                              
+    d=SSumL[ns]/voldiv;SSumL[ns]=0;
+    if(d<-32767) d=-32767;if(d>32767) d=32767;
+    *pS++=d;
+        
+    SSumR[ns]+=MixREVERBRight(0);
+    SSumR[ns]+=MixREVERBRight(1);
+
+    d=SSumR[ns]/voldiv;SSumR[ns]=0;
+    if(d<-32767) d=-32767;if(d>32767) d=32767;
+    *pS++=d;
+   }
+
+  InitREVERB();
+
+ }
+
+ // end of big main loop...
+
+ bThreadEnded=1;
+
+#ifndef _WINDOWS
+ return 0;
+#endif
+}
+
+void sexypsf_stop(void)
+{
+ decaybegin=decayend=0;
+}
+
+void SPUendflush(void)
+{
+   if((seektime!=~0) && seektime>sampcount)
+   {
+    pS=(short *)pSpuBuffer;
+    sexypsf_update(0,0);
+   }
+   else if((unsigned short *)pS>((unsigned short *)pSpuBuffer+1024))
+   {
+    sexypsf_update((unsigned short *)pSpuBuffer,(unsigned short *)pS-(unsigned short*)pSpuBuffer);
+    pS=(short *)pSpuBuffer;
+   }
+}
+
+////////////////////////////////////////////////////////////////////////
+// WINDOWS THREAD... simply calls the timer func and stays forever :)
+////////////////////////////////////////////////////////////////////////
+
+#ifdef _WINDOWS
+
+DWORD WINAPI MAINThreadEx(LPVOID lpParameter)
+{
+ MAINProc(0,0,0,0,0);
+ return 0;
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+// SPU ASYNC... even newer epsxe func
+//  1 time every 'cycle' cycles... harhar
+////////////////////////////////////////////////////////////////////////
+
+int sexypsf_seek(unsigned long t)
+{
+ seektime=t*441/10;
+ if(seektime>sampcount) return(1);
+ return(0);
+}
+
+EXPORT_GCC void CALLBACK SPU2async(unsigned long cycle)
+{
+ if(iSpuAsyncWait)
+  {
+   iSpuAsyncWait++;
+   if(iSpuAsyncWait<=64) return;
+   iSpuAsyncWait=0;
+  }
+
+#ifdef _WINDOWS
+ if(iDebugMode==2)
+  {
+   if(IsWindow(hWDebug)) DestroyWindow(hWDebug);
+   hWDebug=0;iDebugMode=0;
+  }
+ if(iRecordMode==2)
+  {
+   if(IsWindow(hWRecord)) DestroyWindow(hWRecord);
+   hWRecord=0;iRecordMode=0;
+  }
+#endif
+
+ if(iUseTimer==2)                                      // special mode, only used in Linux by this spu (or if you enable the experimental Windows mode)
+  {
+   if(!bSpuInit) return;                               // -> no init, no call
+
+#ifdef _WINDOWS
+   MAINProc(0,0,0,0,0);                                // -> experimental win mode... not really tested... don't like the drawbacks
+#else
+   MAINThread(0);                                      // -> linux high-compat mode
+#endif
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// XA AUDIO
+////////////////////////////////////////////////////////////////////////
+
+// dummy func... not used yet
+EXPORT_GCC void CALLBACK SPU2playADPCMchannel(xa_decode_t *xap)
+{
+ if(!iUseXA)    return;                                // no XA? bye
+ if(!xap)       return;
+ if(!xap->freq) return;                                // no xa freq ? bye
+
+ FeedXA(xap);                                          // call main XA feeder
+}
+
+////////////////////////////////////////////////////////////////////////
+// INIT/EXIT STUFF
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+// SPUINIT: this func will be called first by the main emu
+////////////////////////////////////////////////////////////////////////
+
+#ifdef _WINDOWS
+static HINSTANCE hIRE = NULL;
+#endif
+              
+EXPORT_GCC long CALLBACK SPU2init(void)
+{
+ spuMemC=(unsigned char *)spuMem;                      // just small setup
+ memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN));
+ memset(rvb,0,2*sizeof(REVERBInfo));
+
+ InitADSR();
+
+#ifdef _WINDOWS
+ if(hIRE==NULL) hIRE=LoadLibrary("Riched32.dll ");     // needed for debug output
+#endif
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+// 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));
+ pS=(short *)pSpuBuffer;                               // setup soundbuffer pointer
+
+ bEndThread=0;                                         // init thread vars
+ bThreadEnded=0; 
+ bSpuInit=1;                                           // flag: we are inited
+
+#ifdef _WINDOWS
+
+ if(iUseTimer==1)                                      // windows: use timer
+  {
+   timeBeginPeriod(1);
+   timeSetEvent(1,1,MAINProc,0,TIME_ONESHOT);
+  }
+ else 
+ if(iUseTimer==0)                                      // windows: use thread
+  {
+   //_beginthread(MAINThread,0,NULL);
+   DWORD dw;
+   hMainThread=CreateThread(NULL,0,MAINThreadEx,0,0,&dw);
+   SetThreadPriority(hMainThread,
+                     //THREAD_PRIORITY_TIME_CRITICAL);
+                     THREAD_PRIORITY_HIGHEST);
+  }
+
+#else
+
+#ifndef NOTHREADLIB
+ if(!iUseTimer)                                        // linux: use thread
+  {
+   pthread_create(&thread, NULL, MAINThread, NULL);
+  }
+#endif
+
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////
+// REMOVETIMER: kill threads/timers
+////////////////////////////////////////////////////////////////////////
+
+void RemoveTimer(void)
+{
+ bEndThread=1;                                         // raise flag to end thread
+
+#ifdef _WINDOWS
+
+ if(iUseTimer!=2)                                      // windows thread?
+  {
+   while(!bThreadEnded) {Sleep(5L);}                   // -> wait till thread has ended
+   Sleep(5L);
+  }
+ if(iUseTimer==1) timeEndPeriod(1);                    // windows timer? stop it
+
+#else
+
+#ifndef NOTHREADLIB
+ if(!iUseTimer)                                        // linux tread?
+  {
+   int i=0;
+   while(!bThreadEnded && i<2000) {usleep(1000L);i++;} // -> wait until thread has ended
+   if(thread!=-1) {pthread_cancel(thread);thread=-1;}  // -> cancel thread anyway
+  }
+#endif
+
+#endif
+
+ bThreadEnded=0;                                       // no more spu is running
+ bSpuInit=0;
+}
+
+////////////////////////////////////////////////////////////////////////
+// SETUPSTREAMS: init most of the spu buffers
+////////////////////////////////////////////////////////////////////////
+
+void SetupStreams(void)
+{ 
+ int i;
+
+ pSpuBuffer=(unsigned char *)malloc(32768);            // alloc mixing buffer
+
+ i=NSSIZE*2;
+
+ sRVBStart[0] = (int *)malloc(i*4);                    // alloc reverb buffer
+ memset(sRVBStart[0],0,i*4);
+ sRVBEnd[0]  = sRVBStart[0] + i;
+ sRVBPlay[0] = sRVBStart[0];
+ sRVBStart[1] = (int *)malloc(i*4);                    // alloc reverb buffer
+ memset(sRVBStart[1],0,i*4);
+ sRVBEnd[1]  = sRVBStart[1] + i;
+ sRVBPlay[1] = sRVBStart[1];
+
+ XAStart =                                             // alloc xa buffer (not used here anyway)
+  (unsigned long *)malloc(48000*4);
+ XAPlay  = XAStart;
+ XAFeed  = XAStart;
+ XAEnd   = XAStart + 48000;
+
+ 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].pLoop=spuMemC;
+   s_chan[i].pStart=spuMemC;
+   s_chan[i].pCurr=spuMemC;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// REMOVESTREAMS: free most buffer
+////////////////////////////////////////////////////////////////////////
+
+void RemoveStreams(void)
+{ 
+ free(pSpuBuffer);                                     // free mixing buffer
+ pSpuBuffer=NULL;
+ free(sRVBStart[0]);                                   // free reverb buffer
+ sRVBStart[0]=0;
+ free(sRVBStart[1]);                                   // free reverb buffer
+ sRVBStart[1]=0;
+ free(XAStart);                                        // free XA buffer
+ XAStart=0;
+
+/*
+ int i;
+ for(i=0;i<MAXCHAN;i++)
+  {
+   WaitForSingleObject(s_chan[i].hMutex,2000);
+   ReleaseMutex(s_chan[i].hMutex);
+   if(s_chan[i].hMutex)    
+    {CloseHandle(s_chan[i].hMutex);s_chan[i].hMutex=0;}
+  }
+*/
+}
+
+
+////////////////////////////////////////////////////////////////////////
+// SPUOPEN: called by main emu after init
+////////////////////////////////////////////////////////////////////////
+   
+EXPORT_GCC long CALLBACK SPU2open(void *pDsp)                          
+{
+#ifdef _WINDOWS
+ HWND hW=0;
+#endif
+ 
+ if(bSPUIsOpen) return 0;                              // security for some stupid main emus
+
+ iUseXA=1;                                             // just small setup
+ iVolume=3;
+ bEndThread=0;
+ bThreadEnded=0;
+ spuMemC=(unsigned char *)spuMem;      
+ memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN));
+ pSpuIrq[0]=0;
+ pSpuIrq[1]=0;
+ iSPUIRQWait=1;
+ dwNewChannel2[0]=0;
+ dwNewChannel2[1]=0;
+ dwEndChannel2[0]=0;
+ dwEndChannel2[1]=0;
+ spuCtrl2[0]=0;              
+ spuCtrl2[1]=0;              
+ spuStat2[0]=0;
+ spuStat2[1]=0;
+ spuIrq2[0]=0;             
+ spuIrq2[1]=0;             
+ spuAddr2[0]=0xffffffff;   
+ spuAddr2[1]=0xffffffff;   
+ spuRvbAddr2[0]=0;
+ spuRvbAddr2[1]=0;
+ spuRvbAEnd2[0]=0;
+ spuRvbAEnd2[1]=0;
+ 
+#ifdef _WINDOWS
+ LastWrite=0xffffffff;LastPlay=0;                      // init some play vars
+ if(!IsWindow(hW)) hW=GetActiveWindow();
+ hWMain = hW;                                          // store hwnd
+#endif
+
+ SetupStreams();                                       // prepare streaming
+
+ SetupTimer();                                         // timer for feeding data
+
+ bSPUIsOpen=1;
+
+#ifdef _WINDOWS
+ if(iDebugMode)                                        // windows debug dialog
+  {
+   hWDebug=CreateDialog(hInst,MAKEINTRESOURCE(IDD_DEBUG),
+                        NULL,(DLGPROC)DebugDlgProc);
+   SetWindowPos(hWDebug,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE);
+   UpdateWindow(hWDebug);
+   SetFocus(hWMain);
+  }
+
+ if(iRecordMode)                                        // windows recording dialog
+  {
+   hWRecord=CreateDialog(hInst,MAKEINTRESOURCE(IDD_RECORD),
+                        NULL,(DLGPROC)RecordDlgProc);
+   SetWindowPos(hWRecord,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE);
+   UpdateWindow(hWRecord);
+   SetFocus(hWMain);
+  }
+#endif
+
+ return 0;        
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// not used yet
+#ifndef _WINDOWS
+void SPU2setConfigFile(char * pCfg)
+{
+
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////
+// SPUCLOSE: called before shutdown
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2close(void)
+{
+ if(!bSPUIsOpen) return;                               // some security
+
+ bSPUIsOpen=0;                                         // no more open
+
+#ifdef _WINDOWS
+ if(IsWindow(hWDebug)) DestroyWindow(hWDebug);
+ hWDebug=0;
+ if(IsWindow(hWRecord)) DestroyWindow(hWRecord);
+ hWRecord=0;
+#endif
+
+ RemoveTimer();                                        // no more feeding
+
+ RemoveStreams();                                      // no more streaming
+}
+
+////////////////////////////////////////////////////////////////////////
+// SPUSHUTDOWN: called by main emu on final exit
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2shutdown(void)
+{
+#ifdef _WINDOWS
+ if(hIRE!=NULL) {FreeLibrary(hIRE);hIRE=NULL;}
+#endif
+
+ return;
+}
+
+////////////////////////////////////////////////////////////////////////
+// SPUTEST: we don't test, we are always fine ;)
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC long CALLBACK SPU2test(void)
+{
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+// SPUCONFIGURE: call config dialog
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2configure(void)
+{
+
+}
+
+////////////////////////////////////////////////////////////////////////
+// SPUABOUT: show about window
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2about(void)
+{
+
+}
+
+////////////////////////////////////////////////////////////////////////
+// SETUP CALLBACKS
+// this functions will be called once, 
+// passes a callback that should be called on SPU-IRQ/cdda volume change
+////////////////////////////////////////////////////////////////////////
+
+// not used yet
+EXPORT_GCC void CALLBACK SPU2irqCallback(void (CALLBACK *callback)(void))
+{
+ irqCallback = callback;
+}
+
+// not used yet
+EXPORT_GCC void CALLBACK SPU2registerCallback(void (CALLBACK *callback)(void))
+{
+ irqCallback = callback;
+}
+
+// not used yet
+EXPORT_GCC void CALLBACK SPU2registerCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short))
+{
+ cddavCallback = CDDAVcallback;
+}
+
+////////////////////////////////////////////////////////////////////////
+// COMMON PLUGIN INFO FUNCS
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC char * CALLBACK PS2EgetLibName(void)
+{
+ return libraryName;        
+}                         
+
+#define PS2E_LT_SPU2 0x4
+
+EXPORT_GCC unsigned long CALLBACK PS2EgetLibType(void)
+{
+ return PS2E_LT_SPU2;
+}
+
+EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type)
+{
+ unsigned char v=version;
+
+ // key hack to fake a lower version:
+ //if(GetAsyncKeyState(VK_SHIFT)&0x8000) v--;
+
+ // compile hack to set lib version to PCSX2 0.6 standards
+ //v=2;
+
+ return v<<16|revision<<8|build;
+}
+
+// not used yet
+char * SPU2getLibInfos(void)
+{
+ return libraryInfo;
+}
+
+////////////////////////////////////////////////////////////////////////
+
--- a/Plugins/Input/sexypsf/spu/spu.h	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/spu.h	Sun Mar 19 12:51:03 2006 -0800
@@ -1,8 +1,34 @@
-int SPUinit(void);
-int SPUopen(void);
-void SPUsetlength(s32 stop, s32 fade);
-int SPUclose(void);
-void SPUendflush(void);
-
-// External, called by SPU code.
-void SPUirq(void);
+/***************************************************************************
+                            spu.h  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+void SetupTimer(void);
+void RemoveTimer(void);
+EXPORT_GCC void CALLBACK SPU2playADPCMchannel(xa_decode_t *xap);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/stdafx.c	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+//	spuPeopsSound.pch will be the pre-compiled header
+//	stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
--- a/Plugins/Input/sexypsf/spu/stdafx.h	Sat Mar 18 14:48:04 2006 -0800
+++ b/Plugins/Input/sexypsf/spu/stdafx.h	Sun Mar 19 12:51:03 2006 -0800
@@ -24,8 +24,63 @@
 //
 //*************************************************************************//
 
+//////////////////////////////////////////////////////////
+// WINDOWS
+//////////////////////////////////////////////////////////
+
+#ifdef _WINDOWS
+
+#ifdef _GCC
+#define EXPORT_GCC  __declspec (dllexport)
+#else
+#define EXPORT_GCC
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#define STRICT
+#include <windows.h>                
+#include <windowsx.h>
+#include "mmsystem.h"
+#include <process.h>
 #include <stdlib.h>
-#include <string.h> 
-#include <math.h>  
+
+// enable that for auxprintf();
+//#define SMALLDEBUG
+//#include <dbgout.h>
+//void auxprintf (LPCTSTR pFormat, ...);
+
+#define INLINE __inline
+
+//////////////////////////////////////////////////////////
+// LINUX
+//////////////////////////////////////////////////////////
+#else
+
+#define EXPORT_GCC
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/soundcard.h>
+#include <unistd.h>
+#ifndef NOTHREADLIB
+#include <pthread.h>
+#endif
+#define RRand(range) (random()%range)
+#include <string.h>
+#include <sys/time.h>
+#include <math.h>
+
+#undef CALLBACK
+#define CALLBACK
+#define DWORD unsigned long
+#define LOWORD(l)           ((unsigned short)(l))
+#define HIWORD(l)           ((unsigned short)(((unsigned long)(l) >> 16) & 0xFFFF))
 
 #define INLINE inline
+
+#endif
+
+#include "psemuxa.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/xa.c	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,363 @@
+/***************************************************************************
+                            xa.c  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2003/02/18 - kode54
+// - added gaussian interpolation
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_XA
+
+// will be included from spu.c
+#ifdef _IN_SPU
+
+////////////////////////////////////////////////////////////////////////
+// XA GLOBALS
+////////////////////////////////////////////////////////////////////////
+
+xa_decode_t   * xapGlobal=0;
+
+unsigned long * XAFeed  = NULL;
+unsigned long * XAPlay  = NULL;
+unsigned long * XAStart = NULL;
+unsigned long * XAEnd   = NULL;
+
+unsigned long   XARepeat  = 0;
+unsigned long   XALastVal = 0;
+
+int             iLeftXAVol  = 32767;
+int             iRightXAVol = 32767;
+
+static int gauss_ptr = 0;
+static int gauss_window[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+#define gvall0 gauss_window[gauss_ptr]
+#define gvall(x) gauss_window[(gauss_ptr+x)&3]
+#define gvalr0 gauss_window[4+gauss_ptr]
+#define gvalr(x) gauss_window[4+((gauss_ptr+x)&3)]
+
+////////////////////////////////////////////////////////////////////////
+// MIX XA 
+////////////////////////////////////////////////////////////////////////
+
+INLINE void MixXA(void)
+{
+ int ns;
+
+ for(ns=0;ns<NSSIZE && XAPlay!=XAFeed;ns++)
+  {
+   XALastVal=*XAPlay++;
+   if(XAPlay==XAEnd) XAPlay=XAStart;
+   SSumL[ns]+=(((short)(XALastVal&0xffff))       * iLeftXAVol)/32767;
+   SSumR[ns]+=(((short)((XALastVal>>16)&0xffff)) * iRightXAVol)/32767;
+  }
+
+ if(XAPlay==XAFeed && XARepeat)
+  {
+   XARepeat--;
+   for(;ns<NSSIZE;ns++)
+    {
+     SSumL[ns]+=(((short)(XALastVal&0xffff))       * iLeftXAVol)/32767;
+     SSumR[ns]+=(((short)((XALastVal>>16)&0xffff)) * iRightXAVol)/32767;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+// FEED XA 
+////////////////////////////////////////////////////////////////////////
+
+INLINE void FeedXA(xa_decode_t *xap)
+{
+ int sinc,spos,i,iSize,iPlace,vl,vr;
+
+ if(!bSPUIsOpen) return;
+
+ xapGlobal = xap;                                      // store info for save states
+ XARepeat  = 100;                                      // set up repeat
+
+ iSize=((44100*xap->nsamples)/xap->freq);              // get size
+ if(!iSize) return;                                    // none? bye
+
+ if(XAFeed<XAPlay) iPlace=XAPlay-XAFeed;               // how much space in my buf?
+ else              iPlace=(XAEnd-XAFeed) + (XAPlay-XAStart);
+
+ if(iPlace==0) return;                                 // no place at all
+
+ //----------------------------------------------------//
+ if(iXAPitch)                                          // pitch change option?
+  {
+   static DWORD dwLT=0;
+   static DWORD dwFPS=0;
+   static int   iFPSCnt=0;
+   static int   iLastSize=0;
+   static DWORD dwL1=0;
+   DWORD dw=SexyTime64(),dw1,dw2;
+
+   iPlace=iSize;
+
+   dwFPS+=dw-dwLT;iFPSCnt++;
+
+   dwLT=dw;
+                                       
+   if(iFPSCnt>=10)
+    {
+     if(!dwFPS) dwFPS=1;
+     dw1=1000000/dwFPS; 
+     if(dw1>=(dwL1-100) && dw1<=(dwL1+100)) dw1=dwL1;
+     else dwL1=dw1;
+     dw2=(xap->freq*100/xap->nsamples);
+     if((!dw1)||((dw2+100)>=dw1)) iLastSize=0;
+     else
+      {
+       iLastSize=iSize*dw2/dw1;
+       if(iLastSize>iPlace) iLastSize=iPlace;
+       iSize=iLastSize;
+      }
+     iFPSCnt=0;dwFPS=0;
+    }
+   else
+    {
+     if(iLastSize) iSize=iLastSize;
+    }
+  }
+ //----------------------------------------------------//
+
+ spos=0x10000L;
+ sinc = (xap->nsamples << 16) / iSize;                 // calc freq by num / size
+
+ if(xap->stereo)
+  {
+   unsigned long * pS=(unsigned long *)xap->pcm;
+   unsigned long l=0;
+
+   if(iXAPitch)
+    {
+     long l1,l2;short s;
+     for(i=0;i<iSize;i++)
+      {
+       if(iUseInterpolation==2) 
+        {
+         while(spos>=0x10000L)
+          {
+           l = *pS++;
+           gauss_window[gauss_ptr] = (short)LOWORD(l);
+           gauss_window[4+gauss_ptr] = (short)HIWORD(l);
+           gauss_ptr = (gauss_ptr+1) & 3;
+           spos -= 0x10000L;
+          }
+         vl = (spos >> 6) & ~3;
+         vr=(gauss[vl]*gvall0)&~2047;
+         vr+=(gauss[vl+1]*gvall(1))&~2047;
+         vr+=(gauss[vl+2]*gvall(2))&~2047;
+         vr+=(gauss[vl+3]*gvall(3))&~2047;
+         l= (vr >> 11) & 0xffff;
+         vr=(gauss[vl]*gvalr0)&~2047;
+         vr+=(gauss[vl+1]*gvalr(1))&~2047;
+         vr+=(gauss[vl+2]*gvalr(2))&~2047;
+         vr+=(gauss[vl+3]*gvalr(3))&~2047;
+         l |= vr << 5;
+        }
+       else
+        {
+         while(spos>=0x10000L)
+          {
+           l = *pS++;
+           spos -= 0x10000L;
+          }
+        }
+
+       s=(short)LOWORD(l);
+       l1=s;
+       l1=(l1*iPlace)/iSize;
+       if(l1<-32767) l1=-32767;
+       if(l1> 32767) l1=32767;
+       s=(short)HIWORD(l);
+       l2=s;
+       l2=(l2*iPlace)/iSize;
+       if(l2<-32767) l2=-32767;
+       if(l2> 32767) l2=32767;
+       l=(l1&0xffff)|(l2<<16);
+
+       *XAFeed++=l;
+
+       if(XAFeed==XAEnd) XAFeed=XAStart;
+       if(XAFeed==XAPlay) 
+        {
+         if(XAPlay!=XAStart) XAFeed=XAPlay-1;
+         break;
+        }
+
+       spos += sinc;
+      }
+    }
+   else
+    {
+     for(i=0;i<iSize;i++)
+      {
+       if(iUseInterpolation==2) 
+        {
+         while(spos>=0x10000L)
+          {
+           l = *pS++;
+           gauss_window[gauss_ptr] = (short)LOWORD(l);
+           gauss_window[4+gauss_ptr] = (short)HIWORD(l);
+           gauss_ptr = (gauss_ptr+1) & 3;
+           spos -= 0x10000L;
+          }
+         vl = (spos >> 6) & ~3;
+         vr=(gauss[vl]*gvall0)&~2047;
+         vr+=(gauss[vl+1]*gvall(1))&~2047;
+         vr+=(gauss[vl+2]*gvall(2))&~2047;
+         vr+=(gauss[vl+3]*gvall(3))&~2047;
+         l= (vr >> 11) & 0xffff;
+         vr=(gauss[vl]*gvalr0)&~2047;
+         vr+=(gauss[vl+1]*gvalr(1))&~2047;
+         vr+=(gauss[vl+2]*gvalr(2))&~2047;
+         vr+=(gauss[vl+3]*gvalr(3))&~2047;
+         l |= vr << 5;
+        }
+       else
+        {
+         while(spos>=0x10000L)
+          {
+           l = *pS++;
+           spos -= 0x10000L;
+          }
+        }
+
+       *XAFeed++=l;
+
+       if(XAFeed==XAEnd) XAFeed=XAStart;
+       if(XAFeed==XAPlay) 
+        {
+         if(XAPlay!=XAStart) XAFeed=XAPlay-1;
+         break;
+        }
+
+       spos += sinc;
+      }
+    }
+  }
+ else
+  {
+   unsigned short * pS=(unsigned short *)xap->pcm;
+   unsigned long l;short s=0;
+
+   if(iXAPitch)
+    {
+     long l1;
+     for(i=0;i<iSize;i++)
+      {
+       if(iUseInterpolation==2) 
+        {
+         while(spos>=0x10000L)
+          {
+           gauss_window[gauss_ptr] = (short)*pS++;
+           gauss_ptr = (gauss_ptr+1) & 3;
+           spos -= 0x10000L;
+          }
+         vl = (spos >> 6) & ~3;
+         vr=(gauss[vl]*gvall0)&~2047;
+         vr+=(gauss[vl+1]*gvall(1))&~2047;
+         vr+=(gauss[vl+2]*gvall(2))&~2047;
+         vr+=(gauss[vl+3]*gvall(3))&~2047;
+         l1=s= vr >> 11;
+         l1 &= 0xffff;
+        }
+       else
+        {
+         while(spos>=0x10000L)
+          {
+           s = *pS++;
+           spos -= 0x10000L;
+          }
+         l1=s;
+        }
+
+       l1=(l1*iPlace)/iSize;
+       if(l1<-32767) l1=-32767;
+       if(l1> 32767) l1=32767;
+       l=(l1&0xffff)|(l1<<16);
+       *XAFeed++=l;
+
+       if(XAFeed==XAEnd) XAFeed=XAStart;
+       if(XAFeed==XAPlay) 
+        {
+         if(XAPlay!=XAStart) XAFeed=XAPlay-1;
+         break;
+        }
+
+       spos += sinc;
+      }
+    }
+   else
+    {
+     for(i=0;i<iSize;i++)
+      {
+       if(iUseInterpolation==2) 
+        {
+         while(spos>=0x10000L)
+          {
+           gauss_window[gauss_ptr] = (short)*pS++;
+           gauss_ptr = (gauss_ptr+1) & 3;
+           spos -= 0x10000L;
+          }
+         vl = (spos >> 6) & ~3;
+         vr=(gauss[vl]*gvall0)&~2047;
+         vr+=(gauss[vl+1]*gvall(1))&~2047;
+         vr+=(gauss[vl+2]*gvall(2))&~2047;
+         vr+=(gauss[vl+3]*gvall(3))&~2047;
+         l=s= vr >> 11;
+         l &= 0xffff;
+        }
+       else
+        {
+         while(spos>=0x10000L)
+          {
+           s = *pS++;
+           spos -= 0x10000L;
+          }
+         l=s;
+        }
+
+       *XAFeed++=(l|(l<<16));
+
+       if(XAFeed==XAEnd) XAFeed=XAStart;
+       if(XAFeed==XAPlay) 
+        {
+         if(XAPlay!=XAStart) XAFeed=XAPlay-1;
+         break;
+        }
+
+       spos += sinc;
+      }
+    }
+  }
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/xa.h	Sun Mar 19 12:51:03 2006 -0800
@@ -0,0 +1,29 @@
+/***************************************************************************
+                            xa.h  -  description
+                             -------------------
+    begin                : Wed May 15 2002
+    copyright            : (C) 2002 by Pete Bernert
+    email                : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version. See also the license.txt file for *
+ *   additional informations.                                              *
+ *                                                                         *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+
+INLINE void MixXA(void);
+INLINE void FeedXA(xa_decode_t *xap);