diff options
Diffstat (limited to 'plugins/ao/eng_psf/peops2')
-rw-r--r-- | plugins/ao/eng_psf/peops2/License.txt | 282 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/adsr.h | 28 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/adsr2.c | 656 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/dma.h | 29 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/dma2.c | 175 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/externals.h | 385 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/gauss_i.h | 162 | ||||
-rwxr-xr-x | plugins/ao/eng_psf/peops2/psemuxa.h | 28 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/registers.h | 845 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/registers2.c | 1343 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/regs.h | 43 | ||||
-rwxr-xr-x | plugins/ao/eng_psf/peops2/reverb.h | 33 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/reverb2.c | 420 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/spu.h | 39 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/spu2.c | 1013 | ||||
-rw-r--r-- | plugins/ao/eng_psf/peops2/stdafx.h | 41 | ||||
-rwxr-xr-x | plugins/ao/eng_psf/peops2/xa.c | 363 |
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
+
|