summaryrefslogtreecommitdiff
path: root/plugins/ao/eng_psf/peops2
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/ao/eng_psf/peops2')
-rw-r--r--plugins/ao/eng_psf/peops2/License.txt282
-rw-r--r--plugins/ao/eng_psf/peops2/adsr.h28
-rw-r--r--plugins/ao/eng_psf/peops2/adsr2.c656
-rw-r--r--plugins/ao/eng_psf/peops2/dma.h29
-rw-r--r--plugins/ao/eng_psf/peops2/dma2.c175
-rw-r--r--plugins/ao/eng_psf/peops2/externals.h385
-rw-r--r--plugins/ao/eng_psf/peops2/gauss_i.h162
-rwxr-xr-xplugins/ao/eng_psf/peops2/psemuxa.h28
-rw-r--r--plugins/ao/eng_psf/peops2/registers.h845
-rw-r--r--plugins/ao/eng_psf/peops2/registers2.c1343
-rw-r--r--plugins/ao/eng_psf/peops2/regs.h43
-rwxr-xr-xplugins/ao/eng_psf/peops2/reverb.h33
-rw-r--r--plugins/ao/eng_psf/peops2/reverb2.c420
-rw-r--r--plugins/ao/eng_psf/peops2/spu.h39
-rw-r--r--plugins/ao/eng_psf/peops2/spu2.c1013
-rw-r--r--plugins/ao/eng_psf/peops2/stdafx.h41
-rwxr-xr-xplugins/ao/eng_psf/peops2/xa.c363
17 files changed, 5885 insertions, 0 deletions
diff --git a/plugins/ao/eng_psf/peops2/License.txt b/plugins/ao/eng_psf/peops2/License.txt
new file mode 100644
index 00000000..e51338c2
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/License.txt
@@ -0,0 +1,282 @@
+#########################################################################
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/plugins/ao/eng_psf/peops2/adsr.h b/plugins/ao/eng_psf/peops2/adsr.h
new file mode 100644
index 00000000..777a0d84
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/adsr.h
@@ -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
+//
+//*************************************************************************//
+
+INLINE void StartADSR(int ch);
+INLINE int MixADSR(int ch);
diff --git a/plugins/ao/eng_psf/peops2/adsr2.c b/plugins/ao/eng_psf/peops2/adsr2.c
new file mode 100644
index 00000000..442cc38f
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/adsr2.c
@@ -0,0 +1,656 @@
+/***************************************************************************
+ adsr.c - description
+ -------------------
+ begin : Wed May 15 2002
+ copyright : (C) 2002 by Pete Bernert
+ email : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2003/05/14 - xodnizel
+// - removed stopping of reverb on sample end
+//
+// 2003/01/06 - Pete
+// - added Neill's ADSR timings
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_ADSR
+
+// will be included from spu.c
+#ifdef _IN_SPU
+
+////////////////////////////////////////////////////////////////////////
+// ADSR func
+////////////////////////////////////////////////////////////////////////
+
+unsigned long RateTable[160];
+
+void InitADSR(void) // INIT ADSR
+{
+ unsigned long r,rs,rd;int i;
+
+ memset(RateTable,0,sizeof(unsigned long)*160); // build the rate table according to Neill's rules (see at bottom of file)
+
+ r=3;rs=1;rd=0;
+
+ for(i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0
+ {
+ if(r<0x3FFFFFFF)
+ {
+ r+=rs;
+ rd++;if(rd==5) {rd=1;rs*=2;}
+ }
+ if(r>0x3FFFFFFF) r=0x3FFFFFFF;
+
+ RateTable[i]=r;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE void StartADSR(int ch) // MIX ADSR
+{
+ s_chan[ch].ADSRX.lVolume=1; // and init some adsr vars
+ s_chan[ch].ADSRX.State=0;
+ s_chan[ch].ADSRX.EnvelopeVol=0;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE int MixADSR(int ch) // MIX ADSR
+{
+ if(s_chan[ch].bStop) // should be stopped:
+ { // do release
+ if(s_chan[ch].ADSRX.ReleaseModeExp)
+ {
+ switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7)
+ {
+ case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +0 + 32]; break;
+ case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +4 + 32]; break;
+ case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +6 + 32]; break;
+ case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +8 + 32]; break;
+ case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +9 + 32]; break;
+ case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +10+ 32]; break;
+ case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +11+ 32]; break;
+ case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +12+ 32]; break;
+ }
+ }
+ else
+ {
+ s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x0C + 32];
+ }
+
+ if(s_chan[ch].ADSRX.EnvelopeVol<0)
+ {
+ s_chan[ch].ADSRX.EnvelopeVol=0;
+ s_chan[ch].bOn=0;
+ //s_chan[ch].bReverb=0;
+ //s_chan[ch].bNoise=0;
+ }
+
+ s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
+ return s_chan[ch].ADSRX.lVolume;
+ }
+ else // not stopped yet?
+ {
+ if(s_chan[ch].ADSRX.State==0) // -> attack
+ {
+ if(s_chan[ch].ADSRX.AttackModeExp)
+ {
+ if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000)
+ s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32];
+ else
+ s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + 32];
+ }
+ else
+ {
+ s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32];
+ }
+
+ if(s_chan[ch].ADSRX.EnvelopeVol<0)
+ {
+ s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF;
+ s_chan[ch].ADSRX.State=1;
+ }
+
+ s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
+ return s_chan[ch].ADSRX.lVolume;
+ }
+ //--------------------------------------------------//
+ if(s_chan[ch].ADSRX.State==1) // -> decay
+ {
+ switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7)
+ {
+ case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+0 + 32]; break;
+ case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+4 + 32]; break;
+ case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+6 + 32]; break;
+ case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+8 + 32]; break;
+ case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+9 + 32]; break;
+ case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+10+ 32]; break;
+ case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+11+ 32]; break;
+ case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+12+ 32]; break;
+ }
+
+ if(s_chan[ch].ADSRX.EnvelopeVol<0) s_chan[ch].ADSRX.EnvelopeVol=0;
+ if(((s_chan[ch].ADSRX.EnvelopeVol>>27)&0xF) <= s_chan[ch].ADSRX.SustainLevel)
+ {
+ s_chan[ch].ADSRX.State=2;
+ }
+
+ s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
+ return s_chan[ch].ADSRX.lVolume;
+ }
+ //--------------------------------------------------//
+ if(s_chan[ch].ADSRX.State==2) // -> sustain
+ {
+ if(s_chan[ch].ADSRX.SustainIncrease)
+ {
+ if(s_chan[ch].ADSRX.SustainModeExp)
+ {
+ if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000)
+ s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32];
+ else
+ s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x18 + 32];
+ }
+ else
+ {
+ s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32];
+ }
+
+ if(s_chan[ch].ADSRX.EnvelopeVol<0)
+ {
+ s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF;
+ }
+ }
+ else
+ {
+ if(s_chan[ch].ADSRX.SustainModeExp)
+ {
+ switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7)
+ {
+ case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +0 + 32];break;
+ case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +4 + 32];break;
+ case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +6 + 32];break;
+ case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +8 + 32];break;
+ case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +9 + 32];break;
+ case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +10+ 32];break;
+ case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +11+ 32];break;
+ case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +12+ 32];break;
+ }
+ }
+ else
+ {
+ s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x0F + 32];
+ }
+
+ if(s_chan[ch].ADSRX.EnvelopeVol<0)
+ {
+ s_chan[ch].ADSRX.EnvelopeVol=0;
+ }
+ }
+ s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21;
+ return s_chan[ch].ADSRX.lVolume;
+ }
+ }
+ return 0;
+}
+
+#endif
+
+/*
+James Higgs ADSR investigations:
+
+PSX SPU Envelope Timings
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+First, here is an extract from doomed's SPU doc, which explains the basics
+of the SPU "volume envelope":
+
+*** doomed doc extract start ***
+
+--------------------------------------------------------------------------
+Voices.
+--------------------------------------------------------------------------
+The SPU has 24 hardware voices. These voices can be used to reproduce sample
+data, noise or can be used as frequency modulator on the next voice.
+Each voice has it's own programmable ADSR envelope filter. The main volume
+can be programmed independently for left and right output.
+
+The ADSR envelope filter works as follows:
+Ar = Attack rate, which specifies the speed at which the volume increases
+ from zero to it's maximum value, as soon as the note on is given. The
+ slope can be set to lineair or exponential.
+Dr = Decay rate specifies the speed at which the volume decreases to the
+ sustain level. Decay is always decreasing exponentially.
+Sl = Sustain level, base level from which sustain starts.
+Sr = Sustain rate is the rate at which the volume of the sustained note
+ increases or decreases. This can be either lineair or exponential.
+Rr = Release rate is the rate at which the volume of the note decreases
+ as soon as the note off is given.
+
+ lvl |
+ ^ | /\Dr __
+ Sl _| _ / _ \__--- \
+ | / ---__ \ Rr
+ | /Ar Sr \ \
+ | / \\
+ |/___________________\________
+ ->time
+
+The overal volume can also be set to sweep up or down lineairly or
+exponentially from it's current value. This can be done seperately
+for left and right.
+
+Relevant SPU registers:
+-------------------------------------------------------------
+$1f801xx8 Attack/Decay/Sustain level
+bit |0f|0e 0d 0c 0b 0a 09 08|07 06 05 04|03 02 01 00|
+desc.|Am| Ar |Dr |Sl |
+
+Am 0 Attack mode Linear
+ 1 Exponential
+
+Ar 0-7f attack rate
+Dr 0-f decay rate
+Sl 0-f sustain level
+-------------------------------------------------------------
+$1f801xxa Sustain rate, Release Rate.
+bit |0f|0e|0d|0c 0b 0a 09 08 07 06|05|04 03 02 01 00|
+desc.|Sm|Sd| 0| Sr |Rm|Rr |
+
+Sm 0 sustain rate mode linear
+ 1 exponential
+Sd 0 sustain rate mode increase
+ 1 decrease
+Sr 0-7f Sustain Rate
+Rm 0 Linear decrease
+ 1 Exponential decrease
+Rr 0-1f Release Rate
+
+Note: decay mode is always Expontial decrease, and thus cannot
+be set.
+-------------------------------------------------------------
+$1f801xxc Current ADSR volume
+bit |0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00|
+desc.|ADSRvol |
+
+ADSRvol Returns the current envelope volume when
+ read.
+-- James' Note: return range: 0 -> 32767
+
+*** doomed doc extract end ***
+
+By using a small PSX proggie to visualise the envelope as it was played,
+the following results for envelope timing were obtained:
+
+1. Attack rate value (linear mode)
+
+ Attack value range: 0 -> 127
+
+ Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 | | 80 |
+ -----------------------------------------------------------------
+ Frames | 11 | 21 | 42 | 84 | 169| 338| 676| |2890|
+
+ Note: frames is no. of PAL frames to reach full volume (100%
+ amplitude)
+
+ Hmm, noticing that the time taken to reach full volume doubles
+ every time we add 4 to our attack value, we know the equation is
+ of form:
+ frames = k * 2 ^ (value / 4)
+
+ (You may ponder about envelope generator hardware at this point,
+ or maybe not... :)
+
+ By substituting some stuff and running some checks, we get:
+
+ k = 0.00257 (close enuf)
+
+ therefore,
+ frames = 0.00257 * 2 ^ (value / 4)
+ If you just happen to be writing an emulator, then you can probably
+ use an equation like:
+
+ %volume_increase_per_tick = 1 / frames
+
+
+ ------------------------------------
+ Pete:
+ ms=((1<<(value>>2))*514)/10000
+ ------------------------------------
+
+2. Decay rate value (only has log mode)
+
+ Decay value range: 0 -> 15
+
+ Value | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
+ ------------------------------------------------
+ frames | | | | | 6 | 12 | 24 | 47 |
+
+ Note: frames here is no. of PAL frames to decay to 50% volume.
+
+ formula: frames = k * 2 ^ (value)
+
+ Substituting, we get: k = 0.00146
+
+ Further info on logarithmic nature:
+ frames to decay to sustain level 3 = 3 * frames to decay to
+ sustain level 9
+
+ Also no. of frames to 25% volume = roughly 1.85 * no. of frames to
+ 50% volume.
+
+ Frag it - just use linear approx.
+
+ ------------------------------------
+ Pete:
+ ms=((1<<value)*292)/10000
+ ------------------------------------
+
+
+3. Sustain rate value (linear mode)
+
+ Sustain rate range: 0 -> 127
+
+ Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 |
+ -------------------------------------------
+ frames | 9 | 19 | 37 | 74 | 147| 293| 587|
+
+ Here, frames = no. of PAL frames for volume amplitude to go from 100%
+ to 0% (or vice-versa).
+
+ Same formula as for attack value, just a different value for k:
+
+ k = 0.00225
+
+ ie: frames = 0.00225 * 2 ^ (value / 4)
+
+ For emulation purposes:
+
+ %volume_increase_or_decrease_per_tick = 1 / frames
+
+ ------------------------------------
+ Pete:
+ ms=((1<<(value>>2))*450)/10000
+ ------------------------------------
+
+
+4. Release rate (linear mode)
+
+ Release rate range: 0 -> 31
+
+ Value | 13 | 14 | 15 | 16 | 17 |
+ ---------------------------------------------------------------
+ frames | 18 | 36 | 73 | 146| 292|
+
+ Here, frames = no. of PAL frames to decay from 100% vol to 0% vol
+ after "note-off" is triggered.
+
+ Formula: frames = k * 2 ^ (value)
+
+ And so: k = 0.00223
+
+ ------------------------------------
+ Pete:
+ ms=((1<<value)*446)/10000
+ ------------------------------------
+
+
+Other notes:
+
+Log stuff not figured out. You may get some clues from the "Decay rate"
+stuff above. For emu purposes it may not be important - use linear
+approx.
+
+To get timings in millisecs, multiply frames by 20.
+
+
+
+- James Higgs 17/6/2000
+james7780@yahoo.com
+
+//---------------------------------------------------------------
+
+OLD adsr mixing according to james' rules... has to be called
+every one millisecond
+
+
+ long v,v2,lT,l1,l2,l3;
+
+ if(s_chan[ch].bStop) // psx wants to stop? -> release phase
+ {
+ if(s_chan[ch].ADSR.ReleaseVal!=0) // -> release not 0: do release (if 0: stop right now)
+ {
+ if(!s_chan[ch].ADSR.ReleaseVol) // --> release just started? set up the release stuff
+ {
+ s_chan[ch].ADSR.ReleaseStartTime=s_chan[ch].ADSR.lTime;
+ s_chan[ch].ADSR.ReleaseVol=s_chan[ch].ADSR.lVolume;
+ s_chan[ch].ADSR.ReleaseTime = // --> calc how long does it take to reach the wanted sus level
+ (s_chan[ch].ADSR.ReleaseTime*
+ s_chan[ch].ADSR.ReleaseVol)/1024;
+ }
+ // -> NO release exp mode used (yet)
+ v=s_chan[ch].ADSR.ReleaseVol; // -> get last volume
+ lT=s_chan[ch].ADSR.lTime- // -> how much time is past?
+ s_chan[ch].ADSR.ReleaseStartTime;
+ l1=s_chan[ch].ADSR.ReleaseTime;
+
+ if(lT<l1) // -> we still have to release
+ {
+ v=v-((v*lT)/l1); // --> calc new volume
+ }
+ else // -> release is over: now really stop that sample
+ {v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;}
+ }
+ else // -> release IS 0: release at once
+ {
+ v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;
+ }
+ }
+ else
+ {//--------------------------------------------------// not in release phase:
+ v=1024;
+ lT=s_chan[ch].ADSR.lTime;
+ l1=s_chan[ch].ADSR.AttackTime;
+
+ if(lT<l1) // attack
+ { // no exp mode used (yet)
+// if(s_chan[ch].ADSR.AttackModeExp)
+// {
+// v=(v*lT)/l1;
+// }
+// else
+ {
+ v=(v*lT)/l1;
+ }
+ if(v==0) v=1;
+ }
+ else // decay
+ { // should be exp, but who cares? ;)
+ l2=s_chan[ch].ADSR.DecayTime;
+ v2=s_chan[ch].ADSR.SustainLevel;
+
+ lT-=l1;
+ if(lT<l2)
+ {
+ v-=(((v-v2)*lT)/l2);
+ }
+ else // sustain
+ { // no exp mode used (yet)
+ l3=s_chan[ch].ADSR.SustainTime;
+ lT-=l2;
+ if(s_chan[ch].ADSR.SustainModeDec>0)
+ {
+ if(l3!=0) v2+=((v-v2)*lT)/l3;
+ else v2=v;
+ }
+ else
+ {
+ if(l3!=0) v2-=(v2*lT)/l3;
+ else v2=v;
+ }
+
+ if(v2>v) v2=v;
+ if(v2<=0) {v2=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;}
+
+ v=v2;
+ }
+ }
+ }
+
+ //----------------------------------------------------//
+ // ok, done for this channel, so increase time
+
+ s_chan[ch].ADSR.lTime+=1; // 1 = 1.020408f ms;
+
+ if(v>1024) v=1024; // adjust volume
+ if(v<0) v=0;
+ s_chan[ch].ADSR.lVolume=v; // store act volume
+
+ return v; // return the volume factor
+*/
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+
+/*
+-----------------------------------------------------------------------------
+Neill Corlett
+Playstation SPU envelope timing notes
+-----------------------------------------------------------------------------
+
+This is preliminary. This may be wrong. But the model described herein fits
+all of my experimental data, and it's just simple enough to sound right.
+
+ADSR envelope level ranges from 0x00000000 to 0x7FFFFFFF internally.
+The value returned by channel reg 0xC is (envelope_level>>16).
+
+Each sample, an increment or decrement value will be added to or
+subtracted from this envelope level.
+
+Create the rate log table. The values double every 4 entries.
+ entry #0 = 4
+
+ 4, 5, 6, 7,
+ 8,10,12,14,
+ 16,20,24,28, ...
+
+ entry #40 = 4096...
+ entry #44 = 8192...
+ entry #48 = 16384...
+ entry #52 = 32768...
+ entry #56 = 65536...
+
+increments and decrements are in terms of ratelogtable[n]
+n may exceed the table bounds (plan on n being between -32 and 127).
+table values are all clipped between 0x00000000 and 0x3FFFFFFF
+
+when you "voice on", the envelope is always fully reset.
+(yes, it may click. the real thing does this too.)
+
+envelope level begins at zero.
+
+each state happens for at least 1 cycle
+(transitions are not instantaneous)
+this may result in some oddness: if the decay rate is uberfast, it will cut
+the envelope from full down to half in one sample, potentially skipping over
+the sustain level
+
+ATTACK
+------
+- if the envelope level has overflowed past the max, clip to 0x7FFFFFFF and
+ proceed to DECAY.
+
+Linear attack mode:
+- line extends upward to 0x7FFFFFFF
+- increment per sample is ratelogtable[(Ar^0x7F)-0x10]
+
+Logarithmic attack mode:
+if envelope_level < 0x60000000:
+ - line extends upward to 0x60000000
+ - increment per sample is ratelogtable[(Ar^0x7F)-0x10]
+else:
+ - line extends upward to 0x7FFFFFFF
+ - increment per sample is ratelogtable[(Ar^0x7F)-0x18]
+
+DECAY
+-----
+- if ((envelope_level>>27)&0xF) <= Sl, proceed to SUSTAIN.
+ Do not clip to the sustain level.
+- current line ends at (envelope_level & 0x07FFFFFF)
+- decrement per sample depends on (envelope_level>>28)&0x7
+ 0: ratelogtable[(4*(Dr^0x1F))-0x18+0]
+ 1: ratelogtable[(4*(Dr^0x1F))-0x18+4]
+ 2: ratelogtable[(4*(Dr^0x1F))-0x18+6]
+ 3: ratelogtable[(4*(Dr^0x1F))-0x18+8]
+ 4: ratelogtable[(4*(Dr^0x1F))-0x18+9]
+ 5: ratelogtable[(4*(Dr^0x1F))-0x18+10]
+ 6: ratelogtable[(4*(Dr^0x1F))-0x18+11]
+ 7: ratelogtable[(4*(Dr^0x1F))-0x18+12]
+ (note that this is the same as the release rate formula, except that
+ decay rates 10-1F aren't possible... those would be slower in theory)
+
+SUSTAIN
+-------
+- no terminating condition except for voice off
+- Sd=0 (increase) behavior is identical to ATTACK for both log and linear.
+- Sd=1 (decrease) behavior:
+Linear sustain decrease:
+- line extends to 0x00000000
+- decrement per sample is ratelogtable[(Sr^0x7F)-0x0F]
+Logarithmic sustain decrease:
+- current line ends at (envelope_level & 0x07FFFFFF)
+- decrement per sample depends on (envelope_level>>28)&0x7
+ 0: ratelogtable[(Sr^0x7F)-0x1B+0]
+ 1: ratelogtable[(Sr^0x7F)-0x1B+4]
+ 2: ratelogtable[(Sr^0x7F)-0x1B+6]
+ 3: ratelogtable[(Sr^0x7F)-0x1B+8]
+ 4: ratelogtable[(Sr^0x7F)-0x1B+9]
+ 5: ratelogtable[(Sr^0x7F)-0x1B+10]
+ 6: ratelogtable[(Sr^0x7F)-0x1B+11]
+ 7: ratelogtable[(Sr^0x7F)-0x1B+12]
+
+RELEASE
+-------
+- if the envelope level has overflowed to negative, clip to 0 and QUIT.
+
+Linear release mode:
+- line extends to 0x00000000
+- decrement per sample is ratelogtable[(4*(Rr^0x1F))-0x0C]
+
+Logarithmic release mode:
+- line extends to (envelope_level & 0x0FFFFFFF)
+- decrement per sample depends on (envelope_level>>28)&0x7
+ 0: ratelogtable[(4*(Rr^0x1F))-0x18+0]
+ 1: ratelogtable[(4*(Rr^0x1F))-0x18+4]
+ 2: ratelogtable[(4*(Rr^0x1F))-0x18+6]
+ 3: ratelogtable[(4*(Rr^0x1F))-0x18+8]
+ 4: ratelogtable[(4*(Rr^0x1F))-0x18+9]
+ 5: ratelogtable[(4*(Rr^0x1F))-0x18+10]
+ 6: ratelogtable[(4*(Rr^0x1F))-0x18+11]
+ 7: ratelogtable[(4*(Rr^0x1F))-0x18+12]
+
+-----------------------------------------------------------------------------
+*/
+
diff --git a/plugins/ao/eng_psf/peops2/dma.h b/plugins/ao/eng_psf/peops2/dma.h
new file mode 100644
index 00000000..e11ece6d
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/dma.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ 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
+//
+//*************************************************************************//
+
+void InterruptDMA4(void);
+void InterruptDMA7(void);
+
diff --git a/plugins/ao/eng_psf/peops2/dma2.c b/plugins/ao/eng_psf/peops2/dma2.c
new file mode 100644
index 00000000..d137dfc2
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/dma2.c
@@ -0,0 +1,175 @@
+/***************************************************************************
+ dma.c - description
+ -------------------
+ begin : Wed May 15 2002
+ copyright : (C) 2002 by Pete Bernert
+ email : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "../peops2/stdafx.h"
+
+#define _IN_DMA
+
+#include "../peops2/externals.h"
+#include "../peops2/registers.h"
+//#include "debug.h"
+
+extern uint32 psx_ram[(2*1024*1024)/4];
+
+////////////////////////////////////////////////////////////////////////
+// READ DMA (many values)
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2readDMA4Mem(u32 usPSXMem,int iSize)
+{
+ int i;
+ u16 *ram16 = (u16 *)&psx_ram[0];
+
+ for(i=0;i<iSize;i++)
+ {
+ ram16[usPSXMem>>1]=spuMem[spuAddr2[0]]; // spu addr 0 got by writeregister
+ usPSXMem+=2;
+ spuAddr2[0]++; // inc spu addr
+ if(spuAddr2[0]>0xfffff) spuAddr2[0]=0; // wrap
+ }
+
+ spuAddr2[0]+=0x20; //?????
+
+
+ iSpuAsyncWait=0;
+
+ // got from J.F. and Kanodin... is it needed?
+ regArea[(PS2_C0_ADMAS)>>1]=0; // Auto DMA complete
+ spuStat2[0]=0x80; // DMA complete
+}
+
+EXPORT_GCC void CALLBACK SPU2readDMA7Mem(u32 usPSXMem,int iSize)
+{
+ int i;
+ u16 *ram16 = (u16 *)&psx_ram[0];
+
+ for(i=0;i<iSize;i++)
+ {
+ ram16[usPSXMem>>1]=spuMem[spuAddr2[1]]; // spu addr 1 got by writeregister
+ usPSXMem+=2;
+ spuAddr2[1]++; // inc spu addr
+ if(spuAddr2[1]>0xfffff) spuAddr2[1]=0; // wrap
+ }
+
+ spuAddr2[1]+=0x20; //?????
+
+ iSpuAsyncWait=0;
+
+ // got from J.F. and Kanodin... is it needed?
+ regArea[(PS2_C1_ADMAS)>>1]=0; // Auto DMA complete
+ spuStat2[1]=0x80; // DMA complete
+}
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+// to investigate: do sound data updates by writedma affect spu
+// irqs? Will an irq be triggered, if new data is written to
+// the memory irq address?
+
+////////////////////////////////////////////////////////////////////////
+// WRITE DMA (many values)
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2writeDMA4Mem(u32 usPSXMem,int iSize)
+{
+ int i;
+ u16 *ram16 = (u16 *)&psx_ram[0];
+
+ for(i=0;i<iSize;i++)
+ {
+ spuMem[spuAddr2[0]] = ram16[usPSXMem>>1]; // spu addr 0 got by writeregister
+ usPSXMem+=2;
+ spuAddr2[0]++; // inc spu addr
+ if(spuAddr2[0]>0xfffff) spuAddr2[0]=0; // wrap
+ }
+
+ iSpuAsyncWait=0;
+
+ // got from J.F. and Kanodin... is it needed?
+ spuStat2[0]=0x80; // DMA complete
+}
+
+EXPORT_GCC void CALLBACK SPU2writeDMA7Mem(u32 usPSXMem,int iSize)
+{
+ int i;
+ u16 *ram16 = (u16 *)&psx_ram[0];
+
+ for(i=0;i<iSize;i++)
+ {
+ spuMem[spuAddr2[1]] = ram16[usPSXMem>>1]; // spu addr 1 got by writeregister
+ spuAddr2[1]++; // inc spu addr
+ if(spuAddr2[1]>0xfffff) spuAddr2[1]=0; // wrap
+ }
+
+ iSpuAsyncWait=0;
+
+ // got from J.F. and Kanodin... is it needed?
+ spuStat2[1]=0x80; // DMA complete
+}
+
+////////////////////////////////////////////////////////////////////////
+// INTERRUPTS
+////////////////////////////////////////////////////////////////////////
+
+void InterruptDMA4(void)
+{
+// taken from linuzappz NULL spu2
+// spu2Rs16(CORE0_ATTR)&= ~0x30;
+// spu2Rs16(REG__1B0) = 0;
+// spu2Rs16(SPU2_STATX_WRDY_M)|= 0x80;
+
+ spuCtrl2[0]&=~0x30;
+ regArea[(PS2_C0_ADMAS)>>1]=0;
+ spuStat2[0]|=0x80;
+}
+
+EXPORT_GCC void CALLBACK SPU2interruptDMA4(void)
+{
+ InterruptDMA4();
+}
+
+void InterruptDMA7(void)
+{
+// taken from linuzappz NULL spu2
+// spu2Rs16(CORE1_ATTR)&= ~0x30;
+// spu2Rs16(REG__5B0) = 0;
+// spu2Rs16(SPU2_STATX_DREQ)|= 0x80;
+
+ spuCtrl2[1]&=~0x30;
+ regArea[(PS2_C1_ADMAS)>>1]=0;
+ spuStat2[1]|=0x80;
+}
+
+EXPORT_GCC void CALLBACK SPU2interruptDMA7(void)
+{
+ InterruptDMA7();
+}
+
diff --git a/plugins/ao/eng_psf/peops2/externals.h b/plugins/ao/eng_psf/peops2/externals.h
new file mode 100644
index 00000000..83e74c08
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/externals.h
@@ -0,0 +1,385 @@
+/***************************************************************************
+ externals.h - description
+ -------------------
+ begin : Wed May 15 2002
+ copyright : (C) 2002 by Pete Bernert
+ email : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2002/04/04 - Pete
+// - increased channel struct for interpolation
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#ifndef PEOPS2_EXTERNALS
+#define PEOPS2_EXTERNALS
+
+#include "ao.h"
+
+typedef int8 s8;
+typedef int16 s16;
+typedef int32 s32;
+typedef int64 s64;
+
+typedef uint8 u8;
+typedef uint16 u16;
+typedef uint32 u32;
+typedef uint64 u64;
+
+#if LSB_FIRST
+static INLINE u16 BFLIP16(u16 x)
+{
+ return x;
+}
+#else
+static INLINE u16 BFLIP16(u16 x)
+{
+ return( ((x>>8)&0xFF)| ((x&0xFF)<<8) );
+}
+#endif
+
+/////////////////////////////////////////////////////////
+// generic defines
+/////////////////////////////////////////////////////////
+
+//#define PSE_LT_SPU 4
+//#define PSE_SPU_ERR_SUCCESS 0
+//#define PSE_SPU_ERR -60
+//#define PSE_SPU_ERR_NOTCONFIGURED PSE_SPU_ERR - 1
+//#define PSE_SPU_ERR_INIT PSE_SPU_ERR - 2
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+////////////////////////////////////////////////////////////////////////
+// spu defines
+////////////////////////////////////////////////////////////////////////
+
+// sound buffer sizes
+// 400 ms complete sound buffer
+#define SOUNDSIZE 76800
+// 137 ms test buffer... if less than that is buffered, a new upload will happen
+#define TESTSIZE 26304
+
+// num of channels
+#define MAXCHAN 48
+#define HLFCHAN 24
+
+// ~ 1 ms of data (was 45)
+#define NSSIZE 1
+//45
+
+///////////////////////////////////////////////////////////
+// struct defines
+///////////////////////////////////////////////////////////
+
+// ADSR INFOS PER CHANNEL
+typedef struct
+{
+ int AttackModeExp;
+ long AttackTime;
+ long DecayTime;
+ long SustainLevel;
+ int SustainModeExp;
+ long SustainModeDec;
+ long SustainTime;
+ int ReleaseModeExp;
+ unsigned long ReleaseVal;
+ long ReleaseTime;
+ long ReleaseStartTime;
+ long ReleaseVol;
+ long lTime;
+ long lVolume;
+} ADSRInfo;
+
+typedef struct
+{
+ int State;
+ int AttackModeExp;
+ int AttackRate;
+ int DecayRate;
+ int SustainLevel;
+ int SustainModeExp;
+ int SustainIncrease;
+ int SustainRate;
+ int ReleaseModeExp;
+ int ReleaseRate;
+ int EnvelopeVol;
+ long lVolume;
+ long lDummy1;
+ long lDummy2;
+} ADSRInfoEx;
+
+///////////////////////////////////////////////////////////
+
+// Tmp Flags
+
+// used for debug channel muting
+#define FLAG_MUTE 1
+
+// used for simple interpolation
+#define FLAG_IPOL0 2
+#define FLAG_IPOL1 4
+
+///////////////////////////////////////////////////////////
+
+// MAIN CHANNEL STRUCT
+typedef struct
+{
+ // no mutexes used anymore... don't need them to sync access
+ //HANDLE hMutex;
+
+ int bNew; // start flag
+
+ int iSBPos; // mixing stuff
+ int spos;
+ int sinc;
+ int SB[32+32]; // Pete added another 32 dwords in 1.6 ... prevents overflow issues with gaussian/cubic interpolation (thanx xodnizel!), and can be used for even better interpolations, eh? :)
+ int sval;
+
+ unsigned char * pStart; // start ptr into sound mem
+ unsigned char * pCurr; // current pos in sound mem
+ unsigned char * pLoop; // loop ptr in sound mem
+
+ int iStartAdr;
+ int iLoopAdr;
+ int iNextAdr;
+
+ int bOn; // is channel active (sample playing?)
+ int bStop; // is channel stopped (sample _can_ still be playing, ADSR Release phase)
+ int bEndPoint; // end point reached
+ int bReverbL; // can we do reverb on this channel? must have ctrl register bit, to get active
+ int bReverbR;
+
+ int bVolumeL; // Volume on/off
+ int bVolumeR;
+
+ int iActFreq; // current psx pitch
+ int iUsedFreq; // current pc pitch
+ int iLeftVolume; // left volume
+ int iLeftVolRaw; // left psx volume value
+ int bIgnoreLoop; // ignore loop bit, if an external loop address is used
+ int iMute; // mute mode
+ int iRightVolume; // right volume
+ int iRightVolRaw; // right psx volume value
+ int iRawPitch; // raw pitch (0...3fff)
+ int iIrqDone; // debug irq done flag
+ int s_1; // last decoding infos
+ int s_2;
+ int bRVBActive; // reverb active flag
+ int bNoise; // noise active flag
+ int bFMod; // freq mod (0=off, 1=sound channel, 2=freq channel)
+ int iOldNoise; // old noise val for this channel
+ ADSRInfo ADSR; // active ADSR settings
+ ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start)
+
+} SPUCHAN;
+
+///////////////////////////////////////////////////////////
+
+typedef struct
+{
+ int StartAddr; // reverb area start addr in samples
+ int EndAddr; // reverb area end addr in samples
+ int CurrAddr; // reverb area curr addr in samples
+
+ int VolLeft;
+ int VolRight;
+ int iLastRVBLeft;
+ int iLastRVBRight;
+ int iRVBLeft;
+ int iRVBRight;
+ int iCnt;
+
+ int FB_SRC_A; // (offset)
+ int FB_SRC_B; // (offset)
+ int IIR_ALPHA; // (coef.)
+ int ACC_COEF_A; // (coef.)
+ int ACC_COEF_B; // (coef.)
+ int ACC_COEF_C; // (coef.)
+ int ACC_COEF_D; // (coef.)
+ int IIR_COEF; // (coef.)
+ int FB_ALPHA; // (coef.)
+ int FB_X; // (coef.)
+ int IIR_DEST_A0; // (offset)
+ int IIR_DEST_A1; // (offset)
+ int ACC_SRC_A0; // (offset)
+ int ACC_SRC_A1; // (offset)
+ int ACC_SRC_B0; // (offset)
+ int ACC_SRC_B1; // (offset)
+ int IIR_SRC_A0; // (offset)
+ int IIR_SRC_A1; // (offset)
+ int IIR_DEST_B0; // (offset)
+ int IIR_DEST_B1; // (offset)
+ int ACC_SRC_C0; // (offset)
+ int ACC_SRC_C1; // (offset)
+ int ACC_SRC_D0; // (offset)
+ int ACC_SRC_D1; // (offset)
+ int IIR_SRC_B1; // (offset)
+ int IIR_SRC_B0; // (offset)
+ int MIX_DEST_A0; // (offset)
+ int MIX_DEST_A1; // (offset)
+ int MIX_DEST_B0; // (offset)
+ int MIX_DEST_B1; // (offset)
+ int IN_COEF_L; // (coef.)
+ int IN_COEF_R; // (coef.)
+} REVERBInfo;
+
+#ifdef _WINDOWS
+//extern HINSTANCE hInst;
+//#define WM_MUTE (WM_USER+543)
+#endif
+
+///////////////////////////////////////////////////////////
+// SPU.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_SPU
+
+// psx buffers / addresses
+
+extern unsigned short regArea[];
+extern unsigned short spuMem[];
+extern unsigned char * spuMemC;
+extern unsigned char * pSpuIrq[];
+extern unsigned char * pSpuBuffer;
+
+// user settings
+
+extern int iUseXA;
+extern int iVolume;
+extern int iXAPitch;
+extern int iUseTimer;
+extern int iSPUIRQWait;
+extern int iDebugMode;
+extern int iRecordMode;
+extern int iUseReverb;
+extern int iUseInterpolation;
+extern int iDisStereo;
+// MISC
+
+extern SPUCHAN s_chan[];
+extern REVERBInfo rvb[];
+
+extern unsigned long dwNoiseVal;
+extern unsigned short spuCtrl2[];
+extern unsigned short spuStat2[];
+extern unsigned long spuIrq2[];
+extern unsigned long spuAddr2[];
+extern unsigned long spuRvbAddr2[];
+extern unsigned long spuRvbAEnd2[];
+
+extern int bEndThread;
+extern int bThreadEnded;
+extern int bSpuInit;
+
+extern int SSumR[];
+extern int SSumL[];
+extern int iCycle;
+extern short * pS;
+extern unsigned long dwNewChannel2[];
+extern unsigned long dwEndChannel2[];
+
+extern int iSpuAsyncWait;
+
+#ifdef _WINDOWS
+//extern HWND hWMain; // window handle
+//extern HWND hWDebug;
+#endif
+
+extern void (CALLBACK *cddavCallback)(unsigned short,unsigned short);
+
+#endif
+
+///////////////////////////////////////////////////////////
+// CFG.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_CFG
+
+#ifndef _WINDOWS
+extern char * pConfigFile;
+#endif
+
+#endif
+
+///////////////////////////////////////////////////////////
+// DSOUND.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_DSOUND
+
+#ifdef _WINDOWS
+extern unsigned long LastWrite;
+extern unsigned long LastPlay;
+#endif
+
+#endif
+
+///////////////////////////////////////////////////////////
+// RECORD.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_RECORD
+
+#ifdef _WINDOWS
+extern int iDoRecord;
+#endif
+
+#endif
+
+///////////////////////////////////////////////////////////
+// XA.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_XA
+
+extern xa_decode_t * xapGlobal;
+
+extern unsigned long * XAFeed;
+extern unsigned long * XAPlay;
+extern unsigned long * XAStart;
+extern unsigned long * XAEnd;
+
+extern unsigned long XARepeat;
+extern unsigned long XALastVal;
+
+extern int iLeftXAVol;
+extern int iRightXAVol;
+
+#endif
+
+///////////////////////////////////////////////////////////
+// REVERB.C globals
+///////////////////////////////////////////////////////////
+
+#ifndef _IN_REVERB
+
+extern int * sRVBPlay[];
+extern int * sRVBEnd[];
+extern int * sRVBStart[];
+
+#endif
+
+#endif // PEOPS2_EXTERNALS
diff --git a/plugins/ao/eng_psf/peops2/gauss_i.h b/plugins/ao/eng_psf/peops2/gauss_i.h
new file mode 100644
index 00000000..83ecf5b7
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/gauss_i.h
@@ -0,0 +1,162 @@
+/***************************************************************************
+ gauss_i.h - description
+ -----------------------
+ begin : Sun Feb 08 2003
+ copyright : (C) 2003 by Chris Moeller, eh, whatever
+ email : chris@kode54.tk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2003/02/08 - kode54
+// - generated by interleaving table from gauss.h from the libopenspc
+// project; a gaussian bell curve table logged from the SPC-700,
+// though Neill says he logged the same curve from a PSX SPU. Also
+// says that interleaving the coefficients together runs faster. Meh.
+//
+//*************************************************************************//
+
+#ifndef GAUSS_H
+#define GAUSS_H
+
+static 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
diff --git a/plugins/ao/eng_psf/peops2/psemuxa.h b/plugins/ao/eng_psf/peops2/psemuxa.h
new file mode 100755
index 00000000..84c62604
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/psemuxa.h
@@ -0,0 +1,28 @@
+//============================================
+//=== Audio XA decoding
+//=== Kazzuya
+//============================================
+
+#ifndef DECODEXA_H
+#define DECODEXA_H
+
+typedef struct
+{
+ long y0, y1;
+} ADPCM_Decode_t;
+
+typedef struct
+{
+ int freq;
+ int nbits;
+ int stereo;
+ int nsamples;
+ ADPCM_Decode_t left, right;
+ short pcm[16384];
+} xa_decode_t;
+
+long xa_decode_sector( xa_decode_t *xdp,
+ unsigned char *sectorp,
+ int is_first_sector );
+
+#endif
diff --git a/plugins/ao/eng_psf/peops2/registers.h b/plugins/ao/eng_psf/peops2/registers.h
new file mode 100644
index 00000000..75e1c395
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/registers.h
@@ -0,0 +1,845 @@
+/***************************************************************************
+ registers.h - description
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - generic cleanup for the Peops release... register values by Kanodin &
+// his team
+//
+//*************************************************************************//
+
+//###########################################################################
+
+#define PS2_C0_SPUaddr_Hi (0x000 + 0x1A8)
+#define PS2_C0_SPUaddr_Lo (0x000 + 0x1AA)
+#define PS2_C1_SPUaddr_Hi (0x400 + 0x1A8)
+#define PS2_C1_SPUaddr_Lo (0x400 + 0x1AA)
+#define PS2_C0_SPUdata (0x000 + 0x1AC)
+#define PS2_C1_SPUdata (0x400 + 0x1AC)
+
+#define PS2_C0_SPUDMActrl (0x000 + 0x1AE)
+#define PS2_C1_SPUDMActrl (0x400 + 0x1AE)
+
+#define PS2_C0_SPUstat (0x000 + 0x344)
+#define PS2_C1_SPUstat (0x400 + 0x344)
+#define PS2_C0_ReverbAddr_Hi (0x000 + 0x2E0)
+#define PS2_C0_ReverbAddr_Lo (0x000 + 0x2E2)
+#define PS2_C1_ReverbAddr_Hi (0x400 + 0x2E0)
+#define PS2_C1_ReverbAddr_Lo (0x400 + 0x2E2)
+
+#define PS2_C0_ReverbAEnd_Hi (0x000 + 0x33C)
+#define PS2_C0_ReverbAEnd_Lo (0x000 + 0x33E)
+#define PS2_C1_ReverbAEnd_Hi (0x400 + 0x33C)
+#define PS2_C1_ReverbAEnd_Lo (0x400 + 0x33E)
+
+#define PS2_C0_DryL1 (0x000 + 0x188)
+#define PS2_C1_DryL1 (0x400 + 0x188)
+#define PS2_C0_DryL2 (0x000 + 0x18A)
+#define PS2_C1_DryL2 (0x400 + 0x18A)
+
+#define PS2_C0_DryR1 (0x000 + 0x190)
+#define PS2_C1_DryR1 (0x400 + 0x190)
+#define PS2_C0_DryR2 (0x000 + 0x192)
+#define PS2_C1_DryR2 (0x400 + 0x192)
+
+#define PS2_C0_ATTR (0x000 + 0x19A)
+#define PS2_C1_ATTR (0x400 + 0x19A)
+#define PS2_C0_ADMAS (0x000 + 0x1B0)
+#define PS2_C1_ADMAS (0x400 + 0x1B0)
+
+#define PS2_C0_SPUirqAddr_Hi (0x000 + 0x19C)
+#define PS2_C0_SPUirqAddr_Lo (0x000 + 0x19D)
+#define PS2_C1_SPUirqAddr_Hi (0x400 + 0x19C)
+#define PS2_C1_SPUirqAddr_Lo (0x400 + 0x19D)
+#define PS2_C0_SPUrvolL (0x000 + 0x764)
+#define PS2_C0_SPUrvolR (0x000 + 0x766)
+#define PS2_C1_SPUrvolL (0x028 + 0x764)
+#define PS2_C1_SPUrvolR (0x028 + 0x766)
+#define PS2_C0_SPUon1 (0x000 + 0x1A0)
+#define PS2_C0_SPUon2 (0x000 + 0x1A2)
+#define PS2_C1_SPUon1 (0x400 + 0x1A0)
+#define PS2_C1_SPUon2 (0x400 + 0x1A2)
+#define PS2_C0_SPUoff1 (0x000 + 0x1A4)
+#define PS2_C0_SPUoff2 (0x000 + 0x1A6)
+#define PS2_C1_SPUoff1 (0x400 + 0x1A4)
+#define PS2_C1_SPUoff2 (0x400 + 0x1A6)
+#define PS2_C0_FMod1 (0x000 + 0x180)
+#define PS2_C0_FMod2 (0x000 + 0x182)
+#define PS2_C1_FMod1 (0x400 + 0x180)
+#define PS2_C1_FMod2 (0x400 + 0x182)
+#define PS2_C0_Noise1 (0x000 + 0x184)
+#define PS2_C0_Noise2 (0x000 + 0x186)
+#define PS2_C1_Noise1 (0x400 + 0x184)
+#define PS2_C1_Noise2 (0x400 + 0x186)
+
+#define PS2_C0_RVBon1_L (0x000 + 0x18C)
+#define PS2_C0_RVBon2_L (0x000 + 0x18E)
+#define PS2_C0_RVBon1_R (0x000 + 0x194)
+#define PS2_C0_RVBon2_R (0x000 + 0x196)
+
+#define PS2_C1_RVBon1_L (0x400 + 0x18C)
+#define PS2_C1_RVBon2_L (0x400 + 0x18E)
+#define PS2_C1_RVBon1_R (0x400 + 0x194)
+#define PS2_C1_RVBon2_R (0x400 + 0x196)
+#define PS2_C0_Reverb (0x000 + 0x2E4)
+#define PS2_C1_Reverb (0x400 + 0x2E4)
+#define PS2_C0_ReverbX (0x000 + 0x774)
+#define PS2_C1_ReverbX (0x028 + 0x774)
+#define PS2_C0_SPUend1 (0x000 + 0x340)
+#define PS2_C0_SPUend2 (0x000 + 0x342)
+#define PS2_C1_SPUend1 (0x400 + 0x340)
+#define PS2_C1_SPUend2 (0x400 + 0x342)
+
+#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
+
+
+//###########################################################################
+
+/*
+ Included the info received in Regs.txt list by Neill Corlett - Kanodin
+
+ Voice parameters:
+ SD_VP_VOLL, SD_VP_VOLR - Volume left/right per voice. Assuming identical to PS1.
+ SD_VP_PITCH - Pitch scaler 0000-3FFF. Assuming identical to PS1.
+ SD_VP_ADSR1, SD_VP_ADSR1 - Envelope data. Bitfields are documented as identical to PS1.
+ SD_VP_ENVX - Current envelope value. Assuming identical to PS1.
+ SD_VP_VOLXL, SD_VP_VOLXR - Current voice volume left/right. Does not exist on the PS1.
+ Guessing that this is handy for the increase/decrease modes.
+
+ Voice addresses:
+
+ SD_VA_SSA - Sample start address; assuming identical to PS1
+ SD_VA_LSAX - Loop start address; assuming identical to PS1
+ SD_VA_NAX - Seems to be documented as the current playing address.
+ Does not exist on PS1.
+
+ Switches:
+
+ SD_S_PMON - Pitch mod; assuming identical to PS1
+ SD_S_NON - Noise; assuming identical to PS1
+ SD_S_VMIXL, SD_S_VMIXR - Voice mix L/R. Guessing this is just a separate L/R version
+ of the "voice enable" bits on the PS1.
+ SD_S_VMIXEL, SD_S_VMIXER - Voice effect mix L/R. Guessing this is just a separate L/R
+ version of the "voice reverb enable" bits on the PS1.
+ SD_S_KON, SD_S_KOFF - Key on/off; assuming identical to PS1
+
+
+ Addresses:
+
+ SD_A_TSA - Transfer start address; assuming identical to PS1
+ SD_A_ESA - Effect start address - this is probably analogous to the
+ PS1's reverb work area start address
+ SD_A_EEA - Effect end address - this would've been fixed to 0x7FFFF on
+ the PS1; settable in 128K increments on the PS2.
+ SD_A_IRQA - IRQ address; assuming identical to PS1
+
+ Volume parameters:
+
+ SD_P_MVOLL, SD_P_MVOLR - Master volume L/R; assuming identical to PS1
+ SD_P_EVOLL, SD_P_EVOLR - Effect volume L/R; assuming analogous to RVOL on the PS1
+ SD_P_AVOLL, SD_P_AVOLR - External input volume L/R
+ This is probably where CORE0 connects to CORE1
+ SD_P_BVOLL, SD_P_BVOLR - Sound data input volume - perhaps this is the volume of
+ the raw PCM auto-DMA input? analogous to CD input volume?
+ SD_P_MVOLXL, SD_P_MVOLXR - Current master volume L/R; seems self-explanatory
+
+ SD_P_MMIX - Mixer / effect enable bits.
+ bit 11 = MSNDL = voice output dry L
+ 10 = MSNDR = voice output dry R
+ 9 = MSNDEL = voice output wet L
+ 8 = MSNDER = voice output wet R
+ 7 = MINL = sound data input dry L
+ 6 = MINR = sound data input dry R
+ 5 = MINEL = sound data input wet L
+ 4 = MINER = sound data input wet R
+ 3 = SINL = core external input dry L
+ 2 = SINR = core external input dry R
+ 1 = SINEL = core external input wet L
+ 0 = SINER = core external input wet R
+
+Core attributes (SD_C)
+
+ bit 4..5 - DMA related
+ bit 6 - IRQ enable
+ bit 7 - effect enable (reverb enable)
+ bit 13..8 - noise clock
+ bit 14 - mute
+
+ - if you READ the two DMA related bits, if either are set, the channel is
+ considered "busy" by sceSdVoiceTrans
+
+
+
+Reverb parameters:
+
+ Same as PS1 reverb (I used the names from my reverb doc).
+
+
+Other PS2 IOP notes
+
+ There's two DMA controllers:
+ The original one at 1F801080-1F8010FF (channels 0-6)
+ A new one at 1F801500-1F80157F (channels 7-13)
+
+ They appear to function the same way - 7 channels each.
+
+ SPU CORE0's DMA channel is 4 as per usual
+ SPU CORE1's DMA channel is 7
+
+DMA channel 10 is SIF
+
+ Original INTR controller at 1F801000-1F80107F
+
+ All interrupt handling seems to be done using the old INTR, but
+ with some new bits defined:
+
+
+
+ Reading from 1F801078 masks interrupts and returns 1 if they weren't
+ masked before. Writing 1 to 1F801078 re-enables interrupts.
+ Writing 0 doesn't. Maybe it was like that on the original PS1 too.
+
+Six root counters:
+
+ RTC# address sources size prescale interrupt#
+0 0x1F801100 sysclock,pixel 16 bit 1 only 4
+1 0x1F801110 sysclock,hline 16 bit 1 only 5
+2 0x1F801120 sysclock 16 bit 1,8 6
+3 0x1F801480 sysclock,hline 32 bit 1 only 14
+4 0x1F801490 sysclock 32 bit 1,8,16,256 15
+5 0x1F8014A0 sysclock 32 bit 1,8,16,256 16
+
+Count (0x0) and Compare (0x8) registers work as before, only with more bits
+in the new counters.
+
+Mode (0x4) works like this when written:
+
+ bits 0..2 gate
+ bit 3 reset on target
+ bit 4 target interrupt enable
+ bit 5 overflow interrupt enable
+ bit 6 master enable (?)
+ bit 7 ?
+ bit 8 clock select
+ bit 9 prescale (OLD)
+ bit 10..12 ?
+ bit 13..14 prescale (NEW)
+ bit 15 ? always set to 1
+
+Gate:
+ TM_NO_GATE 000
+ TM_GATE_ON_Count 001
+ TM_GATE_ON_ClearStart 011
+ TM_GATE_ON_Clear_OFF_Start 101
+ TM_GATE_ON_Start 111
+
+ V-blank ----+ +----------------------------+ +------
+ | | | |
+ | | | |
+ +----+ +----+
+ TM_NO_GATE:
+
+ 0================================>============
+
+ TM_GATE_ON_Count:
+
+ <---->0==========================><---->0=====
+
+ TM_GATE_ON_ClearStart:
+
+ 0====>0================================>0=====
+
+ TM_GATE_ON_Clear_OFF_Start:
+
+ 0====><-------------------------->0====><-----
+
+ TM_GATE_ON_Start:
+
+ <---->0==========================>============
+
+ reset on target: if set, counter resets to 0 when Compare value is reached
+
+ target interrupt enable: if set, interrupt when Compare value is reached
+ overflow interrupt enable: if set, interrupt when counter overflows
+
+ master enable: if this bit is clear, the timer should do nothing.
+
+ clock select: for counters 0, 1, and 3, setting this will select the alternate
+ counter (pixel or hline)
+
+ prescale (OLD): for counter 2 only. set this to prescale (divide) by 8.
+
+ prescale (NEW): for counters 4 and 5 only:
+
+ 00 = prescale by 1
+ 01 = prescale by 8
+ 10 = prescale by 16
+ 11 = prescale by 256
+
+Writing 0x4 also clears the counter. (I think.)
+
+When 0x4 is read, it becomes Status:
+
+ bit 0..10 ?
+ bit 11 compare value was reached
+ bit 12 count overflowed
+ bit 13..15 ?
+
+Reading probably clears these bits.
+
+
+
+ 1F8014B0 (word) - timer-related but otherwise unknown
+ 1F8014C0 (word) - timer-related but otherwise unknown
+
+
+ don't currently know how the interrupts work for DMA ch7 yet
+
+ 1F801060 (word) - address of some kind.
+
+ 1F801450 (word) -
+ if bit 3 is SET, we're in PS1 mode.
+ if bit 3 is CLEAR, we're in PS2 IOP mode.
+
+ 1F802070 (byte) - unknown. status byte of some kind? visible to EE?
+
+ 1D000000-1D00007F (?) - SIF related
+
+ 1D000020 (word) - read counter of some sort?
+ sceSifInit waits for bit 0x10000 of this to be set.
+ 1D000030 (word) - read counter of some sort?
+ 1D000040 (word) - read bits 0x20, 0x40 mean something
+ 1D000060 (word) - used to detect whether the SIF interface exists
+ read must be 0x1D000060, or the top 20 bits must be zero
+*/
+
+/*
+
+// DirectX Audio SPU2 Driver for PCSX2
+// audio.c by J.F. and Kanodin (hooper1@cox.net)
+//
+// Copyright 2003 J.F. and Kanodin, and distributed under the
+// terms of the GNU General Public License, v2 or later.
+// http://www.gnu.org/copyleft/gpl.html.
+
+Included these just in case you need them J.F. - Kanodin
+
+// Core Start Addresses
+#define CORE0 0x1f900000
+#define CORE1 0x1f900400
+
+
+ #define IOP_INT_VBLANK (1<<0)
+ #define IOP_INT_GM (1<<1)
+ #define IOP_INT_CDROM (1<<2)
+ #define IOP_INT_DMA (1<<3)
+ #define IOP_INT_RTC0 (1<<4)
+ #define IOP_INT_RTC1 (1<<5)
+ #define IOP_INT_RTC2 (1<<6)
+ #define IOP_INT_SIO0 (1<<7)
+ #define IOP_INT_SIO1 (1<<8)
+ #define IOP_INT_SPU (1<<9)
+ #define IOP_INT_PIO (1<<10)
+ #define IOP_INT_EVBLANK (1<<11)
+ #define IOP_INT_DVD (1<<12)
+ #define IOP_INT_PCMCIA (1<<13)
+ #define IOP_INT_RTC3 (1<<14)
+ #define IOP_INT_RTC4 (1<<15)
+ #define IOP_INT_RTC5 (1<<16)
+ #define IOP_INT_SIO2 (1<<17)
+ #define IOP_INT_HTR0 (1<<18)
+ #define IOP_INT_HTR1 (1<<19)
+ #define IOP_INT_HTR2 (1<<20)
+ #define IOP_INT_HTR3 (1<<21)
+ #define IOP_INT_USB (1<<22)
+ #define IOP_INT_EXTR (1<<23)
+ #define IOP_INT_FWRE (1<<24)
+ #define IOP_INT_FDMA (1<<25)
+
+// CORE0 => +0x000, CORE1 => +0x400
+
+// individual voice parameter regs
+
+#define VP_VOLL(cr, vc) (0x400 * cr + 0x000 + (vc << 4)) // voice volume (left)
+#define VP_VOLR(cr, vc) (0x400 * cr + 0x002 + (vc << 4)) // voice volume (right)
+#define VP_PITCH(cr, vc) (0x400 * cr + 0x004 + (vc << 4)) // voice pitch
+#define VP_ADSR1(cr, vc) (0x400 * cr + 0x006 + (vc << 4)) // voice envelope (AR, DR, SL)
+#define VP_ADSR2(cr, vc) (0x400 * cr + 0x008 + (vc << 4)) // voice envelope (SR, RR)
+#define VP_ENVX(cr, vc) (0x400 * cr + 0x00A + (vc << 4)) // voice envelope (current value)
+#define VP_VOLXL(cr, vc) (0x400 * cr + 0x00C + (vc << 4)) // voice volume (current value left)
+#define VP_VOLXR(cr, vc) (0x400 * cr + 0x00E + (vc << 4)) // voice volume (current value right)
+
+#define VA_SSA(cr, vc) (0x400 * cr + 0x1C0 + (vc * 12)) // voice waveform data start address
+#define VA_LSAX(cr, vc) (0x400 * cr + 0x1C4 + (vc * 12)) // voice waveform data loop address
+#define VA_NAX(cr, vc) (0x400 * cr + 0x1C8 + (vc * 12)) // voice waveform data next address
+
+// common settings
+
+#define S_PMON(cr) (0x400 * cr + 0x180) // pitch modulation on
+#define S_NON(cr) (0x400 * cr + 0x184) // noise generator on
+#define S_VMIXL(cr) (0x400 * cr + 0x188) // voice output mixing (dry left)
+#define S_VMIXEL(cr) (0x400 * cr + 0x18C) // voice output mixing (wet left)
+#define S_VMIXR(cr) (0x400 * cr + 0x190) // voice output mixing (dry right)
+#define S_VMIXER(cr) (0x400 * cr + 0x194) // voice output mixing (wet right)
+#define P_MMIX(cr) (0x400 * cr + 0x198) // output type after voice mixing (See paragraph below)
+#define P_ATTR(cr) (0x400 * cr + 0x19A) // core attributes (See paragraph below)
+#define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address
+#define S_KON(cr) (0x400 * cr + 0x1A0) // key on (start voice sound generation)
+#define S_KOFF(cr) (0x400 * cr + 0x1A4) // key off (end voice sound generation)
+#define A_TSA(cr) (0x400 * cr + 0x1A8) // DMA transfer start address
+#define P_DATA(cr) (0x400 * cr + 0x1AC) // DMA data register
+#define P_CTRL(cr) (0x400 * cr + 0x1AE) // DMA control register
+#define P_ADMAS(cr) (0x400 * cr + 0x1B0) // AutoDMA status
+
+#define A_ESA(cr) (0x400 * cr + 0x2E0) // effects work area start address
+
+#define FB_SRC_A(cr) (0x400 * cr + 0x2E4)
+#define FB_SRC_B(cr) (0x400 * cr + 0x2E8)
+#define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC)
+#define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0)
+#define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4)
+#define ACC_SRC_A1(cr) (0x400 * cr + 0x2F8)
+#define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC)
+
+#define ACC_SRC_B1(cr) (0x400 * cr + 0x300)
+#define IIR_SRC_A0(cr) (0x400 * cr + 0x304)
+#define IIR_SRC_A1(cr) (0x400 * cr + 0x308)
+#define IIR_DEST_B0(cr) (0x400 * cr + 0x30C)
+#define IIR_DEST_B1(cr) (0x400 * cr + 0x310)
+#define ACC_SRC_C0(cr) (0x400 * cr + 0x314)
+#define ACC_SRC_C1(cr) (0x400 * cr + 0x318)
+
+#define ACC_SRC_D0(cr) (0x400 * cr + 0x31C)
+#define ACC_SRC_D1(cr) (0x400 * cr + 0x320)
+#define IIR_SRC_B1(cr) (0x400 * cr + 0x324)
+#define IIR_SRC_B0(cr) (0x400 * cr + 0x328)
+#define MIX_DEST_A0(cr) (0x400 * cr + 0x32C)
+#define MIX_DEST_A1(cr) (0x400 * cr + 0x330)
+#define MIX_DEST_B0(cr) (0x400 * cr + 0x334)
+#define MIX_DEST_B1(cr) (0x400 * cr + 0x338)
+
+#define A_EEA(cr) (0x400 * cr + 0x33C) // effects work area end address
+
+#define P_ENDX(cr) (0x400 * cr + 0x340) // voice loop end status
+#define P_STAT(cr) (0x400 * cr + 0x344) // DMA status register
+#define P_ENDS(cr) (0x400 * cr + 0x346) // ?
+
+// CORE0 => +0x400, CORE1 => +0x428
+
+#define P_MVOLL(cr) (0x28 * cr + 0x760) // master volume (left)
+#define P_MVOLR(cr) (0x28 * cr + 0x762) // master volume (right)
+#define P_EVOLL(cr) (0x28 * cr + 0x764) // effect return volume (left)
+#define P_EVOLR(cr) (0x28 * cr + 0x766) // effect return volume (right)
+#define P_AVOLL(cr) (0x28 * cr + 0x768) // core external input volume (left)
+#define P_AVOLR(cr) (0x28 * cr + 0x76A) // core external input volume (right)
+#define P_BVOLL(cr) (0x28 * cr + 0x76C) // sound data input volume (left)
+#define P_BVOLR(cr) (0x28 * cr + 0x76E) // sound data input volume (right)
+#define P_MVOLXL(cr) (0x28 * cr + 0x770) // current master volume (left)
+#define P_MVOLXR(cr) (0x28 * cr + 0x772) // current master volume (right)
+
+#define IIR_ALPHA(cr) (0x28 * cr + 0x774)
+#define ACC_COEF_A(cr) (0x28 * cr + 0x776)
+#define ACC_COEF_B(cr) (0x28 * cr + 0x778)
+#define ACC_COEF_C(cr) (0x28 * cr + 0x77A)
+#define ACC_COEF_D(cr) (0x28 * cr + 0x77C)
+#define IIR_COEF(cr) (0x28 * cr + 0x77E)
+#define FB_ALPHA(cr) (0x28 * cr + 0x780)
+#define FB_X(cr) (0x28 * cr + 0x782)
+#define IN_COEF_L(cr) (0x28 * cr + 0x784)
+#define IN_COEF_R(cr) (0x28 * cr + 0x786)
+
+// CORE1 only => +0x400
+
+#define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass
+#define SPDIF_MODE 0x7C6
+#define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD
+#define SPDIF_COPY 0x7CA // SPDIF Copy Protection
+
+// PS1 SPU CORE
+
+// individual voice settings
+
+#define SPU_VP_PITCH(vc) (0xC04 + (vc << 4)) // voice pitch
+#define SPU_VA_SSA(vc) (0xC06 + (vc << 4)) // voice waveform data start address
+#define SPU_VP_ADSR(vc) (0xC08 + (vc << 4)) // voice envelope
+#define SPU_VA_SSA(vc) (0xC0E + (vc << 4)) // voice waveform data loop address
+
+// common settings
+
+#define SPU_P_MVOLL 0xD80 // master volume (left)
+#define SPU_P_MVOLR 0xD82 // master volume (right)
+#define SPU_P_RVOLL 0xD84 // effect return volume (left)
+#define SPU_P_RVOLR 0xD86 // effect return volume (right)
+#define SPU_S_KON1 0xD88 // key on
+#define SPU_S_KON2 0xD8A //
+#define SPU_S_KOFF1 0xD8C // key off
+#define SPU_S_KOFF2 0xD8E //
+#define SPU_S_PMON1 0xD90 // pitch modulation on
+#define SPU_S_PMON2 0xD92 //
+#define SPU_S_NON1 0xD94 // noise generator on
+#define SPU_S_NON2 0xD96 //
+#define SPU_S_RVBON1 0xD98 // effects on
+#define SPU_S_RVBON2 0xD9A //
+#define SPU_S_MUTE1 0xD9C // voice mute
+#define SPU_S_MUTE2 0xD9E //
+
+#define SPU_A_ESA 0xDA2 // effects work area start
+#define SPU_A_IRQA 0xDA4 // IRQ address
+#define SPU_A_TSA 0xDA6 // DMA transfer start address
+#define SPU_P_DATA 0xDA8 // DMA data register
+#define SPU_P_CTRL 0xDAA // DMA control register
+#define SPU_P_STAT 0xDAE // DMA status register
+
+#define SPU_P_CDL 0xDB0 // sound data input volume (left)
+#define SPU_P_CDR 0xDB2 // sound data input volume (right)
+#define SPU_P_EXTL 0xDB4 // external input volume (left)
+#define SPU_P_EXTR 0xDB6 // external input volume (right)
+
+#define SPU_P_REVERB 0xDC0 // effects control
+
+
+// Individual voice parameter regs CORE 0
+// Only
+
+
+#define VP_VOLL(cr, vc) (0x400 * cr + 0x000 + (vc << 4)) // voice volume (left)
+#define VP_VOLR(cr, vc) (0x400 * cr + 0x002 + (vc << 4)) // voice volume (right)
+#define VP_PITCH(cr, vc) (0x400 * cr + 0x004 + (vc << 4)) // voice pitch
+#define VP_ADSR1(cr, vc) (0x400 * cr + 0x006 + (vc << 4)) // voice envelope (AR, DR, SL)
+#define VP_ADSR2(cr, vc) (0x400 * cr + 0x008 + (vc << 4)) // voice envelope (SR, RR)
+#define VP_ENVX(cr, vc) (0x400 * cr + 0x00A + (vc << 4)) // voice envelope (current value)
+#define VP_VOLXL(cr, vc) (0x400 * cr + 0x00C + (vc << 4)) // voice volume (current value left)
+#define VP_VOLXR(cr, vc) (0x400 * cr + 0x00E + (vc << 4)) // voice volume (current value right)
+
+#define VA_SSA(cr, vc) (0x400 * cr + 0x1C0 + (vc * 12)) // voice waveform data start address
+#define VA_LSAX(cr, vc) (0x400 * cr + 0x1C4 + (vc * 12)) // voice waveform data loop address
+#define VA_NAX(cr, vc) (0x400 * cr + 0x1C8 + (vc * 12)) // voice waveform data next address
+
+
+// CORE 0 Common Settings
+
+
+#define S_PMON(cr) (0x400 * cr + 0x180) // pitch modulation on
+#define S_NON(cr) (0x400 * cr + 0x184) // noise generator on
+#define S_VMIXL(cr) (0x400 * cr + 0x188) // voice output mixing (dry left)
+#define S_VMIXEL(cr) (0x400 * cr + 0x18C) // voice output mixing (wet left)
+#define S_VMIXR(cr) (0x400 * cr + 0x190) // voice output mixing (dry right)
+#define S_VMIXER(cr) (0x400 * cr + 0x194) // voice output mixing (wet right)
+#define P_MMIX(cr) (0x400 * cr + 0x198) // output type after voice mixing (See paragraph below)
+#define P_ATTR(cr) (0x400 * cr + 0x19A) // core attributes (See paragraph below)
+#define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address
+#define S_KON(cr) (0x400 * cr + 0x1A0) // key on (start voice sound generation)
+#define S_KOFF(cr) (0x400 * cr + 0x1A4) // key off (end voice sound generation)
+#define A_TSA(cr) (0x400 * cr + 0x1A8) // DMA transfer start address
+#define P_DATA(cr) (0x400 * cr + 0x1AC) // DMA data register
+#define P_CTRL(cr) (0x400 * cr + 0x1AE) // DMA control register
+#define P_ADMAS(cr) (0x400 * cr + 0x1B0) // AutoDMA status
+
+#define A_ESA(cr) (0x400 * cr + 0x2E0) // effects work area start address
+
+
+// Core 0 Reverb Addresses
+
+
+#define FB_SRC_A(cr) (0x400 * cr + 0x2E4)
+#define FB_SRC_B(cr) (0x400 * cr + 0x2E8)
+#define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC)
+#define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0)
+#define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4)
+#define ACC_SRC_A1(cr) (0x400 * cr + 0x2F8)
+#define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC)
+
+#define ACC_SRC_B1(cr) (0x400 * cr + 0x300)
+#define IIR_SRC_A0(cr) (0x400 * cr + 0x304)
+#define IIR_SRC_A1(cr) (0x400 * cr + 0x308)
+#define IIR_DEST_B0(cr) (0x400 * cr + 0x30C)
+#define IIR_DEST_B1(cr) (0x400 * cr + 0x310)
+#define ACC_SRC_C0(cr) (0x400 * cr + 0x314)
+#define ACC_SRC_C1(cr) (0x400 * cr + 0x318)
+
+#define ACC_SRC_D0(cr) (0x400 * cr + 0x31C)
+#define ACC_SRC_D1(cr) (0x400 * cr + 0x320)
+#define IIR_SRC_B1(cr) (0x400 * cr + 0x324)
+#define IIR_SRC_B0(cr) (0x400 * cr + 0x328)
+#define MIX_DEST_A0(cr) (0x400 * cr + 0x32C)
+#define MIX_DEST_A1(cr) (0x400 * cr + 0x330)
+#define MIX_DEST_B0(cr) (0x400 * cr + 0x334)
+#define MIX_DEST_B1(cr) (0x400 * cr + 0x338)
+
+#define A_EEA(cr) (0x400 * cr + 0x33C) // effects work area end address
+
+#define P_ENDX(cr) (0x400 * cr + 0x340) // voice loop end status
+#define P_STAT(cr) (0x400 * cr + 0x344) // DMA status register
+#define P_ENDS(cr) (0x400 * cr + 0x346) // ?
+
+
+// CORE 0 Specific
+
+
+#define P_MVOLL(cr) (0x28 * cr + 0x760) // master volume (left)
+#define P_MVOLR(cr) (0x28 * cr + 0x762) // master volume (right)
+#define P_EVOLL(cr) (0x28 * cr + 0x764) // effect return volume (left)
+#define P_EVOLR(cr) (0x28 * cr + 0x766) // effect return volume (right)
+#define P_AVOLL(cr) (0x28 * cr + 0x768) // core external input volume (left)
+#define P_AVOLR(cr) (0x28 * cr + 0x76A) // core external input volume (right)
+#define P_BVOLL(cr) (0x28 * cr + 0x76C) // sound data input volume (left)
+#define P_BVOLR(cr) (0x28 * cr + 0x76E) // sound data input volume (right)
+#define P_MVOLXL(cr) (0x28 * cr + 0x770) // current master volume (left)
+#define P_MVOLXR(cr) (0x28 * cr + 0x772) // current master volume (right)
+
+
+// More CORE 0 Reverb
+
+
+#define IIR_ALPHA(cr) (0x28 * cr + 0x774)
+#define ACC_COEF_A(cr) (0x28 * cr + 0x776)
+#define ACC_COEF_B(cr) (0x28 * cr + 0x778)
+#define ACC_COEF_C(cr) (0x28 * cr + 0x77A)
+#define ACC_COEF_D(cr) (0x28 * cr + 0x77C)
+#define IIR_COEF(cr) (0x28 * cr + 0x77E)
+#define FB_ALPHA(cr) (0x28 * cr + 0x780)
+#define FB_X(cr) (0x28 * cr + 0x782)
+#define IN_COEF_L(cr) (0x28 * cr + 0x784)
+#define IN_COEF_R(cr) (0x28 * cr + 0x786)
+
+
+// CORE 1 only
+
+#define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass
+#define SPDIF_MODE 0x7C6
+#define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD
+#define SPDIF_COPY 0x7CA // SPDIF Copy Protection
+*/
+
+/* PS1 SPU CORE
+
+*** The below really isn't needed, only if you ***
+*** want to add SPU support to the plugin ***
+*** which I see no need to add at this time. ***
+*** individual voice settings ***
+
+#define SPU_VP_PITCH(vc) (0xC04 + (vc << 4)) // voice pitch
+#define SPU_VA_SSA(vc) (0xC06 + (vc << 4)) // voice waveform data start address
+#define SPU_VP_ADSR(vc) (0xC08 + (vc << 4)) // voice envelope
+#define SPU_VA_SSA(vc) (0xC0E + (vc << 4)) // voice waveform data loop address
+
+// common settings
+
+#define SPU_P_MVOLL 0xD80 // master volume (left)
+#define SPU_P_MVOLR 0xD82 // master volume (right)
+#define SPU_P_RVOLL 0xD84 // effect return volume (left)
+#define SPU_P_RVOLR 0xD86 // effect return volume (right)
+#define SPU_S_KON1 0xD88 // key on
+#define SPU_S_KON2 0xD8A //
+#define SPU_S_KOFF1 0xD8C // key off
+#define SPU_S_KOFF2 0xD8E //
+#define SPU_S_PMON1 0xD90 // pitch modulation on
+#define SPU_S_PMON2 0xD92 //
+#define SPU_S_NON1 0xD94 // noise generator on
+#define SPU_S_NON2 0xD96 //
+#define SPU_S_RVBON1 0xD98 // effects on
+#define SPU_S_RVBON2 0xD9A //
+#define SPU_S_MUTE1 0xD9C // voice mute
+#define SPU_S_MUTE2 0xD9E //
+
+#define SPU_A_ESA 0xDA2 // effects work area start
+#define SPU_A_IRQA 0xDA4 // IRQ address
+#define SPU_A_TSA 0xDA6 // DMA transfer start address
+#define SPU_P_DATA 0xDA8 // DMA data register
+#define SPU_P_CTRL 0xDAA // DMA control register
+#define SPU_P_STAT 0xDAE // DMA status register
+
+#define SPU_P_CDL 0xDB0 // sound data input volume (left)
+#define SPU_P_CDR 0xDB2 // sound data input volume (right)
+#define SPU_P_EXTL 0xDB4 // external input volume (left)
+#define SPU_P_EXTR 0xDB6 // external input volume (right)
+
+#define SPU_P_REVERB 0xDC0 // effects control
+*/
+
+/*
+#define H_SPUReverbAddr 0x0da2
+#define H_SPUirqAddr 0x0da4
+#define H_SPUaddr 0x0da6
+#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
+*/
diff --git a/plugins/ao/eng_psf/peops2/registers2.c b/plugins/ao/eng_psf/peops2/registers2.c
new file mode 100644
index 00000000..0f3a8242
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/registers2.c
@@ -0,0 +1,1343 @@
+/***************************************************************************
+ registers.c - description
+ -------------------
+ begin : Wed May 15 2002
+ copyright : (C) 2002 by Pete Bernert
+ email : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2003/02/09 - kode54
+// - removed &0x3fff from reverb volume registers, fixes a few games,
+// hopefully won't be breaking anything
+//
+// 2003/01/19 - Pete
+// - added Neill's reverb
+//
+// 2003/01/06 - Pete
+// - added Neill's ADSR timings
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_REGISTERS
+
+#include "../peops2/externals.h"
+#include "../peops2/registers.h"
+#include "../peops2/regs.h"
+#include "../peops2/reverb.h"
+
+/*
+// adsr time values (in ms) by James Higgs ... see the end of
+// the adsr.c source for details
+
+#define ATTACK_MS 514L
+#define DECAYHALF_MS 292L
+#define DECAY_MS 584L
+#define SUSTAIN_MS 450L
+#define RELEASE_MS 446L
+*/
+
+// we have a timebase of 1.020408f ms, not 1 ms... so adjust adsr defines
+#define ATTACK_MS 494L
+#define DECAYHALF_MS 286L
+#define DECAY_MS 572L
+#define SUSTAIN_MS 441L
+#define RELEASE_MS 437L
+
+// Prototypes
+void SetVolumeL(unsigned char ch,short vol);
+void SetVolumeR(unsigned char ch,short vol);
+void ReverbOn(int start,int end,unsigned short val,int iRight);
+void SetReverbAddr(int core);
+void VolumeOn(int start,int end,unsigned short val,int iRight);
+
+////////////////////////////////////////////////////////////////////////
+// WRITE REGISTERS: called by main emu
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val)
+{
+ long r=reg&0xffff;
+
+ regArea[r>>1] = val;
+
+// printf("SPU2: %04x to %08x\n", val, reg);
+
+ if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info?
+ {
+ int ch=(r>>4)&0x1f;
+ if(r>=0x400) ch+=24;
+
+ switch(r&0x0f)
+ {
+ //------------------------------------------------// r volume
+ case 0:
+ SetVolumeL((unsigned char)ch,val);
+ break;
+ //------------------------------------------------// l volume
+ case 2:
+ SetVolumeR((unsigned char)ch,val);
+ break;
+ //------------------------------------------------// pitch
+ case 4:
+ SetPitch(ch,val);
+ break;
+ //------------------------------------------------// level with pre-calcs
+ case 6:
+ {
+ const unsigned long lval=val;unsigned long lx;
+ //---------------------------------------------//
+ s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0;
+ s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;
+ s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;
+ s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;
+ //---------------------------------------------//
+ if(!iDebugMode) break;
+ //---------------------------------------------// stuff below is only for debug mode
+
+ s_chan[ch].ADSR.AttackModeExp=(lval&0x8000)?1:0; //0x007f
+
+ lx=(((lval>>8) & 0x007f)>>2); // attack time to run from 0 to 100% volume
+ lx=min(31,lx); // no overflow on shift!
+ if(lx)
+ {
+ lx = (1<<lx);
+ if(lx<2147483) lx=(lx*ATTACK_MS)/10000L; // another overflow check
+ else lx=(lx/10000L)*ATTACK_MS;
+ if(!lx) lx=1;
+ }
+ s_chan[ch].ADSR.AttackTime=lx;
+
+ s_chan[ch].ADSR.SustainLevel= // our adsr vol runs from 0 to 1024, so scale the sustain level
+ (1024*((lval) & 0x000f))/15;
+
+ lx=(lval>>4) & 0x000f; // decay:
+ if(lx) // our const decay value is time it takes from 100% to 0% of volume
+ {
+ lx = ((1<<(lx))*DECAY_MS)/10000L;
+ if(!lx) lx=1;
+ }
+ s_chan[ch].ADSR.DecayTime = // so calc how long does it take to run from 100% to the wanted sus level
+ (lx*(1024-s_chan[ch].ADSR.SustainLevel))/1024;
+ }
+ break;
+ //------------------------------------------------// adsr times with pre-calcs
+ case 8:
+ {
+ const unsigned long lval=val;unsigned long lx;
+
+ //----------------------------------------------//
+ s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;
+ s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;
+ s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;
+ s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;
+ s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;
+ //----------------------------------------------//
+ if(!iDebugMode) break;
+ //----------------------------------------------// stuff below is only for debug mode
+
+ s_chan[ch].ADSR.SustainModeExp = (lval&0x8000)?1:0;
+ s_chan[ch].ADSR.ReleaseModeExp = (lval&0x0020)?1:0;
+
+ lx=((((lval>>6) & 0x007f)>>2)); // sustain time... often very high
+ lx=min(31,lx); // values are used to hold the volume
+ if(lx) // until a sound stop occurs
+ { // the highest value we reach (due to
+ lx = (1<<lx); // overflow checking) is:
+ if(lx<2147483) lx=(lx*SUSTAIN_MS)/10000L; // 94704 seconds = 1578 minutes = 26 hours...
+ else lx=(lx/10000L)*SUSTAIN_MS; // should be enuff... if the stop doesn't
+ if(!lx) lx=1; // come in this time span, I don't care :)
+ }
+ s_chan[ch].ADSR.SustainTime = lx;
+
+ lx=(lval & 0x001f);
+ s_chan[ch].ADSR.ReleaseVal =lx;
+ if(lx) // release time from 100% to 0%
+ { // note: the release time will be
+ lx = (1<<lx); // adjusted when a stop is coming,
+ if(lx<2147483) lx=(lx*RELEASE_MS)/10000L; // so at this time the adsr vol will
+ else lx=(lx/10000L)*RELEASE_MS; // run from (current volume) to 0%
+ if(!lx) lx=1;
+ }
+ s_chan[ch].ADSR.ReleaseTime=lx;
+
+ if(lval & 0x4000) // add/dec flag
+ s_chan[ch].ADSR.SustainModeDec=-1;
+ else s_chan[ch].ADSR.SustainModeDec=1;
+ }
+ break;
+ //------------------------------------------------//
+ }
+
+ iSpuAsyncWait=0;
+
+ return;
+ }
+
+ if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) // some channel info?
+ {
+ int ch=0;
+ if(r>=0x400) {ch=24;r-=0x400;}
+
+ ch+=(r-0x1c0)/12;
+ r-=(ch%24)*12;
+ switch(r)
+ {
+ //------------------------------------------------//
+ case 0x1C0:
+ s_chan[ch].iStartAdr=(((unsigned long)val&0xf)<<16)|(s_chan[ch].iStartAdr&0xFFFF);
+ s_chan[ch].pStart=spuMemC+(s_chan[ch].iStartAdr<<1);
+ break;
+ case 0x1C2:
+ s_chan[ch].iStartAdr=(s_chan[ch].iStartAdr & 0xF0000) | (val & 0xFFFF);
+ s_chan[ch].pStart=spuMemC+(s_chan[ch].iStartAdr<<1);
+ break;
+ //------------------------------------------------//
+ case 0x1C4:
+ s_chan[ch].iLoopAdr=(((unsigned long)val&0xf)<<16)|(s_chan[ch].iLoopAdr&0xFFFF);
+ s_chan[ch].pLoop=spuMemC+(s_chan[ch].iLoopAdr<<1);
+ s_chan[ch].bIgnoreLoop=1;
+ break;
+ case 0x1C6:
+ s_chan[ch].iLoopAdr=(s_chan[ch].iLoopAdr & 0xF0000) | (val & 0xFFFF);
+ s_chan[ch].pLoop=spuMemC+(s_chan[ch].iLoopAdr<<1);
+ s_chan[ch].bIgnoreLoop=1;
+ break;
+ //------------------------------------------------//
+ case 0x1C8:
+ // unused... check if it gets written as well
+ s_chan[ch].iNextAdr=(((unsigned long)val&0xf)<<16)|(s_chan[ch].iNextAdr&0xFFFF);
+ break;
+ case 0x1CA:
+ // unused... check if it gets written as well
+ s_chan[ch].iNextAdr=(s_chan[ch].iNextAdr & 0xF0000) | (val & 0xFFFF);
+ break;
+ //------------------------------------------------//
+ }
+
+ iSpuAsyncWait=0;
+
+ return;
+ }
+
+ switch(r)
+ {
+ //-------------------------------------------------//
+ case PS2_C0_SPUaddr_Hi:
+ spuAddr2[0] = (((unsigned long)val&0xf)<<16)|(spuAddr2[0]&0xFFFF);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUaddr_Lo:
+ spuAddr2[0] = (spuAddr2[0] & 0xF0000) | (val & 0xFFFF);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUaddr_Hi:
+ spuAddr2[1] = (((unsigned long)val&0xf)<<16)|(spuAddr2[1]&0xFFFF);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUaddr_Lo:
+ spuAddr2[1] = (spuAddr2[1] & 0xF0000) | (val & 0xFFFF);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUdata:
+ spuMem[spuAddr2[0]] = val;
+ spuAddr2[0]++;
+ if(spuAddr2[0]>0xfffff) spuAddr2[0]=0;
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUdata:
+ spuMem[spuAddr2[1]] = val;
+ spuAddr2[1]++;
+ if(spuAddr2[1]>0xfffff) spuAddr2[1]=0;
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_ATTR:
+ spuCtrl2[0]=val;
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_ATTR:
+ spuCtrl2[1]=val;
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUstat:
+ spuStat2[0]=val;
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUstat:
+ spuStat2[1]=val;
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_ReverbAddr_Hi:
+ spuRvbAddr2[0] = (((unsigned long)val&0xf)<<16)|(spuRvbAddr2[0]&0xFFFF);
+ SetReverbAddr(0);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_ReverbAddr_Lo:
+ spuRvbAddr2[0] = (spuRvbAddr2[0] & 0xF0000) | (val & 0xFFFF);
+ SetReverbAddr(0);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_ReverbAEnd_Hi:
+ spuRvbAEnd2[0] = (((unsigned long)val&0xf)<<16)|(/*spuRvbAEnd2[0]&*/0xFFFF);
+ rvb[0].EndAddr=spuRvbAEnd2[0];
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_ReverbAEnd_Hi:
+ spuRvbAEnd2[1] = (((unsigned long)val&0xf)<<16)|(/*spuRvbAEnd2[1]&*/0xFFFF);
+ rvb[1].EndAddr=spuRvbAEnd2[1];
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_ReverbAddr_Hi:
+ spuRvbAddr2[1] = (((unsigned long)val&0xf)<<16)|(spuRvbAddr2[1]&0xFFFF);
+ SetReverbAddr(1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_ReverbAddr_Lo:
+ spuRvbAddr2[1] = (spuRvbAddr2[1] & 0xF0000) | (val & 0xFFFF);
+ SetReverbAddr(1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUirqAddr_Hi:
+ spuIrq2[0] = (((unsigned long)val&0xf)<<16)|(spuIrq2[0]&0xFFFF);
+ pSpuIrq[0]=spuMemC+(spuIrq2[0]<<1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUirqAddr_Lo:
+ spuIrq2[0] = (spuIrq2[0] & 0xF0000) | (val & 0xFFFF);
+ pSpuIrq[0]=spuMemC+(spuIrq2[0]<<1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUirqAddr_Hi:
+ spuIrq2[1] = (((unsigned long)val&0xf)<<16)|(spuIrq2[1]&0xFFFF);
+ pSpuIrq[1]=spuMemC+(spuIrq2[1]<<1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUirqAddr_Lo:
+ spuIrq2[1] = (spuIrq2[1] & 0xF0000) | (val & 0xFFFF);
+ pSpuIrq[1]=spuMemC+(spuIrq2[1]<<1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUrvolL:
+ rvb[0].VolLeft=val;
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUrvolR:
+ rvb[0].VolRight=val;
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUrvolL:
+ rvb[1].VolLeft=val;
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUrvolR:
+ rvb[1].VolRight=val;
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUon1:
+ SoundOn(0,16,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUon2:
+ SoundOn(16,24,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUon1:
+ SoundOn(24,40,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUon2:
+ SoundOn(40,48,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUoff1:
+ SoundOff(0,16,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUoff2:
+ SoundOff(16,24,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUoff1:
+ SoundOff(24,40,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUoff2:
+ SoundOff(40,48,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_SPUend1:
+ case PS2_C0_SPUend2:
+ if(val) dwEndChannel2[0]=0;
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_SPUend1:
+ case PS2_C1_SPUend2:
+ if(val) dwEndChannel2[1]=0;
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_FMod1:
+ FModOn(0,16,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_FMod2:
+ FModOn(16,24,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_FMod1:
+ FModOn(24,40,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_FMod2:
+ FModOn(40,48,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_Noise1:
+ NoiseOn(0,16,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_Noise2:
+ NoiseOn(16,24,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_Noise1:
+ NoiseOn(24,40,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_Noise2:
+ NoiseOn(40,48,val);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_DryL1:
+ VolumeOn(0,16,val,0);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_DryL2:
+ VolumeOn(16,24,val,0);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_DryL1:
+ VolumeOn(24,40,val,0);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_DryL2:
+ VolumeOn(40,48,val,0);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_DryR1:
+ VolumeOn(0,16,val,1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_DryR2:
+ VolumeOn(16,24,val,1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_DryR1:
+ VolumeOn(24,40,val,1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_DryR2:
+ VolumeOn(40,48,val,1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_RVBon1_L:
+ ReverbOn(0,16,val,0);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_RVBon2_L:
+ ReverbOn(16,24,val,0);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_RVBon1_L:
+ ReverbOn(24,40,val,0);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_RVBon2_L:
+ ReverbOn(40,48,val,0);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_RVBon1_R:
+ ReverbOn(0,16,val,1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_RVBon2_R:
+ ReverbOn(16,24,val,1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_RVBon1_R:
+ ReverbOn(24,40,val,1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C1_RVBon2_R:
+ ReverbOn(40,48,val,1);
+ break;
+ //-------------------------------------------------//
+ case PS2_C0_Reverb+0:
+ rvb[0].FB_SRC_A=(((unsigned long)val&0xf)<<16)|(rvb[0].FB_SRC_A&0xFFFF);
+ break;
+ case PS2_C0_Reverb+2:
+ rvb[0].FB_SRC_A=(rvb[0].FB_SRC_A & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+4:
+ rvb[0].FB_SRC_B=(((unsigned long)val&0xf)<<16)|(rvb[0].FB_SRC_B&0xFFFF);
+ break;
+ case PS2_C0_Reverb+6:
+ rvb[0].FB_SRC_B=(rvb[0].FB_SRC_B & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+8:
+ rvb[0].IIR_DEST_A0=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_DEST_A0&0xFFFF);
+ break;
+ case PS2_C0_Reverb+10:
+ rvb[0].IIR_DEST_A0=(rvb[0].IIR_DEST_A0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+12:
+ rvb[0].IIR_DEST_A1=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_DEST_A1&0xFFFF);
+ break;
+ case PS2_C0_Reverb+14:
+ rvb[0].IIR_DEST_A1=(rvb[0].IIR_DEST_A1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+16:
+ rvb[0].ACC_SRC_A0=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_A0&0xFFFF);
+ break;
+ case PS2_C0_Reverb+18:
+ rvb[0].ACC_SRC_A0=(rvb[0].ACC_SRC_A0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+20:
+ rvb[0].ACC_SRC_A1=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_A1&0xFFFF);
+ break;
+ case PS2_C0_Reverb+22:
+ rvb[0].ACC_SRC_A1=(rvb[0].ACC_SRC_A1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+24:
+ rvb[0].ACC_SRC_B0=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_B0&0xFFFF);
+ break;
+ case PS2_C0_Reverb+26:
+ rvb[0].ACC_SRC_B0=(rvb[0].ACC_SRC_B0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+28:
+ rvb[0].ACC_SRC_B1=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_B1&0xFFFF);
+ break;
+ case PS2_C0_Reverb+30:
+ rvb[0].ACC_SRC_B1=(rvb[0].ACC_SRC_B1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+32:
+ rvb[0].IIR_SRC_A0=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_SRC_A0&0xFFFF);
+ break;
+ case PS2_C0_Reverb+34:
+ rvb[0].IIR_SRC_A0=(rvb[0].IIR_SRC_A0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+36:
+ rvb[0].IIR_SRC_A1=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_SRC_A1&0xFFFF);
+ break;
+ case PS2_C0_Reverb+38:
+ rvb[0].IIR_SRC_A1=(rvb[0].IIR_SRC_A1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+40:
+ rvb[0].IIR_DEST_B0=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_DEST_B0&0xFFFF);
+ break;
+ case PS2_C0_Reverb+42:
+ rvb[0].IIR_DEST_B0=(rvb[0].IIR_DEST_B0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+44:
+ rvb[0].IIR_DEST_B1=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_DEST_B1&0xFFFF);
+ break;
+ case PS2_C0_Reverb+46:
+ rvb[0].IIR_DEST_B1=(rvb[0].IIR_DEST_B1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+48:
+ rvb[0].ACC_SRC_C0=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_C0&0xFFFF);
+ break;
+ case PS2_C0_Reverb+50:
+ rvb[0].ACC_SRC_C0=(rvb[0].ACC_SRC_C0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+52:
+ rvb[0].ACC_SRC_C1=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_C1&0xFFFF);
+ break;
+ case PS2_C0_Reverb+54:
+ rvb[0].ACC_SRC_C1=(rvb[0].ACC_SRC_C1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+56:
+ rvb[0].ACC_SRC_D0=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_D0&0xFFFF);
+ break;
+ case PS2_C0_Reverb+58:
+ rvb[0].ACC_SRC_D0=(rvb[0].ACC_SRC_D0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+60:
+ rvb[0].ACC_SRC_D1=(((unsigned long)val&0xf)<<16)|(rvb[0].ACC_SRC_D1&0xFFFF);
+ break;
+ case PS2_C0_Reverb+62:
+ rvb[0].ACC_SRC_D1=(rvb[0].ACC_SRC_D1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+64:
+ rvb[0].IIR_SRC_B1=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_SRC_B1&0xFFFF);
+ break;
+ case PS2_C0_Reverb+66:
+ rvb[0].IIR_SRC_B1=(rvb[0].IIR_SRC_B1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+68:
+ rvb[0].IIR_SRC_B0=(((unsigned long)val&0xf)<<16)|(rvb[0].IIR_SRC_B0&0xFFFF);
+ break;
+ case PS2_C0_Reverb+70:
+ rvb[0].IIR_SRC_B0=(rvb[0].IIR_SRC_B0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+72:
+ rvb[0].MIX_DEST_A0=(((unsigned long)val&0xf)<<16)|(rvb[0].MIX_DEST_A0&0xFFFF);
+ break;
+ case PS2_C0_Reverb+74:
+ rvb[0].MIX_DEST_A0=(rvb[0].MIX_DEST_A0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+76:
+ rvb[0].MIX_DEST_A1=(((unsigned long)val&0xf)<<16)|(rvb[0].MIX_DEST_A1&0xFFFF);
+ break;
+ case PS2_C0_Reverb+78:
+ rvb[0].MIX_DEST_A1=(rvb[0].MIX_DEST_A1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+80:
+ rvb[0].MIX_DEST_B0=(((unsigned long)val&0xf)<<16)|(rvb[0].MIX_DEST_B0&0xFFFF);
+ break;
+ case PS2_C0_Reverb+82:
+ rvb[0].MIX_DEST_B0=(rvb[0].MIX_DEST_B0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_Reverb+84:
+ rvb[0].MIX_DEST_B1=(((unsigned long)val&0xf)<<16)|(rvb[0].MIX_DEST_B1&0xFFFF);
+ break;
+ case PS2_C0_Reverb+86:
+ rvb[0].MIX_DEST_B1=(rvb[0].MIX_DEST_B1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C0_ReverbX+0: rvb[0].IIR_ALPHA=(short)val; break;
+ case PS2_C0_ReverbX+2: rvb[0].ACC_COEF_A=(short)val; break;
+ case PS2_C0_ReverbX+4: rvb[0].ACC_COEF_B=(short)val; break;
+ case PS2_C0_ReverbX+6: rvb[0].ACC_COEF_C=(short)val; break;
+ case PS2_C0_ReverbX+8: rvb[0].ACC_COEF_D=(short)val; break;
+ case PS2_C0_ReverbX+10: rvb[0].IIR_COEF=(short)val; break;
+ case PS2_C0_ReverbX+12: rvb[0].FB_ALPHA=(short)val; break;
+ case PS2_C0_ReverbX+14: rvb[0].FB_X=(short)val; break;
+ case PS2_C0_ReverbX+16: rvb[0].IN_COEF_L=(short)val; break;
+ case PS2_C0_ReverbX+18: rvb[0].IN_COEF_R=(short)val; break;
+ //-------------------------------------------------//
+ case PS2_C1_Reverb+0:
+ rvb[1].FB_SRC_A=(((unsigned long)val&0xf)<<16)|(rvb[1].FB_SRC_A&0xFFFF);
+ break;
+ case PS2_C1_Reverb+2:
+ rvb[1].FB_SRC_A=(rvb[1].FB_SRC_A & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+4:
+ rvb[1].FB_SRC_B=(((unsigned long)val&0xf)<<16)|(rvb[1].FB_SRC_B&0xFFFF);
+ break;
+ case PS2_C1_Reverb+6:
+ rvb[1].FB_SRC_B=(rvb[1].FB_SRC_B & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+8:
+ rvb[1].IIR_DEST_A0=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_DEST_A0&0xFFFF);
+ break;
+ case PS2_C1_Reverb+10:
+ rvb[1].IIR_DEST_A0=(rvb[1].IIR_DEST_A0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+12:
+ rvb[1].IIR_DEST_A1=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_DEST_A1&0xFFFF);
+ break;
+ case PS2_C1_Reverb+14:
+ rvb[1].IIR_DEST_A1=(rvb[1].IIR_DEST_A1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+16:
+ rvb[1].ACC_SRC_A0=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_A0&0xFFFF);
+ break;
+ case PS2_C1_Reverb+18:
+ rvb[1].ACC_SRC_A0=(rvb[1].ACC_SRC_A0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+20:
+ rvb[1].ACC_SRC_A1=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_A1&0xFFFF);
+ break;
+ case PS2_C1_Reverb+22:
+ rvb[1].ACC_SRC_A1=(rvb[1].ACC_SRC_A1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+24:
+ rvb[1].ACC_SRC_B0=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_B0&0xFFFF);
+ break;
+ case PS2_C1_Reverb+26:
+ rvb[1].ACC_SRC_B0=(rvb[1].ACC_SRC_B0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+28:
+ rvb[1].ACC_SRC_B1=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_B1&0xFFFF);
+ break;
+ case PS2_C1_Reverb+30:
+ rvb[1].ACC_SRC_B1=(rvb[1].ACC_SRC_B1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+32:
+ rvb[1].IIR_SRC_A0=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_SRC_A0&0xFFFF);
+ break;
+ case PS2_C1_Reverb+34:
+ rvb[1].IIR_SRC_A0=(rvb[1].IIR_SRC_A0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+36:
+ rvb[1].IIR_SRC_A1=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_SRC_A1&0xFFFF);
+ break;
+ case PS2_C1_Reverb+38:
+ rvb[1].IIR_SRC_A1=(rvb[1].IIR_SRC_A1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+40:
+ rvb[1].IIR_DEST_B0=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_DEST_B0&0xFFFF);
+ break;
+ case PS2_C1_Reverb+42:
+ rvb[1].IIR_DEST_B0=(rvb[1].IIR_DEST_B0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+44:
+ rvb[1].IIR_DEST_B1=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_DEST_B1&0xFFFF);
+ break;
+ case PS2_C1_Reverb+46:
+ rvb[1].IIR_DEST_B1=(rvb[1].IIR_DEST_B1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+48:
+ rvb[1].ACC_SRC_C0=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_C0&0xFFFF);
+ break;
+ case PS2_C1_Reverb+50:
+ rvb[1].ACC_SRC_C0=(rvb[1].ACC_SRC_C0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+52:
+ rvb[1].ACC_SRC_C1=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_C1&0xFFFF);
+ break;
+ case PS2_C1_Reverb+54:
+ rvb[1].ACC_SRC_C1=(rvb[1].ACC_SRC_C1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+56:
+ rvb[1].ACC_SRC_D0=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_D0&0xFFFF);
+ break;
+ case PS2_C1_Reverb+58:
+ rvb[1].ACC_SRC_D0=(rvb[1].ACC_SRC_D0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+60:
+ rvb[1].ACC_SRC_D1=(((unsigned long)val&0xf)<<16)|(rvb[1].ACC_SRC_D1&0xFFFF);
+ break;
+ case PS2_C1_Reverb+62:
+ rvb[1].ACC_SRC_D1=(rvb[1].ACC_SRC_D1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+64:
+ rvb[1].IIR_SRC_B1=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_SRC_B1&0xFFFF);
+ break;
+ case PS2_C1_Reverb+66:
+ rvb[1].IIR_SRC_B1=(rvb[1].IIR_SRC_B1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+68:
+ rvb[1].IIR_SRC_B0=(((unsigned long)val&0xf)<<16)|(rvb[1].IIR_SRC_B0&0xFFFF);
+ break;
+ case PS2_C1_Reverb+70:
+ rvb[1].IIR_SRC_B0=(rvb[1].IIR_SRC_B0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+72:
+ rvb[1].MIX_DEST_A0=(((unsigned long)val&0xf)<<16)|(rvb[1].MIX_DEST_A0&0xFFFF);
+ break;
+ case PS2_C1_Reverb+74:
+ rvb[1].MIX_DEST_A0=(rvb[1].MIX_DEST_A0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+76:
+ rvb[1].MIX_DEST_A1=(((unsigned long)val&0xf)<<16)|(rvb[1].MIX_DEST_A1&0xFFFF);
+ break;
+ case PS2_C1_Reverb+78:
+ rvb[1].MIX_DEST_A1=(rvb[1].MIX_DEST_A1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+80:
+ rvb[1].MIX_DEST_B0=(((unsigned long)val&0xf)<<16)|(rvb[1].MIX_DEST_B0&0xFFFF);
+ break;
+ case PS2_C1_Reverb+82:
+ rvb[1].MIX_DEST_B0=(rvb[1].MIX_DEST_B0 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_Reverb+84:
+ rvb[1].MIX_DEST_B1=(((unsigned long)val&0xf)<<16)|(rvb[1].MIX_DEST_B1&0xFFFF);
+ break;
+ case PS2_C1_Reverb+86:
+ rvb[1].MIX_DEST_B1=(rvb[1].MIX_DEST_B1 & 0xF0000) | ((val) & 0xFFFF);
+ break;
+ case PS2_C1_ReverbX+0: rvb[1].IIR_ALPHA=(short)val; break;
+ case PS2_C1_ReverbX+2: rvb[1].ACC_COEF_A=(short)val; break;
+ case PS2_C1_ReverbX+4: rvb[1].ACC_COEF_B=(short)val; break;
+ case PS2_C1_ReverbX+6: rvb[1].ACC_COEF_C=(short)val; break;
+ case PS2_C1_ReverbX+8: rvb[1].ACC_COEF_D=(short)val; break;
+ case PS2_C1_ReverbX+10: rvb[1].IIR_COEF=(short)val; break;
+ case PS2_C1_ReverbX+12: rvb[1].FB_ALPHA=(short)val; break;
+ case PS2_C1_ReverbX+14: rvb[1].FB_X=(short)val; break;
+ case PS2_C1_ReverbX+16: rvb[1].IN_COEF_L=(short)val; break;
+ case PS2_C1_ReverbX+18: rvb[1].IN_COEF_R=(short)val; break;
+ }
+
+ iSpuAsyncWait=0;
+
+}
+
+////////////////////////////////////////////////////////////////////////
+// READ REGISTER: called by main emu
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC unsigned short CALLBACK SPU2read(unsigned long reg)
+{
+ long r=reg&0xffff;
+
+#ifdef _WINDOWS
+// if(iDebugMode==1) logprintf("R_REG %X\r\n",reg&0xFFFF);
+#endif
+
+ iSpuAsyncWait=0;
+
+ if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info?
+ {
+ switch(r&0x0f)
+ {
+ //------------------------------------------------// env value
+ case 10:
+ {
+ int ch=(r>>4)&0x1f;
+ if(r>=0x400) ch+=24;
+ if(s_chan[ch].bNew) return 1; // we are started, but not processed? return 1
+ if(s_chan[ch].ADSRX.lVolume && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well
+ !s_chan[ch].ADSRX.EnvelopeVol)
+ return 1;
+ return (unsigned short)(s_chan[ch].ADSRX.EnvelopeVol>>16);
+ }break;
+ }
+ }
+
+ if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) // some channel info?
+ {
+ int ch=0;unsigned long rx=r;
+ if(rx>=0x400) {ch=24;rx-=0x400;}
+
+ ch+=(rx-0x1c0)/12;
+ rx-=(ch%24)*12;
+
+ switch(rx)
+ {
+ //------------------------------------------------//
+ case 0x1C4:
+ return (((s_chan[ch].pLoop-spuMemC)>>17)&0xF);
+ break;
+ case 0x1C6:
+ return (((s_chan[ch].pLoop-spuMemC)>>1)&0xFFFF);
+ break;
+ //------------------------------------------------//
+ case 0x1C8:
+ return (((s_chan[ch].pCurr-spuMemC)>>17)&0xF);
+ break;
+ case 0x1CA:
+ return (((s_chan[ch].pCurr-spuMemC)>>1)&0xFFFF);
+ break;
+ //------------------------------------------------//
+ }
+ }
+
+ switch(r)
+ {
+ //--------------------------------------------------//
+ case PS2_C0_SPUend1:
+ return (unsigned short)((dwEndChannel2[0]&0xFFFF));
+ case PS2_C0_SPUend2:
+ return (unsigned short)((dwEndChannel2[0]>>16));
+ //--------------------------------------------------//
+ case PS2_C1_SPUend1:
+ return (unsigned short)((dwEndChannel2[1]&0xFFFF));
+ case PS2_C1_SPUend2:
+ return (unsigned short)((dwEndChannel2[1]>>16));
+ //--------------------------------------------------//
+ case PS2_C0_ATTR:
+ return spuCtrl2[0];
+ break;
+ //--------------------------------------------------//
+ case PS2_C1_ATTR:
+ return spuCtrl2[1];
+ break;
+ //--------------------------------------------------//
+ case PS2_C0_SPUstat:
+ return spuStat2[0];
+ break;
+ //--------------------------------------------------//
+ case PS2_C1_SPUstat:
+ return spuStat2[1];
+ break;
+ //--------------------------------------------------//
+ case PS2_C0_SPUdata:
+ {
+ unsigned short s=spuMem[spuAddr2[0]];
+ spuAddr2[0]++;
+ if(spuAddr2[0]>0xfffff) spuAddr2[0]=0;
+ return s;
+ }
+ //--------------------------------------------------//
+ case PS2_C1_SPUdata:
+ {
+ unsigned short s=spuMem[spuAddr2[1]];
+ spuAddr2[1]++;
+ if(spuAddr2[1]>0xfffff) spuAddr2[1]=0;
+ return s;
+ }
+ //--------------------------------------------------//
+ case PS2_C0_SPUaddr_Hi:
+ return (unsigned short)((spuAddr2[0]>>16)&0xF);
+ break;
+ case PS2_C0_SPUaddr_Lo:
+ return (unsigned short)((spuAddr2[0]&0xFFFF));
+ break;
+ //--------------------------------------------------//
+ case PS2_C1_SPUaddr_Hi:
+ return (unsigned short)((spuAddr2[1]>>16)&0xF);
+ break;
+ case PS2_C1_SPUaddr_Lo:
+ return (unsigned short)((spuAddr2[1]&0xFFFF));
+ break;
+ //--------------------------------------------------//
+ }
+
+ return regArea[r>>1];
+}
+
+EXPORT_GCC void CALLBACK SPU2writePS1Port(unsigned long reg, unsigned short val)
+{
+ const u32 r=reg&0xfff;
+
+ if(r>=0xc00 && r<0xd80) // channel info
+ {
+ SPU2write(r-0xc00, val);
+ return;
+ }
+
+ switch(r)
+ {
+ //-------------------------------------------------//
+ case H_SPUaddr:
+ spuAddr2[0] = (u32) val<<2;
+ break;
+ //-------------------------------------------------//
+ case H_SPUdata:
+ spuMem[spuAddr2[0]] = BFLIP16(val);
+ spuAddr2[0]++;
+ if(spuAddr2[0]>0xfffff) spuAddr2[0]=0;
+ break;
+ //-------------------------------------------------//
+ case H_SPUctrl:
+// spuCtrl=val;
+ break;
+ //-------------------------------------------------//
+ case H_SPUstat:
+ spuStat2[0]=val & 0xf800;
+ break;
+ //-------------------------------------------------//
+ case H_SPUReverbAddr:
+ spuRvbAddr2[0] = val;
+ SetReverbAddr(0);
+ break;
+ //-------------------------------------------------//
+ case H_SPUirqAddr:
+ spuIrq2[0] = val<<2;
+ pSpuIrq[0]=spuMemC+((u32) val<<1);
+ 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[0].VolLeft=(s16)val;
+ //printf("%d\n",val);
+ break;
+ //-------------------------------------------------//
+ case H_SPUrvolR:
+ rvb[0].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:
+ ReverbOn(0,16,val,0);
+ break;
+
+ //-------------------------------------------------//
+ case H_RVBon2:
+ ReverbOn(16,24,val,0);
+ break;
+
+ //-------------------------------------------------//
+ case H_Reverb+0:
+ rvb[0].FB_SRC_A=val;
+ break;
+
+ case H_Reverb+2 : rvb[0].FB_SRC_B=(s16)val; break;
+ case H_Reverb+4 : rvb[0].IIR_ALPHA=(s16)val; break;
+ case H_Reverb+6 : rvb[0].ACC_COEF_A=(s16)val; break;
+ case H_Reverb+8 : rvb[0].ACC_COEF_B=(s16)val; break;
+ case H_Reverb+10 : rvb[0].ACC_COEF_C=(s16)val; break;
+ case H_Reverb+12 : rvb[0].ACC_COEF_D=(s16)val; break;
+ case H_Reverb+14 : rvb[0].IIR_COEF=(s16)val; break;
+ case H_Reverb+16 : rvb[0].FB_ALPHA=(s16)val; break;
+ case H_Reverb+18 : rvb[0].FB_X=(s16)val; break;
+ case H_Reverb+20 : rvb[0].IIR_DEST_A0=(s16)val; break;
+ case H_Reverb+22 : rvb[0].IIR_DEST_A1=(s16)val; break;
+ case H_Reverb+24 : rvb[0].ACC_SRC_A0=(s16)val; break;
+ case H_Reverb+26 : rvb[0].ACC_SRC_A1=(s16)val; break;
+ case H_Reverb+28 : rvb[0].ACC_SRC_B0=(s16)val; break;
+ case H_Reverb+30 : rvb[0].ACC_SRC_B1=(s16)val; break;
+ case H_Reverb+32 : rvb[0].IIR_SRC_A0=(s16)val; break;
+ case H_Reverb+34 : rvb[0].IIR_SRC_A1=(s16)val; break;
+ case H_Reverb+36 : rvb[0].IIR_DEST_B0=(s16)val; break;
+ case H_Reverb+38 : rvb[0].IIR_DEST_B1=(s16)val; break;
+ case H_Reverb+40 : rvb[0].ACC_SRC_C0=(s16)val; break;
+ case H_Reverb+42 : rvb[0].ACC_SRC_C1=(s16)val; break;
+ case H_Reverb+44 : rvb[0].ACC_SRC_D0=(s16)val; break;
+ case H_Reverb+46 : rvb[0].ACC_SRC_D1=(s16)val; break;
+ case H_Reverb+48 : rvb[0].IIR_SRC_B1=(s16)val; break;
+ case H_Reverb+50 : rvb[0].IIR_SRC_B0=(s16)val; break;
+ case H_Reverb+52 : rvb[0].MIX_DEST_A0=(s16)val; break;
+ case H_Reverb+54 : rvb[0].MIX_DEST_A1=(s16)val; break;
+ case H_Reverb+56 : rvb[0].MIX_DEST_B0=(s16)val; break;
+ case H_Reverb+58 : rvb[0].MIX_DEST_B1=(s16)val; break;
+ case H_Reverb+60 : rvb[0].IN_COEF_L=(s16)val; break;
+ case H_Reverb+62 : rvb[0].IN_COEF_R=(s16)val; break;
+ }
+}
+
+EXPORT_GCC unsigned short CALLBACK SPU2readPS1Port(unsigned long reg)
+{
+ const u32 r=reg&0xfff;
+
+ if(r>=0x0c00 && r<0x0d80)
+ {
+ return SPU2read(r-0xc00);
+ }
+
+ switch(r)
+ {
+// case H_SPUctrl:
+// return spuCtrl;
+ break;
+
+ case H_SPUstat:
+ return spuStat2[0];
+ break;
+
+ case H_SPUaddr:
+ return (u16)(spuAddr2[0]>>2);
+ break;
+
+ case H_SPUdata:
+ {
+ u16 s=BFLIP16(spuMem[spuAddr2[0]]);
+ spuAddr2[0]++;
+ if(spuAddr2[0]>0xfffff) spuAddr2[0]=0;
+ return s;
+ }
+ break;
+
+ case H_SPUirqAddr:
+ return spuIrq2[0]>>2;
+ break;
+ }
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+// SOUND ON register write
+////////////////////////////////////////////////////////////////////////
+
+void SoundOn(int start,int end,unsigned short val) // SOUND ON PSX COMAND
+{
+ int ch;
+
+ for(ch=start;ch<end;ch++,val>>=1) // loop channels
+ {
+ if((val&1) && s_chan[ch].pStart) // mmm... start has to be set before key on !?!
+ {
+ s_chan[ch].bIgnoreLoop=0;
+ s_chan[ch].bNew=1;
+ dwNewChannel2[ch/24]|=(1<<(ch%24)); // bitfield for faster testing
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// SOUND OFF register write
+////////////////////////////////////////////////////////////////////////
+
+void SoundOff(int start,int end,unsigned short val) // SOUND OFF PSX COMMAND
+{
+ int ch;
+ for(ch=start;ch<end;ch++,val>>=1) // loop channels
+ {
+ if(val&1) // && s_chan[i].bOn) mmm...
+ {
+ s_chan[ch].bStop=1;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// FMOD register write
+////////////////////////////////////////////////////////////////////////
+
+void FModOn(int start,int end,unsigned short val) // FMOD ON PSX COMMAND
+{
+ int ch;
+
+ for(ch=start;ch<end;ch++,val>>=1) // loop channels
+ {
+ if(val&1) // -> fmod on/off
+ {
+ if(ch>0)
+ {
+ s_chan[ch].bFMod=1; // --> sound channel
+ s_chan[ch-1].bFMod=2; // --> freq channel
+ }
+ }
+ else
+ {
+ s_chan[ch].bFMod=0; // --> turn off fmod
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// NOISE register write
+////////////////////////////////////////////////////////////////////////
+
+void NoiseOn(int start,int end,unsigned short val) // NOISE ON PSX COMMAND
+{
+ int ch;
+
+ for(ch=start;ch<end;ch++,val>>=1) // loop channels
+ {
+ if(val&1) // -> noise on/off
+ {
+ s_chan[ch].bNoise=1;
+ }
+ else
+ {
+ s_chan[ch].bNoise=0;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// LEFT VOLUME register write
+////////////////////////////////////////////////////////////////////////
+
+// please note: sweep and phase invert are wrong... but I've never seen
+// them used
+
+void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME
+{
+ s_chan[ch].iLeftVolRaw=vol;
+
+ if(vol&0x8000) // sweep?
+ {
+ short sInc=1; // -> sweep up?
+ if(vol&0x2000) sInc=-1; // -> or down?
+ if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this
+ vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64
+ vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half!
+ vol*=128;
+ }
+ else // no sweep:
+ {
+ if(vol&0x4000) // -> mmm... phase inverted? have to investigate this
+ //vol^=0xffff;
+ vol=0x3fff-(vol&0x3fff);
+ }
+
+ vol&=0x3fff;
+ s_chan[ch].iLeftVolume=vol; // store volume
+}
+
+////////////////////////////////////////////////////////////////////////
+// RIGHT VOLUME register write
+////////////////////////////////////////////////////////////////////////
+
+void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME
+{
+ s_chan[ch].iRightVolRaw=vol;
+
+ if(vol&0x8000) // comments... see above :)
+ {
+ short sInc=1;
+ if(vol&0x2000) sInc=-1;
+ if(vol&0x1000) vol^=0xffff;
+ vol=((vol&0x7f)+1)/2;
+ vol+=vol/(2*sInc);
+ vol*=128;
+ }
+ else
+ {
+ if(vol&0x4000) //vol=vol^=0xffff;
+ vol=0x3fff-(vol&0x3fff);
+ }
+
+ vol&=0x3fff;
+ s_chan[ch].iRightVolume=vol;
+}
+
+////////////////////////////////////////////////////////////////////////
+// PITCH register write
+////////////////////////////////////////////////////////////////////////
+
+void SetPitch(int ch,unsigned short val) // SET PITCH
+{
+ int NP;
+ double intr;
+
+ if(val>0x3fff) NP=0x3fff; // get pitch val
+ else NP=val;
+
+ intr = (double)48000.0f / (double)44100.0f * (double)NP;
+ NP = (UINT32)intr;
+
+ s_chan[ch].iRawPitch=NP;
+
+ NP=(44100L*NP)/4096L; // calc frequency
+
+ if(NP<1) NP=1; // some security
+ s_chan[ch].iActFreq=NP; // store frequency
+}
+
+////////////////////////////////////////////////////////////////////////
+// REVERB register write
+////////////////////////////////////////////////////////////////////////
+
+void ReverbOn(int start,int end,unsigned short val,int iRight) // REVERB ON PSX COMMAND
+{
+ int ch;
+
+ for(ch=start;ch<end;ch++,val>>=1) // loop channels
+ {
+ if(val&1) // -> reverb on/off
+ {
+ if(iRight) s_chan[ch].bReverbR=1;
+ else s_chan[ch].bReverbL=1;
+ }
+ else
+ {
+ if(iRight) s_chan[ch].bReverbR=0;
+ else s_chan[ch].bReverbL=0;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// REVERB START register write
+////////////////////////////////////////////////////////////////////////
+
+void SetReverbAddr(int core)
+{
+ long val=spuRvbAddr2[core];
+
+ if(rvb[core].StartAddr!=val)
+ {
+ if(val<=0x27ff)
+ {
+ rvb[core].StartAddr=rvb[core].CurrAddr=0;
+ }
+ else
+ {
+ rvb[core].StartAddr=val;
+ rvb[core].CurrAddr=rvb[core].StartAddr;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// DRY LEFT/RIGHT per voice switches
+////////////////////////////////////////////////////////////////////////
+
+void VolumeOn(int start,int end,unsigned short val,int iRight) // VOLUME ON PSX COMMAND
+{
+ int ch;
+
+ for(ch=start;ch<end;ch++,val>>=1) // loop channels
+ {
+ if(val&1) // -> reverb on/off
+ {
+ if(iRight) s_chan[ch].bVolumeR=1;
+ else s_chan[ch].bVolumeL=1;
+ }
+ else
+ {
+ if(iRight) s_chan[ch].bVolumeR=0;
+ else s_chan[ch].bVolumeL=0;
+ }
+ }
+}
+
+
diff --git a/plugins/ao/eng_psf/peops2/regs.h b/plugins/ao/eng_psf/peops2/regs.h
new file mode 100644
index 00000000..2cacafe1
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/regs.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ regs.h - description
+ -------------------
+ begin : Wed May 15 2002
+ copyright : (C) 2002 by Pete Bernert
+ email : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+
+void SoundOn(int start,int end,unsigned short val);
+void SoundOff(int start,int end,unsigned short val);
+void VolumeOn(int start,int end,unsigned short val,int iRight);
+void FModOn(int start,int end,unsigned short val);
+void NoiseOn(int start,int end,unsigned short val);
+void SetVolumeL(unsigned char ch,short vol);
+void SetVolumeR(unsigned char ch,short vol);
+void SetPitch(int ch,unsigned short val);
+void ReverbOn(int start,int end,unsigned short val,int iRight);
+void SetReverbAddr(int core);
+
+EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val);
+
diff --git a/plugins/ao/eng_psf/peops2/reverb.h b/plugins/ao/eng_psf/peops2/reverb.h
new file mode 100755
index 00000000..5305030c
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/reverb.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ reverb.h - description
+ -------------------
+ begin : Wed May 15 2002
+ copyright : (C) 2002 by Pete Bernert
+ email : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+
+INLINE void StartREVERB(int ch);
+INLINE void StoreREVERB(int ch,int ns);
+
diff --git a/plugins/ao/eng_psf/peops2/reverb2.c b/plugins/ao/eng_psf/peops2/reverb2.c
new file mode 100644
index 00000000..da37ef90
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/reverb2.c
@@ -0,0 +1,420 @@
+/***************************************************************************
+ reverb.c - description
+ -------------------
+ begin : Wed May 15 2002
+ copyright : (C) 2002 by Pete Bernert
+ email : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed to SPU2 functionality
+//
+// 2003/01/19 - Pete
+// - added Neill's reverb (see at the end of file)
+//
+// 2002/12/26 - Pete
+// - adjusted reverb handling
+//
+// 2002/08/14 - Pete
+// - added extra reverb
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_REVERB
+
+// will be included from spu.c
+#ifdef _IN_SPU
+
+////////////////////////////////////////////////////////////////////////
+// globals
+////////////////////////////////////////////////////////////////////////
+
+// REVERB info and timing vars...
+
+int * sRVBPlay[2];
+int * sRVBEnd[2];
+int * sRVBStart[2];
+
+////////////////////////////////////////////////////////////////////////
+// START REVERB
+////////////////////////////////////////////////////////////////////////
+
+INLINE void StartREVERB(int ch)
+{
+ int core=ch/24;
+
+ if((s_chan[ch].bReverbL || s_chan[ch].bReverbR) && (spuCtrl2[core]&0x80)) // reverb possible?
+ {
+ if(iUseReverb==1) s_chan[ch].bRVBActive=1;
+ }
+ else s_chan[ch].bRVBActive=0; // else -> no reverb
+}
+
+////////////////////////////////////////////////////////////////////////
+// HELPER FOR NEILL'S REVERB: re-inits our reverb mixing buf
+////////////////////////////////////////////////////////////////////////
+
+INLINE void InitREVERB(void)
+{
+ if(iUseReverb==1)
+ {
+ memset(sRVBStart[0],0,NSSIZE*2*4);
+ memset(sRVBStart[1],0,NSSIZE*2*4);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// STORE REVERB
+////////////////////////////////////////////////////////////////////////
+
+INLINE void StoreREVERB(int ch,int ns)
+{
+ int core=ch/24;
+
+ if(iUseReverb==0) return;
+ else
+ if(iUseReverb==1) // -------------------------------- // Neil's reverb
+ {
+ const int iRxl=(s_chan[ch].sval*s_chan[ch].iLeftVolume*s_chan[ch].bReverbL)/0x4000;
+ const int iRxr=(s_chan[ch].sval*s_chan[ch].iRightVolume*s_chan[ch].bReverbR)/0x4000;
+
+ ns<<=1;
+
+ *(sRVBStart[core]+ns) +=iRxl; // -> we mix all active reverb channels into an extra buffer
+ *(sRVBStart[core]+ns+1)+=iRxr;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE int g_buffer(int iOff,int core) // get_buffer content helper: takes care about wraps
+{
+ short * p=(short *)spuMem;
+ iOff=(iOff)+rvb[core].CurrAddr;
+ while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1));
+ while(iOff<rvb[core].StartAddr) iOff=rvb[core].EndAddr-(rvb[core].StartAddr-iOff);
+ return (int)*(p+iOff);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE void s_buffer(int iOff,int iVal,int core) // set_buffer content helper: takes care about wraps and clipping
+{
+ short * p=(short *)spuMem;
+ iOff=(iOff)+rvb[core].CurrAddr;
+ while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1));
+ while(iOff<rvb[core].StartAddr) iOff=rvb[core].EndAddr-(rvb[core].StartAddr-iOff);
+ if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;
+ *(p+iOff)=(short)iVal;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE void s_buffer1(int iOff,int iVal,int core) // set_buffer (+1 sample) content helper: takes care about wraps and clipping
+{
+ short * p=(short *)spuMem;
+ iOff=(iOff)+rvb[core].CurrAddr+1;
+ while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1));
+ while(iOff<rvb[core].StartAddr) iOff=rvb[core].EndAddr-(rvb[core].StartAddr-iOff);
+ if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;
+ *(p+iOff)=(short)iVal;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE int MixREVERBLeft(int ns,int core)
+{
+ if(iUseReverb==1)
+ {
+ if(!rvb[core].StartAddr || !rvb[core].EndAddr ||
+ rvb[core].StartAddr>=rvb[core].EndAddr) // reverb is off
+ {
+ rvb[core].iLastRVBLeft=rvb[core].iLastRVBRight=rvb[core].iRVBLeft=rvb[core].iRVBRight=0;
+ return 0;
+ }
+
+ rvb[core].iCnt++;
+
+ if(rvb[core].iCnt&1) // we work on every second left value: downsample to 22 khz
+ {
+ if((spuCtrl2[core]&0x80)) // -> reverb on? oki
+ {
+ int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1;
+
+ const int INPUT_SAMPLE_L=*(sRVBStart[core]+(ns<<1));
+ const int INPUT_SAMPLE_R=*(sRVBStart[core]+(ns<<1)+1);
+
+ const int IIR_INPUT_A0 = (g_buffer(rvb[core].IIR_SRC_A0,core) * rvb[core].IIR_COEF)/32768L + (INPUT_SAMPLE_L * rvb[core].IN_COEF_L)/32768L;
+ const int IIR_INPUT_A1 = (g_buffer(rvb[core].IIR_SRC_A1,core) * rvb[core].IIR_COEF)/32768L + (INPUT_SAMPLE_R * rvb[core].IN_COEF_R)/32768L;
+ const int IIR_INPUT_B0 = (g_buffer(rvb[core].IIR_SRC_B0,core) * rvb[core].IIR_COEF)/32768L + (INPUT_SAMPLE_L * rvb[core].IN_COEF_L)/32768L;
+ const int IIR_INPUT_B1 = (g_buffer(rvb[core].IIR_SRC_B1,core) * rvb[core].IIR_COEF)/32768L + (INPUT_SAMPLE_R * rvb[core].IN_COEF_R)/32768L;
+
+ const int IIR_A0 = (IIR_INPUT_A0 * rvb[core].IIR_ALPHA)/32768L + (g_buffer(rvb[core].IIR_DEST_A0,core) * (32768L - rvb[core].IIR_ALPHA))/32768L;
+ const int IIR_A1 = (IIR_INPUT_A1 * rvb[core].IIR_ALPHA)/32768L + (g_buffer(rvb[core].IIR_DEST_A1,core) * (32768L - rvb[core].IIR_ALPHA))/32768L;
+ const int IIR_B0 = (IIR_INPUT_B0 * rvb[core].IIR_ALPHA)/32768L + (g_buffer(rvb[core].IIR_DEST_B0,core) * (32768L - rvb[core].IIR_ALPHA))/32768L;
+ const int IIR_B1 = (IIR_INPUT_B1 * rvb[core].IIR_ALPHA)/32768L + (g_buffer(rvb[core].IIR_DEST_B1,core) * (32768L - rvb[core].IIR_ALPHA))/32768L;
+
+ s_buffer1(rvb[core].IIR_DEST_A0, IIR_A0,core);
+ s_buffer1(rvb[core].IIR_DEST_A1, IIR_A1,core);
+ s_buffer1(rvb[core].IIR_DEST_B0, IIR_B0,core);
+ s_buffer1(rvb[core].IIR_DEST_B1, IIR_B1,core);
+
+ ACC0 = (g_buffer(rvb[core].ACC_SRC_A0,core) * rvb[core].ACC_COEF_A)/32768L +
+ (g_buffer(rvb[core].ACC_SRC_B0,core) * rvb[core].ACC_COEF_B)/32768L +
+ (g_buffer(rvb[core].ACC_SRC_C0,core) * rvb[core].ACC_COEF_C)/32768L +
+ (g_buffer(rvb[core].ACC_SRC_D0,core) * rvb[core].ACC_COEF_D)/32768L;
+ ACC1 = (g_buffer(rvb[core].ACC_SRC_A1,core) * rvb[core].ACC_COEF_A)/32768L +
+ (g_buffer(rvb[core].ACC_SRC_B1,core) * rvb[core].ACC_COEF_B)/32768L +
+ (g_buffer(rvb[core].ACC_SRC_C1,core) * rvb[core].ACC_COEF_C)/32768L +
+ (g_buffer(rvb[core].ACC_SRC_D1,core) * rvb[core].ACC_COEF_D)/32768L;
+
+ FB_A0 = g_buffer(rvb[core].MIX_DEST_A0 - rvb[core].FB_SRC_A,core);
+ FB_A1 = g_buffer(rvb[core].MIX_DEST_A1 - rvb[core].FB_SRC_A,core);
+ FB_B0 = g_buffer(rvb[core].MIX_DEST_B0 - rvb[core].FB_SRC_B,core);
+ FB_B1 = g_buffer(rvb[core].MIX_DEST_B1 - rvb[core].FB_SRC_B,core);
+
+ s_buffer(rvb[core].MIX_DEST_A0, ACC0 - (FB_A0 * rvb[core].FB_ALPHA)/32768L,core);
+ s_buffer(rvb[core].MIX_DEST_A1, ACC1 - (FB_A1 * rvb[core].FB_ALPHA)/32768L,core);
+
+ s_buffer(rvb[core].MIX_DEST_B0, (rvb[core].FB_ALPHA * ACC0)/32768L - (FB_A0 * (int)(rvb[core].FB_ALPHA^0xFFFF8000))/32768L - (FB_B0 * rvb[core].FB_X)/32768L,core);
+ s_buffer(rvb[core].MIX_DEST_B1, (rvb[core].FB_ALPHA * ACC1)/32768L - (FB_A1 * (int)(rvb[core].FB_ALPHA^0xFFFF8000))/32768L - (FB_B1 * rvb[core].FB_X)/32768L,core);
+
+ rvb[core].iLastRVBLeft = rvb[core].iRVBLeft;
+ rvb[core].iLastRVBRight = rvb[core].iRVBRight;
+
+ rvb[core].iRVBLeft = (g_buffer(rvb[core].MIX_DEST_A0,core)+g_buffer(rvb[core].MIX_DEST_B0,core))/3;
+ rvb[core].iRVBRight = (g_buffer(rvb[core].MIX_DEST_A1,core)+g_buffer(rvb[core].MIX_DEST_B1,core))/3;
+
+ rvb[core].iRVBLeft = (rvb[core].iRVBLeft * rvb[core].VolLeft) / 0x4000;
+ rvb[core].iRVBRight = (rvb[core].iRVBRight * rvb[core].VolRight) / 0x4000;
+
+ rvb[core].CurrAddr++;
+ if(rvb[core].CurrAddr>rvb[core].EndAddr) rvb[core].CurrAddr=rvb[core].StartAddr;
+
+ return rvb[core].iLastRVBLeft+(rvb[core].iRVBLeft-rvb[core].iLastRVBLeft)/2;
+ }
+ else // -> reverb off
+ {
+ rvb[core].iLastRVBLeft=rvb[core].iLastRVBRight=rvb[core].iRVBLeft=rvb[core].iRVBRight=0;
+ }
+
+ rvb[core].CurrAddr++;
+ if(rvb[core].CurrAddr>rvb[core].EndAddr) rvb[core].CurrAddr=rvb[core].StartAddr;
+ }
+
+ return rvb[core].iLastRVBLeft;
+ }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+INLINE int MixREVERBRight(int core)
+{
+ if(iUseReverb==1) // Neill's reverb:
+ {
+ int i=rvb[core].iLastRVBRight+(rvb[core].iRVBRight-rvb[core].iLastRVBRight)/2;
+ rvb[core].iLastRVBRight=rvb[core].iRVBRight;
+ return i; // -> just return the last right reverb val (little bit scaled by the previous right val)
+ }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+#endif
+
+/*
+-----------------------------------------------------------------------------
+PSX reverb hardware notes
+by Neill Corlett
+-----------------------------------------------------------------------------
+
+Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway
+yadda yadda.
+
+-----------------------------------------------------------------------------
+
+Basics
+------
+
+- The reverb buffer is 22khz 16-bit mono PCM.
+- It starts at the reverb address given by 1DA2, extends to
+ the end of sound RAM, and wraps back to the 1DA2 address.
+
+Setting the address at 1DA2 resets the current reverb work address.
+
+This work address ALWAYS increments every 1/22050 sec., regardless of
+whether reverb is enabled (bit 7 of 1DAA set).
+
+And the contents of the reverb buffer ALWAYS play, scaled by the
+"reverberation depth left/right" volumes (1D84/1D86).
+(which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0)
+
+-----------------------------------------------------------------------------
+
+Register names
+--------------
+
+These are probably not their real names.
+These are probably not even correct names.
+We will use them anyway, because we can.
+
+1DC0: FB_SRC_A (offset)
+1DC2: FB_SRC_B (offset)
+1DC4: IIR_ALPHA (coef.)
+1DC6: ACC_COEF_A (coef.)
+1DC8: ACC_COEF_B (coef.)
+1DCA: ACC_COEF_C (coef.)
+1DCC: ACC_COEF_D (coef.)
+1DCE: IIR_COEF (coef.)
+1DD0: FB_ALPHA (coef.)
+1DD2: FB_X (coef.)
+1DD4: IIR_DEST_A0 (offset)
+1DD6: IIR_DEST_A1 (offset)
+1DD8: ACC_SRC_A0 (offset)
+1DDA: ACC_SRC_A1 (offset)
+1DDC: ACC_SRC_B0 (offset)
+1DDE: ACC_SRC_B1 (offset)
+1DE0: IIR_SRC_A0 (offset)
+1DE2: IIR_SRC_A1 (offset)
+1DE4: IIR_DEST_B0 (offset)
+1DE6: IIR_DEST_B1 (offset)
+1DE8: ACC_SRC_C0 (offset)
+1DEA: ACC_SRC_C1 (offset)
+1DEC: ACC_SRC_D0 (offset)
+1DEE: ACC_SRC_D1 (offset)
+1DF0: IIR_SRC_B1 (offset)
+1DF2: IIR_SRC_B0 (offset)
+1DF4: MIX_DEST_A0 (offset)
+1DF6: MIX_DEST_A1 (offset)
+1DF8: MIX_DEST_B0 (offset)
+1DFA: MIX_DEST_B1 (offset)
+1DFC: IN_COEF_L (coef.)
+1DFE: IN_COEF_R (coef.)
+
+The coefficients are signed fractional values.
+-32768 would be -1.0
+ 32768 would be 1.0 (if it were possible... the highest is of course 32767)
+
+The offsets are (byte/8) offsets into the reverb buffer.
+i.e. you multiply them by 8, you get byte offsets.
+You can also think of them as (samples/4) offsets.
+They appear to be signed. They can be negative.
+None of the documented presets make them negative, though.
+
+Yes, 1DF0 and 1DF2 appear to be backwards. Not a typo.
+
+-----------------------------------------------------------------------------
+
+What it does
+------------
+
+We take all reverb sources:
+- regular channels that have the reverb bit on
+- cd and external sources, if their reverb bits are on
+and mix them into one stereo 44100hz signal.
+
+Lowpass/downsample that to 22050hz. The PSX uses a proper bandlimiting
+algorithm here, but I haven't figured out the hysterically exact specifics.
+I use an 8-tap filter with these coefficients, which are nice but probably
+not the real ones:
+
+0.037828187894
+0.157538631280
+0.321159685278
+0.449322115345
+0.449322115345
+0.321159685278
+0.157538631280
+0.037828187894
+
+So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz.
+
+* IN MY EMULATION, I divide these by 2 to make it clip less.
+ (and of course the L/R output coefficients are adjusted to compensate)
+ The real thing appears to not do this.
+
+At every 22050hz tick:
+- If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb
+ steady-state algorithm described below
+- AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer
+ (This part may not be exactly right and I guessed at the coefs. TODO: check later.)
+ L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0])
+ R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1])
+- Advance the current buffer position by 1 sample
+
+The wet out L and R are then upsampled to 44100hz and played at the
+"reverberation depth left/right" (1D84/1D86) volume, independent of the main
+volume.
+
+-----------------------------------------------------------------------------
+
+Reverb steady-state
+-------------------
+
+The reverb steady-state algorithm is fairly clever, and of course by
+"clever" I mean "batshit insane".
+
+buffer[x] is relative to the current buffer position, not the beginning of
+the buffer. Note that all buffer offsets must wrap around so they're
+contained within the reverb work area.
+
+Clipping is performed at the end... maybe also sooner, but definitely at
+the end.
+
+IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
+IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
+IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
+IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
+
+IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA);
+IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA);
+IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA);
+IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA);
+
+buffer[IIR_DEST_A0 + 1sample] = IIR_A0;
+buffer[IIR_DEST_A1 + 1sample] = IIR_A1;
+buffer[IIR_DEST_B0 + 1sample] = IIR_B0;
+buffer[IIR_DEST_B1 + 1sample] = IIR_B1;
+
+ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A +
+ buffer[ACC_SRC_B0] * ACC_COEF_B +
+ buffer[ACC_SRC_C0] * ACC_COEF_C +
+ buffer[ACC_SRC_D0] * ACC_COEF_D;
+ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A +
+ buffer[ACC_SRC_B1] * ACC_COEF_B +
+ buffer[ACC_SRC_C1] * ACC_COEF_C +
+ buffer[ACC_SRC_D1] * ACC_COEF_D;
+
+FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A];
+FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A];
+FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B];
+FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B];
+
+buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA;
+buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA;
+buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X;
+buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X;
+
+-----------------------------------------------------------------------------
+*/
+
diff --git a/plugins/ao/eng_psf/peops2/spu.h b/plugins/ao/eng_psf/peops2/spu.h
new file mode 100644
index 00000000..89e2e900
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/spu.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ spu.h - description
+ -------------------
+ begin : Wed May 15 2002
+ copyright : (C) 2002 by Pete Bernert
+ email : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+
+void SetupTimer(void);
+void RemoveTimer(void);
+EXPORT_GCC void CALLBACK SPU2playADPCMchannel(xa_decode_t *xap);
+
+EXPORT_GCC long CALLBACK SPU2init(void);
+EXPORT_GCC long CALLBACK SPU2open(void *pDsp);
+EXPORT_GCC void CALLBACK SPU2async(unsigned long cycle);
+EXPORT_GCC void CALLBACK SPU2close(void);
+
diff --git a/plugins/ao/eng_psf/peops2/spu2.c b/plugins/ao/eng_psf/peops2/spu2.c
new file mode 100644
index 00000000..1dae1e4a
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/spu2.c
@@ -0,0 +1,1013 @@
+/***************************************************************************
+ spu.c - description
+ -------------------
+ begin : Wed May 15 2002
+ copyright : (C) 2002 by Pete Bernert
+ email : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2005/08/29 - Pete
+// - changed to 48Khz output
+//
+// 2004/12/25 - Pete
+// - inc'd version for pcsx2-0.7
+//
+// 2004/04/18 - Pete
+// - changed all kind of things in the plugin
+//
+// 2004/04/04 - Pete
+// - changed plugin to emulate PS2 spu
+//
+// 2003/04/07 - Eric
+// - adjusted cubic interpolation algorithm
+//
+// 2003/03/16 - Eric
+// - added cubic interpolation
+//
+// 2003/03/01 - linuzappz
+// - libraryName changes using ALSA
+//
+// 2003/02/28 - Pete
+// - added option for type of interpolation
+// - adjusted spu irqs again (Thousant Arms, Valkyrie Profile)
+// - added MONO support for MSWindows DirectSound
+//
+// 2003/02/20 - kode54
+// - amended interpolation code, goto GOON could skip initialization of gpos and cause segfault
+//
+// 2003/02/19 - kode54
+// - moved SPU IRQ handler and changed sample flag processing
+//
+// 2003/02/18 - kode54
+// - moved ADSR calculation outside of the sample decode loop, somehow I doubt that
+// ADSR timing is relative to the frequency at which a sample is played... I guess
+// this remains to be seen, and I don't know whether ADSR is applied to noise channels...
+//
+// 2003/02/09 - kode54
+// - one-shot samples now process the end block before stopping
+// - in light of removing fmod hack, now processing ADSR on frequency channel as well
+//
+// 2003/02/08 - kode54
+// - replaced easy interpolation with gaussian
+// - removed fmod averaging hack
+// - changed .sinc to be updated from .iRawPitch, no idea why it wasn't done this way already (<- Pete: because I sometimes fail to see the obvious, haharhar :)
+//
+// 2003/02/08 - linuzappz
+// - small bugfix for one usleep that was 1 instead of 1000
+// - added iDisStereo for no stereo (Linux)
+//
+// 2003/01/22 - Pete
+// - added easy interpolation & small noise adjustments
+//
+// 2003/01/19 - Pete
+// - added Neill's reverb
+//
+// 2003/01/12 - Pete
+// - added recording window handlers
+//
+// 2003/01/06 - Pete
+// - added Neill's ADSR timings
+//
+// 2002/12/28 - Pete
+// - adjusted spu irq handling, fmod handling and loop handling
+//
+// 2002/08/14 - Pete
+// - added extra reverb
+//
+// 2002/06/08 - linuzappz
+// - SPUupdate changed for SPUasync
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_SPU
+
+#include "../peops2/externals.h"
+#include "../peops2/regs.h"
+#include "../peops2/dma.h"
+
+////////////////////////////////////////////////////////////////////////
+// globals
+////////////////////////////////////////////////////////////////////////
+
+// psx buffer / addresses
+
+unsigned short regArea[32*1024];
+unsigned short spuMem[1*1024*1024];
+unsigned char * spuMemC;
+unsigned char * pSpuIrq[2];
+unsigned char * pSpuBuffer;
+
+// user settings
+
+int iUseXA=0;
+int iVolume=3;
+int iXAPitch=1;
+int iUseTimer=2;
+int iSPUIRQWait=1;
+int iDebugMode=0;
+int iRecordMode=0;
+int iUseReverb=1;
+int iUseInterpolation=2;
+
+// MAIN infos struct for each channel
+
+SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling)
+REVERBInfo rvb[2];
+
+unsigned long dwNoiseVal=1; // global noise generator
+
+unsigned short spuCtrl2[2]; // some vars to store psx reg infos
+unsigned short spuStat2[2];
+unsigned long spuIrq2[2];
+unsigned long spuAddr2[2]; // address into spu mem
+unsigned long spuRvbAddr2[2];
+unsigned long spuRvbAEnd2[2];
+int bEndThread=0; // thread handlers
+int bThreadEnded=0;
+int bSpuInit=0;
+int bSPUIsOpen=0;
+
+unsigned long dwNewChannel2[2]; // flags for faster testing, if new channel starts
+unsigned long dwEndChannel2[2];
+
+// UNUSED IN PS2 YET
+void (CALLBACK *irqCallback)(void)=0; // func of main emu, called on spu irq
+void (CALLBACK *cddavCallback)(unsigned short,unsigned short)=0;
+
+// certain globals (were local before, but with the new timeproc I need em global)
+
+const int f[5][2] = { { 0, 0 },
+ { 60, 0 },
+ { 115, -52 },
+ { 98, -55 },
+ { 122, -60 } };
+int SSumR[NSSIZE];
+int SSumL[NSSIZE];
+int iCycle=0;
+short * pS;
+
+static int lastch=-1; // last channel processed on spu irq in timer mode
+static int lastns=0; // last ns pos
+static int iSecureStart=0; // secure start counter
+
+extern void ps2_update(unsigned char *samples, long lBytes);
+
+////////////////////////////////////////////////////////////////////////
+// CODE AREA
+////////////////////////////////////////////////////////////////////////
+
+// dirty inline func includes
+
+#include "reverb2.c"
+#include "adsr2.c"
+
+////////////////////////////////////////////////////////////////////////
+// helpers for simple interpolation
+
+//
+// easy interpolation on upsampling, no special filter, just "Pete's common sense" tm
+//
+// instead of having n equal sample values in a row like:
+// ____
+// |____
+//
+// we compare the current delta change with the next delta change.
+//
+// if curr_delta is positive,
+//
+// - and next delta is smaller (or changing direction):
+// \.
+// -__
+//
+// - and next delta significant (at least twice) bigger:
+// --_
+// \.
+//
+// - and next delta is nearly same:
+// \.
+// \.
+//
+//
+// if curr_delta is negative,
+//
+// - and next delta is smaller (or changing direction):
+// _--
+// /
+//
+// - and next delta significant (at least twice) bigger:
+// /
+// __-
+//
+// - and next delta is nearly same:
+// /
+// /
+//
+
+
+INLINE void InterpolateUp(int ch)
+{
+ if(s_chan[ch].SB[32]==1) // flag == 1? calc step and set flag... and don't change the value in this pass
+ {
+ const int id1=s_chan[ch].SB[30]-s_chan[ch].SB[29]; // curr delta to next val
+ const int id2=s_chan[ch].SB[31]-s_chan[ch].SB[30]; // and next delta to next-next val :)
+
+ s_chan[ch].SB[32]=0;
+
+ if(id1>0) // curr delta positive
+ {
+ if(id2<id1)
+ {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
+ else
+ if(id2<(id1<<1))
+ s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
+ else
+ s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L;
+ }
+ else // curr delta negative
+ {
+ if(id2>id1)
+ {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
+ else
+ if(id2>(id1<<1))
+ s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
+ else
+ s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L;
+ }
+ }
+ else
+ if(s_chan[ch].SB[32]==2) // flag 1: calc step and set flag... and don't change the value in this pass
+ {
+ s_chan[ch].SB[32]=0;
+
+ s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L;
+ if(s_chan[ch].sinc<=0x8000)
+ s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1));
+ else s_chan[ch].SB[29]+=s_chan[ch].SB[28];
+ }
+ else // no flags? add bigger val (if possible), calc smaller step, set flag1
+ s_chan[ch].SB[29]+=s_chan[ch].SB[28];
+}
+
+//
+// even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm
+//
+
+INLINE void InterpolateDown(int ch)
+{
+ if(s_chan[ch].sinc>=0x20000L) // we would skip at least one val?
+ {
+ s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight
+ if(s_chan[ch].sinc>=0x30000L) // we would skip even more vals?
+ s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// helpers for gauss interpolation
+
+#define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos])
+#define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3])
+
+#include "gauss_i.h"
+
+////////////////////////////////////////////////////////////////////////
+
+//#include "xa.c"
+
+////////////////////////////////////////////////////////////////////////
+// START SOUND... called by main thread to setup a new sound on a channel
+////////////////////////////////////////////////////////////////////////
+
+INLINE void StartSound(int ch)
+{
+ dwNewChannel2[ch/24]&=~(1<<(ch%24)); // clear new channel bit
+ dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit
+
+ StartADSR(ch);
+ StartREVERB(ch);
+
+ s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start
+
+ s_chan[ch].s_1=0; // init mixing vars
+ s_chan[ch].s_2=0;
+ s_chan[ch].iSBPos=28;
+
+ s_chan[ch].bNew=0; // init channel flags
+ s_chan[ch].bStop=0;
+ s_chan[ch].bOn=1;
+
+ s_chan[ch].SB[29]=0; // init our interpolation helpers
+ s_chan[ch].SB[30]=0;
+
+ if(iUseInterpolation>=2) // gauss interpolation?
+ {s_chan[ch].spos=0x30000L;s_chan[ch].SB[28]=0;} // -> start with more decoding
+ else {s_chan[ch].spos=0x10000L;s_chan[ch].SB[31]=0;} // -> no/simple interpolation starts with one 44100 decoding
+}
+
+////////////////////////////////////////////////////////////////////////
+// MAIN SPU FUNCTION
+// here is the main job handler... thread, timer or direct func call
+// basically the whole sound processing is done in this fat func!
+////////////////////////////////////////////////////////////////////////
+
+static u32 sampcount;
+static u32 decaybegin;
+static u32 decayend;
+
+// Counting to 65536 results in full volume offage.
+void setlength2(s32 stop, s32 fade)
+{
+ if(stop==~0)
+ {
+ decaybegin=~0;
+ }
+ else
+ {
+ stop=(stop*441)/10;
+ fade=(fade*441)/10;
+
+ decaybegin=stop;
+ decayend=stop+fade;
+ }
+}
+// 5 ms waiting phase, if buffer is full and no new sound has to get started
+// .. can be made smaller (smallest val: 1 ms), but bigger waits give
+// better performance
+
+#define PAUSE_W 5
+#define PAUSE_L 5000
+
+////////////////////////////////////////////////////////////////////////
+
+int iSpuAsyncWait=0;
+
+static void *MAINThread(int samp2run)
+{
+ int s_1,s_2,fa,voldiv=iVolume;
+ unsigned char * start;unsigned int nSample;
+ int ch,predict_nr,shift_factor,flags,d,d2,s;
+ int gpos,bIRQReturn=0;
+
+// while(!bEndThread) // until we are shutting down
+ {
+ //--------------------------------------------------//
+ // ok, at the beginning we are looking if there is
+ // enuff free place in the dsound/oss buffer to
+ // fill in new data, or if there is a new channel to start.
+ // if not, we wait (thread) or return (timer/spuasync)
+ // until enuff free place is available/a new channel gets
+ // started
+
+ if(dwNewChannel2[0] || dwNewChannel2[1]) // new channel should start immedately?
+ { // (at least one bit 0 ... MAXCHANNEL is set?)
+ iSecureStart++; // -> set iSecure
+ if(iSecureStart>5) iSecureStart=0; // (if it is set 5 times - that means on 5 tries a new samples has been started - in a row, we will reset it, to give the sound update a chance)
+ }
+ else iSecureStart=0; // 0: no new channel should start
+
+/* if (!iSecureStart)
+ {
+ iSecureStart=0; // reset secure
+ return;
+ }*/
+
+#if 0
+ while(!iSecureStart && !bEndThread) // && // no new start? no thread end?
+// (SoundGetBytesBuffered()>TESTSIZE)) // and still enuff data in sound buffer?
+ {
+ iSecureStart=0; // reset secure
+
+ if(iUseTimer) return 0; // linux no-thread mode? bye
+
+ if(dwNewChannel2[0] || dwNewChannel2[1])
+ iSecureStart=1; // if a new channel kicks in (or, of course, sound buffer runs low), we will leave the loop
+ }
+#endif
+
+ //--------------------------------------------------// continue from irq handling in timer mode?
+
+ if(lastch>=0) // will be -1 if no continue is pending
+ {
+ ch=lastch; lastch=-1; // -> setup all kind of vars to continue
+ goto GOON; // -> directly jump to the continue point
+ }
+
+ //--------------------------------------------------//
+ //- main channel loop -//
+ //--------------------------------------------------//
+ {
+ for(ch=0;ch<MAXCHAN;ch++) // loop em all... we will collect 1 ms of sound of each playing channel
+ {
+ if(s_chan[ch].bNew) StartSound(ch); // start new sound
+ if(!s_chan[ch].bOn) continue; // channel not playing? next
+
+ if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq) // new psx frequency?
+ {
+ s_chan[ch].iUsedFreq=s_chan[ch].iActFreq; // -> take it and calc steps
+ s_chan[ch].sinc=s_chan[ch].iRawPitch<<4;
+ if(!s_chan[ch].sinc) s_chan[ch].sinc=1;
+ if(iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simle imterpolation mode: set flag
+ }
+// ns=0;
+// while(ns<NSSIZE) // loop until 1 ms of data is reached
+ {
+ while(s_chan[ch].spos>=0x10000L)
+ {
+ if(s_chan[ch].iSBPos==28) // 28 reached?
+ {
+ start=s_chan[ch].pCurr; // set up the current pos
+
+ if (start == (unsigned char*)-1) // special "stop" sign
+ {
+ s_chan[ch].bOn=0; // -> turn everything off
+ s_chan[ch].ADSRX.lVolume=0;
+ s_chan[ch].ADSRX.EnvelopeVol=0;
+ goto ENDX; // -> and done for this channel
+ }
+
+ s_chan[ch].iSBPos=0;
+
+ //////////////////////////////////////////// spu irq handler here? mmm... do it later
+
+ s_1=s_chan[ch].s_1;
+ s_2=s_chan[ch].s_2;
+
+ predict_nr=(int)*start;start++;
+ shift_factor=predict_nr&0xf;
+ predict_nr >>= 4;
+ flags=(int)*start;start++;
+
+ // -------------------------------------- //
+
+ for (nSample=0;nSample<28;start++)
+ {
+ d=(int)*start;
+ s=((d&0xf)<<12);
+ if(s&0x8000) s|=0xffff0000;
+
+ fa=(s >> shift_factor);
+ fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
+ s_2=s_1;s_1=fa;
+ s=((d & 0xf0) << 8);
+
+ s_chan[ch].SB[nSample++]=fa;
+
+ if(s&0x8000) s|=0xffff0000;
+ fa=(s>>shift_factor);
+ fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
+ s_2=s_1;s_1=fa;
+
+ s_chan[ch].SB[nSample++]=fa;
+ }
+
+ //////////////////////////////////////////// irq check
+
+ if(spuCtrl2[ch/24]&0x40) // some irq active?
+ {
+ if((pSpuIrq[ch/24] > start-16 && // irq address reached?
+ pSpuIrq[ch/24] <= start) ||
+ ((flags&1) && // special: irq on looping addr, when stop/loop flag is set
+ (pSpuIrq[ch/24] > s_chan[ch].pLoop-16 &&
+ pSpuIrq[ch/24] <= s_chan[ch].pLoop)))
+ {
+ s_chan[ch].iIrqDone=1; // -> debug flag
+
+ if(irqCallback) irqCallback(); // -> call main emu (not supported in SPU2 right now)
+ else
+ {
+ if(ch<24) InterruptDMA4(); // -> let's see what is happening if we call our irqs instead ;)
+ else InterruptDMA7();
+ }
+
+ if(iSPUIRQWait) // -> option: wait after irq for main emu
+ {
+ iSpuAsyncWait=1;
+ bIRQReturn=1;
+ }
+ }
+ }
+
+ //////////////////////////////////////////// flag handler
+
+ if((flags&4) && (!s_chan[ch].bIgnoreLoop))
+ s_chan[ch].pLoop=start-16; // loop adress
+
+ if(flags&1) // 1: stop/loop
+ {
+ dwEndChannel2[ch/24]|=(1<<(ch%24));
+
+ // We play this block out first...
+ //if(!(flags&2)|| s_chan[ch].pLoop==NULL)
+ // 1+2: do loop... otherwise: stop
+ if(flags!=3 || s_chan[ch].pLoop==NULL) // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example)
+ { // and checking if pLoop is set avoids crashes, yeah
+ start = (unsigned char*)-1;
+ }
+ else
+ {
+ start = s_chan[ch].pLoop;
+ }
+ }
+
+ s_chan[ch].pCurr=start; // store values for next cycle
+ s_chan[ch].s_1=s_1;
+ s_chan[ch].s_2=s_2;
+
+ ////////////////////////////////////////////
+
+ if(bIRQReturn) // special return for "spu irq - wait for cpu action"
+ {
+ bIRQReturn=0;
+ {
+ lastch=ch;
+// lastns=ns; // changemeback
+
+ return;
+ }
+ }
+
+ ////////////////////////////////////////////
+
+GOON: ;
+
+ }
+
+ fa=s_chan[ch].SB[s_chan[ch].iSBPos++]; // get sample data
+
+// if((spuCtrl2[ch/24]&0x4000)==0) fa=0; // muted?
+// else // else adjust
+ {
+ if(fa>32767L) fa=32767L;
+ if(fa<-32767L) fa=-32767L;
+ }
+
+ if(iUseInterpolation>=2) // gauss/cubic interpolation
+ {
+ gpos = s_chan[ch].SB[28];
+ gval0 = fa;
+ gpos = (gpos+1) & 3;
+ s_chan[ch].SB[28] = gpos;
+ }
+ else
+ if(iUseInterpolation==1) // simple interpolation
+ {
+ s_chan[ch].SB[28] = 0;
+ s_chan[ch].SB[29] = s_chan[ch].SB[30]; // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour'
+ s_chan[ch].SB[30] = s_chan[ch].SB[31];
+ s_chan[ch].SB[31] = fa;
+ s_chan[ch].SB[32] = 1; // -> flag: calc new interolation
+ }
+ else s_chan[ch].SB[29]=fa; // no interpolation
+
+ s_chan[ch].spos -= 0x10000L;
+ }
+
+ ////////////////////////////////////////////////
+ // noise handler... just produces some noise data
+ // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used...
+ // and sometimes the noise will be used as fmod modulation... pfff
+
+ if(s_chan[ch].bNoise)
+ {
+ if((dwNoiseVal<<=1)&0x80000000L)
+ {
+ dwNoiseVal^=0x0040001L;
+ fa=((dwNoiseVal>>2)&0x7fff);
+ fa=-fa;
+ }
+ else fa=(dwNoiseVal>>2)&0x7fff;
+
+ // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val
+ fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl2[ch/24]&0x3f00)>>9))+1));
+ if(fa>32767L) fa=32767L;
+ if(fa<-32767L) fa=-32767L;
+ s_chan[ch].iOldNoise=fa;
+
+ if(iUseInterpolation<2) // no gauss/cubic interpolation?
+ s_chan[ch].SB[29] = fa; // -> store noise val in "current sample" slot
+ } //----------------------------------------
+ else // NO NOISE (NORMAL SAMPLE DATA) HERE
+ {//------------------------------------------//
+ if(iUseInterpolation==3) // cubic interpolation
+ {
+ long xd;
+ xd = ((s_chan[ch].spos) >> 1)+1;
+ gpos = s_chan[ch].SB[28];
+
+ fa = gval(3) - 3*gval(2) + 3*gval(1) - gval0;
+ fa *= (xd - (2<<15)) / 6;
+ fa >>= 15;
+ fa += gval(2) - gval(1) - gval(1) + gval0;
+ fa *= (xd - (1<<15)) >> 1;
+ fa >>= 15;
+ fa += gval(1) - gval0;
+ fa *= xd;
+ fa >>= 15;
+ fa = fa + gval0;
+ }
+ //------------------------------------------//
+ else
+ if(iUseInterpolation==2) // gauss interpolation
+ {
+ int vl, vr;
+ vl = (s_chan[ch].spos >> 6) & ~3;
+ gpos = s_chan[ch].SB[28];
+ vr=(gauss[vl]*gval0)&~2047;
+ vr+=(gauss[vl+1]*gval(1))&~2047;
+ vr+=(gauss[vl+2]*gval(2))&~2047;
+ vr+=(gauss[vl+3]*gval(3))&~2047;
+ fa = vr>>11;
+/*
+ vr=(gauss[vl]*gval0)>>9;
+ vr+=(gauss[vl+1]*gval(1))>>9;
+ vr+=(gauss[vl+2]*gval(2))>>9;
+ vr+=(gauss[vl+3]*gval(3))>>9;
+ fa = vr>>2;
+*/
+ }
+ //------------------------------------------//
+ else
+ if(iUseInterpolation==1) // simple interpolation
+ {
+ if(s_chan[ch].sinc<0x10000L) // -> upsampling?
+ InterpolateUp(ch); // --> interpolate up
+ else InterpolateDown(ch); // --> else down
+ fa=s_chan[ch].SB[29];
+ }
+ //------------------------------------------//
+ else fa=s_chan[ch].SB[29]; // no interpolation
+ }
+
+ s_chan[ch].sval = (MixADSR(ch) * fa) / 1023; // add adsr
+
+ if(s_chan[ch].bFMod==2) // fmod freq channel
+ {
+ int NP=s_chan[ch+1].iRawPitch;
+ double intr;
+
+ NP=((32768L+s_chan[ch].sval)*NP)/32768L; // mmm... I still need to adjust that to 1/48 khz... we will wait for the first game/demo using it to decide how to do it :)
+
+ if(NP>0x3fff) NP=0x3fff;
+ if(NP<0x1) NP=0x1;
+
+ intr = (double)48000.0f / (double)44100.0f * (double)NP;
+ NP = (UINT32)intr;
+
+ NP=(44100L*NP)/(4096L); // calc frequency
+
+ s_chan[ch+1].iActFreq=NP;
+ s_chan[ch+1].iUsedFreq=NP;
+ s_chan[ch+1].sinc=(((NP/10)<<16)/4410);
+ if(!s_chan[ch+1].sinc) s_chan[ch+1].sinc=1;
+ if(iUseInterpolation==1) // freq change in sipmle interpolation mode
+ s_chan[ch+1].SB[32]=1;
+
+// mmmm... set up freq decoding positions?
+// s_chan[ch+1].iSBPos=28;
+// s_chan[ch+1].spos=0x10000L;
+ }
+ else
+ {
+ //////////////////////////////////////////////
+ // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
+
+ if(s_chan[ch].iMute)
+ s_chan[ch].sval=0; // debug mute
+ else
+ {
+ if(s_chan[ch].bVolumeL)
+ SSumL[0]+=(s_chan[ch].sval*s_chan[ch].iLeftVolume)/0x4000L;
+ if(s_chan[ch].bVolumeR)
+ SSumR[0]+=(s_chan[ch].sval*s_chan[ch].iRightVolume)/0x4000L;
+ }
+
+ //////////////////////////////////////////////
+ // now let us store sound data for reverb
+
+ if(s_chan[ch].bRVBActive) StoreREVERB(ch,0);
+ }
+
+ ////////////////////////////////////////////////
+ // ok, go on until 1 ms data of this channel is collected
+
+ s_chan[ch].spos += s_chan[ch].sinc;
+
+ }
+ENDX: ;
+ }
+ }
+
+ //---------------------------------------------------//
+ //- here we have another 1 ms of sound data
+ //---------------------------------------------------//
+
+ ///////////////////////////////////////////////////////
+ // mix all channels (including reverb) into one buffer
+
+ SSumL[0]+=MixREVERBLeft(0,0);
+ SSumL[0]+=MixREVERBLeft(0,1);
+ SSumR[0]+=MixREVERBRight(0);
+ SSumR[0]+=MixREVERBRight(1);
+
+ d=SSumL[0]/voldiv;SSumL[0]=0;
+ d2=SSumR[0]/voldiv;SSumR[0]=0;
+
+ if(d<-32767) d=-32767;if(d>32767) d=32767;
+ if(d2<-32767) d2=-32767;if(d2>32767) d2=32767;
+
+ if(sampcount>=decaybegin)
+ {
+ s32 dmul;
+ if(decaybegin!=~0) // Is anyone REALLY going to be playing a song
+ // for 13 hours?
+ {
+ if(sampcount>=decayend)
+ {
+// ao_song_done = 1;
+ return(0);
+ }
+
+ dmul=256-(256*(sampcount-decaybegin)/(decayend-decaybegin));
+ d=(d*dmul)>>8;
+ d2=(d2*dmul)>>8;
+ }
+ }
+ sampcount++;
+
+ *pS++=d;
+ *pS++=d2;
+
+ InitREVERB();
+
+ //////////////////////////////////////////////////////
+ // feed the sound
+ // wanna have around 1/60 sec (16.666 ms) updates
+ if ((((unsigned char *)pS)-((unsigned char *)pSpuBuffer)) == (735*4))
+ {
+ ps2_update((u8*)pSpuBuffer,(u8*)pS-(u8*)pSpuBuffer);
+ pS=(short *)pSpuBuffer;
+ }
+ }
+
+ // end of big main loop...
+
+ bThreadEnded=1;
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+// SPU ASYNC... even newer epsxe func
+// 1 time every 'cycle' cycles... harhar
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2async(unsigned long cycle)
+{
+ if(iSpuAsyncWait)
+ {
+ iSpuAsyncWait++;
+ if(iSpuAsyncWait<=64) return;
+ iSpuAsyncWait=0;
+ }
+
+ MAINThread(0); // -> linux high-compat mode
+}
+
+////////////////////////////////////////////////////////////////////////
+// INIT/EXIT STUFF
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+// SPUINIT: this func will be called first by the main emu
+////////////////////////////////////////////////////////////////////////
+
+
+EXPORT_GCC long CALLBACK SPU2init(void)
+{
+ spuMemC=(unsigned char *)spuMem; // just small setup
+ memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN));
+ memset(rvb,0,2*sizeof(REVERBInfo));
+
+ sampcount = 0;
+
+ InitADSR();
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+// SETUPTIMER: init of certain buffers and threads/timers
+////////////////////////////////////////////////////////////////////////
+
+static void SetupTimer(void)
+{
+ memset(SSumR,0,NSSIZE*sizeof(int)); // init some mixing buffers
+ memset(SSumL,0,NSSIZE*sizeof(int));
+ pS=(short *)pSpuBuffer; // setup soundbuffer pointer
+
+ bEndThread=0; // init thread vars
+ bThreadEnded=0;
+ bSpuInit=1; // flag: we are inited
+}
+
+////////////////////////////////////////////////////////////////////////
+// REMOVETIMER: kill threads/timers
+////////////////////////////////////////////////////////////////////////
+
+static void RemoveTimer(void)
+{
+ bEndThread=1; // raise flag to end thread
+ bThreadEnded=0; // no more spu is running
+ bSpuInit=0;
+}
+
+////////////////////////////////////////////////////////////////////////
+// SETUPSTREAMS: init most of the spu buffers
+////////////////////////////////////////////////////////////////////////
+
+static void SetupStreams(void)
+{
+ int i;
+
+ pSpuBuffer=(unsigned char *)malloc(32768); // alloc mixing buffer
+
+ i=NSSIZE*2;
+
+ sRVBStart[0] = (int *)malloc(i*4); // alloc reverb buffer
+ memset(sRVBStart[0],0,i*4);
+ sRVBEnd[0] = sRVBStart[0] + i;
+ sRVBPlay[0] = sRVBStart[0];
+ sRVBStart[1] = (int *)malloc(i*4); // alloc reverb buffer
+ memset(sRVBStart[1],0,i*4);
+ sRVBEnd[1] = sRVBStart[1] + i;
+ sRVBPlay[1] = sRVBStart[1];
+
+ for(i=0;i<MAXCHAN;i++) // loop sound channels
+ {
+// we don't use mutex sync... not needed, would only
+// slow us down:
+// s_chan[i].hMutex=CreateMutex(NULL,FALSE,NULL);
+ s_chan[i].ADSRX.SustainLevel = 1024; // -> init sustain
+ s_chan[i].iMute=0;
+ s_chan[i].iIrqDone=0;
+ s_chan[i].pLoop=spuMemC;
+ s_chan[i].pStart=spuMemC;
+ s_chan[i].pCurr=spuMemC;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// REMOVESTREAMS: free most buffer
+////////////////////////////////////////////////////////////////////////
+
+static void RemoveStreams(void)
+{
+ free(pSpuBuffer); // free mixing buffer
+ pSpuBuffer=NULL;
+ free(sRVBStart[0]); // free reverb buffer
+ sRVBStart[0]=0;
+ free(sRVBStart[1]); // free reverb buffer
+ sRVBStart[1]=0;
+
+/*
+ int i;
+ for(i=0;i<MAXCHAN;i++)
+ {
+ WaitForSingleObject(s_chan[i].hMutex,2000);
+ ReleaseMutex(s_chan[i].hMutex);
+ if(s_chan[i].hMutex)
+ {CloseHandle(s_chan[i].hMutex);s_chan[i].hMutex=0;}
+ }
+*/
+}
+
+
+////////////////////////////////////////////////////////////////////////
+// SPUOPEN: called by main emu after init
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC long CALLBACK SPU2open(void *pDsp)
+{
+ if(bSPUIsOpen) return 0; // security for some stupid main emus
+
+ iUseXA=0; // just small setup
+ iVolume=3;
+ bEndThread=0;
+ bThreadEnded=0;
+ spuMemC=(unsigned char *)spuMem;
+ memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN));
+ pSpuIrq[0]=0;
+ pSpuIrq[1]=0;
+ iSPUIRQWait=1;
+ dwNewChannel2[0]=0;
+ dwNewChannel2[1]=0;
+ dwEndChannel2[0]=0;
+ dwEndChannel2[1]=0;
+ spuCtrl2[0]=0;
+ spuCtrl2[1]=0;
+ spuStat2[0]=0;
+ spuStat2[1]=0;
+ spuIrq2[0]=0;
+ spuIrq2[1]=0;
+ spuAddr2[0]=0xffffffff;
+ spuAddr2[1]=0xffffffff;
+ spuRvbAddr2[0]=0;
+ spuRvbAddr2[1]=0;
+ spuRvbAEnd2[0]=0;
+ spuRvbAEnd2[1]=0;
+
+// ReadConfig(); // read user stuff
+
+// SetupSound(); // setup midas (before init!)
+
+ SetupStreams(); // prepare streaming
+
+ SetupTimer(); // timer for feeding data
+
+ bSPUIsOpen=1;
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+// SPUCLOSE: called before shutdown
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2close(void)
+{
+ if(!bSPUIsOpen) return; // some security
+
+ bSPUIsOpen=0; // no more open
+
+ RemoveTimer(); // no more feeding
+
+// RemoveSound(); // no more sound handling
+
+ RemoveStreams(); // no more streaming
+}
+
+////////////////////////////////////////////////////////////////////////
+// SPUSHUTDOWN: called by main emu on final exit
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC void CALLBACK SPU2shutdown(void)
+{
+ return;
+}
+
+////////////////////////////////////////////////////////////////////////
+// SPUTEST: we don't test, we are always fine ;)
+////////////////////////////////////////////////////////////////////////
+
+EXPORT_GCC long CALLBACK SPU2test(void)
+{
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+// SETUP CALLBACKS
+// this functions will be called once,
+// passes a callback that should be called on SPU-IRQ/cdda volume change
+////////////////////////////////////////////////////////////////////////
+
+// not used yet
+EXPORT_GCC void CALLBACK SPU2irqCallback(void (CALLBACK *callback)(void))
+{
+ irqCallback = callback;
+}
+
+// not used yet
+EXPORT_GCC void CALLBACK SPU2registerCallback(void (CALLBACK *callback)(void))
+{
+ irqCallback = callback;
+}
+
+// not used yet
+EXPORT_GCC void CALLBACK SPU2registerCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short))
+{
+ cddavCallback = CDDAVcallback;
+}
diff --git a/plugins/ao/eng_psf/peops2/stdafx.h b/plugins/ao/eng_psf/peops2/stdafx.h
new file mode 100644
index 00000000..943f38d3
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/stdafx.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ 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
+//
+//*************************************************************************//
+
+#define EXPORT_GCC
+
+#include <stdlib.h>
+#define RRand(range) (random()%range)
+#include <string.h>
+#include <math.h>
+
+#undef CALLBACK
+#define CALLBACK
+#define DWORD unsigned long
+#define LOWORD(l) ((unsigned short)(l))
+#define HIWORD(l) ((unsigned short)(((unsigned long)(l) >> 16) & 0xFFFF))
+
+#include "psemuxa.h"
+
diff --git a/plugins/ao/eng_psf/peops2/xa.c b/plugins/ao/eng_psf/peops2/xa.c
new file mode 100755
index 00000000..fb63ad40
--- /dev/null
+++ b/plugins/ao/eng_psf/peops2/xa.c
@@ -0,0 +1,363 @@
+/***************************************************************************
+ xa.c - description
+ -------------------
+ begin : Wed May 15 2002
+ copyright : (C) 2002 by Pete Bernert
+ email : BlackDove@addcom.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+//*************************************************************************//
+// History of changes:
+//
+// 2003/02/18 - kode54
+// - added gaussian interpolation
+//
+// 2002/05/15 - Pete
+// - generic cleanup for the Peops release
+//
+//*************************************************************************//
+
+#include "stdafx.h"
+
+#define _IN_XA
+
+// will be included from spu.c
+#ifdef _IN_SPU
+
+////////////////////////////////////////////////////////////////////////
+// XA GLOBALS
+////////////////////////////////////////////////////////////////////////
+
+xa_decode_t * xapGlobal=0;
+
+unsigned long * XAFeed = NULL;
+unsigned long * XAPlay = NULL;
+unsigned long * XAStart = NULL;
+unsigned long * XAEnd = NULL;
+
+unsigned long XARepeat = 0;
+unsigned long XALastVal = 0;
+
+int iLeftXAVol = 32767;
+int iRightXAVol = 32767;
+
+static int gauss_ptr = 0;
+static int gauss_window[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+#define gvall0 gauss_window[gauss_ptr]
+#define gvall(x) gauss_window[(gauss_ptr+x)&3]
+#define gvalr0 gauss_window[4+gauss_ptr]
+#define gvalr(x) gauss_window[4+((gauss_ptr+x)&3)]
+
+////////////////////////////////////////////////////////////////////////
+// MIX XA
+////////////////////////////////////////////////////////////////////////
+
+INLINE void MixXA(void)
+{
+ int ns;
+
+ for(ns=0;ns<NSSIZE && XAPlay!=XAFeed;ns++)
+ {
+ XALastVal=*XAPlay++;
+ if(XAPlay==XAEnd) XAPlay=XAStart;
+ SSumL[ns]+=(((short)(XALastVal&0xffff)) * iLeftXAVol)/32767;
+ SSumR[ns]+=(((short)((XALastVal>>16)&0xffff)) * iRightXAVol)/32767;
+ }
+
+ if(XAPlay==XAFeed && XARepeat)
+ {
+ XARepeat--;
+ for(;ns<NSSIZE;ns++)
+ {
+ SSumL[ns]+=(((short)(XALastVal&0xffff)) * iLeftXAVol)/32767;
+ SSumR[ns]+=(((short)((XALastVal>>16)&0xffff)) * iRightXAVol)/32767;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// FEED XA
+////////////////////////////////////////////////////////////////////////
+
+INLINE void FeedXA(xa_decode_t *xap)
+{
+ int sinc,spos,i,iSize,iPlace,vl,vr;
+
+ if(!bSPUIsOpen) return;
+
+ xapGlobal = xap; // store info for save states
+ XARepeat = 100; // set up repeat
+
+ iSize=((44100*xap->nsamples)/xap->freq); // get size
+ if(!iSize) return; // none? bye
+
+ if(XAFeed<XAPlay) iPlace=XAPlay-XAFeed; // how much space in my buf?
+ else iPlace=(XAEnd-XAFeed) + (XAPlay-XAStart);
+
+ if(iPlace==0) return; // no place at all
+
+ //----------------------------------------------------//
+ if(iXAPitch) // pitch change option?
+ {
+ static DWORD dwLT=0;
+ static DWORD dwFPS=0;
+ static int iFPSCnt=0;
+ static int iLastSize=0;
+ static DWORD dwL1=0;
+ DWORD dw=timeGetTime(),dw1,dw2;
+
+ iPlace=iSize;
+
+ dwFPS+=dw-dwLT;iFPSCnt++;
+
+ dwLT=dw;
+
+ if(iFPSCnt>=10)
+ {
+ if(!dwFPS) dwFPS=1;
+ dw1=1000000/dwFPS;
+ if(dw1>=(dwL1-100) && dw1<=(dwL1+100)) dw1=dwL1;
+ else dwL1=dw1;
+ dw2=(xap->freq*100/xap->nsamples);
+ if((!dw1)||((dw2+100)>=dw1)) iLastSize=0;
+ else
+ {
+ iLastSize=iSize*dw2/dw1;
+ if(iLastSize>iPlace) iLastSize=iPlace;
+ iSize=iLastSize;
+ }
+ iFPSCnt=0;dwFPS=0;
+ }
+ else
+ {
+ if(iLastSize) iSize=iLastSize;
+ }
+ }
+ //----------------------------------------------------//
+
+ spos=0x10000L;
+ sinc = (xap->nsamples << 16) / iSize; // calc freq by num / size
+
+ if(xap->stereo)
+ {
+ unsigned long * pS=(unsigned long *)xap->pcm;
+ unsigned long l=0;
+
+ if(iXAPitch)
+ {
+ long l1,l2;short s;
+ for(i=0;i<iSize;i++)
+ {
+ if(iUseInterpolation==2)
+ {
+ while(spos>=0x10000L)
+ {
+ l = *pS++;
+ gauss_window[gauss_ptr] = (short)LOWORD(l);
+ gauss_window[4+gauss_ptr] = (short)HIWORD(l);
+ gauss_ptr = (gauss_ptr+1) & 3;
+ spos -= 0x10000L;
+ }
+ vl = (spos >> 6) & ~3;
+ vr=(gauss[vl]*gvall0)&~2047;
+ vr+=(gauss[vl+1]*gvall(1))&~2047;
+ vr+=(gauss[vl+2]*gvall(2))&~2047;
+ vr+=(gauss[vl+3]*gvall(3))&~2047;
+ l= (vr >> 11) & 0xffff;
+ vr=(gauss[vl]*gvalr0)&~2047;
+ vr+=(gauss[vl+1]*gvalr(1))&~2047;
+ vr+=(gauss[vl+2]*gvalr(2))&~2047;
+ vr+=(gauss[vl+3]*gvalr(3))&~2047;
+ l |= vr << 5;
+ }
+ else
+ {
+ while(spos>=0x10000L)
+ {
+ l = *pS++;
+ spos -= 0x10000L;
+ }
+ }
+
+ s=(short)LOWORD(l);
+ l1=s;
+ l1=(l1*iPlace)/iSize;
+ if(l1<-32767) l1=-32767;
+ if(l1> 32767) l1=32767;
+ s=(short)HIWORD(l);
+ l2=s;
+ l2=(l2*iPlace)/iSize;
+ if(l2<-32767) l2=-32767;
+ if(l2> 32767) l2=32767;
+ l=(l1&0xffff)|(l2<<16);
+
+ *XAFeed++=l;
+
+ if(XAFeed==XAEnd) XAFeed=XAStart;
+ if(XAFeed==XAPlay)
+ {
+ if(XAPlay!=XAStart) XAFeed=XAPlay-1;
+ break;
+ }
+
+ spos += sinc;
+ }
+ }
+ else
+ {
+ for(i=0;i<iSize;i++)
+ {
+ if(iUseInterpolation==2)
+ {
+ while(spos>=0x10000L)
+ {
+ l = *pS++;
+ gauss_window[gauss_ptr] = (short)LOWORD(l);
+ gauss_window[4+gauss_ptr] = (short)HIWORD(l);
+ gauss_ptr = (gauss_ptr+1) & 3;
+ spos -= 0x10000L;
+ }
+ vl = (spos >> 6) & ~3;
+ vr=(gauss[vl]*gvall0)&~2047;
+ vr+=(gauss[vl+1]*gvall(1))&~2047;
+ vr+=(gauss[vl+2]*gvall(2))&~2047;
+ vr+=(gauss[vl+3]*gvall(3))&~2047;
+ l= (vr >> 11) & 0xffff;
+ vr=(gauss[vl]*gvalr0)&~2047;
+ vr+=(gauss[vl+1]*gvalr(1))&~2047;
+ vr+=(gauss[vl+2]*gvalr(2))&~2047;
+ vr+=(gauss[vl+3]*gvalr(3))&~2047;
+ l |= vr << 5;
+ }
+ else
+ {
+ while(spos>=0x10000L)
+ {
+ l = *pS++;
+ spos -= 0x10000L;
+ }
+ }
+
+ *XAFeed++=l;
+
+ if(XAFeed==XAEnd) XAFeed=XAStart;
+ if(XAFeed==XAPlay)
+ {
+ if(XAPlay!=XAStart) XAFeed=XAPlay-1;
+ break;
+ }
+
+ spos += sinc;
+ }
+ }
+ }
+ else
+ {
+ unsigned short * pS=(unsigned short *)xap->pcm;
+ unsigned long l;short s=0;
+
+ if(iXAPitch)
+ {
+ long l1;
+ for(i=0;i<iSize;i++)
+ {
+ if(iUseInterpolation==2)
+ {
+ while(spos>=0x10000L)
+ {
+ gauss_window[gauss_ptr] = (short)*pS++;
+ gauss_ptr = (gauss_ptr+1) & 3;
+ spos -= 0x10000L;
+ }
+ vl = (spos >> 6) & ~3;
+ vr=(gauss[vl]*gvall0)&~2047;
+ vr+=(gauss[vl+1]*gvall(1))&~2047;
+ vr+=(gauss[vl+2]*gvall(2))&~2047;
+ vr+=(gauss[vl+3]*gvall(3))&~2047;
+ l1=s= vr >> 11;
+ l1 &= 0xffff;
+ }
+ else
+ {
+ while(spos>=0x10000L)
+ {
+ s = *pS++;
+ spos -= 0x10000L;
+ }
+ l1=s;
+ }
+
+ l1=(l1*iPlace)/iSize;
+ if(l1<-32767) l1=-32767;
+ if(l1> 32767) l1=32767;
+ l=(l1&0xffff)|(l1<<16);
+ *XAFeed++=l;
+
+ if(XAFeed==XAEnd) XAFeed=XAStart;
+ if(XAFeed==XAPlay)
+ {
+ if(XAPlay!=XAStart) XAFeed=XAPlay-1;
+ break;
+ }
+
+ spos += sinc;
+ }
+ }
+ else
+ {
+ for(i=0;i<iSize;i++)
+ {
+ if(iUseInterpolation==2)
+ {
+ while(spos>=0x10000L)
+ {
+ gauss_window[gauss_ptr] = (short)*pS++;
+ gauss_ptr = (gauss_ptr+1) & 3;
+ spos -= 0x10000L;
+ }
+ vl = (spos >> 6) & ~3;
+ vr=(gauss[vl]*gvall0)&~2047;
+ vr+=(gauss[vl+1]*gvall(1))&~2047;
+ vr+=(gauss[vl+2]*gvall(2))&~2047;
+ vr+=(gauss[vl+3]*gvall(3))&~2047;
+ l=s= vr >> 11;
+ l &= 0xffff;
+ }
+ else
+ {
+ while(spos>=0x10000L)
+ {
+ s = *pS++;
+ spos -= 0x10000L;
+ }
+ l=s;
+ }
+
+ *XAFeed++=(l|(l<<16));
+
+ if(XAFeed==XAEnd) XAFeed=XAStart;
+ if(XAFeed==XAPlay)
+ {
+ if(XAPlay!=XAStart) XAFeed=XAPlay-1;
+ break;
+ }
+
+ spos += sinc;
+ }
+ }
+ }
+}
+
+#endif
+