changeset 333:42cdc99e395a trunk

[svn] Now that the build system is ready, upload the plugin code.
author chainsaw
date Sun, 25 Dec 2005 13:11:21 -0800
parents 07576d3ed844
children 0daaddb10914
files Plugins/Input/sexypsf/Makefile.am Plugins/Input/sexypsf/Misc.c Plugins/Input/sexypsf/Misc.h Plugins/Input/sexypsf/PsxBios.c Plugins/Input/sexypsf/PsxBios.h Plugins/Input/sexypsf/PsxCommon.h Plugins/Input/sexypsf/PsxCounters.c Plugins/Input/sexypsf/PsxCounters.h Plugins/Input/sexypsf/PsxDma.c Plugins/Input/sexypsf/PsxDma.h Plugins/Input/sexypsf/PsxHLE.c Plugins/Input/sexypsf/PsxHLE.h Plugins/Input/sexypsf/PsxHw.c Plugins/Input/sexypsf/PsxHw.h Plugins/Input/sexypsf/PsxInterpreter.c Plugins/Input/sexypsf/PsxMem.c Plugins/Input/sexypsf/PsxMem.h Plugins/Input/sexypsf/R3000A.c Plugins/Input/sexypsf/R3000A.h Plugins/Input/sexypsf/Spu.c Plugins/Input/sexypsf/Spu.h Plugins/Input/sexypsf/driver.h Plugins/Input/sexypsf/spu.c Plugins/Input/sexypsf/spu/adsr.c Plugins/Input/sexypsf/spu/adsr.h Plugins/Input/sexypsf/spu/dma.c Plugins/Input/sexypsf/spu/dma.h Plugins/Input/sexypsf/spu/externals.h Plugins/Input/sexypsf/spu/gauss_i.h Plugins/Input/sexypsf/spu/registers.c Plugins/Input/sexypsf/spu/registers.h Plugins/Input/sexypsf/spu/regs.h Plugins/Input/sexypsf/spu/reverb.c Plugins/Input/sexypsf/spu/spu.c Plugins/Input/sexypsf/spu/spu.h Plugins/Input/sexypsf/spu/stdafx.h Plugins/Input/sexypsf/types.h Plugins/Input/sexypsf/xmms.c
diffstat 38 files changed, 7878 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/Makefile.am	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,24 @@
+lib_LTLIBRARIES = libsexypsf.la
+
+libdir = $(plugindir)/$(INPUT_PLUGIN_DIR)
+
+libsexypsf_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+
+libsexypsf_la_SOURCES = \
+	PsxCommon.h types.h \
+	PsxBios.c PsxBios.h \
+	PsxCounters.c PsxCounters.h \
+	PsxDma.c PsxDma.h \
+	Spu.c Spu.h \
+	PsxMem.c PsxMem.h \
+	PsxHw.c PsxHw.h \
+	Misc.c Misc.h driver.h \
+	R3000A.c R3000A.h \
+	PsxInterpreter.c \
+	PsxHLE.c PsxHLE.h \
+	spu/spu.c \
+	xmms.c
+
+libsexypsf_la_LIBADD = -lz
+
+INCLUDES = $(GTK_CFLAGS) -I$(top_builddir)/intl -I$(top_srcdir)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/Misc.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,469 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "PsxCommon.h"
+#include "driver.h"
+
+// LOAD STUFF
+
+typedef struct {
+    unsigned char id[8];
+    u32 text;                   
+    u32 data;                    
+    u32 pc0;
+    u32 gp0;                     
+    u32 t_addr;
+    u32 t_size;
+    u32 d_addr;                  
+    u32 d_size;                  
+    u32 b_addr;                  
+    u32 b_size;                  
+    u32 S_addr;//normal must a s not a S but error (???)
+    u32 s_size;
+    u32 SavedSP;
+    u32 SavedFP;
+    u32 SavedGP;
+    u32 SavedRA;
+    u32 SavedS0;
+} PACKSTRUCT EXE_HEADER;
+
+static long TimeToMS(const char *str)
+{
+             int x,c=0;
+             int acc=0;
+	     char s[100];
+
+	     strncpy(s,str,100);
+	     s[99]=0;
+
+             for(x=strlen(s);x>=0;x--)
+              if(s[x]=='.' || s[x]==',')
+              {
+               acc=atoi(s+x+1);
+               s[x]=0;
+              }
+              else if(s[x]==':')
+              {
+               if(c==0) acc+=atoi(s+x+1)*10;
+               else if(c==1) acc+=atoi(s+x+(x?1:0))*10*60;
+               c++;
+               s[x]=0;
+              }
+              else if(x==0)
+	      {
+               if(c==0) acc+=atoi(s+x)*10;
+               else if(c==1) acc+=atoi(s+x)*10*60;
+               else if(c==2) acc+=atoi(s+x)*10*60*60;
+	      }
+             acc*=100;  // To milliseconds.
+	    return(acc);
+}
+
+char *GetFileWithBase(char *f, char *newfile)
+{
+  static char *ret;
+  char *tp1;
+                       
+ #if PSS_STYLE==1
+     tp1=((char *)strrchr(f,'/'));
+ #else
+     tp1=((char *)strrchr(f,'\\'));
+  #if PSS_STYLE!=3
+  {
+     char *tp3;
+
+     tp3=((char *)strrchr(f,'/'));
+     if(tp1<tp3) tp1=tp3;
+  }
+  #endif
+ #endif
+     if(!tp1)
+     {
+      ret=malloc(strlen(newfile)+1);
+      strcpy(ret,newfile);
+     }
+     else              
+     {
+      ret=malloc(tp1-f+2+strlen(newfile));	// 1(NULL), 1(/).
+      memcpy(ret,f,tp1-f);
+      ret[tp1-f]='/';
+      ret[tp1-f+1]=0;
+      strcat(ret,newfile);
+     }
+    return(ret);
+}
+
+static int GetKeyVal(char *buf, char **key, char **val)
+{
+ char *tmp;
+
+ tmp=buf;
+
+ /* First, convert any weirdo ASCII characters to spaces. */
+ while(*tmp++) if(*tmp>0 && *tmp<0x20) *tmp=0x20;
+
+ /* Strip off white space off end of string(which should be the "value"). */
+ for(tmp=buf+strlen(buf)-1;tmp>=buf;tmp--)
+ {
+  if(*tmp != 0x20) break;
+  *tmp=0;
+ }
+
+ /* Now, search for the first non-whitespace character. */
+ while(*buf == 0x20) buf++; 
+
+ tmp=buf;
+ while((*buf != 0x20) && (*buf != '=')) 
+ {
+  if(!*buf) return(0);	/* Null character. */
+  buf++;
+ }
+
+ /* Allocate memory, copy string, and terminate string. */
+ if(!(*key=malloc(buf-tmp+1))) return(0);
+ strncpy(*key,tmp,buf-tmp);
+ (*key)[(buf-tmp)]=0;
+
+ /* Search for "=" character. */
+ while(*buf != '=')
+ {
+  if(!*buf) return(0);  /* Null character. */
+  buf++;
+ }
+
+ buf++;	/* Skip over equals character. */
+
+ /* Remove leading whitespace on value. */
+ while(*buf == 0x20)
+ {
+  if(!*buf) return(0);  /* Null character. */
+  buf++;
+ }
+
+ /* Allocate memory, and copy string over.  Trailing whitespace was eliminated
+    earlier.
+ */
+
+ if(!(*val=malloc(strlen(buf)+1))) return(0);
+ strcpy(*val,buf);
+
+ //puts(*key);
+ //puts(*val);
+
+ return(1);
+}
+
+static void FreeTags(PSFTAG *tags)
+{
+ while(tags)
+ {
+  PSFTAG *tmp=tags->next;
+
+  free(tags->key);
+  free(tags->value);
+  free(tags);
+
+  tags=tmp;
+ }
+}
+
+static void AddKV(PSFTAG **tag, char *key, char *val)
+{
+ PSFTAG *tmp;
+
+ tmp=malloc(sizeof(PSFTAG));
+ memset(tmp,0,sizeof(PSFTAG));
+
+ tmp->key=key;
+ tmp->value=val;
+ tmp->next=0;
+
+ if(!*tag) *tag=tmp;
+ else 
+ {
+  PSFTAG *rec;
+  rec=*tag;
+  while(rec->next) rec=rec->next;
+  rec->next=tmp;
+ }
+
+}
+
+typedef struct {
+	int num;
+	char *value;
+} LIBNCACHE;
+
+static int ccomp(const void *v1, const void *v2)
+{
+ const LIBNCACHE *a1,*a2;
+ a1=v1; a2=v2;
+
+ return(a1->num - a2->num);
+}
+
+static PSFINFO *LoadPSF(char *path, int level, int type) // Type==1 for just info load.
+{
+        FILE *fp;
+        EXE_HEADER tmpHead;
+        char *in,*out=0;
+	u8 head[4];
+        u32 reserved;
+        u32 complen;
+        u32 crc32; 
+        uLongf outlen;
+	PSFINFO *psfi;
+	PSFINFO *tmpi;
+
+	//printf("Loading: %s\n",path);
+        if(!(fp=fopen(path,"rb")))
+ 	{
+	 return(0);
+	}
+ 
+	fread(head,1,4,fp);
+	if(memcmp(head,"PSF\x01",4)) return(0);
+
+	psfi=malloc(sizeof(PSFINFO));
+	memset(psfi,0,sizeof(PSFINFO));
+        psfi->stop=~0;
+        psfi->fade=0; 
+
+        fread(&reserved,1,4,fp);
+        fread(&complen,1,4,fp);
+	complen=BFLIP32(complen);
+
+        fread(&crc32,1,4,fp);
+	crc32=BFLIP32(crc32);
+
+        fseek(fp,reserved,SEEK_CUR);
+
+        if(type)
+	 fseek(fp,complen,SEEK_CUR);
+        else
+        {
+         in=malloc(complen);
+         out=malloc(1024*1024*2+0x800);
+         fread(in,1,complen,fp);
+         outlen=1024*1024*2;
+         uncompress(out,&outlen,in,complen);
+         free(in);
+         memcpy(&tmpHead,out,sizeof(EXE_HEADER));
+         psxRegs.pc = BFLIP32(tmpHead.pc0);
+         psxRegs.GPR.n.gp = BFLIP32(tmpHead.gp0);
+         psxRegs.GPR.n.sp = BFLIP32(tmpHead.S_addr);
+         if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;
+
+ 	 if(level)
+ 	 {
+	  LoadPSXMem(BFLIP32(tmpHead.t_addr),BFLIP32(tmpHead.t_size),out+0x800);
+          free(out);
+	 }
+        }
+
+        {
+         u8 tagdata[5];
+         if(fread(tagdata,1,5,fp)==5)
+         {
+          if(!memcmp(tagdata,"[TAG]",5))
+          {
+           char linebuf[1024];
+
+           while(fgets(linebuf,1024,fp)>0)
+           {
+            int x;
+	    char *key=0,*value=0;
+
+	    if(!GetKeyVal(linebuf,&key,&value))
+	    { 
+	     if(key) free(key);
+	     if(value) free(value);
+	     continue;
+            }
+
+	    AddKV(&psfi->tags,key,value);
+
+	    if(!level)
+	    {
+       	     static char *yoinks[8]={"title","artist","game","year","genre",
+                                  "copyright","psfby","comment"};
+	     char **yoinks2[8]={&psfi->title,&psfi->artist,&psfi->game,&psfi->year,&psfi->genre,
+                                    &psfi->copyright,&psfi->psfby,&psfi->comment};
+	     for(x=0;x<8;x++)
+	      if(!strcasecmp(key,yoinks[x]))
+		*yoinks2[x]=value;
+	     if(!strcasecmp(key,"length"))
+	      psfi->stop=TimeToMS(value);
+	     else if(!strcasecmp(key,"fade"))
+	      psfi->fade=TimeToMS(value);
+	    }
+
+	    if(!strcasecmp(key,"_lib") && !type)
+	    {
+	     char *tmpfn;
+	     /* Load file name "value" from the directory specified in
+		the full path(directory + file name) "path"
+	     */
+	     tmpfn=GetFileWithBase(path,value);
+	     if(!(tmpi=LoadPSF(tmpfn,level+1,0))) 
+	     {
+	      free(key);
+	      free(value);
+	      free(tmpfn);
+ 	      if(!level) free(out);
+	      fclose(fp);
+	      FreeTags(psfi->tags);
+	      free(psfi);
+	      return(0);
+	     }
+	     FreeTags(tmpi->tags);
+	     free(tmpi);
+	     free(tmpfn);
+	    }
+           }
+          }
+         }
+        }  
+
+        fclose(fp);
+
+	/* Now, if we're at level 0(main PSF), load the main executable, and any libN stuff */
+        if(!level && !type)
+        {
+         LoadPSXMem(BFLIP32(tmpHead.t_addr),BFLIP32(tmpHead.t_size),out+0x800);
+	 free(out);
+        }
+
+	if(!type)	/* Load libN */
+	{
+	 LIBNCACHE *cache;
+	 PSFTAG *tag;
+	 unsigned int libncount=0;
+	 unsigned int cur=0;
+
+	 tag=psfi->tags;
+	 while(tag)
+	 {
+	  if(!strncasecmp(tag->key,"_lib",4) && tag->key[4])
+	   libncount++;
+	  tag=tag->next;
+	 }
+
+	 if(libncount)
+	 {
+	  cache=malloc(sizeof(LIBNCACHE)*libncount);
+
+	  tag=psfi->tags;
+	  while(tag)
+	  {
+	   if(!strncasecmp(tag->key,"_lib",4) && tag->key[4])
+	   {
+	    cache[cur].num=atoi(&tag->key[4]);
+	    cache[cur].value=tag->value;
+	    cur++;
+	   }
+	   tag=tag->next;
+	  }
+	  qsort(cache, libncount, sizeof(LIBNCACHE), ccomp);
+	  for(cur=0;cur<libncount;cur++)
+	  {
+	   u32 ba[3];
+	   char *tmpfn;
+
+ 	   if(cache[cur].num < 2) continue;
+
+	   ba[0]=psxRegs.pc;
+	   ba[1]=psxRegs.GPR.n.gp;
+	   ba[2]=psxRegs.GPR.n.sp;
+
+           /* Load file name "value" from the directory specified in
+                the full path(directory + file name) "path"
+             */
+           tmpfn=GetFileWithBase(path,cache[cur].value);
+           if(!(tmpi=LoadPSF(tmpfn,level+1,0)))
+           {
+            //free(key);
+            //free(value);
+            //free(tmpfn);
+            //fclose(fp);
+            //return(0);
+           }
+           free(tmpfn);
+	   FreeTags(tmpi->tags);
+	   free(tmpi);
+
+	   psxRegs.pc=ba[0];
+       	   psxRegs.GPR.n.gp=ba[1];
+	   psxRegs.GPR.n.sp=ba[2];
+	  }
+	  free(cache);
+
+	 }	// if(libncount)
+
+	}	// if(!type)
+
+	return(psfi);
+}
+
+void sexypsf_freepsfinfo(PSFINFO *info)
+{
+ FreeTags(info->tags);
+ free(info);
+}
+
+PSFINFO *sexypsf_getpsfinfo(char *path)
+{
+	PSFINFO *ret;
+        if(!(ret=LoadPSF(path,0,1))) return(0);
+        if(ret->stop==~0) ret->fade=0;
+        ret->length=ret->stop+ret->fade;
+        return(ret);	
+}
+
+PSFINFO *sexypsf_load(char *path) 
+{
+	PSFINFO *ret;
+
+        psxInit();
+        psxReset();
+
+        SPUinit();
+        SPUopen();
+
+	if(!(ret=LoadPSF(path,0,0)))
+	{
+	 psxShutdown();
+	 return(0);
+	}
+
+	if(ret->stop==~0) ret->fade=0; // Infinity+anything is still infinity...or is it?
+	SPUsetlength(ret->stop,ret->fade);
+	ret->length=ret->stop+ret->fade;
+
+        return(ret);
+}
+
+void sexypsf_execute(void)
+{
+ psxCpu->Execute();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/Misc.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,22 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MISC_H__
+#define __MISC_H__
+
+#endif /* __MISC_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxBios.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,1367 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdlib.h> 
+#include <stdio.h> 
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "PsxCommon.h"
+//We try to emulate bios :) HELP US :P
+
+#ifdef NONONO
+char *biosA0n[256] = {
+// 0x00
+	"open",		"lseek",	"read",		"write",
+	"close",	"ioctl",	"exit",		"sys_a0_07",
+	"getc",		"putc",		"todigit",	"atof",
+	"strtoul",	"strtol",	"abs",		"labs",
+// 0x10
+	"atoi",		"atol",		"atob",		"setjmp",
+	"longjmp",	"strcat",	"strncat",	"strcmp",
+	"strncmp",	"strcpy",	"strncpy",	"strlen",
+	"index",	"rindex",	"strchr",	"strrchr",
+// 0x20
+	"strpbrk",	"strspn",	"strcspn",	"strtok",
+	"strstr",	"toupper",	"tolower",	"bcopy",
+	"bzero",	"bcmp",		"memcpy",	"memset",
+	"memmove",	"memcmp",	"memchr",	"rand",
+// 0x30
+	"srand",	"qsort",	"strtod",	"malloc",
+	"free",		"lsearch",	"bsearch",	"calloc",
+	"realloc",	"InitHeap",	"_exit",	"getchar",
+	"putchar",	"gets",		"puts",		"printf",
+// 0x40
+	"sys_a0_40",		"LoadTest",					"Load",		"Exec",
+	"FlushCache",		"InstallInterruptHandler",	"GPU_dw",	"mem2vram",
+	"SendGPUStatus",	"GPU_cw",					"GPU_cwb",	"SendPackets",
+	"sys_a0_4c",		"GetGPUStatus",				"GPU_sync",	"sys_a0_4f",
+// 0x50
+	"sys_a0_50",		"LoadExec",				"GetSysSp",		"sys_a0_53",
+	"_96_init()",		"_bu_init()",			"_96_remove()",	"sys_a0_57",
+	"sys_a0_58",		"sys_a0_59",			"sys_a0_5a",	"dev_tty_init",
+	"dev_tty_open",		"sys_a0_5d",			"dev_tty_ioctl","dev_cd_open",
+// 0x60
+	"dev_cd_read",		"dev_cd_close",			"dev_cd_firstfile",	"dev_cd_nextfile",
+	"dev_cd_chdir",		"dev_card_open",		"dev_card_read",	"dev_card_write",
+	"dev_card_close",	"dev_card_firstfile",	"dev_card_nextfile","dev_card_erase",
+	"dev_card_undelete","dev_card_format",		"dev_card_rename",	"dev_card_6f",
+// 0x70
+	"_bu_init",			"_96_init",		"_96_remove",		"sys_a0_73",
+	"sys_a0_74",		"sys_a0_75",	"sys_a0_76",		"sys_a0_77",
+	"_96_CdSeekL",		"sys_a0_79",	"sys_a0_7a",		"sys_a0_7b",
+	"_96_CdGetStatus",	"sys_a0_7d",	"_96_CdRead",		"sys_a0_7f",
+// 0x80
+	"sys_a0_80",		"sys_a0_81",	"sys_a0_82",		"sys_a0_83",
+	"sys_a0_84",		"_96_CdStop",	"sys_a0_86",		"sys_a0_87",
+	"sys_a0_88",		"sys_a0_89",	"sys_a0_8a",		"sys_a0_8b",
+	"sys_a0_8c",		"sys_a0_8d",	"sys_a0_8e",		"sys_a0_8f",
+// 0x90
+	"sys_a0_90",		"sys_a0_91",	"sys_a0_92",		"sys_a0_93",
+	"sys_a0_94",		"sys_a0_95",	"AddCDROMDevice",	"AddMemCardDevide",
+	"DisableKernelIORedirection",		"EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b",
+	"SetConf",			"GetConf",		"sys_a0_9e",		"SetMem",
+// 0xa0
+	"_boot",			"SystemError",	"EnqueueCdIntr",	"DequeueCdIntr",
+	"sys_a0_a4",		"ReadSector",	"get_cd_status",	"bufs_cb_0",
+	"bufs_cb_1",		"bufs_cb_2",	"bufs_cb_3",		"_card_info",
+	"_card_load",		"_card_auto",	"bufs_cd_4",		"sys_a0_af",
+// 0xb0
+	"sys_a0_b0",		"sys_a0_b1",	"do_a_long_jmp",	"sys_a0_b3",
+	"?? sub_function",
+};
+
+char *biosB0n[256] = {
+// 0x00
+	"SysMalloc",		"sys_b0_01",	"sys_b0_02",	"sys_b0_03",
+	"sys_b0_04",		"sys_b0_05",	"sys_b0_06",	"DeliverEvent",
+	"OpenEvent",		"CloseEvent",	"WaitEvent",	"TestEvent",
+	"EnableEvent",		"DisableEvent",	"OpenTh",		"CloseTh",
+// 0x10
+	"ChangeTh",			"sys_b0_11",	"InitPAD",		"StartPAD",
+	"StopPAD",			"PAD_init",		"PAD_dr",		"ReturnFromExecption",
+	"ResetEntryInt",	"HookEntryInt",	"sys_b0_1a",	"sys_b0_1b",
+	"sys_b0_1c",		"sys_b0_1d",	"sys_b0_1e",	"sys_b0_1f",
+// 0x20
+	"UnDeliverEvent",	"sys_b0_21",	"sys_b0_22",	"sys_b0_23",
+	"sys_b0_24",		"sys_b0_25",	"sys_b0_26",	"sys_b0_27",
+	"sys_b0_28",		"sys_b0_29",	"sys_b0_2a",	"sys_b0_2b",
+	"sys_b0_2c",		"sys_b0_2d",	"sys_b0_2e",	"sys_b0_2f",
+// 0x30
+	"sys_b0_30",		"sys_b0_31",	"open",			"lseek",
+	"read",				"write",		"close",		"ioctl",
+	"exit",				"sys_b0_39",	"getc",			"putc",
+	"getchar",			"putchar",		"gets",			"puts",
+// 0x40
+	"cd",				"format",		"firstfile",	"nextfile",
+	"rename",			"delete",		"undelete",		"AddDevice",
+	"RemoteDevice",		"PrintInstalledDevices", "InitCARD", "StartCARD",
+	"StopCARD",			"sys_b0_4d",	"_card_write",	"_card_read",
+// 0x50
+	"_new_card",		"Krom2RawAdd",	"sys_b0_52",	"sys_b0_53",
+	"_get_errno",		"_get_error",	"GetC0Table",	"GetB0Table",
+	"_card_chan",		"sys_b0_59",	"sys_b0_5a",	"ChangeClearPAD",
+	"_card_status",		"_card_wait",
+};
+
+char *biosC0n[256] = {
+// 0x00
+	"InitRCnt",			  "InitException",		"SysEnqIntRP",		"SysDeqIntRP",
+	"get_free_EvCB_slot", "get_free_TCB_slot",	"ExceptionHandler",	"InstallExeptionHandler",
+	"SysInitMemory",	  "SysInitKMem",		"ChangeClearRCnt",	"SystemError",
+	"InitDefInt",		  "sys_c0_0d",			"sys_c0_0e",		"sys_c0_0f",
+// 0x10
+	"sys_c0_10",		  "sys_c0_11",			"InstallDevices",	"FlushStfInOutPut",
+	"sys_c0_14",		  "_cdevinput",			"_cdevscan",		"_circgetc",
+	"_circputc",		  "ioabort",			"sys_c0_1a",		"KernelRedirect",
+	"PatchAOTable",
+};
+#endif
+
+//#define r0 (psxRegs.GPR.n.r0)
+#define at (psxRegs.GPR.n.at)
+#define v0 (psxRegs.GPR.n.v0)
+#define v1 (psxRegs.GPR.n.v1)
+#define a0 (psxRegs.GPR.n.a0)
+#define a1 (psxRegs.GPR.n.a1)
+#define a2 (psxRegs.GPR.n.a2)
+#define a3 (psxRegs.GPR.n.a3)
+#define t0 (psxRegs.GPR.n.t0)
+#define t1 (psxRegs.GPR.n.t1)
+#define t2 (psxRegs.GPR.n.t2)
+#define t3 (psxRegs.GPR.n.t3)
+#define t4 (psxRegs.GPR.n.t4)
+#define t5 (psxRegs.GPR.n.t5)
+#define t6 (psxRegs.GPR.n.t6)
+#define t7 (psxRegs.GPR.n.t7)
+#define s0 (psxRegs.GPR.n.s0)
+#define s1 (psxRegs.GPR.n.s1)
+#define s2 (psxRegs.GPR.n.s2)
+#define s3 (psxRegs.GPR.n.s3)
+#define s4 (psxRegs.GPR.n.s4)
+#define s5 (psxRegs.GPR.n.s5)
+#define s6 (psxRegs.GPR.n.s6)
+#define s7 (psxRegs.GPR.n.s7)
+#define t8 (psxRegs.GPR.n.t6)
+#define t9 (psxRegs.GPR.n.t7)
+#define k0 (psxRegs.GPR.n.k0)
+#define k1 (psxRegs.GPR.n.k1)
+#define gp (psxRegs.GPR.n.gp)
+#define sp (psxRegs.GPR.n.sp)
+#define fp (psxRegs.GPR.n.s8)
+#define ra (psxRegs.GPR.n.ra)
+#define pc0 (psxRegs.pc)
+
+#define Ra0 ((char*)PSXM(a0))
+#define Ra1 ((char*)PSXM(a1))
+#define Ra2 ((char*)PSXM(a2))
+#define Ra3 ((char*)PSXM(a3))
+#define Rv0 ((char*)PSXM(v0))
+#define Rsp ((char*)PSXM(sp))
+
+
+typedef struct _malloc_chunk {
+	u32 stat;
+	u32 size;
+	u32 fd;
+	u32 bk;
+} PACKSTRUCT malloc_chunk;
+
+#define INUSE 0x1
+
+typedef struct {
+	u32 desc;
+	s32 status;
+	s32 mode;
+	u32 fhandler;
+} PACKSTRUCT EvCB[32];
+
+#define EvStUNUSED	0x0000
+#define EvStWAIT	0x1000
+#define EvStACTIVE	0x2000
+#define EvStALREADY 0x4000
+
+#define EvMdINTR	0x1000
+#define EvMdNOINTR	0x2000
+
+typedef struct {
+	s32 status;
+	s32 mode;
+	u32 reg[32];
+	u32 func;
+} PACKSTRUCT TCB;
+
+static u32 *jmp_int;
+
+static u32 regs[35];
+static EvCB *Event;
+
+//static EvCB *HwEV; // 0xf0
+//static EvCB *EvEV; // 0xf1
+static EvCB *RcEV; // 0xf2
+//static EvCB *UeEV; // 0xf3
+//static EvCB *SwEV; // 0xf4
+//static EvCB *ThEV; // 0xff
+
+static u32 heap_addr;
+static u32 SysIntRP[8];
+static TCB Thread[8];
+static int CurThread;
+
+static INLINE void softCall(u32 pc) {
+	pc0 = pc;
+	ra = 0x80001000;
+	while (pc0 != 0x80001000) psxCpu->ExecuteBlock();
+}
+
+static INLINE void softCall2(u32 pc) {
+	u32 sra = ra;
+	pc0 = pc;
+	ra = 0x80001000;
+	while (pc0 != 0x80001000) psxCpu->ExecuteBlock();
+	ra = sra;
+}
+
+static INLINE void DeliverEvent(u32 ev, u32 spec) {
+	if (Event[ev][spec].status != BFLIP32(EvStACTIVE)) return;
+
+//	Event[ev][spec].status = BFLIP32(EvStALREADY);
+	if (Event[ev][spec].mode == BFLIP32(EvMdINTR)) {
+		softCall2(BFLIP32(Event[ev][spec].fhandler));
+	} else Event[ev][spec].status = BFLIP32(EvStALREADY);
+}
+
+/*                                           *
+//                                           *
+//                                           *
+//               System calls A0             */
+
+/* Abs and labs do the same thing? */
+
+static void bios_abs() { // 0x0e
+	if((s32)a0 < 0) v0=0-(s32)a0;
+	else v0=a0;
+	//v0 = abs(a0);
+	pc0 = ra;
+}
+
+static void bios_labs() { // 0x0f
+        if((s32)a0 < 0) v0=0-(s32)a0;
+        else v0=a0;
+	//v0 = labs(a0);
+	pc0 = ra;
+}
+
+static void bios_atoi() { // 0x10
+	v0 = atoi((char *)Ra0);
+	pc0 = ra;
+}
+
+static void bios_atol() { // 0x11
+	v0 = atoi((char *)Ra0);
+	pc0 = ra;
+}
+
+static void bios_setjmp() { // 13
+	u32 *jmp_buf= (u32*)Ra0;
+	int i;
+
+	jmp_buf[0] =  BFLIP32(ra);
+	jmp_buf[1] =  BFLIP32(sp);
+	jmp_buf[2] =  BFLIP32(fp);
+	for (i=0; i<8; i++) // s0-s7
+		jmp_buf[3+i] = BFLIP32(psxRegs.GPR.r[16+i]);
+	jmp_buf[11] =  BFLIP32(gp);
+
+	v0 = 0; pc0 = ra;
+}
+
+static void bios_longjmp() { //14
+	u32 *jmp_buf= (u32*)Ra0;
+	int i;
+
+	ra = BFLIP32(jmp_buf[0]); /* ra */
+	sp = BFLIP32(jmp_buf[1]); /* sp */
+	fp = BFLIP32(jmp_buf[2]); /* fp */
+	for (i=0; i<8; i++) // s0-s7
+	   psxRegs.GPR.r[16+i] =  BFLIP32(jmp_buf[3+i]);
+	gp = BFLIP32(jmp_buf[11]); /* gp */
+
+	v0 = a1; pc0 = ra;
+}
+
+static void bios_strcat() { // 0x15
+	u32 dest,src;
+
+	dest=a0;
+	src=a1;
+
+	while(PSXMu8(dest) != 0) dest++; /* Move to end of first string. */
+	while(PSXMu8(src) != 0) 
+	{
+	 if(PSXM(dest) && PSXM(src))
+	  PSXMu8(dest)=PSXMu8(src);
+	 src++;
+	 dest++;
+	}
+	PSXMu8(dest) = 0;	/* Append null character. */
+	//strcat(Ra0, Ra1);
+
+	v0 = a0; 
+	pc0 = ra;
+}
+
+/*0x16*/
+static void bios_strncat() 
+{ 
+        u32 dest,src,count;
+        
+        dest=a0;
+        src=a1;
+        count=a2;
+
+        while(PSXMu8(dest) != 0) dest++; /* Move to end of first string. */
+        while(PSXMu8(src) != 0 && count)
+        {
+         if(PSXM(dest) && PSXM(src))
+          PSXMu8(dest)=PSXMu8(src);
+         src++;
+         dest++;
+	 count--;
+        }
+        PSXMu8(dest) = 0;       /* Append null character. */
+
+ //strncat(Ra0, Ra1, a2); 
+ v0 = a0; 
+ pc0 = ra;
+}
+
+static void bios_strcmp() { // 0x17
+	v0 = strcmp(Ra0, Ra1);
+	pc0 = ra;
+}
+
+static void bios_strncmp() { // 0x18
+	u32 max=a2;
+	u32 string1=a0;
+	u32 string2=a1;
+	s8 tmpv=0;
+
+	while(max>0)
+	{
+	 u8 tmp1=PSXMuR8(string1);
+	 u8 tmp2=PSXMuR8(string2);
+
+	 if(!tmp1 || !tmp2) break;
+
+	 tmpv=tmp1-tmp2;
+	 if(tmpv) break;
+         if(!tmp1 || !tmp2) break;
+	 if(!PSXM(string1) || !PSXM(string2)) break;
+	 max--;
+	 string1++;
+	 string2++;
+	}
+	if(tmpv>0) v0=1;
+	else if(tmpv<0) v0=-1;
+	else v0=0;
+	//printf("%s:%s, %d, %d\n",Ra0,Ra1,a2,v0);
+	//v0 = strncmp(Ra0, Ra1, a2);
+	pc0 = ra;
+}
+
+/*0x19*/
+static void bios_strcpy()  
+{ 
+ u32 src=a1,dest=a0;
+ u8 val;
+
+ do
+ {
+  val=PSXMu8(src);
+  PSXMu8(dest)=val;
+  src++; 
+  dest++;
+ } while(val);
+ //strcpy(Ra0, Ra1); 
+ v0 = a0; 
+ pc0 = ra;
+}
+/*0x1a*/
+static void bios_strncpy() 
+{ 
+ u32 src=a1,dest=a0,max=a2;
+ u8 val;  
+ 
+ do
+ {
+  val=PSXMu8(src); 
+  PSXMu8(dest)=val;
+  src++;   
+  dest++;
+  max--;
+ } while(val && max);
+
+ //strncpy(Ra0, Ra1, a2);  
+ v0 = a0; 
+ pc0 = ra;
+}
+
+/*0x1b*/
+static void bios_strlen()  
+{ 
+ u32 src=a0;
+
+ while(PSXMu8(src)) src++;
+
+ v0 = src-a0;  
+ pc0 = ra;
+}
+
+static void bios_index() { // 0x1c
+	char *pcA0 = (char *)Ra0; 
+	char *pcRet = strchr(pcA0, a1); 
+	if(pcRet) 
+		v0 = a0 + pcRet - pcA0; 
+	else 
+		v0 = 0;
+    pc0 = ra;
+}
+
+static void bios_rindex() { // 0x1d
+	char *pcA0 = (char *)Ra0; 
+	char *pcRet = strrchr(pcA0, a1); 
+	if(pcRet) 
+		v0 = a0 + pcRet - pcA0; 
+	else 
+		v0 = 0;
+    pc0 = ra;  
+}
+
+static void bios_strchr() { // 0x1e
+	char *pcA0 = (char *)Ra0; 
+	char *pcRet = strchr(pcA0, a1); 
+	if(pcRet) 
+		v0 = a0 + pcRet - pcA0; 
+	else 
+		v0 = 0;
+    pc0 = ra;
+}
+
+static void bios_strrchr() { // 0x1f
+	char *pcA0 = (char *)Ra0; 
+	char *pcRet = strrchr(pcA0, a1); 
+	if(pcRet) 
+		v0 = a0 + pcRet - pcA0; 
+	else 
+		v0 = 0;
+    pc0 = ra;
+}
+
+static void bios_strpbrk() { // 0x20
+	char *pcA0 = (char *)Ra0; 
+	char *pcRet = strpbrk(pcA0, (char *)Ra1); 
+	if(pcRet) 
+		v0 = a0 + pcRet - pcA0; 
+	else 
+		v0 = 0;
+    pc0 = ra;
+}
+
+static void bios_strspn()  { v0 = strspn ((char *)Ra0, (char *)Ra1); pc0 = ra;}/*21*/ 
+static void bios_strcspn() { v0 = strcspn((char *)Ra0, (char *)Ra1); pc0 = ra;}/*22*/ 
+
+#ifdef MOO
+static void bios_strtok() { // 0x23
+	char *pcA0 = (char *)Ra0;
+	char *pcRet = strtok(pcA0, (char *)Ra1);
+	if(pcRet)
+		v0 = a0 + pcRet - pcA0;
+	else
+		v0 = 0;
+    pc0 = ra;
+}
+#endif
+
+static void bios_strstr() { // 0x24
+	char *pcA0 = (char *)Ra0;
+	char *pcRet = strstr(pcA0, (char *)Ra1);
+	if(pcRet)
+		v0 = a0 + pcRet - pcA0;
+	else
+		v0 = 0;
+    pc0 = ra;
+}
+
+/*0x25*/
+static void bios_toupper() {v0 = toupper(a0); pc0 = ra;}
+
+/*0x26*/
+static void bios_tolower() {v0 = tolower(a0); pc0 = ra;}
+
+/*0x27*/
+static void bios_bcopy()   
+{
+ u32 dest=a1, src=a0, len=a2;
+
+ while(len--)
+ {
+  PSXMu8(dest)=PSXMu8(src);
+  dest++;
+  src++;
+ }
+ //memcpy(Ra1,Ra0,a2); 
+ pc0=ra;
+}
+
+/*0x28*/
+static void bios_bzero()   
+{
+ u32 dest=a0, len=a1;
+ 
+ while(len--)
+ {
+  PSXMu8(dest)=0;
+  dest++;
+ }
+
+ //memset(Ra0,0,a1); 
+ pc0=ra;
+}
+
+/*0x29*/
+static void bios_bcmp()    {v0 = memcmp(Ra0,Ra1,a2); pc0=ra; }
+
+/*0x2a*/
+static void bios_memcpy()  
+{
+ u32 dest=a0, src=a1, len=a2;
+ 
+ while(len--)
+ {
+  PSXMu8(dest)=PSXMu8(src);
+  dest++;
+  src++;
+ }
+ //memcpy(Ra0, Ra1, a2); 
+ v0 = a0; 
+ pc0 = ra;
+}
+
+static void bios_memset()  /*0x2b*/
+{
+ u32 len=a2;
+ u32 dest=a0;
+
+ while(len--)
+ {
+  if(PSXM(dest)) PSXMu8(dest)=a1;
+  dest++;
+ }
+ //memset(Ra0, a1, a2);
+ v0 = a0; 
+ pc0 = ra;
+}
+
+#ifdef MOO
+/*0x2c*/void bios_memmove() {memmove(Ra0, Ra1, a2); v0 = a0; pc0 = ra;}
+#endif
+
+/*0x2d*/
+static void bios_memcmp()  
+{
+ v0 = memcmp(Ra0, Ra1, a2); 
+ pc0 = ra;
+}
+
+static void bios_memchr() { // 2e
+	void *ret = memchr(Ra0, a1, a2);
+	if (ret != NULL) v0 = (u32)((char*)ret - Ra0) + a0;
+	else v0 = 0;
+	pc0 = ra;
+}
+
+static void bios_rand() { // 2f
+	v0 = 1+(int) (32767.0*rand()/(RAND_MAX+1.0));
+	pc0 = ra;
+}
+
+static void bios_srand() { // 30
+	srand(a0); pc0 = ra;
+}
+
+static void bios_malloc() { // 33
+	u32 chunk;
+	u32 fd;
+
+	/* a0:  Number of bytes to allocate. */
+
+	chunk = heap_addr;
+
+	/* Search for first chunk that's large enough and not currently
+	   being used.
+	*/
+	while( (a0 > BFLIP32(((malloc_chunk*)PSXM(chunk)) ->size)) ||
+		(BFLIP32( ((malloc_chunk*)PSXM(chunk))->stat  ) == INUSE)
+		)
+		chunk=((malloc_chunk*)PSXM(chunk)) -> fd;
+	//printf("%08x\n",chunk);
+
+	/* split free chunk */
+	fd = chunk + sizeof(malloc_chunk) + a0;
+	((malloc_chunk*)PSXM(fd))->stat = ((malloc_chunk*)PSXM(chunk))->stat;
+	((malloc_chunk*)PSXM(fd))->size = BFLIP32(BFLIP32(((malloc_chunk*)PSXM(chunk))->size) - a0);
+	((malloc_chunk*)PSXM(fd))->fd = ((malloc_chunk*)PSXM(chunk))->fd;
+	((malloc_chunk*)PSXM(fd))->bk = chunk;
+
+	/* set new chunk */
+	((malloc_chunk*)PSXM(chunk))->stat = BFLIP32(INUSE);
+	((malloc_chunk*)PSXM(chunk))->size = BFLIP32(a0);
+	((malloc_chunk*)PSXM(chunk))->fd = fd;
+
+	v0 = chunk + sizeof(malloc_chunk);
+	v0|= 0x80000000;
+	//	printf ("malloc %lx,%lx\n", v0, a0);
+	pc0 = ra;
+}
+
+static void bios_InitHeap() { // 39
+	malloc_chunk *chunk;
+
+	heap_addr = a0; // Ra0
+
+	chunk = (malloc_chunk *)PSXM(heap_addr);
+	chunk->stat = 0;
+	if (((a0 & 0x1fffff) + a1)>= 0x200000) 
+	 chunk->size = BFLIP32(0x1ffffc - (a0 & 0x1fffff));
+	else chunk->size = BFLIP32(a1);
+	chunk->fd = 0;
+	chunk->bk = 0;
+
+	pc0 = ra;
+}
+
+static void bios_FlushCache() { // 44
+
+	pc0 = ra;
+}
+
+static void bios__bu_init() { // 70
+
+	DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
+	DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
+
+	pc0 = ra;
+}
+
+static void bios__96_init() { // 71
+
+	pc0 = ra;
+}
+
+static void bios__96_remove() { // 72
+
+	pc0 = ra;
+}
+
+/* System calls B0 */
+
+static void bios_SetRCnt() { // 02
+
+	a0&= 0x3;
+	if (a0 != 3) {
+		u32 mode=0;
+
+		psxRcntWtarget(a0, a1);
+		if (a2&0x1000) mode|= 0x050; // Interrupt Mode
+		if (a2&0x0100) mode|= 0x008; // Count to 0xffff
+		if (a2&0x0010) mode|= 0x001; // Timer stop mode
+		if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode
+		else         { if (a2&0x0001) mode|= 0x100; } // System Clock mode
+
+		psxRcntWmode(a0, mode);
+	}
+	pc0 = ra;
+}
+
+static void bios_GetRCnt() { // 03
+
+	a0&= 0x3;
+	if (a0 != 3) v0 = psxRcntRcount(a0);
+	else v0 = 0;
+	pc0 = ra;
+}
+
+static void bios_StartRCnt() { // 04
+
+	a0&= 0x3;
+	if (a0 != 3) psxHu32(0x1074)|= BFLIP32(1<<(a0+4));
+	else psxHu32(0x1074)|= BFLIP32(0x1);
+	v0 = 1; pc0 = ra;
+}
+
+static void bios_StopRCnt() { // 05
+
+	a0&= 0x3;
+	if (a0 != 3) psxHu32(0x1074)&= BFLIP32(~(1<<(a0+4)));
+	else psxHu32(0x1074)&= BFLIP32(~0x1);
+	pc0 = ra;
+}
+
+static void bios_ResetRCnt() { // 06
+
+	a0&= 0x3;
+	if (a0 != 3) {
+		psxRcntWmode(a0, 0);
+		psxRcntWtarget(a0, 0);
+		psxRcntWcount(a0, 0);
+	}
+	pc0 = ra;
+}
+
+
+/* gets ev for use with Event */
+#define GetEv() \
+	ev = (a0 >> 24) & 0xf; \
+	if (ev == 0xf) ev = 0x5; \
+	ev*= 32; \
+	ev+= a0&0x1f;
+
+/* gets spec for use with Event */
+#define GetSpec() \
+	spec = 0; \
+	switch (a1) { \
+		case 0x0301: spec = 16; break; \
+		case 0x0302: spec = 17; break; \
+		default: \
+			for (i=0; i<16; i++) if (a1 & (1 << i)) { spec = i; break; } \
+			break; \
+	}
+
+static void bios_DeliverEvent() { // 07
+	int ev, spec;
+	int i;
+
+	GetEv();
+	GetSpec();
+
+	DeliverEvent(ev, spec);
+
+	pc0 = ra;
+}
+
+static void bios_OpenEvent() { // 08
+	int ev, spec;
+	int i;
+
+	GetEv();
+	GetSpec();
+
+	Event[ev][spec].status = BFLIP32(EvStWAIT);
+	Event[ev][spec].mode = BFLIP32(a2);
+	Event[ev][spec].fhandler = BFLIP32(a3);
+
+	v0 = ev | (spec << 8);
+	pc0 = ra;
+}
+
+static void bios_CloseEvent() { // 09
+	int ev, spec;
+
+	ev   = a0 & 0xff;
+	spec = (a0 >> 8) & 0xff;
+
+	Event[ev][spec].status = BFLIP32(EvStUNUSED);
+
+	v0 = 1; pc0 = ra;
+}
+
+static void bios_WaitEvent() { // 0a
+	int ev, spec;
+
+	ev   = a0 & 0xff;
+	spec = (a0 >> 8) & 0xff;
+
+	Event[ev][spec].status = BFLIP32(EvStACTIVE);
+
+	v0 = 1; pc0 = ra;
+}
+
+static void bios_TestEvent() { // 0b
+	int ev, spec;
+
+	ev   = a0 & 0xff;
+	spec = (a0 >> 8) & 0xff;
+
+	if (Event[ev][spec].status == BFLIP32(EvStALREADY)) {
+		Event[ev][spec].status = BFLIP32(EvStACTIVE); v0 = 1;
+	} else v0 = 0;
+
+	pc0 = ra;
+}
+
+static void bios_EnableEvent() { // 0c
+	int ev, spec;
+
+	ev   = a0 & 0xff;
+	spec = (a0 >> 8) & 0xff;
+
+	Event[ev][spec].status = BFLIP32(EvStACTIVE);
+
+	v0 = 1; pc0 = ra;
+}
+
+static void bios_DisableEvent() { // 0d
+	int ev, spec;
+
+	ev   = a0 & 0xff;
+	spec = (a0 >> 8) & 0xff;
+
+	Event[ev][spec].status = BFLIP32(EvStWAIT);
+
+	v0 = 1; pc0 = ra;
+}
+
+/*
+ *	long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
+ */
+
+static void bios_OpenTh() { // 0e
+	int th;
+
+	for (th=1; th<8; th++)
+		if (Thread[th].status == 0) break;
+
+	Thread[th].status = BFLIP32(1);
+	Thread[th].func    = BFLIP32(a0);
+	Thread[th].reg[29] = BFLIP32(a1);
+	Thread[th].reg[28] = BFLIP32(a2);
+
+	v0 = th; pc0 = ra;
+}
+
+/*
+ *	int CloseTh(long thread);
+ */
+
+static void bios_CloseTh() { // 0f
+	int th = a0 & 0xff;
+
+	if (Thread[th].status == 0) {
+		v0 = 0;
+	} else {
+		Thread[th].status = 0;
+		v0 = 1;
+	}
+
+	pc0 = ra;
+}
+
+/*
+ *	int ChangeTh(long thread);
+ */
+
+static void bios_ChangeTh() { // 10
+	int th = a0 & 0xff;
+
+	if (Thread[th].status == 0 || CurThread == th) {
+		v0 = 0;
+
+		pc0 = ra;
+	} else {
+		v0 = 1;
+
+		if (Thread[CurThread].status == BFLIP32(2)) {
+			Thread[CurThread].status = BFLIP32(1);
+			Thread[CurThread].func = BFLIP32(ra);
+			memcpy(Thread[CurThread].reg, psxRegs.GPR.r, 32*4);
+		}
+
+		memcpy(psxRegs.GPR.r, Thread[th].reg, 32*4);
+		pc0 = BFLIP32(Thread[th].func);
+		Thread[th].status = BFLIP32(2);
+		CurThread = th;
+	}
+}
+
+static void bios_ReturnFromException() { // 17
+	memcpy(psxRegs.GPR.r, regs, 32*4);
+	psxRegs.GPR.n.lo = regs[32];
+	psxRegs.GPR.n.hi = regs[33];
+
+	pc0 = psxRegs.CP0.n.EPC;
+	if (psxRegs.CP0.n.Cause & 0x80000000) pc0+=4;
+
+	psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
+						  ((psxRegs.CP0.n.Status & 0x3c) >> 2);
+}
+
+static void bios_ResetEntryInt() { // 18
+
+	jmp_int = NULL;
+	pc0 = ra;
+}
+
+static void bios_HookEntryInt() { // 19
+
+	jmp_int = (u32*)Ra0;
+	pc0 = ra;
+}
+
+static void bios_UnDeliverEvent() { // 0x20
+	int ev, spec;
+	int i;
+
+	GetEv();
+	GetSpec();
+
+	if (Event[ev][spec].status == BFLIP32(EvStALREADY) &&
+		Event[ev][spec].mode == BFLIP32(EvMdNOINTR))
+			Event[ev][spec].status = BFLIP32(EvStACTIVE);
+
+	pc0 = ra;
+}
+
+static void bios_GetC0Table() { // 56
+
+	v0 = 0x674; pc0 = ra;
+}
+
+static void bios_GetB0Table() { // 57
+
+	v0 = 0x874; pc0 = ra;
+}
+
+/* System calls C0 */
+
+/*
+ * int SysEnqIntRP(int index , long *queue);
+ */
+
+static void bios_SysEnqIntRP() { // 02
+
+	SysIntRP[a0] = a1;
+
+	v0 = 0; pc0 = ra;
+}
+
+/*
+ * int SysDeqIntRP(int index , long *queue);
+ */
+
+static void bios_SysDeqIntRP() { // 03
+
+	SysIntRP[a0] = 0;
+
+	v0 = 0; pc0 = ra;
+}
+
+static void bios_ChangeClearRCnt() { // 0a
+	u32 *ptr;
+
+	ptr = (u32*)PSXM((a0 << 2) + 0x8600);
+	v0 = BFLIP32(*ptr);
+	*ptr = BFLIP32(a1);
+
+//	psxRegs.CP0.n.Status|= 0x404;
+	pc0 = ra;
+}
+
+static void bios_dummy() { 
+	pc0 = ra; 
+}
+
+void (*biosA0[256])();
+void (*biosB0[256])();
+void (*biosC0[256])();
+
+void psxBiosInit() {
+	u32 base, size;
+	u32 *ptr; 
+	int i;
+
+	heap_addr=0;
+	CurThread = 0;
+	jmp_int = NULL;
+
+	for(i = 0; i < 256; i++) {
+		biosA0[i] = NULL;
+		biosB0[i] = NULL;
+		biosC0[i] = NULL;
+	}
+
+	for(i = 0; i < 256; i++) {
+		if (biosA0[i] == NULL) biosA0[i] = bios_dummy;
+		if (biosB0[i] == NULL) biosB0[i] = bios_dummy;
+		if (biosC0[i] == NULL) biosC0[i] = bios_dummy;
+	}
+
+	biosA0[0x0e] = bios_abs;
+	biosA0[0x0f] = bios_labs;
+	biosA0[0x10] = bios_atoi;  
+	biosA0[0x11] = bios_atol;  
+	//biosA0[0x12] = bios_atob;
+	biosA0[0x13] = bios_setjmp;
+	biosA0[0x14] = bios_longjmp;
+
+	biosA0[0x15] = bios_strcat;
+	biosA0[0x16] = bios_strncat;
+	biosA0[0x17] = bios_strcmp;
+	biosA0[0x18] = bios_strncmp;
+	biosA0[0x19] = bios_strcpy;
+	biosA0[0x1a] = bios_strncpy;
+	biosA0[0x1b] = bios_strlen;
+	biosA0[0x1c] = bios_index;
+	biosA0[0x1d] = bios_rindex;
+	biosA0[0x1e] = bios_strchr;
+	biosA0[0x1f] = bios_strrchr;
+	biosA0[0x20] = bios_strpbrk;
+	biosA0[0x21] = bios_strspn;
+	biosA0[0x22] = bios_strcspn;
+	//biosA0[0x23] = bios_strtok;
+	biosA0[0x24] = bios_strstr;
+	biosA0[0x25] = bios_toupper;
+	biosA0[0x26] = bios_tolower;
+	biosA0[0x27] = bios_bcopy;
+	biosA0[0x28] = bios_bzero;
+	biosA0[0x29] = bios_bcmp;
+	biosA0[0x2a] = bios_memcpy;
+	biosA0[0x2b] = bios_memset;
+	//biosA0[0x2c] = bios_memmove;
+	biosA0[0x2c] = bios_memcpy;	/* Our code should be compatible
+					   with both memcpy and memmove 
+					   semantics. */
+	biosA0[0x2d] = bios_memcmp;
+	biosA0[0x2e] = bios_memchr;
+
+	biosA0[0x2f] = bios_rand;
+	biosA0[0x30] = bios_srand;
+
+	//biosA0[0x31] = bios_qsort;
+	//biosA0[0x32] = bios_strtod;
+	biosA0[0x33] = bios_malloc;
+	//biosA0[0x34] = bios_free;
+    	//biosA0[0x35] = bios_lsearch;
+    	//biosA0[0x36] = bios_bsearch;
+    	//biosA0[0x37] = bios_calloc;
+    	//biosA0[0x38] = bios_realloc;
+	biosA0[0x39] = bios_InitHeap;
+    	//biosA0[0x3a] = bios__exit;
+	biosA0[0x44] = bios_FlushCache;
+    	//biosA0[0x45] = bios_InstallInterruptHandler;
+	//biosA0[0x4f] = bios_sys_a0_4f;
+	//biosA0[0x50] = bios_sys_a0_50;		
+	biosA0[0x70] = bios__bu_init;
+	biosA0[0x71] = bios__96_init;
+	biosA0[0x72] = bios__96_remove;
+	//biosA0[0x73] = bios_sys_a0_73;
+	//biosA0[0x74] = bios_sys_a0_74;
+	//biosA0[0x75] = bios_sys_a0_75;
+	//biosA0[0x76] = bios_sys_a0_76;
+	//biosA0[0x77] = bios_sys_a0_77;
+	//biosA0[0x78] = bios__96_CdSeekL;
+	//biosA0[0x79] = bios_sys_a0_79;
+	//biosA0[0x7a] = bios_sys_a0_7a;
+	//biosA0[0x7b] = bios_sys_a0_7b;
+	//biosA0[0x7c] = bios__96_CdGetStatus;
+	//biosA0[0x7d] = bios_sys_a0_7d;
+	//biosA0[0x7e] = bios__96_CdRead;
+	//biosA0[0x7f] = bios_sys_a0_7f;
+	//biosA0[0x80] = bios_sys_a0_80;
+	//biosA0[0x81] = bios_sys_a0_81;
+	//biosA0[0x82] = bios_sys_a0_82;		
+	//biosA0[0x83] = bios_sys_a0_83;
+	//biosA0[0x84] = bios_sys_a0_84;
+	//biosA0[0x85] = bios__96_CdStop;	
+	//biosA0[0x86] = bios_sys_a0_86;
+	//biosA0[0x87] = bios_sys_a0_87;
+	//biosA0[0x88] = bios_sys_a0_88;
+	//biosA0[0x89] = bios_sys_a0_89;
+	//biosA0[0x8a] = bios_sys_a0_8a;
+	//biosA0[0x8b] = bios_sys_a0_8b;
+	//biosA0[0x8c] = bios_sys_a0_8c;
+	//biosA0[0x8d] = bios_sys_a0_8d;
+	//biosA0[0x8e] = bios_sys_a0_8e;		
+	//biosA0[0x8f] = bios_sys_a0_8f;
+	//biosA0[0x90] = bios_sys_a0_90;
+	//biosA0[0x91] = bios_sys_a0_91;
+	//biosA0[0x92] = bios_sys_a0_92;
+	//biosA0[0x93] = bios_sys_a0_93;
+	//biosA0[0x94] = bios_sys_a0_94;
+	//biosA0[0x95] = bios_sys_a0_95;
+	//biosA0[0x96] = bios_AddCDROMDevice;
+	//biosA0[0x97] = bios_AddMemCardDevide;
+	//biosA0[0x98] = bios_DisableKernelIORedirection;
+	//biosA0[0x99] = bios_EnableKernelIORedirection;
+	//biosA0[0x9a] = bios_sys_a0_9a;
+	//biosA0[0x9b] = bios_sys_a0_9b;
+	//biosA0[0x9c] = bios_SetConf;
+	//biosA0[0x9d] = bios_GetConf;
+	//biosA0[0x9e] = bios_sys_a0_9e;
+	//biosA0[0x9f] = bios_SetMem;
+	//biosA0[0xa0] = bios__boot;
+	//biosA0[0xa1] = bios_SystemError;
+	//biosA0[0xa2] = bios_EnqueueCdIntr;
+	//biosA0[0xa3] = bios_DequeueCdIntr;
+	//biosA0[0xa4] = bios_sys_a0_a4;
+	//biosA0[0xa5] = bios_ReadSector;
+	//biosA0[0xa6] = bios_get_cd_status;
+	//biosA0[0xa7] = bios_bufs_cb_0;
+	//biosA0[0xa8] = bios_bufs_cb_1;
+	//biosA0[0xa9] = bios_bufs_cb_2;
+	//biosA0[0xaa] = bios_bufs_cb_3;
+	//biosA0[0xab] = bios__card_info;
+	//biosA0[0xac] = bios__card_load;
+	//biosA0[0axd] = bios__card_auto;
+	//biosA0[0xae] = bios_bufs_cd_4;
+	//biosA0[0xaf] = bios_sys_a0_af;
+	//biosA0[0xb0] = bios_sys_a0_b0;
+	//biosA0[0xb1] = bios_sys_a0_b1;
+	//biosA0[0xb2] = bios_do_a_long_jmp
+	//biosA0[0xb3] = bios_sys_a0_b3;
+	//biosA0[0xb4] = bios_sub_function;
+//*******************B0 CALLS****************************
+	//biosB0[0x00] = bios_SysMalloc;
+	//biosB0[0x01] = bios_sys_b0_01;
+	biosB0[0x02] = bios_SetRCnt;
+	biosB0[0x03] = bios_GetRCnt;
+	biosB0[0x04] = bios_StartRCnt;
+	biosB0[0x05] = bios_StopRCnt;
+	biosB0[0x06] = bios_ResetRCnt;
+	biosB0[0x07] = bios_DeliverEvent;
+	biosB0[0x08] = bios_OpenEvent;
+	biosB0[0x09] = bios_CloseEvent;
+	biosB0[0x0a] = bios_WaitEvent;
+	biosB0[0x0b] = bios_TestEvent;
+	biosB0[0x0c] = bios_EnableEvent;
+	biosB0[0x0d] = bios_DisableEvent;
+	biosB0[0x0e] = bios_OpenTh;
+	biosB0[0x0f] = bios_CloseTh;
+	biosB0[0x10] = bios_ChangeTh;
+	//biosB0[0x11] = bios_bios_b0_11;
+	biosB0[0x17] = bios_ReturnFromException;
+	biosB0[0x18] = bios_ResetEntryInt;
+	biosB0[0x19] = bios_HookEntryInt;
+	//biosB0[0x1a] = bios_sys_b0_1a;
+	//biosB0[0x1b] = bios_sys_b0_1b;
+	//biosB0[0x1c] = bios_sys_b0_1c;
+	//biosB0[0x1d] = bios_sys_b0_1d;
+	//biosB0[0x1e] = bios_sys_b0_1e;
+	//biosB0[0x1f] = bios_sys_b0_1f;
+	biosB0[0x20] = bios_UnDeliverEvent;
+	//biosB0[0x21] = bios_sys_b0_21;
+	//biosB0[0x22] = bios_sys_b0_22;
+	//biosB0[0x23] = bios_sys_b0_23;
+	//biosB0[0x24] = bios_sys_b0_24;
+	//biosB0[0x25] = bios_sys_b0_25;
+	//biosB0[0x26] = bios_sys_b0_26;
+	//biosB0[0x27] = bios_sys_b0_27;
+	//biosB0[0x28] = bios_sys_b0_28;
+	//biosB0[0x29] = bios_sys_b0_29;
+	//biosB0[0x2a] = bios_sys_b0_2a;
+	//biosB0[0x2b] = bios_sys_b0_2b;
+	//biosB0[0x2c] = bios_sys_b0_2c;
+	//biosB0[0x2d] = bios_sys_b0_2d;
+	//biosB0[0x2e] = bios_sys_b0_2e;
+	//biosB0[0x2f] = bios_sys_b0_2f;
+	//biosB0[0x30] = bios_sys_b0_30;
+	//biosB0[0x31] = bios_sys_b0_31;
+	biosB0[0x56] = bios_GetC0Table;
+	biosB0[0x57] = bios_GetB0Table;
+	//biosB0[0x58] = bios__card_chan;
+	//biosB0[0x59] = bios_sys_b0_59;
+	//biosB0[0x5a] = bios_sys_b0_5a;
+	//biosB0[0x5c] = bios__card_status;
+	//biosB0[0x5d] = bios__card_wait;
+//*******************C0 CALLS****************************
+	//biosC0[0x00] = bios_InitRCnt;
+	//biosC0[0x01] = bios_InitException;
+	biosC0[0x02] = bios_SysEnqIntRP;
+	biosC0[0x03] = bios_SysDeqIntRP;
+	//biosC0[0x04] = bios_get_free_EvCB_slot;
+	//biosC0[0x05] = bios_get_free_TCB_slot;
+	//biosC0[0x06] = bios_ExceptionHandler;
+	//biosC0[0x07] = bios_InstallExeptionHandler;
+	//biosC0[0x08] = bios_SysInitMemory;
+	//biosC0[0x09] = bios_SysInitKMem;
+	biosC0[0x0a] = bios_ChangeClearRCnt;	
+	//biosC0[0x0b] = bios_SystemError;
+	//biosC0[0x0c] = bios_InitDefInt;
+	//biosC0[0x0d] = bios_sys_c0_0d;
+	//biosC0[0x0e] = bios_sys_c0_0e;
+	//biosC0[0x0f] = bios_sys_c0_0f;
+	//biosC0[0x10] = bios_sys_c0_10;
+	//biosC0[0x11] = bios_sys_c0_11;
+	//biosC0[0x12] = bios_InstallDevices;
+	//biosC0[0x13] = bios_FlushStfInOutPut;
+	//biosC0[0x14] = bios_sys_c0_14;
+	//biosC0[0x15] = bios__cdevinput;
+	//biosC0[0x16] = bios__cdevscan;
+	//biosC0[0x17] = bios__circgetc;
+	//biosC0[0x18] = bios__circputc;		  
+	//biosC0[0x19] = bios_ioabort;
+	//biosC0[0x1a] = bios_sys_c0_1a
+	//biosC0[0x1b] = bios_KernelRedirect;
+	//biosC0[0x1c] = bios_PatchAOTable;
+//************** THE END ***************************************
+
+	base = 0x1000;
+	size = sizeof(EvCB) * 32;
+	Event = (void *)&psxR[base]; base+= size*6;
+	memset(Event, 0, size * 6);
+	//HwEV = Event;
+	//EvEV = Event + 32;
+	RcEV = Event + 32*2;
+	//UeEV = Event + 32*3;
+	//SwEV = Event + 32*4;
+	//ThEV = Event + 32*5;
+
+	ptr = (u32*)&psxM[0x0874]; // b0 table
+	ptr[0] = BFLIP32(0x4c54 - 0x884);
+
+	ptr = (u32*)&psxM[0x0674]; // c0 table
+	ptr[6] = BFLIP32(0xc80);
+
+	memset(SysIntRP, 0, sizeof(SysIntRP));
+	memset(Thread, 0, sizeof(Thread));
+	Thread[0].status = BFLIP32(2); // main thread
+
+	psxMu32(0x0150) = BFLIP32(0x160);
+	psxMu32(0x0154) = BFLIP32(0x320);
+	psxMu32(0x0160) = BFLIP32(0x248);
+	strcpy(&psxM[0x248], "bu");
+
+/*	psxMu32(0x0ca8) = BFLIP32(0x1f410004);
+	psxMu32(0x0cf0) = BFLIP32(0x3c020000);
+	psxMu32(0x0cf4) = BFLIP32(0x2442641c);
+	psxMu32(0x09e0) = BFLIP32(0x43d0);
+	psxMu32(0x4d98) = BFLIP32(0x946f000a);
+*/
+	// opcode HLE
+	psxRu32(0x0000) = BFLIP32((0x3b << 26) | 4);
+	psxMu32(0x0000) = BFLIP32((0x3b << 26) | 0);
+	psxMu32(0x00a0) = BFLIP32((0x3b << 26) | 1);
+	psxMu32(0x00b0) = BFLIP32((0x3b << 26) | 2);
+	psxMu32(0x00c0) = BFLIP32((0x3b << 26) | 3);
+	psxMu32(0x4c54) = BFLIP32((0x3b << 26) | 0);
+	psxMu32(0x8000) = BFLIP32((0x3b << 26) | 5);
+	psxMu32(0x07a0) = BFLIP32((0x3b << 26) | 0);
+	psxMu32(0x0884) = BFLIP32((0x3b << 26) | 0);
+	psxMu32(0x0894) = BFLIP32((0x3b << 26) | 0);
+}
+
+void psxBiosShutdown() {
+}
+
+void biosInterrupt() {
+	if (BFLIP32(psxHu32(0x1070)) & 0x1) { // Vsync
+		if (RcEV[3][1].status == BFLIP32(EvStACTIVE)) {
+			softCall(BFLIP32(RcEV[3][1].fhandler));
+//			hwWrite32(0x1f801070, ~(1));
+		}
+	}
+
+	if (BFLIP32(psxHu32(0x1070)) & 0x70) { // Rcnt 0,1,2
+		int i;
+
+		for (i=0; i<3; i++) {
+			if (BFLIP32(psxHu32(0x1070)) & (1 << (i+4))) {
+				if (RcEV[i][1].status == BFLIP32(EvStACTIVE)) {
+					softCall(BFLIP32(RcEV[i][1].fhandler));
+					psxHwWrite32(0x1f801070, ~(1 << (i+4)));
+				}
+			}
+		}
+	}
+}
+
+static INLINE void SaveRegs() {
+        memcpy(regs, psxRegs.GPR.r, 32*4);
+        regs[32] = psxRegs.GPR.n.lo;
+        regs[33] = psxRegs.GPR.n.hi;
+        regs[34] = psxRegs.pc;
+}
+
+void psxBiosException() {
+	int i;
+
+	switch (psxRegs.CP0.n.Cause & 0x3c) {
+		case 0x00: // Interrupt
+#ifdef PSXCPU_LOG
+//			PSXCPU_LOG("interrupt\n");
+#endif
+			SaveRegs();
+
+			biosInterrupt();
+
+			for (i=0; i<8; i++) {
+				if (SysIntRP[i]) {
+					u32 *queue = (u32*)PSXM(SysIntRP[i]);
+
+					s0 = BFLIP32(queue[2]);
+					softCall(BFLIP32(queue[1]));
+				}
+			}
+
+			if (jmp_int != NULL) {
+				int i;
+
+				psxHwWrite32(0x1f801070, 0xffffffff);
+
+				ra = BFLIP32(jmp_int[0]);
+				sp = BFLIP32(jmp_int[1]);
+				fp = BFLIP32(jmp_int[2]);
+				for (i=0; i<8; i++) // s0-s7
+					 psxRegs.GPR.r[16+i] = BFLIP32(jmp_int[3+i]);
+				gp = BFLIP32(jmp_int[11]);
+
+				v0 = 1;
+				pc0 = ra;
+				return;
+			}
+			psxHwWrite16(0x1f801070, 0);
+			break;
+		case 0x20: // Syscall
+#ifdef PSXCPU_LOG
+//			PSXCPU_LOG("syscall exp %x\n", a0);
+#endif
+			switch (a0) {
+				case 1: // EnterCritical - disable irq's
+					psxRegs.CP0.n.Status&=~0x404; break;
+				case 2: // ExitCritical - enable irq's
+					psxRegs.CP0.n.Status|= 0x404; break;
+			}
+			pc0 = psxRegs.CP0.n.EPC + 4;
+
+			psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
+								  ((psxRegs.CP0.n.Status & 0x3c) >> 2);
+			return;
+		default:
+#ifdef PSXCPU_LOG
+			PSXCPU_LOG("unk exp\n");
+#endif
+			break;
+	}
+
+	pc0 = psxRegs.CP0.n.EPC;
+	if (psxRegs.CP0.n.Cause & 0x80000000) pc0+=4;
+
+	psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
+						  ((psxRegs.CP0.n.Status & 0x3c) >> 2);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxBios.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,34 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PSXBIOS_H__
+#define __PSXBIOS_H__
+
+extern char *biosA0n[256];
+extern char *biosB0n[256];
+extern char *biosC0n[256];
+
+void psxBiosInit();
+void psxBiosShutdown();
+void psxBiosException();
+
+extern void (*biosA0[256])();
+extern void (*biosB0[256])();
+extern void (*biosC0[256])();
+
+#endif /* __PSXBIOS_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxCommon.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,59 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PSXCOMMON_H__
+#define __PSXCOMMON_H__
+
+#if PSS_STYLE==2
+
+#define PSS "\\"
+#define PS '\\'
+
+#elif PSS_STYLE==1
+
+#define PSS "/"
+#define PS '/'
+
+#elif PSS_STYLE==3
+
+#define PSS "\\"
+#define PS '\\'
+#endif
+
+#include <zlib.h>
+
+#include <sys/types.h>
+#include "types.h"
+
+void __Log(char *fmt, ...);
+
+#define BIAS	2
+#define PSXCLK	33868800	/* 33.8688 Mhz */
+
+#include "R3000A.h"
+#include "PsxMem.h"
+#include "PsxHw.h"
+#include "PsxBios.h"
+#include "PsxDma.h"
+#include "PsxCounters.h"
+#include "PsxHLE.h"
+#include "Spu.h"
+#include "Misc.h"
+#include "spu/spu.h"
+
+#endif /* __PSXCOMMON_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxCounters.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,247 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+
+#include "PsxCommon.h"
+
+static int cnts = 4;
+static u32 last=0;
+
+static void psxRcntUpd(u32 index) {
+	psxCounters[index].sCycle = psxRegs.cycle;
+	if (((!(psxCounters[index].mode & 1)) || (index!=2)) &&
+		psxCounters[index].mode & 0x30) {
+		if (psxCounters[index].mode & 0x10) { // Interrupt on target
+			psxCounters[index].Cycle = ((psxCounters[index].target - psxCounters[index].count) * psxCounters[index].rate) / BIAS;
+		} else { // Interrupt on 0xffff
+			psxCounters[index].Cycle = ((0xffff - psxCounters[index].count) * psxCounters[index].rate) / BIAS;
+		}
+	} else psxCounters[index].Cycle = 0xffffffff;
+}
+
+static void psxRcntReset(u32 index) {
+	psxCounters[index].count = 0;
+	psxRcntUpd(index);
+
+	psxHu32(0x1070)|= BFLIP32(psxCounters[index].interrupt);
+	if (!(psxCounters[index].mode & 0x40)) { // Only 1 interrupt
+		psxCounters[index].Cycle = 0xffffffff;
+	}
+}
+
+static void psxRcntSet() {
+	int i;
+
+	psxNextCounter = 0x7fffffff;
+	psxNextsCounter = psxRegs.cycle;
+
+	for (i=0; i<cnts; i++) {
+		s32 count;
+
+		if (psxCounters[i].Cycle == 0xffffffff) continue;
+
+		count = psxCounters[i].Cycle - (psxRegs.cycle - psxCounters[i].sCycle);
+
+		if (count < 0) {
+			psxNextCounter = 0; break;
+		}
+
+		if (count < (s32)psxNextCounter) {
+			psxNextCounter = count;
+		}
+	}
+}
+
+void psxRcntInit() {
+
+	memset(psxCounters, 0, sizeof(psxCounters));
+
+        psxCounters[0].rate = 1; psxCounters[0].interrupt = 0x10;
+        psxCounters[1].rate = 1; psxCounters[1].interrupt = 0x20;
+	psxCounters[2].rate = 1; psxCounters[2].interrupt = 64;
+
+	psxCounters[3].interrupt = 1;
+	psxCounters[3].mode = 0x58; // The VSync counter mode
+	psxCounters[3].target = 1;
+	psxUpdateVSyncRate();
+
+	cnts = 4;
+
+        psxRcntUpd(0); psxRcntUpd(1); psxRcntUpd(2); psxRcntUpd(3);
+        psxRcntSet();
+	last=0;
+}
+
+
+int CounterSPURun(void)
+{
+ u32 cycles;
+
+ if(psxRegs.cycle<last)
+ {
+  cycles=0xFFFFFFFF-last;
+  cycles+=psxRegs.cycle;
+ }
+ else
+  cycles=psxRegs.cycle-last;
+
+ if(cycles>=16)
+ {
+  if(!SPUasync(cycles)) return(0);
+  last=psxRegs.cycle;
+ }
+ return(1);
+}
+
+/* Set by spu irq stuff in spu code to number of cpu cycles to back
+   up(if necessary).  Very crazy hack.  Eh, not implemented.  Hmm.
+   TODO!
+*/
+s32 spuirqvoodoo=-1;
+
+void CounterDeadLoopSkip()
+{
+	s32 min,x,lmin;
+
+	lmin=0x7FFFFFFF;
+
+	for(x=0;x<4;x++)
+	{
+	 if (psxCounters[x].Cycle != 0xffffffff)
+	 {
+ 	  min=psxCounters[x].Cycle;
+	  min-=(psxRegs.cycle - psxCounters[x].sCycle);
+	  if(min<lmin) lmin=min;
+//	  if(min<0) exit();
+//	  printf("Poo: %d, ",min);
+	 }
+	}
+
+	if(lmin>0)
+	{
+//	 printf("skip %u\n",lmin);
+	 psxRegs.cycle+=lmin;
+	}
+}
+
+void psxUpdateVSyncRate() {
+        //if (Config.PsxType) // ntsc - 0 | pal - 1
+        //     psxCounters[3].rate = (PSXCLK / 50);// / BIAS;
+        //else 
+	psxCounters[3].rate = (PSXCLK / 60);// / BIAS;
+}
+
+void psxRcntUpdate() 
+{
+        if ((psxRegs.cycle - psxCounters[3].sCycle) >= psxCounters[3].Cycle) {
+		//printf("%d\n",(psxRegs.cycle - psxCounters[3].sCycle)- psxCounters[3].Cycle);
+                psxRcntUpd(3);
+                psxHu32(0x1070)|= BFLIP32(1);
+        }
+        if ((psxRegs.cycle - psxCounters[0].sCycle) >= psxCounters[0].Cycle) {
+                psxRcntReset(0);
+        }
+                
+        if ((psxRegs.cycle - psxCounters[1].sCycle) >= psxCounters[1].Cycle) {  
+                psxRcntReset(1);
+        }
+                 
+        if ((psxRegs.cycle - psxCounters[2].sCycle) >= psxCounters[2].Cycle) {
+                psxRcntReset(2);
+        }
+
+        psxRcntSet();
+
+}
+
+void psxRcntWcount(u32 index, u32 value) {
+	psxCounters[index].count = value;
+	psxRcntUpd(index);
+	psxRcntSet();
+}
+
+void psxRcntWmode(u32 index, u32 value)  {
+	psxCounters[index].mode = value;
+	psxCounters[index].count = 0;
+
+        if(index == 0) {
+                switch (value & 0x300) {
+                        case 0x100:
+                                psxCounters[index].rate = ((psxCounters[3].rate /** BIAS*/) / 386) / 262; // seems ok
+                                break;
+                        default:
+                                psxCounters[index].rate = 1;
+                }
+        }
+        else if(index == 1) {
+                switch (value & 0x300) {
+                        case 0x100:
+                                psxCounters[index].rate = (psxCounters[3].rate /** BIAS*/) / 262; // seems ok
+				//psxCounters[index].rate = (PSXCLK / 60)/262; //(psxCounters[3].rate*16/262);
+				//printf("%d\n",psxCounters[index].rate);
+                                break;
+                        default:
+                                psxCounters[index].rate = 1;
+                }
+        }
+	else if(index == 2) {
+		switch (value & 0x300) {
+			case 0x200:
+				psxCounters[index].rate = 8; // 1/8 speed
+				break;
+			default:
+				psxCounters[index].rate = 1; // normal speed
+		}
+	}
+
+	// Need to set a rate and target
+	psxRcntUpd(index);
+	psxRcntSet();
+}
+
+void psxRcntWtarget(u32 index, u32 value) {
+//	SysPrintf("writeCtarget[%ld] = %lx\n", index, value);
+	psxCounters[index].target = value;
+	psxRcntUpd(index);
+	psxRcntSet();
+}
+
+u32 psxRcntRcount(u32 index) {
+	u32 ret;
+
+//	if ((!(psxCounters[index].mode & 1)) || (index!=2)) {
+		if (psxCounters[index].mode & 0x08) { // Wrap at target
+			//if (Config.RCntFix) { // Parasite Eve 2
+			//	ret = (psxCounters[index].count + /*BIAS **/ ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff;
+			//} else {
+				ret = (psxCounters[index].count + BIAS * ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff;
+			//}
+		} else { // Wrap at 0xffff
+			ret = (psxCounters[index].count + BIAS * (psxRegs.cycle / psxCounters[index].rate)) & 0xffff;
+			//if (Config.RCntFix) { // Vandal Hearts 1/2
+			//	ret/= 16;
+			//}
+		}
+//		return (psxCounters[index].count + BIAS * ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff;
+//	} else return 0;
+
+//	SysPrintf("readCcount[%ld] = %lx (mode %lx, target %lx, cycle %lx)\n", index, ret, psxCounters[index].mode, psxCounters[index].target, psxRegs.cycle);
+
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxCounters.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,43 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PSXCOUNTERS_H__
+#define __PSXCOUNTERS_H__
+
+typedef struct {
+	u32 count, mode, target;
+	u32 sCycle, Cycle, rate, interrupt;
+} psxCounter;
+
+psxCounter psxCounters[5];
+
+u32 psxNextCounter, psxNextsCounter;
+
+void psxRcntInit();
+void psxRcntUpdate();
+void psxRcntWcount(u32 index, u32 value);
+void psxRcntWmode(u32 index, u32 value);
+void psxRcntWtarget(u32 index, u32 value);
+u32 psxRcntRcount(u32 index);
+
+void psxUpdateVSyncRate();
+
+int CounterSPURun(void);
+void CounterDeadLoopSkip();
+
+#endif /* __PSXCOUNTERS_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxDma.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,59 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "PsxCommon.h"
+
+void psxDma4(u32 madr, u32 bcr, u32 chcr) { // SPU
+	switch (chcr) {
+		case 0x01000201: //cpu to spu transfer
+		{
+		 bcr= (bcr>>16) * (bcr&0xffff) * 2;
+
+		 //printf("%08x, %08x\n",madr,bcr);
+		 SPUwriteDMAMem(madr, bcr);		
+		}
+		break;
+		case 0x01000200: //spu to cpu transfer
+		{
+		 //printf("%08x\n",madr);
+	  	 SPUreadDMAMem (madr, (bcr >> 16) * (bcr & 0xffff) * 2);
+		}
+		break;
+	}
+}
+
+void psxDma6(u32 madr, u32 bcr, u32 chcr) {
+	u32 *mem = (u32 *)PSXM(madr);
+
+#ifdef PSXDMA_LOG
+	PSXDMA_LOG("*** DMA 6 - OT *** %lx addr = %lx size = %lx\n", chcr, madr, bcr);
+#endif
+
+	if (chcr == 0x11000002) {
+		while (bcr--) {
+			*mem-- = (madr - 4) & 0xffffff;
+			madr -= 4;
+		}
+		mem++; *mem = 0xffffff;
+	} else {
+		// Unknown option
+#ifdef PSXDMA_LOG
+		PSXDMA_LOG("*** DMA 6 - OT unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr);
+#endif
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxDma.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,27 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PSXDMA_H__
+#define __PSXDMA_H__
+
+void psxDma2(u32 madr, u32 bcr, u32 chcr);
+void psxDma3(u32 madr, u32 bcr, u32 chcr);
+void psxDma4(u32 madr, u32 bcr, u32 chcr);
+void psxDma6(u32 madr, u32 bcr, u32 chcr);
+
+#endif /* __PSXDMA_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxHLE.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,93 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "PsxCommon.h"
+
+static void hleDummy() {
+	psxRegs.pc = psxRegs.GPR.n.ra;
+
+	psxBranchTest();
+}
+
+static void hleA0() {
+	u32 call = psxRegs.GPR.n.t1 & 0xff;
+
+	if (biosA0[call]) biosA0[call]();
+	//else
+	// printf("Unknown A0: %08x\n",call);
+	psxBranchTest();
+}
+
+static void hleB0() {
+	u32 call = psxRegs.GPR.n.t1 & 0xff;
+
+	if (biosB0[call]) biosB0[call]();
+        //else
+        // printf("Unknown B0: %08x\n",call);
+
+	psxBranchTest();
+}
+
+static void hleC0() {
+	u32 call = psxRegs.GPR.n.t1 & 0xff;
+
+	if (biosC0[call]) biosC0[call]();
+        //else
+        // printf("Unknown C0: %08x\n",call);
+
+	psxBranchTest();
+}
+
+static void hleBootstrap() { // 0xbfc00000
+	//SysPrintf("hleBootstrap\n");
+}
+
+typedef struct {                   
+	u32 _pc0;      
+	u32 gp0;      
+	u32 t_addr;   
+	u32 t_size;   
+	u32 d_addr;   
+	u32 d_size;   
+	u32 b_addr;   
+	u32 b_size;   
+	u32 S_addr;
+	u32 s_size;
+	u32 _sp,_fp,_gp,ret,base;
+} PACKSTRUCT EXEC;
+
+static void hleExecRet() {
+	EXEC *header = (EXEC*)PSXM(psxRegs.GPR.n.s0);
+
+	//SysPrintf("ExecRet %x: %x\n", psxRegs.GPR.n.s0, header->ret);
+
+	psxRegs.GPR.n.ra = BFLIP32(header->ret);
+	psxRegs.GPR.n.sp = BFLIP32(header->_sp);
+	psxRegs.GPR.n.s8 = BFLIP32(header->_fp);
+	psxRegs.GPR.n.gp = BFLIP32(header->_gp);
+	psxRegs.GPR.n.s0 = BFLIP32(header->base);
+
+	psxRegs.GPR.n.v0 = 1;
+	psxRegs.pc = psxRegs.GPR.n.ra;
+}
+
+void (*psxHLEt[256])() = {
+	hleDummy, hleA0, hleB0, hleC0,
+	hleBootstrap, hleExecRet
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxHLE.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,24 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PSXHLE_H__
+#define __PSXHLE_H__
+
+extern void (*psxHLEt[256])();
+
+#endif /* __PSXHLE_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxHw.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,236 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "PsxCommon.h"
+
+#define HW_DMA4_MADR (psxHu32(0x10c0)) // SPU DMA
+#define HW_DMA4_BCR  (psxHu32(0x10c4))
+#define HW_DMA4_CHCR (psxHu32(0x10c8))
+
+#define HW_DMA_PCR   (psxHu32(0x10f0))
+#define HW_DMA_ICR   (psxHu32(0x10f4))
+
+void psxHwReset() {
+	memset(psxH, 0, 0x10000);
+	psxRcntInit();
+}
+
+u8 psxHwRead8(u32 add) {
+	u8 hard;
+
+	switch (add) {
+		default:
+			hard = psxHu8(add); 
+			return hard;
+	}
+	return hard;
+}
+
+u16 psxHwRead16(u32 add) {
+	u16 hard;
+
+	switch (add) {
+                case 0x1f801100:
+                        hard = psxRcntRcount(0);
+                        return hard;
+                case 0x1f801104:
+                        hard = psxCounters[0].mode;
+                        return hard;
+                case 0x1f801108:
+                        hard = psxCounters[0].target;
+                        return hard;
+                case 0x1f801110:
+                        hard = psxRcntRcount(1);
+                        return hard;
+                case 0x1f801114:
+                        hard = psxCounters[1].mode;
+                        return hard;
+                case 0x1f801118:
+                        hard = psxCounters[1].target;
+                        return hard;
+		case 0x1f801120:
+			hard = psxRcntRcount(2);
+			return hard;
+		case 0x1f801124:
+			hard = psxCounters[2].mode;
+			return hard;
+		case 0x1f801128:
+			hard = psxCounters[2].target;
+			return hard;
+	
+		default:
+			if (add>=0x1f801c00 && add<0x1f801e00) {
+            		  hard = SPUreadRegister(add);
+			} else {
+				hard = BFLIP16(psxHu16(add)); 
+			}
+            return hard;
+	}
+	return hard;
+}
+
+u32 psxHwRead32(u32 add) {
+	u32 hard;
+
+	switch (add) {
+		// time for rootcounters :)
+                case 0x1f801100:
+                        hard = psxRcntRcount(0);
+                        return hard;
+                case 0x1f801104:
+                        hard = psxCounters[0].mode;
+                        return hard;
+                case 0x1f801108:
+                        hard = psxCounters[0].target;
+                        return hard;
+               case 0x1f801110:
+                        hard = psxRcntRcount(1);
+                        return hard;
+                case 0x1f801114:
+                        hard = psxCounters[1].mode;
+                        return hard;
+                case 0x1f801118:
+                        hard = psxCounters[1].target;
+                        return hard;
+		case 0x1f801120:
+			hard = psxRcntRcount(2);
+			return hard;
+		case 0x1f801124:
+			hard = psxCounters[2].mode;
+			return hard;
+		case 0x1f801128:
+			hard = psxCounters[2].target;
+			return hard;
+
+		default:
+			hard = BFLIP32(psxHu32(add)); 
+			return hard;
+	}
+	return hard;
+}
+
+void psxHwWrite8(u32 add, u8 value) {
+	switch (add) {
+		default:
+			psxHu8(add) = value;
+			return;
+	}
+	psxHu8(add) = value;
+}
+
+void psxHwWrite16(u32 add, u16 value) {
+	switch (add) {
+
+		case 0x1f801070: 
+			psxHu16(0x1070) &= BFLIP16( BFLIP16(psxHu16(0x1074)) & value);
+			return;
+                case 0x1f801100:
+                        psxRcntWcount(0, value); return;
+                case 0x1f801104:
+                        psxRcntWmode(0, value); return;
+                case 0x1f801108:
+                        psxRcntWtarget(0, value); return;
+                
+                case 0x1f801110:
+                        psxRcntWcount(1, value); return;
+                case 0x1f801114:
+                        psxRcntWmode(1, value); return;
+                case 0x1f801118:
+                        psxRcntWtarget(1, value); return;
+        
+                case 0x1f801120:
+                        psxRcntWcount(2, value); return;
+                case 0x1f801124:
+                        psxRcntWmode(2, value); return;
+                case 0x1f801128:
+                        psxRcntWtarget(2, value); return;
+
+		default:
+			if (add>=0x1f801c00 && add<0x1f801e00) {
+            			SPUwriteRegister(add, value);
+				return;
+			}
+
+			psxHu16(add) = BFLIP16(value);
+			return;
+	}
+	psxHu16(add) = BFLIP16(value);
+}
+
+#define	DMA_INTERRUPT(n) \
+	if (BFLIP32(HW_DMA_ICR) & (1 << (16 + n))) { \
+		HW_DMA_ICR|= BFLIP32(1 << (24 + n)); \
+		psxHu32(0x1070) |= BFLIP32(8); \
+	}
+
+#define DmaExec(n) { \
+	if (BFLIP32(HW_DMA##n##_CHCR) & 0x01000000 && BFLIP32(HW_DMA_PCR) & (8 << (n * 4))) { \
+		psxDma##n(BFLIP32(HW_DMA##n##_MADR), BFLIP32(HW_DMA##n##_BCR), BFLIP32(HW_DMA##n##_CHCR)); \
+		HW_DMA##n##_CHCR &= BFLIP32(~0x01000000); \
+		DMA_INTERRUPT(n); \
+	} \
+}
+
+void psxHwWrite32(u32 add, u32 value) {
+	switch (add) {
+		case 0x1f801070: 
+			psxHu32(0x1070) &= BFLIP32(BFLIP32(psxHu32(0x1074)) & value);
+			return;
+		case 0x1f8010c8:
+			HW_DMA4_CHCR = BFLIP32(value);        // DMA4 chcr (SPU DMA)
+			DmaExec(4);
+			return;
+		case 0x1f8010f4:
+		{
+			u32 tmp = (~value) & BFLIP32(HW_DMA_ICR);
+			HW_DMA_ICR = BFLIP32(((tmp ^ value) & 0xffffff) ^ tmp);
+			return;
+		}
+
+                case 0x1f801100:
+                        psxRcntWcount(0, value & 0xffff); return;
+                case 0x1f801104:
+                        psxRcntWmode(0, value); return;
+                case 0x1f801108:
+                        psxRcntWtarget(0, value & 0xffff); return; 
+                                //  HW_DMA_ICR&= (~value)&0xff000000;
+                
+                case 0x1f801110:
+                        psxRcntWcount(1, value & 0xffff); return;
+                case 0x1f801114:
+                        psxRcntWmode(1, value); return;
+                case 0x1f801118:
+                        psxRcntWtarget(1, value & 0xffff); return;
+
+		case 0x1f801120:
+			psxRcntWcount(2, value & 0xffff); return;
+		case 0x1f801124:
+			psxRcntWmode(2, value); return;
+		case 0x1f801128:
+			psxRcntWtarget(2, value & 0xffff); return;
+
+		default:
+			psxHu32(add) = BFLIP32(value);
+			return;
+	}
+	psxHu32(add) = BFLIP32(value);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxHw.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,30 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PSXHW_H__
+#define __PSXHW_H__
+
+void psxHwReset();
+u8   psxHwRead8 (u32 add);
+u16  psxHwRead16(u32 add);
+u32  psxHwRead32(u32 add);
+void psxHwWrite8 (u32 add, u8  value);
+void psxHwWrite16(u32 add, u16 value);
+void psxHwWrite32(u32 add, u32 value);
+
+#endif /* __PSXHW_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxInterpreter.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,747 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdlib.h>
+
+#include "PsxCommon.h"
+
+static int branch;
+static int branch2;
+static u32 branchPC;
+
+// These macros are used to assemble the repassembler functions
+
+//        if(!PSXM(psxRegs.pc)) puts("Whoops");   
+//	  Fix this...
+
+//        printf("%08x ", psxRegs.pc);
+
+#define execI() { \
+	psxRegs.code = BFLIP32(PSXMu32(psxRegs.pc)); \
+        	\
+	psxRegs.pc+= 4; psxRegs.cycle++; \
+	psxBSC[psxRegs.code >> 26](); \
+}
+
+// Subsets
+static void (*psxBSC[64])();
+static void (*psxSPC[64])();
+static void (*psxREG[32])();
+static void (*psxCP0[32])();
+
+static void delayRead(int reg, u32 bpc) {
+	u32 rold, rnew;
+
+//	SysPrintf("delayRead at %x!\n", psxRegs.pc);
+
+	rold = psxRegs.GPR.r[reg];
+	psxBSC[psxRegs.code >> 26](); // branch delay load
+	rnew = psxRegs.GPR.r[reg];
+
+	psxRegs.pc = bpc;
+
+	psxBranchTest();
+
+	psxRegs.GPR.r[reg] = rold;
+	execI(); // first branch opcode
+	psxRegs.GPR.r[reg] = rnew;
+
+	branch = 0;
+}
+
+static void delayWrite(int reg, u32 bpc) {
+
+/*	SysPrintf("delayWrite at %x!\n", psxRegs.pc);
+
+//	SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4));
+//	SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/
+
+	// no changes from normal behavior
+
+	psxBSC[psxRegs.code >> 26]();
+
+	branch = 0;
+	psxRegs.pc = bpc;
+
+	psxBranchTest();
+}
+
+static void delayReadWrite(int reg, u32 bpc) {
+
+//	SysPrintf("delayReadWrite at %x!\n", psxRegs.pc);
+
+	// the branch delay load is skipped
+
+	branch = 0;
+	psxRegs.pc = bpc;
+
+	psxBranchTest();
+}
+
+// this defines shall be used with the tmp 
+// of the next func (instead of _Funct_...)
+#define _tFunct_  ((tmp      ) & 0x3F)  // The funct part of the instruction register 
+#define _tRd_     ((tmp >> 11) & 0x1F)  // The rd part of the instruction register 
+#define _tRt_     ((tmp >> 16) & 0x1F)  // The rt part of the instruction register 
+#define _tRs_     ((tmp >> 21) & 0x1F)  // The rs part of the instruction register 
+#define _tSa_     ((tmp >>  6) & 0x1F)  // The sa part of the instruction register
+
+static void psxDelayTest(u32 reg, u32 bpc) {
+	u32 tmp;
+
+	tmp = BFLIP32(PSXMu32(bpc));
+	branch = 1;
+
+	switch (tmp >> 26) {
+		case 0x00: // SPECIAL
+			switch (_tFunct_) {
+				case 0x00: // SLL
+					if (!tmp) break; // NOP
+				case 0x02: case 0x03: // SRL/SRA
+					if (_tRd_ == reg && _tRt_ == reg) {
+						delayReadWrite(reg, bpc); return;
+					} else if (_tRt_ == reg) {
+						delayRead(reg, bpc); return;
+					} else if (_tRd_ == reg) {
+						delayWrite(reg, bpc); return;
+					}
+					break;
+
+				case 0x08: // JR
+					if (_tRs_ == reg) {
+						delayRead(reg, bpc); return;
+					}
+					break;
+				case 0x09: // JALR
+					if (_tRd_ == reg && _tRs_ == reg) {
+						delayReadWrite(reg, bpc); return;
+					} else if (_tRs_ == reg) {
+						delayRead(reg, bpc); return;
+					} else if (_tRd_ == reg) {
+						delayWrite(reg, bpc); return;
+					}
+					break;
+
+				// SYSCALL/BREAK just a break;
+
+				case 0x20: case 0x21: case 0x22: case 0x23:
+				case 0x24: case 0x25: case 0x26: case 0x27: 
+				case 0x2a: case 0x2b: // ADD/ADDU...
+				case 0x04: case 0x06: case 0x07: // SLLV...
+					if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) {
+						delayReadWrite(reg, bpc); return;
+					} else if (_tRt_ == reg || _tRs_ == reg) {
+						delayRead(reg, bpc); return;
+					} else if (_tRd_ == reg) {
+						delayWrite(reg, bpc); return;
+					}
+					break;
+
+				case 0x10: case 0x12: // MFHI/MFLO
+					if (_tRd_ == reg) {
+						delayWrite(reg, bpc); return;
+					}
+					break;
+				case 0x11: case 0x13: // MTHI/MTLO
+					if (_tRs_ == reg) {
+						delayRead(reg, bpc); return;
+					}
+					break;
+
+				case 0x18: case 0x19:
+				case 0x1a: case 0x1b: // MULT/DIV...
+					if (_tRt_ == reg || _tRs_ == reg) {
+						delayRead(reg, bpc); return;
+					}
+					break;
+			}
+			break;
+
+		case 0x01: // REGIMM
+			switch (_tRt_) {
+				case 0x00: case 0x02:
+				case 0x10: case 0x12: // BLTZ/BGEZ...
+					if (_tRs_ == reg) {
+						delayRead(reg, bpc); return;
+					}
+					break;
+			}
+			break;
+
+		// J would be just a break;
+		case 0x03: // JAL
+			if (31 == reg) {
+				delayWrite(reg, bpc); return;
+			}
+			break;
+
+		case 0x04: case 0x05: // BEQ/BNE
+			if (_tRs_ == reg || _tRt_ == reg) {
+				delayRead(reg, bpc); return;
+			}
+			break;
+
+		case 0x06: case 0x07: // BLEZ/BGTZ
+			if (_tRs_ == reg) {
+				delayRead(reg, bpc); return;
+			}
+			break;
+
+		case 0x08: case 0x09: case 0x0a: case 0x0b:
+		case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU...
+			if (_tRt_ == reg && _tRs_ == reg) {
+				delayReadWrite(reg, bpc); return;
+			} else if (_tRs_ == reg) {
+				delayRead(reg, bpc); return;
+			} else if (_tRt_ == reg) {
+				delayWrite(reg, bpc); return;
+			}
+			break;
+
+		case 0x0f: // LUI
+			if (_tRt_ == reg) {
+				delayWrite(reg, bpc); return;
+			}
+			break;
+
+		case 0x10: // COP0
+			switch (_tFunct_) {
+				case 0x00: // MFC0
+					if (_tRt_ == reg) { delayWrite(reg, bpc); return; }
+					break;
+				case 0x02: // CFC0
+					if (_tRt_ == reg) { delayWrite(reg, bpc); return; }
+					break;
+				case 0x04: // MTC0
+					if (_tRt_ == reg) { delayRead(reg, bpc); return; }
+					break;
+				case 0x06: // CTC0
+					if (_tRt_ == reg) { delayRead(reg, bpc); return; }
+					break;
+				// RFE just a break;
+			}
+			break;
+
+		case 0x22: case 0x26: // LWL/LWR
+			if (_tRt_ == reg) {
+				delayReadWrite(reg, bpc); return;
+			} else if (_tRs_ == reg) {
+				delayRead(reg, bpc); return;
+			}
+			break;
+
+		case 0x20: case 0x21: case 0x23:
+		case 0x24: case 0x25: // LB/LH/LW/LBU/LHU
+			if (_tRt_ == reg && _tRs_ == reg) {
+				delayReadWrite(reg, bpc); return;
+			} else if (_tRs_ == reg) {
+				delayRead(reg, bpc); return;
+			} else if (_tRt_ == reg) {
+				delayWrite(reg, bpc); return;
+			}
+			break;
+
+		case 0x28: case 0x29: case 0x2a:
+		case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR
+			if (_tRt_ == reg || _tRs_ == reg) {
+				delayRead(reg, bpc); return;
+			}
+			break;
+
+		case 0x32: case 0x3a: // LWC2/SWC2
+			if (_tRs_ == reg) {
+				delayRead(reg, bpc); return;
+			}
+			break;
+	}
+	psxBSC[psxRegs.code >> 26]();
+
+	branch = 0;
+	psxRegs.pc = bpc;
+
+	psxBranchTest();
+}
+
+static void psxNULL(void);
+
+static INLINE void doBranch(u32 tar) {
+	u32 tmp;
+
+	branch2 = branch = 1;
+	branchPC = tar;
+
+	psxRegs.code = BFLIP32(PSXMu32(psxRegs.pc));
+
+	psxRegs.pc+= 4; psxRegs.cycle++;
+
+	// check for load delay
+	tmp = psxRegs.code >> 26;
+	switch (tmp) {
+		case 0x10: // COP0
+			switch (_Rs_) {
+				case 0x00: // MFC0
+				case 0x02: // CFC0
+					psxDelayTest(_Rt_, branchPC);
+					return;
+			}
+			break;
+		case 0x32: // LWC2
+			psxDelayTest(_Rt_, branchPC);
+			return;
+		default:
+			if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
+				psxDelayTest(_Rt_, branchPC);
+				return;
+			}
+			break;
+	}
+
+	psxBSC[psxRegs.code >> 26]();
+
+        if((psxRegs.pc-8)==branchPC && !(psxRegs.code>>26)) 
+        {
+	 //printf("%08x\n",psxRegs.code>>26);
+	 CounterDeadLoopSkip();
+	}
+	branch = 0;
+	psxRegs.pc = branchPC;
+
+	psxBranchTest();
+}
+
+/*********************************************************
+* Arithmetic with immediate operand                      *
+* Format:  OP rt, rs, immediate                          *
+*********************************************************/
+static void psxADDI() 	{ if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; }		// Rt = Rs + Im 	(Exception on Integer Overflow)
+static void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; }		// Rt = Rs + Im
+static void psxANDI() 	{ if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; }		// Rt = Rs And Im
+static void psxORI() 	{ if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; }		// Rt = Rs Or  Im
+static void psxXORI() 	{ if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; }		// Rt = Rs Xor Im
+static void psxSLTI() 	{ if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; }		// Rt = Rs < Im		(Signed)
+static void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_ImmU_); }		// Rt = Rs < Im		(Unsigned)
+
+/*********************************************************
+* Register arithmetic                                    *
+* Format:  OP rd, rs, rt                                 *
+*********************************************************/
+static void psxADD()	{ if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); }	// Rd = Rs + Rt		(Exception on Integer Overflow)
+static void psxADDU() 	{ if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); }	// Rd = Rs + Rt
+static void psxSUB() 	{ if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); }	// Rd = Rs - Rt		(Exception on Integer Overflow)
+static void psxSUBU() 	{ if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); }	// Rd = Rs - Rt
+static void psxAND() 	{ if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); }	// Rd = Rs And Rt
+static void psxOR() 	{ if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); }	// Rd = Rs Or  Rt
+static void psxXOR() 	{ if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); }	// Rd = Rs Xor Rt
+static void psxNOR() 	{ if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
+static void psxSLT() 	{ if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); }	// Rd = Rs < Rt		(Signed)
+static void psxSLTU() 	{ if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); }	// Rd = Rs < Rt		(Unsigned)
+
+/*********************************************************
+* Register mult/div & Register trap logic                *
+* Format:  OP rs, rt                                     *
+*********************************************************/
+static void psxDIV() {
+	if (_i32(_rRt_) != 0) {
+		_rLo_ = _i32(_rRs_) / _i32(_rRt_);
+		_rHi_ = _i32(_rRs_) % _i32(_rRt_);
+	}
+}
+
+static void psxDIVU() {
+	if (_rRt_ != 0) {
+		_rLo_ = _rRs_ / _rRt_;
+		_rHi_ = _rRs_ % _rRt_;
+	}
+}
+
+static void psxMULT() {
+	u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
+
+	psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
+	psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
+}
+
+static void psxMULTU() {
+	u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
+
+	psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
+	psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
+}
+
+/*********************************************************
+* Register branch logic                                  *
+* Format:  OP rs, offset                                 *
+*********************************************************/
+#define RepZBranchi32(op)      if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
+#define RepZBranchLinki32(op)  if(_i32(_rRs_) op 0) { _SetLink(31); doBranch(_BranchTarget_); }
+
+static void psxBGEZ()   { RepZBranchi32(>=) }      // Branch if Rs >= 0
+static void psxBGEZAL() { RepZBranchLinki32(>=) }  // Branch if Rs >= 0 and link
+static void psxBGTZ()   { RepZBranchi32(>) }       // Branch if Rs >  0
+static void psxBLEZ()   { RepZBranchi32(<=) }      // Branch if Rs <= 0
+static void psxBLTZ()   { RepZBranchi32(<) }       // Branch if Rs <  0
+static void psxBLTZAL() { RepZBranchLinki32(<) }   // Branch if Rs <  0 and link
+
+/*********************************************************
+* Shift arithmetic with constant shift                   *
+* Format:  OP rd, rt, sa                                 *
+*********************************************************/
+static void psxSLL() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
+static void psxSRA() { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
+static void psxSRL() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
+
+/*********************************************************
+* Shift arithmetic with variant register shift           *
+* Format:  OP rd, rt, rs                                 *
+*********************************************************/
+static void psxSLLV() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _u32(_rRs_); } // Rd = Rt << rs
+static void psxSRAV() { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (arithmetic)
+static void psxSRLV() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (logical)
+
+/*********************************************************
+* Load higher 16 bits of the first word in GPR with imm  *
+* Format:  OP rt, immediate                              *
+*********************************************************/
+static void psxLUI() { if (!_Rt_) return; _rRt_ = psxRegs.code << 16; } // Upper halfword of Rt = Im
+
+/*********************************************************
+* Move from HI/LO to GPR                                 *
+* Format:  OP rd                                         *
+*********************************************************/
+static void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
+static void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
+
+/*********************************************************
+* Move to GPR to HI/LO & Register jump                   *
+* Format:  OP rs                                         *
+*********************************************************/
+static void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
+static void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
+
+/*********************************************************
+* Special purpose instructions                           *
+* Format:  OP                                            *
+*********************************************************/
+static void psxBREAK() {
+	// Break exception - psx rom doens't handles this
+}
+
+static void psxSYSCALL() {
+	psxRegs.pc -= 4;
+	psxException(0x20, branch);
+}
+
+static void psxRFE() {
+	psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
+						  ((psxRegs.CP0.n.Status & 0x3c) >> 2);
+}
+
+/*********************************************************
+* Register branch logic                                  *
+* Format:  OP rs, rt, offset                             *
+*********************************************************/
+#define RepBranchi32(op)      if(_i32(_rRs_) op _i32(_rRt_)) { doBranch(_BranchTarget_); }
+
+static void psxBEQ() {	RepBranchi32(==) }  // Branch if Rs == Rt
+static void psxBNE() {	RepBranchi32(!=) }  // Branch if Rs != Rt
+
+/*********************************************************
+* Jump to target                                         *
+* Format:  OP target                                     *
+*********************************************************/
+static void psxJ()   { doBranch(_JumpTarget_); }
+static void psxJAL() {	_SetLink(31); doBranch(_JumpTarget_); }
+
+/*********************************************************
+* Register jump                                          *
+* Format:  OP rs, rd                                     *
+*********************************************************/
+static void psxJR()   {                 doBranch(_u32(_rRs_)); }
+static void psxJALR() { if (_Rd_) { _SetLink(_Rd_); } doBranch(_u32(_rRs_)); }
+
+/*********************************************************
+* Load and store for GPR                                 *
+* Format:  OP rt, offset(base)                           *
+*********************************************************/
+
+#define _oB_ (_u32(_rRs_) + _Imm_)
+
+static void psxLB() {
+	if (_Rt_) {
+		_rRt_ = (s8)psxMemRead8(_oB_); 
+	} else {
+		psxMemRead8(_oB_); 
+	}
+}
+
+static void psxLBU() {
+	if (_Rt_) {
+		_rRt_ = psxMemRead8(_oB_);
+	} else {
+		psxMemRead8(_oB_); 
+	}
+}
+
+static void psxLH() {
+	if (_Rt_) {
+		_rRt_ = (s16)psxMemRead16(_oB_);
+	} else {
+		psxMemRead16(_oB_);
+	}
+}
+
+static void psxLHU() {
+	if (_Rt_) {
+		_rRt_ = psxMemRead16(_oB_);
+	} else {
+		psxMemRead16(_oB_);
+	}
+}
+
+static void psxLW() {
+	if (_Rt_) {
+		_rRt_ = psxMemRead32(_oB_);
+	} else {
+		psxMemRead32(_oB_);
+	}
+}
+
+static u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
+static u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
+
+static void psxLWL() {
+	u32 addr = _oB_;
+	u32 shift = addr & 3;
+	u32 mem = psxMemRead32(addr & ~3);
+
+	if (!_Rt_) return;
+	_rRt_ =	( _u32(_rRt_) & LWL_MASK[shift]) | 
+					( mem << LWL_SHIFT[shift]);
+
+	/*
+	Mem = 1234.  Reg = abcd
+
+	0   4bcd   (mem << 24) | (reg & 0x00ffffff)
+	1   34cd   (mem << 16) | (reg & 0x0000ffff)
+	2   234d   (mem <<  8) | (reg & 0x000000ff)
+	3   1234   (mem      ) | (reg & 0x00000000)
+	*/
+}
+
+static u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
+static u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
+
+static void psxLWR() {
+	u32 addr = _oB_;
+	u32 shift = addr & 3;
+	u32 mem = psxMemRead32(addr & ~3);
+
+	if (!_Rt_) return;
+	_rRt_ =	( _u32(_rRt_) & LWR_MASK[shift]) | 
+					( mem >> LWR_SHIFT[shift]);
+
+	/*
+	Mem = 1234.  Reg = abcd
+
+	0   1234   (mem      ) | (reg & 0x00000000)
+	1   a123   (mem >>  8) | (reg & 0xff000000)
+	2   ab12   (mem >> 16) | (reg & 0xffff0000)
+	3   abc1   (mem >> 24) | (reg & 0xffffff00)
+	*/
+}
+
+static void psxSB() { psxMemWrite8 (_oB_, _u8 (_rRt_)); }
+static void psxSH() { psxMemWrite16(_oB_, _u16(_rRt_)); }
+static void psxSW() { psxMemWrite32(_oB_, _u32(_rRt_)); }
+
+static const u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
+static const u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
+
+static void psxSWL() {
+	u32 addr = _oB_;
+	u32 shift = addr & 3;
+	u32 mem = psxMemRead32(addr & ~3);
+
+	psxMemWrite32(addr & ~3,  (_u32(_rRt_) >> SWL_SHIFT[shift]) |
+			     (  mem & SWL_MASK[shift]) );
+	/*
+	Mem = 1234.  Reg = abcd
+
+	0   123a   (reg >> 24) | (mem & 0xffffff00)
+	1   12ab   (reg >> 16) | (mem & 0xffff0000)
+	2   1abc   (reg >>  8) | (mem & 0xff000000)
+	3   abcd   (reg      ) | (mem & 0x00000000)
+	*/
+}
+
+static const u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
+static const u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
+
+static void psxSWR() {
+	u32 addr = _oB_;
+	u32 shift = addr & 3;
+	u32 mem = psxMemRead32(addr & ~3);
+
+	psxMemWrite32(addr & ~3,  (_u32(_rRt_) << SWR_SHIFT[shift]) |
+			     (  mem & SWR_MASK[shift]) );
+
+	/*
+	Mem = 1234.  Reg = abcd
+
+	0   abcd   (reg      ) | (mem & 0x00000000)
+	1   bcd4   (reg <<  8) | (mem & 0x000000ff)
+	2   cd34   (reg << 16) | (mem & 0x0000ffff)
+	3   d234   (reg << 24) | (mem & 0x00ffffff)
+	*/
+}
+
+/*********************************************************
+* Moves between GPR and COPx                             *
+* Format:  OP rt, fs                                     *
+*********************************************************/
+static void psxMFC0() { if (!_Rt_) return; _rRt_ = (int)_rFs_; }
+static void psxCFC0() { if (!_Rt_) return; _rRt_ = (int)_rFs_; }
+
+static INLINE void MTC0(int reg, u32 val) {
+	switch (reg) {
+		case 13: // Cause
+			psxRegs.CP0.n.Cause = val & ~(0xfc00);
+
+			// the next code is untested, if u know please
+			// tell me if it works ok or not (linuzappz)
+			if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 &&
+				psxRegs.CP0.n.Status & 0x1) {
+				psxException(psxRegs.CP0.n.Cause, 0);
+			}
+			break;
+
+		default:
+			psxRegs.CP0.r[reg] = val;
+			break;
+	}
+}
+
+static void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); }
+static void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); }
+
+/*********************************************************
+* Unknow instruction (would generate an exception)       *
+* Format:  ?                                             *
+*********************************************************/
+static void psxNULL() { 
+#ifdef PSXCPU_LOG
+	PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
+#endif
+}
+
+static void psxSPECIAL() {
+	psxSPC[_Funct_]();
+}
+
+static void psxREGIMM() {
+	psxREG[_Rt_]();
+}
+
+static void psxCOP0() {
+	psxCP0[_Rs_]();
+}
+
+static void psxHLE() {
+	psxHLEt[psxRegs.code & 0xff]();
+}
+
+static void (*psxBSC[64])() = {
+	psxSPECIAL, psxREGIMM, psxJ   , psxJAL  , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
+	psxADDI   , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
+	psxCOP0   , psxNULL  , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
+	psxNULL   , psxNULL  , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
+	psxLB     , psxLH    , psxLWL , psxLW   , psxLBU , psxLHU , psxLWR , psxNULL,
+	psxSB     , psxSH    , psxSWL , psxSW   , psxNULL, psxNULL, psxSWR , psxNULL, 
+	psxNULL   , psxNULL  , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
+	psxNULL   , psxNULL  , psxNULL, psxHLE  , psxNULL, psxNULL, psxNULL, psxNULL 
+};
+
+
+static void (*psxSPC[64])() = {
+	psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV   , psxNULL , psxSRLV, psxSRAV,
+	psxJR  , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
+	psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL   , psxNULL , psxNULL, psxNULL,
+	psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL   , psxNULL , psxNULL, psxNULL,
+	psxADD , psxADDU , psxSUB , psxSUBU, psxAND    , psxOR   , psxXOR , psxNOR ,
+	psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL   , psxNULL , psxNULL, psxNULL,
+	psxNULL, psxNULL , psxNULL, psxNULL, psxNULL   , psxNULL , psxNULL, psxNULL,
+	psxNULL, psxNULL , psxNULL, psxNULL, psxNULL   , psxNULL , psxNULL, psxNULL
+};
+
+static void (*psxREG[32])() = {
+	psxBLTZ  , psxBGEZ  , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
+	psxNULL  , psxNULL  , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
+	psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
+	psxNULL  , psxNULL  , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
+};
+
+static void (*psxCP0[32])() = {
+	psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL,
+	psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
+	psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
+	psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
+};
+
+
+///////////////////////////////////////////
+
+static int intInit() {
+	return 0;
+}
+
+static void intReset() {
+ branch=branch2=0;
+}
+
+static void intExecute() {
+	for (;;) 
+	{
+	 if(!CounterSPURun()) 
+	 {
+	  psxShutdown();
+	  return;
+	 }
+	 SPUendflush();
+	 execI();
+	}
+}
+
+static void intExecuteBlock() {
+	branch2 = 0;
+	while (!branch2) execI();
+}
+
+static void intClear(u32 Addr, u32 Size) {
+}
+
+static void intShutdown() {
+}
+
+R3000Acpu psxInt = {
+	intInit,
+	intReset,
+	intExecute,
+	intExecuteBlock,
+	intClear,
+	intShutdown
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxMem.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,236 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "PsxCommon.h"
+
+void LoadPSXMem(u32 address, s32 length, char *data)
+{
+ //printf("%08x %08x\n",address,length);
+ while(length>0)
+ {
+  if(address&65535)
+  {
+   u32 tmplen;
+
+   //puts("Squishy");
+   tmplen=((65536-(address&65535))>length)?length:65536-(address&65535);
+   if(psxMemLUT[address>>16])
+    memcpy((char *)(psxMemLUT[address>>16]+(address&65535)),data,tmplen);
+   address+=tmplen;
+   data+=tmplen;
+   length-=tmplen;
+   //printf("%08x %08x\n",address,tmplen);
+   continue;
+  }
+  if(psxMemLUT[address>>16])
+  {
+   memcpy((char *)(psxMemLUT[address>>16]),data,(length<65536)?length:65536);
+  }
+  data+=65536;
+  address+=65536;
+  length-=65536;
+ }
+}
+
+static int writeok;
+int psxMemInit() {
+	int i;
+
+	writeok=1;
+
+	psxMemLUT = malloc(0x10000 * sizeof *psxMemLUT);
+	memset(psxMemLUT, 0, 0x10000 * sizeof *psxMemLUT);
+
+	psxM = (char*)malloc(0x00200000);
+	psxP = (char*)malloc(0x00010000);
+	psxH = (char*)malloc(0x00010000);
+	psxR = (char*)malloc(0x00080000);
+	if (psxMemLUT == NULL || psxM == NULL || psxP == NULL || psxH == NULL || psxR == NULL) {
+		printf("Error allocating memory"); return -1;
+	}
+
+	for (i=0; i<0x80; i++) psxMemLUT[i + 0x0000] = &psxM[(i & 0x1f) << 16];
+
+	memcpy(psxMemLUT + 0x8000, psxMemLUT, 0x80 * sizeof *psxMemLUT);
+	memcpy(psxMemLUT + 0xa000, psxMemLUT, 0x80 * sizeof *psxMemLUT);
+
+	for (i=0; i<0x01; i++) psxMemLUT[i + 0x1f00] = (u32)&psxP[i << 16];
+
+	for (i=0; i<0x01; i++) psxMemLUT[i + 0x1f80] = (u32)&psxH[i << 16];
+
+	for (i=0; i<0x08; i++) psxMemLUT[i + 0xbfc0] = (u32)&psxR[i << 16];
+
+	return 0;
+}
+
+void psxMemReset() {
+	memset(psxM, 0, 0x00200000);
+	memset(psxP, 0, 0x00010000);
+}
+
+void psxMemShutdown() {
+	free(psxM);
+	free(psxP);
+	free(psxH);
+	free(psxR);
+	free(psxMemLUT);
+}
+
+u8 psxMemRead8(u32 mem) {
+	char *p;
+	u32 t;
+
+	t = mem >> 16;
+	if (t == 0x1f80) {
+		if (mem < 0x1f801000)
+			return psxHu8(mem);
+		else
+			return psxHwRead8(mem);
+	} else {
+		p = (char *)(psxMemLUT[t]);
+		if (p != NULL) {
+			return *(u8 *)(p + (mem & 0xffff));
+		} else {
+			return 0;
+		}
+	}
+}
+
+u16 psxMemRead16(u32 mem) {
+	char *p;
+	u32 t;
+
+	t = mem >> 16;
+	if (t == 0x1f80) {
+		if (mem < 0x1f801000)
+			return BFLIP16(psxHu16(mem));
+		else
+			return psxHwRead16(mem);
+	} else {
+		p = (char *)(psxMemLUT[t]);
+		if (p != NULL) {
+			return BFLIP16(*(u16 *)(p + (mem & 0xffff)));
+		} else {
+			return 0;
+		}
+	}
+}
+
+u32 psxMemRead32(u32 mem) {
+	char *p;
+	u32 t;
+
+	t = mem >> 16;
+	if (t == 0x1f80) {
+		if (mem < 0x1f801000)
+			return BFLIP32(psxHu32(mem));
+		else
+			return psxHwRead32(mem);
+	} else {
+		p = (char *)(psxMemLUT[t]);
+		if (p != NULL) {
+			return BFLIP32(*(u32 *)(p + (mem & 0xffff)));
+		} else {
+			return 0;
+		}
+	}
+}
+
+void psxMemWrite8(u32 mem, u8 value) {
+	char *p;
+	u32 t;
+
+	t = mem >> 16;
+	if (t == 0x1f80) {
+		if (mem < 0x1f801000)
+			psxHu8(mem) = value;
+		else
+			psxHwWrite8(mem, value);
+	} else {
+		p = (char *)(psxMemLUT[t]);
+		if (p != NULL) {
+			*(u8  *)(p + (mem & 0xffff)) = value;
+		}
+	}
+}
+
+void psxMemWrite16(u32 mem, u16 value) {
+	char *p;
+	u32 t;
+
+	t = mem >> 16;
+	if (t == 0x1f80) {
+		if (mem < 0x1f801000)
+			psxHu16(mem) = BFLIP16(value);
+		else
+			psxHwWrite16(mem, value);
+	} else {
+		p = (char *)(psxMemLUT[t]);
+		if (p != NULL) {
+			*(u16 *)(p + (mem & 0xffff)) = BFLIP16(value);
+		}
+	}
+}
+
+void psxMemWrite32(u32 mem, u32 value) {
+	char *p;
+	u32 t;
+
+//	if ((mem&0x1fffff) == 0x71E18 || value == 0x48088800) SysPrintf("t2fix!!\n");
+	t = mem >> 16;
+	if (t == 0x1f80) {
+		if (mem < 0x1f801000)
+			psxHu32(mem) = BFLIP32(value);
+		else
+			psxHwWrite32(mem, value);
+	} else {
+		p = (char *)(psxMemLUT[t]);
+		if (p != NULL) {
+			*(u32 *)(p + (mem & 0xffff)) = BFLIP32(value);
+		} else {
+			if (mem != 0xfffe0130) {
+
+			} else {
+				int i;
+
+				switch (value) {
+					case 0x800: case 0x804:
+						if (writeok == 0) break;
+						writeok = 0;
+						memset(psxMemLUT + 0x0000, 0, 0x80 * sizeof *psxMemLUT);
+						memset(psxMemLUT + 0x8000, 0, 0x80 * sizeof *psxMemLUT);
+						memset(psxMemLUT + 0xa000, 0, 0x80 * sizeof *psxMemLUT);
+						break;
+					case 0x1e988:
+						if (writeok == 1) break;
+						writeok = 1;
+						for (i=0; i<0x80; i++) psxMemLUT[i + 0x0000] = &psxM[(i & 0x1f) << 16];
+						memcpy(psxMemLUT + 0x8000, psxMemLUT, 0x80 * sizeof *psxMemLUT);
+						memcpy(psxMemLUT + 0xa000, psxMemLUT, 0x80 * sizeof *psxMemLUT);
+						break;
+					default:
+						break;
+				}
+			}
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/PsxMem.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,81 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PSXMEMORY_H__
+#define __PSXMEMORY_H__
+
+#ifdef MSB_FIRST
+static INLINE u16 BFLIP16(u16 x)
+{
+ return( ((x>>8)&0xFF)| ((x&0xFF)<<8) );
+}
+
+static INLINE u32 BFLIP32(u32 x)
+{
+ return ( ((x>>24)&0xFF) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | ((x<<24)&0xFF000000) );
+}
+#else
+static INLINE u16 BFLIP16(u16 x)
+{
+ return x;
+}
+
+static INLINE u32 BFLIP32(u32 x)
+{
+ return x;
+}
+#endif
+
+s8 *psxM;
+#define psxMu32(mem)	(*(u32*)&psxM[(mem) & 0x1fffff])
+
+s8 *psxP;
+s8 *psxR;
+#define psxRu32(mem)	(*(u32*)&psxR[(mem) & 0x7ffff])
+
+s8 *psxH;
+
+#define psxHu8(mem)	(*(u8*) &psxH[(mem) & 0xffff])
+
+#define psxHu16(mem)   	(*(u16*)&psxH[(mem) & 0xffff])
+#define psxHu32(mem)   	(*(u32*)&psxH[(mem) & 0xffff])
+
+char **psxMemLUT;
+
+#define PSXM(mem)		(psxMemLUT[(mem) >> 16] == 0 ? NULL : (void*)(psxMemLUT[(mem) >> 16] + ((mem) & 0xffff)))
+
+#define PSXMu8(mem)	(*(u8 *)PSXM(mem))
+#define PSXMu32(mem)    (*(u32*)PSXM(mem))
+
+#define PSXMuR8(mem)        (PSXM(mem)?PSXMu8(mem):0)
+#define PSXMuW8(mem,val)    (PSXM(mem)?PSXMu8(mem)=val:;)
+
+int  psxMemInit();
+void psxMemReset();
+void psxMemShutdown();
+
+u8   psxMemRead8 (u32 mem);
+u16  psxMemRead16(u32 mem);
+u32  psxMemRead32(u32 mem);
+void psxMemWrite8 (u32 mem, u8 value);
+void psxMemWrite16(u32 mem, u16 value);
+void psxMemWrite32(u32 mem, u32 value);
+
+void LoadPSXMem(u32 address, s32 length, char *data);
+
+#endif /* __PSXMEMORY_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/R3000A.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,97 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "PsxCommon.h"
+
+int psxInit() {
+
+	psxCpu = &psxInt;
+
+	if (psxMemInit() == -1) return -1;
+
+	return psxCpu->Init();
+}
+
+void psxReset() {
+	psxCpu->Reset();
+	psxMemReset();
+
+	memset(&psxRegs, 0, sizeof(psxRegs));
+
+	psxRegs.pc = 0xbfc00000; // Start in bootstrap
+	psxRegs.CP0.r[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1
+	psxRegs.CP0.r[15] = 0x00000002; // PRevID = Revision ID, same as R3000A
+
+	psxHwReset();
+	psxBiosInit();
+}
+
+void psxShutdown() {
+	psxMemShutdown();
+	psxBiosShutdown();
+
+	psxCpu->Shutdown();
+	SPUclose();
+}
+
+void psxException(u32 code, u32 bd) {
+	// Set the Cause
+	psxRegs.CP0.n.Cause = code;
+
+#ifdef PSXCPU_LOG
+	if (bd) PSXCPU_LOG("bd set\n");
+#endif
+	// Set the EPC & PC
+	if (bd) {
+		psxRegs.CP0.n.Cause|= 0x80000000;
+		psxRegs.CP0.n.EPC = (psxRegs.pc - 4);
+	} else
+		psxRegs.CP0.n.EPC = (psxRegs.pc);
+
+	if (psxRegs.CP0.n.Status & 0x400000)
+		psxRegs.pc = 0xbfc00180;
+	else
+		psxRegs.pc = 0x80000080;
+
+	// Set the Status
+	psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status &~0x3f) |
+						  ((psxRegs.CP0.n.Status & 0xf) << 2);
+
+	psxBiosException();
+}
+
+void psxBranchTest() {
+	if ((psxRegs.cycle - psxNextsCounter) >= psxNextCounter)
+		psxRcntUpdate();
+
+	if (psxHu32(0x1070) & psxHu32(0x1074)) {
+		if ((psxRegs.CP0.n.Status & 0x401) == 0x401) {
+			psxException(0x400, 0);
+		}
+	}
+
+}
+void psxExecuteBios() {
+	while (psxRegs.pc != 0x80030000)
+		psxCpu->ExecuteBlock();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/R3000A.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,122 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __R3000A_H__
+#define __R3000A_H__
+
+#include <stdio.h>
+
+#include "PsxCommon.h"
+
+typedef struct {
+	int  (*Init)();
+	void (*Reset)();
+	void (*Execute)();		/* executes up to a break */
+	void (*ExecuteBlock)();	/* executes up to a jump */
+	void (*Clear)(u32 Addr, u32 Size);
+	void (*Shutdown)();
+} R3000Acpu;
+
+R3000Acpu *psxCpu;
+extern R3000Acpu psxInt;
+
+typedef union {
+        struct {
+                u32 r0, at, v0, v1, a0, a1, a2, a3,
+                                                t0, t1, t2, t3, t4, t5, t6, t7,
+                                                s0, s1, s2, s3, s4, s5, s6, s7,
+                                                t8, t9, k0, k1, gp, sp, s8, ra, lo, hi;
+        } n PACKSTRUCT;
+        u32 r[34]; /* Lo, Hi in r[33] and r[34] */
+} psxGPRRegs;
+
+typedef union {
+	struct {
+		u32	Index,     Random,    EntryLo0,  EntryLo1,
+						Context,   PageMask,  Wired,     Reserved0,
+						BadVAddr,  Count,     EntryHi,   Compare,
+						Status,    Cause,     EPC,       PRid,
+						Config,    LLAddr,    WatchLO,   WatchHI,
+						XContext,  Reserved1, Reserved2, Reserved3,
+						Reserved4, Reserved5, ECC,       CacheErr,
+						TagLo,     TagHi,     ErrorEPC,  Reserved6;
+	} n PACKSTRUCT;
+	u32 r[32];
+} psxCP0Regs;
+
+typedef struct {
+	psxGPRRegs GPR;		/* General Purpose Registers */
+	psxCP0Regs CP0;		/* Coprocessor0 Registers */
+	u32 pc;				/* Program counter */
+	u32 code;			/* The instruction */
+	u32 cycle;
+	u32 interrupt;
+} psxRegisters;
+
+psxRegisters psxRegs;
+
+#define _i32(x) (s32)x
+#define _u32(x) (u32)x
+
+#define _i16(x) (s16)x
+#define _u16(x) (u32)x
+
+#define _i8(x) (s8)x
+#define _u8(x) (u8)x
+
+/**** R3000A Instruction Macros ****/
+#define _PC_       psxRegs.pc       // The next PC to be executed
+
+#define _Funct_  ((psxRegs.code      ) & 0x3F)  // The funct part of the instruction register 
+#define _Rd_     ((psxRegs.code >> 11) & 0x1F)  // The rd part of the instruction register 
+#define _Rt_     ((psxRegs.code >> 16) & 0x1F)  // The rt part of the instruction register 
+#define _Rs_     ((psxRegs.code >> 21) & 0x1F)  // The rs part of the instruction register 
+#define _Sa_     ((psxRegs.code >>  6) & 0x1F)  // The sa part of the instruction register
+#define _Im_     ((u16)psxRegs.code) // The immediate part of the instruction register
+#define _Target_ (psxRegs.code & 0x03ffffff)    // The target part of the instruction register
+
+#define _Imm_	((s16)psxRegs.code) // sign-extended immediate
+#define _ImmU_	(psxRegs.code&0xffff) // zero-extended immediate
+
+#define _rRs_   psxRegs.GPR.r[_Rs_]   // Rs register
+#define _rRt_   psxRegs.GPR.r[_Rt_]   // Rt register
+#define _rRd_   psxRegs.GPR.r[_Rd_]   // Rd register
+#define _rSa_   psxRegs.GPR.r[_Sa_]   // Sa register
+#define _rFs_   psxRegs.CP0.r[_Rd_]   // Fs register
+
+#define _c2dRs_ psxRegs.CP2D.r[_Rs_]  // Rs cop2 data register
+#define _c2dRt_ psxRegs.CP2D.r[_Rt_]  // Rt cop2 data register
+#define _c2dRd_ psxRegs.CP2D.r[_Rd_]  // Rd cop2 data register
+#define _c2dSa_ psxRegs.CP2D.r[_Sa_]  // Sa cop2 data register
+
+#define _rHi_   psxRegs.GPR.n.hi   // The HI register
+#define _rLo_   psxRegs.GPR.n.lo   // The LO register
+
+#define _JumpTarget_    ((_Target_ * 4) + (_PC_ & 0xf0000000))   // Calculates the target during a jump instruction
+#define _BranchTarget_  ((s16)_Im_ * 4 + _PC_)                 // Calculates the target during a branch instruction
+
+#define _SetLink(x)     psxRegs.GPR.r[x] = _PC_ + 4;       // Sets the return address in the link register
+
+int  psxInit();
+void psxReset();
+void psxShutdown();
+void psxException(u32 code, u32 bd);
+void psxBranchTest();
+void psxExecuteBios();
+
+#endif /* __R3000A_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/Spu.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,23 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "PsxCommon.h"
+
+void SPUirq(void) {
+	psxHu32(0x1070)|=BFLIP32(0x200);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/Spu.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,41 @@
+/*  Pcsx - Pc Psx Emulator
+ *  Copyright (C) 1999-2002  Pcsx Team
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __SPU_H__
+#define __SPU_H__
+
+#define H_SPUirqAddr     0x0da4
+#define H_SPUaddr        0x0da6
+#define H_SPUdata        0x0da8
+#define H_SPUctrl        0x0daa
+#define H_SPUstat        0x0dae
+#define H_SPUon1         0x0d88
+#define H_SPUon2         0x0d8a
+#define H_SPUoff1        0x0d8c
+#define H_SPUoff2        0x0d8e
+
+
+void SPUirq(void);
+u16 SPUreadRegister(u32 reg);
+void SPUwriteRegister(u32 reg, u16 val);
+int SPUasync(u32 cycle);
+void SPUwriteDMAMem(u32 usPSXMem,int iSize);
+void SPUreadDMAMem(u32 usPSXMem,int iSize);
+
+
+#endif /* __SPU_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/driver.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,26 @@
+#include "types.h"
+
+typedef struct __PSFTAG
+{
+ char *key;
+ char *value;
+ struct __PSFTAG *next;
+} PSFTAG;
+
+typedef struct {
+        u32 length;
+        u32 stop;
+        u32 fade;
+        char *title,*artist,*game,*year,*genre,*psfby,*comment,*copyright;
+        PSFTAG *tags;
+} PSFINFO;
+
+int sexypsf_seek(u32 t);
+void sexypsf_stop(void);
+void sexypsf_execute(void);
+
+PSFINFO *sexypsf_load(char *path);
+PSFINFO *sexypsf_getpsfinfo(char *path);
+void sexypsf_freepsfinfo(PSFINFO *info);
+
+void sexypsf_update(unsigned char*,long);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,637 @@
+/***************************************************************************
+                            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 s32 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!=~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!=~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=~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;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/adsr.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,618 @@
+/***************************************************************************
+                          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]
+
+-----------------------------------------------------------------------------
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/adsr.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/dma.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,75 @@
+/***************************************************************************
+                            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
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/dma.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,31 @@
+/***************************************************************************
+                            dma.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
+//
+//*************************************************************************//
+
+
+u16 CALLBACK SPUreadDMA(void);
+void CALLBACK SPUreadDMAMem(u16 * pusPSXMem,int iSize);
+void CALLBACK SPUwriteDMA(u16 val);
+void CALLBACK SPUwriteDMAMem(u16 * pusPSXMem,int iSize);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/externals.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,177 @@
+/***************************************************************************
+                         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;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/gauss_i.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,163 @@
+/***************************************************************************
+                          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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/registers.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,490 @@
+/***************************************************************************
+                         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
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/registers.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,153 @@
+/***************************************************************************
+                         registers.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
+//
+//*************************************************************************//
+
+#define H_SPUReverbAddr  0x0da2
+#define H_SPUirqAddr     0x0da4
+#define H_SPUaddr        0x0da6
+#define H_SPUdata        0x0da8
+#define H_SPUctrl        0x0daa
+#define H_SPUstat        0x0dae
+#define H_SPUmvolL       0x0d80
+#define H_SPUmvolR       0x0d82
+#define H_SPUrvolL       0x0d84
+#define H_SPUrvolR       0x0d86
+#define H_SPUon1         0x0d88
+#define H_SPUon2         0x0d8a
+#define H_SPUoff1        0x0d8c
+#define H_SPUoff2        0x0d8e
+#define H_FMod1          0x0d90
+#define H_FMod2          0x0d92
+#define H_Noise1         0x0d94
+#define H_Noise2         0x0d96
+#define H_RVBon1         0x0d98
+#define H_RVBon2         0x0d9a
+#define H_SPUMute1       0x0d9c
+#define H_SPUMute2       0x0d9e
+#define H_CDLeft         0x0db0
+#define H_CDRight        0x0db2
+#define H_ExtLeft        0x0db4
+#define H_ExtRight       0x0db6
+#define H_Reverb         0x0dc0
+#define H_SPUPitch0      0x0c04
+#define H_SPUPitch1      0x0c14
+#define H_SPUPitch2      0x0c24
+#define H_SPUPitch3      0x0c34
+#define H_SPUPitch4      0x0c44
+#define H_SPUPitch5      0x0c54
+#define H_SPUPitch6      0x0c64
+#define H_SPUPitch7      0x0c74
+#define H_SPUPitch8      0x0c84
+#define H_SPUPitch9      0x0c94
+#define H_SPUPitch10     0x0ca4
+#define H_SPUPitch11     0x0cb4
+#define H_SPUPitch12     0x0cc4
+#define H_SPUPitch13     0x0cd4
+#define H_SPUPitch14     0x0ce4
+#define H_SPUPitch15     0x0cf4
+#define H_SPUPitch16     0x0d04
+#define H_SPUPitch17     0x0d14
+#define H_SPUPitch18     0x0d24
+#define H_SPUPitch19     0x0d34
+#define H_SPUPitch20     0x0d44
+#define H_SPUPitch21     0x0d54
+#define H_SPUPitch22     0x0d64
+#define H_SPUPitch23     0x0d74
+
+#define H_SPUStartAdr0   0x0c06
+#define H_SPUStartAdr1   0x0c16
+#define H_SPUStartAdr2   0x0c26
+#define H_SPUStartAdr3   0x0c36
+#define H_SPUStartAdr4   0x0c46
+#define H_SPUStartAdr5   0x0c56
+#define H_SPUStartAdr6   0x0c66
+#define H_SPUStartAdr7   0x0c76
+#define H_SPUStartAdr8   0x0c86
+#define H_SPUStartAdr9   0x0c96
+#define H_SPUStartAdr10  0x0ca6
+#define H_SPUStartAdr11  0x0cb6
+#define H_SPUStartAdr12  0x0cc6
+#define H_SPUStartAdr13  0x0cd6
+#define H_SPUStartAdr14  0x0ce6
+#define H_SPUStartAdr15  0x0cf6
+#define H_SPUStartAdr16  0x0d06
+#define H_SPUStartAdr17  0x0d16
+#define H_SPUStartAdr18  0x0d26
+#define H_SPUStartAdr19  0x0d36
+#define H_SPUStartAdr20  0x0d46
+#define H_SPUStartAdr21  0x0d56
+#define H_SPUStartAdr22  0x0d66
+#define H_SPUStartAdr23  0x0d76
+
+#define H_SPULoopAdr0   0x0c0e
+#define H_SPULoopAdr1   0x0c1e
+#define H_SPULoopAdr2   0x0c2e
+#define H_SPULoopAdr3   0x0c3e
+#define H_SPULoopAdr4   0x0c4e
+#define H_SPULoopAdr5   0x0c5e
+#define H_SPULoopAdr6   0x0c6e
+#define H_SPULoopAdr7   0x0c7e
+#define H_SPULoopAdr8   0x0c8e
+#define H_SPULoopAdr9   0x0c9e
+#define H_SPULoopAdr10  0x0cae
+#define H_SPULoopAdr11  0x0cbe
+#define H_SPULoopAdr12  0x0cce
+#define H_SPULoopAdr13  0x0cde
+#define H_SPULoopAdr14  0x0cee
+#define H_SPULoopAdr15  0x0cfe
+#define H_SPULoopAdr16  0x0d0e
+#define H_SPULoopAdr17  0x0d1e
+#define H_SPULoopAdr18  0x0d2e
+#define H_SPULoopAdr19  0x0d3e
+#define H_SPULoopAdr20  0x0d4e
+#define H_SPULoopAdr21  0x0d5e
+#define H_SPULoopAdr22  0x0d6e
+#define H_SPULoopAdr23  0x0d7e
+
+#define H_SPU_ADSRLevel0   0x0c08
+#define H_SPU_ADSRLevel1   0x0c18
+#define H_SPU_ADSRLevel2   0x0c28
+#define H_SPU_ADSRLevel3   0x0c38
+#define H_SPU_ADSRLevel4   0x0c48
+#define H_SPU_ADSRLevel5   0x0c58
+#define H_SPU_ADSRLevel6   0x0c68
+#define H_SPU_ADSRLevel7   0x0c78
+#define H_SPU_ADSRLevel8   0x0c88
+#define H_SPU_ADSRLevel9   0x0c98
+#define H_SPU_ADSRLevel10  0x0ca8
+#define H_SPU_ADSRLevel11  0x0cb8
+#define H_SPU_ADSRLevel12  0x0cc8
+#define H_SPU_ADSRLevel13  0x0cd8
+#define H_SPU_ADSRLevel14  0x0ce8
+#define H_SPU_ADSRLevel15  0x0cf8
+#define H_SPU_ADSRLevel16  0x0d08
+#define H_SPU_ADSRLevel17  0x0d18
+#define H_SPU_ADSRLevel18  0x0d28
+#define H_SPU_ADSRLevel19  0x0d38
+#define H_SPU_ADSRLevel20  0x0d48
+#define H_SPU_ADSRLevel21  0x0d58
+#define H_SPU_ADSRLevel22  0x0d68
+#define H_SPU_ADSRLevel23  0x0d78
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/regs.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,34 @@
+/***************************************************************************
+                           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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/reverb.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,383 @@
+/***************************************************************************
+                          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;
+
+-----------------------------------------------------------------------------
+*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/spu.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,637 @@
+/***************************************************************************
+                            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 s32 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!=~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!=~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=~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;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/spu.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,8 @@
+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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/spu/stdafx.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,31 @@
+/***************************************************************************
+                           StdAfx.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
+//
+//*************************************************************************//
+
+#include <stdlib.h>
+#include <string.h> 
+#include <math.h>  
+
+#define INLINE inline
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/types.h	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,23 @@
+#ifndef _SPSF_TYPES_H__
+#define _SPSF_TYPES_H__
+
+#include <inttypes.h>
+
+#define INLINE inline
+
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+typedef int64_t s64;
+        
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+
+
+/* For gcc only? */
+#define PACKSTRUCT	__attribute__ ((packed))
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/sexypsf/xmms.c	Sun Dec 25 13:11:21 2005 -0800
@@ -0,0 +1,283 @@
+/*  sexyPSF - PSF1 player
+ *  Copyright (C) 2002-2004 xodnizel
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "audacious/plugin.h"
+#include "libaudacious/util.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "driver.h"
+
+#define CMD_SEEK	0x80000000
+#define CMD_STOP	0x40000000
+
+#define uint32 u32
+#define int16 short
+
+static volatile uint32 command;
+static volatile int playing=0;
+
+static PSFINFO *PSFInfo=NULL;
+
+extern InputPlugin sexypsf_ip;
+static char *fnsave=NULL;
+
+InputPlugin *get_iplugin_info(void)
+      {
+         sexypsf_ip.description = "sexyPSF PSF1 Player 0.4.8";
+         return &sexypsf_ip;
+      }
+/*
+static void sexypsf_init(void)
+{
+}
+static void sexypsf_about(void)
+{
+}
+static void sexypsf_config(void)
+{
+}
+*/
+
+static int sexypsf_xmms_testfile(char *fn)
+{
+ char buf[4];
+ char *tmps;
+ static const char *teststr="psflib";
+ FILE *fp;
+ if(!strncasecmp(fn,"http://",7)) return(0); // Don't handle http://blahblah
+
+ /* Filter out psflib files */
+ if(strlen(teststr) < strlen(fn))
+ {
+  tmps=fn+strlen(fn);
+  tmps-=strlen(teststr);
+  if(!strcasecmp(tmps,teststr))
+   return(0);
+ }
+
+ if(!(fp=fopen(fn,"rb"))) return(0);
+ if(fread(buf,1,4,fp)!=4) {fclose(fp);return(0);}
+ fclose(fp);
+ if(memcmp(buf,"PSF\x01",4))	// Only allow for PSF1 files for now.
+   return 0;
+ return(1);
+}
+
+static char *MakeTitle(PSFINFO *info)
+{
+ char *ret;
+
+ ret=malloc( (info->game?strlen(info->game):0) + (info->title?strlen(info->title):0) + 3 + 1);
+ sprintf(ret,"%s - %s",info->game?info->game:"",info->title?info->title:"");
+
+ return(ret);
+}
+
+static void SI(void)
+{
+ char *tmp;
+ tmp=MakeTitle(PSFInfo);
+ sexypsf_ip.set_info(tmp,PSFInfo->length,44100*2*2*8,44100,2);
+ free(tmp);
+}
+
+static GThread *dethread;
+void sexypsf_update(unsigned char *Buffer, long count)
+{
+ int mask = ~((((16 / 8) * 2)) - 1);
+ if(count)
+  sexypsf_ip.add_vis_pcm(sexypsf_ip.output->written_time(), FMT_S16_NE, 2, count/4, Buffer);
+
+ while(count>0)
+ {
+  int t=sexypsf_ip.output->buffer_free() & mask;
+  if(t>count)
+  {
+   sexypsf_ip.output->write_audio(Buffer,count);
+  }
+  else
+  {
+   if(t)
+    sexypsf_ip.output->write_audio(Buffer,t);
+   usleep((count-t)*1000*5/441/2);
+  }
+  count-=t;
+  Buffer+=t;
+ }
+ if(command&CMD_SEEK)
+ {
+  int t=(command&~(CMD_SEEK|CMD_STOP))*1000;
+
+  if(sexypsf_seek(t))
+   sexypsf_ip.output->flush(t);
+  else	// Negative time!  Must make a C time machine.
+  {
+   sexypsf_stop();
+   return;
+  }
+  command&=~CMD_SEEK;
+ }
+ if(command&CMD_STOP)
+ {
+  sexypsf_stop();
+ }
+}
+static volatile int nextsong=0;
+
+static void *sexypsf_playloop(void *arg)
+{
+ dofunky:
+
+ sexypsf_execute();
+
+ /* We have reached the end of the song. Now what... */
+ sexypsf_ip.output->buffer_free();
+ sexypsf_ip.output->buffer_free();
+
+ while(!(command&CMD_STOP)) 
+ {
+  if(command&CMD_SEEK)
+  {
+   int t=(command&~(CMD_SEEK|CMD_STOP))*1000;
+   sexypsf_ip.output->flush(t);
+   if(!(PSFInfo=sexypsf_load(fnsave)))
+    break;
+   sexypsf_seek(t); 
+   command&=~CMD_SEEK;
+   goto dofunky;
+  }
+  if(!sexypsf_ip.output->buffer_playing()) break;
+  usleep(2000);
+ }
+ sexypsf_ip.output->close_audio();
+ if(!(command&CMD_STOP)) nextsong=1;
+ g_thread_exit(NULL);
+ return(NULL);
+}
+
+static int paused;
+static void sexypsf_xmms_play(char *fn)
+{
+ if(playing)
+  return;
+ nextsong=0;
+ paused = 0;
+ if(!sexypsf_ip.output->open_audio(FMT_S16_NE, 44100, 2))
+ {
+  puts("Error opening audio.");
+  return;
+ }
+ fnsave=malloc(strlen(fn)+1);
+ strcpy(fnsave,fn);
+ if(!(PSFInfo=sexypsf_load(fn)))
+ {
+  sexypsf_ip.output->close_audio();
+  nextsong=1;
+ }
+ else
+ {
+  command=0;
+  SI();
+  playing=1;
+  dethread = g_thread_create((GThreadFunc)sexypsf_playloop,NULL,TRUE,NULL);
+ }
+}
+
+static void sexypsf_xmms_stop(void)
+{
+ if(!playing) return;
+
+ if(paused)
+  sexypsf_ip.output->pause(0);
+ paused = 0;
+
+ command=CMD_STOP;
+ g_thread_join(dethread);
+ playing = 0;
+
+ if(fnsave)
+ {
+  free(fnsave);
+  fnsave=NULL;
+ } 
+ sexypsf_freepsfinfo(PSFInfo);
+ PSFInfo=NULL;
+}
+
+static void sexypsf_xmms_pause(short p)
+{
+ if(!playing) return;
+ sexypsf_ip.output->pause(p);
+ paused = p;
+}
+
+static void sexypsf_xmms_seek(int time)
+{
+ if(!playing) return;
+ command=CMD_SEEK|time;
+}
+
+static int sexypsf_xmms_gettime(void)
+{
+ if(nextsong)
+  return(-1);
+ if(!playing) return(0);
+ return sexypsf_ip.output->output_time();
+}
+
+static void sexypsf_xmms_getsonginfo(char *fn, char **title, int *length)
+{
+  PSFINFO *tmp;
+
+  if((tmp=sexypsf_getpsfinfo(fn)))
+  {
+   *length=tmp->length;
+   *title=MakeTitle(tmp);
+   sexypsf_freepsfinfo(tmp);
+  }
+}
+
+InputPlugin sexypsf_ip =
+{
+ 0,
+ 0,
+ "Plays PSF1 files.",
+ 0,
+ 0,
+ 0,
+ sexypsf_xmms_testfile,
+ 0,
+ sexypsf_xmms_play,
+ sexypsf_xmms_stop,
+ sexypsf_xmms_pause,
+ sexypsf_xmms_seek,
+ 0,
+ sexypsf_xmms_gettime,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ sexypsf_xmms_getsonginfo,
+ 0,
+ 0
+};